Skip to content

fix(spec): the step-18 upgrade rationale states the element data-binding ruling in words instead of a tracker id - #24201

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-24179-step18-rationale-tracker-ids
Oct 17, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-24179-step18-rationale-tracker-ids

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24179

Clause-②: no

Two STEP18_RATIONALE fragments in packages/spec/src/migrations/registry.ts.template told the upgrading author "(#11509, ruling A-narrow…)": a tracker number and a ruling letter. os migrate meta --from 17 prints that text for the 17 → 18 hop (packages/cli/src/commands/migrate/meta.ts:933, hop.rationale), and the generated upgrade guide renders it (packages/spec/scripts/build-upgrade-guide.ts:114). Each parenthetical now states what was decided, with the ruling's date, in the ruled DATE … form the earlier step-18 sweep (f623e2f71) used for the rest of the list. Text only: fragment ids, orders and the other 122 fragments are byte-identical. Scope is triage's grade 6236131058: these two strings, no new gate for text: fields.

Dev executor for the domain:spec seat 1 PM (claim 6236550221, session session_01TyRhWbVbbQpQJTDbW8VahJ).

What changed

fragment id before after
element-flat-data-binding-retired "…second data door (#11509, ruling A-narrow): the flat…" "…second data door (ruled 2026-10-08, which leaves the object-* blocks their native keys): the flat…"
object-grid-default-filters-retired "…defaultFilters (#11509, ruling A-narrow, in the shape of the defaultSort retirement): the legacy…" "…defaultFilters (ruled 2026-10-08 together with the element layer's flat binding keys, in the shape of the defaultSort retirement): the legacy…"

Where the words come from. The ruling of record is comment 6051498447 on the tracker: the maintainer's 「11509 同意」 of 2026-10-08T03:20Z, letter A-narrow. In its words: the element layer's ten flat data-binding keys retire and object-grid.defaultFilters retires with them, while "the object-* block layer keeps its native keys"; sub-question 1 says defaultFilters "retires with a conversion in the shape defaultSort's took". The first sentence already said that an element now binds through dataSource only, so its parenthetical carries the part it did not say: the narrowing, meaning the block layer keeps its keys. The second keeps its defaultSort clause and gains what the ruling joined it to. Neither parenthetical names ADR-0049: the ruling decides a synonym consolidation (one data door per element) and does not cite enforce-or-remove.

Provenance. The #11509 id stays in the // comment at the head of each fragment's D3 entry, the file the fragment id names: packages/spec/src/migrations/entries/semantic/18.element-flat-data-binding-retired.ts:5 and 18.object-grid-default-filters-retired.ts:5, both // #11509 (v18, ruling A-narrow). No // comment was added inside the list, though the dispatch suggested one. scripts/step18-rationale-merge.test.ts parses the list against a fixed element shape (id, order, text, then the literal chain) and fails on any residue. Measured on a scratch copy with that test's own ELEMENT regex: a // #11509 … line put above the element, or between id: and order:, stops the parse at fragment 28 of 124 (residueOk false). The list has no // lines today, and the f623e2f71 sweep added none.

Changeset .changeset/24179-step18-rationale-tracker-ids.md, @objectstack/spec patch. The text ships: after pnpm --filter @objectstack/spec build, dist/migrations/index.js and dist/migrations/index.mjs carry the new wording (2 files), and the old second data door (#11509 occurs 0 times in dist/. Positive control: the neighbouring conversion id action-block-endpoint-to-target occurs in 8 dist/ files. protocol-upgrade-guide.md is in files[] and is generated at publish. No committed generated artifact moves: check:generated reports all 14 up to date, and registry.ts is gitignored.

Measured (tree objectstack-ai/objectstack at base 2bcaefba9, head f953eaa70)

  • Premise. git grep -n '#11509, ruling A-narrow' packages/spec/src/migrations/registry.ts.template at base gives 2 hits, :1746 and :2336. Control: STEP18_RATIONALE gives 3 hits in the same file (:41, :1207, :3319).
  • Re-scan of every # followed by digits on the template's non-comment lines (base). 6 lines. 2 are the targets. The other 4 (:279, :665, :756, :910) are Prime Directive #12 / PD #12 / Prime Directive #10 in step 17's rationale. Those are directive numbers, not tracker ids. None is in STEP18_RATIONALE.
  • The parsed list, using the merge test's own parser and evaluating each literal chain. At base: 124 fragments, 2 carry a # followed by digits (element-flat-data-binding-retired and object-grid-default-filters-retired, each #11509). At head: 124 fragments, 0 do.
  • What the author sees. Read through the generated registry module (MIGRATIONS_BY_MAJOR[18].rationale, 121,772 chars), the head text has 0 # followed by digits. tsx scripts/build-upgrade-guide.ts --out SCRATCH writes a guide with 0 occurrences of #11509, and the new wording appears.
  • No test pins either sentence. git grep for "second data door", for the old defaultFilters parenthetical and for ruling A-narrow in non-comment test lines finds nothing. The two tests that read these entries (element-flat-binding-retirement.test.ts, page-component-filter-record-to-rule-array.test.ts) assert conversionIds and semantic ids only.

Tests and gates (all at f953eaa70)

  • pnpm --filter @objectstack/spec build: VERDICT command-exit 0.
  • Full local spec suite: pnpm --filter @objectstack/spec exec vitest run --project local --maxWorkers=2 gave Test Files 691 passed (691), Tests 20961 passed, 1 todo, VERDICT command-exit 0.
  • Repo-project files that pin this file's shape, run locally because they are the edited file's own pins: scripts/step18-rationale-merge.test.ts and src/ui/element-flat-binding-retirement.test.ts gave 2 files, 65 tests passed. The other 65 repo-project files are CI's (Test Core).
  • pnpm --filter @objectstack/spec typecheck (tsc, scripts typecheck and test typecheck): VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec check:generated: exit 0, "All 14 generated artifacts are up to date".
  • Derived gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack gave 80 commands, and --ran reconciliation says 80 derived, 79 run, 1 NOT-MEASURED, 0 UNRUN. 79 exited 0. pnpm check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET: it needs every package's dist, which needs a whole-repo build), so it is NOT MEASURED locally and left to CI's Lint & Repo Gates. Four gates first exited non-zero because of how I ran them, and each was re-run green on a stable dist. check:doc-formula-expressions and check:lean-entry-closure first exited 3 because their prerequisite builds were missing; they passed after building @objectstack/lint and @objectstack/objectql. check:entry-nameability and check:exported-any first read a dist that a concurrent rebuild of mine was rewriting. All 19 derived commands that overlapped that rebuild (17 spec check:* gates, check:changeset-gate-self-tests and check:cross-package-test-inputs) were re-run too, all green.
  • node scripts/check-nul-bytes.mjs: exit 0. A control-byte grep over both changed files gives no hits.

Acceptance notes

  • Observation, no card filed. Step 17's rationale (registry.ts.template:279, :665, :756, :910) and several step-18 conversion texts in the generated guide cite Prime Directive #12 / #10 / #2. Those are AGENTS.md directive numbers, not tracker ids, so they fall outside this card's class. The text is already published, and nobody carries it.
  • origin/main moved one commit past the base (7d6ec91d2, packages/cli only, no overlap with this diff). The branch was not merged forward; PR CI and the merge queue validate the merged tree.
  • check:doc-authoring still does not reach text: fields. Per the triage grade, no gate is added.

Generated by Claude Code

…ing ruling in words instead of a tracker id

Two STEP18_RATIONALE fragments, the ones `os migrate meta` prints for
the 17 -> 18 hop and the upgrade guide renders, cited their decision as
a tracker number and a ruling letter. Each parenthetical now states the
decision with the ruling's date: the element layer loses its second
data door while the object-* blocks keep their native keys, and
object-grid's defaultFilters retires together with the element layer's
flat binding keys, in the shape of the defaultSort retirement.

Text only: fragment ids, orders and every other fragment are unchanged.

Claude-Session: https://claude.ai/code/session_01TyRhWbVbbQpQJTDbW8VahJ
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Oct 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/migrations/registry.ts.template), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/src/migrations/registry.ts.template) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 143 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 1489952946603ea3d9212f5d69bb7f16952f185a → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f953eaa7047ecd306e2137a395fe038fe0e1f7bf
Local-runs: none
Scope: packages/spec/src/migrations/registry.ts.template + packages/spec/src/migrations/entries/semantic/18.element-flat-data-binding-retired.ts, packages/spec/src/migrations/entries/semantic/18.object-grid-default-filters-retired.ts, packages/spec/scripts/step18-rationale-merge.test.ts, packages/spec/scripts/build-migration-registry.ts, packages/spec/scripts/build-upgrade-guide.ts, packages/cli/src/commands/migrate/meta.ts, scripts/check-doc-authoring.mjs

Inputs: card #24179 (body, triage 6236131058, claim 6236550221, os-dev-report 6237361136); PR #24201 body, file list (2 files, +15/-3) and its diff against main, byte-identical (index lines aside) to the three-dot diff of main and the branch fetched into this clone at merge-base 2bcaefba9; the check-runs on f953eaa70; the ruling of record on #11509 (comment 6051498447). Not read: the dispatch order. origin/main at read time is 8a88901be, three commits past the merge-base; the one packages/spec file they move is src/ui/component.zod.ts (TSDoc), nothing this diff's text reaches, and this PR commits no generated artifact (registry.ts is gitignored, the guide is generated at publish), so no artifact can be jointly wrong.

① Derived judgments

  • Accept set: unchanged — right. The diff edits two text: string chains inside STEP18_RATIONALE; id and order of both elements are byte-identical, the list still parses as 124 elements with zero comment lines (checked at head with the merge test's own ELEMENT shape), and no Zod schema, conversion entry, migration entry, export or type moves.
  • Public surface: shape unchanged, one value changed — right, and at the right layer. MIGRATIONS_BY_MAJOR is exported from @objectstack/spec/migrations (api-surface/migrations.json); only the string [18].rationale evaluates to changes. renderRegistry in build-migration-registry.ts emits every non-marker template line verbatim, so the new wording reaches registry.ts and dist/migrations/index.{js,mjs} as written. The two consumers print it verbatim and are untouched: os migrate meta (meta.ts:933, hop.rationale) and the upgrade guide (build-upgrade-guide.ts:114, step.rationale). A producer-side text fix with no consumer accommodation is the correct shape under Prime Directive Add comprehensive test suite for Zod schema validation #12.
  • Runtime-string rule: closed for the card's class. At base the template's non-comment lines carried #11509 at :1746 and :2336; at head a scan for a hash followed by digits on non-comment lines finds only step 17's four Prime Directive #12 / #10 citations (:279, :665, :756, :910), which are directive numbers, not tracker ids, and outside this card. check:doc-authoring's id population (#[0-9]{3,5} over *.ts|*.mts) does not scan the .ts.template text: fields, as the card states; the fix does not depend on it.
  • Wording against the ruling — right. Comment 6051498447 on [Direction · v18] Retire the flat object/filter data-binding family — dataSource as the single data-binding door (re-anchor of the deleted #6590 tracker) #11509 (「11509 同意」, letter A-narrow, 2026-10-08) says the element layer's flat keys retire, "the object-* block layer keeps its native keys", and (sub-question 1) object-grid.defaultFilters "retires with a conversion in the shape defaultSort's took". Fragment 1's "(ruled 2026-10-08, which leaves the object-* blocks their native keys)" and fragment 2's "(ruled 2026-10-08 together with the element layer's flat binding keys, in the shape of the defaultSort retirement)" each restate exactly that. The ruled DATE form is the one the f623e2f71 sweep used at :2187, :2457, :2459. Not naming ADR-0049 is right: the ruling decides a synonym consolidation and does not cite enforce-or-remove.
  • Provenance kept. // #11509 (v18, ruling A-narrow) stands at line 5 of both D3 entry files the fragment ids name, so the card's "keep the id in the // comments beside the entries" is met, and the dispatch's hold-off on // and * comments is respected.

② Semver level

.changeset/24179-step18-rationale-tracker-ids.md: @objectstack/spec patch, Clause-②: no, the same line the PR body carries. Right: the diff publishes a changed string value inside an existing export and nothing else — no key, export, type or conversion is added, removed or narrowed — so no with no arm is the only well-formed declaration, and patch is the floor a published fix takes (not skip-changeset: the text ships in the tarball and the upgrade guide). The changeset body states the before and after in words and carries no tracker id itself. Check Changeset is success on this head. The changeset prose face is the dispatching seat's ACCEPT per contract-review.md; it is judged here for level and declaration only.

③ Boundary flags

Dev flags (os-dev-report deviations; open_questions is empty):

  1. No // provenance comment inside the list — answered, correct. The merge test's sticky ELEMENT regex pins {, id:, order:, text: byte-for-byte and fragmentsOf requires zero residue, so a comment above an element or between id: and order: cannot parse, as the dev measured. One position the probe did not try — a six-space-indented // line inside the text: chain — would pass the regex and runInNewContext, but it would be the list's first comment line (zero today, the sweep added none) and the dispatch holds comments off; the D3 headers already carry the id. Not a defect, no change asked.
  2. Two repo-project test files run locally beyond the os-dev floor — accepted; they pin the edited file's own shape; the rest is Test Core's.
  3. Self-inflicted build race, 19 gates re-run green — accepted; the head's check-runs, not the local re-runs, are the verdict of record.
  4. origin/main not merged forward — accepted; see Inputs: no overlap, the queue rebuilds the merged tree.
  5. Model-free commit trailer per AGENTS.md — accepted.
  6. check:dual-build-cjs-loads NOT MEASURED locally — accepted; it runs in Lint · repo & tooling gates, which is success on the head.

Out-of-scope finding (step 17's Prime Directive #N citations, carrier: none) — agreed: directive numbers, not tracker ids, outside this card's class; noted, no card owed. Card boundary "no new gate for text: fields" — held; the diff adds none.

Check-runs on f953eaa70 at this record's read (re-read just before posting): 39 runs; 26 success (Check Changeset, Governed Surface Queue Guard, Build Core, every Lint · lane including repo & tooling gates, Spec property liveness, Type Check · source gates, · consumer gates, · debt ledger, and the three claim and path guards among them), 6 skipped by paths filter, 0 failure, and 7 still in_progress: Test Core 1–6 and Type Check · workspace. Their conclusions are the gate verdicts; this record judges the contract. The PASS below is the contract verdict; the landing still waits on those 7 reaching success (in_progress is not a pass).

Implemented-by: claude/issue-24179-step18-rationale-tracker-ids
Reviewed-by: session_01TyRhWbVbbQpQJTDbW8VahJ

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · PR #24201 @ f953eaa704 (#24179) · domain:spec seat 1 · os-project-manager · session session_01TyRhWbVbbQpQJTDbW8VahJ · 2026-10-17T17:45Z

Reviewer of record. Every item below was checked against GitHub and the code, not against the report (6237361136 on #24179).

  • Shape: draft, base main. The first line is Fixes #24179, the body's only closing keyword, then Clause-②: no, matching claim 6236550221. 2 files, +15/−3, assignee os-project-manager. Not governed: check-governed-merges.mjs --pr 24201 finds no path on the register, 18 changed lines.
  • Premise, measured by the seat before dispatch (2bcaefba9): registry.ts.template:1746 and :2336 each carried "([Direction · v18] Retire the flat object/filter data-binding family — dataSource as the single data-binding door (re-anchor of the deleted #6590 tracker) #11509, ruling A-narrow" in a text: fragment.
  • What it lands:
    • The two parentheticals now state the decision in words, in the ruled DATE form the earlier sweep used: the element layer's second data door retires while the object-* blocks keep their native keys; defaultFilters retires together with those flat keys, in the shape of the defaultSort retirement.
    • id and order of both fragments are unchanged. A patch changeset.
    • The changeset's sentences were read against the diff. "The rest of both sentences, every other fragment, and every conversion and migration entry are unchanged" holds: two hunks, both inside the text: chains.
  • Contract review: PASS 6237578498 on this head (CONTRACT_REVIEW_TIER). It checked the wording against the ruling of record on [Direction · v18] Retire the flat object/filter data-binding family — dataSource as the single data-binding door (re-anchor of the deleted #6590 tracker) #11509 (6051498447), and agrees with Clause-②: no and patch.
  • Gates: 41 check-runs on f953eaa704, all completed: 35 success, 6 skipped, 0 failed. The five required contexts are success. Mergeable, state clean.
    • The six skips were matched by name against check-expected-skips.mjs's roster, read in the script: the four full-battery lanes, the opt-in tarball smoke, and Build Docs, which is gated on ci.yml's docs filter output, and this diff touches no docs path.
    • The script itself could not run in this checkout: it imports yaml, and the shared checkout has no installed dependencies.
  • Deviations, accepted:
    • no // provenance comment beside the fragments: the merge test's element parser refuses one, as measured; the id stays in both D3 entry headers;
    • two repo-project files run locally;
    • a self-inflicted build race, with all 19 overlapping gates re-run green;
    • main not merged in: no overlap;
    • the model-free trailer pair.
  • Out-of-scope finding: step 17's Prime Directive #N citations are directive numbers, not tracker ids: dropped — outside the card's class (the review agrees).

The PR goes to the merge queue in this act. #22444 waits on this landing for registry.ts.template.


Generated by Claude Code

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/s tooling

Projects

None yet

2 participants