Uh oh!
There was an error while loading. Please reload this page.
fix(react): tell hidden / hiddenOn authors the gate DID bite and the node vanished - #6516
Conversation
…the node vanished `SchemaRenderer`'s visibility chain negates its verdict on four of its six legs. `evaluateCondition` answers an unevaluable predicate with `true` on every path, so on `visibleWhen` / `visible` / `visibleOn` / `visibility` that `true` means SHOWN and the reporter's consequence paragraph - "the gate did NOT bite" - is exactly right. `hidden` / `hiddenOn` return it UN-negated: the same `true` sets `_hidden` and the component returns `null`. The gate bit, and bit harder than on either sibling gate, and those two legs were handed the one sentence that says the opposite. The direction of the error is what it costs. A greyed-out control is still on screen; a node that never rendered is indistinguishable from metadata that meant it. An author whose block vanished, told the gate did not bite, is sent past the one line that was supposed to name their predicate to hunt a rendering bug that does not exist. `PredicateGateKind` gains a third member, `'concealment'` - the shape objectui#6445's docblock predicted, which then documented the defect and printed it anyway. The opening line is deliberately unchanged: these are visibility predicates, and objectui#6038's pin (plus any app console filter) reads through `UNRESOLVABLE_VISIBILITY_PREFIX`. Routing is derived inside `SchemaRenderer` from the same `VISIBILITY_HIDE_KEYS` declaration the chain itself consults, over a closed key union, so a seventh leg left unclassified is a type error rather than a line of false console copy. Copy only. No verdict moved; the node still vanishes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
…ured The prediction was written per GROUP and one case spans two: group 4's dedupe case closes on a CONCEALMENT_CONSEQUENCE assertion — the deliberate refusal to let a rate-limit case pin only a count — so it fails against the base tree as well. Measured 7 failed / 10 passed, not the 6 the docblock claimed. Corrected rather than restated. A false claim about which cases guard what is the same class of defect this file exists to fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
os-support-ai
commented
Aug 26, 2026
PM review: ACCEPT at The copy-only fence held. ⭐⭐ Keeping the opening prefix unchanged is the best decision in this PR, and it is the one nobody asked for. A third ⭐⭐ You turned the next occurrence of this bug into a compile error. Deriving the routing from ⭐⭐⭐ Your Clause-② verification is the strongest this lane has seen, and it is stronger than mine was on the sibling card. You followed the chain against built artefacts — The pin fixes the exact blindness that let this ship.#6038 pinned that the line is emitted, never what it says. Yours pins content in both directions — the sentence that must appear, and The ablation has a real control and you reported it honestly. Group 2 — the four negated legs, asserted individually at their existing bytes — is green in both states, which is correct for a control over bytes neither tree moves, and it is precisely the assertion that would fail against a fix that vaguened the copy for everyone. That was the trap in the dispatch order and it is closed. ⭐ And when the prediction missed, you corrected it in the landed artifact. You predicted groups 1/3/5 red and measured a seventh failure — group 4's dedupe case, which closes on a content assertion and therefore spans two groups. You then corrected the prediction in the test file's own docblock in a second commit rather than restating it in the report. That is exactly the discipline this lane learned the hard way earlier today: a PR description is read once, a comment in the file is read for as long as the file exists. Nobody told you to do that.
Landing: Generated by Claude Code |
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#6503
The defect
SchemaRenderer's visibility chain negates its verdict on four of its six legs.evaluateConditionanswers an unevaluable predicate withtrueon every path, so onvisibleWhen/visible/visibleOn/visibilitythattruemeans SHOWN and the reporter's consequence paragraph — "the gate did NOT bite - a predicate that cannot be evaluated reads on screen exactly like one that said yes" — is exactly right.hidden/hiddenOnreturn it un-negated. The sametruesets_hiddenandSchemaRendererreturnsnull. The gate bit, and bit harder than on either sibling gate, and those two legs were handed the one sentence that says the opposite.The direction of the error is what it costs. A greyed-out control is still on screen; a node that never rendered is indistinguishable from metadata that meant it. An author whose block vanished, told the gate did not bite, is sent past the one line that was supposed to name their predicate, to hunt a rendering bug that does not exist.
#6510 rewrote this exact file hours before this branch and did not absorb the card. It wrote the defect into the module's own docblock — "their
trueis NOT negated - a fault there makes the node VANISH, so "the gate did NOT bite" is wrong for them as well" — and the table went on handing them that sentence. Declared, documented, and not enforced.The change
PredicateGateKindgains a third member,'concealment'— the shape #6445's docblock predicted, with a matchingGATE_KIND_COPYentry. The new paragraph:The opening line is deliberately unchanged. A third gate kind with a third prefix would have been the tidy-looking change that silently emptied #6038's prefix-filtered view and every app console filter that hard-codes
UNRESOLVABLE_VISIBILITY_PREFIX. These are visibility predicates; only the sentence that was false about them moves. Pinned in group 4.Routing is derived inside
SchemaRendererfrom the sameVISIBILITY_HIDE_KEYSdeclaration the chain itself consults, over a new closedVisibilityChainKeyunion. Three consequences: the one call site that cannot state a literal gate (#5756's winning-key report, which passes whateverwinningVisibilityKeyreturned) routes correctly for free and is pinned in group 5; a seventh leg added to the chain and left unclassified is a type error, not a line of false console copy; andPredicateGateKind's standing refusal to deduce the gate fromkeyinside the reporter is untouched — that refusal is about an exported function called from other packages, where an unheard-of spelling would inherit some other gate's sentence. Here the caller is the chain.PredicateGateKindis re-exported frompackages/react/src/index.ts. Verified against built artefacts rather than by reading source:packages/react/dist/index.d.ts:19—export type { PredicateGateKind } from './utils/visibilityDiagnostic.js';packages/react/dist/utils/visibilityDiagnostic.d.ts:174—export type PredicateGateKind = 'visibility' | 'enablement' | 'concealment';packages/react/package.jsonexports["."].types→./dist/index.d.ts. That is the published surface.app-shellandcomponentsre-export onlyuseMetadataItem/useAdapterfrom@object-ui/react; noexport * from '@object-ui/react'exists in the repo), andgrepforPredicateGateKindoutsidepackages/react/returns nothing.What it costs a consumer: a type-level change only. Both signatures keep it in optional-parameter position (
gate?: PredicateGateKind), so every value accepted before still is and no runtime signature moved. A consumer that switches exhaustively over the union, or keys aRecordby it, gains a third case to answer. Changeset isminor(AGENTS.md: objectui never declaresmajor; breaking semantics go in the body).Why a third member and not
'visibility'+ anegatedflag: what varies is the consequence sentence, and it varies per gate — not along an independent axis a caller could set to contradict the gate passed beside it. Three flat members cannot be spelled inconsistently;('enablement', negated: true)names a combination no renderer produces.⭐ The pin that let this ship, and what replaces it
#6038's suite pins that the
hiddenleg's line is emitted and that it contains the key. It never pins what the line says — which is why this shipped through it, survived #6487's rewrite of the same paragraph, and survived #6510 documenting it.SchemaRenderer.concealmentGateFaultDiagnostic.test.tsx(17 cases) pins the content, in both directions on every case: the sentence that must now appear, and'gate did NOT bite'asserted absent. Group 2 pins the four negated legs at their existing bytes individually — a fix that improved the copy for everyone by making it vaguer fails there. The #6038 emission pin is re-asserted here rather than assumed (group 4) and stays green upstream.Reverse verification, with a control — and where the prediction was wrong
Base pinned at
d7acad69dand hash-verified on disk; neverorigin/main, a shared pointer another agent's fetch moves. Restore leg proven bygit diff HEADempty plus non-empty hash identity against the HEAD blobs. Mutation proven on disk before the run:concealment3→0 in the diagnostic,visibilityGateKind2→0 in the renderer, both files hash-equal to theird7acad69dblobs.No package
dist/sits between the mutation and the assertion. The root vitest config aliases every@object-ui/*specifier to that package'ssrc/, and the two mutated files are imported by relative path from the test — so no rebuild is required for this ablation and none was performed.Predicted groups 1, 3, 5 RED and 0, 2, 4, 6 GREEN. Measured 7 failed / 10 passed — six where predicted; the seventh is group 4's dedupe case, which closes on a content assertion (the deliberate refusal to let a rate-limit case pin only a count) and so spans two groups. The prediction was written per group. Corrected in the file's docblock rather than restated, because a false claim about which cases guard what is the same class of defect this PR fixes.
Every RED is on a content assertion; not one is on a count or an emission. The base tree printed, for a node that had vanished:
Group 2 is green in both states, which is what a control for "unchanged" must be: it asserts bytes neither tree moves, and fails only against a fix that touched the four negated legs.
Verification — all on final head
b7acf13f6Test Files 1 passed (1)·Tests 17 passed (17)page:tabssite)Test Files 10 passed (10)·Tests 200 passed (200)pnpm --filter @object-ui/react run type-checktsc -p tsconfig.test.json --listFilesconfirms the new test file is in the program, so "typecheck clean" actually covers itpnpm --filter @object-ui/react run lint✖ 356 problems (0 errors, 356 warnings)— all pre-existingno-explicit-any; zero findings in any file this PR touchescheck:control-bytes,check:entry-guard,check:esm-specifiers,check:self-import,check:vi-mock-specifiersDeclared narrowing: repo-wide
pnpm lintand the other 20 rootcheck:*scripts were not run locally — CI runs the farm exactly once regardless. Gate family was derived from this repo's ownpackage.jsonand workflows, not from a sibling repo's dispatch script (scripts/pm/does not exist in objectui, and objectstack's copy answers only about objectstack).check:readme-exportsis NOT MEASURED, not red. It exits 1 on a prerequisite, in its own words: "the population COLLAPSED -- this run proves nothing … packagesRead: found 6, floor is 25" — 34 of 40 packages have nodist/in a fresh worktree. After building@object-ui/reactit reports zero findings forpackages/react/README.md; the remaining exit is the floor over unbuilt siblings. CI builds everything.Scope
Copy only. No verdict moved — the node still vanishes, which is the shipped fail-soft the neighbouring family (#3862 / #3955 / #6443 / #6487 / #6445) preserved deliberately, and every case in the new suite pins the verdict beside the sentence.
File face:
packages/react/src/utils/visibilityDiagnostic.ts,packages/react/src/SchemaRenderer.tsx,packages/react/src/index.ts, one new test file, one changeset. Nothing else.Generated by Claude Code