Repository navigation
fix(runtime): the package doors record the signed-in caller in metadata history, never a body actor - #28502
Conversation
Discard-drafts, commit revert, rollback, adopt-orphans, duplicate and the publish-drafts app unhide save now record the request's authenticated user through one helper (packageWriteActor), the rule resolveMetaWriteActor states for the single-item door. A body actor is ignored, not refused. Claude-Session: https://claude.ai/code/session_01QUs3BvyWc2j7Vh5KBnJtam Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUs3BvyWc2j7Vh5KBnJtam Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUs3BvyWc2j7Vh5KBnJtam Co-authored-by: Claude <noreply@anthropic.com>
…-a0v6t5 # Conflicts: # packages/runtime/src/domains/packages.ts
Claude-Session: https://claude.ai/code/session_01QUs3BvyWc2j7Vh5KBnJtam Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUs3BvyWc2j7Vh5KBnJtam Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 39 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin bc9a2306c9bc09131c52c18316ef4cbf194c5f33 && git checkout bc9a2306c9bc09131c52c18316ef4cbf194c5f33
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ea74ebf93f8b1b955b2b77327c3a34c677d4d751 4f64ab7c64284373fb9c8a5310e8c8abf805e8a0 && git checkout -B drift-repro ea74ebf93f8b1b955b2b77327c3a34c677d4d751 && git merge --no-ff 4f64ab7c64284373fb9c8a5310e8c8abf805e8a0
node scripts/docs-audit/affected-docs.mjs --json ea74ebf93f8b1b955b2b77327c3a34c677d4d751
|
|
domain:server#4 · os-zhuang · session_01QUs3BtyH9zgxKzYrJiH18J ACCEPT · PR #28502 · Head-sha 维护者速读
席位意见:六处都改用 N-06 已落地的同一个解析函数,没有第二份;每个入口单独消融验证;可合。 席位核对
|
Requested by Sam · project thread
Fixes #28414
Clause-②: no
Metadata-protocol: none
维护者速读
actor。manage_metadata的人可以在请求体里填别人的名字,历史里就显示成别人改的;管理员靠这份记录决定回滚什么、找谁问。actor只是被忽略,不会被拒绝,老调用照常工作;系统调用(没有用户)跟以前一样不记 actor。没有数据迁移,回滚即 revert 本 PR。packages/runtime/src/domains/packages.ts(六处调用改用resolvePackageWriteActor,以及该函数头注释)、packages/runtime/src/domains/packages-write-actor-session.test.ts。pnpm --filter @objectstack/runtime exec vitest run src/domains/packages-write-actor-session.test.ts,预期 17 个用例全绿。What changes
Runtime (
packages/runtime/src/domains/packages.ts). Six protocol calls that passedbody.actorstraight through now record the user id of the request's authorized execution context, throughresolvePackageWriteActor:POST /packages/:id/discard-drafts→discardPackageDraftsPOST /packages/:id/commits/:commitId/revert→revertCommitPOST /packages/:id/rollback→rollbackToPackageCommitPOST /packages/:id/adopt-orphans→reassignOrphanedMetadataPOST /packages/:id/duplicate→duplicatePackagePOST /packages/:id/publish-drafts→saveMetaItem. It reuses theactorthat door already resolves for its own publish.A body
actoris ignored, not refused. A context with no user id (a system caller) sends noactor, so the protocol records the actor-lessnull(#4556), as it did before for a body without one.Shared helper owner: #28406 (PR #28422). N-06 landed first, so it owns
resolvePackageWriteActor. This PR consumes it and adds no second helper. Its docblock no longer says "only publish-drafts reads it today"; it now lists every door that reads it.SDK (
packages/client/src/index.ts). Theactormember of the inlineoptsobject types onpackages.discardDrafts,packages.revertCommit,packages.rollback,packages.adoptOrphansandpackages.duplicateis marked@deprecated(the server ignores it). This matches what #28422 did forpackages.publishDrafts. No type changes shape and no export is added or removed, henceClause-②: no.Spec (Wanted 3): no diff. No
packages/specrequest schema declaresactorfor these doors.package-lifecycle.zod.tsholds only response transcriptions; the route ledger names norequestSchemafor them;PublishPackageDraftsRequestSchema(#28447) already stripsactor. With nothing to drop or mark, there is no spec change, no regenerated artifact, andMetadata-protocol: none. The claim'sClause-②: yesline assumed a spec hunk that does not exist.Tests
packages/runtime/src/domains/packages-write-actor-session.test.ts(new, 17 cases), drivingdispatch()over a realSchemaRegistryand a recording protocol:actor, with or without a bodyactor.actor.http-dispatcher.test.ts, the commit-revert routing case, expected the body'sai:claude. It now expects the session user.packages-publish-drafts-request-conformance.test.ts(feat(spec): declare the publish-drafts request body, so the change note is part of the published API contract #28447) pinned "the app re-save still forwards a bodyactor" and said to flip it when this card landed. Flipped toUSER. The route-ledger row note carried no sentence about it, so nothing there changed.Acceptance notes
{}or no body on all five doors (PackagesPage.tsx,commitHistory.ts,packages-io.ts). The SDK sendsoptsonly when given, and no in-repo caller passesactor. The CLI calls none of these routes. ADR-0008 and ADR-0067 describerecorded_byholding an AI principal such asai:claudefor an AI apply's commit. That commit is written server-side by the protocol and is untouched here; only fixtures sentai:claudethrough these HTTP doors.:2074 → saveMetaItemis not a seventh door. It is the app re-save inside the publish-drafts handler. feat(runtime,metadata-protocol,client,console): Studio publish takes a change note; item history names the person #28422 left it readingbody.actor(its own conformance pin said so), and this PR closes it.881d0d31was committed with the repo hook path overridden by mistake, so.githooks/pre-commitdid not run on it. Its only check,node scripts/check-regen-pending.mjs, was run by hand right after: exit 0. No generated artifact is in this diff.Verification
Readings at head
4f64ab7cunless stated.fea2382bdiffers from it only by a test-file comment.Package tests, typecheck, lint
pnpm --filter @objectstack/runtime testat881d0d31: Test Files 1 failed / 496 passed, Tests 1 failed / 8069 passed / 19 skipped. The one failure was the feat(spec): declare the publish-drafts request body, so the change note is part of the published API contract #28447 pin above, flipped infea2382b. That file plus the new file andhttp-dispatcher.test.tsatfea2382b: 3 files, 276 tests passed.4f64ab7c: 17 passed.pnpm --filter @objectstack/client testat881d0d31: Test Files 53 passed, Tests 689 passed (lock VERDICT command-exit 0).pnpm --filter @objectstack/runtime typecheckatfea2382b: VERDICT command-exit 0.pnpm --filter @objectstack/client typecheckat881d0d31: VERDICT command-exit 0.pnpm lint(repo-wide) atfea2382b: exit 0. eslint--no-inline-configon the changed test file at4f64ab7c: exit 0.Ablation (scripts/ablation-replace.mjs; each leg restores the `body.actor` pass-through at ONE call site; restored blob equals HEAD, git diff HEAD empty)
Tests import
src/relatively, so no dist rebuild sits between mutation and run. Atfea2382b:Each leg reds exactly its own door's cases.
Dispatch gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 61 families. Every command was run with exit captured to disk before any pipe, against881d0d31(same 61 as the 6-path derivation atfea2382b).check-plugin-teardown-shape --self-test(shallow clone),spec check:skill-examplesandcheck:dual-build-cjs-loads(no full build). Aftergit fetch --unshallowand a fullpnpm build(VERDICT command-exit 0) atfea2382b, all three exit 0.fea2382bbecause the last commits touched test files:check:cross-package-test-inputs,check:test-source-alias,check:engine-double-contract,check:nul-bytes,check:issue-citations,check:doc-authoring,check:type-check-coverage,check:type-check-debt,check:tier-file-adoption,check:objectql-double-limit,check:rest-log-spy-declared: all exit 0.--ranreconciliation: 61 derived, 61 run, 0 NOT-MEASURED (derived zero), 0 UNRUN.Generated by Claude Code