Skip to content

docs(adr): ADR-0005 appendix (c) — the persisted document is the parsed body once every round-trip key is declared - #20777

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-20457-adr-0005-appendix-c-parsed-body
Sep 30, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-20457-adr-0005-appendix-c-parsed-body

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20457

Part of #20051 (stage (iii) of ruling 甲 there; stage (iv), the storage switch, stays on that card).

Clause-②: no

What this changes

One file, docs/adr/0005-metadata-customization-overlay.md:

  • Appendix (c), the persisted-document bullet of "Addendum — 2026-05-16 (c)", now states the ruled end state: the persisted document is the parsed body (parsed.data) once every round-trip key is declared. The bullet itself says the rule is ruled but not yet in force.
  • A dated note directly under that bullet ("Amended (2026-09-30)"), written the way ADR-0053's 2026-09-30 in-place amendment is written:
    1. the provenance: ruling 甲 on spec(ui)+metadata save: judge a flattened view overlay's top-level options.KIND with the strict per-kind schema and persist the PARSED body — the door half of objectui#10380 #20051, comment 5856781584, maintainer 「开始总监决裁」;
    2. the 2026-05-16 bullet, quoted verbatim and marked superseded;
    3. what "every round-trip key is declared" means for view: the record VIEW_CONSOLE_ROUND_TRIP_KEYS and its closure test;
    4. the stage (ii) symbol that declares each key, on each member: ViewItemWireSchema and VIEW_METADATA_MEMBERS.listOverlay, via viewSwitcherRowStateFields, viewItemWireFields, listOverlayRoundTripFields, viewItemBaseShape and flattenedViewOverlayFields;
    5. where the census's other finds map instead (objectName to object, and the others);
    6. the interim state;
    7. what stage (iv) does.
  • Status line: one new Amended (2026-09-30, …) entry. Prime Directive [WIP] Add Chinese version of the documentation #13 asks for an amended status line when a recorded decision is reversed, and every earlier decision-changing amendment of this ADR is on that line. This is the one line outside the bullet-plus-note surface the claim names. Same file.

⛔ No persistence code, no GUARD pins, nothing under packages/. No scripts/adr-anchors/ file either: no gate asked for one (all green below). The ADR's new code citations are symbol anchors that check-adr-symbol-anchors resolves.

Declared is not yet enforced: how the text handles that

On main the runtime still stores request.item. The verbatim-save pins are still there (protocol-meta.test.ts "preserves Studio-only auxiliary fields verbatim (not stripped)", protocol.graft-folded-form-sections.test.ts "GUARD: Studio-only round-trip keys still survive the save"). So the ADR states the decision and the status next to each other:

  • the amended bullet ends with "Ruled, not yet in force";
  • note item 5 says that today a key no member declares is still stored, so "declared" does not yet mean "the only keys stored";
  • note item 6 lists what stage (iv) does: store the parsed body, flip the GUARD pins, judge ViewItemWireSchema's top-level options, and first measure the production count of stored rows that carry undeclared top-level keys.

This follows the PM's working assumption. It also matches the repo convention: ADR-0053's 2026-09-30 amendment carries an "Interim state" item in the same way.

Evidence (head c8ee5833)

  • Gates were derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, with no paths: the same 19 as the dispatch. Reconciled with --ran: "19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero — all 19 recorded an exit code and none of them is 3)".
  • All 19 exit 0 on c8ee5833: check-adr-links (+ --self-test), check-adr-symbol-anchors (+ --self-test), check-ci-filter-parity, check-closing-keyword-parity (+ --self-test), check-comment-mask-corpus, check:doc-formula-expressions, check:adr-anchors, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-prior-rulings, check:refd-timer-probe, check:watch-hint-literal.
  • check-adr-symbol-anchors printed: "2156 anchors across 140 records resolve — 320 symbol (294 declaration, 26 literal), 1809 file-level, 27 cross-repo, 6 exempt, 9 continuation".
  • check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET: @objectstack/formula and @objectstack/lint were unbuilt in the fresh worktree). That run measured nothing. I built both through the verify lock (a turbo cache hit, 4 of 4) and reran it: exit 0.
  • Ablation (a one-off; no permanent test file). With the change committed, I used scripts/ablation-replace.mjs to break one new anchor, renaming #listOverlayRoundTripFields to #listOverlayRoundTripFieldz (anchor count 1 to 0, blob a893abb2 to 50270267).
    • The gate then printed "❌ check-adr-symbol-anchors: 1 finding(s)" and "[unresolved-symbol] … #listOverlayRoundTripFieldz" at the note's line.
    • I restored the file with git checkout HEAD --. Its blob was back to a893abb2 and git diff HEAD was empty.
    • So the gate reads the new anchors; it does not pass over them.
  • No changeset: docs/adr/** publishes nothing (skip-changeset).

Acceptance notes

These are observations, not filed. Their carrier is stage (iv) on #20051.

  1. The verbatim-save pin population is wider than the two the ruling read. Three tests assert the verbatim save by name:

    • packages/objectql/src/protocol-meta.test.ts: "preserves Studio-only auxiliary fields verbatim (not stripped)";
    • packages/metadata-protocol/src/protocol.graft-folded-form-sections.test.ts: "GUARD: Studio-only round-trip keys still survive the save";
    • packages/metadata-protocol/src/protocol.graft-normalized-operators.test.ts: "keeps Studio-only auxiliary fields a parsed.data swap would strip".

    At least one more depends on the verbatim save: protocol.runtime-authoring-gate.test.ts, "the door persists the authored body verbatim". Two of the pins need re-judging, not just flipping. The graft-folded GUARD writes isPinned / isDefault / sortOrder onto a form overlay, and VIEW_CONSOLE_ROUND_TRIP_KEYS records that the console never writes them there. The protocol-meta pin writes objectName, which the census maps to object.

  2. Per-type scope of the switch. resolveOverlaySchema validates every type with a registered schema, and each one is stored as sent today. The ruling's end state names "a saved view", and the round-trip census covered view only. The amended bullet states the rule with its condition ("once every round-trip key is declared") and claims a satisfied condition for view only. Whether the stage (iv) switch covers dashboard and the other validated types is stage (iv)'s question.

  3. Code comments that cite this decision. The resolveOverlaySchema docblock and the saveMetaItem comment in packages/metadata-protocol/src/protocol.ts, and the pins, cite "ADR-0005 §Validation", a heading this ADR does not have. They describe today's behaviour, which stays true until stage (iv). No scripts/adr-anchors/ entry ties protocol.ts to ADR-0005. Stage (iv) implements the decision in code, so that is where the anchor belongs (Prime Directive [WIP] Add Chinese version of the documentation #13).

维护者速读(草稿)

改了什么:只改了 ADR-0005 这一份文档。

为什么改:这是裁决甲的第 (iii) 步。第 (ii) 步已经把控制台会写回、再读回的键都声明进了 spec:置顶、排序、可见性分组、默认视图、列状态,以及设置覆盖标记。所以附录 (c) 现在可以照实写。

风险与代价(含回滚):

  • 纯文档改动。不动运行时代码,不动测试,不发布任何包。
  • 唯一的风险是读者把新文字当成"运行时已经这样做了"。所以条目本身写明"已裁定、尚未生效";注记也写明:目前仍然原样存请求体,存储切换是第 (iv) 步。
  • 回滚:revert 这一个 commit 即可。

席位意见:

你要做的:审阅后在本 PR 上给 APPROVED。这是 Tier H 治理面 docs/adr/**,由席位落地。存储切换本身(第 iv 步)仍挂在 #20051 上,不在本 PR 里。


Generated by Claude Code

…d body once every round-trip key is declared

Amends the persisted-document bullet of "Addendum 2026-05-16 (c)" to the
end state of ruling 甲 on #20051, with a dated note (2026-09-30) naming the
stage (ii) spec symbols that declare each round-trip key of a stored view
row, and stating that the storage switch (stage iv) has not landed. The
status line records the amendment (Prime Directive #13).

Claude-Session: https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Sep 30, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 30, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c8ee5833960b9077e9f15e6ade4adf71105612bd
Local-runs: none

Inputs read: card #20457 (body + all 3 comments: unlock 5875792846, claim 5903925634, os-dev-report 5904124008); PR #20777 (body, file list, net diff against main); the check-runs on c8ee5833; ruling 甲 = comment 5856781584 on #20051 and #20051's body. Repository files were read at the head and at origin/main with git show / git grep only.

Check-runs on c8ee5833 (read twice). First read ~04:41Z: 34 runs — 20 success, 11 skipped, 3 in_progress (Lint & Repo Gates, Type Check · workspace, Type Check · debt ledger), 0 failure. Second read 04:45:50Z: 34 runs — 22 success, 11 skipped, 1 in_progress, 0 failure; the one job not yet completed is Type Check · workspace. Completed success and load-bearing for this diff: Lint & Repo Gates (04:43:50Z — the job that runs check-adr-symbol-anchors, check:adr-anchors, check:doc-authoring, check-closing-keyword-parity, check:pm-prior-rulings), Check Documentation Links (check-adr-links), Check Changeset, Governed Surface Queue Guard, Part-of PR must not also close its card, The card this PR closes must claim this branch, No other open PR may claim the same issue / …the same single-writer path, Type Check · source gates / consumer gates / debt ledger, Test Core 1–6/6 and rollup, Dogfood Regression Gate. The 11 skipped are path-filtered (Build Core, Build Docs, Console Pin Gate, Temporal Conformance, dogfood shards, tarball smoke, duplicate Auto Label / Check PR Size / Check Changeset rows). No gate on the head contradicts the dev's 19-of-19 local reading.

① Derived judgments

Surface. The net diff against main is exactly one file, docs/adr/0005-metadata-customization-overlay.md (+71 / −7, blob 9db4cf53 → a893abb2). Nothing under packages/, no test, no pin, no scripts/adr-anchors/ entry. (The head's parent is c9c182ed; main has since moved to eead9dcf, and the two extra paths a two-dot diff shows are main's own, not the PR's.) Accept-set change: none. Public-surface change: none. Right.

Does the amended text say what the ruling orders? Ruling 甲 item 1 (iii), verbatim: 「the appendix says the persisted document is the parsed body once every round-trip key is declared, with a dated note pointing at the spec symbols」. The bullet at :337 now reads "The persisted document is the parsed body (parsed.data) once every round-trip key is declared", and the dated note under it names the spec symbols key by key. Card acceptance ("Appendix (c) says the persisted document is the parsed body. It carries a dated note naming the stage (ii) spec symbols that declare each round-trip key"; "⛔ No change to persistence code or to the GUARD pins") is met on the file list. Right.

Does it claim the runtime already does what it does not? No. The bullet ends "⚠️ Ruled, not yet in force: … today saveMetaItem still stores the request body (request.item)"; note item 5 says so again ("'declared' does not yet mean 'the only keys stored'"); the status-line entry says "the storage switch itself is the ruling's last stage, not yet landed". Verified at the head: packages/metadata-protocol/src/protocol.ts saveMetaItem (decl :15871) still safeParses, then re-assigns request.item = graftNormalizedOperators(graftFoldedFormSections(request.item, parsed.data), parsed.data) and persists request.item; the verbatim-save pins are green on main. The hedge is the one thing that keeps the amendment truthful today, and it copies the in-place form ADR-0053 used on 2026-09-30 (docs/adr/0053-…:751 "Amended (2026-09-30) — … Provenance: … Why: …", numbered items, item 9 "Interim state"). Right.

Every factual statement in the amendment, checked at the head's base:

  • Status line: heading "Addendum — 2026-05-16 (c): spec validation on overlay save" exists (:312); code cites it as "ADR-0005 appendix (c)" (view.zod.ts:5188, :6214, view-console-round-trip-keys.test.ts:10). Right. The line already carries every earlier decision-changing amendment (2026-05-22, 2026-04-13, 2026-08-09, 2026-09-04); appending this one is what PD [WIP] Add Chinese version of the documentation #13 asks for a reversed decision ("an amended status line on the old one"). Right.
  • Note header: ruling 甲, maintainer 「开始总监决裁」, 2026-09-27, batch 🔗 Broken links detected in documentation #227 item 2, comment 5856781584 — all match the ruling comment (created 2026-09-27T14:36Z). "keeps the persistence half of ruling A (comment 5824043998, item 2) as the end state" and the quoted 「a saved view is the parsed body, every key the console reads back is declared on the contract, and ADR-0005 appendix (c) is amended to say so」 are the ruling's own words. Right.
  • Item 1 (superseded text): the quotation equals the seven removed lines byte-for-byte modulo wrapping. Right.
  • Item 2: packages/spec/src/ui/view.zod.ts#VIEW_CONSOLE_ROUND_TRIP_KEYS is at :6242, #VIEW_METADATA_MEMBERS at :6193; packages/spec/src/ui/view-console-round-trip-keys.test.ts exists and asserts exactly what the note says — record equals the census (:98), each (key, member) pair "is a declared, described member" (:110) and "a parse … keeps it" through the member and through ViewMetadataSchema (:116); the docblock names the .objectui-sha pin (file present, dd3f7e1b). "A new round-trip key joins the record … in the change that adds the console write" restates the record's "⛔ Not a registry to grow by hand". Right.
  • Item 3 (key by key): c9c182ed is the head's parent and on main. viewItem → ViewItemWireSchema and listOverlay → VIEW_METADATA_MEMBERS.listOverlay per the record at :6193. isPinned / sortOrder / visibility: one declaration in viewSwitcherRowStateFields (:5199), spread by viewItemWireFields (:5236) into both ViewItemWireSchema arms and by listOverlayRoundTripFields (:6009) into ListViewOverlayWireSchema. isDefault: viewItemBaseShape (:4931, reached through viewItemArmShape) on viewItem; flattenedViewOverlayFields (:5486) on listOverlay. columnState: viewItemWireFields / flattenedViewOverlayFields. _isOverride: listOverlayRoundTripFields only, z.literal(true). All six match the record's branch lists. Right. One precision note, not a defect: "No form-overlay row carries these keys: the switcher lists list-family views only" is true of console-written rows (the record's subject, and the reason given is the viewSwitcherRowStateFields docblock's own), but the form member does declare isDefault and columnState through flattenedViewOverlayFields('form'); a reader taking the sentence as a statement about declarations would over-read it. The note names the record as the authority, so the text stands; the Tier H reviewer may ask for "writes" in place of "carries".
  • Item 4: objectName → object, top-level id → name, bare-array exportOptions → object form, filter[].id / sort[].id → stripViewConsoleDecorations (:496) with VIEW_CONSOLE_ROW_DECORATIONS = ['id'] (:423), _draft / _diagnostics → METADATA_READ_DECORATIONS (packages/spec/src/kernel/metadata-read-decorations.ts:48) — each is what the record's docblock says, and the test's "what the census mapped to an existing spelling stays undeclared" block pins objectName and id. Right.
  • Item 5: #saveMetaItem stores the request body with the two grafts (above); packages/objectql/src/protocol-meta.test.ts:586 "preserves Studio-only auxiliary fields verbatim (not stripped)" exists; "the 2026-05-16 'unknown extras preserved' case listed below" is the ADR's own test paragraph at :419. Right.
  • Item 6: matches ruling item 1 (iv) (parsed body stored; GUARD pins flip; ViewItemWireSchema top-level options judged in the same step) and item 4 (count of stored views carrying undeclared top-level keys measured against production sys_metadata before landing); the closing 「stored and unread」 → 「200, then the user's pinned / sort / visibility state silently dropped」 is verbatim from the ruling. Right.

Anchors. The note's new path#Symbol anchors and bare #Symbol continuations resolve — Lint & Repo Gates (which runs check-adr-symbol-anchors and check:adr-anchors) is success on the head, and Check Documentation Links (check-adr-links) is success. The dev's one-off ablation (rename #listOverlayRoundTripFields → red, restore → blob a893abb2 again) is consistent with that; not re-run here. No scripts/adr-anchors/ file is owed: its README adds an anchor "when an ADR's decision is realized in code", which is stage (iv). Right.

No other doc echoes the superseded bullet (git grep for "original request.item" / "NOT parsed.data" across docs/ hits only this file). Nothing left inconsistent in the doc corpus.

② Semver level

Label skip-changeset; Check Changeset success. The diff publishes nothing from any released package (one file under docs/adr/**), which is exactly what AGENTS.md reserves that label for. Right. Clause-②: no on the PR body and on the claim — no authorable key, export or config field is added, widened or narrowed; the ruling's own changeset plan (item 4) places minor on stage (ii) and minor + BREAKING on stage (iv), none on stage (iii). Right.

③ Boundary flags

Dev report 5904124008 (os-dev-report, status: done, head: c8ee5833, premise_still_valid: true). open_questions: [] — nothing to answer there.

Deviations, each answered:

  1. Status line edited, outside the claim's literal bullet-plus-note surface. Accepted. PD [WIP] Add Chinese version of the documentation #13 makes an amended status line the record of a reversed decision; the file's convention agrees; it is the claimed file. Not a breach.
  2. Trailers per AGENTS.md rather than the harness reminder. Accepted. The commit ends with Claude-Session: https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg and the model-free Co-authored-by: Claude trailer; the PR body's footer is the session-URL form. That is the rule AGENTS.md states (model-free pair, pre-push refuses a model id). Correct.
  3. Report uses the plain first-line os-dev-report marker. Accepted — it is the marker this review reads, and AGENTS.md bars tag-shaped tokens in bodies.

Out-of-scope findings, each verified and answered (carrier: stage (iv) on #20051, which is pm:blocked with #20456 and #20457 on its Blocked-by: line, so the stage (iv) dev reads this PR through the sub-card — no separate card is owed; the seat may drop a one-line pointer on #20051 when it closes #20457):

  1. Verbatim-save pin population is wider than two. True at the head: protocol-meta.test.ts:586, protocol.graft-folded-form-sections.test.ts:222, protocol.graft-normalized-operators.test.ts:126 assert it by name, and protocol.runtime-authoring-gate.test.ts:879 depends on it. The graft-folded GUARD does write isPinned / isDefault / sortOrder onto a flatForm(…) body, and the protocol-meta pin does write objectName: 'lead' — both need re-judging, not flipping, once stage (iv) lands. Belongs to stage (iv); noted correctly, nothing to change here.
  2. Per-type scope of the switch. True: resolveOverlaySchema dispatches view and dashboard; the note's item 3 is explicitly scoped to view, and the bullet states the rule with its condition. Stage (iv)'s judgment; nothing to change here.
  3. Code cites "ADR-0005 §Validation", a heading the ADR lacks. True: 20-plus hits under packages/ (protocol.ts:367, :7289, :15876, :16396, registry.ts:2547, the pins, three objectql round-trip tests, CHANGELOGs). They describe today's behaviour, still true until stage (iv), which is where PD [WIP] Add Chinese version of the documentation #13 puts the code citation and the scripts/adr-anchors/ entry. Nothing to change here.

Tier H: docs/adr/** lands only on the maintainer's APPROVED review (PD #14); the PR is draft and awaiting that word, which this record does not stand in for and does not judge. Landing is the owning seat's after that review.

Implemented-by: claude/issue-20457-adr-0005-appendix-c-parsed-body
Reviewed-by: session_01KTZmMfzVzjNvyaLyQ8mHvg

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)— PR #20777 · ADR-0005 附录 (c) 修订(#20457,#20051 裁决甲第 iii 步)

skills 席 1 · session_01KTZmMfzVzjNvyaLyQ8mHvg · 2026-09-30T04:51Z · 所审 head c8ee5833

改了什么:只改 docs/adr/0005-metadata-customization-overlay.md 一个文件(+71 / −7)。

  • 附录 (c) 原文是「保存覆盖层时原样存请求体(request.item),不存解析结果」。现改为裁决甲的终态:往返键全部在契约上声明之后,存的是解析后的结果(parsed.data)。条目本身标明「已裁定、尚未生效」。
  • 条目下紧跟一段 2026-09-30 修订注记,共六项:① 原文逐字引用,标为已被取代;② 权威记录是 VIEW_CONSOLE_ROUND_TRIP_KEYS 及其闭合测试;③ 逐键列出声明它的 spec 符号(置顶、排序、可见性、默认视图、列状态、覆盖标记);④ 普查中其他发现映射到已有拼写(如 objectName → object);⑤ 现状:运行时仍原样存请求体;⑥ 第 (iv) 步要做的事。
  • 状态行追加一条「Amended (2026-09-30)」。

为什么改:这是裁决甲(#20051,「开始总监决裁」)的第 (iii) 步。第 (ii) 步(#20456 / PR #20474)已把控制台会写回、再读回的键全部声明进 spec,附录 (c) 可以照实改写。

风险与代价(含回滚):纯文档,不动代码、测试或任何发布包(skip-changeset)。唯一的风险是读者误以为运行时已按新规则存储。条目、注记第 ⑤ 项和状态行三处都写明存储切换是第 (iv) 步、尚未落地,席位已在 main 上核实确实仍原样存储。回滚:revert 这一个提交。

席位意见:ACCEPT,建议批准。

  • 契约复核 PASS(评论 5904271563,由隔离的达档子代理出具,席位核验后采纳)。复核逐条核对了注记中的全部事实陈述:10 个 spec 符号均可解析、逐键映射与构造函数一致、saveMetaItem 现状属实。
  • CI 全绿:24 success + 11 按路径跳过,0 失败。
  • 一处可选措辞:注记第 ③ 项「No form-overlay row carries these keys」,对控制台写入的行成立;但 form 成员在声明层面确实声明了 isDefault / columnState,把 carries 改成 writes 更严谨。不影响批准,如需修改请留言,席位派补丁轮。
  • dev 另记三条观察,都交给第 (iv) 步:需重判的 GUARD pin 比裁决点名的更多;切换是否也覆盖 dashboard 等类型;代码里仍以「ADR-0005 §Validation」引用本条。已写入 PR 的 Acceptance notes,并在 spec(ui)+metadata save: judge a flattened view overlay's top-level options.KIND with the strict per-kind schema and persist the PARSED body — the door half of objectui#10380 #20051 留了指针。

你要做的:在本 PR 上给 APPROVED。批准后由本席位过落地前检,翻 ready 并入队。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs(adr): ADR-0005 appendix (c): the persisted document is the parsed body once every round-trip key is declared (#20051 stage iii, ruling 甲)

3 participants