Skip to content

docs(changeset): date the spec-symbol gate's export filter in the #6286 release note (objectui#9528) - #10970

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-9528-changeset-spec-symbol-claim
Sep 28, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-9528-changeset-spec-symbol-claim

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #9528

Clause-②: no — release-note prose; no contract, accept set or public surface changes (a contract review is still owed: the diff is .changeset prose)

What changes

One sentence in the pending .changeset/6286-explain-batch-cap-from-spec.md. That body publishes verbatim into @object-ui/plugin-grid's CHANGELOG at the next release, and the release PR objectui#5400 regenerates from main, so this only helps if it lands before that PR merges. The frontmatter is untouched: check-changeset-overwrite.mjs prints declared at base: @object-ui/plugin-grid: patch and declares now: @object-ui/plugin-grid: patch.

Before:

… is exactly the drift scripts/check-spec-symbol-derivation.mjs argues about — and could not catch here, because both of its scanners skip non-exported declarations and this const was module-local (objectui#5899).

After:

… is exactly the drift scripts/check-spec-symbol-derivation.mjs argues about — and could not catch here: when this change landed, both of its scanners skipped non-exported declarations, and this const was module-local (objectui#5899). objectui#6291 has since removed that filter from both scanners.

Why this wording, and why the history stays

The sentence was true when written and went false later. It is not a false sentence from the start. So the fix keeps the explanation, puts it in the past tense and dates it. Deleting it would lose true history.

1. True when the changeset landed. c38162d7c9 (#6333, 2026-08-25) added the changeset. At that commit, both scanners in the gate open with the same filter line, once in scanFileForClaims (rule 2) and once in scanFile (rule 1):

if (!hasExportModifier(stmt)) continue;

The table below counts that line and two related markers in each revision of the gate file (git show REV:scripts/check-spec-symbol-derivation.mjs | grep -c …):

revision if (!hasExportModifier(stmt)) continue; const hasExportModifier // No export filter
c38162d7c9 (#6333 lands) 2 1 0
9207c53e45^ 2 1 0
9207c53e45 (#7274, objectui#6291) 0 1 2
b120b66077 (this PR's base) 0 0 3 (two code comments plus one header mention of them)

2. False since 9207c53e45 (#7274, objectui#6291, 2026-09-02). On the base, the two scanners now carry // No export filter: a module-local declaration carrying a spec-alignment in scanFileForClaims and // No export filter (objectui#6291). A module-local declaration under a spec in scanFile. The gate's own header says the same thing: "⛔ HISTORY, NOT BEHAVIOUR. Neither scanner has an export filter today."

The order of the two commits was checked on a shallow checkout, so it needs a control leg:

  • git merge-base --is-ancestor c38162d7c9 9207c53e45 exits 0.
  • The reverse check exits 1.
  • Control leg: git merge-base --is-ancestor 62311b6419 c38162d7c9 exits 0. 62311b6419 is the gate's first commit (2026-07-30), older than both.

3. Which rule would catch this const, then and now. I measured this with a 2×2 probe, not read it off the header:

  • Fixture A is the pre-refactor(plugin-grid): import the batch-explain cap from @objectstack/spec/security #6333 hook source, git show c38162d7c9^:packages/plugin-grid/src/hooks/useRecordCrudVerdicts.ts. In it, const EXPLAIN_BATCH_MAX_RECORD_IDS = 200; is module-local.
  • Fixture B is the same file with export added. It is the control.
  • Both fixtures were fed to the scanners of both gate versions, using today's spec export set (5085 names; EXPLAIN_BATCH_MAX_RECORD_IDS maps to @objectstack/spec/security).
  • The only change to the c38162d7c9 copy was exporting its scanFile. The anchor count was checked on disk: 1 plain before and 0 after; 0 exported before and 1 after.
fixture gate at c38162d7c9: rule 1 rule 2 gate at b120b66077: rule 1 rule 2
A — module-local (verbatim) none none const finding none
B — export added (control) const finding none const finding none

What the probe shows:

  • When plugin-grid's local EXPLAIN_BATCH_MAX_RECORD_IDS has reached its own stated expiry — the spec pin now exports the constant #6286 landed, the export filter is what hid the const from rule 1. The control proves the old rule 1 flags the const as soon as it is exported.
  • Today rule 1 (the name match) reports it. DEBT is empty and no ALLOW key names it, so it would be a fresh finding and the gate would exit 1.
  • Rule 2 reports it in no cell, and no filter is involved. findClaim returns null on the const's doc comment. The comment names @objectstack/spec@17.0.0-rc.6 but contains none of the CLAIM_PATTERNS phrases.
  • So for this const, the card is right that rule 1 is the operative rule. The claim note's point is also true: both scanners dropped the filter. But that matters for rule 2 only in general, not for this const.

The new sentence therefore states only history: the filter existed when the change landed, and objectui#6291 removed it from both scanners. It asserts no live capability of the gate, so a later change to the gate cannot make it false the way the old sentence became false (AGENTS.md #9).

The other pending changesets that name the gate

git grep -l check-spec-symbol-derivation b120b66077 -- .changeset lists seven files. As a positive control, the same form of search for plugin-grid in the 6286 file counts 1. I widened the search to every spelling of the gate (spec-symbol, check:spec-symbols), which gives 17 files, and read all 17 in full. I also grepped every pending body for non-exported|unexported|not exported|export filter|hasExportModifier|export modifier|exported only and for module-local. Only the 6286 file states the export-filter property. The other 16 say nothing about it:

  • 7265-core-context-token-mirrors, 7265-data-objectstack-filter-operator-rename, 7265-components-sort-direction-bound, 7265-plugin-detail-record-alert-renderer-props, spec-symbol-mirrors-app-shell-7265, 7265-types-user-filter-field-derives, 9596-debt-issue-anchor-truthiness: these describe module-local mirrors that the rule-1 DEBT ledger carried, which fits today's behaviour.
  • console-form-container-specs-one-declaration-5596: says derivation is the gate's sanctioned form.
  • listview-comment-pair-4559: says rule 2 reads the attached comment block.
  • 9542-result-dialog-i18nlabel: names the rule-2 failure class.
  • 3162-types-ledger-batch8-verdicts, spec-pin-17-1-0-5328, spec-refresh-17-2-0-5668: ledger and pin history.
  • ci-decide-markdown-trace-9241: says the gate opens content/docs/**.
  • 8841-tree-view-config-derive and date-range-default-range-binding-4984: explain a miss by name matching (and, in 4984, rule 2's tie test). That is a different property, which I did not re-measure here.

Gates (all read at HEAD 25b8b6eeb2, the only commit on this branch)

command exit verdict line
pnpm check:changeset-claims 0 ✅ No pending changeset names a file this change touches.; self-contradiction: Every package declared across those 1 body(ies) is either not negated in its own prose, …; born-false: Line addresses read in them: 0.
node scripts/check-changeset-presence.mjs 0 ✅ No source or published contract of a released package changed in this range, so no changeset is owed.
node scripts/check-changeset-overwrite.mjs 0 (report-only) 1 modified — case 2, "CORRECTING a declaration on purpose … prose that no longer matches the change"; the declared package set is unchanged
node scripts/check-changeset-no-major.mjs 0 ✅ No changeset declares a major bump.
node scripts/check-changeset-fixed.mjs 0 ✅ All workspace packages are in the changeset fixed group.
pnpm check:control-bytes 0 ✅ check-control-bytes: OK (scanned 9240 tracked text file(s); skipped 85 binary).
pnpm check:new-line-citations 0 VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0
pnpm exec vitest run --maxWorkers=2 on the 24 scripts/__tests__/*.test.ts that mention .changeset (via os-verify-lock.sh) 0 Test Files 24 passed (24) / Tests 914 passed (914) / VERDICT command-exit 0

The 24-file set is a superset of what node scripts/markdown-test-inputs.mjs --changed - returns for this file. That helper records .changeset/** as the input of check-changeset-no-major.test.ts; the positive control is packages/plugin-dashboard/README.md, which it echoes back. No package source, gate or test is touched, so nothing else is owed. node scripts/check-governed-queue-guard.mjs --test on the file answers ✅ NOT GOVERNED.

Acceptance notes

  • spec-symbol-mirrors-app-shell-7265 reads "held six declarations … Four are now bound … and three were renamed". That is 4 + 3 against six. Its commit (14a1b92035, refactor(app-shell): bind or rename the six spec-symbol mirrors, shrinking the ledger 11 to 5 (objectui#7265 app-shell slice) #9465) removes six app-shell names from DEBT, so one name may have held two declarations. I did not measure this. That changeset has empty frontmatter, so it publishes nothing. Nobody is carrying this; it is only noted here.
  • The 24-file test run printed one fatal: Invalid symmetric difference expression 0000… line on stderr while every test passed. The SHA in it is all zeros; check-changeset-overwrite.test.ts and docs-build-trigger.test.ts are the two files in the set that spell such a SHA. I did not trace it further. It is not a failure.

Contract review

A contract review is owed and the PM seat commissions it. Everything above is meant to be re-runnable: every quoted code string, commit and command reproduces on this repo. This PR touches no gate, adds no checker, and leaves the frontmatter and bump level unchanged.

Session: https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35U


Generated by Claude Code

…filter in the past tense (objectui#9528)

The pending `6286-explain-batch-cap-from-spec.md` said both scanners of
`scripts/check-spec-symbol-derivation.mjs` "skip non-exported declarations".
That was true when #6333 landed (c38162d: both `scanFile` and
`scanFileForClaims` opened with `if (!hasExportModifier(stmt)) continue;`)
and stopped being true at 9207c53 (objectui#6291), which dropped the filter
from both. The body publishes verbatim at the next release, so the sentence
now keeps the history and dates it: skipped when this change landed, filter
since removed. Frontmatter (package, bump level) unchanged.

Claude-Session: https://claude.ai/code/session_01EBx9rvB7dufCz4at53x35U
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 25b8b6eeb26946ef72aeb396a6643d6e29f6da47
Local-runs: none

Inputs: card #9528 (body and both comments — the PM claim comment and the os-dev-report), PR #10970 (body, file list, net diff against main at the head), and the head's check-runs. Every revision cited below was read with git show / git log on the sibling checkout; nothing was built, run or re-run, and no other thread was consulted.

① Derived judgments

  • Accept set / public surface: nothing moves — right. The net diff against main is one file, .changeset/6286-explain-batch-cap-from-spec.md, +3 / −2, prose only. No source, export, schema, test or gate is touched; Governed Surface Queue Guard is green and the path is not a governed surface.
  • Frontmatter byte-identical to the base — right. '@object-ui/plugin-grid': patch on both sides: the first four lines of the file at the PR base 328abeb553 and at the head compare equal, and the file is identical at origin/main, at 328abeb553 and at b120b66077 (the branch point, 25b8b6eeb2^).
  • Provenance of the changeset — right. c38162d7c9 (refactor(plugin-grid): import the batch-explain cap from @objectstack/spec/security #6333, 2026-08-25) is the ONLY commit that ever touched the file (git log --diff-filter=A and the full git log on the path agree), so 「when this change landed」 names exactly one revision.
  • Claim 1 of the rewritten sentence — the export filter existed in BOTH scanners when the changeset landed — TRUE. At c38162d7c9 the gate scripts/check-spec-symbol-derivation.mjs holds if (!hasExportModifier(stmt)) continue; exactly twice: once inside export function scanFileForClaims (rule 2) and once inside function scanFile (rule 1). 9207c53e45^ reads the same: 2 filter lines, 1 helper definition, 0 No export filter comments.
  • Claim 2 — objectui#6291 has since removed that filter from both scanners — TRUE. At 9207c53e45 (fix(tooling): drop the derivation gate's export filter — rule 2 as a one-liner, rule 1 scoped #7274, 2026-09-02) the filter line occurs 0 times and the two // No export filter comments sit in the same two functions (scanFileForClaims, scanFile); the hasExportModifier helper is still defined there but has no call site (its only other mentions are two header lines). The commit message names the ruling twice: 「Half 1 of the split ruled on objectui#6291」 and 「Half 2 of the split ruled on objectui#6291」. Ancestry: c38162d7c9 is an ancestor of 9207c53e45, the reverse is not, and 9207c53e45 is an ancestor of the PR base — so the old sentence was true when written and became false at 9207c53e45, which is what the PR body claims and what the new sentence records. On the base the helper is gone (0 definitions) and the gate's own header reads 「HISTORY, NOT BEHAVIOUR. Neither scanner has an export filter today」; the rewritten sentence agrees with it.
  • Does the sentence still say why the gate could not catch that const — yes. It keeps both halves of the cause (the scanners skipped non-exported declarations; the const was module-local, objectui#5899), dates them to the landing, and records the removal. It asserts no live capability of the gate, so a later gate change cannot falsify it the way 9207c53e45 falsified the old wording (objectui AGENTS.md 完善设计器的每一个细节 #9). One precision remark, not a defect: the dev's own 2×2 probe shows rule 2 never reports this const in any cell (findClaim returns null on its doc comment), so the filter was the operative cause for rule 1 only; the sentence does not claim otherwise.
  • The REST of the body, read at the head — no false statement; one dated one, carried to ③. Checked on the head or in the objectstack sibling: the hook imports EXPLAIN_BATCH_MAX_RECORD_IDS from @objectstack/spec/security and chunks by it; the pre-change hook at c38162d7c9^ carried const EXPLAIN_BATCH_MAX_RECORD_IDS = 200; under a comment naming 17.0.0-rc.6 and 400 VALIDATION_FAILED; the rc→17.0.0 pin bump is 7484f7f0a8 (chore(deps): bump @objectstack/spec from 17.0.0-rc.6 to 17.0.0 #4953, 2026-08-17, before the changeset landed, so 「It has.」 holds); the spec source exports EXPLAIN_BATCH_MAX_RECORD_IDS = 200 and its TSDoc says an over-cap batch is refused at validation with HTTP 400 and never truncated, while the rest package's envelope test pins 400 VALIDATION_FAILED for a request failing ExplainRequestSchema; both named tests exist at the head (useRecordCrudVerdicts.batchCap.test.tsx stubs the spec module through vi.mock and captures the real cap as its control; rowRecordCrudVerdict.test.tsx imports the export and binds its cap to it — its only literal 200 is an HTTP status); the kept half of the comment sits on the import at the head. The tarball reading (rc.6 lacks the export, 17.0.0 / 17.1.0 / 17.2.0 carry it) is a measurement of immutable artefacts and was not re-taken.

② Semver level

  • Frontmatter unchanged at '@object-ui/plugin-grid': patch — right for what the ORIGINAL change publishes (an import replacing a value-equal local const; no value, no behaviour, no surface change), and this PR publishes nothing of its own: a .changeset/*.md-only diff owes no changeset (Changeset Declaration green), declares no major (Changeset Bump Policy green), and @object-ui/plugin-grid is in the fixed group of .changeset/config.json, so patch is a valid level for it.
  • The PR body's Clause-② declaration — value no, followed by the reasoning 「release-note prose; no contract, accept set or public surface changes …」, and identical on the card's claim comment — is a line-initial fixed key named once, a value token no, no parenthetical arm, not a quoted-and-continued span: under clause2-line.mjs it reads declared / no / arm null. Well-formed, and right: nothing widens or narrows.

③ Boundary flags

  • open_questions: the dev declared none — nothing to answer.
  • Dev deviation 1 (commit trailers are the model-free pair; PR footer is the session-URL form): both are the forms AGENTS.md prescribes for those surfaces, and the harness reminder's model-named trailer is the documented exemption — no action.
  • Dev deviation 2 (the local test set widened from 「reads .changeset/」 to 「mentions .changeset」, 24 files): a superset of the adjudicated reader — no action; the head's Test shards are the gate of record.
  • Dev acceptance note (one fatal: Invalid symmetric difference expression stderr line naming an all-zero sha during the local run, every test passing): a local-run artefact, not a property of this diff; the check-runs on the head decide — not escalated.
  • Dev out-of-scope note — .changeset/spec-symbol-mirrors-app-shell-7265.md says 「held six declarations … Four are now bound … and three were renamed」, 4 + 3 against six. Real contradiction, confirmed: its commit 14a1b92035 (refactor(app-shell): bind or rename the six spec-symbol mirrors, shrinking the ledger 11 to 5 (objectui#7265 app-shell slice) #9465) removed six names from DEBT (AdminScope, AppLike, FlowEdge, FlowRuntimeState, ObjectLike, RemoteTable) and the same commit's ledger comment says 「six names, seven sites」 — ObjectLike is both bound (Picked down in useTrackRouteAsRecent) and renamed (in deriveRelatedLists, to MergedObjectLike). 「Six declarations」 should read six names / seven declarations. It publishes nothing: its frontmatter is empty (--- immediately followed by ---), so the sentence never reaches a CHANGELOG. ⛔ Not fixed here — another card's body, and this seat is read-only. Left to the adopting seat to file or leave.
  • The dated ^17.0.0 sentence from ①: not the card's sentence, not false, publishes as the history of that change. Escalated to the adopting seat as a possible one-sentence follow-up of the same class as finding(changeset): a pending changeset says the spec-symbol gate skips non-exported declarations — objectui#6291 made that false, and it publishes verbatim #9528, lower stakes; it does not hold this PR.
  • Ordering the PR body itself flags: the release PR objectui#5400 regenerates from main and deletes this file at publication, so the correction only lands if this PR merges first. Not verified here (that PR is outside this brief's inputs); the adopting seat orders the landing.

Check-runs on the head, read at 2026-09-28T12:11Z (their conclusions are the gate verdicts): 41 runs, 38 completed success, 3 completed skipped (Test (coverage), dependabot, and the coverage-shard matrix entry whose name is the workflow's own unexpanded placeholder), 0 failures, 0 still running. Nine were in progress at the first read (the eight Test (shard N/8) runs and Spec Main Shape Gate) and were waited on in the foreground until they completed — all success. Lint, Type Check, Changeset Declaration, Changeset Bump Policy, Changeset Claim Re-read, Changeset Overwrite Report, Line Citation Gate, Control Byte Scan and Governed Surface Queue Guard are all success.

Implemented-by: claude/issue-9528-changeset-spec-symbol-claim
Reviewed-by: session_01EBx9rvB7dufCz4at53x35U

VERDICT: PASS

Posted 2026-09-28T12:11Z.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 28, 2026 12:14
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 7a9db91 Sep 28, 2026
43 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-9528-changeset-spec-symbol-claim branch September 28, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants