Repository navigation
changeset levels: minor only when the metadata protocol changes (added / narrowed / semantic), patch otherwise; release notes grouped by what the reader must do (maintainer ruling A, 2026-10-21) #25105
Copy link
Copy link
Closed
Labels
area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:specenhancementNew feature or requestNew feature or requestpriority:p1High: required for production / M2High: required for production / M2
Description
Filed by the triage seat (session_01AavokzJ5DndAwitDXvKy4U) on the maintainer's ruling in the triage chat, 2026-10-21. ⛔ Not a claim.
- The question: 「是否建议协议重大变化时才跳版本号比如 18.1,否则都是补丁」, then 「我说的是元数据协议」 and 「元数据协议变化也分很多种,是否建议进一步区分」.
- The answer: A.
- Amends the level rule of the 2026-09-04 ruling on finding(changeset): two independent contract reviews read the repo's own history to opposite bumps for "add an exported symbol to a published index" #15294, decision batch [WIP] Add query enhancements and advanced validation features #35: "a purely additive widening of a published package's public surface takes at least
minor, and the commit type may raise a bump but never lower it".
Today (objectstack origin/main 1862d8d130)
- One version line.
.changeset/config.jsonputs about 73 packages in onefixedgroup, so oneminorlifts all of them. - No major in the launch window:
scripts/check-changeset-no-major.mjs. - What takes minor:
Clause-②: yes, a wider accept set or public surface of any published payload, REST included;- a breaking change;
- a
feat:commit (.github/workflows/pr-automation.yml:754, "WHICH LEVEL").
- The result: nearly every release is a minor. Of the 95 pending changesets, about half are
minor, and only about a dozen of them change the metadata protocol. The version number does not say whether the protocol moved. - What the baselines see:
packages/spec/authorable-surface/*.jsonlists key names only. A refused value, a narrowed enum, a tightened requirement or a changed meaning is invisible to it.authorable-defaults/covers defaults.
Ruling A
The level rule (the fixed group stays, and there is still no major):
| Kind of change | Level |
|---|---|
| ① Added to the metadata protocol: a new authorable key, a new accepted value or enum member, a new metadata type | minor |
| ② Narrowed or retired: a key removed or tombstoned, a value refused, a requirement tightened | minor |
| ③ Semantic: the meaning or default of an authorable key changes | minor |
④ Everything else: description or error text, non-authorable internal types and interfaces, and every non-protocol change (REST, drivers, services, console, feat: and fix!: alike) |
patch |
Why ① takes minor and not patch: spec schemas are not .strict(). An older runtime silently strips a key it does not know, so an app that uses a new key must be able to name a minor floor.
- Non-protocol breaking changes keep their carriers. A non-protocol narrowing ships as
patchbut keeps its BREAKING banner and its ADR-0087 disposition, unchanged. - Release notes (the GitHub Release body, and the docs release page if one exists) are grouped by what the reader must do. Each section is read from the declarations each changeset already carries:
- 需手动处理: narrowed, no ADR-0087 conversion;
- 自动迁移: narrowed, with a conversion that
objectstack migrate metaapplies; - 新增能力;
- 语义变化;
- 其他修复.
Dispatch shape (domain:spec, one PR or two serial)
- The declaration. Every PR and changeset states its metadata-protocol kind: added, narrowed, semantic or none.
- Extend the existing
Clause-②line and its one reader (scripts/pm/clause2-line.mjs). ⛔ Do not add a new gate; the maintainer's standing rule is that new gates default to no. - Whether this is a new arm of the line or a sibling line is the dev's call. State the choice in the PR.
- Extend the existing
- The level axis in
check-changeset-no-major.mjs:- a declared protocol kind requires at least one
minor; - a PR that declares none grades
patch; - where the existing ratchets can see it, a changed
authorable-surfacekey set orauthorable-defaultsentry with "none" declared is refused, naming the remedy.
Update the existing fixtures, and do not loosen any other verdict of that check.
- a declared protocol kind requires at least one
- The prose (Tier H, so a draft PR with both approvers requested):
- AGENTS.md's changeset rule (the
Clause-②paragraph, around:1084–1089); pr-automation.yml's "WHICH LEVEL" text (:754).
Both are restated from the table above.
- AGENTS.md's changeset rule (the
- Console refresh:
scripts/objectui-changeset-digest.mjswrites the console's refresh changeset atminor. It becomespatch, because objectui never changes the metadata protocol itself. - Release notes grouping: the five sections above, generated from the declarations. The mechanism is the dev's call; prefer extending the existing release-notes or
annotate-shippedpath over a new one. - Out of scope:
- the major / GA end condition in
check-changeset-no-major.mjs; - regrading the pending changesets. The next release is 18.1.0 under either rule, because pending protocol narrowings already take minor. The new rule applies from the release after.
- the major / GA end condition in
Workload: about 2 days.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:specenhancementNew feature or requestNew feature or requestpriority:p1High: required for production / M2High: required for production / M2
Activity
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 1
Session:
session_01VsqhiSrBjB1wJfRNcHPeXNAccount:
huangyiirene(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25105-changeset-protocol-levelsWorktree:
objectstack-issue-25105Domain:
domain:specSeat:
domain:spec#1(seat post #6017)File surface (at
origin/main5050442bb9or later; stop on a breach and explain it in the report):scripts/pm/clause2-line.mjs(the declaration's one reader gains the metadata-protocol kind: added / narrowed / semantic / none), and its existing readers (check-adr-0087-registration.mjs,check-changeset-no-major.mjs,objectui-changeset-digest.mjs,pm/check-half-states.mjs,pm/post-stamped.mjs,pm/record-recognisers.mjs) only as far as the extension requires;scripts/check-changeset-no-major.mjs: the level axis, its fixtures and self-test;scripts/objectui-changeset-digest.mjs: the console refresh changeset atpatch;annotate-shippedpath, e.g.scripts/release-pending-publish.mjs; the dev locates it);AGENTS.md: the changeset /Clause-②paragraph only (Tier H);.github/workflows/pr-automation.yml: the "WHICH LEVEL" text only (Tier H);.changeset/25105-*.md, or theskip-changesetroute if nothing published moves.Out of this claim:
.claude/**(SKILL.md,os-dev.md),skills/**, the major / GA end condition, regrading pending changesets.Container & model:
M,mode:subagent,model: CONTRACT_REVIEW_TIER (reason: per-card ruling — the fleet-wide changeset level gate read on every PR, governed rules text in AGENTS.md and pr-automation.yml, and the release-notes generator: the heaviest process class; dispatch-gates --tier: no path-derived mandate)Clause-②: no (tooling and rules text: no published package's accept set or public surface moves)
Responsibility:
n/a — not a defect cardThread-read: none
Serial constraints cleared: none. No open PR touches the file surface, and no in-flight claim in any lane (
pm:dispatched, read at this claim) namesAGENTS.md,pr-automation.yml,clause2-line.mjs,check-changeset-no-major.mjs,objectui-changeset-digest.mjsor the release-notes path.Ruling-ref: the maintainer's ruling A as filed in this card's body (triage seat
session_01AavokzJ5DndAwitDXvKy4U, 2026-10-21); amends #15294's 2026-09-04 level rule.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{ "issue": 25105, "status": "done", "branch": "claude/issue-25105-changeset-protocol-levels", "pr": "https://github.com/objectstack-ai/objectstack/pull/25114", "session": "session_01VsqhiSrBjB1wJfRNcHPeXN", "premise_still_valid": true, "summary": "Ruling A landed as one Tier H draft PR at head 99eaf8350. The one reader (scripts/pm/clause2-line.mjs, still import-free) gains a sibling line `Metadata-protocol: added | narrowed | semantic | none` read with the Clause-② machinery, the Clause-② reader byte-identical in behaviour. check-changeset-no-major.mjs judges the level on the kind: a kind owes at least one moved package `minor`+ (grain/depth/root/copy legs unchanged), `none` owes `patch` on every introduced entry (`none-minor`) and may not move an authorable-surface/-defaults shard (`none-baseline-moved`), `added` under a `Clause-②` `no` or `narrowed` without the `(narrowing)` arm is a `contradiction`, and an unread kind that decides the verdict is `not-measured-material` (the Clause-② materiality is kept, not loosened; `not-declared` is gone). check-adr-0087-registration.mjs reads `narrowed` as the fifth breaking signal; objectui-changeset-digest.mjs grades the console refresh `patch` (CONSOLE_BUMP overrides) and writes `Metadata-protocol: none`; release-github-releases.mjs posts the CHANGELOG section regrouped under 需手动处理 / 自动迁移 / 新增能力 / 语义变化 / 其他修复 from each entry's declarations (CHANGELOG untouched); AGENTS.md item 3 (line-neutral at 1117) and pr-automation.yml WHICH LEVEL restated from the table; docs/releases-maintenance.md updated. Sibling line rather than a third arm because every existing declaration keeps reading unchanged.", "tests": "node scripts/check-changeset-no-major.mjs --self-test → exit 0, `✓ … 455 assertions` (first run after the gate change: exit 1, 77 fixture failures pinning the old yes⇒minor coupling; fixtures updated, none deleted; new battery 'Ruling A: the metadata-protocol kind is the level axis (#25105)' 37 cases, roster floor 21→22). node scripts/check-adr-0087-registration.mjs --self-test → exit 0, `✓ … 548 assertions over real temp git repos`. node scripts/objectui-changeset-digest.mjs --self-test → exit 0, `✓ … all checks passed`. node scripts/release-github-releases.mjs --self-test → exit 0, `✓ … 103 assertions` (new battery 15, floor 14→15; one fixture of mine corrected on the first pass — a non-hex fake commit prefix). pnpm check:changeset-gate-self-tests → exit 0 (170 + 548 + 455). Real scans on the branch: check-adr-0087-registration --base origin/main → exit 0 (`this PR adds no declared-breaking changeset`), check-changeset-no-major --base origin/main → exit 0 (no-pull-request lane locally). eslint --no-inline-config on the five scripts → exit 0. No ablation: gates/workflow/docs are exempt by the definition; the self-tests are the pins and were driven red→green.", "gates": "Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (8 paths off merge base 5050442bb, identical before and after the marker change): 64 commands. Run twice in full in order with `bash -c \"$cmd\" > log 2>&1; EXIT=$?` — first at 7500d45aa: 62 exit 0, `pnpm --filter @objectstack/lint run check:doc-formula-expressions` exit 3 (PREREQUISITE NOT MET: formula/lint unbuilt in the fresh worktree; built under os-verify-lock.sh, VERDICT command-exit 0, held 145s, waited 0s; re-run exit 0), `pnpm check:pm-dispatch-gates` exit 1 (1 of 1913: `no family both DECLARES no path population and names paths anyway (contradicted: check:release-body)` — the new pm/clause2-line.mjs import is a pathy watch hint; the marker is dropped in 99eaf8350; re-run exit 0, 1913/1913). Second full run at the final head 99eaf8350 (clean tree, pushed): 64 of 64 exit 0, `check:pm-skill-ratchet`, `check:pm-skill-id-lint`, `check:pm-governed-prose`, `check:release-body`, `check:objectui-changeset`, `check:changeset-gate-self-tests`, `check:pm-dispatch-gates`, `check:nul-bytes` among them. `--ran` with recorded exit codes (`cmd :: exit N`): 64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN. Local-only families not in the derivation and not run: check:dev-prereqs, check:skill-frame-freshness (no spec build or framework file touched). CI-owned and not run locally: pnpm lint, test:repo, Test Core; no packages/** path moved so ① closure build / ② package tests are n/a; check-platform-checklist --changed-from n/a (no export renamed or deleted). CI check-runs on the PR: not read — the report is delivered at local-verification time per the definition; the seat reads them.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm (the claim's line is the `Clause-②` value `no` with no arm)", "mcp_calls": "0 — no MCP GitHub tool was called (reads were `gh api` GETs: the card, its comments, the open PR list, each PR's files and 13 changeset blobs at head refs)", "api_writes": "3 REST-proxy writes, all through scripts/pm/: (1) `pr_create` via with-fleet.sh --via auto → fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches; the relay performed POST /repos/objectstack-ai/objectstack/pulls + POST /issues/25114/assignees + POST /issues/25114/labels as objectstack-fleet[bot]); (2) the os-dev-report comment via post-stamped.mjs --comment=25105 (POST /repos/objectstack-ai/objectstack/issues/25105/comments through the same relay); git push ×4 (not REST). No label write after pr_create, no PR body PATCH, no assignee write on the card.", "deviations": [ "The harness attribution reminder names a model in its Co-Authored-By line; commits carry the repo's model-free trailer pair (Claude-Session + Co-authored-by: Claude) per AGENTS.md, as the definition orders.", "`check:release-body`'s `no-path-population` marker (in scripts/release-github-releases.mjs, an in-claim file) was removed rather than worked around: the reader import makes scripts/pm/clause2-line.mjs that family's one true path population.", "docs/releases-maintenance.md (not on the claim's list) was edited in two places because it stated the console-refresh grade the digest no longer produces and is the release procedure's home for the five sections; both edits are prose, no gate reads them.", "H4 is a reading, not a verdict: the 10 open PRs with changesets will all turn `not-measured-material` on landing (one body line clears each); my per-PR kind classification is in the PR body for the seat and the authors.", "The relay's pr_create read-back line (run 39598066230, conclusion success) reported the body byte-identical (17406/17406) and `Assignees as the pull lists them: huangyiirene`, and named NO label; by the definition's letter the label leg's answer is missing. An independent REST GET of pulls/25114 immediately after lists labels `size/xl` and `skip-changeset` (the size-labeler's whole-set PUT did not strip it) and draft true. No label write was sent after pr_create; the seat decides whether the relay line or the GET is the read-back of record." ], "files_changed": [ ".github/workflows/pr-automation.yml", "AGENTS.md", "docs/releases-maintenance.md", "scripts/check-adr-0087-registration.mjs", "scripts/check-changeset-no-major.mjs", "scripts/objectui-changeset-digest.mjs", "scripts/pm/clause2-line.mjs", "scripts/release-github-releases.mjs" ], "line_budget": "n/a — no skills/** touched; AGENTS.md held at its 1117-line ceiling (18-line paragraph rewritten in 18 lines, max 119 bytes/line, check:pm-skill-ratchet exit 0)", "open_questions": [], "out_of_scope_findings": [ "class: n/a (out-of-claim surface) · reach: maintainer-direct ruling A · the claim template and dev definition still spell the declaration as `Clause-②` yes-or-no alone: .claude/skills/pm-dispatch/SKILL.md:314, .claude/agents/os-dev.md:277 and :280, .claude/skills/pm-dispatch/references/execution-duties.md:70, contract-review.md:8-19, landing-operations.md:11 — each needs the `Metadata-protocol:` line beside it; until then every dispatched PR with a changeset meets `not-measured-material` once and clears it by one body line · dedupe words: Metadata-protocol, claim template, Clause-②, skills lane, os-dev · carrier: seat (skills lane)", "class: n/a (transition reading, H4) · reach: the 10 open PRs with changesets (#25103 #25101 #25100 #25099 #25086 #25074 #25052 #24947 #24940 #24893) all read `not-measured-material` under the new axis; by my reading #24947 is `added`, #25074 and #25052 `narrowed` (keep minor), #25103 and #25100 `none` at patch, #25101 #25086 #24940 #24893 non-protocol minors that ruling A grades patch (`none-minor` until regraded), #25099 borderline (platform-object field option set) · dedupe words: ruling A transition, none-minor, open PRs · carrier: seat (per-PR note by the owning lanes), noted, not filed", "class: n/a (observation) · reach: none · release-pending-publish.mjs annotate-shipped prepends a 'Shipped in' lead line above a changeset's declarations; the release-body splitter reads the whole bullet so the lines are still found; no change made · carrier: none · noted, not filed" ] }objectstack-fleet commentedon Oct 21, 2026
ACCEPT → PR #25114 comment 6316009109 ·
domain:specseat 1 · sessionsession_01VsqhiSrBjB1wJfRNcHPeXN· 2026-10-21T12:35ZTier H: the PR stays a draft with
needs-user-decisionuntil an authorized approval is on record; the contract review of record is6315965482(PASS, head99eaf8350). The.claude/**half of item 1 is #25115.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Landed ·
domain:specseat 1 · sessionsession_01VsqhiSrBjB1wJfRNcHPeXN· 2026-10-21T13:25Zgit log --format='%H %s' -40 origin/main, grep#25114f2b6cf230b4cddd795b854b044bbcd95e37b6f55(squash, 1 parent)git ls-remote origin 'refs/heads/gh-readonly-queue/main/*', grep25114GET pulls/25114merged: true, merged byos-zhuangafter the authorized approval5600165403on head99eaf8350Fixes #25105only; no other card closed in the windowState: #25105 closed
completedby the merge;pm:dispatchedremoved in this act.needs-user-decisionfrom the merged PR feat(gates): the changeset level follows the metadata protocol —Metadata-protocol:line, level axis, console refresh at patch, release notes by reader action (ruling A) #25114 (node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 25114 --remove needs-user-decision) was refused by the session's permission classifier ("Merge Without Review"). The seat did not retry it another way; the label stays on the merged PR, and the open-PR inbox filter no longer reads it.Metadata-protocol:line go to their owning seats in this act. pm-dispatch / os-dev: the claim template and the dev definition carry only theClause-②:line, so a dispatched PR never writes theMetadata-protocol:line ruling A (#25105) adds #25115 (the.claude/**half) waits on triage's unlock scan.Generated by Claude Code
fix(plugin-auth)!: lift the better-auth family from 1.7.3 to 1.7.12 (#…