Skip to content

feat(qa-checklist): resolve an area-qualified provisioning.use (#10593 gap 2) - #11508

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-10593-checklist-use-resolve-check
Aug 24, 2026
Merged

os-steve merged 1 commit into
mainfrom
claude/issue-10593-checklist-use-resolve-check

Conversation

@claude

@claude claude Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #10593

Gap 2: cross-area recipe reuse gets a spelling. Implements the maintainer ruling of 2026-08-22 — option A, area-qualified references — over option B (a shared areas/_fixtures.json) and option C (recipes stay area-local, cross-area consumers duplicate). The ruling is not re-litigated here.

The problem

A provisioning recipe is proved by one area and sometimes needed by a second. Until now fixtures.provisioning.use could only name a key in the item's own area, so a cross-area consumer had exactly one option left: cite the recipe by name in knownGaps prose. Prose is the one form that cannot drift-check — rename the recipe and search.json moves while the sentence in records-forms.json does not, silently and with nothing red.

What changed

use now has two spellings, and the gate resolves both:

"use": "qa-scratch-authz"                    // a recipe of the item's OWN area
"use": "search:qa-contributor-bound-member"  // "<area>:<recipe>" — one another area owns

The area half is the filename stem. Every reference already written keeps working — the qualifier is an addition, not a migration, and the self-test pins that as a regression, not as an aspiration.

Two implementation notes worth review attention:

  • The area files are now walked twice. The recipe universe has to be complete before any item is judged; a single pass would test each item against a half-built map, and whether a cross-area reference resolved would depend on readdir order.
  • Recipes are keyed by filename stem, deliberately not by doc.area. The two must agree, and that agreement is itself checked one line down — keying by a mismatched doc.area would let a qualified reference resolve through the very inconsistency the gate reports.

Per the dispatch, the resolver stays inside check-platform-checklist.mjs; no new module under scripts/ (that would move dispatch-gates' family universe, which #11190 is measuring across this same round).

Non-vacuity — this is the part to review

A two-level lookup has a failure mode the one-level one did not: resolving too much. No "it resolves" assertion can see that, so every limb is observed failing as well as passing. Self-test: 36 → 56 assertions.

Ablation A (the #10810 precedent): provisioningProblems() neutered to return early. Predicted 27 of the 34 provisioning assertions red — U4–U13 and Q4–Q20, every case asserting the check fires; U1/U2/U3/Q1/Q2/Q3 assert zero problems and U14 exercises areaRecipeKeys only. Observed exactly 27, exactly that set, and the full gate refused with the provisioning-resolve check's own positive control FAILED rather than going quietly green. Mutation confirmed on disk by anchor count (marker 0 → 1 at line 307) and sha256, never by the editor's exit code; restored byte-identically via an EXIT INT TERM trap (sha back to 3fa7b602…, marker count 0, clean git status).

Ablation B — the sharper one, because it tests the code/data pairing rather than the code alone. The gate was swapped back to origin/main (confirmed on disk: sha 39d95f98…, recipesByArea occurrences 10 → 0, git diff --quiet origin/main clean) while keeping this PR's data change. The base gate reds on exactly the converted item:

✗ records-forms.json · records-forms.crud-roundtrip: "fixtures.provisioning.use" names
  "search:qa-contributor-bound-member" but this area file has no area-level "fixtures"
  block to resolve it against — …

So the green below is produced by the new two-level lookup and by nothing else, and the data change genuinely requires the code change. Restored byte-identically.

All three failure shapes reproduced on the live corpus (each injection confirmed present on disk before the reading was taken; all reverted by trap):

injected use what the gate said
search:qa-recipe-nobody-wrote …not a recipe in area "search"'s area-level "fixtures" block — \search` offers `qa-contributor-bound-member``
serch:qa-contributor-bound-member …whose area half names "serch" — there is no such area file — did you mean \search`?`
search:qa:member …not a usable reference: it carries 2 ":" separators…
search: …not a usable reference: its recipe half is empty…
qa-contributor-bound-member (unqualified) …\search` defines it: write `search:qa-contributor-bound-member` … and do NOT fork a second copy into this area.`

That last row is the upgrade that makes the drift self-correcting: an author who copied an unqualified key across areas is handed the exact spelling that works.

The two prose pointers, converted where they sit

  • records-forms.crud-roundtrip clause 7 now carries use: "search:qa-contributor-bound-member"; its knownGaps and clause-7 verify text stop saying the reference cannot be spelled.
  • search.json's recipe knownGaps stops saying no cross-area spelling exists, and now describes a recipe with consumers in two areas, both machine-resolved.

Both consuming items take a revision bump and a history entry. For search.rls-both-personas that follows the precedent its own revision 5 set: area-level recipes carry no revision/history, so a consuming item's revision is the only pin the recipe text has. What a run does is unchanged in every particular — same recipe, same file, same clause, same object and row; no step, clause, oracle or persona changed.

⚠️ Two things this PR's green does NOT tell you

1. check:platform-checklist is not CI-wired, by maintainer decision recorded at .github/workflows/lint.yml. That decision is honoured, not changed. The local runs in this PR are the only signal this gate will ever get — a green Lint & Repo Gates on this PR says nothing whatsoever about it, and a typo'd use is caught at the next manual sweep rather than on the PR that introduces it.

2. The gate is already red on main, for a reason this PR does not touch. Measured on pristine origin/main @ 63da5867 before any edit: coverage.json · manifest: UNCLASSIFIED. packages/spec/liveness/manifest.json landed 2026-08-23 (#11338) without a matching coverage.json entry — 31 liveness kinds against 30 coverage entries. Already filed as #11421; nothing here is a fix for it, and it is the second-order cost of (1) showing up in practice. This PR's contribution to the problem list is zero: base and branch print the identical single problem.

With that one unrelated problem temporarily waived as a measurement (reverted; coverage.json sha256 unchanged), the gate goes fully green and reports the census:

check-platform-checklist: OK — 15 areas, 205 items (205 active); coverage: 30 kinds mapped,
1 waived; traps: 19 documented, 19 in use; provisioning: 4 area recipes, 7 item references
resolved (1 area-qualified) (self-checks: 22 trap-vocabulary + 34 provisioning-resolve assertions).

Gates

All on the final commit 4638ae27, exit codes captured before any pipe, each verdict quoted from the line the gate printed itself. Derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths passed — it takes the change set from the merge base), re-derived on the final commit, same 8 families both times.

gate exit verdict line
check:cross-package-test-inputs 0 OK: 14 package(s) read outside themselves, all declared…
check:doc-authoring 0 ✓ doc authoring guard: 389 files clean
--filter @objectstack/lint check:doc-formula-expressions 0 ✓ … 22 record-scoped formula example(s) across 420 files / 1449 TS blocks judged clean
check:entry-guard 0 ✓ … 139 scripts/ file(s) — every entry guard goes through invoked-as.mjs
check:parse-guard 0 self-test + scan clean
check:pnpm-filter-targets 0 ✓ … 120/148 --filter occurrence(s) … resolve
scripts/check-ci-filter-parity.mjs 0 OK: all 89 declared cross-package glob(s)…
scripts/check-cross-package-test-inputs.mjs 0 OK: 14 package(s) read outside themselves, all declared
check:nul-bytes 0 OK (scanned 6455 text file(s) … no raw ASCII control bytes)
check:platform-checklist 1 the pre-existing #11421 problem only — identical on base and branch

eslint scripts/check-platform-checklist.mjs exit 0. The repo-wide pnpm lint was narrowed deliberately, and the narrowing is a measurement: eslint --print-config on the changed file reports parserOptions.project, projectService and EXPERIMENTAL_useProjectService all undefined, so type-aware linting is not enabled and this diff cannot move the verdict of any file it does not touch; --format json judged all 4 changed files, 0 problems. CI runs the full farm regardless.

Dependency closure built under scripts/pm/os-verify-lock.sh before any gate was trusted; git status --porcelain empty afterwards, so nothing generated is in this diff.

Deliberately not in this PR

No changeset: internal QA gate plus internal QA ledger, nothing published changes — same posture as #10810, which changed these same files. skip-changeset applied.

Generated by Claude Code


Generated by Claude Code

A checklist provisioning recipe is proved by one area and sometimes needed by
a second. Until now `fixtures.provisioning.use` could only name a key in the
item's OWN area, so a cross-area consumer had one option left: cite the recipe
by name in `knownGaps` prose. Prose is the one form that cannot drift-check —
rename the recipe and `search.json` moves while the sentence in
`records-forms.json` does not, silently.

`use` now has two spellings and the gate resolves both:

    "qa-scratch-authz"                      a recipe of the item's own area
    "search:qa-contributor-bound-member"    "<area>:<recipe>", any area

Option A on the second gap of #10593, ruled by the maintainer on 2026-08-22
over a shared `areas/_fixtures.json` and over "recipes stay area-local, and a
cross-area consumer duplicates". Every reference already written keeps working
unchanged — the qualifier is an addition, not a migration, and the self-test
pins that.

The lookup is two-level, so the file is now walked twice: the recipe universe
has to be complete before any item is judged, or whether a cross-area
reference resolves would depend on readdir order. Recipes are keyed by
FILENAME stem rather than `doc.area`, so a qualified reference cannot resolve
through the very area/filename mismatch the gate reports one line down.

A two-level lookup can also fail by resolving too MUCH, which no "it resolves"
assertion can see, so all three failure shapes are pinned firing and pinned
distinguishable: a real area missing the key, a missing area, and a malformed
reference (`a:b:c`, `search:`, a padded half). A bare key that some other area
defines is now told the exact qualified spelling to write. Self-test: 36 -> 56
assertions.

Converts the two cross-area prose pointers where they already sit:
`records-forms.crud-roundtrip` clause 7 opts into the recipe `search.json`
owns, and that recipe's own `knownGaps` stops saying no cross-area spelling
exists. Both consuming items take a revision bump and a history entry, per the
lifecycle rule and the precedent set when the recipe text last changed.

The unreferenced-recipe direction stays unchecked. Its stated reason has
expired — with a qualified spelling, an unreferenced recipe is unambiguously
dead text — so the deferral is now tracked at #11506 rather than resting on a
justification that no longer holds.

Note: `check:platform-checklist` is deliberately not CI-wired, so the local
run is the only signal this gate gets.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 24, 2026
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation labels Aug 24, 2026
@os-steve
os-steve marked this pull request as ready for review August 24, 2026 02:13
@os-steve
os-steve added this pull request to the merge queue Aug 24, 2026
Merged via the queue into main with commit d10e214 Aug 24, 2026
32 checks passed
@os-steve
os-steve deleted the claude/issue-10593-checklist-use-resolve-check branch August 24, 2026 02:24
os-steve pushed a commit that referenced this pull request Aug 24, 2026
`check:platform-checklist` resolved `fixtures.provisioning.use` forwards only.
The reverse direction — a recipe nobody opts into — was deliberately deferred
while cross-area reuse had no spelling: flagging it then would have settled that
open convention by accident, in the direction of "recipes are area-local".

The maintainer's option-A ruling of 2026-08-22 (#10593 gap 2, landed in #11508)
discharged that reason. Every legitimate consumer can now express itself as a
`use` from any area, so a recipe with no `use` pointing at it is unambiguously
dead text rather than possibly-referenced-from-prose.

Three definitional edges are decided rather than left to the reader:

- a reference from a `retired` item still counts. The forward direction runs on
  every item regardless of status, so a retired item's `use` must resolve and its
  recipe must exist; an active-only reading would make the two directions
  mutually unsatisfiable the moment a recipe's last consumer retired;
- the direction is suppressed while any `use` dangles, so one typo cannot also
  accuse the correct recipe it was aiming at;
- no waiver spelling is invented — the population needing one is zero, and the
  failure names the two remedies that exist (give it a consumer, or delete it).

All four recipes on the ledger are referenced by seven items, so this direction's
subject population is zero and stays that way on a healthy ledger. That makes its
green uninformative on its own, so the 19-assertion positive control runs inline
on every invocation, like the trap-vocabulary and resolve controls beside it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 1, 2026
…ectstack-ai#11847)

`check:platform-checklist` resolved `fixtures.provisioning.use` forwards only.
The reverse direction — a recipe nobody opts into — was deliberately deferred
while cross-area reuse had no spelling: flagging it then would have settled that
open convention by accident, in the direction of "recipes are area-local".

The maintainer's option-A ruling of 2026-08-22 (objectstack-ai#10593 gap 2, landed in objectstack-ai#11508)
discharged that reason. Every legitimate consumer can now express itself as a
`use` from any area, so a recipe with no `use` pointing at it is unambiguously
dead text rather than possibly-referenced-from-prose.

Three definitional edges are decided rather than left to the reader:

- a reference from a `retired` item still counts. The forward direction runs on
  every item regardless of status, so a retired item's `use` must resolve and its
  recipe must exist; an active-only reading would make the two directions
  mutually unsatisfiable the moment a recipe's last consumer retired;
- the direction is suppressed while any `use` dangles, so one typo cannot also
  accuse the correct recipe it was aiming at;
- no waiver spelling is invented — the population needing one is zero, and the
  failure names the two remedies that exist (give it a consumer, or delete it).

All four recipes on the ledger are referenced by seven items, so this direction's
subject population is zero and stays that way on a healthy ledger. That makes its
green uninformative on its own, so the 19-assertion positive control runs inline
on every invocation, like the trap-vocabulary and resolve controls beside it.


Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants