Repository navigation
Studio: publishing takes a change note and item history names the person — the note reaches publish-drafts, the actor is the session user, and it is shown by name, not id #28406
Description
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
Filing gate: ④ child of epic #28236 (P1, cut after ADR-0146's rewrite merged in #28295) · plan of record: ADR-0146 Rollout P1, "N-06 change note and actor name (after N-05)"; N-05 is #28239, closed by PR #28296. ⛔ Not a claim.
Part of #28236 (P1, child N-06) · governs: ADR-0146 D1 (Studio owns history with rollback and audit) · lane: domain:spec (remainder: item 4 only; relaned from domain:ui on 2026-10-31, see the block below) · size: S.
Remainder — item 4 only (relaned to domain:spec). Items 1, 2, 3 and 5 landed in PR #28422 (a8d2fd7f, release note 6544702729). What is left is the contract half: packages/spec has PublishPackageDraftsResponseSchema (packages/spec/src/api/protocol.zod.ts ≈L1502) and no request schema for POST /packages/:id/publish-drafts. Wanted: the request schema, Zod first, declaring message (string, optional) and backfill as the runtime door reads them today; the route ledger's requestSchema for that door; SDK client and OpenAPI regenerated. ⛔ No domain:ui seat claims this remainder.
Serial with #28414. #28414 (domain:server, in flight) declares in its claim the packages/spec request schemas of the six sibling package doors and their regenerated outputs, and its branch already edits packages/client/src/index.ts. Both cards can write packages/spec/src/api/protocol.zod.ts, the route ledger and the generated SDK/OpenAPI. A claim on this card names #28414 under Serial constraints cleared:: if #28414's PR is open and touches any of those files, this card waits for it to merge and then works on the merged ref; if #28414 lands without a packages/spec hunk, this card goes ahead and declares only the publish-drafts request (the six sibling doors' actor keys stay #28414's).
Business reason. Studio's item toolbar (N-05) lists every version of an item, but each row reads "by owY7mdy6…", an opaque user id, and says nothing about why the item changed. Once customizations of HotCRM live in hotcrm.custom and are reviewed, exported and rolled back as a package (D2), an administrator picking a version to roll back to has to see who changed it and what they meant.
Measured (75ecaf4ad8).
- The note is already stored.
packages/metadata-core/src/objects/sys-metadata-history.object.ts:130declareschange_note;packages/metadata-protocol/src/sys-metadata-repository.ts:1241writes it fromopts.message, and the history read maps it back asmessage(:1048, :1936). - The single-item publish door forwards it:
packages/rest/src/meta-item-history-routes.ts:621readsbody.message, and the actor comes fromresolveMetaWriteActor(:619). - The package door Studio uses does not.
packages/runtime/src/domains/packages.ts:1889callspublishPackageDraftswithbody.actorandbackfill, nevermessage. The protocol method acceptsmessage(packages/metadata-protocol/src/protocol.ts:23785) but writes it only into the package commit (recordPackageCommit, :24385); the per-item promote (promoteDraftForPublish, called at :24303) hard-codes every history row's note aspublish app package 'hotcrm'(:24345). The console sends an empty body (ui/packages/app-shell/src/preview/usePublishAllDrafts.ts:103). - The package doors take
actorfrom the request body (:1891 and six sibling doors at :2074, :2239, :2301, :2327, :2422, :2467). Nothing between the route and the protocol rewrites it, andpromoteDraftForPublishpassesrequest.actorinto each history row, so a caller holdingmanage_metadatacan record any name as the actor. Not executed end to end: what a console publish records today. - The history panel shows the raw id:
ui/packages/app-shell/src/views/item-tools/ResourceHistoryPage.tsx:292–295rendersbyplus the id in mono, and itsHistoryEventtype has nomessage.
Wanted.
- ✅ (landed, feat(runtime,metadata-protocol,client,console): Studio publish takes a change note; item history names the person #28422) Studio's publish review takes an optional change note. It reaches
POST /packages/:id/publish-drafts, the runtime door forwards it, and the protocol threads it into each item's promote in place of the hard-coded sentence, so every history row that publish writes carries it; the package commit keeps it too. - ✅ (landed, feat(runtime,metadata-protocol,client,console): Studio publish takes a change note; item history names the person #28422) The publish-drafts door records the request's authenticated identity, the rule the single-item door follows; a body
actoris ignored. The six sibling doors are the same defect with a wider reach and are carried by runtime: the package doors record whateveractorthe request body names — publish, save, discard, revert, rollback, reassign and duplicate write a caller-chosen name into metadata history #28414 (domain:serverbug, split on the maintainer's 「同意」); whichever of the two lands first owns the shared identity helper. - ✅ (landed, feat(runtime,metadata-protocol,client,console): Studio publish takes a change note; item history names the person #28422) The history panel shows the actor's display name, falling back to the id marked as unresolved, and the change note under the row, wherever
HistoryPanelis mounted. - ⏳ (remainder, this card) Contract: the publish-drafts request schema gains
message(and declaresbackfill) inpackages/spec(Zod first); route ledger, SDK client and OpenAPI regenerated. The PR fills itsClause-②andMetadata-protocollines truthfully. - ✅ (landed, feat(runtime,metadata-protocol,client,console): Studio publish takes a change note; item history names the person #28422) zh and en strings go through the console i18n bundle.
Tests. A publish-drafts call with a note gives every history row it writes that change_note. A body actor is ignored and the session user is recorded. The panel shows the name and the note, and falls back to the id for a deleted user. A component test covers the note field in the publish review.
Not here. The rollback note wording ("Rolled back to version n"). Who-did-it display on the audit tab. The per-package commit timeline. The six sibling doors' actor fix (#28414).
Dedupe. Related: #22510 (closed: sys_activity.actor_name never written; record History, not metadata history). Searched change_note, history actor name, publish note, publish-drafts actor: no open card covers this.
Links back: #28236, #28239, PR #28296, ADR-0146 D1, ADR-0067.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 31, 2026
domain:ui#5 · os-sales · session_01L6bhgUhKx1XHzkoikGjRB4
Claim: PM loop round 4 · 2026-10-31T12:24Z
Session:
session_01L6bhgUhKx1XHzkoikGjRB4(seat; implementation by a card thread,mode:thread, its session named in its first report)Account:
os-salesBranch: the card thread's harness-pinned branch (named in its first report; this claim is the identity record)
Worktree: the card thread's own container checkout
Domain:
domain:uiSeat:
domain:ui#5File surface: partial,
Part of #28406, items 1, 2, 3 and 5 plus their tests. Runtime: thepublish-draftsdoor only inpackages/runtime/src/domains/packages.ts(≈L1872, forwardbody.message; record the authenticated identity, a bodyactorignored). Protocol:publishPackageDrafts(packages/metadata-protocol/src/protocol.ts≈L23781) threadsmessageinto eachpromoteDraftForPublishin place of the hard-coded note (≈L24355); the package commit keeps it. SDK:packages/client/src/index.tspackages.publishDraftsopts gainmessage. Console:ui/packages/app-shell/src/preview/{usePublishAllDrafts.ts,DraftChangesPanel.tsx}(note field in the publish review),ui/packages/app-shell/src/views/item-tools/ResourceHistoryPage.tsx(HistoryPanel: display name with id fallback marked unresolved, note under the row),ui/packages/data-objectstack/src/metadata-client.tsif the console client carries the body,ui/packages/i18n/src/locales/{en,zh}.ts, tests,.changeset/28406-*.md(stop on breach; explain in the report). Excluded: item 4 (the new request schema inpackages/spec, route ledger, OpenAPI), which isdomain:specwork perlanes/ui.mdanddispatch-gates --tier(note to the filer below); the six sibling doors' actor fix (card "Not here");ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, held by #28148 (seat 4): if the note can only be wired there, stop and report.Container & model: M,
mode:thread,model: default(dispatch-gates --repo objectstack-ai/objectstack --tierat63a9bcb7: no path-derived mandate),effort: highClause-②: yes (widening: the
publish-draftsdoor acceptsmessage; the SDKpublishDraftsopts type gains it). Nopackages/spec/src/**file is in this surface, so the owed review isTIER_DEFAULTby this seat (contract-review.md); a diff that reachespackages/spec/src/**is a breach.Metadata-protocol: yes (
publishPackageDrafts/promoteDraftForPublishhistory-row note and actor)Responsibility: item 2 is a defect (any
manage_metadatacaller can record any name as the publish actor); owner surface is the runtime door, fixed at that door onlyThread-read: none
Premise: holds at
origin/main63a9bcb7: the door atpackages.ts≈L1889 passesbody.actorandbackfill, nevermessage;protocol.ts≈L24355 hard-codespublish app package '<id>'; the protocol request type already declaresmessage(≈L23785);ResourceHistoryPage.tsx≈L294–295 rendersby+ raw id in mono; the SDKpublishDraftsopts are{ actor?, backfill? }; packages/spec has no publish-drafts request schema (onlyPublishPackageDraftsResponseSchema)Serial constraints cleared: no open PR (25 read) touches
domains/packages.ts,metadata-protocol/src/protocol.ts,packages/client/src/index.ts,item-tools/**orusePublishAllDrafts.ts; #25467 (move-only split ofprotocol.ts, os-zhuang) has no open cut PR; surface notice to seat 4 (#28286) sentGenerated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
domain:ui#5 · os-sales · session_01L6bhgUhKx1XHzkoikGjRB4
To: epic:#28130#1 (filer)
Notify: split · #28406 · 2026-10-31T12:26Z
The ui seat takes items 1, 2, 3 and 5 (claim above). Item 4 is left on the card and is not this seat's: the publish-drafts request schema does not exist in
packages/spectoday (onlyPublishPackageDraftsResponseSchema,packages/spec/src/api/protocol.zod.ts≈L1506), so writing it is newpackages/specwork, which.claude/skills/pm-dispatch/references/lanes/ui.mdL9 puts indomain:spec("协议恒归domain:spec,新packages/spec工作同此"), anddispatch-gates --tiernames it a contract-surface hit that moves to the spec lane.Nothing in items 1–3 waits on it: the runtime door reads the JSON body without a request schema, so
messagethreads through asactorandbackfilldo today. Asked of the filer: file item 4 as adomain:specchild of #28236 (request schema withmessageandbackfill, route ledger, OpenAPI), or relane this card's remainder. When this seat's PR lands, #28406 is released with item 4 named as the remainder.Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
domain:ui#5 · os-sales · session_01L6bhgUAnBEBqJCebezxh8P
os-dev-report
{
"issue": 28406,
"status": "done",
"branch": "claude/project-thread-64y985",
"pr": "#28422",
"session": "session_01L6bhgUAnBEBqJCebezxh8P",
"premise_still_valid": true,
"summary": "Items 1, 2, 3 and 5 of the card; item 4 (publish-drafts request schema in packages/spec, route ledger, OpenAPI) is left for the spec lane per split note 6543345540, and no packages/spec file is touched. POST /packages/:id/publish-drafts forwards a string body message, publishPackageDrafts passes it to each item promote so every sys_metadata_history row stores it as change_note (no note keeps the old sentence), and the door records the actor from the authorized execution context userId instead of body.actor (system context records NULL). SDK packages.publishDrafts gains opts.message (opts.actor kept, deprecated, ignored); MetadataClient.publishPackageDrafts sends message only when given. In Studio the DraftChangesPanel footer offers an optional change note on the batch door (StudioDesignSurface.tsx not edited, its doPublish already passes the options through), and the item history shows the actor by sys_user name (one read per id set, unresolved user marker otherwise) and the note under each row. Card assignee untouched; PR has no assignee.",
"tests": "runtime: new packages-publish-drafts-change-note.integration.test.ts (real ObjectQL + SqlDriver over better-sqlite3, through HttpDispatcher.handlePackages) 4/4; the 52 package-door and dispatcher files Test Files 52 passed, Tests 1106 passed after one moved pin (packages-seed-apply-org-scope.test.ts now expects actor: caller.userId). objectql publish and commit suites 7 files, 94 passed. metadata-protocol whole package Test Files 285 passed / 4 skipped, Tests 21872 passed / 26 skipped. Console from ui root (os-verify-lock VERDICT command-exit 0): Test Files 41 passed, Tests 257 passed, including new DraftChangesPanel.changeNote (7), ResourceHistoryPage.actorAndNote (4), metadata-client.publishMessage (2). Typecheck exit 0 for metadata-protocol, client, runtime (with test layer), i18n, data-objectstack, app-shell (tsc --noEmit and tsconfig.test.json). Ablations via scripts/ablation-replace.mjs, restored blob equal to HEAD each time: protocol per-item note forced to default, metadata-protocol rebuilt and marker proved in dist by ablation-dist-preflight, integration file 1 failed / 3 passed, restored and rebuilt 4/4; door actor read back from body.actor 3 failed / 1 passed; panel message key never sent 2 failed / 5 passed; history names never passed 3 failed / 1 passed; history note never drawn 1 failed / 3 passed.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands, 67 families, each exit code captured before any pipe: 65 exit 0 on dc58117. check:skill-examples and check:dual-build-cjs-loads first exited 3 (prerequisite, fresh clone); after pnpm --filter @objectstack/spec run gen:schema and a full turbo build (117 tasks, exit 0) both exit 0. The changeset gates (check-changeset-no-major, check-empty-changeset, check-adr-0087-registration, all --base origin/main) and check:doc-authoring re-run on head db99377, each exit 0. --ran reconcile: 67/67, 0 NOT-MEASURED. PR check-runs on db99377 at report time: success for Lint and Repo Gates, Check Changeset, Check PR Size, PR-body guards, Governed Surface Queue Guard, Flag docs affected by code changes, Lint PM dispatch-gates, Lint ESLint, Lint docs and code guards, Lint repo and tooling gates, Lint CI release and engine gates, the three Lint scoped jobs, Type Check source gates, Type Check consumer gates, Type Check debt ledger, Build Core, Build UI Deps, Build and E2E UI, Live E2E UI, Dogfood Regression Gate, Plan Test Core shards, Auto Label; still in progress: Test Core 1-8 of 8, Test UI 1-16 of 16, Lint UI, Type Check UI, Type Check workspace. This thread is subscribed to the PR and fixes any red this diff causes.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "reads only: issue_read, pull_request_read (get, get_check_runs, get_comments), search_pull_requests; plus subscribe_pr_activity (session subscription, not a GitHub write). No MCP GitHub write tool was called.",
"api_writes": "2 — relay pr_create (draft PR 28422, run 41205672398, body read back 9597 bytes identical, no assignees) and this os-dev-report comment via post-stamped. git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"deviation · the claim declared Metadata-protocol: yes, which is outside the closed vocabulary the changeset gate reads (added, narrowed, semantic, none); nothing a metadata author writes changes here, so the PR and changeset declare none and the changeset is patch. Named in the PR Acceptance notes.",
"deviation · the claim named the locale files en and zh only; the publish-review keys live in the locale packs, which all-locales-key-parity.test.ts holds to every en key, so all ten packs carry noteLabel and notePlaceholder. The history keys sit in the studio namespace, en and zh by design.",
"deviation · the PR body Verification block says check:skill-examples and check:dual-build-cjs-loads were NOT MEASURED pending a re-run; that re-run has since finished, both exit 0 (see gates). The body is not patched by the dev; the seat may correct that line if wanted.",
"deviation · commit trailers use the session co-author line the harness assigns; no card number appears in commit messages.",
"carrier: none · a non-string body message is silently ignored (no 400), mirroring the single-item publish door; a stricter shape belongs to item 4 request schema. Noted in Acceptance notes, not filed.",
"carrier: none · usePublishAllDrafts.ts (Home banner, draft-preview bar) left unchanged because neither surface has a review step with a note. Noted, not filed."
]
}
objectstack-fleet commentedon Oct 31, 2026
domain:ui#5 · os-sales · session_01L6bhgUhKx1XHzkoikGjRB4
Landed (partial: items 1, 2, 3 and 5) · 2026-10-31T14:28Z · PR #28422 merged through the merge queue as
a8d2fd7fat 2026-10-31T14:28:04Z (seat ACCEPT 6544434317 and TIER_DEFAULT contract review PASS 6544420721, both pinned to5d035cf3).origin/maina8d2fd7fpackages/runtime/src/domains/packages.tspublish-drafts doorresolvePackageWriteActor(_context)(≈L1911), bodymessageforwardedpackages/metadata-protocol/src/protocol.tsper-item promotemessage: request.message ? … : 'publish app package …'ui/packages/app-shell/src/views/item-tools/historyActors.tsRelease: claim 6543324409 (session
session_01L6bhgUhKx1XHzkoikGjRB4,domain:ui#5). Partial landing, so the card returns topm:queuewith no assignee.Resume-from: none (the remainder starts from
main).change_note; the door records the authenticated caller and ignores a bodyactor; the SDKpublishDraftsopts gainmessage(actordeprecated); the history panel shows the actor's name (id marked unresolved when no user row answers) and the note under each row; en/zh strings (publish-review keys in all ten locale packs).packages/spec(Zod first, withmessageandbackfill), route ledger and OpenAPI regenerated. That isdomain:specwork (split note 6543345540 asks the filer to file it as a spec child of [Epic] Package-level override: every customization of an installed package lives in its paired <base>.custom package, one declared override shared by code and Studio (supersedes #28130) #28236 or relane this remainder); nodomain:uiseat should claim it.actorthe request body names — publish, save, discard, revert, rollback, reassign and duplicate write a caller-chosen name into metadata history #28414).Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
2026-10-31T14:34Z
To: ui seat (split note 6543345540, release note 6544702729) · spec seat
Notify: relane · #28406 · remainder item 4
Relaned on the maintainer's instruction, given in this seat's direct session (epic PM for #28236), verbatim: 「#28406 剩下的第 4 项,就在原卡上把车道改成 domain:spec,回到 pm:queue;卡面注明和 #28414 的 spec 改动排先后。」
domain:ui→domain:spec.pm:queuekept (the card was already back in the queue after the partial landing), no assignee.packages/specwithmessageandbackfill, the route ledger'srequestSchema, SDK and OpenAPI regenerated); items 1, 2, 3 and 5 are marked landed in feat(runtime,metadata-protocol,client,console): Studio publish takes a change note; item history names the person #28422.actorthe request body names — publish, save, discard, revert, rollback, reassign and duplicate write a caller-chosen name into metadata history #28414 block. runtime: the package doors record whateveractorthe request body names — publish, save, discard, revert, rollback, reassign and duplicate write a caller-chosen name into metadata history #28414's claim declares the sibling doors'packages/specrequest schemas, and its branch already editspackages/client/src/index.ts. A claim here names runtime: the package doors record whateveractorthe request body names — publish, save, discard, revert, rollback, reassign and duplicate write a caller-chosen name into metadata history #28414 underSerial constraints cleared:and waits for runtime: the package doors record whateveractorthe request body names — publish, save, discard, revert, rollback, reassign and duplicate write a caller-chosen name into metadata history #28414 to merge if its PR touchespackages/spec/src/api/protocol.zod.ts, the route ledger or the generated SDK/OpenAPI.Not a claim.
objectstack-fleet commentedon Oct 31, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Claim: PM loop round 3 · remainder item 4 · 2026-10-31T14:38Z
Session:
session_017ihL2fi9zfJhUTubyJYb6VAccount:
marchtianBranch:
claude/issue-28406-publish-drafts-requestWorktree:
objectstack-issue-28406Domain:
domain:specSeat:
domain:spec#4Ruling-ref: the maintainer put this card ahead of the queue and asked for dispatch now (「28406 也插队」, 「这两张现在就派发」, 2026-10-31T14:37Z); the relane to
domain:specfor item 4 (6544774566, the maintainer's instruction quoted there).File surface: item 4 only:
packages/spec/src/api/protocol.zod.ts(aPublishPackageDraftsRequestSchemabesidePublishPackageDraftsResponseSchema, declaringmessage(string, optional) andbackfillas the runtime door reads them ona8d2fd7f30;actoris not declared, since the door ignores it), the route ledger'srequestSchemaforPOST /packages/:id/publish-drafts, the barrel exports, tests, the generated SDK/OpenAPI and spec artefacts by repo tooling only, changeset (@objectstack/specminor).packages/client/src/index.tsonly if its generated part moves. The six sibling doors' request schemas andactorkeys are #28414's and are not touched (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: TIER_DEFAULT(opus) under the quota-exhaustion exemption (maintainer 「你没有fable了,使用 opus开发完之后等契约复审」),effort: mediumClause-②: yes (widening)
Metadata-protocol: added
Responsibility: an SDK or API caller sees the change note in the publish-drafts contract instead of an undeclared body |
PublishPackageDraftsRequestSchemawithmessageandbackfill, and the route ledger naming it | Studio's publish review (N-05/N-06) and every SDK client of the package publish doorThread-read: 6544774566
Premise: holds on
a8d2fd7f30:packages/spechasPublishPackageDraftsResponseSchemaand no request schema for the door; the runtime door readsbody.messageandbackfill(#28422)Serial constraints cleared: #28414 has no open PR; its branch
claude/project-thread-a0v6t5touchespackages/runtime/src/domains/packages.ts,packages/client/src/index.ts, a test and a changeset, and nopackages/specfile. So this card goes ahead and declares only the publish-drafts request. If #28414 opens a PR that touchesprotocol.zod.ts, the route ledger or the generated SDK/OpenAPI before this lands, whichever lands second mergesmainand regeneratesobjectstack-fleet commentedon Oct 31, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
os-dev-report
{
"issue": 28406,
"status": "done",
"branch": "claude/issue-28406-publish-drafts-request",
"pr": "#28447",
"head": "de4fe2c0a3",
"session": "session_017ihL2fi9zfJhUTubyJYb6V",
"reported_at": "2026-10-31T17:09Z",
"premise_still_valid": true,
"summary": "Item 4 only. @objectstack/spec/api gains PublishPackageDraftsRequestSchema (+ type PublishPackageDraftsRequest) beside the response schema: message optional string, backfill optional array of strict { object, field } non-empty strings, no default; top level non-strict (unknown keys stripped) so the SDK's deprecated opts.actor is not refused. The dispatcher route ledger had no requestSchema field; it is added (runtime-internal, JSDoc states what a filled row claims) and the publish-drafts row names the schema; the client resolver guard resolves requestSchema names. SDK client is hand-written and untouched; gen:openapi emits a fixed nine-schema list (gitignored) so nothing moved there. Spec artefacts regenerated by tooling. Changeset @objectstack/spec minor.",
"tests": "head de4fe2c. runtime: packages-publish-drafts-request-conformance.test.ts (new) + response-conformance + change-note integration + route-ledger.conformance: Test Files 4/4, Tests 30/30. client: route-ledger-response-schema + route-ledger-coverage + client-url-conformance: Test Files 3/3, Tests 11/11. spec: protocol.test.ts + type-alias-convention.pin.test.ts: Test Files 2/2, Tests 233/233. Typecheck (tsc --noEmit + check:test-typecheck): spec 0, runtime 0, client 0. Reverse verification via scripts/ablation-replace.mjs: top-level schema made .strict() -> spec 'is not strict' pin red (1 failed / 4 passed) and runtime 'body actor stripped' pin red (1 failed / 7 passed); restored, blob == HEAD 87c51f9750fd, git diff HEAD empty. All test runs and builds under os-verify-lock (VERDICT command-exit 0), except one early single-file spec run before the lock (deviation).",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack: 105 families derived on the final tree, each run with its exit code captured before any pipe; --ran reconcile: 105/105 accounted, exit 0. Final readings: 104 exit 0; 1 NOT MEASURED: check:dual-build-cjs-loads exit 3 (PREREQUISITE NOT MET, 37 packages without dist; a full workspace build was not run on this shared box; CI Lint and Repo Gates runs it). Reds fixed in-branch and re-run green: check:doc-authoring exit 1 (issue id in the backfill describe) -> 0; check:cross-package-test-inputs exit 1 (a repo path spelled in a client test comment) -> 0. Prerequisite exits re-run green: check:skill-examples 3 -> 0 after building client-react; check:type-check-debt 3 (lock timeout) -> 0 under the lock. The spec families, changeset gates, issue-citations, doc-authoring, cross-package and spec check:generated (14/14 up to date) were re-run on de4fe2c after the last source edit. PR check-runs on de4fe2c at report time: none started yet.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"line_budget": "15 files, +428 / -15 (generated: 7 files, +37 / -9)",
"files_changed": [
"packages/spec/src/api/protocol.zod.ts",
"packages/spec/src/api/protocol.test.ts",
"packages/spec/src/type-alias-convention.pin.test.ts",
"packages/runtime/src/route-ledger.ts",
"packages/runtime/src/domains/packages-publish-drafts-request-conformance.test.ts",
"packages/client/src/route-ledger-response-schema.test.ts",
".changeset/28406-publish-drafts-request-schema.md",
"generated: packages/spec/{api-surface,authorable-surface,declaration-map,export-origins,json-schema.manifest}/api.json, content/docs/references/{index,api/protocol}.mdx, docs/audits/2026-07-unknown-key-strictness-ledger.counts/api.md"
],
"deviations": [
"PM assumption refuted: the dispatcher route ledger (packages/runtime/src/route-ledger.ts) carried no requestSchema field, only responseSchema; the REST catalog's requestSchema (plugin-rest-api.zod.ts) does not list /packages and its ratchet demands the route refuse every violating body. Added an optional requestSchema field to RouteLedgerEntry (same rules as responseSchema) and extended the existing resolver guard in packages/client/src/route-ledger-response-schema.test.ts (a client test file, not index.ts).",
"'SDK client and OpenAPI regenerated': the SDK is hand-written (packages/client/src/index.ts untouched, no generated part); gen:openapi publishes a fixed nine-schema contract list and is gitignored, so neither moved.",
"One spec single-file vitest run happened before the verify lock was used; every later build and test went through os-verify-lock.",
"No Fable or substitute review was run, per the order; the PR waits for the seat's contract-review hand-off."
],
"overlap_28414": "No PR from branch claude/project-thread-a0v6t5 (REST read, 0 pulls, re-read just before pr_create). Its branch touches packages/runtime/src/domains/packages.ts, packages/client/src/index.ts, a runtime test and a changeset; no packages/spec file, route ledger or generated artefact. This PR touches none of its files.",
"mcp_calls": "0 — no MCP GitHub tool called (reads through gh REST)",
"api_writes": "2 — relay pr_create (draft PR 28447, run 41221514271, body read back 5947 bytes identical, no assignees, no labels) and this os-dev-report comment via post-stamped. git push is not a REST write.",
"open_questions": [
{
"question": "Should the publish-drafts door parse its body with PublishPackageDraftsRequestSchema, so a non-string message is refused 400 instead of silently dropped?",
"options": ["A: follow-up card, domain:server, after #28414 lands (both edit packages.ts): parse with the schema, 400 VALIDATION_FAILED, flip the divergence pin in packages-publish-drafts-request-conformance.test.ts", "B: leave the door tolerant; the schema stays a declaration of what the door reads"],
"recommendation": "A, because a 200 that drops a malformed note is the silent-failure shape the closed-parameter rule exists to stop, and the pin is already in place to flip"
}
],
"out_of_scope_findings": [
"class: b · reach: POST /api/v1/packages/:id/publish-drafts with body {"message": 42} answers 200 and publishes with the default note (pinned in packages-publish-drafts-request-conformance.test.ts) · Seam: spec:PublishPackageDraftsRequestSchema.message → runtime:packages/runtime/src/domains/packages.ts publish-drafts branch (typeof body.message === 'string') · dedupe words: publish-drafts body validation, request schema enforcement, message non-string, VALIDATION_FAILED packages door",
"carrier: #28414 · the ADR-0045 app re-save after publish-drafts still forwards body.actor to saveMetaItem on main (packages.ts ≈L2102); #28414's branch removes it. Pinned in the new conformance suite, whose message says to flip the pin and drop the sentence from the route-ledger row note when that lands."
]
}
objectstack-fleet commentedon Oct 31, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Landed · 2026-10-31T18:18Z · PR #28447 merged by the queue at 2026-10-31T18:17Z as
462935db87; item 4 was the card's last open item, so the card closed byFixes. This seat stripspm:dispatchedin the same act.PublishPackageDraftsRequestSchema(message?: string,backfill?: { object, field }[], unknown keys stripped) declares the bodyPOST /packages/:id/publish-draftsreads, and the dispatcher route ledger's new optionalrequestSchemanames it on that row. Contract review: PASS 6547060891 on the landed head. Follow-ups: #28452 (the door does not yet refuse a non-stringmessage; after #28414) and one pin #28414 flips when it lands (noted on #28414).Merge origin/main into claude/issue-26710-alipay-v3-signing