Skip to content

docs(lint): name what actually guards the unprovisionedAnchors wiring, not a gate that cannot see call sites - #8944

Merged
os-project-manager merged 2 commits into
mainfrom
claude/issue-8664-unprovisioned-anchors-false-guard-claim
Aug 16, 2026
Merged

docs(lint): name what actually guards the unprovisionedAnchors wiring, not a gate that cannot see call sites#8944
os-project-manager merged 2 commits into
mainfrom
claude/issue-8664-unprovisioned-anchors-false-guard-claim

Conversation

@os-project-manager

@os-project-manageros-project-manager commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Fixes#8664

Comment-only change to packages/lint/src/validate-page-field-bindings.ts. No behaviour change, no changeset.

The false claim

The tail of checkFieldRefs' unprovisionedAnchors parameter comment read:

Every in-repo caller passes it; check-cross-package-test-inputs is what would notice if one stopped.

The first clause is true. The second is false, and false in the dangerous direction — it tells the next author the wiring is machine-guarded, which is exactly the belief that stops someone writing the test that guards it.

Answer chosen: (a) correct the sentence

The card offered two: correct the sentence to name what actually guards the wiring, or add the guard it claims exists. I took (a), following the precedent #8404 set in the sibling module — name the in-repo callers explicitly and point at the tests that pin the threading. What made (a) the right pick here is that the measurement below shows the wiring at both module seams is already guarded, by #8340's own tests; there was no missing guard to add at that level, only a misnamed one.

Zone 2 — the gate re-read, not inherited

Verified against scripts/check-cross-package-test-inputs.mjs as it stands after #8899 (merged 16:08Z today), not against the card's description of it:

  • It is an input-scoping gate. Layer A unions a declaring package into turbo ls --affected; layer B verifies turbo.json carries a matching pkg#test task whose inputs include the same globs, so the cache hash moves with them.
  • It finds escaping tests by scanning test source text for filesystem path spellings, deliberately (a detector with no dependencies cannot fail to resolve in CI). It has no symbol table, no call graph, no notion of a function's parameter list.
  • fix(devx): check:cross-package-test-inputs sees the new URL, argument-position and climb-and-descend path spellings #8899's widening — the published RECOGNISED_PATH_SPELLINGS, new URL seeds, "argument-position reads", the shallowest-depth escape criterion — is about which path expressions it recognises. "Argument position" there means a path expression appearing as an argument, e.g. readFileSync(new URL('...', import.meta.url)). It is not call-site inspection, and the card's conclusion holds unchanged.
  • Its @objectstack/lint entry declares the authoring-rule-wiring / validate-rule-compilability / lint-startup-registry-verdict.corpus radius. Nothing in it concerns the anchor index.

There is also a category point worth recording: checkFieldRefs and all of its callers live insidepackages/lint. The gate's whole subject is tests that read outside their own package, so an intra-package wiring question is outside its remit entirely.

What actually notices — measured, not asserted

I dropped the argument at each of the seven in-repo threading sites in turn and ran the suite:

#SiteDrop the index ⇒
P1validate-page-field-bindings.ts:433validatePageFieldBindingsRED — "warns on a highlights binding over an unprovisioned anchor…"
R0validate-react-page-props.ts:1100 — into checkBlockFieldPropsRED — "reaches the FILTER position through the shared core…"
R2validate-react-page-props.ts:849queried refsRED — same test
R1validate-react-page-props.ts:846own refs (skipped)GREEN
R3validate-react-page-props.ts:858ObjectForm subform child refsGREEN
R4validate-react-page-props.ts:863subs.parent (totalField rollup)GREEN
R5validate-react-page-props.ts:873-880 — the COMPONENT_FIELD_SPECS / Block pathGREEN

Each ablation was applied to a pristine tree and reverted with git checkout HEAD -- ... before the next; the final diff is the comment and nothing else.

The replacement comment says exactly this: both entry seams are pinned and by which tests, and the four finer-grained calls are threaded by convention only. Writing "tests pin this" flatly would have re-created the card's own defect one grain finer, so the gap is stated rather than papered over. It is filed separately as #8943 (unassigned, finding) — adding those four pins is the other half the grading said not to mix in here.

Scope item 2 — checked by reading, not only by grep

The card and its grading both asked for "the other three #8340 modules" to be checked for the same copied sentence; the PM measured that it was never copied verbatim. I read all five siblings to judge whether any makes an equivalent guarantee in different words, which an exact-string sweep cannot see. It does not:

  • validate-searchable-fields.ts:348-355 — the same comment block, but its tail already names the two callers explicitly (lint: searchableFields is a FIFTH blanket-SYSTEM_FIELDS read site — a declared anchor on an external object becomes a $searchFields narrowing over a column with no storage #8404's fix). No gate claim. Correct as it stands.
  • validate-react-page-props.ts:834-837 — normative ("must hand over the same index rather than answer differently"), not a claim that something enforces it.
  • validate-flow-template-paths.ts:322-326 and validate-widget-bindings.ts:336-339 — build the index locally and expose no optional parameter, so there is no threading to guarantee. Structurally confirmed: only three files in the package declare unprovisionedAnchors?: at all.
  • validate-react-page-props.test.ts:343-352 — the one other guarantee-shaped claim in the family, and it is a strong one ("with the argument dropped here… the whole lint suite stays green. This test is the only thing that goes red"). I re-verified it: ablating that call leaves exactly one test red across 73 files / 2045 tests. True as written.

Verification

Gate families re-derived against the real diff (node scripts/pm/dispatch-gates.mjs packages/lint/src/validate-page-field-bindings.ts); it returned the same two the dispatch named and added none. All runs below are at final HEAD 6eb42ab71, judged by exit status:

  • pnpm check:cross-package-test-inputs — exit 0 (All 26 self-test cases passed. / OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.)
  • node scripts/check-cross-package-test-inputs.mjs — exit 0 (the ci.yml spelling); --self-test also exit 0
  • node scripts/check-nul-bytes.mjs — exit 0, plus a manual control-character self-scan of the changed file (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', no hits) since the change is prose
  • pnpm --filter @objectstack/lint test — exit 0, 73 files, 2041 passed | 4 skipped (2045)
  • pnpm --filter @objectstack/lint typecheck — exit 0

Generated by Claude Code

…#8664)
The tail of `checkFieldRefs`' `unprovisionedAnchors` parameter comment named
`check-cross-package-test-inputs` as the gate that would notice an in-repo
caller dropping the index. That gate is a CI input-scoping gate: it decides
which packages CI runs (turbo's affected set) and how the `test` task cache is
keyed, from a declared glob list. It scans test source text for filesystem path
spellings; it has no symbol table, no call graph, and no view of argument
passing, so it structurally cannot notice a dropped argument. Its
`@objectstack/lint` entry declares the authoring-rule-wiring radius and says
nothing about the anchor index.
The claim was false in the dangerous direction: it told the next author the
wiring was machine-guarded, which is exactly the belief that stops someone
writing the test that guards it.
Replaced with what was measured, following #8404's precedent: the two in-repo
callers named explicitly, and the behaviour tests that actually go red — found
by dropping the argument at each of the seven in-repo threading sites in turn.
Both module seams are pinned; the four finer-grained calls inside
`checkBlockFieldProps` are threaded by convention only and leave the whole lint
suite green when dropped, which the comment now says rather than implies
otherwise. That coverage gap is filed as #8943.
Comment-only: no behaviour change, no changeset.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm
@vercel

vercelBot commented Aug 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 16, 2026 2:14am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/hook-bodies.mdx(via @objectstack/lint)
  • content/docs/deployment/validating-metadata.mdx(via packages/lint)
  • content/docs/permissions/authorization.mdx(via @objectstack/lint)

1 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/v17.mdx(via @objectstack/lint)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-project-manager@claude