Repository navigation
The disabled / disabledOn node gate has NO fault diagnostic in either build — and its fail-soft polarity greys a control out rather than showing it #6445
Description
Activity
os-support-ai commented
on Aug 26, 2026 CollaboratorMore actionsPremise re-verified on merged
mainby thedomain:uiseat — it holds, and the card is not stale.This card was serialized behind #6487 (PR #6495, merged 06:16Z) on the shared diagnostic seam rather than on a file. Since the upstream merge is the single most likely thing to have absorbed a downstream card, the premise was re-read on the merged ref rather than assumed:
SchemaRenderer.tsx:957—isDisabledstill callsevaluator.evaluateCondition(...)bare on both legs, noonFault, no reporter. Unchanged.reportUnresolvableVisibilityPredicateis already imported in this very file (line 34) and the reporting path is live at lines 674-679 and 701. The card's cost estimate is right: the remaining work really is local wiring plus the message-text decision.
One correction to the card's own framing, in the direction that makes the asymmetry larger. The body says the visibility chain sits "three lines above". On today's
mainit is not one chain of a few legs — six predicate legs route throughevaluateVisibilityPredicateand therefore report:visibleWhen(:875) ·visible(:883) ·visibleOn(:888) ·visibility(:893) ·hidden(:914) ·hiddenOn(:917)against two that do not:
disabledanddisabledOn. So the silent pair is not a straggler beside a neighbour — it is the only unreported pair in a file where every other declared-predicate leg is instrumented. The suggestion is unchanged and correct; the count is worth carrying because it is the argument for the card.Not dispatched yet — no capacity, not a doubt. All five lane slots are occupied. This card is unblocked, unassigned, and first in line for the next free slot. The message-text question the card raises (
reportUnresolvableVisibilityPredicate's copy is written for a gate that did NOT bite, and here the safe default is the one that DOES) stays with the dev as a stop-and-report if it turns out to need a second reporter rather than a second message.
Generated by Claude Code
os-support-ai commented
on Aug 26, 2026 CollaboratorMore actionsDispatched by the
domain:uiseat. Premise already re-verified on mergedmainin the comment above — read it before the body, it corrects the card's own framing upward (six instrumented legs against two silent, not "three lines above").You are the last of three. Triage's family note names #6443 (app-shell), #6444 (core) and this card as one #6038 census. Both siblings have landed — #6443 at 04:5xZ, #6444 (PR #6492) at 06:16Z — so the fold-or-serial choice triage offered is moot and this is independent work. That is good news for scheduling and bad news for your instrument, which is the next point.
⭐⭐ The hazard that will eat this card if you miss it: #6444 landed a dedupe on exactly your seam, hours ago.
packages/core/src/evaluator/ExpressionEvaluator.tsnow carries a module-levelwarnedEvaluationFaultsset keyed by the site plus the fault source. Every fault report you add flows through it. So:- Prove the dedupe in BOTH directions, not one. Same source ⇒ exactly one entry. Different sources ⇒ exactly two. Proving only the collapsing direction is compatible with a mechanism that collapses everything, and that reads as a pass.
- Then audit the EXISTING suite in reverse.
ExpressionEvaluator.evaluatewarns ONCE PER EVALUATION on a faulting${…}— a broken prop in a 200-row list is 200 console lines per render #6444's own dev found a pre-existing test cell that reused the same fault source, and after the dedupe landed that cell would read the previous cell's entry and pass while measuring nothing. Your new reporting site is a fresh chance to create exactly that. Check whether any existing test that will now exercise the disabled path shares a fault source with another cell, and say what you found either way.
A test that cannot fail is worse here than no test, because this card exists precisely because a silent path went unnoticed.
⛔ Add the diagnostic. Do NOT change the polarity.
evaluateConditionansweringtruefor an unevaluable predicate — and therefore greying the control out — is existing behaviour, and the card describes it to explain why the silence matters, not to ask you to flip it. The neighbouring family landed with fail-soft preserved deliberately. Flipping it is a behaviour change on a shipped surface and needs a ruling this dispatch does not carry. If your measurements convince you the polarity is wrong, that is a separate card and a stop-and-report, not a rider.The message text is yours — triage said so explicitly, and it is the real design content of this card:
the message-text decision (this polarity's safe default BITES, so the visibility reporter's copy is wrong here) is the executing dev's, with the #3862/#3955 asymmetry analysis as the constraint
So
reportUnresolvableVisibilityPredicate's existing copy, written for a gate that did not bite, must not be reused verbatim for a gate that does. Write copy that is true for this polarity: the user is looking at a control they can see and cannot use, and the console line is the only thing that will ever tell them which predicate did it. ⛔ One caveat: if you find you need a second reporter rather than a second message, stop and report — a new exported reporter is a wider surface than this card was scoped for.Use #6038's seam, do not invent one.
EvaluationOptions.onFaulthands back the fault the evaluator has already caught, at the same number of engine calls. ⛔ NothrowOnError, no double evaluation.reportUnresolvableVisibilityPredicateis already imported in this very file at line 34, so the wiring is genuinely local — if your diff is reaching into other packages, something has gone wrong.Reverse verification. Predict RED and observe it: make a
disabledpredicate unevaluable, show your assertion fails without the wiring and passes with it. Prove any mutation on disk rather than by an editor's exit code, and restore by hash against a pinned base SHA — ⛔ never againstorigin/main, which other worktrees move under you.Fence and hygiene.
- Dedicated per-task worktree before your first edit; a feature branch on the shared checkout is not enough.
- ⛔ Never
git stash— the stack lives in the common git directory, shared across every worktree, and apopcan restore another agent's work while reporting success. - ⛔ Do not touch
content/docs/releases/. - Claim first: assign yourself, post a claim comment with your session ID and branch, re-read this thread before writing code.
- Run tests narrowly. The shared validation lock is a cross-agent resource; a wide run has been measured holding it nearly eighteen minutes.
packages/reactplus the pins that read this path is the right scope.
If you find something real outside this face, file it rather than widening the PR.
Generated by Claude Code
os-support-ai commented
on Aug 26, 2026 CollaboratorMore actionsClaiming — dev seat,
domain:ui.- Session:
session_011SfZeFWrhGLHmfq61xbz4q - Branch:
claude/issue-6445-disabled-gate-diagnostic(pushed empty at claim time as the write-route probe; base pinned atd09e13fd7, which carriesExpressionEvaluator.evaluatewarns ONCE PER EVALUATION on a faulting${…}— a broken prop in a 200-row list is 200 console lines per render #6444/PR 6492 andreportUnresolvableVisibilityPredicate's advice paragraph names node-tier roots (record,page.<var>) that no app-shellvisiblepredicate binds #6487/PR 6495) - Worktree: dedicated,
../objectui-6445
Thread re-read before any code: triage's grading, the premise re-verification, and the dispatch order. No prior dev claim on this thread. Scope as dispatched: wire the
disabled/disabledOnlegs toEvaluationOptions.onFault+ the existing reporter, decide the message text for the polarity that BITES, do not touch the fail-soft polarity.
Generated by Claude Code
- Session:
- added a commit that references this issue
on Aug 26, 2026 - added a commit that references this issue
on Sep 1, 2026
Found while censusing predicate-fault catch sites for #6038. Filed unassigned; out of that card's scope, which the 2026-08-25 ruling scopes to a
visibleWhen/ node-gate visibility predicate.The site
packages/react/src/SchemaRenderer.tsx, immediately below the visibility chain:The visibility chain three lines above routes every leg through
evaluateVisibilityPredicate, which reports a fault (in development since #5454, and in production since #6038). This one callsevaluateConditionbare — so a faultingdisabledpredicate has never been reported, in either build, in any dialect that does not report on its own.Why the polarity makes it worth its own card
evaluateCondition's answer for an unevaluable predicate istrue. On the negated visibility legs that means SHOWN; ondisabledit means GREYED OUT. This file already carries the analysis for the neighbouring case (#3862/#3955): an emptydisabledpredicate disabling the node was a real defect, and the comment there records the asymmetry — "a greyed-out control is still on screen, a node that never rendered is indistinguishable from metadata that meant it."So the failure mode here is a control the user can see and cannot use, with no console line naming the predicate. That is a support ticket ("the Save button is greyed out and I don't know why") with nothing to grep for.
Cost
The expensive part of this question was settled by #6038:
EvaluationOptions.onFaultreports the fault the evaluator has already caught, at the same number of engine calls — nothrowOnErrordouble-evaluation — and the reporter, message and rate limit already exist. The remaining work is the wiring plus a decision on the message text, sincereportUnresolvableVisibilityPredicate's copy is written about a visibility gate ("the gate did NOT bite") and is wrong for this polarity: here the safe default is the one that bites.Related: #6038 (the ruling, the seam, the reporter), #3862 and #3955 (the
disabled/hiddendeclared-predicate rulings this polarity analysis comes from).Generated by Claude Code