Skip to content

Commit 3795c5f

Browse files
feat(spec): error-code provenance gate + four adjudicated ledger rows (#14091)
* feat(spec): error-code provenance rows + check:error-code-provenance gate (WIP) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1 * feat(spec): regen artifacts, admission-pin update, dispatcher-safe fixtures Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1 * test(spec): ADR-0122 isomorphism pin Iso865 for ProvenanceWaiverSchema Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mciyv38maJ6HYVMiaM26T1 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 09e4b0e commit 3795c5f

17 files changed

Lines changed: 951 additions & 12 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
Error-code ledger: provenance rows and a provenance gate (#13353). Four adjudicated owner-key rows land for packages that already stamp registered codes on their own wire doors — `@objectstack/plugin-webhooks` / `INVALID_REQUEST`, `@objectstack/cloud-connection` / `FORBIDDEN`, `@objectstack/cli` / `ENVIRONMENT_NOT_FOUND`, `@objectstack/trigger-api` / `INVALID_REQUEST`. The registered union is unchanged (every code was already registered under another package), so `ErrorCode` accepts and rejects exactly what it did before — the rows are provenance only. A new mechanical gate (`check:error-code-provenance`) sweeps `packages/**` non-test source and fails any stamp site of a registered code the stamping package's own owner key does not list; deliberate "the door, not the producer, names the wire vocabulary" splits are recorded in the new exported `PROVENANCE_WAIVERS` table (with `ProvenanceWaiverSchema`), held live by the gate in both directions.

.github/workflows/lint.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2262,6 +2262,23 @@ jobs:
22622262
- name: Dispatcher error-code vocabulary guard
22632263
run: pnpm check:dispatcher-error-vocabulary
22642264

2265+
# #13353: the PROVENANCE half of the same ledger. The gate above reports
2266+
# codes the vocabulary does not contain; this one reports REGISTERED codes
2267+
# stamped by a package whose own owner key does not list them — the drift
2268+
# the ledger's admission rules structurally cannot see (they check casing,
2269+
# duplication and shadowing, never who emits), re-found by hand three
2270+
# times (#7504, #13254, #13353). Deliberate "the door, not the producer,
2271+
# names the wire vocabulary" splits are recorded in PROVENANCE_WAIVERS
2272+
# inside the ledger file and held live by the gate in both directions.
2273+
# Same placement rationale as its sibling above — no `paths:` filter,
2274+
# deliberately: the producers live in any package, and the rows live in
2275+
# packages/spec. It CANNOT ride the spec vitest suite instead: turbo
2276+
# hashes only per-package inputs, so a cached spec `test` run would stay
2277+
# green on exactly the PR that adds an unlisted stamper elsewhere.
2278+
# Runs its own --self-test first (wired into the package script).
2279+
- name: Error-code provenance guard
2280+
run: pnpm --filter @objectstack/spec check:error-code-provenance
2281+
22652282
# #10534 follow-up 4: a `rawApp` mount under the auth basePath with no ledger
22662283
# row. `auth-plugin.ts` mounts routes DIRECTLY on the raw Hono app, ahead of
22672284
# the better-auth catch-all, so the vendor's route table cannot account for

content/docs/references/api/error-code-ledger.mdx

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,18 @@ registration is a recorded waiver, never drift. A code registered NOWHERE
9797
A code emitted by several packages is listed once per emitting package —
9898
the union dedupes; the per-package rows are provenance, not identity.
9999

100+
Since #13353 that sentence has a mechanical half: the provenance gate
101+
(`check:error-code-provenance`, `packages/spec/scripts/`) sweeps every
102+
stamp site of a REGISTERED code in `packages/**` non-test source and fails
103+
when the stamping package's own owner key does not list it. The admission
104+
rules below never ask WHO emits, so before that gate an unlisted emitter was
105+
invisible to every gate the repo has (three hand sweeps found the same class
106+
three times: #7504, #13254, #13353). Two deliberate shapes are NOT rows and
107+
are recorded in `PROVENANCE_WAIVERS` instead: a DOOR in another
108+
package that names the wire vocabulary itself (`FLOW_DISABLED`,
109+
`UPDATE_ID_MISMATCH` — see their rows' comments), and a shared constructor
110+
package whose throw is served under another package's registration.
111+
100112
## Retiring a code
101113

102114
A row whose last EMITTER is deleted comes out with it. The admission rules
@@ -129,8 +141,8 @@ SEPARATE vocabulary and do not belong here — see #3977 (ADR-0112 D6).
129141
## TypeScript Usage
130142

131143
```typescript
132-
import { ErrorCode, StandardSynonymWaiverSchema } from '@objectstack/spec/api';
133-
import type { ErrorCode, StandardSynonymWaiver } from '@objectstack/spec/api';
144+
import { ErrorCode, ProvenanceWaiverSchema, StandardSynonymWaiverSchema } from '@objectstack/spec/api';
145+
import type { ErrorCode, ProvenanceWaiver, StandardSynonymWaiver } from '@objectstack/spec/api';
134146

135147
// Validate data
136148
const result = ErrorCode.parse(data);
@@ -442,6 +454,20 @@ const result = ErrorCode.parse(data);
442454
* `WRONG_PASSWORD`
443455

444456

457+
---
458+
459+
## ProvenanceWaiver
460+
461+
### Properties
462+
463+
| Property | Type | Required | Description |
464+
| :--- | :--- | :--- | :--- |
465+
| **package** | `string` || The package whose source stamps the code without an owner-key row |
466+
| **code** | `string` || The registered code the package stamps |
467+
| **registeredUnder** | `string` || The owner key that deliberately carries the row instead |
468+
| **reason** | `string` || Why the stamping package carries no row — recorded so provenance is a decision, not drift |
469+
470+
445471
---
446472

447473
## StandardSynonymWaiver

content/docs/references/index.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Protocol Reference
3-
description: Every schema published by @objectstack/spec — 1597 schemas across 14 protocol modules
3+
description: Every schema published by @objectstack/spec — 1598 schemas across 14 protocol modules
44
---
55

66
{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}
@@ -20,7 +20,7 @@ counts are sums of the rows they head. Regenerate with
2020
| Module | Pages | Schemas | Description |
2121
| :--- | ---: | ---: | :--- |
2222
| [AI Protocol](/docs/references/ai) | 11 | 66 | Agents, tools, skills, RAG and knowledge sources, model registry, conversations. |
23-
| [API Protocol](/docs/references/api) | 31 | 438 | REST contracts, endpoints, routing, realtime, batch, discovery. |
23+
| [API Protocol](/docs/references/api) | 31 | 439 | REST contracts, endpoints, routing, realtime, batch, discovery. |
2424
| [Automation Protocol](/docs/references/automation) | 13 | 68 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. |
2525
| [Cloud Protocol](/docs/references/cloud) | 11 | 94 | Environments, packages and versions, marketplace, developer portal, tenancy. |
2626
| [Data Protocol](/docs/references/data) | 29 | 166 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. |
@@ -33,7 +33,7 @@ counts are sums of the rows they head. Regenerate with
3333
| [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. |
3434
| [System Protocol](/docs/references/system) | 36 | 291 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. |
3535
| [UI Protocol](/docs/references/ui) | 16 | 153 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. |
36-
| **Total** | **200** | **1597** | 14 protocol modules |
36+
| **Total** | **200** | **1598** | 14 protocol modules |
3737

3838
---
3939

@@ -61,7 +61,7 @@ Agents, tools, skills, RAG and knowledge sources, model registry, conversations.
6161

6262
## API Protocol
6363

64-
**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **31 pages, 438 schemas**
64+
**Source:** `packages/spec/src/api/` · **Import:** `@objectstack/spec/api` · **31 pages, 439 schemas**
6565

6666
REST contracts, endpoints, routing, realtime, batch, discovery.
6767

@@ -77,7 +77,7 @@ REST contracts, endpoints, routing, realtime, batch, discovery.
7777
| [`dispatcher.zod.ts`](/docs/references/api/dispatcher) | `DispatcherConfig`, `DispatcherErrorCode`, `DispatcherErrorResponse`, `DispatcherRoute` |
7878
| [`documentation.zod.ts`](/docs/references/api/documentation) | `ApiChangelogEntry`, `ApiDocumentationConfig`, `ApiTestCollection`, `ApiTestRequest`, `ApiTestingUiConfig`, `ApiTestingUiType`, `CodeGenerationTemplate`, `GeneratedApiDocumentation`, `OpenApiSecurityScheme`, `OpenApiServer`, `OpenApiSpec` |
7979
| [`endpoint.zod.ts`](/docs/references/api/endpoint) | `ApiEndpoint`, `ApiMapping` |
80-
| [`error-code-ledger.zod.ts`](/docs/references/api/error-code-ledger) | `ErrorCode`, `StandardSynonymWaiver` |
80+
| [`error-code-ledger.zod.ts`](/docs/references/api/error-code-ledger) | `ErrorCode`, `ProvenanceWaiver`, `StandardSynonymWaiver` |
8181
| [`errors.zod.ts`](/docs/references/api/errors) | `EnhancedApiError`, `ErrorCategory`, `ErrorResponse`, `FieldError`, `FieldErrorCode`, `RetryStrategy`, `StandardErrorCode` |
8282
| [`events.zod.ts`](/docs/references/api/events) | `BulkDataEvent`, `BulkDataEventType`, `DataEvent`, `DataEventType`, `MetadataEvent`, `MetadataEventType` |
8383
| [`export.zod.ts`](/docs/references/api/export) | `CreateExportJobRequest`, `CreateExportJobResponse`, `CreateImportJobRequest`, `CreateImportJobResponse`, `DeduplicationStrategy`, `ExportFormat`, `ExportImportTemplate`, `ExportJobProgress`, `ExportJobStatus`, `ExportJobSummary`, `FieldMappingEntry`, `GetExportJobDownloadRequest`, `GetExportJobDownloadResponse`, `ImportJobProgress`, `ImportJobResults`, `ImportJobStatus`, `ImportJobSummary`, `ImportMapping`, `ImportRequest`, `ImportResponse`, `ImportRowResult`, `ImportValidationConfig`, `ImportValidationMode`, `ImportValidationResult`, `ImportWriteMode`, `ListExportJobsRequest`, `ListExportJobsResponse`, `ListImportJobsRequest`, `ListImportJobsResponse`, `ScheduleExportRequest`, `ScheduleExportResponse`, `ScheduledExport`, `UndoImportJobResponse` |

docs/audits/2026-07-unknown-key-strictness-ledger.counts.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ directory rather than per file.
257257
| Dir | Sites |
258258
|---|---|
259259
| `ai/` | 77 |
260-
| `api/` | 453 |
260+
| `api/` | 454 |
261261
| `cloud/` | 83 |
262262
| `identity/` | 32 |
263263
| `integration/` | 10 |

packages/spec/api-surface/api.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@
726726
"OpenApiSpecSchema (const)",
727727
"OperatorMapping (type)",
728728
"OperatorMappingSchema (const)",
729+
"PROVENANCE_WAIVERS (const)",
729730
"PackageApiContracts (const)",
730731
"PackageApiErrorCode (type)",
731732
"PackageExportManifest (type)",
@@ -767,6 +768,8 @@
767768
"PresignedUrlResponse (type)",
768769
"PresignedUrlResponseParsed (type)",
769770
"PresignedUrlResponseSchema (const)",
771+
"ProvenanceWaiver (type)",
772+
"ProvenanceWaiverSchema (const)",
770773
"PublishMetaItemRequest (type)",
771774
"PublishMetaItemRequestSchema (const)",
772775
"PublishMetaItemResponse (type)",

packages/spec/authorable-surface/api.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,10 @@
13091309
"api/PresignedUrlResponse:error",
13101310
"api/PresignedUrlResponse:meta",
13111311
"api/PresignedUrlResponse:success",
1312+
"api/ProvenanceWaiver:code",
1313+
"api/ProvenanceWaiver:package",
1314+
"api/ProvenanceWaiver:reason",
1315+
"api/ProvenanceWaiver:registeredUnder",
13121316
"api/PublishMetaItemRequest:actor",
13131317
"api/PublishMetaItemRequest:message",
13141318
"api/PublishMetaItemRequest:name",

packages/spec/declaration-map/api.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@
573573
"PresenceUpdateSchema": "api/PresenceUpdate",
574574
"PresignedUrlResponse": "api/PresignedUrlResponse",
575575
"PresignedUrlResponseSchema": "api/PresignedUrlResponse",
576+
"ProvenanceWaiver": "api/ProvenanceWaiver",
577+
"ProvenanceWaiverSchema": "api/ProvenanceWaiver",
576578
"PublishMetaItemRequest": "api/PublishMetaItemRequest",
577579
"PublishMetaItemRequestSchema": "api/PublishMetaItemRequest",
578580
"PublishMetaItemResponse": "api/PublishMetaItemResponse",

packages/spec/export-origins/api.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@
726726
"OpenApiSpecSchema": "src/api/documentation.zod.ts#OpenApiSpecSchema (const)",
727727
"OperatorMapping": "src/api/query-adapter.zod.ts#OperatorMapping (type)",
728728
"OperatorMappingSchema": "src/api/query-adapter.zod.ts#OperatorMappingSchema (const)",
729+
"PROVENANCE_WAIVERS": "src/api/error-code-ledger.zod.ts#PROVENANCE_WAIVERS (const)",
729730
"PackageApiContracts": "src/api/package-api.zod.ts#PackageApiContracts (const)",
730731
"PackageApiErrorCode": "src/api/package-api.zod.ts#PackageApiErrorCode (type)",
731732
"PackageExportManifest": "src/api/package-lifecycle.zod.ts#PackageExportManifest (type)",
@@ -767,6 +768,8 @@
767768
"PresignedUrlResponse": "src/api/storage.zod.ts#PresignedUrlResponse (type)",
768769
"PresignedUrlResponseParsed": "src/api/storage.zod.ts#PresignedUrlResponseParsed (type)",
769770
"PresignedUrlResponseSchema": "src/api/storage.zod.ts#PresignedUrlResponseSchema (const)",
771+
"ProvenanceWaiver": "src/api/error-code-ledger.zod.ts#ProvenanceWaiver (type)",
772+
"ProvenanceWaiverSchema": "src/api/error-code-ledger.zod.ts#ProvenanceWaiverSchema (const)",
770773
"PublishMetaItemRequest": "src/api/protocol.zod.ts#PublishMetaItemRequest (type)",
771774
"PublishMetaItemRequestSchema": "src/api/protocol.zod.ts#PublishMetaItemRequestSchema (const)",
772775
"PublishMetaItemResponse": "src/api/protocol.zod.ts#PublishMetaItemResponse (type)",

packages/spec/json-schema.manifest/api.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@
315315
"api/PresenceStatus",
316316
"api/PresenceUpdate",
317317
"api/PresignedUrlResponse",
318+
"api/ProvenanceWaiver",
318319
"api/PublishMetaItemRequest",
319320
"api/PublishMetaItemResponse",
320321
"api/PublishPackageDraftsResponse",

0 commit comments

Comments
 (0)