What this card is
The maintainer ruled on E3 (comment 5550450281 on #14147, 2026-09-05, verbatim: 「已发布必修,其余立卡」): for the class 「a superseded architecture still stated as live」, a published surface is fixed in the round, and non-published residue becomes one finding card while the PR lands. This is that card for PR #15395 (card #14147, ruling C 5522734749). The maintainer ruled these sites are carded rather than fixed in the PR; nothing here blocks #15395.
The class, in one sentence: any present-tense statement that a non-system INSERT is exempt from, or seeds past, the static readonly strip, or that the strip lives at the DataProtocol ingress. False since ruling C (2026-09-03): engine.insert runs the same isSystem-gated stripReadonlyFields as engine.update; the metadata-protocol ingress copy is deleted; a sys_-prefixed or managedBy object is left to its own guards by staticReadonlyInsertSubject (that asymmetry is #15719); readonlyWhen alone stays insert-exempt; preserveAudit is UPDATE-only.
How 「published」 was measured (PR #15395 patch round R4, head a73dd85db): the three packages were rebuilt and each site's sentence grepped, exit captured before any pipe, in the built dist/**/*.d.ts (the shipped declaration surface), the dist/**/*.{js,mjs,cjs}, and content/docs/** (the generated references/** projections and the customer-facing pages), with a firing control per package (the exported identifier next to the sentence). Three of the third verdict's nine N5 sites reached a .d.ts and were fixed in R4 — packages/spec/src/security/public-form.ts (TSDoc on PUBLIC_FORM_SERVER_MANAGED_FIELDS), packages/objectql/src/readonly-strict-errors.ts:166-173 (the operation property TSDoc of ReadonlyFieldRejectedError) and packages/services/service-settings/src/settings-service.ts:2274-2285 (the upsertRow docblock). The sites below reach no published artefact: test files and scripts/ are outside every package's files, and a floating module docblock ahead of a non-exported const is not emitted into the .d.ts. One boundary stated so nobody re-derives it: every shipped .js.map embeds its whole source (sourcesContent), so by that reading no source comment is ever non-published — that reading contradicts the ruling's own examples (test headers, in-source notes, scripts/ text), so the .d.ts / docs measurement above is the one applied.
The residue — each site, what it says, why it is the class
| # |
site (at a73dd85db) |
what it says |
why it is the class |
| 1 |
packages/objectql/src/readonly-strict-errors.ts:21-22 — the module docblock of the file that defines ERR_READONLY_FIELD_REJECTED (floating, ahead of the non-exported READONLY_CLASS_REASONS; NOT in dist/index.d.ts, measured) |
「on INSERT only the runtime-owned ones, because a create is deliberately exempt from the author-declared strips (#3413)」 |
False since C: engine.ts throws ReadonlyFieldRejectedError with the insertDropped union the static pass feeds; engine-insert-static-readonly-strip.test.ts 「strictReadonlyWrites refuses before any driver dispatch」 pins a static completed_at refused with ERR_READONLY_FIELD_REJECTED. ⚠️ The same file's operation TSDoc (:166-173) WAS published and was corrected in R4, so the file now disagrees with itself 150 lines apart — this card is the remedy for the non-published half. buildRefusalMessage is right and pinned byte-for-byte (#5126/#5503); do not touch it |
| 2 |
packages/services/service-settings/src/settings-secret-rotation.test.ts:13 (test header) |
「The INSERT path is deliberately exempt (#3413).」 |
The general sentence is false. The object (sys_setting: sys_-prefixed, managedBy: 'engine-owned') still behaves as the file describes — the first write inserts and lands, later updates are stripped — but by the platform-object carve-out in staticReadonlyInsertSubject (#15719), not by #3413. Its source sibling settings-service.ts:2274-2285 was corrected in R4 with exactly that mechanism |
| 3 |
packages/services/service-settings/src/settings-secret-rotation.test.ts:189 (a helper's docblock) |
「while the INSERT path is exempt (#3413)」 |
As 2 |
| 4 |
packages/services/service-settings/src/sys-secret-orphan-report.test.ts:190 (a helper's docblock) |
「while the INSERT path is exempt (#3413)」 |
As 2 |
| 5 |
packages/rest/src/rest-batch-endpoint.test.ts:308-312 (the comment heading the create-ingress-parity block) |
「The engine's INSERT path is static-readonly-exempt by design (#3413), so the #3043 strip that stops a non-system caller from seeding a read-only column lives at the protocol's create ingress」 |
The overturned sentence verbatim, one file from the source note (rest-server.ts:12357-12375) that R3 corrected — source and test now contradict each other. The routing the test pins is still right (one create ingress, one response contract: assertObjectRegistered #3770, the internal: true response strip #7823, the droppedFields relay); only the stated reason is superseded |
| 6 |
packages/services/service-automation/src/builtin/crud-dropped-fields.test.ts:144-146 (comment heading create_record is wired symmetrically (#3407)) |
「Today ObjectQL's insert path strips nothing (INSERT is readonly-exempt, FLS write denial throws) — but the node listens anyway, so a future insert-side strip surfaces instead of going silent.」 |
The 「future」 strip is live: crud-nodes.ts:321-330 one file over says so, and create-record-readonly-drop.test.ts (2 passed) proves a non-system flow's readonly seed is dropped and reported. The test's own assertions still hold (they feed the channel a synthetic drop) |
| 7 |
packages/spec/scripts/liveness/proof-registry.mts:156 (provenance comment on the readonly-static-write proof entry) |
「The proof pins the server-side strip (forge dropped, sibling edit lands, insert exempt) over real HTTP.」 |
The ledger's own statement of what the proof proves; the proof's header (showcase-static-readonly.dogfood.test.ts) and the R2-fixed packages/spec/liveness/field.json readonly row say the strip covers BOTH write paths. scripts/ is outside packages/spec's files; the :150 summary (「cannot be forged by a non-system UPDATE」) is true but names UPDATE only — a spec-lane call whether it should name INSERT too |
Stale by omission, not false — listed so nobody re-finds it: packages/objectql/src/validation/rule-validator.ts:1021, the stripReadonlyFields docblock, opens 「Strip CALLER-SUPPLIED writes to read-only fields from an UPDATE payload (#2948)」 and describes its guards in UPDATE terms, while since #14147 engine.insert calls the same function over staticReadonlyInsertSubject (the function's callers and the later paragraphs of the same file say so). Not in dist/*.d.ts (measured; control stripReadonlyFields present twice in other docblocks that already say 「on both write paths since #14147」).
Out of this card, stated so it is not re-filed: skills/objectstack-data/SKILL.md:274 (「from an UPDATE payload」) is the governed half of the ruling and lands in #15382 (human merge). content/docs/kernel/contracts/data-engine.mdx:371-373 is a historical quotation followed by 「That row is superseded」. Everything else the R4 sweep returns (147 unique lines over the twelve premise spellings, the content-only ingress co-occurrence pass and the claim-level patterns insert…exempt / exempt…insert / readonly-exempt / may seed|can seed / seed…readonly / readonly…seed / #3413 / covers UPDATE etc.) is classified line by line in the PR #15395 body (R4 section) as historical, ruled-state, readonlyWhen, the #7823 response strip, delegation prose, a pin that forbids the spelling, an unrelated subject, or a parser fixture.
How to close it
One prose-only PR, no behaviour change, no test deleted or skipped: replace each sentence with the ruled state (the R3/R4 corrections of rest-server.ts:12357-12375, settings-service.ts:2274-2285 and crud-nodes.ts:321-330 are the templates), then re-run the sweep from the PR #15395 body and show the live class at zero with the same positive controls. Cross-links: #14147 (card), PR #15395 (the engine change), ruling C 5522734749, verdicts 5548671173 (+ addendum 5548681179), 5549250610, 5550434842, the E3 ruling 5550450281, #15719 (the create/update asymmetry on managedBy objects), #15382 (the governed prose half), #15394 (the lint rules' scan gap).
Filed by the domain:engine execution seat, session session_01ARYe3yQTQCUFm5qPYNgKaJ, PR #15395 patch round R4. Ungraded, unrouted, unassigned — finding only, for the triage round.
Generated by Claude Code
What this card is
The maintainer ruled on E3 (comment 5550450281 on #14147, 2026-09-05, verbatim: 「已发布必修,其余立卡」): for the class 「a superseded architecture still stated as live」, a published surface is fixed in the round, and non-published residue becomes one
findingcard while the PR lands. This is that card for PR #15395 (card #14147, ruling C5522734749). The maintainer ruled these sites are carded rather than fixed in the PR; nothing here blocks #15395.The class, in one sentence: any present-tense statement that a non-system INSERT is exempt from, or seeds past, the static
readonlystrip, or that the strip lives at the DataProtocol ingress. False since ruling C (2026-09-03):engine.insertruns the sameisSystem-gatedstripReadonlyFieldsasengine.update; the metadata-protocol ingress copy is deleted; asys_-prefixed ormanagedByobject is left to its own guards bystaticReadonlyInsertSubject(that asymmetry is #15719);readonlyWhenalone stays insert-exempt;preserveAuditis UPDATE-only.How 「published」 was measured (PR #15395 patch round R4, head
a73dd85db): the three packages were rebuilt and each site's sentence grepped, exit captured before any pipe, in the builtdist/**/*.d.ts(the shipped declaration surface), thedist/**/*.{js,mjs,cjs}, andcontent/docs/**(the generatedreferences/**projections and the customer-facing pages), with a firing control per package (the exported identifier next to the sentence). Three of the third verdict's nine N5 sites reached a.d.tsand were fixed in R4 —packages/spec/src/security/public-form.ts(TSDoc onPUBLIC_FORM_SERVER_MANAGED_FIELDS),packages/objectql/src/readonly-strict-errors.ts:166-173(theoperationproperty TSDoc ofReadonlyFieldRejectedError) andpackages/services/service-settings/src/settings-service.ts:2274-2285(theupsertRowdocblock). The sites below reach no published artefact: test files andscripts/are outside every package'sfiles, and a floating module docblock ahead of a non-exported const is not emitted into the.d.ts. One boundary stated so nobody re-derives it: every shipped.js.mapembeds its whole source (sourcesContent), so by that reading no source comment is ever non-published — that reading contradicts the ruling's own examples (test headers, in-source notes,scripts/text), so the.d.ts/ docs measurement above is the one applied.The residue — each site, what it says, why it is the class
a73dd85db)packages/objectql/src/readonly-strict-errors.ts:21-22— the module docblock of the file that definesERR_READONLY_FIELD_REJECTED(floating, ahead of the non-exportedREADONLY_CLASS_REASONS; NOT indist/index.d.ts, measured)engine.tsthrowsReadonlyFieldRejectedErrorwith theinsertDroppedunion the static pass feeds;engine-insert-static-readonly-strip.test.ts「strictReadonlyWrites refuses before any driver dispatch」 pins a staticcompleted_atrefused withERR_READONLY_FIELD_REJECTED.operationTSDoc (:166-173) WAS published and was corrected in R4, so the file now disagrees with itself 150 lines apart — this card is the remedy for the non-published half.buildRefusalMessageis right and pinned byte-for-byte (#5126/#5503); do not touch itpackages/services/service-settings/src/settings-secret-rotation.test.ts:13(test header)sys_setting:sys_-prefixed,managedBy: 'engine-owned') still behaves as the file describes — the first write inserts and lands, later updates are stripped — but by the platform-object carve-out instaticReadonlyInsertSubject(#15719), not by #3413. Its source siblingsettings-service.ts:2274-2285was corrected in R4 with exactly that mechanismpackages/services/service-settings/src/settings-secret-rotation.test.ts:189(a helper's docblock)packages/services/service-settings/src/sys-secret-orphan-report.test.ts:190(a helper's docblock)packages/rest/src/rest-batch-endpoint.test.ts:308-312(the comment heading the create-ingress-parity block)readonly-exempt by design (#3413), so the #3043 strip that stops a non-system caller from seeding a read-only column lives at the protocol's create ingress」rest-server.ts:12357-12375) that R3 corrected — source and test now contradict each other. The routing the test pins is still right (one create ingress, one response contract:assertObjectRegistered#3770, theinternal: trueresponse strip #7823, thedroppedFieldsrelay); only the stated reason is supersededpackages/services/service-automation/src/builtin/crud-dropped-fields.test.ts:144-146(comment headingcreate_record is wired symmetrically (#3407))crud-nodes.ts:321-330one file over says so, andcreate-record-readonly-drop.test.ts(2 passed) proves a non-system flow's readonly seed is dropped and reported. The test's own assertions still hold (they feed the channel a synthetic drop)packages/spec/scripts/liveness/proof-registry.mts:156(provenance comment on thereadonly-static-writeproof entry)showcase-static-readonly.dogfood.test.ts) and the R2-fixedpackages/spec/liveness/field.jsonreadonlyrow say the strip covers BOTH write paths.scripts/is outsidepackages/spec'sfiles; the:150summary(「cannot be forged by a non-system UPDATE」) is true but names UPDATE only — a spec-lane call whether it should name INSERT tooStale by omission, not false — listed so nobody re-finds it:
packages/objectql/src/validation/rule-validator.ts:1021, thestripReadonlyFieldsdocblock, opens 「Strip CALLER-SUPPLIED writes to read-only fields from an UPDATE payload (#2948)」 and describes its guards in UPDATE terms, while since #14147engine.insertcalls the same function overstaticReadonlyInsertSubject(the function's callers and the later paragraphs of the same file say so). Not indist/*.d.ts(measured; controlstripReadonlyFieldspresent twice in other docblocks that already say 「on both write paths since #14147」).Out of this card, stated so it is not re-filed:
skills/objectstack-data/SKILL.md:274(「from an UPDATE payload」) is the governed half of the ruling and lands in #15382 (human merge).content/docs/kernel/contracts/data-engine.mdx:371-373is a historical quotation followed by 「That row is superseded」. Everything else the R4 sweep returns (147 unique lines over the twelve premise spellings, the content-onlyingressco-occurrence pass and the claim-level patternsinsert…exempt/exempt…insert/readonly-exempt/may seed|can seed/seed…readonly/readonly…seed/#3413/covers UPDATEetc.) is classified line by line in the PR #15395 body (R4 section) as historical, ruled-state,readonlyWhen, the #7823 response strip, delegation prose, a pin that forbids the spelling, an unrelated subject, or a parser fixture.How to close it
One prose-only PR, no behaviour change, no test deleted or skipped: replace each sentence with the ruled state (the R3/R4 corrections of
rest-server.ts:12357-12375,settings-service.ts:2274-2285andcrud-nodes.ts:321-330are the templates), then re-run the sweep from the PR #15395 body and show the live class at zero with the same positive controls. Cross-links: #14147 (card), PR #15395 (the engine change), ruling C5522734749, verdicts5548671173(+ addendum5548681179),5549250610,5550434842, the E3 ruling5550450281, #15719 (the create/update asymmetry onmanagedByobjects), #15382 (the governed prose half), #15394 (the lint rules' scan gap).Filed by the
domain:engineexecution seat, sessionsession_01ARYe3yQTQCUFm5qPYNgKaJ, PR #15395 patch round R4. Ungraded, unrouted, unassigned —findingonly, for the triage round.Generated by Claude Code