Skip to content

§06 F14 says an archived contract stays editable 「除 notes 外」, but clm_contract has no notes field — §03 gives it summary #44

Description

@zhuangjianguo

Documentation drift, found while browser-verifying card 09 (#39 / PR #42, merged as a7b7db5). The implementation is not wrong; the sentence is. ⛔ Not a decision card — there is nothing to choose.

The mismatch

DESIGN.md §06 F14 says that after archiving, a contract is 「此后除 notes 外只读」 — read-only except notes.

DESIGN.md §03 gives clm_contract a summary field and puts notes on the child objects (clm_contract_version.notes, clm_obligation.notes, clm_signature.notes). There is no notes on the contract, and there never was.

What the implementation did, and why it is right

contract.hook.ts's F14 freeze keeps summary open (plus the platform's updated_at / updated_by, which ride along on every write). That is the only reading that leaves an archived record annotatable at all — the alternative, taking §06 literally, would freeze the contract completely, because the field it names to keep open does not exist.

Measured on the merged branch: archive_no on an active contract → 422 naming the status; on a terminated one → 200 with archived_at stamped; then editing summary → 200, editing title → 422 Fields refused: title`.

Fix

One word in §06 F14: 「除 notes 外只读」 → 「除 summary 外只读」.

⚠️ §06 is not a governed surface (AGENTS.md governs DESIGN.md §01–§04 only), so a §06-only edit self-merges on the normal path. ⛔ Do not fold it into a PR that also touches §01–§04, or it inherits the human-merge path for one word.

⛔ Also do not fold this into PR #40 (chain head #6): that PR is already reviewed, ACCEPTed and awaiting the maintainer's merge. Adding a commit would invalidate a review that is already on the record.

Related

#39 / PR #42 (found here) · src/objects/contract.hook.ts F14 · DESIGN.md §03 field list, §06 F14

Activity

  1. zhuangjianguo commented on Sep 10, 2026

    @zhuangjianguo
    CollaboratorAuthor

    Claim: session session_01R3n3GGzobdegM4HUzah1iR · branch claude/issue-44-design-summary-not-notes

    PM dispatch. The assignee and this claim are set by the PM seat on behalf of the dev that will work this card; the dev inherits both, checks that this is the newest Claim: on the thread and that it names its branch, and ⛔ posts no second claim and never writes the assignee field.

    Unblocked. PR #40 merged at 10:48Z as 296fab8 — the maintainer's merge, on the governed path, exactly as AGENTS.md requires. DESIGN.md is unheld. Branch off current origin/main (296fab8).

    ⚠️ Re-read §06 F14 on 296fab8 before editing. PR #40 just changed DESIGN.md §02, §03, §06 and §09 — including a §06 edit (F9 lost its intake-payment clause). Your target sentence is a different F, but the file moved under this card and the card was written against the pre-#40 text. Confirm 「此后除 notes 外只读」 is still there, verbatim, and confirm §03 still gives clm_contract a summary and no notes. If either moved, stop and say so.

    Dispatch notes on top of the card body:

    • One word. 「除 notes 外只读」 → 「除 summary 外只读」. ⛔ Nothing else in §06, ⛔ nothing in any other section.
    • §06 is outside the governed range (AGENTS.md governs DESIGN.md §01–§04), so this merges on the normal path. ⛔ Do not touch §01–§04 — a single character there converts this one-word fix into a human-merge PR.
    • Two more DESIGN.md cards are queued behind you — docs: the position census disagrees with itself in three places — README says seven over a table of six, DESIGN.md §11 says both 7 and 8 #58 (§11) and DESIGN.md §09 still specifies 各阶段合同数**漏斗** — the app stopped shipping a funnel in #48 and narrowed what it plots in #59 #63 (§09). They are NOT dispatched and will not be until yours merges. ⛔ Do not fold either in, and ⛔ do not "while I'm here" any other §06 sentence.
    • Gates all four, exit codes captured before any pipe. None of them reads DESIGN.md (tsconfig includes only objectstack.config.ts and src/**/*; validate/lint walk the metadata graph) — say that plainly rather than implying they verified the change. No changeset (this repo has no changeset gate — do not add one). No browser run: the diff changes no runnable surface.
    • The evidence this card wants is not a gate run. It is the reading that summary is the field F14's freeze actually leaves open. The card cites contract.hook.ts and a measured 422 Fields refused: title / 200 on summary; confirm that against the tree you branch from rather than inheriting it, and put the reading in the PR body.

    Generated by Claude Code

  2. zhuangjianguo commented on Sep 10, 2026

    @zhuangjianguo
    CollaboratorAuthor

    ACCEPT — PR #68

    CI green on head 1187094b (two Validate runs, both success), base is current main (296fab8), diff is DESIGN.md line 239, +1/−1, and §06 is outside the governed range (AGENTS.md governs §01–§04). First round. Squash-merging.

    The premise re-check earned its place

    I asked for it because PR #40 had merged minutes earlier and moved §02/§03/§06/§09. You re-read both premises on 296fab8 and reported something the card got slightly wrong:

    The file spells it 「此后除 notes 外只读」 — notes in backticks; the card quoted it with the code formatting dropped.

    That is the right level of care for an exact-match edit. A card that quotes a target string without its formatting is one sed away from a no-op that reports success.

    The reading, not the gates

    This card's whole content is a claim about which field the freeze leaves open, and you answered it from the source rather than from the card's inherited measurements:

    OPEN_AFTER_ARCHIVE = ['summary', 'id', 'organization_id',
                          'created_at', 'created_by', 'updated_at', 'updated_by']
    

    with the observation that makes it decisive — summary is the only caller-authorable name in that list; the other six are the id, the tenant column and the engine's audit columns that ride along on every write. From which the card's "taking §06 literally would freeze the contract completely" stops being rhetoric: the allow-list is keyed by field name, a notes entry matches nothing on clm_contract, and the remainder is zero writable fields.

    Turning "say it plainly" into a measurement

    The dispatch told you to state that no gate reads DESIGN.md rather than implying the gates verified this. You did — and then you proved it:

    Mechanically: grep -il DESIGN across all four gate logs → no match.

    That is better than the instruction. The tsconfig-include argument establishes it should be true; the grep establishes it is true of the four logs actually attached to this PR. On a repository where three of this session's ten merges touched files no gate can see, having the negative demonstrated rather than argued is worth the two seconds it cost.

    The stale comment — your call ratified, and recorded so it is not lost

    src/objects/contract.hook.ts quotes the pre-fix sentence verbatim as the premise for its allow-list, and after this merges that quote reads as history. You left it alone and said why. Agreed, and it is not being filed — recording the reasoning here rather than in a card so the decision is on GitHub either way:

    The comment is not false. It accurately records what §06 said when the hook was written, why the implementation diverged, and its closing line — "Reported as a §06/§03 wording mismatch rather than resolved by adding a field: §03 is a governed surface" — is a report that this PR closes out. Deleting a correct historical note would be churn, and touching src/ to do it would widen a one-word §06 diff into the gated surface. It is a free rider for whoever next opens that file for a real reason; neither #58 nor #63 does.

    Queue

    #58 (§11) dispatched next, alone. #63 (§09) after it. ⛔ Still one DESIGN.md card at a time.


    Generated by Claude Code

  3. zhuangjianguo commented on Sep 10, 2026

    @zhuangjianguo
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 44,
      "status": "done",
      "branch": "claude/issue-44-design-summary-not-notes",
      "pr": "https://github.com/objectstack-ai/hotclm/pull/68",
      "premise_still_valid": true,
      "summary": "One word in DESIGN.md §06 F14: 「此后除 `notes` 外只读」 → 「此后除 `summary` 外只读」, at DESIGN.md:239. Whole diff is 1 file, 1 insertion, 1 deletion; §01–§04 untouched, no other §06 sentence touched, neither queued DESIGN.md card (#58, #63) folded in. Both premises were re-read on 296fab8 after PR #40 moved §02/§03/§06/§09 and both hold: the F14 sentence is present and unmoved (the file spells `notes` in backticks; the card quoted it with the code formatting dropped — same sentence), and §03 still gives clm_contract `summary` with zero `notes`. The assignee was already set and the newest Claim: comment already names this session and branch, so I inherited both and posted no second claim and never wrote the assignee.",
      "tests": "GATES (all four run in the dedicated worktree, each redirected to its own file with $? read on the very next statement — no pipe between command and exit code): pnpm validate=0 ('✓ Validation passed (2275ms)'), pnpm lint=0 ('21 warning(s), 5 suggestion(s) (1367ms)'), pnpm typecheck=0 (tsc --noEmit, no diagnostics), pnpm lint:i18n-gate=0 ('✓ i18n gate' · 'COVERAGE : 0 missing keys across 2 locale(s)'). NOT EVIDENCE FOR THIS CHANGE, stated plainly: none of the four reads DESIGN.md — tsconfig.json include is [\"objectstack.config.ts\",\"src/**/*\"] so the file is not in the typecheck program, validate/lint walk the compiled metadata graph from objectstack.config.ts, and `grep -il DESIGN` across all four gate logs returns no match. They are recorded only because AGENTS.md requires them green before a PR opens, and they show the branch did not disturb the metadata graph. The validate/lint warnings are pre-existing on 296fab8 (carrier-only field notices, one approval-routing suggestion), none on clm_contract.summary or the archive path. THE ACTUAL EVIDENCE is the reading, confirmed against 296fab8 rather than inherited from the card, and tabulated in the PR body: contract.object.ts:366 declares `summary: Field.richtext(…)` and grep -c notes on that file returns 0; contract.hook.ts hook `contract_archive` has OPEN_AFTER_ARCHIVE = ['summary','id','organization_id','created_at','created_by','updated_at','updated_by'], in which `summary` is the only caller-authorable name (the other six are the id, the tenant column and the engine audit columns that ride along on every write); the gainsArchiveNo && !terminal branch throws refuse(…, 'INVALID_STATE', 422) interpolating the status, which is the card's 422 on an `active` contract; the terminal side sets input.archived_at = new Date().toISOString(), which is the 200 with archived_at stamped; `summary` in the allow-list leaves `attempted` empty, which is the 200 on a summary edit; `title` absent from it lands in `attempted` and yields exactly 'Fields refused: title', which is the card's 422. Rows 4-7 are readings of the code path that produces each measured response, not a fresh HTTP re-measurement — no browser run is owed since the diff changes no runnable surface. ON-DISK PROOF of the edit itself (the docs-only analogue of an ablation; no ablation or reverse-verification applies because no code changed and nothing new can fail): before the sed, old-spelling count = 1 and new-spelling count = 0; after, old = 0 and new = 1; git diff shows exactly the one line at DESIGN.md:239. Control-character self-scan on the edited file and on the PR body: grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' → no match on either. NO CHANGESET: this repo has no changeset gate and no .changeset/ convention; release notes are written centrally at release time. NO VERIFY LOCK: scripts/pm/os-verify-lock.sh does not exist in hotclm (it is an objectstack-repo mechanism), so the gates were run directly.",
      "mcp_calls": "5 — issue_read get, issue_read get_comments, create_pull_request, pull_request_read get, add_issue_comment (this report). No search call was needed: the card names its own target and no duplicate check was owed, since nothing was filed.",
      "open_questions": [],
      "out_of_scope_findings": [
        "noted, not filed: src/objects/contract.hook.ts quotes the pre-fix §06 sentence verbatim in a comment (「\"此后除 notes 外只读\" (§06 F14)」) as the premise for its allow-list; once this merges the quote reads as history rather than as the current text. Stale phrasing, not a defect — no runtime behaviour, gate or contract depends on it, and the reasoning it records is exactly what this PR codifies. Left alone deliberately: the card is one word in §06 and touching src/ would widen a docs diff into the gated surface for a comment. Successor: none — the two DESIGN.md cards queued behind this one (#58 on §11, #63 on §09) do not touch contract.hook.ts.",
        "noted, not filed: the MCP create_pull_request path appended its own '_Generated by [Claude Code](https://claude.ai/code/session_…)_' footer after the one already in the body I sent, so PR #68 carries two attribution footers. Left as-is rather than looped on — editing the body to drop one risks the same append again. Platform/tooling behaviour, reported not patched."
      ]
    }

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions