chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger - #14638

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger
Sep 2, 2026
Merged

chore(spec): govern the four RestServerConfig sub-objects in the liveness ledger#14638
os-sam merged 2 commits into
mainfrom
claude/issue-14369-rest-server-config-liveness-ledger

Conversation

@claude

@claudeclaudeBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes#14369

Lands the ten declared-but-unread RestServerConfig keys in the liveness ledger, with the census re-run and pinned to a ref. Per the triage ruling, the dispatchable unit is the LEDGER: no key is removed, enforced, deprecated or re-described, packages/spec/src/api/rest-server.zod.ts is not edited, and the @example fence is left for the per-key follow-up.

Correction: the card's named landing is wrong-typed

The card names packages/spec/liveness/api.json. Measured on origin/main, that file is ApiEndpointSchema's ledger ("type": "api", and its only cacheTtl row is ApiEndpointSchema.cacheTtl, a different key from RestServerConfig.metadata.cacheTtl). RestServerConfigSchema is server/plugin construction config and is not a registered metadata type, so appending rows to api.json would have put them under a schema the gate never walks — orphan rows on arrival.

The route non-metadata-type schemas take is SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts, the way query, webhook, validation, qa and manifest are governed. This PR follows that precedent.

Why four roots and not one

RestServerConfigSchema is the obvious single root and measurement rules it out. The ledger walk drills exactly one level (check-liveness.mts classifies props[key] and, when the entry declares children, one level beneath it — there is no recursion, and no ledger file in the repo carries nested children). With the whole config as the root, the four sub-objects would BE the drilled level, so metadata.endpoints.schema and batch.operations.upsertMany — two of the card's ten — would have no row of their own. Their container's blanket verdict would be live (three of four members gate a real route mount), silently covering a dead key: the #4956 shape, in the file written to end it.

Rooting on the four sub-schemas puts every one of the ten keys at a drillable coordinate, so each carries its own falsifiable verdict. RestApiConfigSchema (the fifth sub-object, api) is deliberately not enrolled — its consumption seam is still validate-only and is the subject of #14366, so a census of it would record a half that is about to move.

Container coverage is unchanged by this PR: still 58 blanket verdicts over 301 child keys, 7 deferrals over 273. No row is added to undrilled-containers.baseline.json — the shrink-only ratchet is not touched.

Files

FileTypeRows
packages/spec/liveness/crud_endpoints.jsoncrud_endpoints = CrudEndpointsConfigSchema11 (live 6, dead 5)
packages/spec/liveness/metadata_endpoints.jsonmetadata_endpoints = MetadataEndpointsConfigSchema8 (live 6, dead 2)
packages/spec/liveness/batch_endpoints.jsonbatch_endpoints = BatchEndpointsConfigSchema7 (live 5, dead 2)
packages/spec/liveness/route_generation.jsonroute_generation = RouteGenerationConfigSchema6 (dead 6)

Enrolment: GOVERNED + SPEC_ONLY_SCHEMAS in packages/spec/scripts/liveness/check-liveness.mts (import + four entries + the rationale block). README.md gains four "Current state" rows and its heading moves 31 → 35; state-counts.md was regenerated by the gate (pnpm --filter @objectstack/spec gen:liveness-counts), never by hand.

Census, re-run and pinned

Ref: 2514d49f388e898e666ae04f19ba376d04db5422 (2514d49f3), the merge base this branch is cut from. Method: read sites in packages/rest/src non-test sources, excluding NormalizedRestServerConfig's type declaration (rest-server.ts lines 723-786) and normalizeConfig itself (3518-3616), comments excluded; plus a repo-wide grep outside packages/spec and that file; plus objectui @ d4c6a86.

keyread sitesverdict
routes.includeObjects0dead
routes.excludeObjects0dead
routes.nameTransform0 (repo-wide 0)dead
routes.overrides0dead (3 rows: enabled / basePath / operations)
crud.patterns0dead (4 rows: method / path / summary / description)
crud.objectParamStyle0 (repo-wide 0)dead
metadata.cacheTtl0dead
metadata.endpoints.schema0dead
batch.defaultAtomic0 (repo-wide 0)dead
batch.operations.upsertMany0dead

Ten keys, fifteen rows: the two container keys are expanded into a row per member so the verdict is falsifiable per key rather than inherited. The card's first list is confirmed live in the same pass and carries live rows with path#symbol evidence plus a producer pointer at rest-server.ts#normalizeConfig: crud.operations.{create,read,update,delete,list} and crud.dataPrefix (5 independent consumers); metadata.{prefix,enableCache,maskObjectFields} and metadata.endpoints.{types,items,item}; batch.{maxBatchSize,enableBatchEndpoint} and batch.operations.{createMany,updateMany,deleteMany}.

Repo-wide grep for nameTransform / objectParamStyle / defaultAtomic outside packages/spec and rest-server.ts returns only changesets, the generated reference page content/docs/references/api/rest-server.mdx, and #11984's own refusal tests — no consumer. objectui @ d4c6a86 is clean (0 hits for every key, and 0 for RestServerConfig itself). The closed cloud runtime was not reachable from the measuring container, so every row declares "evidenceScope": "in-repo" rather than claiming a sweep that was not run.

No premise change. All ten keys still measure 0. Two sharpenings the re-run added, both recorded in the rows rather than acted on: metadata.endpoints.schema gates a route that does not exist (packages/rest/src mounts no path ending in /schema at all), and batch.operations.upsertMany is its twin (the protocol carries createManyData / updateManyData / deleteManyData and no upsertManyData).

metadata.cacheTtl's negative-bound observation travels in that key's ledger note, per the triage ruling, and is not filed as a separate defect.

What #11984 settled, and what it did not

Kept as the note's own distinction: #11984 made RestServer.normalizeConfig PARSE and CONSUME these four sub-objects instead of casting them, so an out-of-enum or out-of-range value is refused at construction. That settles accept/reject. Executing a declared contract does not give a key a consumer — which is why routes.nameTransform is validated against its enum and still mounts exactly what 'none' mounts.

Out of scope, reported not fixed

api.documentation and api.responseFormat (and their children) also measure 0 read sites in packages/rest/src at this ref — dead keys in the same declared-but-unenforced class, on the one sub-object this PR does not enrol. Not classified here and not filed as part of this card; recorded for the dev report so the api half can be dispatched with the finding in hand.

Changeset

packages/spec/liveness/** is named in packages/spec's files, so the ledgers ship in the published tarball — a patch changeset for @objectstack/spec is included and pnpm check:published-files is green. No skip-changeset label.

Gates

Derived on the final head with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (36 commands) and run with each exit code captured before any pipe. At 0e9a1f50a:

  • 34 pass, including pnpm --filter @objectstack/spec check:liveness, check:generated (all 15 artifacts current), check:empty-state, check:strictness-ledger, check:variant-docs, check:published-files, check:merge-driver, check:adr-0087-registration, check:pm-governed-merges, pnpm check:nul-bytes.
  • 3 NOT MEASURED — all one cause, an unbuilt workspace in the measuring container, none a finding: check-test-completeness (exit 3, its own text says it grades a saved turbo run test log and none was named), check:dual-build-cjs-loads (exit 3, "PREREQUISITE NOT MET — this gate reads built output"; its 93-case self-test passes), check-dev-prereqs (exit 1, "1 unmet precondition, not a list of problems" — 66 of 67 packages have no dist/). CI checks out fresh and builds, so all three are measured there.
  • Liveness script suites: pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 scripts/liveness scripts/zod-graph.test.ts src/system/metadata-form-zod-reconciliation.test.ts13 files, 360 tests, all pass (the gate script is edited, so its own suite is not optional).
  • pnpm --filter @objectstack/spec typecheck — green (tsc --noEmit + check:scripts-typecheck + check:test-typecheck).

The gate is what judges this work: with the four files absent, check:liveness reds with four UNCLASSIFIED types; with them present and the README/state-counts halves missing, it reds on the index and on the generated count artifact. Both were observed on the way in.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ess ledger
WIP
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
…ness ledger
Four new ledger files classify all 32 authorable properties of
CrudEndpointsConfigSchema, MetadataEndpointsConfigSchema,
BatchEndpointsConfigSchema and RouteGenerationConfigSchema — the
RestServerConfig sub-objects a host writes when it constructs the REST
server — enrolled through the gate's SPEC_ONLY_SCHEMAS override, the
route query / qa / manifest already take.
17 properties are live with a symbol-anchored consumer and a producer
pointer at the normalizer. 15 are dead: the ten keys the census
measured, with crud.patterns and routes.overrides expanded into a row
per member. No key is removed, enforced, deprecated or re-described;
rest-server.zod.ts is not edited.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 6 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/batch_endpoints.json, packages/spec/liveness/crud_endpoints.json, …) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 13bf05d3fe8b1795f3f5aee7daf29ee217590ab9packageMentionDocs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Sep 2, 2026
@os-sam
os-sam marked this pull request as ready for review September 2, 2026 16:42
@os-sam
os-sam enabled auto-merge September 2, 2026 16:42
@os-sam
os-sam added this pull request to the merge queueSep 2, 2026
Merged via the queue into main with commit a3d5724Sep 2, 2026
36 checks passed
@os-sam
os-sam deleted the claude/issue-14369-rest-server-config-liveness-ledger branch September 2, 2026 18:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mtooling

Projects

None yet

2 participants

@os-sam@claude