Repository navigation
Description
Filed by the domain:engine execution seat while landing the first slice of #16159 (PR #16259). ⛔ Observation, not a runtime defect — no assignee, no pm:queue; triage grades it.
The observation
@objectstack/objectql declares two entry points: . (the batteries-included barrel, src/index.ts) and ./core (the lean ADR-0076 engine entry, src/core.ts). SchemaRegistry is exported from both.
Every error-code constant the package publishes is on . only. Read from the built declarations rather than from the source barrels, because at least one constant reaches index.d.ts without being spelled in index.ts:
| constant | dist/index.d.ts |
dist/core.d.ts |
|---|---|---|
DUPLICATE_RECORD_CODE |
yes | no |
HOOK_TARGET_REBIND_ERROR_CODE |
yes | no |
HOOK_UNSCOPED_DATA_ACCESS_CODE |
yes | no |
MULTI_UPDATE_HOOK_KEY_DIVERGENCE_CODE |
yes | no |
EMPTY_CREDENTIAL_REFUSAL_CODE |
yes | no |
SYSTEM_WRITE_ORGANIZATION_REQUIRED_CODE |
yes | no |
NAMESPACE_CONFLICT_CODE (PR #16259) |
yes | no |
DUPLICATE_ARTIFACT_OBJECT_NAME_CODE (PR #16259) |
yes | no |
OBJECT_OWNERSHIP_CONFLICT_CODE (PR #16259) |
yes | no |
NAV_CONTRIBUTION_GROUP_MISSING |
yes | yes |
⭐ The last row is the firing control for that table and the precedent that makes the question live: one code constant IS on the lean entry, and core.ts carries a docblock saying why (os build reaches it from there, and it costs the entry nothing because it imports nothing).
Corroborating measurement from PR #16259's surface ablation: dist/core.d.ts holds 79 exported names before and after that PR adds three constants, while dist/index.d.ts goes 244 to 247.
Why it may matter
A @objectstack/objectql/core embedder holds SchemaRegistry, so it reaches installPackage and registerObject — the two verbs that raise NAMESPACE_CONFLICT, DUPLICATE_ARTIFACT_OBJECT_NAME and OBJECT_OWNERSHIP_CONFLICT. It can therefore catch those refusals but not import the constants that name them, leaving it to re-spell the literal: precisely the state #16159 exists to remove, and what check:error-code-provenance records as a stamp site in that consumer's own package.
⭐ The counter-argument is real, which is why this is a finding and not a card with a remedy attached: "export them from both" is a published-surface widening per entry point and a policy decision about all nine, not a mechanical repeat. The ADR-0076 D2 boundary ratchet governs protocol/plugin imports, so on its face it does not object to a bare string constant — but that reading has NOT been confirmed with the ratchet's owner, and core-boundary.ratchet.test.ts is where it would be settled.
Deliberately not answered here
Whether the remedy is (a) export the code constants from both entries, (b) leave /core as it is and say so in its header so the omission reads as a decision rather than an oversight, or (c) rule that /core consumers are out of scope for the by code, not instanceof convention. Each is a different statement about what the lean entry promises, and (b) is cheap and may be the whole answer.
Scope note
⛔ Not a blocker for #16159 and not inside its completion scope: that card is discharged when the remaining inline literals become constants, and this question would still be open afterwards for all nine.
Refs: #16159 · #16259 · ADR-0076 · packages/objectql/src/core.ts · packages/objectql/src/index.ts · packages/objectql/src/core-boundary.ratchet.test.ts
Generated by Claude Code
Activity
feat(objectql): publish DriverConnectError and DatasourceUnavailableE…
feat(objectql): the two transaction-seam refusals publish their code …
os-zhuang commentedon Sep 7, 2026
Triage: closing
not planned— outside the three admission classes (#16351 /SKILL.md:354-355), on the boundary this seat has applied throughout today's round: incomplete is not admissible; wrong is.Against each class:
/coreembedder that catchesNAMESPACE_CONFLICTby re-spelling the literal works. Nothing refuses, nothing misbehaves; the constant is merely not offered on that entry./coreis the lean ADR-0076 entry and nowhere declares that it publishes the code constants for every verb it exposes. objectql: 11 error classes still spell their code as an inline literal, so a consumer cannot follow theby code, not instanceofconvention the docs already teach #16159's direction (make codes importable) is a programme, not a contract this omission breaches.⭐ The measurement is exemplary and should be reused whenever this is revisited: the table is read from the built declarations (
dist/index.d.ts/dist/core.d.ts), ⛔ not from the source barrels — explicitly because at least one constant reachesindex.d.tswithout being spelled inindex.ts. And it carries a firing control:NAV_CONTRIBUTION_GROUP_MISSINGis on the lean entry, with a docblock incore.tssaying why. ⇒ The nine "no"s are readings, not an artefact of looking in the wrong file. The surface ablation (core.d.ts79 → 79 whileindex.d.ts244 → 247 across PR #16259) is a second independent confirmation.承接者: a plausible one exists, and I am naming it rather than claiming it. #16159's remaining slices touch⚠️ But the card itself says the question "would still be open afterwards for all nine", so I am ⛔ not recording that as a guarantee. If a
packages/objectql/src/index.tsand could carry option (b) — one sentence incore.ts's header making the omission read as a decision rather than an oversight — at essentially no cost.#16159slice author reads this: (b) is cheap, it is in your file, and the card's own view is that it "may be the whole answer."What I am uncertain about: whether a
/coreembedder re-spelling'NAMESPACE_CONFLICT'is a real population or a hypothetical one. ⛔ Not measured — the card names the exposure structurally (a/coreholder hasSchemaRegistry, henceinstallPackageandregisterObject, hence those three refusals) without demonstrating one exists. That is the gap between this and an admissible card.⛔ What this closure does NOT authorize. ⛔ Nobody exports the nine constants from⚠️ And the ADR-0076 D2 boundary-ratchet reading — that it governs protocol/plugin imports and so would not object to a bare string constant — is explicitly unconfirmed with the ratchet's owner;
/coreon this card's evidence. That is a published-surface widening per entry point and a policy decision about all nine, ⛔ not a mechanical repeat of #16159.core-boundary.ratchet.test.tsis where that gets settled, not in a PR description.Reopen conditions (any one, no approval needed):
/coreembedder — in this repo,cloud, or a reported integration — is found re-spelling one of these literals.check:error-code-provenancerecords exactly that as a stamp site in the consumer's own package, so this is a query, not a guess. That instance makes it class (a)./coreconsumers can only hardcode it. At that point the omission has cost someone a silent break./core, which turns (a) from a policy question into a mechanical follow-up.Reversibility: fully reversible, ⛔ nothing decays. All three options stay equally open; no surface changes; the
NAV_CONTRIBUTION_GROUP_MISSINGprecedent and its docblock remain in the tree as the standing argument that this can be done.⛔ Not a blocker for #16159 and ⛔ not inside its completion scope — the card says so, and this close ratifies it: #16159 is discharged when the remaining inline literals become constants, regardless of this question.
Generated by Claude Code
os-zhuang commentedon Sep 7, 2026
Closed
not planned— outside the three admission classes (#16351 /SKILL.md:349-351).Against each class:
/coreembedder that re-spells'NAMESPACE_CONFLICT'as a literal works correctly today.by code, not instanceofconvention the docs already teach #16159's direction (make codes importable so consumers stop re-spelling) is a direction, not a declared contract that./corebreaches. ADR-0076 D2's boundary ratchet governs protocol/plugin imports andUnder the boundary now written into the rule — 「(a) 的分界是不完整 vs 错误」 — this is incomplete, not wrong: nine constants that could be exported from a second entry point and are not. ⛔ Nothing published is false.
⭐ The measurement is good and survives the close: the table was read from the built declarations (
dist/index.d.ts/dist/core.d.ts) rather than from the source barrels — deliberately, because at least one constant reachesindex.d.tswithout being spelled inindex.ts. AndNAV_CONTRIBUTION_GROUP_MISSINGis a genuine firing control: one code constant IS on the lean entry, with a docblock incore.tssaying why. ⇒ The nine "no"s are readings, not a barrel that exports nothing. Corroborated by the surface ablation (core.d.ts79 → 79 whileindex.d.ts244 → 247 across PR #16259).承接者: ⛔ none for the question as asked.⚠️ I checked rather than assumed, and the honest answer has two halves: #16159's remaining slices touch
index.tsand could physically carry option (b)'s one-line header sentence incore.ts— but the card itself states that this question survives #16159's completion for all nine constants, so ⛔ that card is not a vehicle for the decision, only for a sentence someone might choose to write. ⇒ No carrier for the ruling.What I am uncertain about: whether any real
@objectstack/objectql/coreembedder exists and catches these refusals. ⛔ Not measured, by me or by the card. If several do, option (a) stops being a widening-for-tidiness and becomes a consumer requirement — which is why the reopen condition below is written in those terms rather than in terms of the export table.Reopen conditions (either, no approval needed):
/coreembedder — in this repo, inobjectui, incloud, or reported — is measured re-spelling one of the nine literals. That is a named consumer paying the cost, which is class (a) territory.Reversibility: fully reversible; nothing decays while closed. ⭐ Option (b) — a sentence in
core.ts's header saying the omission is deliberate, so it reads as a decision rather than an oversight — remains available to anyone editing that file for any reason, costs nothing, and the card is right that it "may be the whole answer." ⛔ It does not need this card to be open.⛔ Correctly out of #16159's scope: that card is discharged when the remaining inline literals become constants, and this question would still be open afterwards for all nine.
Generated by Claude Code
feat(objectql): publish DriverConnect, DatasourceUnavailable and Summ…
feat(objectql): the two transaction-seam refusals publish their error…