Repository navigation
docs(adr-0120): record the caller-supplied id collision on the create doors as an accepted residual, document it, pin it - #28694
Conversation
…d residual, document it, and pin it at the HTTP door ADR-0120 gains a dated amendment under its business-requirement matrix: S10's no-oracle promise covers 'organization' uniqueness only; the record id is the one deployment-global key, and a create colliding on it answers 409 UNIQUE_VIOLATION, writes nothing, names no organization or owner, and is the same for every visibility of the holding row. It extends ruling record 5934879010 rule 2 from upsert to every create door and to the same-organization half, and lists the options considered and rejected. http-protocol.mdx Create Record documents the caller-supplied id and the collision answer. Two dogfood files pin today's behaviour on three create doors: same organization on the stock showcase, another organization on a walled two-organization boot. No product code changes. Claude-Session: https://claude.ai/code/session_017xRBcVy4VXmkQjn2MGeaWk Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 2 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 77c6ae8af5282975109f93e51459e9084128b6f0 && git checkout 77c6ae8af5282975109f93e51459e9084128b6f0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin da6f0ce35da60bf81e79890b227815a989f9b165 393827105956c4e4040116fe0a3471b899a0556d && git checkout -B drift-repro da6f0ce35da60bf81e79890b227815a989f9b165 && git merge --no-ff 393827105956c4e4040116fe0a3471b899a0556d
node scripts/docs-audit/affected-docs.mjs --json da6f0ce35da60bf81e79890b227815a989f9b165 |
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk Contract reviewServed-tier: Read-only, from the net diff ① Derived judgmentsFace: governed rules text (
② Semver level
③ Boundary flags
④ Design judgment
Must-fix: none. Implemented-by: VERDICT: PASS Generated by Claude Code |
The 409 UNIQUE_VIOLATION answer to a create colliding on id holds on a store that enforces the primary key: the SQL-family drivers do, while driver-memory (the dev and edge fallback) declares no primary key and lands a duplicate id. The ADR-0120 amendment note's second fact and the http-protocol.mdx Create Record paragraph now say so, so neither states anything false on a shipped driver. Claude-Session: https://claude.ai/code/session_017xRBcVy4VXmkQjn2MGeaWk Co-authored-by: Claude <noreply@anthropic.com>
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk Contract reviewServed-tier: Delta review by the same reviewer, per contract-review.md: one findings-only commit ① Derived judgmentsThe delta adds one qualifier to the ADR note's second fact and to the page's Create Record paragraph: "on a store that enforces the primary key". Each sentence it introduces, judged:
② Semver levelUnchanged: ③ Boundary flags
④ Design judgmentThe qualifier makes the ADR's recorded fact true on the tree: it names the stores on which the contract is a store-level refusal and the one shipped store on which it is not, without widening the ruling or adding a store the code does not prove. The page restates the same scoping in one clause, consistently with the ADR. The only sentence the delta introduces that the tree does not support is the driver-memory descriptor in ①.4, a characterisation rather than a contract: a should-fix, not a false promise about any door. Must-fix: none. Implemented-by: VERDICT: PASS Generated by Claude Code |
…iver The precondition clause called driver-memory a dev and edge fallback. Its README lists development, unit tests, Storybook and MSW mocks and marks production unsupported, and edge is driver-turso's role. Both the ADR-0120 amendment note and the http-protocol.mdx Create Record paragraph now call it the development and test driver, not a production store. Claude-Session: https://claude.ai/code/session_017xRBcVy4VXmkQjn2MGeaWk Co-authored-by: Claude <noreply@anthropic.com>
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk Contract reviewServed-tier: Delta review by the same reviewer, per contract-review.md: one findings-only commit ① Derived judgments
② Semver levelUnchanged: ③ Boundary flags
④ Design judgmentThe delta changes a descriptor, not a contract: the store precondition the amendment records is as judged in 6559270010, and the one sentence that record found unsupported now says what the driver's own README says. No should-fix remains open on the governed text from this reviewer's records other than the sibling-ordering item in ③, which is the sibling's to carry. Must-fix: none. Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk ACCEPT → head 维护者速读
席位意见:收。本 PR 落实维护者 2026-11-01 在 PM 会话里对 C1 的裁定(选 f,原话「同意」):把裁决 5934879010 细则 2 延伸到所有新建入口,并覆盖同组织内被隐藏的那一半。 席位核对
Generated by Claude Code |
domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk
维护者速读
id是全部署唯一键,新建撞上已有id一律同一种拒绝」这一已接受的残余;HTTP 协议文档 Create Record 一节补上调用方自带id与撞键的回答;新增两个 dogfood 用例钉住今天的行为。零产品代码改动。docs/adr/0120-unique-scope-vocabulary-and-null-safe-tenant-uniqueness.md(修订注记全文,对照你 2026-11-01 的「同意」)→content/docs/protocol/kernel/http-protocol.mdx(Create Record 新增段)→packages/qa/dogfood/test/create-caller-id-collision-walled.dogfood.test.ts(跨组织一侧的断言)。pnpm --filter @objectstack/dogfood exec vitest run test/create-caller-id-collision.dogfood.test.ts test/create-caller-id-collision-walled.dogfood.test.ts,预期 2 个文件、30 个用例全绿。docs/adr/**(Tier H),请审阅修订注记措辞后亲手合并或入队。What changes
A docs + pin PR that records a maintainer ruling. No product code changes.
'organization'uniqueness only; that the recordidis the one deployment-global key; and that a create colliding on it answers one refusal, identical for every visibility of the row that holds the id, naming no organization or owner. It records the ruling chain (ruling record5934879010rule 2, extended by the maintainer on 2026-11-01 from upsert to every create door and to the same-organization half) and the options considered and rejected.content/docs/protocol/kernel/http-protocol.mdx, Create Record: a caller may supplyid; the duplicate-idanswer (409 UNIQUE_VIOLATION, nothing written, no owner or organization detail, the same for every visibility, on every create door).POST /data/:object, per-object batch create and the cross-objectPOST /batch:create-caller-id-collision.dogfood.test.ts— same organization, stock showcase (added to theshared-showcaseproject: no boot options, no metadata or organization writes, assertions scoped to its own rows).create-caller-id-collision-walled.dogfood.test.ts— another organization, walled two-organization boot underisolatedandgroup; the wall itself is measured in a precondition case rather than assumed.idlands as given (control); the hidden-row and visible-row collisions return the same status and the same body, whole; both rows are byte-identical after; the body names no organization, owner, or user.The pins confirm today's behaviour matches the ruling: no answer differed by visibility and none named an organization, so there was nothing to stop and report.
Tests
pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=1on the two new files, under the verify lock:Test Files 2 passed (2),Tests 30 passed (30), lockVERDICT command-exit 0.shared-showcaseproject, which the same-organization file joins. Reason: five verify-lock attempts answered99(queue-timeout) over about 45 minutes behind a sibling dispatch's full-suite hold; CI's dogfood gate runs the project. The new file itself ran inside that project (on its own boot of the shared stack) and passed in the run above.tsc -pover a temporary config that extends the package'stsconfig.jsonwithfilesset to the two new tests (deleted afterwards, tree clean): exit 0, both files in the program (--listFiles, 1113 files), zero errors. The package-widepnpm --filter @objectstack/dogfood typecheckis NOT MEASURED locally, for the same lock-queue reason; CI'sTypeScript Type Checkruns it.Acceptance notes
bootStack(..., { multiTenant: 'posture-only' }). That option's docblock inpackages/verify/src/harness.tssays the stand-in "stamps noorganization_idand scopes no query"; on this boot the row is stamped with the creating organization and another organization's member reads404for it, both asserted in the precondition case. Noted, not filed: a docblock reading, outside this PR's scope.createMany, import insert and upsert, cloneoverrides.id) are named in the ADR note and the doc; they are not pinned by this PR.docs/adr/**,content/docs/**and the private@objectstack/dogfoodpackage, none of which ships in any published package'sfiles[]. Declared withskip-changesetat creation.Verification
Head
393827105. It adds two commits on top ofc2c7d9183, both from the contract-tier review, both prose-only in the same two files:41e8ea516: the ADR-0120 note's second fact and the Create Record paragraph inhttp-protocol.mdxnow name the store precondition. The 409 holds on a store that enforces the primary key (the SQL-family drivers);driver-memorydeclares none.393827105: the same two hunks calldriver-memorythe development and test driver, not a production store. This replaces a descriptor that its README does not support.Re-run at
393827105, exit codes captured before any pipe:node scripts/check-adr-links.mjs:: exit 0 (965 relative link destinations resolve)pnpm check:adr-index:: exit 0 (docs/adr/README.md is current)pnpm check:doc-anchors:: exit 0 (855 internal fragment links resolve)pnpm check:doc-authoring:: exit 0The dogfood run, the narrowed type check and the derived gate families below were taken at
c2c7d9183. The two commits after it touch neither test file and no gate-read path outside those two prose files. Not run locally by design:test:repo(this diff edits none of its tests, and the derivation names none of it) and the repo-wide scans CI owns.Derived gate families (dispatch-gates --commands, reconciled with --ran)
Each line is
command :: exit code, captured before any pipe.node scripts/check-adr-links.mjs:: exit 0node scripts/check-adr-links.mjs --self-test:: exit 0node scripts/check-closing-keyword-parity.mjs:: exit 0node scripts/check-closing-keyword-parity.mjs --self-test:: exit 0node scripts/check-comment-mask-adoption.mjs:: exit 0node scripts/check-comment-mask-adoption.mjs --self-test:: exit 0node scripts/check-comment-mask-corpus.mjs:: exit 0node scripts/check-doc-route-spelling.mjs --advisory:: exit 0node scripts/check-doc-route-spelling.mjs --self-test:: exit 0node scripts/check-docs-section-name.mjs:: exit 0node scripts/check-docs-section-name.mjs --self-test:: exit 0node scripts/check-dts-emitted.mjs --self-test:: exit 0node scripts/check-issue-citations.mjs:: exit 0node scripts/check-plugin-teardown-shape.mjs:: exit 0node scripts/check-plugin-teardown-shape.mjs --self-test:: exit 0node scripts/check-section-landing-index.mjs:: exit 0node scripts/check-section-landing-index.mjs --self-test:: exit 0node scripts/ci/assert-turbo-remote-cache.mjs --self-test:: exit 0node scripts/ci/plan-test-core-shards.mjs --self-test:: exit 0node scripts/ci/prune-turbo-cache.mjs --self-test:: exit 0node scripts/docs-audit/check-affected-docs.mjs:: exit 0node scripts/docs-audit/check-drift-comment.mjs:: exit 0pnpm --filter @objectstack/lint run check:doc-formula-expressions:: exit 0pnpm --filter @objectstack/lint run check:doc-security-posture:: exit 0pnpm --filter @objectstack/spec run check:docs:: exit 0pnpm --filter @objectstack/spec run check:empty-state:: exit 0pnpm --filter @objectstack/spec run check:liveness:: exit 0pnpm --filter @objectstack/spec run check:skill-examples:: exit 3 — NOT MEASURED, PREREQUISITE NOT MET: readspackages/client-react/distdeclarations, outside the dogfood build closure built here; CI runs it in Lint & Repo Gates / TypeScript Type Checkpnpm --filter @objectstack/spec run check:strictness-ledger:: exit 0pnpm --filter @objectstack/spec run check:variant-docs:: exit 0pnpm --filter @objectstack/spec run check:yaml-examples:: exit 0pnpm check:adr-anchors:: exit 0pnpm check:adr-index:: exit 0pnpm check:adr-symbol-anchors:: exit 0pnpm check:ci-filter-parity:: exit 0pnpm check:closed-ceremony-text:: exit 0pnpm check:corpus-claim-drift:: exit 0pnpm check:cross-package-test-inputs:: exit 0pnpm check:doc-anchors:: exit 0pnpm check:doc-authoring:: exit 0pnpm check:doc-frontmatter:: exit 0pnpm check:docs-audit-scope:: exit 0pnpm check:docs-redirects:: exit 0pnpm check:docs-single-h1:: exit 0pnpm check:docs-spec-enumerations:: exit 0pnpm check:docs-transcript-drift:: exit 0pnpm check:driver-memory-census:: exit 0pnpm check:dts-closure:: exit 0pnpm check:dual-build-cjs-loads:: exit 3 — NOT MEASURED, PREREQUISITE NOT MET: reads the dist of seven packages outside the dogfood build closure built here; CI runs it in Lint & Repo Gates / TypeScript Type Checkpnpm check:engine-double-contract:: exit 0pnpm check:gitlink-declared:: exit 0pnpm check:issue-citations:: exit 0pnpm check:keyed-text-bounds:: exit 0pnpm check:lean-entry-closure:: exit 0pnpm check:logger-receiver-detach:: exit 0pnpm check:nul-bytes:: exit 0pnpm check:objectql-double-limit:: exit 0pnpm check:org-identifier:: exit 0pnpm check:page-declaration-shape:: exit 0pnpm check:platform-object-tenancy-census:: exit 0pnpm check:pm-governed-merges:: exit 0pnpm check:pm-prior-rulings:: exit 0pnpm check:published-files:: exit 0pnpm check:published-readme-links:: exit 0pnpm check:query-options-erasure:: exit 0pnpm check:react-page-adapter-contract:: exit 0pnpm check:refd-timer-probe:: exit 0pnpm check:registry-log-declared:: exit 0pnpm check:rest-log-spy-declared:: exit 0pnpm check:role-word:: exit 0pnpm check:skill-identifier-liveness:: exit 0pnpm check:slot-lookup:: exit 0pnpm check:sourcemap-no-sources-content:: exit 0pnpm check:system-context-census:: exit 0pnpm check:test-source-alias:: exit 0pnpm check:tier-file-adoption:: exit 0pnpm check:type-check-coverage:: exit 0pnpm check:type-check-debt:: exit 3 — NOT MEASURED, PREREQUISITE NOT MET: its own closure build never got a turn on the shared verify lock; CI runs it in Lint & Repo Gates / TypeScript Type Checkpnpm check:undeclared-dep-imports:: exit 0pnpm check:vendor-version-stamps:: exit 0pnpm check:watch-hint-literal:: exit 0pnpm check:where-matcher:: exit 0node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE(FILE = the lines above):Generated by Claude Code