fix(spec): register sys_environment_credential in CLOUD_PROVIDED_OBJECT_NAMES - #18851
Conversation
…CT_NAMES The curated cloud list carried the tenant runtime's app, environment, environment-member, license and package objects but not the rotatable credential store that @objectstack/service-tenant registers on the same path, so a reference to that name resolved against nothing and the object-reference ladder classed it as a platform-prefixed name nobody provides. Add the one entry, pin it by name beside sys_license and the package family, and add the changeset. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
The list's header already says this half of the contract cannot be conformance-tested from this repository. The pin comment and the changeset stated the cloud registration chain as though this change had re-taken it; they now name it as a reading carried on the filer's name, at the cloud ref it was taken against, and say plainly that only the objectstack half is asserted here. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 872cad4d0250ad3b189327c63cd53937474d6354 && git checkout 872cad4d0250ad3b189327c63cd53937474d6354
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 631dcbd4b93c3f86d02080bc129a611f0619ed23 d18f7d78a8dbb0e8274719a4b0527643ccf06551 && git checkout -B drift-repro 631dcbd4b93c3f86d02080bc129a611f0619ed23 && git merge --no-ff d18f7d78a8dbb0e8274719a4b0527643ccf06551
node scripts/docs-audit/affected-docs.mjs --json 631dcbd4b93c3f86d02080bc129a611f0619ed23 |
契约复核记录 —— PR #18851 / 卡 #18309 · PASS · 逐字采纳⏱️ 本评论的取数时刻 2026-09-18T00:40Z。所判 head: 路线:本席实测未达 档位证据(取自子代理自身 transcript,⛔ 不取
|
Contract reviewServed-tier: 113/113 ⏱️ 本记录取数时刻 2026-09-18T00:42Z。裁决逐字全文在评论 档位证据取自复核子代理自身 transcript 的逐请求 harness 盖章: ① Derived judgments
② Semver levelchangeset 写 ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Provenance —— 双载体已清⏱️ 2026-09-18T00:43Z。
|
Fixes #18309
Clause-②: yes (widening)
Scoped to item 1 of the card only. Item 2 — grading
sys_tenant_databaseunderenforce-or-remove — is decision-shaped and is not touched here;
packages/spec/src/cloud/tenant.zod.tsis unmodified.What changed
CLOUD_PROVIDED_OBJECT_NAMESgains one member,sys_environment_credential, plus anamed pin test and a
minorchangeset. Three files, 69 insertions, nothing removed andno other member moved — the same shape as PR #17214, which added
sys_package_version.The cloud half is the filer's reading, not a measurement taken here
The registration chain —
objects/sys-environment-credential.object.tsexported throughobjects/index.ts, listed intenantObjectsinmanifest.ts, spread intomanifestService.register({ objects })bytenant-plugin.ts— was read in the cloudrepository at
cb8ee7ff60and is carried here on its filer's name. It is notre-checkable from this repo, which is what the list's own header means by "they cannot be
conformance-tested from this repo". Nothing in this PR re-took it, and the pin comment and
changeset both say so in as many words.
What IS measured here is the objectstack half: the contents of the list, the predicate
built from it, and the ladder verdict that consumes it.
Re-taken readings
Reference census, taken on this branch at
d18f7d78a8(the card's own count was taken2026-09-15 and is unchanged):
sys_environment_credentialin*.object.tssys_environment_credentialanywhere trackedCHANGELOG.mdrename records, and this PR's two spec files)sys_package_versionanywhere tracked (positive control)sys_definitely_not_realanywhere tracked (negative control)So no shipped
*.object.tsreferences the name, the card'spriority:p3gradingstands on its stated reason, and nothing here promotes it.
Does the existing pin test redden? No.
platform-object-names.test.tspins the listneither by length nor by full set: it loops
CLOUD_PROVIDED_OBJECT_NAMESasserting eachmember resolves and is not declared in this repo — both of which a new member satisfies on
arrival — and then pins
sys_licenseand thesys_package*family by name. A memberadded without a named pin is therefore invisible to the suite, which is exactly the gap
the file's own comments say the by-name pins exist to close, so this change adds one in
the same style. Suite went 9 tests to 10, green.
Controls
Both legs rebuild
packages/specand prove the state reacheddist/withscripts/ablation-dist-preflight.mjsbefore the reading is allowed to mean anything —@objectstack/lintresolves@objectstack/spec/systemthroughexports, so a verdicttaken without rebuilding is a fact about the previous build. Probe: an object declaration
whose lookup field targets the name, through
validateObjectReferences.dist)d18f7d78a8)sys_environment_credential(LIT)predicate=false, 1 finding —warning:object-reference-unregistered-platformpredicate=true, 0 findingssys_app,sys_environment,sys_environment_member,sys_license,sys_package,sys_package_installation,sys_package_version(DARK-A)predicate=true, 0 findings — eachpredicate=true, 0 findings — eachsys_definitely_not_real(DARK-B)predicate=false, 1 findingpredicate=false, 1 findingsys_approval_process(instrument control)predicate=false, 1 findingpredicate=false, 1 findingsys_user/crm_deployment(instrument controls)The lit control is non-zero and every dark reading is unchanged. Preflight confirmed the
marker absent from all 216 built files on the ablated leg and present in 8 on the restored
leg; the restore was proven by whole-tree
git status --porcelain(0 lines) and bygit hash-objectmatching the HEAD blobc10c88f1e0…. No probe file was left in the repo.One correction to the card's wording. The card says "the first shipped reference to it
would be refused". The measured verdict is a
warning, not a refusal: rung ④ ofvalidate-object-references's severity ladder is advisory by design, because athird-party package may legitimately provide a platform-prefixed name.
defineStack's ownhard throw uses a prefix test (
isPlatformObjectNameinstack.zod.ts), which acceptedthe name both before and after this change. So the flip is real and the direction the card
describes is right, but what flipped is a diagnostic, not a rejection — the name was never
hard-refused, and this PR does not manufacture a refusal to make the stronger reading true.
The two
merge=os-regenartefacts do not movepackages/spec/api-surface/system.jsonandpackages/spec/export-origins/system.jsonwerepre-declared on the claim as regeneration targets. Measured: they record export names and
origins, not values, so the list's contents are invisible to them —
git grep -c sys_packageover both directories returns 0 hits. The repo's own generatorwrapper confirms it:
pnpm --filter @objectstack/spec check:generatedreports all 15generated artifacts up to date,
check:api-surfaceandcheck:export-originsamongthem, so
--fixhad nothing to regenerate. Neither file is hand-edited and neither is inthis diff. PR #17214 touched the same three-file set for the same reason.
Verification
Run at
d18f7d78a8unless noted.pnpm --filter @objectstack/spec build— green (through the shared verify lock)pnpm --filter @objectstack/spec test— 487 files / 14055 tests passedpnpm --filter @objectstack/spec typecheck— green (incl.check:scripts-typecheck,check:test-typecheck)pnpm --filter @objectstack/lint test— 104 files / 3879 passed, 5 skipped, after building lint's dependency closure. The first run showed 41 files failing to collect on@objectstack/formula/@objectstack/sdui-parserhaving nodist/; that is unbuilt-closure state, not this diff, and it cleared onpnpm --filter '@objectstack/lint^...' build.pnpm --filter @objectstack/spec check:generated— all 15 up to datecheck:nul-bytes,check:merge-driver,check:cross-package-test-inputs,check:test-source-alias,check:published-files,check:dts-closure,check:type-check-coverage,check:entry-nameability,check:browser-reachable-entries,check:dual-source-exports,check:exported-any,check-empty-changeset,check-adr-0087-registration,check-platform-object-tenancy-census,check-spec-docblock-symbol-anchors,check-comment-mask-adoption,check-comment-mask-corpus,check-keyed-text-bounds— all exit 0.eslint --no-inline-configover the diff's two lintable files, 0 errors / 0 warnings, file count read from--format json(2 — the third changed path is a.changeset/*.md, which nofilesentry ineslint.config.mjsmatches). The narrowing is safe because this config runs no type-aware linting —eslint.config.mjs:328records "noparserOptions.project, no typed@typescript-eslintrules", and there is noprojectServiceanywhere in it — so each file's verdict is a function of that file alone and a two-file diff cannot move an untouched file's verdict. The repo-wide run remains CI's.NOT MEASURED, with reasons:
check:type-check-debtexited 3, which the script itself prints asPREREQUISITE NOT MET— it needs the whole-repo build closure thatlint.ymlbuilds before the step. Its own text: "This is NOT a pass and NOT a finding: nothing was measured." Recorded as unmeasured, not as red.check-changeset-no-major.mjsran green but reports its level axis NOT APPLICABLE locally: it reads the clause-② declaration from apull_requestpayload, which a local run has not got. The axis gets its input once this PR exists.dispatch-gates --ranreconciles 27 of 81 derived families run locally. The remainder are checker--self-testinvocations and repo-wide scans that CI owns.Acceptance notes
Observations from the surrounding code, filed nowhere and deliberately not fixed here:
PLATFORM_OBJECTS_BY_PACKAGEcarries a per-package conformance scan that reddens ondrift;
CLOUD_PROVIDED_OBJECT_NAMEShas no such half by construction, so every memberit holds rests on a cross-repo reading with no local ratchet behind it. That is the
documented design, not a defect, and it is why this PR adds a by-name pin rather than
claiming conformance. Noted, not filed — no PR or person is queued against this file.
sys_environment_credentialas existing while theregistry that decides whether a reference resolves said nothing registers it. The two
now agree. Noted, not filed: an ADR stating a true fact about the cloud runtime is not a
contract violation, and nothing in this repo consumed the ADR table as metadata.
Ownership
needs:contract-reviewis the PM seat's to place and the at-tier review is the PM seat'sto run; this PR removes no label and flips no state. Left as a draft.
Generated by Claude Code