fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door - #13481

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to
Aug 30, 2026
Merged

fix(driver-mongodb): refuse the rejected alias reference_to at the schema door#13481
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-13222-mongodb-refuse-reference-to

Conversation

@claude

@claudeclaudeBot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #13222 — deliberately Part of and not a closing keyword. The card as filed covers two things; the maintainer's 2026-08-30 ruling (verbatim 「13222 A」) takes part (1) only, and part (2) is a separate ruling carried in a later batch. mongodb-schema-declared-indexes.test.ts still names #13222 as the owner of part (2), so auto-closing the card on merge would leave that pin pointing at a closed issue. Close it by hand once part (2) has its own home.

What this does

syncCollectionSchema gated its field-level join index on field.reference_to. reference is the only relationship spelling @objectstack/spec declares; reference_to is a rejected alias. So one key had two doors with opposite answers, and the silent one was the one that touched the database.

A field still carrying reference_to when it reaches schema sync now throws VALIDATION_ERROR/400, naming it as a rejected alias in the same words FieldSchema uses. No deprecation window, per the ruling.

Where the door sits, and why it agrees with the SQL door

The SQL door (sql-driver.ts:15191, #11567) is stated before the multiple short-circuit and before the type switch, on the predicate field.reference_to !== undefined. Measured against @objectstack/spec built from this tree, that placement is the spec's own shape:

fixtureFieldSchema.safeParse
{ type:'lookup', reference_to:'company' }success:false, unrecognized_keys
{ type:'text', reference_to:'company' }success:false, unrecognized_keyssame verdict, different type
{ type:'lookup', reference_to: null } / ''success:false, unrecognized_keys — same verdict again
{ type:'lookup', reference:'company' }success:true
{ ..., reference_to: undefined } (own key present)success:false — the schema's predicate is key PRESENCE
canonical output's own keysdoes not include reference_to

⇒ The verdict is gated on neither type nor value, so neither may gate the driver. mongodb-schema.ts has no type switch, so the equivalent placement is ahead of the whole field loop — which also puts it ahead of db.createCollection, so a refused sync leaves nothing behind. The predicate is !== undefined, identical to the SQL door: both doors are narrower than the schema by exactly one shape (an explicitly-spread undefined), and identically so.

⛔ What this deliberately does NOT change

The join-index arm is byte-identicalgit diff shows no +/- line inside it. Its field.reference_to conjunct is now unreachable, and deleting it would start building idx_FIELD_lookup for canonical reference lookups: a boot-time behaviour change for deployments holding large collections, and part (2)'s unruled call. The arm's observable behaviour is exactly what it was, pinned by the last case in the new suite: a user field is indexed, a canonical reference lookup is not. mongodb-schema-declared-indexes.test.ts (#12252's pin) and mongodb-driver.test.ts (#13224's) are untouched and stay green.

Why minor and not patch

#11567 graded its half patch on "no authored deployment could reach the branch". That does not transfer. This package's own published README.md taught reference_to inside a sample calling driver.syncSchema(...)directly, and syncSchema(object, schema: unknown) casts and forwards verbatim with no Zod (mongodb-driver.ts:632-641). README.md is in the package files array, so it shipped at @objectstack/driver-mongodb 17.2.0 and every earlier version. The affected population is non-zero by construction. The changeset's upgrade note names that population.

Re-read on this branch, as asked: README.md no longer teaches the key. Its only remaining reference_to is at :167-168, prose recording that the spelling is refused; the sample at :176 spells reference: 'company'.

Reverse verification (ablation)

Prediction stated before running: RED, and only the six door-dependent cases. Procedure: implementation committed FIRST (23cc629a47), then the door block deleted from mongodb-schema.ts under an EXIT INT TERM trap with an absolute REPO_ROOT.

  • Mutation proven on disk before measuring — anchor count 1, door call-site grep -c went 1 to 0, git hash-object1a55193a to 298d86b4.
  • No rebuild needed, and that is a stated condition, not an omission: the suite imports ./mongodb-schema.js, a relative in-package specifier that vitest resolves to source. No exports hop to dist/, so this pair is outside KNOWN_UNALIASED_TEST_IMPORTS' concern. The red below is itself the proof the source is what ran.
  • Result: vitest exit 1 — 6 failed, 9 passed. Exactly the predicted six; the two door-independent cases and all seven of the sibling mongodb-schema-declared-indexes.test.ts cases stayed green, which is the control that the harness was wired to something.
  • Restore proven: git checkout HEAD -- ABSOLUTE_PATH, then on-disk hash back to 1a55193a and byte-equal to the HEAD blob, git diff HEAD0 bytes, git status --porcelain empty, door call-site count back to 1.

Docs callout — a bounded in-place correction, declared

content/docs/protocol/objectql/types.mdx:734 carried a warn whose middle clause read "The SQL driver's FK DDL is gated on a reference_to property…" — present tense. #11567 retired that DDL and put a refusal in its place (sql-driver.ts:15191), so writing the new MongoDB sentence beside it would have produced a self-contradicting callout: SQL still honouring the key while MongoDB refuses it, which is the opposite of the ruling. The clause is corrected to what landed, evidence being the landed refuseRejectedReferenceAlias call site, and the MongoDB half added beside it. No other content moved; master_detail / tree and the deleteBehavior sentence are preserved.

Gates, all run locally at 00fd198c10

Family derived from the real diff, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (4 paths vs merge base 71627f7b4). Exit codes captured before any pipe.

  • Repo-wide eslint . --no-inline-config — exit 0, 62s, zero bytes of output. No narrowing was needed, so none is claimed.
  • pnpm --filter @objectstack/driver-mongodb test504 passed, 143 skipped (the 5 opt-in mongodb-memory-server suites, driver-mongodb 测试:两个套件并发下载 MongoDB 二进制,mongodb-memory-server 的 rename 竞态让全绿测试 exit 1(队列 flaky) #5517). typecheck exit 0.
  • ⚠️ This package's tsconfig.jsonexcludes every *.test.ts, so typecheck says nothing about the new suite — measured with --listFiles: 0 hits for it. The number that does cover it is the TEST_DEBT ratchet, and it is green: pnpm check:type-check-debt"29 ledger entr(ies) re-measured in 227.1s, 1547 raw tsc error(s) total, none above its recorded number", on a fully built workspace. Reconstructed separately for this package alone: exactly 10 raw errors, TS1309 x7 + TS2550 x3 — byte-for-byte the composition the ledger records — with 0 diagnostics naming the new file.
  • 49 further gate invocations from the derived family, every one exit 0: nul-bytes · changeset-gate-self-tests · empty-changeset · changeset-no-major · adr-0087-registration · objectui-changeset · pm-half-states · keyed-text-bounds · release-rehearsal-clone --self-test · doc-anchors · doc-authoring · docs-single-h1 · docs-redirects · docs-audit-scope · role-word · doc-frontmatter · doc-route-spelling · docs-section-name · section-landing-index · published-readme-links · react-page-adapter-contract · cross-package-test-inputs (both spellings) · test-source-alias · type-source-resolution · driver-conformance · engine-double-contract · where-matcher · query-options-erasure · objectql-double-limit · logger-receiver-detach · slot-lookup · page-declaration-shape · published-files · comment-mask-adoption · undeclared-dep-imports · plugin-teardown-shape · type-check-coverage · ci-filter-parity · shard-attestation · dual-build-cjs-loads · spec check:docs / yaml-examples / skill-examples / empty-state / liveness / strictness-ledger / variant-docs · lint doc-formula-expressions / doc-security-posture.
  • check:doc-authoring caught a real red on the first pass and it is repaired in 00fd198c10: the runtime message carried an internal tracker id, which reaches operators who cannot resolve it. The pointer moved to the adjacent TSDoc.
  • NOT MEASURED, stated as such rather than as green: scripts/pm/check-half-states.mjs (exit 3, PREREQUISITE NOT MET — no GitHub credential in this container; it swept nothing) and scripts/check-test-completeness.mjs (exit 3 — it needs a saved turbo run test log, which the family invocation cannot supply).

Files

  • packages/drivers/driver-mongodb/src/mongodb-schema.ts — the door, its TSDoc, and FieldDef.reference_to re-typed unknown and re-documented as a refused key the door reads.
  • packages/drivers/driver-mongodb/src/mongodb-13222-reference-to-refusal.test.tsnew; one path beyond the file surface my dispatch listed, added because the dispatch also required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declared here rather than left for a reviewer to notice.
  • content/docs/protocol/objectql/types.mdx — the callout above.
  • .changeset/mongodb-refuse-rejected-reference-to-alias.mdminor.

skills/** is untouched, so the published-skill line-count readings do not apply.


Generated by Claude Code

…schema door
`syncCollectionSchema` gated its field-level join index on `field.reference_to`.
`reference` is the only relationship spelling `@objectstack/spec` declares;
`reference_to` is a rejected alias (`FieldSchema` answers `unrecognized_keys`
for it on any field type, carrying any value). So one key had two doors with
opposite answers, and the silent one was the one that touched the database.
The door is stated ahead of `createCollection` and ahead of every per-field
branch, matching the placement `sql-driver.ts` uses for its copy: the spec's
verdict is gated on neither the field's type nor the key's value, so neither may
gate the driver's. Predicate is `!== undefined`, identical to the SQL door.
The join-index arm is left byte-identical and its `field.reference_to` conjunct
is now unreachable, deliberately: deleting it would start building
`idx_FIELD_lookup` for canonical `reference` lookups, which is a boot-time
behaviour change for existing deployments and a separate, still-open ruling.
Graded `minor`, not `patch`: this package's published README taught the key in a
sample calling `driver.syncSchema` directly, and `syncSchema` forwards verbatim
with no Zod, so the affected population is non-zero by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
…message
`check:doc-authoring`'s sibling-package prose-id leg went red on the new
message: a runtime string reaches authors, operators and generated surfaces,
none of whom can resolve an internal issue id. The pointer stays in the adjacent
TSDoc, where the reader who can resolve it already is.
Maintainer ruling 2026-08-12, verbatim: 「处理 issue 时犯的错应该总结成经验,保留 issue id没有意义」
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3jdziLbAPGeceVNmSox5L
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/driver-mongodb, touching 6 documentable anchor(s).

1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/protocol/objectql/types.mdx(via reference_to (symbol), reference_to (literal))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via reference_to (symbol), reference_to (literal))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 6 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344packageMentionDocs.

Which tree this was computed on

This run read content/docs from 1bea04b50853c62ba12ab21e0794060a177195aa — the merge of head 00fd198c10499df823ebec788bf19e87143c1e1a into base 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 1bea04b50853c62ba12ab21e0794060a177195aa && git checkout 1bea04b50853c62ba12ab21e0794060a177195aa
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 00fd198c10499df823ebec788bf19e87143c1e1a && git checkout -B drift-repro 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 && git merge --no-ff 00fd198c10499df823ebec788bf19e87143c1e1a
node scripts/docs-audit/affected-docs.mjs --json 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 8fcd0816dadc10c66aa7a5d2fa5d8b57e7844344 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 30, 2026
@zhuangjianguoClaude

Copy link
Copy Markdown
Collaborator

PM review — ACCEPT. Verified by content, on the diff and on origin/main (9cfc1f7e93), not from the report.

What I checked myself

  1. Fence sweep, on the actual diff (4 files). 0 lines in content/docs/releases/, packages/spec/**, docs/adr/**, .claude/**, skills/**. mongodb-schema-declared-indexes.test.ts (9 fixtures across 6 packages declare reference_to on a lookup — a key FieldSchema refuses — and the SQL driver's FK-emission branch has no test at all #12252's pin) and mongodb-driver.test.ts (test(driver-mongodb): correct the last reference_to fixture, pin the divergence it hid, and stop the published README teaching it #13224's) — 0 lines each.

  2. The join-index arm is byte-identical — confirmed on the diff, not on the claim.mongodb-schema.ts carries exactly four hunks: the StandardErrorCode import, FieldDef.reference_to, the new refuseRejectedReferenceAlias with its TSDoc, and the door loop at the top of syncCollectionSchema. No +/- line falls inside the arm. This was the one place the ruling could have silently overreached into part (2), and it did not.

  3. No new runtime dependency.@objectstack/spec is already a dependencies entry of @objectstack/driver-mongodb on main, so the StandardErrorCode import adds no edge. A new runtime dependency would have been a maintainer call, not a seat's to accept — worth stating that it was checked rather than assumed.

  4. The minor grade holds.README.md on main no longer teaches the key: :167-168 is prose recording that the spelling is refused, and the sample at :176 spells reference:. So the grade rests entirely on the historically shipped population, and the upgrade note names it — the file is in the package files array, it shipped at @objectstack/driver-mongodb 17.2.0 and earlier, and syncSchema(object, schema: unknown) forwards verbatim with no Zod. That is the harder of the two available grades and the right one; patch would have inherited [finding] docs vs driver disagree on whether lookup columns get a real FOREIGN KEY — and the driver branch keys on reference_to, not reference #11567's "no authored deployment could reach the branch", which does not transfer.

  5. The docs callout — the one claim in this PR about a different driver, so the one I would not take on report. Verified on main: sql-driver.ts:15191 reads if (field.reference_to !== undefined) refuseRejectedReferenceAlias(name);, :15414 records [#11567] ⛔ This arm emits NO FOREIGN KEY, and :1508 states "The emission is retired; this is the door." The callout's old present-tense clause — "The SQL driver's FK DDL is gated on a reference_to property" — was already false on main before this PR. The correction is true, bounded to that clause, and declared in the body. Accepted as in-scope.

The open question — ruling A: keep Part of, add no closing keyword

The 2026-08-30 ruling takes part (1) only and carries part (2) in a later batch, and two live pins name #13222 as part (2)'s owner. Part of leaves the card open, which is the recoverable direction: if A is wrong, someone closes a card by hand; if B were wrong, a live card shuts silently and two pins aim at a closed issue with no owner. #13222 therefore stays open after this merges — whoever takes part (2) either closes it in that stroke or gives the pins a new number.

The declared deviation is accepted

The new suite is one path beyond the file surface the dispatch listed, and it is there because the same dispatch required the behaviour be driven through the fake-Db recorder rather than the opt-in mongod lane. Declaring it in the body rather than leaving it for a reviewer to notice is the right handling.

Landing posture

⛔ Held as draft until every check on 00fd198c10 is green — every check, not the required subset. Nothing is red as I write this (Test Core 3–6, Build Docs, Check Changeset, Spec property liveness, Type Check · source gates, Governed Surface Queue Guard and the three claim guards all green; the remainder in flight). When it is fully green I flip ready and enqueue. ⛔ I do not merge it.


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@zhuangjianguo@claude