You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e78c95c
Browse filesBrowse the repository at this point in the historyBrowse files
docs(spec,rest,objectql,mcp,qa,scripts): the deleted ingress strip is no longer stated as live in schema text, code notes, test titles, the census gate's row annotations or the authz matrix
Patch round R3 on the contract re-review (5549250610), items 1-3 and 5. Prose only;
no behaviour change, no test deleted or skipped.
- N2 (a)-(e): the `preserveAudit`, `CreateDataResponseSchema.droppedFields`,
`CreateManyDataResponseSchema.droppedFields` and `BatchOperationResultSchema.droppedFields`
`.describe()` strings and the `CloneDataResponseSchema` TSDoc now state the ruled
state: the static `readonly` strip runs inside `engine.insert`, after `beforeInsert`,
`isSystem`-gated; the DataProtocol ingress copy is deleted. The generated
`content/docs/references/**` rows follow in the next commit via `check:generated --fix`.
- N2 (f)-(k): `rest-server.ts` batch-route note keeps the routing reason on what the
ingress still owns (object-existence gate, #7823 response strip, `droppedFields`
relay) and attributes the platform-object carve-out to the engine, where it lives
(`staticReadonlyInsertSubject`); the #3431 header note; `rule-validator.ts`'s
second-consumer sentence names `staticReadonlyInsertSubject`; the mcp stdio bridge's
divergence list drops the readonly strip and says why it is closed; two test
comments/titles in `engine-autonumber-runtime-owned.test.ts` and one title in
`rest-dropped-fields.test.ts`.
- N3: the seven `why` rows in `check-system-context-census.mjs` re-derived against the
head table (24->23 x2, 22->21 x2, 25->24, 34->33, 60->59). The gate never parses them.
- N4: the authz matrix row states the two mechanisms - a system context for identity
provisioning; the `sys_`/`managedBy` carve-out for the metadata repository's
`sys_metadata_history.recorded_by` provenance row - and re-derives "event-log
cursors" by name as `sys_metadata_history.event_seq` (same row, same mechanism).
Issue-id multiset of the row is byte-identical for the prose-id ledger.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
it('an author-declared `readonly` field of an ORDINARY type is still stripped at the ingress',async()=>{
634
+
it('an author-declared `readonly` field of an ORDINARY type is still stripped on a create through the ingress — inside `engine.insert` since ruling C',async()=>{
632
635
// The #3043 strip keeps its full width — only runtime-owned types moved.
{id: 'readonly-static-write',summary: 'static `readonly: true` stripped from non-system UPDATE (#2948 / #3003) AND INSERT (#3043 at the ingress; in-engine for every caller since the 2026-09-03 ruling) payloads — neither a direct PATCH nor a direct POST can forge approval/status/amount columns the UI never renders',state: 'enforced',
282
-
enforcement: 'UPDATE: objectql/engine.ts stripReadonlyFields on the single-id + multi-row paths (#2948, caller-supplied VALUES only — the entry snapshot carries the caller payload, so a server stamp survives whether the hook ADDED the key or OVERWROTE one the caller also sent, #5591). INSERT: objectql/engine.ts runs the SAME stripReadonlyFields inside engine.insert (maintainer ruling 2026-09-03, option C — one semantics, one enforcement point; the metadata-protocol ingress copy that used to cover only the DataProtocol faces while a direct engine.insert caller bypassed it is deleted), after the beforeInsert hooks and before validation, over staticReadonlyInsertSubject (runtime-owned types keep their own pass, platform objects their own 403 guards); the field re-derives its defaultValue. isSystem exempt on both; internal writers that seed readonly columns on create (identity provisioning, provenance, event-log cursors) do so under a system context; symmetric with the readonlyWhen strip',
282
+
enforcement: 'UPDATE: objectql/engine.ts stripReadonlyFields on the single-id + multi-row paths (#2948, caller-supplied VALUES only — the entry snapshot carries the caller payload, so a server stamp survives whether the hook ADDED the key or OVERWROTE one the caller also sent, #5591). INSERT: objectql/engine.ts runs the SAME stripReadonlyFields inside engine.insert (maintainer ruling 2026-09-03, option C — one semantics, one enforcement point; the metadata-protocol ingress copy that used to cover only the DataProtocol faces while a direct engine.insert caller bypassed it is deleted), after the beforeInsert hooks and before validation, over staticReadonlyInsertSubject (runtime-owned types keep their own pass, platform objects their own 403 guards); the field re-derives its defaultValue. isSystem exempt on both. An internal writer that seeds a readonly column on create does so by one of exactly two mechanisms: (1) a system context — identity provisioning (plugin-auth objectql-adapter.ts wraps its engine in withSystemContext); (2) the platform-object carve-out in staticReadonlyInsertSubject (rule-validator.ts) — a sys_-prefixed or managedBy object is outside the strip subject, so the metadata repository (sys-metadata-repository.ts) seeds sys_metadata_history provenance (recorded_by, readonly lookup) and its event-log cursor (event_seq, readonly number) under the CALLER context, and those columns are policed by the object guards of that platform object rather than swallowed by the strip — as is every other platform-object seeder; symmetric with the readonlyWhen strip',
note: 'The #3003 field report: `readonly: true` used to be UI-only, so a logged-in non-admin self-approved a 4-stage approval (approval_status/approval_stage/confirmed_total) with one same-session REST PATCH on a draft record — RECORD_LOCKED only guards pending flows, and the draft never entered one. #3043 is the INSERT face: the same non-admin could skip the draft entirely and POST a record already `approval_status:"approved"` — a step SHORTER than #3003, and one the UPDATE strip never reached. It was first enforced at the DATA-WRITE INGRESS (not the engine) so it covered every external caller — REST, the GraphQL/MCP dispatcher, bulk import — without stripping internal writers; the maintainer ruling of 2026-09-03 (option C) moved it INTO the engine, so a direct engine.insert caller is covered too and a writer that seeds a readonly column on create (identity provisioning, provenance, event-log cursors) does so under a system context. The strip is SILENT on both paths (HTTP 2xx, forged value dropped; a stripped INSERT field falls back to its defaultValue). `readonlyWhen` stays INSERT-exempt (a conditional lock needs a prior record). System-context writes (import, seed replay, migration) still seed readonly columns. Engine proof in objectql engine-insert-static-readonly-strip.test.ts (forge stripped against a real ObjectQL, default re-seeded, system context allowed, hook stamps survive, strict refuses); delegation proof in metadata-protocol protocol.readonly-insert.test.ts (every create face forwards whole and surfaces the engine verdict as droppedFields where its contract carries one).'},
284
+
note: 'The #3003 field report: `readonly: true` used to be UI-only, so a logged-in non-admin self-approved a 4-stage approval (approval_status/approval_stage/confirmed_total) with one same-session REST PATCH on a draft record — RECORD_LOCKED only guards pending flows, and the draft never entered one. #3043 is the INSERT face: the same non-admin could skip the draft entirely and POST a record already `approval_status:"approved"` — a step SHORTER than #3003, and one the UPDATE strip never reached. It was first enforced at the DATA-WRITE INGRESS (not the engine) so it covered every external caller — REST, the GraphQL/MCP dispatcher, bulk import — without stripping internal writers; the maintainer ruling of 2026-09-03 (option C) moved it INTO the engine, so a direct engine.insert caller is covered too. A writer that seeds a readonly column on create does so under a system context (identity provisioning) or, for a platform object (sys_-prefixed or managedBy), under the carve-out in staticReadonlyInsertSubject that leaves such objects to their own guards — the metadata repository writing sys_metadata_history.recorded_by provenance and its event_seq event-log cursor under the caller context is that second mechanism, not a system context. The strip is SILENT on both paths (HTTP 2xx, forged value dropped; a stripped INSERT field falls back to its defaultValue). `readonlyWhen` stays INSERT-exempt (a conditional lock needs a prior record). System-context writes (import, seed replay, migration) still seed readonly columns. Engine proof in objectql engine-insert-static-readonly-strip.test.ts (forge stripped against a real ObjectQL, default re-seeded, system context allowed, hook stamps survive, strict refuses); delegation proof in metadata-protocol protocol.readonly-insert.test.ts (every create face forwards whole and surfaces the engine verdict as droppedFields where its contract carries one).'},
0 commit comments