You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
The adapter-only data.* diagnostic (#5687) covers the visibility gate only — the same constant predicate on disabled greys a control out in silence #6504
Found while wiring the disabled / disabledOn fault diagnostic (#6445). Filed unassigned — it is a second diagnostic with its own maintainer ruling and its own copy, not part of that card's wiring.
The gap
reportAdapterOnlyDataPredicate (packages/react/src/utils/visibilityDiagnostic.ts, #5687, ruling 2026-08-22 option A) reports a predicate that evaluated perfectly against the wrong object: at the node tier data is the data-source adapter, not the row, so data.status == 'draft' is a CONSTANT for every row. It is called from evaluateVisibilityPredicate's dev leg only.
The disabled / disabledOn gate — now wired for faults by #6445 — is not covered by it. A node written
evaluates cleanly (no fault, so #6445's reporter correctly stays silent), resolves undefined == 'locked' to false… and on the other value of that constant (data.locked == null, !data.assignee, or an adapter that answers nothing) hands the gate a constant true that greys the control out on every row, in every build, with nothing on the console.
Two reasons, both about the message rather than the wiring:
Its ruling is scoped to visibility. The 2026-08-22 option A ruling names the visibility gate; extending a dev-only diagnostic to a second gate is a decision, not an implementation detail.
So it needs a copy decision of the same kind #6445 made (its GATE_KIND_COPY table is the obvious place, and the module now has the machinery), plus a ruling on whether the extension stays dev-only as #5687 is.
Note on the deprecation clock
#5687's own docblock says this diagnostic "dissolves when #5330's deprecation window closes" (data.* as a spelling for the row). If that window is close, the right answer may be to do nothing here — worth stating explicitly rather than leaving the asymmetry undocumented, which is why this is filed rather than fixed.
Related: #5687 (the leg), #5330 (the deprecation), #6445 (the disabled fault diagnostic that exposed the gap).
Triage (triage seat, hourly round 2026-08-26, session session_01DoScS7Ei3iWc39AgGN36wU): graded needs-user-decision + domain:ui, type Task. Rationale: the card asks to extend a diagnostic whose existing scope is a recorded maintainer ruling (2026-08-22 option A, #5687, named the visibility gate only) to a second gate — extending a ruled scope is a decision, and the card's own deprecation-clock note (#5687 dissolves when #5330's window closes) means "do nothing" is a live option, not negligence. Filing into the decision box rather than the queue.
Maintainer ruling recorded — Option A: extend the constant-predicate diagnostic to the disabled gate, dev-only
Provenance: maintainer, 2026-08-27, PM chat decision-inbox batch 5 (adjudication session session_01DKWDdUJ2XNRESVVWUvcpnh), verbatim: 「同意」 — accepting recommendation A with its stated premise affirmed: the #5330data.* deprecation window is not closing near-term.
Ruled: extend the adapter-only constant-predicate diagnostic (#5687, 2026-08-22 option A) to the disabled / disabledOn gate — dev-only, via #6445's GATE_KIND_COPY machinery, with gate-appropriate copy (the constant-true direction: "greys the control on every row while looking exactly like a gate that said no"). ⛔ C (always-on) stays excluded — outside the #5687 precedent.
Inheritance clause, binding: the extension inherits #5687's dissolution note verbatim — when #5330's deprecation window closes, both legs dissolve together; the new copy entry must carry the same pointer so the teardown finds it.
Dispatching on the maintainer's 2026-08-27 ruling (「同意」), Option A, unchanged: extend the adapter-only constant-predicate diagnostic to the disabled / disabledOn gate, dev-only, through #6445's GATE_KIND_COPY machinery.
⛔ C (always-on) stays excluded — outside the #5687 precedent. The extension is dev-only exactly as #5687 is.
⭐ The binding inheritance clause is the part most likely to be dropped
Quoting the ruling:
the extension inherits #5687's dissolution note verbatim — when #5330's deprecation window closes, both legs dissolve together; the new copy entry must carry the same pointer so the teardown finds it.
That is not decoration. #5687's own docblock says the diagnostic dissolves when #5330's data.* deprecation window closes. A second leg added without the same pointer is a second thing the teardown will miss — and a diagnostic that outlives the spelling it exists to police is exactly the kind of residue this lane spends its time removing. ⇒ The pointer is a deliverable, not a comment.
The copy is a decision the ruling already made — get its direction right
The existing message is visibility copy: "on this surface a constant false hides the node on every row while looking exactly like a gate that said no."
⛔ Wrong sentence for this gate. The ruling names the direction: the constant-true case, which greys the control on every row while looking exactly like a gate that said no. That asymmetry is the whole reason this was not folded into #6445 — same machinery, different sentence.
⚠️ And note the defect's shape, because it decides what the diagnostic must catch: the predicate evaluates perfectly, against the wrong object. At the node tier data is the data-source adapter, not the row, so data.status == 'locked' is a constant for every row. There is no fault, so #6445's fault reporter correctly stays silent — which is precisely why this needs its own leg rather than a widened one.
The premise the ruling rests on
The ruling affirms it explicitly: #5330's data.* deprecation window is not closing near-term. That was the decisive fact between A and B — triage flagged it as its own confidence gap and the maintainer answered it.
⛔ If you measure that the window is closing soon, that is a stop-and-report, not a reason to proceed quietly or to switch to B on your own. The seat re-decides; you do not.
Surface
packages/react/src/utils/visibilityDiagnostic.ts and #6445's GATE_KIND_COPY table. packages/react is free — PR #6690 (the settled-schema hook) merged and nothing else holds it.
⚠️ One card is in flight nearby: #6527's B patch round touches packages/types' exports map plus app-shell and plugin-designer. No overlap expected; report it if your work reaches any of those.
Type Task. Changeset patch or minor per the presence gate's own verdict — this is a dev-only diagnostic, no runtime behaviour and no published type changes, so ⛔ not clause-②. If your measurement says otherwise, stop and report.
{
"issue": 6504,
"status": "done",
"branch": "claude/issue-6504-disabled-gate-constant-predicate",
"pr": "https://github.com/objectstack-ai/objectui/pull/6702",
"premise_still_valid": true,
"summary": "Extended objectui#5687's adapter-only `data.*` constant-predicate diagnostic to the `disabled` / `disabledOn` gate, dev-only, per the 2026-08-27 maintainer ruling (Option A) on this issue. Added a new `enablement` entry to a per-gate copy table (`ADAPTER_ONLY_GATE_COPY`, following #6445's `GATE_KIND_COPY` indexing discipline) with new copy for the constant-`true` direction (greys the control on every row), wired via a new dev-only branch in `evaluateEnablementPredicate` (`SchemaRenderer.tsx`) that reuses the single `onFault`-based engine call rather than paying for a second evaluation. Verified the stop-condition premise: #5330's deprecation window is not closing near-term (its Phase 2 survey carrier, #5741, is still open and unassigned, blocked on a live-tenant data channel), so proceeded per the ruling. The dissolution pointer is carried both at #5687's original docblock location (appended clause naming both legs) and in a new docblock on the copy table that quotes the ruling's binding clause verbatim and names every symbol + both call sites a #5330-window teardown must delete together.",
"tests": "`pnpm --filter '@object-ui/react^...' build` (dependency closure: types/core/data-objectstack/i18n all Done) before any judgment. `pnpm --filter '@object-ui/react' run type-check` (tsc --noEmit && tsc -p tsconfig.test.json) -> exit 0, clean. `pnpm exec vitest run packages/react/src/__tests__/SchemaRenderer.disabledGateFaultDiagnostic.test.tsx` -> 'Test Files 1 passed (1)' / 'Tests 32 passed (32)' (23 pre-existing + 1 rewritten-from-negative-to-positive + 9 new). `pnpm exec vitest run .../SchemaRenderer.nodeGateDataPredicate.test.tsx .../SchemaRenderer.concealmentGateFaultDiagnostic.test.tsx` (unchanged siblings) -> 'Test Files 2 passed (2)' / 'Tests 40 passed (40)'. `pnpm exec vitest run packages/react/` (root-level invocation per objectui#3378) -> 'Test Files 62 passed (62)' / 'Tests 926 passed (926)', re-run after ablation restore with identical result. `node scripts/check-control-bytes.mjs` -> exit 0, 'OK (scanned 5553 tracked text file(s); skipped 85 binary)'. `node scripts/check-changeset-presence.mjs` -> exit 0, '3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'. `node scripts/check-changeset-no-major.mjs` -> exit 0. Lint narrowed to the 3 touched files (`eslint --no-inline-config --format json`, exit captured before any pipe): 3 files linted per json array length, 0 errors, 18 pre-existing no-explicit-any warnings on SchemaRenderer.tsx, none within the edited line range (805-864) -- confirmed by running eslint via --stdin on origin/main@9abc02ab2's own copy of the file, which also reports exactly 0 errors / 18 warnings, proving zero new warnings. Narrowing justified: eslint.config.js declares no `project`/`projectService` (no type-aware linting), so the diff cannot move judgment on any untouched file. ABLATION, both legs predicted before running, mutation and restoration proven via git hash-object plus git diff HEAD (never an editor's exit code), each leg wrapped in a trap-based restore. Leg 1 (must-produce): reverted evaluateEnablementPredicate to its pre-change shape (call-site grep count 1->0, blob hash 57c0beb3f...->9f8e8dcd0...). Predicted every new positive-report test turns red and every silence/negative control stays green; observed exactly that -- 8/8 red (acceptance criterion, constant-true direction, copy-is-not-reused, cross-gate content, disabledOn, both dedupe cases, the rewritten pin), 24/24 other cases green. Restored: git diff HEAD empty, hash back to 57c0beb3f.... Leg 2 (false-positive direction): broadened the SHARED (pre-existing, unmodified-by-this-PR) discriminator regex DATA_ROOT_PATH_RE to also match `record` as a root (marker count 0->1, hash 40e466e7d...->191c9de53...). Predicted the new FALSE-POSITIVE CONTROL test and nodeGateDataPredicate.test.tsx's 3a would flip red. OBSERVED DIFFERENTLY, reported as observed rather than forced: neither predicted test flipped (both are independently protected by the `source.indexOf('data.') === -1` fast-reject, since neither predicate string contains the literal substring 'data.'); instead two unrelated PRE-EXISTING pins in nodeGateDataPredicate.test.tsx (2d, 3d) flipped, both already-hardened false-positive guards this card did not write, correctly catching the hostile mutation. Conclusion drawn from the miss: this leg adds no new discriminator logic, only a second call into the existing shared function, so its false-positive resistance is inherited by construction rather than separately proven -- a fact about the suite's (and the shared module's) discriminating power, not a gap in this leg. Restored: git diff HEAD empty, hash back to 40e466e7d.... Leg 3 (visibility leg unchanged): evaluateVisibilityPredicate's call site is untouched (still defaults to 'visibility', no gate argument added); confirmed both by the unmodified sibling test files passing byte-identical to origin/main and by leg 1's mutation showing zero effect on any visibility-leg test. Final tree confirmed clean (`git diff HEAD` 0 lines) after both ablation legs, at commit 20c52cedf (branch head, pushed) -- the sha the PR body's gate table and this report both quote against.",
"mcp_calls": 8,
"open_questions": [],
"out_of_scope_findings": []
}
ACCEPT — PR #6702, head 20c52cedf, flipped ready for review.
What was verified, and what the dev found that the card did not predict.
1. The stop-condition premise holds. The card's dissolution pointer is only useful if #5330's deprecation window is not about to close under it. Checked rather than assumed: #5330's Phase 2 survey carrier, #5741, is still open, unassigned, and blocked on a live-tenant data channel. The window is not closing near-term, so a pointer (rather than an inline teardown) is the right shape here.
2. The dissolution pointer is carried in two places, not one.
A pointer in one place is a pointer someone deletes half of. Both entry points a teardown could arrive through now carry it.
3. Leg 1 (must-produce): 8/8 red as predicted, 24/24 of the others green. The control behaves exactly as the card specified.
4. Leg 2's prediction missed — and the analysis is the more valuable half of this report.
Predicted: broadening the shared DATA_ROOT_PATH_RE to also match record would flip the new false-positive control andnodeGateDataPredicate.test.tsx case 3a red.
Observed: neither flipped. Both are independently protected by the source.indexOf('data.') === -1 fast-reject — neither predicate string contains the literal data., so the broadened regex is never reached. What did flip were two unrelated pre-existing pins (2d, 3d) — already-hardened guards this card did not write.
The dev reported this rather than reshaping the mutation until it produced the predicted signature. Its conclusion, quoted:
this leg adds no new discriminator logic, only a second call into the existing shared function, so its false-positive resistance is inherited by construction rather than separately proven — a fact about the suite's (and the shared module's) discriminating power, not a gap in this leg.
That reading is accepted. A leg that adds a second call into an already-guarded shared function inherits that function's resistance; demanding a separately-proven discriminator for it would be demanding proof of something the leg does not introduce. The correct record is the one written: the property is inherited, and stated as inherited.
5. Leg 3: the visibility leg confirmed unchanged, two independent ways.
Standing note for whoever executes the #5330 teardown: the two docblocks in (2) are a matched pair. Deleting one and leaving the other is worse than deleting neither — the survivor then points at a leg that no longer exists.
Activity
os-support-ai commentedon Aug 26, 2026
Triage (triage seat, hourly round 2026-08-26, session
session_01DoScS7Ei3iWc39AgGN36wU): gradedneeds-user-decision+domain:ui, type Task. Rationale: the card asks to extend a diagnostic whose existing scope is a recorded maintainer ruling (2026-08-22 option A, #5687, named the visibility gate only) to a second gate — extending a ruled scope is a decision, and the card's own deprecation-clock note (#5687 dissolves when #5330's window closes) means "do nothing" is a live option, not negligence. Filing into the decision box rather than the queue.os-decision-facets
data.*predicate against the data-source ADAPTER, so a hoistedproperties.visiblewritten that way hides the block on every row, silently #5687 自述随 [Decision] Row-predicate spelling contract: does the canon narrow torecord.*, or do the bare shorthand anddata.*spellings stay? (the uncarried "#4075 step 3" question) #5330 的data.*废弃窗口关闭而消解 —— 给一个将死拼写加第二条诊断,是对旧世界的投资;窗口远则值得,近则浪费。裁决应先看窗口时间表。disabled/disabledOnnode gate has NO fault diagnostic in either build — and its fail-soft polarity greys a control out rather than showing it #6445 已备好GATE_KIND_COPY机制,扩展成本是一条表项 + 一段 copy。record.*, or do the bare shorthand anddata.*spellings stay? (the uncarried "#4075 step 3" question) #5330 收尾时要拆走的新义务;不扩(B)是零成本选项。disabledgate,新 copy 进GATE_KIND_COPY,保持 dev-only(推荐,条件:[Decision] Row-predicate spelling contract: does the canon narrow torecord.*, or do the bare shorthand anddata.*spellings stay? (the uncarried "#4075 step 3" question) #5330 废弃窗口不在近期关闭);B — 不扩,记录不对称,等窗口关闭一并消解(若窗口近,推荐 B);C — 扩且转 always-on(⛔ 超出 SchemaRenderer's node visibility gate resolves adata.*predicate against the data-source ADAPTER, so a hoistedproperties.visiblewritten that way hides the block on every row, silently #5687 先例,不推荐)。record.*, or do the bare shorthand anddata.*spellings stay? (the uncarried "#4075 step 3" question) #5330 废弃窗口的时间表本分析未查(它是 A/B 之间的决定性事实);disabled上 adapter-only 常量谓词的真实发生率未测。Generated by Claude Code
os-zhuang commentedon Aug 27, 2026
Maintainer ruling recorded — Option A: extend the constant-predicate diagnostic to the
disabledgate, dev-onlyProvenance: maintainer, 2026-08-27, PM chat decision-inbox batch 5 (adjudication session
session_01DKWDdUJ2XNRESVVWUvcpnh), verbatim: 「同意」 — accepting recommendation A with its stated premise affirmed: the #5330data.*deprecation window is not closing near-term.Ruled: extend the adapter-only constant-predicate diagnostic (#5687, 2026-08-22 option A) to the
disabled/disabledOngate — dev-only, via #6445'sGATE_KIND_COPYmachinery, with gate-appropriate copy (the constant-truedirection: "greys the control on every row while looking exactly like a gate that said no"). ⛔ C (always-on) stays excluded — outside the #5687 precedent.Inheritance clause, binding: the extension inherits #5687's dissolution note verbatim — when #5330's deprecation window closes, both legs dissolve together; the new copy entry must carry the same pointer so the teardown finds it.
State:
needs-user-decision→pm:queue.Generated by Claude Code
os-sales commentedon Aug 28, 2026
Claim:
domain:ui@ objectui PM seat, session8ca04858-ea8e-5b85-9182-de59aa49e00c— branchclaude/issue-6504-disabled-gate-constant-predicate.Dispatching on the maintainer's 2026-08-27 ruling (「同意」), Option A, unchanged: extend the adapter-only constant-predicate diagnostic to the
disabled/disabledOngate, dev-only, through #6445'sGATE_KIND_COPYmachinery.⛔ C (always-on) stays excluded — outside the #5687 precedent. The extension is dev-only exactly as #5687 is.
⭐ The binding inheritance clause is the part most likely to be dropped
Quoting the ruling:
That is not decoration. #5687's own docblock says the diagnostic dissolves when #5330's
data.*deprecation window closes. A second leg added without the same pointer is a second thing the teardown will miss — and a diagnostic that outlives the spelling it exists to police is exactly the kind of residue this lane spends its time removing. ⇒ The pointer is a deliverable, not a comment.The copy is a decision the ruling already made — get its direction right
The existing message is visibility copy: "on this surface a constant
falsehides the node on every row while looking exactly like a gate that said no."⛔ Wrong sentence for this gate. The ruling names the direction: the constant-
truecase, which greys the control on every row while looking exactly like a gate that said no. That asymmetry is the whole reason this was not folded into #6445 — same machinery, different sentence.datais the data-source adapter, not the row, sodata.status == 'locked'is a constant for every row. There is no fault, so #6445's fault reporter correctly stays silent — which is precisely why this needs its own leg rather than a widened one.The premise the ruling rests on
The ruling affirms it explicitly: #5330's
data.*deprecation window is not closing near-term. That was the decisive fact between A and B — triage flagged it as its own confidence gap and the maintainer answered it.⛔ If you measure that the window is closing soon, that is a stop-and-report, not a reason to proceed quietly or to switch to B on your own. The seat re-decides; you do not.
Surface
packages/react/src/utils/visibilityDiagnostic.tsand #6445'sGATE_KIND_COPYtable.packages/reactis free — PR #6690 (the settled-schema hook) merged and nothing else holds it.packages/types'exportsmap plusapp-shellandplugin-designer. No overlap expected; report it if your work reaches any of those.Type Task. Changeset
patchorminorper the presence gate's own verdict — this is a dev-only diagnostic, no runtime behaviour and no published type changes, so ⛔ not clause-②. If your measurement says otherwise, stop and report.Generated by Claude Code
os-sales commentedon Aug 28, 2026
os-dev-report
{ "issue": 6504, "status": "done", "branch": "claude/issue-6504-disabled-gate-constant-predicate", "pr": "https://github.com/objectstack-ai/objectui/pull/6702", "premise_still_valid": true, "summary": "Extended objectui#5687's adapter-only `data.*` constant-predicate diagnostic to the `disabled` / `disabledOn` gate, dev-only, per the 2026-08-27 maintainer ruling (Option A) on this issue. Added a new `enablement` entry to a per-gate copy table (`ADAPTER_ONLY_GATE_COPY`, following #6445's `GATE_KIND_COPY` indexing discipline) with new copy for the constant-`true` direction (greys the control on every row), wired via a new dev-only branch in `evaluateEnablementPredicate` (`SchemaRenderer.tsx`) that reuses the single `onFault`-based engine call rather than paying for a second evaluation. Verified the stop-condition premise: #5330's deprecation window is not closing near-term (its Phase 2 survey carrier, #5741, is still open and unassigned, blocked on a live-tenant data channel), so proceeded per the ruling. The dissolution pointer is carried both at #5687's original docblock location (appended clause naming both legs) and in a new docblock on the copy table that quotes the ruling's binding clause verbatim and names every symbol + both call sites a #5330-window teardown must delete together.", "tests": "`pnpm --filter '@object-ui/react^...' build` (dependency closure: types/core/data-objectstack/i18n all Done) before any judgment. `pnpm --filter '@object-ui/react' run type-check` (tsc --noEmit && tsc -p tsconfig.test.json) -> exit 0, clean. `pnpm exec vitest run packages/react/src/__tests__/SchemaRenderer.disabledGateFaultDiagnostic.test.tsx` -> 'Test Files 1 passed (1)' / 'Tests 32 passed (32)' (23 pre-existing + 1 rewritten-from-negative-to-positive + 9 new). `pnpm exec vitest run .../SchemaRenderer.nodeGateDataPredicate.test.tsx .../SchemaRenderer.concealmentGateFaultDiagnostic.test.tsx` (unchanged siblings) -> 'Test Files 2 passed (2)' / 'Tests 40 passed (40)'. `pnpm exec vitest run packages/react/` (root-level invocation per objectui#3378) -> 'Test Files 62 passed (62)' / 'Tests 926 passed (926)', re-run after ablation restore with identical result. `node scripts/check-control-bytes.mjs` -> exit 0, 'OK (scanned 5553 tracked text file(s); skipped 85 binary)'. `node scripts/check-changeset-presence.mjs` -> exit 0, '3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'. `node scripts/check-changeset-no-major.mjs` -> exit 0. Lint narrowed to the 3 touched files (`eslint --no-inline-config --format json`, exit captured before any pipe): 3 files linted per json array length, 0 errors, 18 pre-existing no-explicit-any warnings on SchemaRenderer.tsx, none within the edited line range (805-864) -- confirmed by running eslint via --stdin on origin/main@9abc02ab2's own copy of the file, which also reports exactly 0 errors / 18 warnings, proving zero new warnings. Narrowing justified: eslint.config.js declares no `project`/`projectService` (no type-aware linting), so the diff cannot move judgment on any untouched file. ABLATION, both legs predicted before running, mutation and restoration proven via git hash-object plus git diff HEAD (never an editor's exit code), each leg wrapped in a trap-based restore. Leg 1 (must-produce): reverted evaluateEnablementPredicate to its pre-change shape (call-site grep count 1->0, blob hash 57c0beb3f...->9f8e8dcd0...). Predicted every new positive-report test turns red and every silence/negative control stays green; observed exactly that -- 8/8 red (acceptance criterion, constant-true direction, copy-is-not-reused, cross-gate content, disabledOn, both dedupe cases, the rewritten pin), 24/24 other cases green. Restored: git diff HEAD empty, hash back to 57c0beb3f.... Leg 2 (false-positive direction): broadened the SHARED (pre-existing, unmodified-by-this-PR) discriminator regex DATA_ROOT_PATH_RE to also match `record` as a root (marker count 0->1, hash 40e466e7d...->191c9de53...). Predicted the new FALSE-POSITIVE CONTROL test and nodeGateDataPredicate.test.tsx's 3a would flip red. OBSERVED DIFFERENTLY, reported as observed rather than forced: neither predicted test flipped (both are independently protected by the `source.indexOf('data.') === -1` fast-reject, since neither predicate string contains the literal substring 'data.'); instead two unrelated PRE-EXISTING pins in nodeGateDataPredicate.test.tsx (2d, 3d) flipped, both already-hardened false-positive guards this card did not write, correctly catching the hostile mutation. Conclusion drawn from the miss: this leg adds no new discriminator logic, only a second call into the existing shared function, so its false-positive resistance is inherited by construction rather than separately proven -- a fact about the suite's (and the shared module's) discriminating power, not a gap in this leg. Restored: git diff HEAD empty, hash back to 40e466e7d.... Leg 3 (visibility leg unchanged): evaluateVisibilityPredicate's call site is untouched (still defaults to 'visibility', no gate argument added); confirmed both by the unmodified sibling test files passing byte-identical to origin/main and by leg 1's mutation showing zero effect on any visibility-leg test. Final tree confirmed clean (`git diff HEAD` 0 lines) after both ablation legs, at commit 20c52cedf (branch head, pushed) -- the sha the PR body's gate table and this report both quote against.", "mcp_calls": 8, "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
os-sales commentedon Aug 28, 2026
ACCEPT — PR #6702, head
20c52cedf, flipped ready for review.What was verified, and what the dev found that the card did not predict.
1. The stop-condition premise holds. The card's dissolution pointer is only useful if #5330's deprecation window is not about to close under it. Checked rather than assumed: #5330's Phase 2 survey carrier, #5741, is still open, unassigned, and blocked on a live-tenant data channel. The window is not closing near-term, so a pointer (rather than an inline teardown) is the right shape here.
2. The dissolution pointer is carried in two places, not one.
data.*predicate against the data-source ADAPTER, so a hoistedproperties.visiblewritten that way hides the block on every row, silently #5687's original docblock, naming both legs.ADAPTER_ONLY_GATE_COPYthat quotes the ruling's binding clause verbatim and names every symbol plus both call sites that a [Decision] Row-predicate spelling contract: does the canon narrow torecord.*, or do the bare shorthand anddata.*spellings stay? (the uncarried "#4075 step 3" question) #5330 teardown must delete together.A pointer in one place is a pointer someone deletes half of. Both entry points a teardown could arrive through now carry it.
3. Leg 1 (must-produce): 8/8 red as predicted, 24/24 of the others green. The control behaves exactly as the card specified.
4. Leg 2's prediction missed — and the analysis is the more valuable half of this report.
Predicted: broadening the shared
DATA_ROOT_PATH_REto also matchrecordwould flip the new false-positive control andnodeGateDataPredicate.test.tsxcase 3a red.Observed: neither flipped. Both are independently protected by the
source.indexOf('data.') === -1fast-reject — neither predicate string contains the literaldata., so the broadened regex is never reached. What did flip were two unrelated pre-existing pins (2d, 3d) — already-hardened guards this card did not write.The dev reported this rather than reshaping the mutation until it produced the predicted signature. Its conclusion, quoted:
That reading is accepted. A leg that adds a second call into an already-guarded shared function inherits that function's resistance; demanding a separately-proven discriminator for it would be demanding proof of something the leg does not introduce. The correct record is the one written: the property is inherited, and stated as inherited.
5. Leg 3: the visibility leg confirmed unchanged, two independent ways.
Standing note for whoever executes the #5330 teardown: the two docblocks in (2) are a matched pair. Deleting one and leaving the other is worse than deleting neither — the survivor then points at a leg that no longer exists.
Generated by Claude Code