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
…and (2) admits a whitelist through the static-readonly write strip: the audit/timestamp family plus author-declared business readonly fields (closed_at, resolved_by, …), so an upsert refresh no longer silently drops them.
事实
content/docs/protocol/objectql/state-machine.mdx:113关于treatAsHistorical/preserveAudit的那条 bullet,把readonly白名单豁免描述成对 upsert 的两半都成立:实际只有 update 那一半为真。create 半边走的是 DataProtocol 入口剥离(
packages/metadata-protocol/src/protocol.ts的stripReadonlyForInsert,#3043),它只认context.isSystem,从不读preserveAudit。一次treatAsHistorical的 upsert 导入,因此在它更新的行上保留closed_at,在它新建的行上照旧剥掉。这正是 #6640 记录的那句话(其正文里已点名这条 state-machine 文案),但 #6640 的 file surface 只覆盖
security.mdx的 preserveAudit 段、field.zod.ts的 describe 与重新生成的 reference 文档,没有state-machine.mdx,所以 PR #6823 按纪律没有动它 —— 留下这一处仍与收窄后的契约相抵触。影响
维护者 2026-08-08 对 #6640 的裁决(option 2 + loudness rider)已把契约收窄为「豁免仅在 UPDATE 路径成立」,并由 PR #6823 落到
.describe()与security.mdx。这条 bullet 是同一主张在文档里剩下的最后一处旧说法:读者据此设计一次历史 upsert 导入,会预期新建行也保留closed_at,而实际拿到的是被剥掉的列(现在附带一条 WARN)。顺带记录第二处、更轻的一处:
content/docs/references/kernel/execution-context.mdx:69的preserveAudit行描述为空,因为packages/spec/src/kernel/execution-context.zod.ts:356的preserveAudit: z.boolean().optional()没有.describe()(语义只写在上方 348 行的块注释里)。同一裁决之后,这里正好是写下「UPDATE 路径豁免;INSERT 侧须走 system 上下文」的地方。是否合并处理交由分诊。建议修法
isSystem(措辞可直接沿用 PR fix(metadata-protocol,spec): preserveAudit is UPDATE-only — narrow the contract and warn loudly on a non-system INSERT (#6640) #6823 在security.mdx里落的 callout,保持一处口径);ExecutionContextSchema.preserveAudit补一条.describe(),让生成的 reference 行不再为空(会触发check:docs的重新生成,须整体重跑生成器)。Blocked-by:PR #6823(#6640)—— 收窄后的规范措辞以那条 PR 落地的security.mdxcallout 为准;在它合并前改这里会有两套说法。⛔ 不认领,仅记录。会话:
session_01W6bLax4KMrSfnE1ydFU8Dw