Uh oh!
There was an error while loading. Please reload this page.
feat(spec): PLATFORM_PLUGIN_WIRED_RUNTIMES — provenance roster for plugins[]-wired out-of-repo runtimes - #11613
Conversation
…r plugins[]-wired out-of-repo runtimes The token-keyed PLATFORM_CAPABILITY_PROVIDERS map structurally cannot hold @objectstack/organizations: it backs no requires token (serve loads it off the resolved tenancy posture, ADR-0105). Add a sibling, package-name-keyed provenance roster covering the plugins[]-wired out-of-repo population of two (organizations + security-enterprise), edition typed to exclude 'open' by construction. Provenance only: no new capability token, no widened key space, no posture-to-token resolution semantics. Drift pins in serve-capability-vocabulary.test.ts hold the two rosters to one edition wherever they name the same package, and derive enterprise-row membership so the next enterprise token is covered on arrival. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9cDbY2NBiVJWYx3BpWfH2
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ✅ 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): 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 4a88f205f009f05b7a5638768dd54a9f46bcc4ea && git checkout 4a88f205f009f05b7a5638768dd54a9f46bcc4ea
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2cf5a96cc77cc4a7b64c2512246ac1e121f348d8 e239aa5fe4d807724da894ee17b639cf57fd8a3a && git checkout -B drift-repro 2cf5a96cc77cc4a7b64c2512246ac1e121f348d8 && git merge --no-ff e239aa5fe4d807724da894ee17b639cf57fd8a3a
node scripts/docs-audit/affected-docs.mjs --json 2cf5a96cc77cc4a7b64c2512246ac1e121f348d8 |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11263
Measurement map — why the triage gloss ("add the row") is not directly executable
Re-measured on
6d3550961f(this branch's base), confirming the card's own structural objection:PLATFORM_CAPABILITY_PROVIDERS(packages/spec/src/kernel/platform-capabilities.ts) is keyed byrequirescapability token, and its own docblock defines the vocabulary as "the union of every token the framework CLI and cloud's objectos-runtime resolve".@objectstack/organizationsis resolved by neither throughrequires.serve.tsloads it off the resolved tenancy posture (multiTenant = tenancyPosture !== 'single', ADR-0105 D1,serve.tsaround line 2777), viaimportFromHostfrom the host app (cloud#1013). It backs no token;defineStacktoday rejectsrequires: ['organizations']as an unknown token — correctly.@objectstack/security-enterpriseis alsoplugins[]-wired and has a row only because it additionally backs thehierarchy-securitytoken.organizationstoken to make a row keyable would enter therequiresvocabulary (the drift test enforces 1:1), flippingrequires: ['organizations']from authoring-time rejection to accepted-but-resolved-by-nothing — new capability-token semantics, which the dispatch marks as maintainer territory. Widening the map's key space past the vocabulary breaks the same 1:1 invariant and would makeclassifyRequiredCapabilityclassify a non-token as a provider hit. Both rejected by measurement.Chosen shape — the minimal by-construction alternative the card itself anticipated: a sibling, package-name-keyed provenance export in the same file, covering the
plugins[]-wired out-of-repo population, which is exactly two.Changes
packages/spec/src/kernel/platform-capabilities.ts— new exportedPLATFORM_PLUGIN_WIRED_RUNTIMES(Readonly Record, frozen; key = npm package name) with row typePlatformPluginWiredRuntime(edition: Exclude of CapabilityEdition minus 'open'— the mis-filing cannot compile;noterequired). Rows:@objectstack/organizations(enterprise, posture-load provenance in prose) and@objectstack/security-enterprise(enterprise, names itshierarchy-securitydual listing). The token-keyed map's docblock now points at the sibling for the population it structurally cannot hold. Provenance only: no new token, no widened key space, no posture-to-token resolution semantics — each runtime's load condition stays in the runtime that loads it.packages/spec/src/index.ts— root-entry named exports for both symbols (kernel subpath re-exports wholesale).packages/cli/test/serve-capability-vocabulary.test.ts— the drift test the card names, extended with the cross-roster pins: (1) the organizations row exists and isenterprise; (2) everyenterprise-edition provider package must have a roster row — derived fromCapabilityEdition's own definition (enterprise= the app installs and wires viaplugins[]), sosecurity-enterprise's double listing is checked rather than divergent, and the next enterprise token is covered on arrival; (3) wherever both rosters name one package they agree on edition; (4) no roster package appears in serve'sCAPABILITY_PROVIDERSpackage values.packages/spec/src/kernel/platform-capabilities.test.ts— shape invariants: frozen/non-empty, keys are@objectstack/package names, notes non-empty, runtime edition check, and keys disjoint from the capability vocabulary (the single-list rule's load-bearing half: this roster can never grow a second way to spell arequirestoken).packages/spec/api-surface/+export-origins/— regenerated viacheck:generated --fix(only the 2 proved-stale artifacts); diff is exactly the two new symbols, additive..changeset/plugin-wired-runtime-roster.md—@objectstack/spec: minor(new exported symbols; not breaking, no ADR-0087 marker owed).On the single-list warning the file carries: the two rosters have disjoint key spaces (tokens vs package names) and disjoint membership criteria (requires-resolved vs
plugins[]-wired); the one fact they can state twice (edition of a package in both) is drift-tested to agree. Residual not covered by construction:serve.ts's ownorganizationsPkgliteral is not read from this roster (serve consumption was outside the claimed file surface); if the PM wants the runtime to consume the roster's key, that is a one-line follow-up.Verification — all at final commit
e239aa5fe4(tree clean; no commits after any run)✓ packages/spec/dist/.build-input-hashwritten, exit 0.pnpm --filter @objectstack/spec test→Test Files 420 passed (420) · Tests 11218 passed (11218).pnpm --filter @objectstack/spec typecheck→check:test-typecheck: OK — @objectstack/spec's test layer compiles, exit 0.pnpm --filter @objectstack/spec check:generated→ first run named 2 stale (api-surface/,export-origins/); after--fix:✓ All 14 generated artifacts are up to date.pnpm --filter @objectstack/cli exec vitest run test/serve-capability-vocabulary.test.ts→Tests 12 passed (12);pnpm --filter @objectstack/cli typecheck→ exit 0.@objectstack/spec/kernel→ specdist/, so both legs rebuilt spec and ranscripts/ablation-dist-preflight.mjs. Mutant leg (organizations edition flipped tocloud+ security-enterprise roster row deleted): anchored-write confirmationinjected A count: 1 · injected B count: 1 · removed roster anchor count: 0; preflight✓ marker present in 8 built filesfor both markers; predicted direction RED on exactly the two targeted pins — observedTests 2 failed | 10 passed (12), the two failures being the organizations-edition pin and the enterprise-membership pin, nothing else. Restore leg (trap-guardedgit checkout HEAD): markers 0/0 on disk, roster anchor back to 1, preflight--absent→✓ marker absent from all 209 built files, rerunTests 12 passed (12).node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths passed; stderr confirmed derivation from this checkout ate239aa5fe4): 27 path-derived + 3 convention-triggered. All run locally, each exit code captured before any pipe (per-gate log + immediate$?):check:nul-bytes·check:changeset-gate-self-tests·check:objectui-changeset·check-adr-0087-registration·check-changeset-no-major·check-empty-changeset·release-rehearsal-clone --self-test·check:merge-driver·check-dev-prereqs·check-ci-filter-parity·check:cross-package-test-inputs·check:slot-lookup·check:spec-parsed-alias·check:test-source-alias·check:type-source-resolution·check:published-files·check:query-options-erasure·check:engine-double-contract·check:where-matcher·check-plugin-teardown-shape·check-affected-docs·check:empty-state·check:liveness·check:strictness-ledger·check:variant-docs·check:doc-formula-expressions·check:i18n·check:i18n-coverage·check:type-check-coverage·check:type-check-debt --re-measure— all exit 0. Verdict lines quoted rather than bare exits:check-type-check-coverage: OK — 65/78 workspace packages type-checked;check-type-check-coverage --re-measure: OK — 32 ledger entr(ies) re-measured in 224.7s, 1897 raw tsc error(s) total, none above its recorded number(run against the built closure:turbo run build --filter=./packages/* --filter=./packages/*/*→70 total, exit 0, so the verdict is a measurement, not a refusal). Three gates (dev-prereqs,i18n,i18n-coverage) first failed on the documented unbuilt-workspace precondition and passed after the closure build — build-state, not diff findings.pnpm lint(eslint . --no-inline-config) run in full, not narrowed → exit 0 ate239aa5fe4.Draft on purpose —
needs:contract-review(clause ②: new public spec surface); the PM flips after contract review. Merge is not blocked on any other card; #10921 is already closed by its own PR and is referenced here as prior fact only.Generated by Claude Code
Generated by Claude Code