test(plugin-security,spec): pin the shared identifier schemas to the storage columns that bound them - #12584
Conversation
…storage columns that bound them (#12144)
…entifier-bounds-pin
📓 Docs Drift Check
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
|
PM review — ACCEPT ( Contract verdict on the real diff: the zod chains in What carried the review:
The out-of-scope observation (9 gate families' derivation literals scoring Landing: waiting for every check green on Generated by Claude Code |
Fixes #12144
Route taken: the PIN route (triage comment 5414530579's freely dispatchable half)
The shared identifier schemas (
SystemIdentifierSchema,SnakeCaseIdentifierSchema,EventNameSchema) declare a floor and a grammar and no.max(), while every column that stores an identifier is bounded. This PR links the two surfaces so they cannot drift, the PR #12143 idiom: the pin reads the column widths off the registration surface (SecurityPlugin.init()→ the manifestregister({ objects })call, and theSysMetadataObjectdeclaration imported from@objectstack/metadata-core) rather than restating them, and probes the spec schemas against those live widths.Accept/reject behaviour: UNCHANGED (Clause-② statement). The final diff changes no accepted or rejected value anywhere: the spec edit is TSDoc only (no
.describe(), no validator change), the new file is a test, the docs page is regenerated from the TSDoc, and the changeset is prose. The pin itself asserts acceptance is unchanged at every measured width, and the ablation below shows it turning red under exactly the narrowing the triage fenced.Why no per-surface
.max()(the conditional limb, measured and declined)The conditional limb required each surface to carry a
.max()matching its own enforced ceiling exactly. Measured against origin/main:sys_permission_set.nameSnakeCaseIdentifierSchema(PermissionSetSchema.name)sys_position.nameSnakeCaseIdentifierSchema(PositionSchema.name)sys_capability.namesys_metadata.nameSnakeCaseIdentifierSchemavaluesSnakeCaseIdentifierSchemais ONE shared schema feeding surfaces whose enforced ceilings disagree (100 vs 255), so no single.max()on it can be declared-equals-enforced for every consumer — the blanket.max(100)shape is exactly the fenced narrowing (it would newly refusesys_metadatanames in (100, 255] that are legal stored rows today)..max()to the consumers (e.g.PermissionSetSchema.name) is outside this card's file surface (consumer modules were read-only for measurement), and several consumers (field names, event names, view keys) have no bounded storage column at all — their enforced ceiling is unmeasurable, which the triage rules to "NO.max(); fall back to the pin".So the pin route alone, which the triage names a complete resolution.
What the pin asserts (
packages/plugins/plugin-security/src/identifier-storage-ceiling-pin.test.ts).max()becomes derivable and must be escalated as a spec accept-set change..max()below a storing column reds here by name..max()landing on a shared identifier schema surfaces here with the per-surface measurement burden spelled out.The contract-side half:
identifiers.zod.tsTSDoc now states that the length ceiling is storage-owned, names the disagreeing widths, and points at the pin (regenerated intocontent/docs/references/shared/identifiers.mdxviacheck:generated --fix, on a base that includes the dd4fc6c heading renumbering).Reverse verification (both legs rebuilt, mutations proved on disk)
.max(100)onSnakeCaseIdentifierSchema: mutation proved on disk (injected-marker grep count 1), spec dist rebuilt,ablation-dist-preflightconfirmed the marker in 36 built files; run went RED on tests 3 and 4 (2 failed, 2 passed) — the predicted direction. Restored viagit checkout HEAD,git diff HEADclean, rebuilt, preflight--absentover 211 files, rerun 4/4 green.sys_metadata.namewidth 255 → 8787: mutation proved on disk (marker count 1), metadata-core dist rebuilt, preflight confirmed marker in 2 built files; run went RED on exactly the value pin (1 failed, 3 passed) — the predicted direction. Restored,git diff HEADclean, rebuilt, preflight--absent, rerun 4/4 green.Both suites resolve
@objectstack/specand@objectstack/metadata-corethroughdist/(no vitest alias; both pairs already inKNOWN_UNALIASED_TEST_IMPORTS), hence the rebuild in every leg.Validation (all at head
d7ff0a5, after merging origin/main)pnpm --filter @objectstack/plugin-security test— 84 files / 1545 tests passed (new pin 4/4).pnpm --filter @objectstack/spec typecheckandpnpm --filter @objectstack/plugin-security typecheck— green. The package tsconfig excludes test files fromtsc, so the new test file was additionally typechecked in isolation via a temp config extending the package tsconfig — exit 0.pnpm --filter @objectstack/spec check:generated— "All 14 generated artifacts are up to date" (onlycheck:docswas stale; regenerated with--fix).node scripts/pm/dispatch-gates.mjs(path-derived plus convention-triggered): 45 gates green, includingcheck:engine-double-contract(at its new findOne slice),check:cross-package-test-inputs,check:test-source-alias,check:i18n,check:i18n-stale-fill,check:type-check-coverage,check:type-check-debt --re-measure("none above its recorded number"),check:skill-examples("260 prose examples type-check"),check:nul-bytes. Three gates first reported PREREQUISITE NOT MET on unbuilt dists — treated as not-measured, the full packages closure was built, and all three then passed with their own verdict lines.Changeset: patch for
@objectstack/spec(published TSDoc/docs surface changed; behaviour did not). Not declared breaking, so no ADR-0087 marker is required (check:adr-0087-registrationgreen).Draft for PM review; auto-merge not armed.
Generated by Claude Code