Skip to content

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

Closed

Description

@objectstack-fleet

Filed by the triage seat (session_01AavokzJ5DndAwitDXvKy4U) on the maintainer's ruling in the triage chat, 2026-10-21. ⛔ Not a claim.

Today (objectstack origin/main 1862d8d130)

  • One version line. .changeset/config.json puts about 73 packages in one fixed group, so one minor lifts 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/*.json lists 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 patch but 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 meta applies;
    • 新增能力;
    • 语义变化;
    • 其他修复.

Dispatch shape (domain:spec, one PR or two serial)

  1. 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.
  2. 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-surface key set or authorable-defaults entry with "none" declared is refused, naming the remedy.
      Update the existing fixtures, and do not loosen any other verdict of that check.
  3. 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.
  4. Console refresh: scripts/objectui-changeset-digest.mjs writes the console's refresh changeset at minor. It becomes patch, because objectui never changes the metadata protocol itself.
  5. 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-shipped path over a new one.
  6. 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.

Workload: about 2 days.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01VsqhiSrBjB1wJfRNcHPeXN
    Account: huangyiirene (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-25105-changeset-protocol-levels
    Worktree: objectstack-issue-25105
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface (at origin/main 5050442bb9 or 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 at patch;
    • the release-notes generation path (extend the existing release-notes / annotate-shipped path, 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 the skip-changeset route 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 card
    Thread-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) names AGENTS.md, pr-automation.yml, clause2-line.mjs, check-changeset-no-major.mjs, objectui-changeset-digest.mjs or 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

  2. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    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"
      ]
    }
  3. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #25114 comment 6316009109 · domain:spec seat 1 · session session_01VsqhiSrBjB1wJfRNcHPeXN · 2026-10-21T12:35Z

    Tier H: the PR stays a draft with needs-user-decision until an authorized approval is on record; the contract review of record is 6315965482 (PASS, head 99eaf8350). The .claude/** half of item 1 is #25115.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 21, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 1 · session session_01VsqhiSrBjB1wJfRNcHPeXN · 2026-10-21T13:25Z

    Probe Reading
    git log --format='%H %s' -40 origin/main, grep #25114 f2b6cf230b4cddd795b854b044bbcd95e37b6f55 (squash, 1 parent)
    git ls-remote origin 'refs/heads/gh-readonly-queue/main/*', grep 25114 0 refs (left the queue)
    GET pulls/25114 merged: true, merged by os-zhuang after the authorized approval 5600165403 on head 99eaf8350
    closing keywords in the PR body Fixes #25105 only; no other card closed in the window

    State: #25105 closed completed by the merge; pm:dispatched removed in this act.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:specenhancementNew feature or requestpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions