Skip to content

docs(skills): teach that a save and os validate refuse titleFormat - #30096

Merged
os-zhuang merged 2 commits into
mainfrom
claude/project-thread-1hmgmw
Nov 4, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/project-thread-1hmgmw

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Requested by Irene · project thread

Fixes #29506

Clause-②: no
Metadata-protocol: none

The maintainer waived the model-tier mandate for skills/** while that tier had no quota; this PR was developed below it.

维护者速读

What changes

The refusal is read off main, not the card: packages/lint/src/validate-record-title.ts (validateTitleFormatRetired, severity error, rule title-format-retired, registered in authoring-rules.ts with surfaces: CLI_AND_RUNTIME) and packages/spec/src/migrations/entries/semantic/18.object-title-format-refused.ts ("os validate, os build, os lint and the metadata save gate (422 INVALID_METADATA) refuse the key as title-format-retired, an error").

Token ratchet (no ceiling row moved, no re-wrap)

file tokens before / after / ceiling bytes before / after
skills/objectstack-data/SKILL.md 6119 / 6116 / 6123 24493 / 24482
skills/objectstack-formula/SKILL.md 5956 / 5950 / 5997 23842 / 23819

Why

PR #29499 made a save and os validate refuse an authored titleFormat (ruling 6574393684). The skills still taught "deprecated, not removed" and the ADR still said "advisory, not an error", so an author following them would write a key the platform refuses.

Verification

Head f27efd1d (two commits on d79eecfe: c2236e37, then the S1 ADR follow-up).

Local gates on f27efd1 (and on c2236e3 before it): 50 derived, 50 run with exit 0, 0 NOT MEASURED (`dispatch-gates --ran`)
  • pnpm install --frozen-lockfile and a full pnpm build (exit 0) ran first (on c2236e3; f27efd1 touches only the ADR, so the build was reused), then every command from node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, each with a 900 s timeout and its exit code captured before any pipe.
  • All 50 exited 0, among them check-skills-token-ratchet.mjs (and --self-test), check-adr-links.mjs, check:adr-anchors, check:adr-index, check:adr-symbol-anchors, check-changeset-no-major.mjs, check-empty-changeset.mjs, check:changeset-gate-self-tests, check-comment-mask-corpus.mjs, check:corpus-claim-drift, check:cross-package-test-inputs, check:doc-authoring, check:doc-formula-expressions, check:skill-docs, check:skill-identifier-liveness, check:skill-frame-sync, check:skill-compatibility, check:dts-closure, check:dual-build-cjs-loads and check:role-word.
  • --ran printed: 50 derived famil(ies) accounted for — 50 run, 0 NOT-MEASURED.
  • node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD: exit 0.
  • Writes: two git push (c2236e3, f27efd1); one relay pr_create; no GitHub MCP write.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (No schema touched.)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint is CI's repo-wide run.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 block is the repo's own Chinese reading aid).

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8VVAkUoyAGLYtHWmyX2YW

The objectstack-data properties table and the objectstack-formula template
carriers now say the metadata save gate and os validate refuse titleFormat
(title-format-retired) and that it moves to nameField. ADR-0079 D3 gains a
dated amendment note citing ruling 6574393684 and PR #29499.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAkUoyAGLYtHWmyX2YW
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Nov 4, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract-review-claim: session_01J8VVAnMUWA9rufXzFaEh4J · head c2236e3 · 2026-11-04T13:26Z

The seat review runs at CONTRACT_REVIEW_TIER in an isolated subagent (the seat session is not at that tier). No review seat (lanes/review.md) is seated.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c2236e3772d92ea0c1e381f3267cfde30bac7e74
Local-runs: probe — on a detached worktree of the head (merge-base with origin/main d79eecf, the head's own parent; origin/main at 61b487b when fetched, five commits past the merge-base, none of which touches skills/objectstack-data/SKILL.md, skills/objectstack-formula/SKILL.md, docs/adr/0079-record-display-name.md or scripts/check-skills-token-ratchet.mjs): node scripts/check-skills-token-ratchet.mjs on the head (exit 0: skills/objectstack-data/SKILL.md 6116 / 6123, headroom 7; skills/objectstack-formula/SKILL.md 5950 / 5997, headroom 47) and again with both merge-base files swapped into the same worktree (exit 0: 6119 / 6123 and 5956 / 5997, then restored with git checkout HEAD --, git status --porcelain empty) plus --self-test (exit 0, 97 cases); node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (50 commands on stdout, matching the dev record's 50); node scripts/pm/check-skill-id-lint.mjs (110 files clean, exit 0) and --self-test (23 cases); node scripts/check-skill-identifier-liveness.mjs (486 citations over 71 published files, exit 0) and --self-test; check-skill-compatibility-version.mjs, check-skill-frame-sync.mjs, check-role-word.mjs (live and self-test), check-adr-links.mjs (979 destinations resolve) and --self-test, check-adr-anchors.mjs and --self-test (133 assertions), adr-index.mjs --self-test (46 assertions) and --report (README current), check-adr-symbol-anchors.mjs (3077 anchors across 149 records resolve) and --self-test, scripts/pm/check-prior-rulings.mjs --self-test (155 cases), all exit 0; node scripts/pm/check-governed-merges.mjs --branch HEAD (exit 3, GOVERNED, Tier H, 3 of 4 paths hit — docs/adr/** ×1, skills/** ×2 — 31 changed lines); node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD and --range d79eecfe5b..HEAD (exit 0, one commit, model-free trailer pair); node scripts/check-empty-changeset.mjs --base origin/main (exit 0, one declaring changeset added, none from the merge-base modified) and --self-test (165 assertions); node scripts/check-changeset-no-major.mjs --base origin/main (exit 0, level axis not applicable locally); check-adr-0087-registration.mjs --base origin/main (exit 1: input problem, no tsx under the worktree — NOT MEASURED here, read from CI), check-doc-authoring.mjs, check-closing-keyword-parity.mjs and check-comment-mask-corpus.mjs (each exit 3 PREREQUISITE NOT MET in this container: no node_modules under the worktree; nothing measured, read from CI); wc -c / wc -l on both trees and on the touched lines alone; diff of each file pair with the touched lines removed (byte-identical remainders); git diff --word-diff=porcelain (5 changed segments, all inside the touched lines); grep over skills/** (evals included), packages/** and scripts/** for the cut text and the old reading; git merge-base --is-ancestor 3557366c02 d79eecfe5b (true); gh api REST reads of the PR, its files, commits, comment and reviews, card #29506 and its three comments, PR #29499's merge record, rulings 6574393684 and 6513306068, and the head's check-runs twice. The worktree was removed after the runs and the main checkout was not touched.
Scope: skills/objectstack-data/SKILL.md (the governed hit: the titleFormat row L90), skills/objectstack-formula/SKILL.md (the governed hit: the template row L459 and the cut at L461–462), docs/adr/0079-record-display-name.md (the governed hit: the amendment block under D3, L129–139) + read, not reviewed: .changeset/29506-title-format-refused-teaching.md (the prose face, checked sentence by sentence here), packages/spec/src/migrations/entries/semantic/18.object-title-format-refused.ts (the whole entry), packages/lint/src/validate-record-title.ts (the module note L7–36, TITLE_FORMAT_RETIRED, validateTitleFormatRetired L63–97 with its severity: 'error' and the [#22161] hint comment, validateRecordTitle L100–135), packages/lint/src/authoring-rules.ts L1551–1572 (the validateTitleFormatRetired registration: tier: 'gating', surfaces: CLI_AND_RUNTIME, runtimeTypes: ['object']) and L1576–1585 (validateRecordTitle, tier: 'advisory'), packages/lint/src/rule-explanations.ts L3078–3100 (TITLE_FORMAT_RETIRED_EXPLANATION, what os explain title-format-retired prints), packages/cli/src/commands/explain.ts L7, L478–525 (the wiring), packages/lint/src/validate-record-title.test.ts L59–87 and L168–193 (the error pin and the os explain facts pin), packages/lint/src/runtime-gate.object-writes.test.ts L461–488 (the save-gate refusals), packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts L938–972 (the stored-object 422), packages/cli/test/validate-title-format-retired.test.ts L86–97, packages/spec/src/data/object.zod.ts L3404 (the titleFormat describe), packages/spec/liveness/object.json L41–44, docs/adr/0079-record-display-name.md in full (Provenance, D2, D3 body L141–160, D8 L235–248, Status table, Open question 3 L302–309, Alternatives), docs/adr/README.md L7–8 (the status-line convention), docs/adr/0015 and docs/adr/0035 (the inline amendment-note form), scripts/check-skills-token-ratchet.mjs L513–514 (the two ceiling rows), scripts/check-commit-card-trailers.mjs L320 and L848 (what the repo counts as a model identifier), skills/README.md L74–75, packages/skills/package.json, card #29506 body, comments 6583207819 and 6588349408 (triage) and 6631259687 (claim), PR #30096 body and its one comment 6631861192 (the seat's review claim on this head), PR #29499's merge record (3557366c02, merged), ruling 6574393684 (#29007, letter B) and ruling 6513306068 (#27847, the ratchet path), the dev gate record pr-29506/gates-c2236e37.txt and body.md (read as input)

Reviewer: an isolated contract reviewer at CONTRACT_REVIEW_TIER, read-only on GitHub (REST reads only; nothing written, pushed or commented), fed the card body and comments, the PR body, the net diff against the merge-base, the head's check-runs, AGENTS.md, the pm-dispatch SKILL.md contract-review section, contract-review.md, review-checklist.md, lanes/skills.md and lanes/review.md. The dev gate record was read as input, not as conclusions; every count and every claim about the lint rule, the save gate and the ADR below is this review's own reading of the head tree and of main at the merge-base. No environment variable value is printed anywhere in this record.

① Derived judgments

  1. File surface. One commit (c2236e3, author Claude, PR author objectstack-fleet[bot], head repo = base repo, draft, base main, trailers Co-Authored-By: Claude + Claude-Session:, no model identifier). git diff --stat d79eecfe5b c2236e3772, the REST file listing (+27 / −4, 4 files) and the PR body agree on exactly four paths: skills/objectstack-data/SKILL.md +1/−1 (464 → 464 lines), skills/objectstack-formula/SKILL.md +3/−3 (487 → 487), docs/adr/0079-record-display-name.md +12/−0 and .changeset/29506-title-format-refused-teaching.md +11/−0 (new). The claim (6631259687) named exactly these: the data row L90, the formula row L459, a dated amendment note at D3 with the decision not reopened, one '@objectstack/skills': patch changeset, skill text paid in place within the ceiling. Nothing else is touched; the ratchet script is not in the diff. Correct, and on surface.
  2. The refusal the two rows assert, read at the merge-base (PR feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499's merge 3557366c02 is an ancestor of d79eecf). validateTitleFormatRetired (validate-record-title.ts L75–97) returns one finding per declaring object with severity: 'error' and rule: TITLE_FORMAT_RETIRED = 'title-format-retired' (L39); its registration (authoring-rules.ts L1563–1572) is tier: 'gating', surfaces: CLI_AND_RUNTIME (= ['cli', 'runtime-publish'], L476), runtimeTypes: ['object'], commands: ALL, so the same rule runs under os validate / os build / os lint and at the runtime publish gate. The pins: validate-record-title.test.ts L59–66 ("REFUSES (errors) when titleFormat is declared — ruling of record 6574393684, letter B", severity 'error'); runtime-gate.object-writes.test.ts L461–468 ("REFUSES an object that declares a titleFormat (validateTitleFormatRetired)", the single refusal title-format-retired) and L471–481 (the re-save of a stored object carrying it is refused too); protocol.draft-publish-verdict.test.ts L938–972 (a stored object carrying the key: still read, code: 'INVALID_METADATA', status: 422 on its next save, clean once the key is dropped); validate-title-format-retired.test.ts L86–97 (os validate exits 1 with title-format-retired, and the nameField control validates clean). So "a save and os validate refuse it (title-format-retired)" and "Move it to nameField" are each the code's own words; the diagnostic's name is exactly title-format-retired. Correct.
  3. What os explain title-format-retired prints (rule-explanations.ts L3078–3100, wired through explain.ts L7/L508): paragraph 1 carries the render-only reason ("titleFormat is a render-only template: the server can neither return the title it draws nor query by it, the shared title predicate (objectTitleCompleteness) never reads it, and an explicit nameField takes precedence over it"), paragraph 2 the migration and the refusal doors, paragraph 3 "An error, not a warning, though the schema still parses the key … A draft save passes; its publish is refused." The test at validate-record-title.test.ts L168–193 pins seven of those facts by substring, among them render-only template, neither return the title it draws nor query by it and an explicit \nameField` takes precedence. So both facts the data row drops — the render-only reason and "(it wins)" — have a pinned home in the explanation the lint fix:line points at (the[[maintainer] validate: the field-no-consumers warning is one 856-character line, printed by validate, build and dev alike — one-line verdict + rule: id + a pointer to the full reasoning (os explain, which today takes only schema names) #22161]comment, L86–87), and a second home in ADR-0079 D3's body ("an explicitnameFieldtakes precedence over it", L141–142, unchanged by this PR) and in thetitleFormat` describe itself (object.zod.ts L3404). Correct.
  4. The data row, merge-base L90 → head L90 (192 → 181 bytes). Old: "Deprecated, not removed (ADR-0079) — render-only: the server can't return or query it. Use nameField (it wins); a composite title follows the nameField row". New: "Refused (ADR-0079): a save and os validate refuse it (title-format-retired). Move it to nameField; a composite title follows the nameField row". "Deprecated, not removed" was false after feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 for the only reader this row has — an author deciding whether to write the key — and the new wording states the two doors the code names and the diagnostic to grep. The dropped render-only clause is a reason, not a rule: the row's rule (do not write it; write nameField) survives and is now stronger, and the reason has the homes in ①.3; within the skill, the nameField row directly above (L88) still carries "a text formula is display-only", the half of the reason an author acts on. "(it wins)" is still true at runtime (the ruling's "not honoured" arm: provisionPrimary keeps stamping the pointer, the explanation says the pointer takes precedence) but no longer decides anything an author can write: a new definition carrying both keys is refused before precedence is consulted, and a stored legacy row carrying both is served by the pointer whichever way the author reads the row. Its two homes (①.3) are pinned. lanes/skills.md's test — a cut whose content has no other home loses a rule — is met: neither cut is a rule, and both have homes. Ruling 6513306068's same-file-deletion path is the gate-recognised way to MOVE a ceiling row; no ceiling row moves here (①.7), so that path is not invoked and a home outside the file is not a question this PR raises. Correct.
  5. The formula row and its cut, merge-base L459/L461–462 → head L459/L461–462 (565 → 597 bytes over the three touched lines). The carriers cell goes from "Object.titleFormat (deprecated → nameField, ADR-0079)" to "Object.titleFormat (a save and os validate refuse it; move it to nameField, ADR-0079)": the same two facts as the data row, in the cell that lists where a template may be written, which is exactly where an author would otherwise learn the key is still a legal carrier. The cut sentence, "a template holds a path and a formatter, nothing else.", restates the same row's Grammar cell — "{{ path }} or {{ path \| formatter[:arg] }} — double braces only, no conditionals" — which is byte-identical on both trees and names the two things a template may hold and the one it may not; the instruction the sentence used to motivate, "Move logic into a CEL field", survives with its colon turned into a period. No test under packages/**, scripts/** or skills/** pins the cut sentence (grep: zero hits for holds a path and a formatter). The lines around the cut are otherwise unchanged (①.7). Correct.
  6. The ADR amendment, head L129–139, a > **Amendment (date, #card).** blockquote directly under the D3 heading — the form ADR-0015 L9 and ADR-0035 L100 use. Fact by fact against the head tree: "no longer advisory" (①.2); "ruling of record on object.titleFormat has no effect when the object authors no nameField: the registry stamps a derived nameField that outranks the template, so the record title ignores it #29007 (6574393684, letter B)" (the comment exists, is the director's ruling on object.titleFormat has no effect when the object authors no nameField: the registry stamps a derived nameField that outranks the template, so the record title ignores it #29007, letter B, and binds refusal at the save gate and os validate, not-honoured, not-deleted); "PR feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 (3557366c02) made title-format-retired an error" (the merge sha and the severity both reproduce); "the metadata save gate (422 INVALID_METADATA on an active save, a draft promotion and a restore)" (validate-record-title.ts L22–25 and the 422 pins in ①.2; authoring-rules.ts L1559–1560 says a draft save passes until it is published, which is what "promotion" names); "os validate / os build / os lint" (commands: ALL, the migration entry's own list); "refused, not removed: the schema still parses it, so a stored object that carries it keeps loading and reading until its next save" (object.zod.ts L3404, the stored-object pin L938–972); "The decision below stands" (the ruling: "ADR-0079 D3/D9 stay closed", and D3's prescription — nameField, a stored computed field for a composite title — is what the refusal's fix line prints). The amendment cites the ruling and the PR as the card asked, reopens nothing, and its "refused, not removed" is consistent with Open question 3 (L302–309), which records that this ADR uses "retired" for a key that is still live: the key is still parsed, still live in packages/spec/liveness/object.json L41–44 and still read by objectui, so the open question's residue is unchanged and the amendment does not pretend to settle it. The one clause that over-reaches is "only the 'advisory, not an error' sentence and its citation describe the code before feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499": the same paragraph's "deprecated and lint-warned" (L141) also describes the pre-feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 code (the rule is lint-ERRORED now), as do the dated Status table (L282–291, explicitly a 2026-08-08 snapshot, so legitimately historical) and Open question 3's "deprecated, lint-warned" — S1 (④). Correct, with S1.
  7. The D8 clause. D8 (L235–248) says validate-record-title "reports two warnings — title-format-retired (D3) and title-unresolvable … — and never errors", quoting a sentence of validate-record-title.ts ("Both are warnings…") that no longer exists in that file (the head's module note says the two rules "sit on different tiers", L26–27). After feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 the first half of D8 is false and the second half (title-unresolvable is a warning, validateRecordTitle never errors) is still true. The amendment's "D8's 'never errors' no longer covers this rule" is therefore accurate and narrow: it names the one rule the ruling moved and leaves title-unresolvable under D8. On scope: the card asked for "a dated amendment note at D3"; the D8 clause sits inside that note, edits no line of D8, and records a consequence of the same ruling and the same PR — without it, a reader of D3 would find D8 contradicting the amendment two sections down, which is the "decision nobody can find" Prime Directive 13 warns of. On whether an amendment may touch D8: docs/adr/** is Tier H governed text, so the whole file lands on a GOVERNED_APPROVERS approval, and the ruling itself (not this PR) is what changed D8's truth; the note records, it does not decide. What the clause does not do is leave a pointer AT D8, so a reader who lands on D8 by its anchor still reads an unqualified "never errors" and a quotation the cited file no longer carries, and the ADR's status line (L3: "Accepted — implemented") still names no amendment although docs/adr/README.md L8 makes that line "the single fact" the index is generated from and ADR-0015 / ADR-0035 / ADR-0045 / ADR-0050 / ADR-0055 record their inline amendments there: S1 (④). Accurate, in scope, allowed; the cross-reference is one-directional.
  8. Token ratchet. Measured on both trees: skills/objectstack-data/SKILL.md 6119 → 6116 tokens (ceiling 6123, headroom 4 → 7), skills/objectstack-formula/SKILL.md 5956 → 5950 (ceiling 5997, headroom 41 → 47); exit 0 on both trees, the self-test passes (97 cases), and the ratchet script is not in the diff, so neither ceiling row (L513 ['skills/objectstack-data/SKILL.md', 6123], L514 ['skills/objectstack-formula/SKILL.md', 5997]) moved. Bytes: data 24493 → 24482 (−11, all of it the L90 row 192 → 181); formula 23842 → 23819 (−23: the three touched lines 565 → 597 is +32 for the row and −55 for the cut sentence and its colon). No re-wrap: with L90 removed from both data trees the remainders are byte-identical; with L459 and L461–462 removed from both formula trees the remainders are byte-identical; the porcelain word-diff shows five changed segments, every one inside those lines. Both files shrink, so nothing was bought and nothing is owed. The PR body's "24510" for the data file's byte count before is the file one commit older than the merge-base (83d7e4a, the Version Packages merge, 24510 bytes; skills(data, query, ui): with no searchableFields declared, a field marked searchable: true joins the default search set #29912 then took it to 24493 at d79eecf): the token figures and the formula bytes reproduce, the data "before" bytes do not — S2 (③). Correct except as S2.
  9. Evals. skills/objectstack-data/evals/** and skills/objectstack-formula/evals/** carry no titleFormat, no "not removed", no "render-only", no "it wins" and no "nothing else" (grep, zero hits); the only other titleFormat under skills/** is skills/objectstack-query/rules/filters.md:203, which uses a {record.field} interpolation as an example of a column spelling and asserts nothing about the key's status. No eval asserts the old reading or the cut text. Correct.
  10. Changeset. .changeset/29506-title-format-refused-teaching.md: frontmatter '@objectstack/skills': patch; line-initial Clause-②: no and Metadata-protocol: none; prose: the two skills "no longer call titleFormat deprecated" (true, ①.4–5), "since feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 the metadata save gate and os validate refuse an object that declares it (title-format-retired), and it moves to nameField" (true, ①.2), "The formula skill drops the sentence that restated the template grammar cell beside it" (true, ①.5), "ADR-0079 D3 gains a dated amendment note citing ruling 6574393684 and feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499; the decision is unchanged" (true, ①.6). A PR number in a changeset is the convention here (27 of the 53 changesets on the head cite one), and AGENTS.md's no-tracker-number rule is for rule text and runtime strings, which a changeset is not. @objectstack/skills is published (packages/skills/package.json: no private, files declared) and ships skills/**, so a change to these two files publishes and a patch changeset is owed — AGENTS.md Post-Task Checklist step 3 and the card's Metadata-protocol none agree; skip-changeset would have been wrong. Labels on the PR are documentation, size/s, tooling: no skip-changeset. Check Changeset is success on the head, check-empty-changeset exit 0 here. Correct.
  11. Gates re-run here. The 50 derived commands match the dev record's 50. Of those re-run: token ratchet and self-test, skill-id-lint, skill-identifier-liveness, skill-compatibility, skill-frame-sync, role-word, adr-links, adr-anchors, adr-index, adr-symbol-anchors, pm-prior-rulings self-test, commit-card-trailers, empty-changeset, changeset-no-major all exit 0; governed-merges exit 3 by design. check-adr-0087-registration refuses a verdict here (no tsx), and check-doc-authoring, check-closing-keyword-parity and check-comment-mask-corpus exit 3 PREREQUISITE NOT MET (no node_modules under the worktree) — each is read from CI, where Lint · repo & tooling gates, Lint · CI, release & engine gates, Lint · docs & code guards, Lint · PM dispatch-gates and PR-body guards are all success on the head. The dev record lists all 50 at exit 0 after pnpm install and a full build; nothing I could measure contradicts it. Correct.
  12. PR body against the head. First content line Fixes #29506: the card's three Done-when items — the two skill lines (done), the dated D3 note citing ruling and PR (done), lands only after approval (a landing condition, not a deliverable) — so Fixes is the right verb; the other numbers in the body (feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499, object.titleFormat has no effect when the object authors no nameField: the registry stamps a derived nameField that outranks the template, so the record title ignores it #29007, [maintainer] validate: the field-no-consumers warning is one 856-character line, printed by validate, build and dev alike — one-line verdict + rule: id + a pointer to the full reasoning (os explain, which today takes only schema names) #22161) never sit beside a closing keyword, and PR-body guards is success. Clause-②: no and Metadata-protocol: none are line-initial and right (no spec, no key). The body's code claims reproduce: validateTitleFormatRetired severity error, rule title-format-retired, surfaces: CLI_AND_RUNTIME, the migration entry's quoted sentence (verbatim at 18.object-title-format-refused.ts L19–21), the [#22161] comment pointing the fix line at os explain. The ratchet table's token figures (6119 / 6116 / 6123; 5956 / 5950 / 5997) and the formula bytes (23842 / 23819) reproduce; the data "before" bytes do not (S2). "no re-wrap", "the two lines around the cut are otherwise byte-identical", "no ceiling row moved", "50 derived, 50 run" reproduce. Human Minimum: eight items ticked against the template; item 3 reworded ("pnpm lint is CI's repo-wide run" — Lint · ESLint is success on the head, so nothing is hidden), item 6 "not touched" (true), item 8 notes the 维护者速读 block is the repo's own reading aid (pm-dispatch SKILL.md requires it in Chinese, so true). The model note — "The maintainer waived the model-tier mandate for skills/** while that tier had no quota; this PR was developed below it." — names no model identifier of the claude-… form (check-commit-card-trailers.mjs L320) and no family or display name at all: the tier-word spelling the claim template asks for. Correct except as S2.
  13. Governance. check-governed-merges.mjs --branch HEAD: 3 of 4 paths hit (docs/adr/** ×1, skills/** ×2; the changeset is not on the register), Tier H, 31 changed lines (+27 / −4) under the 3000 threshold, exit 3 as designed; the PR is a draft, no reviews, no assignee, no requested reviewer, auto_merge null, mergeable_state blocked. Landing is the maintainer's hand or an authorized approval; this record does not lift it.

② Semver level

Patch, and the changeset says patch. @objectstack/skills publishes skills/**, so two rule-text edits in published skills are a user-visible fix with no protocol change: Clause-②: no, Metadata-protocol: none, '@objectstack/skills': patch. The ADR and the changeset publish nothing. No packages/spec/src/**, no TypeScript, no skip-changeset; Check Changeset is success on the head.

③ Boundary flags

  • Dev open_questions: none in the body. The body's acceptance notes (the render-only reason dropped for its homes in os explain and D3; "(it wins)" dropped because precedence no longer decides what an author writes; the formula cut chosen because it restates the Grammar cell; the D8 clause added so D8 does not silently contradict the amendment) are each confirmed against the code and accepted, with the one-directional cross-reference qualified in ①.7 / S1.
  • S2, a body fact that does not reproduce: the ratchet table's "24510" for skills/objectstack-data/SKILL.md before is the file's size at 83d7e4a, one commit before the merge-base; at d79eecf it is 24493, and the −11 bytes of this diff are exactly the row's 192 → 181. The token figures, which are what the ratchet grades, reproduce on both trees. Should-fix on the body's wording only; nothing in the tree is wrong.
  • Independence: PR author objectstack-fleet[bot], commit author Claude; no off-relay author note is owed. The PR thread carries the seat's Contract-review-claim: for this head (6631861192) and no other record; no review seat is seated, as the claim says. No assignee or requested reviewer on the PR.
  • Tier H: this record does not lift the landing; the maintainer's hand or an authorized GOVERNED_APPROVERS approval does, and none is on the PR (reviews: none). The one in-progress shard (below) must be read green before any Tier H act.
  • Pre-existing, not this PR's: D8's quotation ("Both are warnings: the auto-provision transform and the id floor mean a green build never ships a fully title-less object." — packages/lint/src/validate-record-title.ts) no longer appears in that file after feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499, and D3's own citation is to a since-consumed changeset; both are historical citations the reconstruction made and the card did not ask to refresh. Folded into S1 as the cheapest place to say so, not a separate card.

④ Design judgment

Per hits file, against the card's scenario (an author or agent reading the skill must learn that a save and os validate refuse titleFormat, and what to write instead; a reader of ADR-0079 must not find D3 still calling the diagnostic advisory) and the code on main:

  • skills/objectstack-data/SKILL.md, the titleFormat row: the row is the one place an author looks up whether the key may be written, and "Refused … a save and os validate refuse it (title-format-retired). Move it to nameField" is the shortest true answer — the two doors the code names, the diagnostic to grep, the prescription, and the pointer to the composite-title case in the row above. The two dropped clauses are reasons the row's reader no longer acts on, with pinned homes where the refusal sends them. Holds.
  • skills/objectstack-formula/SKILL.md, the template row and the cut: the carriers cell is where an author learns which keys may hold a template, so a carrier that is refused must say so in the cell; the cut sentence restated the Grammar cell three columns to the left and motivated an instruction that still stands on its own. The file loses nothing an author reads twice. Holds.
  • docs/adr/0079-record-display-name.md, the D3 amendment: the right form (an inline dated note under the decision it qualifies, the ADR-0015 / ADR-0035 shape), the right content (ruling, PR, the three doors, refused-not-removed, decision stands), and the one necessary cross-reference to D8. Two seams remain: the note's "only … describe the code before feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499" is not exact (the paragraph's "lint-warned" is pre-feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 too), and the cross-reference runs one way — D8 and the status line still read as if nothing moved. Holds, with S1.

Must-fix: none. Should-fix: S1 — three edits in the ADR, all prose, no decision touched: (a) in the amendment, "only the 'advisory, not an error' sentence and its citation" → "the 'deprecated and lint-warned' and 'advisory, not an error' sentences and their citation"; (b) a one-line note under the D8 heading, > **Amended (2026-11-04, #29506).** \title-format-retired` is an error since #29499 — see the D3 amendment; this section's "never errors" and its quotation now describe `title-unresolvable` alone.; (c) the status line gains · Amended (2026-11-04, #29506, ruling 6574393684 — D3 note)sodocs/adr/README.md` (generated from that line) records the amendment, as ADR-0015 / 0035 / 0045 / 0050 / 0055 do. S2 — the PR body's byte table: 24510 → 24493 for the data file's "before".

Check-runs at record time (2026-11-04T13:39Z): 42 check-runs on c2236e3, 28 success, 13 skipped, 0 failure, 1 in progress on the second read (Test Core 1/8); two reads went 27 → 28 success and 2 → 1 in progress (Test Core 2/8 completed success between them) with no non-success completion at either read. Success: Lint & Repo Gates, TypeScript Type Check (the two required floors), Lint · repo & tooling gates, Lint · CI, release & engine gates, Lint · PM dispatch-gates, Lint · docs & code guards, Lint · ESLint, Lint · scoped · tooling self-tests, Lint · scoped · slot lookup & corpus, Lint · scoped · query-options erasure, Type Check · workspace / source gates / debt ledger / consumer gates, Build Core, Governed Surface Queue Guard, Dogfood Regression Gate, Test UI, Test Core (2/8), Test Core (3/8), Plan Test Core shards, Live E2E UI, PR-body guards, Check Changeset, Check Documentation Links, Check PR Size, Auto Label, filter. Skipped by path filter or opt-in: Build Docs, Build UI Deps, Build & E2E UI, Lint UI, Type Check UI, UI Published Artifacts, Dogfood Verify CLI, Temporal Conformance, Schedule gate, 18.x upgrade harness, Packed-tarball smoke, and the matrix-templated placeholder rows for Test UI and the Dogfood shards. Combined status pending (statuses API, 0 statuses). The one in-progress shard is a full-battery test lane on a diff that touches no package source; the landing pre-check still owes a read of it green before any Tier H act. mergeable_state blocked, draft, auto_merge null, labels documentation, size/s, tooling; Tier H (docs/adr/**, skills/**), landing by the maintainer's hand or an authorized approval, not by this record.

Implemented-by: claude/project-thread-1hmgmw
Reviewed-by: session_01J8VVAnMUWA9rufXzFaEh4J

VERDICT: PASS


Generated by Claude Code

The D3 note now names both pre-refusal sentences, D8 carries a pointer back
to it, and the status line records the amendment.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8VVAkUoyAGLYtHWmyX2YW
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract-review-claim: session_01J8VVAnMUWA9rufXzFaEh4J · head f27efd1 · 2026-11-04T13:52Z

The seat delta review (against 6632133331 S1 and S2) runs at CONTRACT_REVIEW_TIER in an isolated subagent (the seat session is not at that tier). No review seat (lanes/review.md) is seated.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: f27efd1de49379837ac325045629b619f2589769
Local-runs: probe — on a detached worktree of the head (merge-base with origin/main still d79eecf; origin/main at f68b47c when fetched, ten commits past the merge-base, none of which touches docs/adr/0079-record-display-name.md, docs/adr/README.md or scripts/adr-index.mjs): node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (50 commands, matching the dev record's 50); node scripts/check-adr-links.mjs (979 destinations resolve) and --self-test; node scripts/check-adr-anchors.mjs (OK: 107 anchored files, 64961 citations resolve) and --self-test (133 assertions); node scripts/adr-index.mjs --self-test (46 assertions), --report (README current) and --check (OK); node scripts/check-adr-symbol-anchors.mjs (3077 anchors across 149 records resolve) and --self-test; node scripts/check-skills-token-ratchet.mjs (exit 0, 57 authored files within ceilings; the skills are not in this delta); node scripts/check-empty-changeset.mjs --base origin/main (exit 0); node scripts/check-doc-route-spelling.mjs --advisory (exit 0); node scripts/pm/check-governed-merges.mjs --branch HEAD (exit 3, GOVERNED, Tier H, 3 of 4 paths hit, 36 changed lines); node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD (exit 0, two commits, model-free trailer pairs); check-adr-0087-registration.mjs --base origin/main (exit 1: input problem, no tsx under the worktree — NOT MEASURED here, read from CI); check-doc-authoring.mjs, check-closing-keyword-parity.mjs, check-comment-mask-corpus.mjs (each exit 3 PREREQUISITE NOT MET: no node_modules under the worktree — read from CI); wc -c / wc -l on the ADR at the merge-base, the prior head and this head; git diff --stat and git diff --word-diff=porcelain of the delta; diff of the two ADR versions with the changed lines removed (byte-identical remainder); awk line lengths over the two notes; grep of docs/adr and content for the D8 anchor; gh api REST reads of the PR, its files, commits, reviews and three comments, comment 6632133331, ruling comment 6574393684, and the head's check-runs and combined status twice. The worktree was removed after the runs and the main checkout was not touched.
Scope: docs/adr/0079-record-display-name.md (the governed hit and the only file in the delta: the status line L3, the D3 note L129–139, the new D8 note L237–239) + read, not reviewed: docs/adr/0079-record-display-name.md L141–149 (the two sentences the D3 note names and their citation), L241–252 (D8's own text, confirmed untouched), docs/adr/README.md L7–8 and L152 (the status-line convention and the generated 0079 row), docs/adr/0015 L3, 0035 L3, 0045 L3, 0050 L3, 0055 L3–5 (the precedent status-line amendments and inline notes), scripts/check-commit-card-trailers.mjs L320 and L836–850 (what the repo counts as a model identifier), PR #30096 body and comments 6631861192, 6632133331 (the full review being continued) and 6632415025 (the seat's claim on this head), ruling 6574393684 (its issue, author and first lines), the dev gate record pr-29506/gates-f27efd1d.txt (read as input)
Delta review of 6632133331 on c2236e37

Reviewer: the same isolated contract reviewer at CONTRACT_REVIEW_TIER, read-only on GitHub (REST reads only; nothing written, pushed or commented). The full review on c2236e3 (PASS, should-fixes S1 and S2) stands as read; this record judges only the delta c2236e37..f27efd1d and the PR body as it now reads. The dev gate record was read as input, not as conclusions. No environment variable value is printed anywhere in this record. Dates quoted from the ADR's own text are described, not typed.

① Derived judgments

  1. Delta surface. One new commit (f27efd1, author Claude, subject "docs(adr): make the ADR-0079 titleFormat amendment two-way", trailers Co-Authored-By: Claude <noreply@anthropic.com> + Claude-Session:, no model identifier). git diff --stat c2236e37 f27efd1d: one file, docs/adr/0079-record-display-name.md, +7 / −4 (430 → 433 lines, 25001 → 25551 bytes). The REST file listing now reads +16 / −1 for the ADR (cumulative against the merge-base: the status line replaced, the 12-line D3 block, the 3-line D8 note) and the PR total +31 / −5 over 4 files; check-governed-merges counts the same 36 lines. The skills, the changeset and the ratchet script are not in the delta, so every figure the full review measured on them stands. With L3 and L136–138 removed from the prior head and L3, L136–138 and L237–239 removed from this head, the two files are byte-identical: nothing else changed, no other line moved or re-wrapped. Correct, and on surface.
  2. S1(a), the D3 note. The note's closing clause now reads "The decision below stands; the "deprecated and lint-warned" and "advisory, not an error" sentences and their citation describe the code before feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499, and D8's "never errors" no longer covers this rule (packages/lint/src/validate-record-title.ts, validateTitleFormatRetired)." The two quoted phrases are verbatim substrings of the paragraph directly below (L141: "titleFormat is deprecated and lint-warned, and an explicit nameField takes precedence over it."; L142–143: "so the diagnostic is advisory, not an error:"), and "their citation" is the one feat(spec,lint): ADR-0079 gate — deprecate titleFormat + record-title validator #2463 changeset quotation that follows them (L145–149). Both sentences describe the pre-feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 code — the rule is now lint-errored, not lint-warned — which is exactly the over-reach the full review's ①.6 named; "only" is gone. The porcelain word-diff shows four token changes inside the note (only → "deprecated and lint-warned" and, sentence → sentences, its → their) and the three physical lines L136–138 re-flowed to carry them; the note's first eight lines and its parenthetical are untouched. The exact spelling S1(a) offered. Resolved.
  3. S1(b), the D8 pointer. A new two-line blockquote sits directly under the ### D8 heading, before D8's first paragraph: > **Amended (<date>, #29506).** \title-format-retired` is an error since feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499; see the amendment under D3. This section's "never errors" and its quotation now describe `title-unresolvable` alone.Fact by fact: the date is the one the D3 note and the status line carry;title-format-retiredis an error since #29499 (the full review's ①.2); "see the amendment under D3" resolves — D3's block is titled "Amendment" and is the only amendment in the file; "never errors" and the quotation ("Both are warnings…") are D8's own L241–247; after #29499title-unresolvableis the one rulevalidateRecordTitlestill reports as a warning (the full review's ①.7), so "alone" is right. The form is ADR-0015 L9 / ADR-0035 L100's inline dated note, the same shape the D3 block already used. D8's own text (L241–252) is byte-identical to the prior head; the heading is unchanged, so the#d8--the-author-time-gate-is-advisory-by-designanchor still resolves (no file underdocs/adrorcontentlinks to it, butcheck-adr-anchors` is green either way). The one-directional cross-reference the full review's ①.7 described now runs both ways. Resolved.
  4. S1(c), the status line. L3 keeps its original text verbatim and gains, after a middle dot, **Amended** (<date>, [#29506](issues/29506), ruling of record [\6574393684`](issues/29007#issuecomment-6574393684) on object.titleFormat has no effect when the object authors no nameField: the registry stamps a derived nameField that outranks the template, so the record title ignores it #29007, letter B) — `title-format-retired` is an error since PR feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499; see the note under D3.Against the precedents: ADR-0035 L3 and ADR-0050 L3 use exactly this shape —· Amended (date, #card, ruling …) — one-clause summary; see the note under
    — and ADR-0045 L3 / ADR-0055 L3–5 the same convention with the date inside the bold or a longer summary; docs/adr/README.md L8 listsAmendedamong the keywords the generated index reads from that line. The two links resolve by REST: issue 29506 is the card, and comment 6574393684 is on issue 29007, by the director seat, headed "Ruling: batch #454 item 1 · letter B", which is the ruling the D3 note cites.adr-index --checkreports the README current and--reportthe same, so the generated row (README L152) did not need to move: the Status column truncates the line at its first clause ("Accepted — implemented. This file is a RETROACTIVE RECONSTRUCTION written…"), which is unchanged, and the keyword the index parses is stillAccepted. check-adr-links(979) andcheck-adr-anchors` are green on the head. Resolved. One label in the PR body is loose: it calls this "the ADR-0045 form", while the spelling actually followed is ADR-0035 / ADR-0050's (the date inside the parentheses, not inside the bold); all five are one convention and S1(c) named the family, so this is a reading note, not a finding.
  5. ADR gates and the rest of the derived list. Of the 50 derived commands, every one that reads docs/adr was re-run here: check-adr-links and its self-test, check-adr-anchors and its self-test (133), adr-index self-test (46) / --report / --check, check-adr-symbol-anchors and its self-test — all exit 0 on the head. check-adr-0087-registration refuses a verdict without tsx (exit 1, an input problem by design) and check-doc-authoring, check-closing-keyword-parity and check-comment-mask-corpus exit 3 PREREQUISITE NOT MET without node_modules; each is read from CI, where Lint · repo & tooling gates, Lint · docs & code guards, Lint · PM dispatch-gates and Lint · CI, release & engine gates are success on the head, and the dev record lists all four at exit 0 after the build it reused from c2236e3 (its header says so; the delta touches only the ADR, so the reuse is sound). The token ratchet, check-empty-changeset, check-doc-route-spelling --advisory and check-governed-merges (exit 3, GOVERNED, by design) reproduce the prior head's readings. Nothing I could measure contradicts the dev record's 50 at exit 0. Correct.
  6. S2, the PR body. The ratchet table now reads skills/objectstack-data/SKILL.md "24493 / 24482" — the merge-base and head byte counts the full review measured (①.8 there); the formula row "23842 / 23819" and all six token figures are unchanged and reproduce. Resolved.
  7. PR body, other updated claims against the head. Head line: "Head f27efd1d (two commits on d79eecfe: c2236e37, then the S1 ADR follow-up)" — merge-base d79eecf and exactly these two commits (REST). The ADR bullet now describes the three edits: names both sentences (①.2), "D8 carries a one-line … pointer back to the D3 note (D8's own text is unchanged)" (①.3), "the status line gains … in the ADR-0045 form" (①.4, with the label note there), "D3's decision and its quoted citation are left as they are" (true: L141–149 unchanged). Gate summary: "Local gates on f27efd1 (and on c2236e3 before it): 50 derived, 50 run with exit 0, 0 NOT MEASURED" and "the build was reused" — the dev record for this head has 50 lines, all :: exit 0, its header says the build was reused from c2236e3, and dispatch-gates --commands on the head prints 50. "Writes: two git push (c2236e3, f27efd1); one relay pr_create; no GitHub MCP write" is consistent with the PR having two commits and three comments, all from objectstack-fleet[bot]. A grep of the body for claude-, the family words the repo's recogniser lists as fixtures (check-commit-card-trailers.mjs L836–850) and "model" finds only the harness's <!-- claude-projects-attribution: … --> marker (unchanged from the reviewed head, not a model identifier, PR-body guards success), "model-tier mandate" (a tier phrase) and the "Claude Code" product name in the footer: no family word, no claude-… id. The 速读 block is unchanged and still true (it describes the D3 Amendment block as the place to look first, which still holds). Correct.
  8. Commit trailers and head check-runs. check-commit-card-trailers.mjs --range origin/main..HEAD: exit 0, "2 commit message(s) … carry no card relation and no model identifier in the trailer pair". Head check-runs on two REST reads, identical: 46 runs, 30 success, 15 skipped, 1 in progress (Test Core 1/8), 0 failure, 0 other non-success; combined status pending (statuses API, 0 statuses). Success includes the two required floors (Lint & Repo Gates, TypeScript Type Check), PR-body guards (both rows), Check Changeset (both rows), Governed Surface Queue Guard, Check PR Size, Check Documentation Links, every Lint and Type Check lane, Build Core, Test Core (2/8) and (3/8), Test UI, Live E2E UI, Dogfood Regression Gate. Nothing red; one pending, the same full-battery shard that was pending on the prior head. Correct.
  9. Review state on this head. The PR thread carries the seat's Contract-review-claim: for f27efd1 (6632415025) and no record on this head; reviews: 0; draft, auto_merge null, mergeable_state blocked, no assignee or requested reviewer, labels documentation, size/s, tooling. Tier H (docs/adr/**, skills/**) still; this record does not lift the landing.

② Semver level

Unchanged: patch, and the changeset still says patch. The delta is prose in an ADR, which publishes nothing; Clause-②: no, Metadata-protocol: none on both the body and the changeset; no packages/** path; Check Changeset success on the head and check-empty-changeset exit 0 here.

③ Boundary flags

  • S1 of 6632133331: resolved in all three parts — (a) the D3 note names both pre-feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 sentences in the spelling offered (①.2); (b) D8 carries the dated pointer back to D3 with its own text untouched (①.3); (c) the status line carries the amendment in the precedent form, the README index stays current (①.4).
  • S2 of 6632133331: resolved; the data file's "before" bytes now read 24493 (①.6).
  • Dev open_questions: none in the body. The body's account of the three ADR edits is accurate; its "ADR-0045 form" label is loose (①.4) and not worth a round-trip.
  • Independence: PR author objectstack-fleet[bot], commit author Claude on both commits; no off-relay author note is owed. No review seat is seated (6632415025); no assignee, requested reviewer, or review on the PR.
  • Tier H: the one in-progress shard (Test Core 1/8) must be read green before any Tier H act; landing is the maintainer's hand or an authorized GOVERNED_APPROVERS approval, not this record.
  • The pre-existing historical citations the full review's ③ noted (D8's quotation no longer in validate-record-title.ts; D3's citation to a consumed changeset) are now each qualified by a dated note beside them; neither is refreshed, and the card did not ask for that.

④ Design judgment

Per hits file, for the delta only:

  • docs/adr/0079-record-display-name.md: the three edits are the cheapest shape that makes the record self-consistent for every entry point a reader has — the status line (what the index and a grep show), D3 (where the decision lives) and D8 (where the old "never errors" would otherwise contradict the amendment two sections down). Each note records a consequence of the ruling and the PR and decides nothing; the decision text, D8's body and the quoted citations are untouched, which is the ADR-0015 / ADR-0035 / ADR-0050 habit of amending beside the text rather than rewriting history. Two physical lines of the new notes (L138 at 94 columns, L238 at 110) run past the blockquote's ~79-column wrap; no ADR gate prices columns and re-flowing them would be churn for its own sake. Holds.

Must-fix: none. Should-fix: none remaining — S1 (a, b, c) and S2 of 6632133331 are all resolved on this head.

Check-runs at record time: 46 check-runs on f27efd1, 30 success, 15 skipped, 0 failure, 1 in progress (Test Core 1/8) on both reads; combined status pending (0 statuses). mergeable_state blocked, draft, auto_merge null; Tier H (docs/adr/**, skills/**), landing by the maintainer's hand or an authorized approval, not by this record, and only after Test Core (1/8) is read green.

Implemented-by: claude/project-thread-1hmgmw
Reviewed-by: session_01J8VVAnMUWA9rufXzFaEh4J

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J

维护者速读

  • 改了什么: data 技能 titleFormat 行、formula 技能 template 行不再说「已弃用、未移除」,改为:保存和 os validate 都拒绝 titleFormat(title-format-retired),改用 nameField。ADR-0079 在 D3 下加一段注明修订日期的说明,D8 和状态行各加一行指向它,D3 的决定本身不重开。附 '@objectstack/skills': patch changeset。
  • 为什么改: feat(spec)!: refuse an object that declares titleFormat at save and os validate, with the nameField prescription #29499 已让 titleFormat 报错(裁定 6574393684),这三处还在讲旧规则。(governed: two skills still call titleFormat "deprecated, not removed", and ADR-0079 D3 still says "advisory, not an error", after #29007 refused it #29506)
  • 风险与回滚: 只改技能文本、ADR 说明和 changeset;token data 6119 → 6116 / 6123、formula 5956 → 5950 / 5997,同文件删减付账,天花板未动,无 re-wrap。可整 PR revert。
  • 先看: skills/objectstack-data/SKILL.md L90;docs/adr/0079-record-display-name.md D3 下的修订说明。
  • 两分钟验证: os explain title-format-retired 对照 data 技能 L90。
  • 需要你做的: skills/**、docs/adr/** 是受治理 Tier H 面,需 os-zhuang 或 hotlong 批准。契约复核:本席全量 6632133331(PASS,两处建议)→ delta 6632587758(PASS),Head-sha f27efd1de49379837ac325045629b619f2589769。批准后本席落地。
  • 席位意见: ACCEPT。

席位核对 — ACCEPT · domain:skills#1 · head f27efd1de49379837ac325045629b619f2589769

  1. 形态: draft → main,Fixes #29506;作者 objectstack-fleet[bot];文件在认领面内,附 @objectstack/skills patch changeset(⛔ 不挂 skip-changeset)。
  2. 前提实测: 复核逐条对过 validateTitleFormatRetired(packages/lint,error 级、门禁层)、运行时门禁、草稿发布 422 与 CLI os validate 退出 1。
  3. 门禁(钉 head f27efd1d): check-runs success 30 / skipped 15 / 进行中 1(Test Core 1/8),无失败;落地前检须读到全绿。派生门禁 50 条全过,ADR 门禁全过。
  4. 接受的偏差: 开发在低于规定档位的模型上进行,依维护者原话(无额度时豁免)。
  5. 范围外去向: 无。
  6. 落地条款: Tier H。保持 draft,挂 needs-user-decision,同轮请 os-zhuang、hotlong 审批;获批后本席过落地前检、清标、ready、auto-merge;维护者直合亦可。

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review November 4, 2026 14:02
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit 987ff33 Nov 4, 2026
53 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-1hmgmw branch November 4, 2026 14:19
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

Development

Successfully merging this pull request may close these issues.

governed: two skills still call titleFormat "deprecated, not removed", and ADR-0079 D3 still says "advisory, not an error", after #29007 refused it

2 participants