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: resolveInjectedColumnProvenance does not know the external.columnMap → owner_id arm plugin-sharing honours since #27425, so the #7858 convergence row and the two columnMap readers diverge (epic #27261) #27661
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
Filing gate: ① consistency defect owed by landed work (#27425, PR #27476f57eddcf), from the post-landing contract review 6493803142 (④ should-fix 1) and the seat carry 6493297056.
Reader: the epic PM (#27261) dispatches it in the epic subtree; the fix is in packages/spec/src/data/injected-system-column-provenance.ts, packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts and packages/lint/src/validate-external-owner-sharing.ts.
Dedupe (open AND closed): "resolveInjectedColumnProvenance columnMap owner_id plugin-sharing convergence" → 2 hits, none this defect (#8119 is the closed #7858 write-gate twin).
reach: no runtime exposure; both sides fail closed. Read on main: for a federated object that maps a remote column onto owner_id through external.columnMap without declaring it, resolveInjectedColumnProvenance(schema, 'owner_id') answers injected-unprovisioned, while plugin-sharing's hasPhantomOwnerAnchor answers false (mapsRemoteColumnOntoOwner) and scopes over the mapped column. The spec module's convergence map still names #7858 as plugin-sharing converging on the helper.
type: Bug
One reader decides "owner anchor provable from declared metadata" (a declared owner_id field, or an external.columnMap value owner_id). Either resolveInjectedColumnProvenance takes the columnMap arm, or the spec module's convergence map records it as a named exception; plugin-sharing (mapsRemoteColumnOntoOwner) and lint (columnMapTargets, hasUnprovableOwnerAnchor) read that one source.
No verdict moves: plugin-sharing's read/write scopes, the lint rules' findings and hints stay byte-identical on the existing pins (federated phantom-scoping suites, external-owner-anchor-sql-read.test.ts, validate-external-owner-sharing.test.ts).
Clause-②: decided by the dev from the diff (a new exported helper arm in @objectstack/spec is a public-surface change) · Metadata-protocol: none. Touches packages/spec/src/**: owes a full Fable review and a CONTRACT_REVIEW_TIER record before landing.
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
Claim: PM loop round 7 2026-10-29T21:57Z
Session: session_017ihL2c5z3q4h8inrn5kwqV (epic PM); implementing card thread session_017ihL2eCEdjSZBk7DGrPPFg
Account: marchtian
Branch: claude/project-thread-c3dfhl (the card thread's platform-assigned branch — measured platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27661
Domain: domain:spec
Seat: epic:#27261#1 (epic PM; no domain:* seat). Maintainer order, 田騏 2026-10-29T21:50Z: 「给我解释后续还有哪些卡,以及为什么不派」 (epic subtree p3 cards are dispatched, not left by pull)
File surface: packages/spec/src/data/injected-system-column-provenance.ts (one exported owner-anchor reader plus its columnMap reader; the #7858 convergence row), packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts (hasPhantomOwnerAnchor reads the spec pair), packages/lint/src/validate-external-owner-sharing.ts (hasUnprovableOwnerAnchor / columnMapTargets read the spec pair), their tests, generated references the spec change re-records, .changeset/** (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: yes
Metadata-protocol: none
Responsibility: #27425 (PR #27476) added the columnMap → owner_id arm in plugin-sharing only; review 6493803142 ④ should-fix 1 and seat carry 6493297056
Thread-read: none
Premise: holds — on origin/mainresolveInjectedColumnProvenance has no columnMap arm while plugin-sharing's mapsRemoteColumnOntoOwner and lint's columnMapTargets each read it.
Serial constraints: #27662 (card thread) edits plugin-sharing's write-deny diagnostic, not federated-phantom-anchors.ts's predicate; say in the report if the two overlap. Contract face (published spec + Clause-②: yes): the PR body says "Fable review owed", and it does not land until a CONTRACT_REVIEW_TIER record PASS is on its head.
{
"issue": 27661,
"status": "done",
"branch": "claude/project-thread-c3dfhl",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27794",
"session": "session_017ihL2eCEdjSZBk7DGrPPFg",
"premise_still_valid": true,
"summary": "Premise held on origin/main 481ade61 (and 3702be40): resolveInjectedColumnProvenance has no columnMap arm, plugin-sharing hasPhantomOwnerAnchor restated the identity comparison plus mapsRemoteColumnOntoOwner, lint hasUnprovableOwnerAnchor restated columnMapTargets, and the #7858 convergence row named the bare provenance verdict. @objectstack/spec/data now exports isOwnerAnchorUnprovable(def) (provenance(owner_id) === injected-unprovisioned AND no external.columnMap value owner_id) and externalColumnMapTargets(def, field); plugin-sharing's hasPhantomOwnerAnchor and lint's hasUnprovableOwnerAnchor return it, lint's externalOwnershipGap reads externalColumnMapTargets, and the four private copies in federated-phantom-anchors.ts are deleted. resolveInjectedColumnProvenance is unchanged by design (PM-accepted plan): lint's security-external-owner-unmapped needs mapped-but-undeclared to stay distinct. Two unpinned edge moves (hand-built doc with no owner_id key; byte-identical declared owner_id on a tier that withholds it) are named in the PR's Acceptance notes, both closed. Head e402956d = fe45a398 + merge of origin/main 79d78b4e via os-regen-merge.sh (two earlier wip commits on the branch; the queue squashes).",
"tests": "Final head e402956d, heavy runs under scripts/pm/os-verify-lock.sh. spec full test (on fe45a398, spec/src/data unchanged by the merge): Test Files 754 passed (754), Tests 22410 passed | 1 todo; plugin-sharing vitest run: 58/58 files, 1290/1290 tests; lint vitest run: 178/178 files, 7623/7623 tests (validate-external-owner-sharing.test.ts, external-owner-anchor-sql-read.test.ts and the federated phantom-scoping suites unchanged and green, so verdicts, findings and hints keep their bytes); metadata-core test 21/21 files, 873/873; spec/lint/plugin-sharing typecheck exit 0. New: 4 cases in packages/spec/src/data/injected-system-column-provenance.test.ts (10/10). Ablation on the committed head: deleting the columnMap guard in isOwnerAnchorUnprovable (grep -c 0 mutated, 1 restored) + spec rebuild turned plugin-sharing sql-read + phantom-scoping 3 failed of 55 and lint owner-sharing + security-posture 1 failed of 202; restored via git checkout HEAD, git diff HEAD empty, rebuilt: 55/55 and 202/202.",
"gates": "Local subset on e402956d after a full pnpm build (lock VERDICT exit 0): dispatch-gates --commands derived 86 families (86 before and after the merge), every one run with its exit code recorded before any pipe: 86 exit 0 (spec check:api-surface unchanged-surface line, check:export-origins 5651 exports, check:docs 232 in sync, check:generated 14/14 up to date, check:dual-build-cjs-loads, check:lean-entry-closure, check:i18n, check:type-check-debt, check-adr-0087-registration / check-empty-changeset / check-changeset-no-major --base origin/main, the self-tests). dispatch-gates --ran: 86 derived, 86 run, 0 NOT-MEASURED, 0 UNRUN. Before the merge check:generated found api-surface/ and export-origins/ stale (the two new names), regenerated and committed. PR check-runs: in_progress at report time (PR opened 23:27Z); not waited on, per the role file.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"line_budget": "n/a — the claim sets none; three-dot diff vs origin/main: 8 files, +176/-116",
"files_changed": [
".changeset/27661-owner-anchor-one-reader.md",
"packages/lint/src/validate-external-owner-sharing.ts",
"packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts",
"packages/plugins/plugin-sharing/vitest.config.ts",
"packages/spec/api-surface/data.json",
"packages/spec/export-origins/data.json",
"packages/spec/src/data/injected-system-column-provenance.test.ts",
"packages/spec/src/data/injected-system-column-provenance.ts"
],
"mcp_calls": "4 reads, 0 GitHub writes — issue_read (get #27661, get_comments #27661), pull_request_read (get #27658 for the body form); plus claude-code-remote subscribe_pr_activity #27794 (harness default). One unauthenticated REST read of #27583 comments for the report form.",
"api_writes": "2 relay writes as objectstack-fleet[bot]: (1) fleet-write pr_create, run 40973266290 = #27794 (draft forced, no assignees, no labels; read-back 11542 bytes sent, 11542 stored, identical); (2) post-stamped --comment=27661, this report. Plus 4 git pushes to claude/project-thread-c3dfhl.",
"open_questions": [],
"deviations": [
"Report comment: the signature line comes first and os-dev-report second, as post-stamped requires; the role file wants os-dev-report on the first line.",
"Two wip commits (no trailer, committed with --no-verify) sit under the final commit on the branch; the branch is not claude/issue-*, so no force-push to squash them. The final commit fe45a398 carries the model-free trailer pair; the queue squash-merges.",
"File surface: packages/plugins/plugin-sharing/vitest.config.ts (one comment that described the deleted comparison) is outside the claim's list; it is the package's test config, comment-only.",
"PR subscription: subscribed to #27794 as the harness asks; no CI waiting or polling in this round."
],
"out_of_scope_findings": [
"carrier: none · noted, not filed — packages/qa/dogfood/test/federated-phantom-share-grant.dogfood.test.ts L251-L256 still calls hasPhantomOwnerAnchor hand-rolled; a historical test comment. Dedupe words: dogfood phantom share grant hand-rolled comment.",
"carrier: none · noted, not filed — plugin-security's tenant twin (federated-phantom-anchors.ts, hasPhantomTenantAnchor) still carries its own identity comparison; the convergence row #7859 keeps it opportunistic and it has no columnMap arm. Dedupe words: hasPhantomTenantAnchor convergence equalsShippedDef plugin-security."
]
}
PR #27794 merged through the queue as 684f2f652c7a0dbf5f030a6582aa62b35791a602 (head db96a59d; contract review PASS 6511315513 at CONTRACT_REVIEW_TIER, which also served as the full review of the spec change; seat ACCEPT 6511399450). @objectstack/spec/data now exports isOwnerAnchorUnprovable and externalColumnMapTargets, the one reader of "is an external object's owner provable from declared metadata". Plugin-sharing and lint read it. plugin-sharing's isFederatedObject stays as a one-line read of platformProvisionsStorage, because #27760 imports it. The record's two doc-only should-fixes ride #27803.
Activity
objectstack-fleet commentedon Oct 29, 2026
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
Claim: PM loop round 7 2026-10-29T21:57Z
Session:
session_017ihL2c5z3q4h8inrn5kwqV(epic PM); implementing card threadsession_017ihL2eCEdjSZBk7DGrPPFgAccount:
marchtianBranch:
claude/project-thread-c3dfhl(the card thread's platform-assigned branch — measured platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27661Domain:
domain:specSeat:
epic:#27261#1(epic PM; nodomain:*seat). Maintainer order, 田騏 2026-10-29T21:50Z: 「给我解释后续还有哪些卡,以及为什么不派」 (epic subtree p3 cards are dispatched, not left by pull)File surface:
packages/spec/src/data/injected-system-column-provenance.ts(one exported owner-anchor reader plus itscolumnMapreader; the #7858 convergence row),packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts(hasPhantomOwnerAnchorreads the spec pair),packages/lint/src/validate-external-owner-sharing.ts(hasUnprovableOwnerAnchor/columnMapTargetsread the spec pair), their tests, generated references the spec change re-records,.changeset/**(stop on breach; explain in the report)Container & model:
S,mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes
Metadata-protocol: none
Responsibility: #27425 (PR #27476) added the
columnMap→owner_idarm in plugin-sharing only; review 6493803142 ④ should-fix 1 and seat carry 6493297056Thread-read: none
Premise: holds — on
origin/mainresolveInjectedColumnProvenancehas nocolumnMaparm while plugin-sharing'smapsRemoteColumnOntoOwnerand lint'scolumnMapTargetseach read it.Serial constraints: #27662 (card thread) edits plugin-sharing's write-deny diagnostic, not
federated-phantom-anchors.ts's predicate; say in the report if the two overlap. Contract face (published spec +Clause-②: yes): the PR body says "Fable review owed", and it does not land until aCONTRACT_REVIEW_TIERrecord PASS is on its head.objectstack-fleet commentedon Oct 29, 2026
epic:#27261#1 · marchtian · session_017ihL2eCEdjSZBk7DGrPPFg
os-dev-report
{ "issue": 27661, "status": "done", "branch": "claude/project-thread-c3dfhl", "pr": "https://github.com/objectstack-ai/objectstack/pull/27794", "session": "session_017ihL2eCEdjSZBk7DGrPPFg", "premise_still_valid": true, "summary": "Premise held on origin/main 481ade61 (and 3702be40): resolveInjectedColumnProvenance has no columnMap arm, plugin-sharing hasPhantomOwnerAnchor restated the identity comparison plus mapsRemoteColumnOntoOwner, lint hasUnprovableOwnerAnchor restated columnMapTargets, and the #7858 convergence row named the bare provenance verdict. @objectstack/spec/data now exports isOwnerAnchorUnprovable(def) (provenance(owner_id) === injected-unprovisioned AND no external.columnMap value owner_id) and externalColumnMapTargets(def, field); plugin-sharing's hasPhantomOwnerAnchor and lint's hasUnprovableOwnerAnchor return it, lint's externalOwnershipGap reads externalColumnMapTargets, and the four private copies in federated-phantom-anchors.ts are deleted. resolveInjectedColumnProvenance is unchanged by design (PM-accepted plan): lint's security-external-owner-unmapped needs mapped-but-undeclared to stay distinct. Two unpinned edge moves (hand-built doc with no owner_id key; byte-identical declared owner_id on a tier that withholds it) are named in the PR's Acceptance notes, both closed. Head e402956d = fe45a398 + merge of origin/main 79d78b4e via os-regen-merge.sh (two earlier wip commits on the branch; the queue squashes).", "tests": "Final head e402956d, heavy runs under scripts/pm/os-verify-lock.sh. spec full test (on fe45a398, spec/src/data unchanged by the merge): Test Files 754 passed (754), Tests 22410 passed | 1 todo; plugin-sharing vitest run: 58/58 files, 1290/1290 tests; lint vitest run: 178/178 files, 7623/7623 tests (validate-external-owner-sharing.test.ts, external-owner-anchor-sql-read.test.ts and the federated phantom-scoping suites unchanged and green, so verdicts, findings and hints keep their bytes); metadata-core test 21/21 files, 873/873; spec/lint/plugin-sharing typecheck exit 0. New: 4 cases in packages/spec/src/data/injected-system-column-provenance.test.ts (10/10). Ablation on the committed head: deleting the columnMap guard in isOwnerAnchorUnprovable (grep -c 0 mutated, 1 restored) + spec rebuild turned plugin-sharing sql-read + phantom-scoping 3 failed of 55 and lint owner-sharing + security-posture 1 failed of 202; restored via git checkout HEAD, git diff HEAD empty, rebuilt: 55/55 and 202/202.", "gates": "Local subset on e402956d after a full pnpm build (lock VERDICT exit 0): dispatch-gates --commands derived 86 families (86 before and after the merge), every one run with its exit code recorded before any pipe: 86 exit 0 (spec check:api-surface unchanged-surface line, check:export-origins 5651 exports, check:docs 232 in sync, check:generated 14/14 up to date, check:dual-build-cjs-loads, check:lean-entry-closure, check:i18n, check:type-check-debt, check-adr-0087-registration / check-empty-changeset / check-changeset-no-major --base origin/main, the self-tests). dispatch-gates --ran: 86 derived, 86 run, 0 NOT-MEASURED, 0 UNRUN. Before the merge check:generated found api-surface/ and export-origins/ stale (the two new names), regenerated and committed. PR check-runs: in_progress at report time (PR opened 23:27Z); not waited on, per the role file.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "line_budget": "n/a — the claim sets none; three-dot diff vs origin/main: 8 files, +176/-116", "files_changed": [ ".changeset/27661-owner-anchor-one-reader.md", "packages/lint/src/validate-external-owner-sharing.ts", "packages/plugins/plugin-sharing/src/federated-phantom-anchors.ts", "packages/plugins/plugin-sharing/vitest.config.ts", "packages/spec/api-surface/data.json", "packages/spec/export-origins/data.json", "packages/spec/src/data/injected-system-column-provenance.test.ts", "packages/spec/src/data/injected-system-column-provenance.ts" ], "mcp_calls": "4 reads, 0 GitHub writes — issue_read (get #27661, get_comments #27661), pull_request_read (get #27658 for the body form); plus claude-code-remote subscribe_pr_activity #27794 (harness default). One unauthenticated REST read of #27583 comments for the report form.", "api_writes": "2 relay writes as objectstack-fleet[bot]: (1) fleet-write pr_create, run 40973266290 = #27794 (draft forced, no assignees, no labels; read-back 11542 bytes sent, 11542 stored, identical); (2) post-stamped --comment=27661, this report. Plus 4 git pushes to claude/project-thread-c3dfhl.", "open_questions": [], "deviations": [ "Report comment: the signature line comes first and os-dev-report second, as post-stamped requires; the role file wants os-dev-report on the first line.", "Two wip commits (no trailer, committed with --no-verify) sit under the final commit on the branch; the branch is not claude/issue-*, so no force-push to squash them. The final commit fe45a398 carries the model-free trailer pair; the queue squash-merges.", "File surface: packages/plugins/plugin-sharing/vitest.config.ts (one comment that described the deleted comparison) is outside the claim's list; it is the package's test config, comment-only.", "PR subscription: subscribed to #27794 as the harness asks; no CI waiting or polling in this round." ], "out_of_scope_findings": [ "carrier: none · noted, not filed — packages/qa/dogfood/test/federated-phantom-share-grant.dogfood.test.ts L251-L256 still calls hasPhantomOwnerAnchor hand-rolled; a historical test comment. Dedupe words: dogfood phantom share grant hand-rolled comment.", "carrier: none · noted, not filed — plugin-security's tenant twin (federated-phantom-anchors.ts, hasPhantomTenantAnchor) still carries its own identity comparison; the convergence row #7859 keeps it opportunistic and it has no columnMap arm. Dedupe words: hasPhantomTenantAnchor convergence equalsShippedDef plugin-security." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV
Landed · 2026-10-30T00:35Z
PR #27794 merged through the queue as
684f2f652c7a0dbf5f030a6582aa62b35791a602(headdb96a59d; contract review PASS 6511315513 atCONTRACT_REVIEW_TIER, which also served as the full review of the spec change; seat ACCEPT 6511399450).@objectstack/spec/datanow exportsisOwnerAnchorUnprovableandexternalColumnMapTargets, the one reader of "is an external object's owner provable from declared metadata". Plugin-sharing and lint read it. plugin-sharing'sisFederatedObjectstays as a one-line read ofplatformProvisionsStorage, because #27760 imports it. The record's two doc-only should-fixes ride #27803.