Repository navigation
fix(metadata-protocol)!: a commit revert or package rollback that would restore a row bound to the read-only base is refused per item, naming the .custom pair - #29632
Conversation
… read-only base is refused per item, naming the pair revertCommit's restore limb (and rollbackToPackageCommit through it) now asks the named-base close on the binding the restore writes, as rollbackMetaItem does, with the same rollback sentence. The item lands in failed[] (NOT_OVERRIDABLE) with nothing written; the soft-remove limb stays open. Claude-Session: https://claude.ai/code/session_01ADHkmTKKCrTrtA7H6oSj28 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmTKKCrTrtA7H6oSj28 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmTKKCrTrtA7H6oSj28 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ADHkmTKKCrTrtA7H6oSj28 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 10 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 fa9f0d69a1d2fb69324e8122a04581bb9b8c31e8 && git checkout fa9f0d69a1d2fb69324e8122a04581bb9b8c31e8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4008e6290f4812b1c18a42ec2589b8a2733cf6c3 85261a810dff62b530193fbe92e7b607158a76d3 && git checkout -B drift-repro 4008e6290f4812b1c18a42ec2589b8a2733cf6c3 && git merge --no-ff 85261a810dff62b530193fbe92e7b607158a76d3
node scripts/docs-audit/affected-docs.mjs --json 4008e6290f4812b1c18a42ec2589b8a2733cf6c3
|
|
domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67 Contract-review-claim: session_01ADHkmQJdgarUjPLNgFBY67 · head a15f252 · 2026-11-02T22:45Z |
|
domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67 Contract reviewServed-tier: ① Derived judgmentsRead on the head's tree,
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS |
…ntry names both meta-door addresses, not yet the commit doors The sentence carried over from the named-base close said the packageless-overlay-write-closed entry names the package-less write only; 1bdf674 widened it to both meta-door addresses. The commit doors are what it does not name yet; that text widening rides the any-package lookup card. Category and id unchanged. Claude-Session: https://claude.ai/code/session_01ADHkmTKKCrTrtA7H6oSj28 Co-authored-by: Claude <noreply@anthropic.com>
|
domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67 席位核对 · ACCEPT · PR #29632 · 2026-11-02T23:34ZHead-sha: 维护者速读(席位终稿)
核对六项
|
|
domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67 Hand-off · PR #29632 · 2026-11-02T23:57ZSeat 3 is going off duty on the maintainer's order. This PR is ACCEPTed ( |
domain:server#3 · os-steve · session_01ADHkmQJdgarUjPLNgFBY67
Requested by Steve · project thread
Fixes #29390
Clause-②: no (narrowing)
Metadata-protocol: none
Skills-docs: none needed —
skills/objectstack-platform/SKILL.mdplaces every customization of an installed base in its paired.custom, declaringoverrides, and says nothing about reverting a commit recorded against the base itself; nothing it says becomes false.维护者速读
POST /packages/:id/commits/:commitId/revert)和整包回滚(POST /packages/:id/rollback)时,若要把旧版本恢复进"绑定只读基础包本身"的那一行(五种可覆盖类型),现在逐项拒绝:该项进failed[],code: NOT_OVERRIDABLE,提示与逐项回滚完全同一句(改写进.custom配对包并声明overrides),不写任何东西;同一提交的其它项照常撤销。packages/metadata-protocol/src/protocol.ts中revertCommit恢复分支新增的判定(restoreVersion之前)、protocol.named-base-overlay-write.test.ts末尾新增的 describe、package-commit-revert-path-package.dogfood.test.ts头注释与最后一个用例。cd packages/metadata-protocol && npx vitest run src/protocol.named-base-overlay-write.test.ts,应见 22 个用例全部通过(其中 5 个为本卡新增)。What changes
@objectstack/metadata-protocol—revertCommit's restore limb (androllbackToPackageCommit, which reverts through it) now asks the #28905 close beforerepo.restoreVersion:namedBaseOverlayWriteRefusal, on the binding the restore writes (resolveOverlayPackageBinding's answer, the keyrollbackMetaItemalready uses), with therollbackarm of the same sentence (closedOverlayWriteClauses, no second spelling).namedBaseCloseSubject, unchanged). The item lands infailed[]withcode: NOT_OVERRIDABLEand the sentence; nothing is written; the revert answers200withsuccess: false; the commit's other items still revert and the revert commit is still recorded.rollbackToPackageCommitreports each refused item (Item 'TYPE/NAME' was not reverted: …) and continues.protocol.ts, inrevertCommit's class body (the [maintainer] refactor(metadata-protocol): splitsrc/protocol.ts(33,065 lines, +10,169 in 30 days) along itsObjectStackProtocolImplementationseams, one move-only slice per PR #25467 E2 section 1 split movedreadItemFromMetadataServicethroughgetUiView, notrevertCommit). They cannot move intoprotocol-packaged-base-refusal.tswithout a second spelling: the restore limb's only calls beforerepo.restoreVersionareresolveOverlayPackageBinding(also read by the cluster write-through replay and byrollbackMetaItem, which asks the package-less close first) andSysMetadataRepository.restoreVersion(the repository layer, no registry, shared withrollbackMetaItem).The sentence an item carries, for
view/showcase_task.defaulton the showcase:Measured before the change (origin/main 7f277a8, booted showcase, REST)
Commits recorded before the close were produced through the real save and
publish-draftsdoors with the close shadowed on the running protocol instance only, then the close restored (a save naming the base answered 403 again).com.example.showcasePOST /meta/view/X/rollbackNOT_OVERRIDABLEsuccess: true,restored; row rewritten (L3 to L2), served at both addressessuccess: false,failed[0].codeNOT_OVERRIDABLE; row and served document unchangedsuccess: true; every pre-close apply commit replayed (one reverted twice)success: false, each refused item infailed[]; row unchangedremoved; base document servedFull readings, including which commits can carry such a row: only an
applycommit the base recorded before the close whose item edited an existing row (creation items take the soft-remove limb;revertcommits recordprevVersion: null; post-close publishes into the base are refused bypromoteDraftForPublishwhere the fix can be taken).Tests
packages/metadata-protocol/src/protocol.named-base-overlay-write.test.ts, new describe "the commit doors: restoring a row bound to the base is closed, removing one stays open (metadata-protocol: a commit revert or package-commit rollback can restore a row bound to a read-only base package that the #28905 close now refuses to write #29390)" (5 cases, the file's engine double reused, so the engine-double ledger is untouched). Pre-close commits come fromsaveMetaItem+publishPackageDraftswith the close shadowed on the instance only:packages/qa/dogfood/test/package-commit-revert-path-package.dogfood.test.ts, new last case: on the booted showcase through REST, the showcase's commits recorded before the close: the edited item's revert and the package rollback are refused naming the pair, the served document unchanged; the created item's revert still removes the row and the shipped document is served again.Ablation (drop the close from the restore limb)
scripts/ablation-replace.mjsreplacedif (namedBase) throw namedBase;beforerepo.restoreVersionin the restore limb (anchor x1 to x0, blob 19bf7c8f to 15c51b71), held under an EXIT trap.Tests 2 failed | 20 passed (22): both red-first cases,expected { success: true, …(5) } to match object { success: false, …(3) }andexpected true to be false(the rollback'ssuccess).pnpm --filter @objectstack/metadata-protocol build,ablation-dist-preflightmarker present indist/index.jsanddist/index.cjs, thenTests 1 failed | 7 passed (8): the metadata-protocol: a commit revert or package-commit rollback can restore a row bound to a read-only base package that the #28905 close now refuses to write #29390 case,expected { success: true, …(5) } to match object { success: false, …(2) }.git diff HEADempty; rebuilt,ablation-dist-preflight --absentmarker absent from all 22 built files, tree clean.Verification on `a15f252f`
All on
a15f252f(this branch after mergingorigin/main0ab4a09e, which carries the #25467 E2 section 1 split and the #29451 dogfood fix), in a card-thread container; heavy runs underscripts/pm/os-verify-lock.sh.pnpm install --frozen-lockfile, then the closurepnpm --filter '@objectstack/dogfood^...' build(with declarations): VERDICT command-exit 0 each.src/protocol.named-base-overlay-write.test.ts: Tests 22 passed (22).pnpm --filter @objectstack/metadata-protocol test: Test Files 308 passed, 4 skipped (312); Tests 22251 passed, 26 skipped (22277); VERDICT command-exit 0.pnpm --filter @objectstack/metadata-protocol typecheck: VERDICT command-exit 0.pnpm --filter @objectstack/objectql test(its revert pins included: rollbackMetaItem / revertCommit always 409 on a package-bound overlay row — restoreVersion's put() scopes the parent lookup topackage_id IS NULL#6215's package-bound revert in place, the email-locale stage-2 batch doors): Test Files 540 passed (540); Tests 10488 passed (10488); VERDICT command-exit 0.pnpm --filter @objectstack/dogfood typecheck: VERDICT command-exit 0.test/package-commit-revert-path-package.dogfood.test.ts: Tests 9 passed (9) (test(dogfood): pin that an uninstalled package's commit is refused through its own revert and rollback path #29450's case, merged from main, included).pnpm --filter @objectstack/dogfood test(no shard, no path): Test Files 398 passed, 3 skipped (401); Tests 3281 passed, 28 skipped (3309); VERDICT command-exit 0.turbo run build --filter='./packages/**', 78/78), thennode scripts/pm/dispatch-gates.mjs --commands(no paths): 65 families, all 65 run, every exit 0;--ranreconciliation: 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN.pnpm lint(eslint . --no-inline-config): exit 0.ecf913edandd776e258the same suites, gates and lint were green, and the battery had 4 reds inflow-runas.dogfood.test.ts(3) anddeclarative-endpoint-anonymous-guest.dogfood.test.ts(1), red too with this PR'ssrcfiles restored toorigin/main(control leg); test(dogfood): re-point the runAs and anonymous-guest flow pins to flow start admission's record rule #29451 on main fixed them, and they are green here.Acceptance notes
publishPackageDrafts' revert plan and the restore limb both read any package's active row. With this change (key A1) that revert is refused naming the pair instead of answering success over nothing. The plan'sprevVersionis not changed here (seat ruling).packages/runtime/src/domains/packages.ts(the REST revert door's comment, outside this card's file surface) says undoing a read-only package's overlay commit "stays open": still true of the door (no package-level guard) and of the soft-remove limb; an item-level refusal now applies to the restore limb. Left for the seat to word if wanted.Human Minimum
packages/specholds no runtime logic. (No spec change.)pnpm lintpasses.main, one pull request.packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.维护者速读section is the required Chinese digest).Card thread session
session_01ADHkmTKKCrTrtA7H6oSj28, seatdomain:server#3.Generated by Claude Code