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
Filed by the
domain:engineexecution seat while landing the first slice of #16159 (PR #16259). ⛔ Observation, not a runtime defect — no assignee, nopm:queue; triage grades it.The observation
@objectstack/objectqldeclares two entry points:.(the batteries-included barrel,src/index.ts) and./core(the lean ADR-0076 engine entry,src/core.ts).SchemaRegistryis 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 reachesindex.d.tswithout being spelled inindex.ts:dist/index.d.tsdist/core.d.tsDUPLICATE_RECORD_CODEHOOK_TARGET_REBIND_ERROR_CODEHOOK_UNSCOPED_DATA_ACCESS_CODEMULTI_UPDATE_HOOK_KEY_DIVERGENCE_CODEEMPTY_CREDENTIAL_REFUSAL_CODESYSTEM_WRITE_ORGANIZATION_REQUIRED_CODENAMESPACE_CONFLICT_CODE(PR #16259)DUPLICATE_ARTIFACT_OBJECT_NAME_CODE(PR #16259)OBJECT_OWNERSHIP_CONFLICT_CODE(PR #16259)NAV_CONTRIBUTION_GROUP_MISSING⭐ 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.tscarries a docblock saying why (os buildreaches it from there, and it costs the entry nothing because it imports nothing).Corroborating measurement from PR #16259's surface ablation:
dist/core.d.tsholds 79 exported names before and after that PR adds three constants, whiledist/index.d.tsgoes 244 to 247.Why it may matter
A
@objectstack/objectql/coreembedder holdsSchemaRegistry, so it reachesinstallPackageandregisterObject— the two verbs that raiseNAMESPACE_CONFLICT,DUPLICATE_ARTIFACT_OBJECT_NAMEandOBJECT_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 whatcheck:error-code-provenancerecords 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.tsis where it would be settled.Deliberately not answered here
Whether the remedy is (a) export the code constants from both entries, (b) leave
/coreas it is and say so in its header so the omission reads as a decision rather than an oversight, or (c) rule that/coreconsumers are out of scope for theby code, not instanceofconvention. 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.tsGenerated by Claude Code