You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
spec: judge a collection item's _packageId against its owning body at defineStack / os validate / os build, so the stamp the boot now refuses (#28534) is refused where it is written #28627
Filing gate: ① a follow-up a landed review owes, finding class (b) (where a refusal fires vs where the author writes). Raised by the CONTRACT_REVIEW_TIER delta review of PR #28587 (comment 6555831347, should-fix S5); re-read by this seat. Child of #27293 (E4). ⛔ Not a claim. It is out of #28534's claim because it is a packages/spec change.
The gap
PR #28587 makes objectql's registerApp and the manifest service's residual door refuse a collection item whose body carries a _packageId other than its registering package's (collectionItemOwnerStampRefusal, packages/objectql/src/engine.ts on that branch). The refusal fires at boot or install only. defineStack, os validate and os build still accept such a body, so the author learns about it from a failed install, not where they wrote it. For permission sets the same rule already runs at build time: ADR-0086 D3's judgePermissionSetOwnerBinding (packages/spec/src/security/permission-set-owner-binding.ts:88, read at origin/maind94dd3a6) is shared by the build doors and the boot.
Work
After PR #28587 lands, add one judge for a collection item's _packageId against its owning body, in packages/spec, the way judgePermissionSetOwnerBinding is shaped. Run it at defineStack, os validate, os build and the artifact parse, and have objectql's refusal call the same judge so the two cannot disagree. Tests: a body carrying a foreign _packageId is refused by os validate with a located message; the same body without the stamp passes (control). This change is in the spec lane (Metadata-protocol: narrowed, the build-door half of the same narrowing), so it needs that lane's review.
Business reason
An AI that writes a metadata app should be told at os validate that a key does not belong in the body, not at an administrator's install.
Reader
The triage seat grades and routes it (spec lane); the epic PM of #27293 dispatches after PR #28587 lands.
Dedupe
The 500 most recent issues and PRs (read 2026-11-01T07:03Z), titles grepped for _packageId|owner stamp|owner binding: 0 hits. Control connector: 53 hits.
Hand-off to the lane, on the maintainer's instruction in this seat's session (2026-11-01, verbatim: 「按你的方案交给车道」). pm:epic → pm:queue in this act; the domain:* label stays. This card waited for PR #28587 (#28534), which merged as d2c487407, so it builds on the classifier on main. The card stays a sub-issue of #27293 for tracking only, and the epic seat no longer reserves it. The triage grade stands.
Claim: PM loop round 3 · 2026-11-01T11:49Z
Session: session_017ihL2fi9zfJhUTubyJYb6V
Account: marchtian
Branch: claude/issue-28627-owner-stamp-build-door
Worktree: objectstack-issue-28627
Domain: domain:spec
Seat: domain:spec#4
Ruling-ref: the epic seat's hand-off to the lane, on the maintainer's 「按你的方案交给车道」 (6557064500); triage p2 (6556398151); the boot-door refusal merged in PR #28587 (d2c487407), whose Clause-②: no (narrowing) / Metadata-protocol: narrowed this card completes at the build doors. The pattern is ADR-0086 D3's shared judge (judgePermissionSetOwnerBinding).
File surface: one judge module in packages/spec (shaped like security/permission-set-owner-binding.ts: an exported pure judge returning the prescription and located issue text, no envelope); its callers at defineStack (stack.zod.ts), os validate / os build (packages/cli) and the artifact parse; packages/objectql/src/engine.ts#collectionItemOwnerStampRefusal rebuilt on the judge, keeping its envelope and its registration-written-stamp exemption in objectql; tests; regenerated artefacts by repo tooling only; changesets (@objectstack/spec minor, and each other moved package). On a breach the dev stops and explains it in the report.
Container & model: M, mode:subagent, model: TIER_DEFAULT (opus) under the quota-exhaustion exemption (maintainer 「你没有fable了,使用 opus开发完之后等契约复审」), effort: high
Clause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility: an author (often an AI) who writes another package's _packageId into an item body hears it at defineStack / os validate / os build, located, instead of from a failed install | one spec judge that the build doors and objectql's registration refusal both call, so they cannot disagree | the install-door semantics PR #28587 already landed; authored and stored connector rows (#28594)
Thread-read: none
Premise: holds on f23e051232. collectionItemOwnerStampRefusal exists only in packages/objectql/src/engine.ts:4881 (callers in engine.ts and plugin.ts:3171, residual door). No packages/spec or packages/cli file judges _packageId. judgePermissionSetOwnerBinding (packages/spec/src/security/permission-set-owner-binding.ts:88) is read by stack.zod.ts, cli/src/utils/permission-set-name-collisions.ts, metadata-protocol and objectql: the shape to follow.
Serial constraints: not measured at claim time; the dev reads the open-PR file lists for engine.ts, stack.zod.ts and the cli validate/build files before opening the PR.
{
"issue": 28627,
"status": "done",
"branch": "claude/issue-28627-owner-stamp-build-door",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28685",
"head": "7f7161f2a6",
"session": "session_017ihL2fi9zfJhUTubyJYb6V",
"premise_still_valid": true,
"summary": "One pure judge judgeCollectionItemOwnerStamp(item, type, name, owner, door) in packages/spec/src/kernel/collection-item-owner-stamp.ts (doors build/register, no envelope) plus OWNER_STAMP_JUDGED_COLLECTIONS (28 stack collections). The stack schema runs it as a superRefine beside the permission-set owner-binding gate, so defineStack, os validate, os build and the artifact parse judge once (no cli source change). objectql collectionItemOwnerStampRefusal calls the judge with door register, keeping its VALIDATION_ERROR/400 envelope, the REGISTRATION_WRITTEN_STAMPS exemption and byte-identical boot words (no pin flipped). An objectql test proves, key by key over STACK_DEFINITION_KEYS, that the build door's set equals the set registerApp refuses.",
"tests": "at 7f7161f2a6 under the verify lock: spec test exit 0 (784 files / 23142 tests); objectql test exit 0 (513 / 9901); metadata-protocol test exit 0 (291 passed 4 skipped / 21944 passed 26 skipped); cli unit exit 0 (363 / 5162); cli integration file collection-item-owner-stamp-validate-door.test.ts exit 0 (2/2); spec+objectql+cli typecheck exit 0. New: spec kernel judge test 9, spec stack build-door test 11, objectql doors test 3, cli validate-door test 2; objectql collection-item-owner-stamp.test.ts unchanged and green. Ablation at 3df38f8d81 via ablation-replace (anchor '.superRefine(applyCollectionItemOwnerStampGate)' x1 to x0, blob 3fcb4152 to 4c4c845a), spec rebuilt, dist preflight --absent: marker absent from 588 files; the os validate test turned red (expected exit 1, got 0), control green; restored blob == HEAD, git diff HEAD empty, rebuilt, preflight: marker present in 4 files, tree clean, file green again.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 7f7161f2a6: 88 commands, exit codes recorded before any pipe. 87 exit 0; pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (seven dists outside the diff), built via turbo cache, re-run exit 0. --ran: 88 derived, 88 run, 0 NOT-MEASURED (record carries the re-run code for that gate). spec check:generated after merge: all 14 artifacts up to date. Local-only check:dev-prereqs exit 1 (35 ui/** workspace packages unbuilt in this container; not the change). PR check-runs: none reported yet at report time (in_progress); CI owns the full farm.",
"dogfood_battery": "7f7161f2a6 · os-verify-lock VERDICT command-exit 0 · Test Files 369 passed, 3 skipped (372) · Tests 2981 passed, 28 skipped (3009) · no failure",
"line_budget": "12 files, +824 / -12 vs main (tests 522, judge module 144, stack.zod.ts +83/-1, engine.ts +18/-11, changesets 44, generated 10)",
"files_changed": [
".changeset/28627-item-owner-stamp-build-door.md",
".changeset/28627-item-owner-stamp-shared-judge.md",
"packages/spec/src/kernel/collection-item-owner-stamp.ts",
"packages/spec/src/kernel/collection-item-owner-stamp.test.ts",
"packages/spec/src/kernel/index.ts",
"packages/spec/src/stack.zod.ts",
"packages/spec/src/stack-collection-item-owner-stamp.test.ts",
"packages/spec/api-surface/kernel.json",
"packages/spec/export-origins/kernel.json",
"packages/objectql/src/engine.ts",
"packages/objectql/src/collection-item-owner-stamp-doors.test.ts",
"packages/cli/test/collection-item-owner-stamp-validate-door.test.ts"
],
"deviations": [
"Independent review: none run, per the order (no Fable quota); the PR waits for the seat's contract-review hand-off.",
"null at the build door is refused by the item schema's own type check (invalid_type at the item's _packageId), not by the judge, because _packageId is declared z.string() and the stack refinement does not run over an inner type failure; '' and foreign strings get the judge's prescription.",
"The objectql changeset is patch: its verdicts and words are unchanged; it carries both declaration lines, a BREAKING banner worded as declared on the spec minor, and the adr-0087 not-required marker, in the service-automation shape of #28587.",
"The ablation ran at 3df38f8d81, before the one merge of origin/main; the merge touched no packages/spec, objectql or cli file.",
"The ran record carries the re-run exit code for check:dual-build-cjs-loads (first pass exit 3, prerequisite)."
],
"mcp_calls": "3 — mcp__github__issue_read (get, get_comments) on #28627, mcp__github__pull_request_read (get) on #28587; reads only",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, opened #28685 as draft, no labels, no assignees); this report comment via post-stamped.mjs. git push is not a REST write.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: seat · noted, not filed — apps and objects bodies keep a foreign _packageId at registerApp's body seam (apps: registry.registerApp -> registerItem -> applyProtection writes only an unset key; objects: stampObjectPackage), so neither door refuses it; the objectql key-by-key test records registerApp refusing in exactly 28 collections and not in apps/objects/objectExtensions. reach: not measured through a public door (no install-local probe), so not filed; dedupe words: _packageId app owner stamp, registerApp apps stampPackage, object owner stamp",
"carrier: seat · noted, not filed — the manifest service's residual registration judges every ARTIFACT_FIELD_TO_TYPE type not in RESIDUAL_TYPES_WITH_OWN_PATH (apps included), while the body seam does not judge apps: a read-only inference about two boot doors judging different sets; dedupe words: residual owner stamp apps",
"carrier: seat · noted, not filed — MetadataPlugin's artifact registration (registerArtifactBodyCollections, packages/metadata/src/plugin.ts) stamps through applyProtection and does not call the judge; read-only inference, not measured; dedupe words: metadata plugin artifact _packageId stamp"
]
}
Landed · 2026-11-01T14:41Z · PR #28685 was merged by the queue at 2026-11-01T14:41Z as e170d42438. The card closed by Fixes, and this seat strips pm:dispatched in the same act.
What landed (Clause-②: no (narrowing)):
The judge. One spec judge, judgeCollectionItemOwnerStamp (@objectstack/spec/kernel), over the 28 collections the boot door judges.
The build door. The stack schema runs the judge, so defineStack, os validate, os build and the artifact parse refuse a foreign _packageId, located at the item's _packageId.
The boot door. objectql's collectionItemOwnerStampRefusal now calls the same judge. Its words are unchanged.
Record:
Contract review: PASS 6559060618 on the landed head 7f7161f2.
Activity
objectstack-fleet commentedon Nov 1, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | none | P③
Triage: p2 ·
domain:spec·area:devpath·pm:epickept · 2026-11-01T09:55Z⛔ Not a claim.
_packageIdstamp is refused at boot or install, whiledefineStack/os validate/os buildaccept it. This is the build-door half, shaped likejudgePermissionSetOwnerBinding, with objectql calling the same judge. p2, in step with connector materializer: an installed package's package-relativeproviderConfigfile ref is read from the HOST's package root, so an install-local app can bind the host's own file (measured: it materializedreadywith the host's OpenAPI document) #28534.packages/spec,Metadata-protocol: narrowed), and its review is the spec lane's.pm:epicstays: the epic PM of [Epic] Marketplace and connector auto-shelf — E1 platform prerequisites (openapi/mcp hardening, outbound OAuth, request signing), E2 administrator credential hand-off, E3 author recipes and handbook, E4 the first shelf of official connector apps #27293 dispatches it after that PR lands.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U
Hand-off to the lane, on the maintainer's instruction in this seat's session (2026-11-01, verbatim: 「按你的方案交给车道」).
pm:epic→pm:queuein this act; thedomain:*label stays. This card waited for PR #28587 (#28534), which merged asd2c487407, so it builds on the classifier onmain. The card stays a sub-issue of #27293 for tracking only, and the epic seat no longer reserves it. The triage grade stands.objectstack-fleet commentedon Nov 1, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Claim: PM loop round 3 · 2026-11-01T11:49Z
Session:
session_017ihL2fi9zfJhUTubyJYb6VAccount:
marchtianBranch:
claude/issue-28627-owner-stamp-build-doorWorktree:
objectstack-issue-28627Domain:
domain:specSeat:
domain:spec#4Ruling-ref: the epic seat's hand-off to the lane, on the maintainer's 「按你的方案交给车道」 (6557064500); triage p2 (6556398151); the boot-door refusal merged in PR #28587 (
d2c487407), whoseClause-②: no (narrowing)/Metadata-protocol: narrowedthis card completes at the build doors. The pattern is ADR-0086 D3's shared judge (judgePermissionSetOwnerBinding).File surface: one judge module in
packages/spec(shaped likesecurity/permission-set-owner-binding.ts: an exported pure judge returning the prescription and located issue text, no envelope); its callers atdefineStack(stack.zod.ts),os validate/os build(packages/cli) and the artifact parse;packages/objectql/src/engine.ts#collectionItemOwnerStampRefusalrebuilt on the judge, keeping its envelope and its registration-written-stamp exemption in objectql; tests; regenerated artefacts by repo tooling only; changesets (@objectstack/specminor, and each other moved package). On a breach the dev stops and explains it in the report.Container & model:
M,mode:subagent,model: TIER_DEFAULT(opus) under the quota-exhaustion exemption (maintainer 「你没有fable了,使用 opus开发完之后等契约复审」),effort: highClause-②: no (narrowing)
Metadata-protocol: narrowed
Responsibility: an author (often an AI) who writes another package's
_packageIdinto an item body hears it atdefineStack/os validate/os build, located, instead of from a failed install | one spec judge that the build doors and objectql's registration refusal both call, so they cannot disagree | the install-door semantics PR #28587 already landed; authored and stored connector rows (#28594)Thread-read: none
Premise: holds on
f23e051232.collectionItemOwnerStampRefusalexists only inpackages/objectql/src/engine.ts:4881(callers inengine.tsandplugin.ts:3171, residual door). Nopackages/specorpackages/clifile judges_packageId.judgePermissionSetOwnerBinding(packages/spec/src/security/permission-set-owner-binding.ts:88) is read bystack.zod.ts,cli/src/utils/permission-set-name-collisions.ts,metadata-protocoland objectql: the shape to follow.Serial constraints: not measured at claim time; the dev reads the open-PR file lists for
engine.ts,stack.zod.tsand the cli validate/build files before opening the PR.objectstack-fleet commentedon Nov 1, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
os-dev-report
{ "issue": 28627, "status": "done", "branch": "claude/issue-28627-owner-stamp-build-door", "pr": "https://github.com/objectstack-ai/objectstack/pull/28685", "head": "7f7161f2a6", "session": "session_017ihL2fi9zfJhUTubyJYb6V", "premise_still_valid": true, "summary": "One pure judge judgeCollectionItemOwnerStamp(item, type, name, owner, door) in packages/spec/src/kernel/collection-item-owner-stamp.ts (doors build/register, no envelope) plus OWNER_STAMP_JUDGED_COLLECTIONS (28 stack collections). The stack schema runs it as a superRefine beside the permission-set owner-binding gate, so defineStack, os validate, os build and the artifact parse judge once (no cli source change). objectql collectionItemOwnerStampRefusal calls the judge with door register, keeping its VALIDATION_ERROR/400 envelope, the REGISTRATION_WRITTEN_STAMPS exemption and byte-identical boot words (no pin flipped). An objectql test proves, key by key over STACK_DEFINITION_KEYS, that the build door's set equals the set registerApp refuses.", "tests": "at 7f7161f2a6 under the verify lock: spec test exit 0 (784 files / 23142 tests); objectql test exit 0 (513 / 9901); metadata-protocol test exit 0 (291 passed 4 skipped / 21944 passed 26 skipped); cli unit exit 0 (363 / 5162); cli integration file collection-item-owner-stamp-validate-door.test.ts exit 0 (2/2); spec+objectql+cli typecheck exit 0. New: spec kernel judge test 9, spec stack build-door test 11, objectql doors test 3, cli validate-door test 2; objectql collection-item-owner-stamp.test.ts unchanged and green. Ablation at 3df38f8d81 via ablation-replace (anchor '.superRefine(applyCollectionItemOwnerStampGate)' x1 to x0, blob 3fcb4152 to 4c4c845a), spec rebuilt, dist preflight --absent: marker absent from 588 files; the os validate test turned red (expected exit 1, got 0), control green; restored blob == HEAD, git diff HEAD empty, rebuilt, preflight: marker present in 4 files, tree clean, file green again.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 7f7161f2a6: 88 commands, exit codes recorded before any pipe. 87 exit 0; pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE NOT MET (seven dists outside the diff), built via turbo cache, re-run exit 0. --ran: 88 derived, 88 run, 0 NOT-MEASURED (record carries the re-run code for that gate). spec check:generated after merge: all 14 artifacts up to date. Local-only check:dev-prereqs exit 1 (35 ui/** workspace packages unbuilt in this container; not the change). PR check-runs: none reported yet at report time (in_progress); CI owns the full farm.", "dogfood_battery": "7f7161f2a6 · os-verify-lock VERDICT command-exit 0 · Test Files 369 passed, 3 skipped (372) · Tests 2981 passed, 28 skipped (3009) · no failure", "line_budget": "12 files, +824 / -12 vs main (tests 522, judge module 144, stack.zod.ts +83/-1, engine.ts +18/-11, changesets 44, generated 10)", "files_changed": [ ".changeset/28627-item-owner-stamp-build-door.md", ".changeset/28627-item-owner-stamp-shared-judge.md", "packages/spec/src/kernel/collection-item-owner-stamp.ts", "packages/spec/src/kernel/collection-item-owner-stamp.test.ts", "packages/spec/src/kernel/index.ts", "packages/spec/src/stack.zod.ts", "packages/spec/src/stack-collection-item-owner-stamp.test.ts", "packages/spec/api-surface/kernel.json", "packages/spec/export-origins/kernel.json", "packages/objectql/src/engine.ts", "packages/objectql/src/collection-item-owner-stamp-doors.test.ts", "packages/cli/test/collection-item-owner-stamp-validate-door.test.ts" ], "deviations": [ "Independent review: none run, per the order (no Fable quota); the PR waits for the seat's contract-review hand-off.", "null at the build door is refused by the item schema's own type check (invalid_type at the item's _packageId), not by the judge, because _packageId is declared z.string() and the stack refinement does not run over an inner type failure; '' and foreign strings get the judge's prescription.", "The objectql changeset is patch: its verdicts and words are unchanged; it carries both declaration lines, a BREAKING banner worded as declared on the spec minor, and the adr-0087 not-required marker, in the service-automation shape of #28587.", "The ablation ran at 3df38f8d81, before the one merge of origin/main; the merge touched no packages/spec, objectql or cli file.", "The ran record carries the re-run exit code for check:dual-build-cjs-loads (first pass exit 3, prerequisite)." ], "mcp_calls": "3 — mcp__github__issue_read (get, get_comments) on #28627, mcp__github__pull_request_read (get) on #28587; reads only", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, opened #28685 as draft, no labels, no assignees); this report comment via post-stamped.mjs. git push is not a REST write.", "open_questions": [], "out_of_scope_findings": [ "carrier: seat · noted, not filed — apps and objects bodies keep a foreign _packageId at registerApp's body seam (apps: registry.registerApp -> registerItem -> applyProtection writes only an unset key; objects: stampObjectPackage), so neither door refuses it; the objectql key-by-key test records registerApp refusing in exactly 28 collections and not in apps/objects/objectExtensions. reach: not measured through a public door (no install-local probe), so not filed; dedupe words: _packageId app owner stamp, registerApp apps stampPackage, object owner stamp", "carrier: seat · noted, not filed — the manifest service's residual registration judges every ARTIFACT_FIELD_TO_TYPE type not in RESIDUAL_TYPES_WITH_OWN_PATH (apps included), while the body seam does not judge apps: a read-only inference about two boot doors judging different sets; dedupe words: residual owner stamp apps", "carrier: seat · noted, not filed — MetadataPlugin's artifact registration (registerArtifactBodyCollections, packages/metadata/src/plugin.ts) stamps through applyProtection and does not call the judge; read-only inference, not measured; dedupe words: metadata plugin artifact _packageId stamp" ] }objectstack-fleet commentedon Nov 1, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Landed · 2026-11-01T14:41Z · PR #28685 was merged by the queue at 2026-11-01T14:41Z as
e170d42438. The card closed byFixes, and this seat stripspm:dispatchedin the same act.What landed (
Clause-②: no (narrowing)):judgeCollectionItemOwnerStamp(@objectstack/spec/kernel), over the 28 collections the boot door judges.defineStack,os validate,os buildand the artifact parse refuse a foreign_packageId, located at the item's_packageId.collectionItemOwnerStampRefusalnow calls the same judge. Its words are unchanged.Record:
7f7161f2.apps, pin the build side key by key, and document the refusal in validating-metadata #28695.install-local: an installed package'sapps[]keeps a self-written_packageId, and the listing and disabled filters misattribute it. Filed as objectql: an installed package'sapps[]entry keeps a self-written_packageId(no #28534 refusal on the apps loop), so the per-package and disabled-package filters attribute the app to the package it names #28697.