Skip to content

The contract page's new-version form defaults "Current" off, and two versions of one contract can both be current #96

Closed

Description

@objectstack-fleet

Ruled: 6395827965 · letter 1A 2A · 2026-10-25T09:14Z

Unblocked: the 17.7.0 → 18.1.0 upgrade landed as PR #110 (7b736a0).

Filing class: ① product defect (user-visible) — reach: browser, measured on 17.7.0. Reader: the repo:hotclm seat, dispatch from pm:queue.

Source: the #87 full browser pass on 17.7.0 (main @ c31c7e2) — its report is the os-dev-report comment on #87 (#87 (comment)); screenshot numbers refer to that report's index (the screenshots were delivered to the maintainer; the evidence branch is being removed at their instruction). Finding 16; screenshots 079–085.

Symptom

  • The version form on the contract page defaults is_current to off, so a clean version saved as offered (079, 082) does not satisfy the signing guard ("A current clean version is required before signing.").
  • After ticking it, versions 1 (draft) and 3 (clean) were both is_current: true: nothing keeps "current" exclusive per contract.

Expected (verify against DESIGN.md §03 clm_contract_version)

A new version is current by default when it is the newest, and marking one current un-marks the others (in a hook, so every door obeys it). If §03 does not pin which, stop with needs_decision.

Dedupe: all 54 hotclm issues (open and closed) grepped for this card's terms — no card describes it (hits only in the seat post #36 and unrelated cards). (terms: is_current)


Filed by the repo:hotclm PM seat from the #87 browser pass.

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 8
    Session: session_01HihZ11bQSqjCgjzHbpv4M1
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-96-current-version
    Worktree: hotclm-issue-96
    Domain: repo:hotclm (single-lane sister repo — no domain:*)
    Seat: repo:hotclm#1
    File surface: src/objects/contract-version.object.ts · a new src/objects/contract-version.hook.ts (and its registration in src/objects/index.ts) · src/pages/contract_detail.page.ts (the version form's default, if that is where it lives) · src/translations/** (only for a new message) — ⛔ not src/objects/contract.hook.ts (held by PR #91) — stop on breach; explain in the report
    Container & model: S, mode:subagent, model: opus (TIER_DEFAULT; hand-derived for a sister repo)
    Clause-②: no
    Responsibility: this app's version object and its hooks | none | legal and records adding versions on every contract page
    Thread-read: none
    Serial constraints cleared: PR #91 holds contract.hook.ts · contract-intake.flow.ts · contract-lifecycle.actions.ts; #93 holds contract-approval.flow.ts · README.md · scripts/demo.mjs; #97 holds the renewal / expiry flows — all outside this surface
    Read at: 2026-10-10T04:04Z


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 96,
      "status": "needs_decision",
      "branch": "claude/issue-96-current-version",
      "pr": null,
      "session": "session_01HihZ11bQSqjCgjzHbpv4M1",
      "premise_still_valid": true,
      "tree": "46e65f0",
      "platform": "@objectstack/* 17.7.0 (pnpm-lock unchanged since the #87 measurement tree c31c7e2)",
      "summary": "Stopped before code, as Zone 1 and the card both rule: DESIGN.md section 03 does not pin either half. The clm_contract_version row lists only `is_current boolean`, and the approved → signing guard reads 「存在 `kind: clean` 的当前版本」. That says nothing about how many versions may be current, and nothing about a default. The governed proposal docs/design/00 section 5.5 doesn't even require 'current': its guard is 「送签必须存在一份清稿」 / 「存在清稿版本」. The premise holds on origin/main 46e65f0 and the default is app metadata, not a Console defect. Two questions with options and a recommendation are below. No PR, no files changed, nothing filed.",
      "premise_evidence": [
        "Form default = app metadata: src/objects/contract-version.object.ts:83-88 declares `is_current: Field.boolean({ defaultValue: false })`. The page's Versions tab (src/pages/contract_detail.page.ts:265-274) is a bare record:related_list with no form defaults, so the platform form shows exactly what the object declares. This is not a Console defect, and there is no platform cause to report.",
        "Exclusivity is not enforced anywhere: the only hook on clm_contract_version is `contract_version_display_name` (src/objects/mirror.hook.ts, it stamps display_name only). src/objects/hooks.ts registers contract.hook + mirror.hook and nothing else. `grep -rn is_current src` finds no writer that un-marks siblings.",
        "#87 measurement reapplies byte-for-byte: `git diff --stat c31c7e2 origin/main` = src/profiles/requester.profile.ts only (#88, sys_comment grants). The version object, page, hooks, flows and pnpm-lock are identical to the tree the #87 browser pass measured (finding 16, screenshots 079-085).",
        "Flows' deliberate writes: contract-intake.flow.ts:375/395/410 write v1 `is_current: true` (the only version). executed-upload.flow.ts:268 (F16 backfill) writes v1 final_signed `is_current: true` (the only version). signature-record.flow.ts:308-314 (F7) writes final_signed `is_current: false` on purpose: 'the negotiation flag is what approved → signing reads … DESIGN.md section 03 keeps signing → approved open for a failed signing round — moving the flag onto the executed copy would make that rollback unre-enterable.'",
        "Caller rights for an un-marking write: clm_requester and clm_records hold create without edit on versions (src/profiles/requester.profile.ts:70, records.profile.ts:35). clm_legal holds edit (legal.profile.ts:56). An exclusivity rule must therefore un-mark siblings as a system write. In-repo precedent: `deviation_gate` (contract.hook.ts:819-846) runs afterUpdate with `runAs: 'system'` and writes the parent from outside its hook chain.",
        "Downstream reader that needs one answer: docs/backlog/12-esign-and-crm-handoff.md:13 has F8 post 'the current `clean` version' to the e-sign provider, i.e. one document."
      ],
      "tests": "No code was written, so no tests ran. Premise verification commands: `git rev-parse origin/main` → 46e65f0a66e4; `git diff --stat c31c7e2 origin/main` → '1 file changed, 29 insertions(+)' (src/profiles/requester.profile.ts); `grep -rn is_current src --include=*.ts` (12 hits: 10 in objects/flows/page, 2 in the en and zh-CN bundles). The browser re-run on 46e65f0 is NOT MEASURED, reason: the result is a decision, and the #87 browser measurement's inputs are byte-identical on this tree (see premise_evidence).",
      "gates": {
        "pnpm verify": "NOT RUN, reason: no diff (needs_decision, files_changed empty); a gate run here would measure origin/main, not a change"
      },
      "line_budget": "n/a",
      "files_changed": [],
      "deviations": [
        "Skipped `pnpm install` in worktree hotclm-issue-96: the stop came before any code, and nothing in the stop needs node_modules. The worktree was removed clean after this report.",
        "The branch claude/issue-96-current-version was pushed empty (equal to origin/main 46e65f0) as the claim's landing marker and is left on the remote for the seat to keep or delete."
      ],
      "mcp_calls": "0",
      "api_writes": "1: this report comment on objectstack-ai/hotclm#96, posted through scripts/pm/post-stamped.mjs (fleet relay). The branch push is git, not REST. Reads: GET issues/96, GET issues/96/comments, GET issues/comments/6092819369 (the #87 report).",
      "open_questions": [
        {
          "question": "Q1: Is 'current' exclusive per contract? (section 03 lists `is_current boolean` and nothing more)",
          "options": [
            "A: At most one current version per contract, enforced by a new src/objects/contract-version.hook.ts (afterInsert/afterUpdate, `runAs: 'system'`): when a row becomes current, every other current row on the same contract is un-marked. This binds every door: form, REST, flows, MCP. Business need: the field's own help text reads 'the version negotiation is currently on' / 「谈判当前所在的版本」, which is singular. F8 has to send ONE clean file to the e-sign provider. The #87 state (draft v1 + clean v3 both current) leaves 'which file gets signed' unanswered. Long-term: one invariant in one hook, and F8 reads 'the' current version without inventing a tie-break. AI-error: an agent adding a version through MCP/REST cannot leave two currents behind, and it does not need to know to un-tick the old one. Startup-focus: one hook file plus one line in hooks.ts, with no schema change and no seed change (no versions are seeded, src/data/index.ts:33). Cost: the un-marking must be a system write, because requester and records cannot edit versions (see precedent `deviation_gate`). Section 03 needs one sentence, a governed edit that is yours to make.",
            "B: Not exclusive. 'Current' is a per-version tag, and the guard keeps reading 'any current clean version'. No code, and the #87 state becomes legal by definition. Business need: the Versions timeline shows several 'Current' rows. Long-term: F8 (card 12) needs its own choosing rule, so the cost moves to card 12. AI-error: high, because nothing tells a writer the flag means anything. Startup-focus: cheapest today.",
            "C: Retire `is_current`. 'Current' becomes the highest-numbered version that is not final_signed, and the guard becomes 'the newest negotiation version is clean'. No flag to get wrong, and it matches docs/design/00 section 5.5's guard (「存在清稿版本」, no 'current'). Cost: a section 03 field removal, rewriting the intake/F16/F7 writes, the page column and both translation bundles. It also loses the ability to sign an earlier clean copy after a later counterparty redline is rejected (legal would re-upload it as a new version)."
          ],
          "recommendation": "A. Business need: one version is what the field already says it means, and what F8 needs to send. Long-term: a single hook makes every door obey the rule, where B pushes the ambiguity onto card 12 and C removes a capability. AI-error: A is the only option where a writer that knows nothing about the flag still leaves a coherent contract. Startup-focus: A is a ~40-line hook with no schema or seed change, against C's multi-file removal. Proposed section 03 wording for the clm_contract_version row: 「is_current boolean(每份合同至多一个当前版本:标记一个即取消其余,hook 强制,各入口一致)」."
        },
        {
          "question": "Q2: Does a new version default to current? (section 03 is silent; today the field declares `defaultValue: false`, and the #87 pass hit exactly that)",
          "options": [
            "A: Yes for every negotiation kind (draft, internal_redline, counterparty_redline, clean); `final_signed` never takes the flag from a negotiation version. Mechanism for the implementer: field `defaultValue: true`, so the form offers it ticked and a write that omits the key stores true. In the Q1 hook, a final_signed row keeps `is_current: true` only when it is the contract's only version (F16's backfill case), and is otherwise stored false. F7's explicit false, intake's true and F16's true all keep their meaning, and signing → approved stays re-enterable. Business need: legal saves a clean version as offered and Start Signing passes, which is the #87 path. Long-term: the newest negotiation round is what the contract is on. AI-error: low, because the writer does nothing special. Startup-focus: a one-line field change plus a few lines in the same hook.",
            "B: Yes for every kind (`defaultValue: true` only, no kind rule). Simplest. The cost: an executed copy added through the version form (records hold create on versions, 「执行副本」) would take the flag off the clean version under Q1-A. That is exactly what F7's comment protects against: after a failed signing round is rolled back to approved, signing could not be re-entered until someone re-ticks the clean version.",
            "C: No, keep `defaultValue: false` and legal ticks it. The #87 symptom stays: a clean version saved as offered does not satisfy the guard. It can only be softened by rewording the refusal ('mark the clean version current'). Cheapest, but the trap stays."
          ],
          "recommendation": "A. Business need: it removes the #87 dead end (save as offered → guard refuses) without asking legal to know about a flag. Long-term: it keeps F7's deliberate design, where the executed copy never displaces the negotiation version, and B breaks that. AI-error: a default that is right for every negotiation write means an agent that omits the key still gets the correct state. Startup-focus: it lives in the same hook file as Q1-A, plus one field line. If section 03 takes the wording, append to the Q1 sentence: 「新的谈判版本默认为当前;final_signed 不夺取当前标记」."
        }
      ],
      "out_of_scope_findings": [
        "carrier: the maintainer, through this decision · noted, not filed. DESIGN.md section 03's approved → signing guard reads 「存在 `kind: clean` 的当前版本」, while the governed proposal docs/design/00-设计方案.md section 5.5 / its state table reads 「送签必须存在一份清稿」 / 「存在清稿版本」 (no 'current'). Q1-C would align the two; A and B leave docs/design/00 as the looser statement. A governed-document wording drift, outside classes a/b/c. Dedupe words: is_current, 当前版本, clean version guard"
      ],
      "platform_causes": "none: the form's 'Current off' default is the app's own `defaultValue: false`, and the Console honours it. Nothing filed, per the lane ruling."
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    决策:「当前版本」是否每份合同唯一?新版本是否默认为当前? · 2026-10-10T04:13Z

    Governing text: DESIGN.md §03(clm_contract_version 行只写 is_current boolean;状态机 approved → signing 守卫「存在 kind: clean 的当前版本」)· §06 F7(签署记录把执行副本写为 is_current: false,以保留签署失败回退后可再次进入签署)· docs/backlog/12(F8 要把「当前 clean 版本」这一份文件发给电子签服务商)

    维护者速读

    事情:浏览器测试(#87)里,法务在合同页按默认值存了一份清稿,「发起签署」仍被守卫拒绝——因为版本表单把「当前」默认关闭(这是应用自己的 defaultValue: false,不是平台问题);勾上之后,同一合同的草稿 v1 与清稿 v3 同时是「当前」,没有任何规则保证唯一。dev 读完 §03 后停下:§03 两件都没规定,这是你的产品语义(且 §03 属受管文本)。

    你要做的:回两个字母,如「1A 2A」。

    问题 1:「当前」是否每份合同至多一个?

    做法 代价 / 收益
    1A(推荐) 至多一个:新增版本对象的 hook,标记一个即以系统身份取消其余,所有入口(表单 / REST / 流程 / MCP)一致 与字段帮助文字「谈判当前所在的版本」一致;F8 只发一份文件无需另立规则;约 40 行 hook,无 schema / 种子改动;§03 需加一句(受管,由你写)
    1B 不唯一:「当前」只是每个版本的标签 今天零成本;但「到底签哪一份」推给卡 12 解决
    1C 取消 is_current:当前 = 编号最大的非执行副本版本 没有可写错的标记;但要删 §03 字段、改三个流程与页面与两套翻译,并失去「回签较早清稿」的能力

    问题 2:新版本是否默认为当前?

    做法 代价 / 收益
    2A(推荐) 谈判类版本(草稿 / 内部修订 / 对方修订 / 清稿)默认当前;执行副本(final_signed)不夺取当前标记(唯一版本时除外,即补录场景) 法务按默认保存即可发起签署(#87 的死路消失);保留 F7 的刻意设计
    2B 所有版本一律默认当前 最简单;但档案岗新增执行副本会把标记从清稿上拿走,签署失败回退后无法再次进入签署——正是 F7 注释所防的
    2C 保持默认关闭,由法务手动勾选 零改动;#87 的陷阱继续存在

    若选 1A + 2A,dev 建议的 §03 措辞:「is_current boolean(每份合同至多一个当前版本:标记一个即取消其余,hook 强制,各入口一致;新的谈判版本默认为当前;final_signed 不夺取当前标记)」。

    四棱分析

    • 实际业务需求:真实且已测——Full browser test on 17.7.0 main: drive the whole contract lifecycle as every audience, in en and zh-CN, and report what a real user hits #87 中按默认保存的清稿过不了签署守卫;F8(卡 12)必须知道发哪一份。
    • 项目长远合理性:1A 把不变量放在一个 hook 里、所有入口遵守;1B 把歧义推给后续卡;1C 删能力。
    • 防 AI 写错:1A + 2A 下,一个对这个标记一无所知的写入者(agent 经 MCP / REST 添加版本)也会留下一致的合同;1B / 2C 依赖写入者「知道要去勾」。
    • 创业阶段不扩散:1A + 2A 是一个 hook 文件加一行字段默认值,无 schema、无种子改动。

    另记(不需裁):docs/design/00 的守卫写的是「存在清稿版本」(无「当前」),与 §03 措辞有出入——属受管文档措辞漂移,随本决策一并由你定稿即可。


    Generated by Claude Code

  4. zhuangjianguo commented on Oct 25, 2026

    @zhuangjianguo
    Collaborator

    Ruling: batch #2 item 4 · letter 1A 2A · maintainer 「同意」 2026-10-25T09:14:04Z

    裁定:1A 2A —— 每份合同至多一个当前版本(hook 强制);新谈判版本默认为当前,执行副本不夺取标记

    维护者在第 2 批决策箱回了「同意」(= 推荐项 1A + 2A,与席位评论 6093651767 的推荐一致)。裁决文档:https://claude.ai/artifact/X4sZxhLrEYshLjkgYp4svr 。

    鲜度门:正文 2026-10-10T03:30Z;评论三条,最后一条 2026-10-10T04:13Z。main e4997a8 复测:contract-version.object.ts:83 仍是 defaultValue: false;hooks.ts 只注册 contract 与 mirror 两个 hook,没有任何写入者取消兄弟版本的标记;F7 刻意写 is_current: false。录裁前重读,无变化。

    裁后执行(给 lane 席位)

    1. §03(受管面) clm_contract_version 行加:「is_current boolean(每份合同至多一个当前版本:标记一个即取消其余,hook 强制,各入口一致;新的谈判版本默认为当前;final_signed 不夺取当前标记)」。同一次受管编辑顺手对齐 docs/design/00 §5.5 的守卫措辞(今天写的是「存在清稿版本」,没有「当前」)。随设计文档 PR,Refs #96。
    2. 代码(按 os-dev-report 6093639240 的方案):新增 src/objects/contract-version.hook.ts 并在 hooks.ts 注册 —— afterInsert / afterUpdate,runAs: 'system'(发起人与档案岗对版本只有 create 没有 edit,取消兄弟标记必须是系统写,先例 deviation_gate):一行成为当前即取消同合同其余行;final_signed 行仅在它是该合同唯一版本时保留 is_current: true(F16 补录),否则存 false。字段 defaultValue: true。intake 的 true、F16 的 true、F7 的显式 false 含义不变,signing → approved 回退后仍可再次进入签署。
    3. 纯应用语义,不涉平台;可在 18.1 升级 PR 之后直接派发。⛔ 不碰 contract.hook.ts(若仍被其他 PR 持有)。

    ⛔ 本席不动标签;lane 席位派发时转标签并带 Ruling-ref:。


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Out of the decision box — Ruling-ref: comment 6395827965 (batch #2 · maintainer 「同意」).

    • State: needs-user-decision → pm:blocked, Blocked-by: the 18.1 upgrade PR, as the ruling prescribes.
    • Then one card: src/objects/contract-version.hook.ts (afterInsert/afterUpdate, runAs: 'system', one current version per contract; final_signed keeps the flag only when it is the only version) registered in hooks.ts, and is_current defaultValue: true. The §03 / docs/design/00 §5.5 wording goes with the design-document PR (Refs #96).

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Unblocked: PR #110 (the 18.1 upgrade) merged as 7b736a0. State pm:blocked → pm:queue; dispatch follows its ruling.


    Generated by Claude Code

  7. 5 remaining items

  8. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 14
    Session: session_017nzWFRUo2U7evMkPdVniAn
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-96-one-current-version
    Worktree: hotclm-issue-96
    Domain: repo:hotclm (single-lane sister repo — no domain:*)
    Seat: repo:hotclm#1
    File surface: src/objects/contract-version.hook.ts (new) · src/objects/hooks.ts (register it) · src/objects/contract-version.object.ts (is_current default) — stop on breach; explain in the report
    Container & model: S, mode:subagent, model: opus (TIER_DEFAULT; hand-derived for a sister repo), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: this app's clm_contract_version (no writer keeps is_current exclusive; the field defaults off) | none known | every requester who saves a clean version and then cannot sign
    Ruling-ref: 6395827965 (batch #2 item 4 · letters 1A 2A)
    Premise: re-measured by the dev on origin/main 7b736a0 (18.1.0)
    Serial constraints cleared: PR #110 merged 7b736a0. ⛔ contract.hook.ts not touched. Scope of this branch: ruling step 2 (code), Part of #96. Step 1 (the DESIGN.md §03 line and docs/design/00 §5.5 wording) is governed surface — it goes to the maintainer as a separate design-doc PR with Refs #96.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 96,
      "status": "done",
      "branch": "claude/issue-96-one-current-version",
      "pr": "https://github.com/objectstack-ai/hotclm/pull/112",
      "session": "session_017nzWFRUo2U7evMkPdVniAn",
      "premise_still_valid": true,
      "summary": "Ruling 6395827965 step 2 (code) is done, opened as draft PR #112 (`Part of #96`, with no closing keyword; step 1 is the maintainer's governed edit). There is a new `src/objects/contract-version.hook.ts` (`contract_version_current`, afterInsert/afterUpdate, runAs system), registered in `hooks.ts`. It re-reads the committed row and does nothing unless that row is current. A non-final_signed current row un-marks every other current version of the same contract. A final_signed row keeps the flag only while it is the contract's only version and is otherwise stored false, leaving its siblings alone. `is_current` now has `defaultValue: true`. The premise was re-measured on main 7b736a0: a version POSTed without the key was stored false, the signing guard refused with 422, and two versions of one contract could both be current. `contract.hook.ts` was not touched. Translations were not touched because no new string was needed.",
      "tests": "No test suite in this repo; proof is measured on real `pnpm demo` boots with a clean .objectstack/data each. Branch 8b3c6f0 on :3096; main 7b736a0 on :3098 as the before picture. Before (main): POST v1 clean with no key stored is_current=false; PATCH approved->signing gave 422 INVALID_STATE 'A current clean version is required before signing.'; v2 draft and v3 clean both written true were both current; the browser form's Current switch was aria-checked=false. After (branch): (a) Chromium (/opt/pw-browsers/chromium): Versions tab -> New opens 'Create Contract Version' with the Current switch aria-checked=true, for admin and for the requester. (b) Admin on an approved contract: v1 clean -> [v1 true]; v2 internal_redline -> [v1 false, v2 true]; v3 clean -> [v1 false, v2 false, v3 true]. A browser save of v3 clean on NDA-2026-0012 (POST clm_contract_version 201) gave [v1 clean false, v2 final_signed false, v3 clean true]. (c) A requester was created via /api/v1/auth/admin/create-user with permissionSet clm_requester. On their own draft contract: v1 draft -> [v1 true]; v2 internal_redline -> [v1 false, v2 true], with the same rows read back as admin. The requester's direct PATCH of v1 is_current:true gave 403 PERMISSION_DENIED, so the un-marking is a system write. A browser save of v3 clean by the requester (201) gave [v1 false, v2 false, v3 true]. (d) final_signed with no key next to a clean v1 was stored false and v1 stayed true; a PATCH of that final_signed to is_current:true answered 200 and read back false. A final_signed as the only version -> true; a later v2 clean -> [v1 final_signed false, v2 clean true]. (e) PATCH approved->signing gave 200 with the default-current clean version. In the browser, Start Signing sent POST /api/v1/actions/clm_contract/start_signing -> 200 and the status read back signing. (f) A completed wet-ink clm_signature inserted on the signing contract ran F7, which filed v5 final_signed with an explicit false. Read back: v3 clean true, v4 (explicit false on insert) false, v5 false. Then signing->approved 200, and approved->signing again 200. F16 through its own flow: NOT MEASURED, reason: both the action route and the automation trigger answered 403 'This caller may not start this flow' for the dev admin. The only-version rule was measured with the same write F16 makes. Boot log: boot-only WARN/ERROR lines, normalised (timestamps, ids, ports, durations), were diffed main vs branch. There are 249 vs 248 unique lines, and the only difference is main's 'Port 3097 is in use — serving on 3098', caused by a stray process of mine. The branch adds no warning. The artifact shows contract_version_current lowered to a body. The browser console on the contract page shows the same set on both trees (one 404, one 401, five object-ui predicate warnings). No ablation: no tested behaviour pinned by a test file changed.",
      "gates": "Local, on 8b3c6f0, each exit captured to its own file before any pipe: pnpm validate exit 0 ('✓ Validation passed (850ms)', 6 author-time warnings, all pre-existing approval-approvers-may-resolve-empty plus the hierarchy-security capability notice); pnpm lint exit 0 ('6 suggestion(s)'); pnpm typecheck exit 0 (tsc --noEmit); pnpm lint:i18n-gate exit 0 ('✓ i18n gate · 0 missing keys across 2 locale(s)'). dispatch-gates.mjs is objectstack-only, so the families were hand-derived from hotclm .github/workflows/ci.yml, which runs exactly these four in the single `Validate` job. PR check-runs on head 8b3c6f0 at report time: Validate completed success (run 40190224026, push), and Validate in_progress (run 40191618471, pull_request).",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm; hotclm has no dogfood package",
      "mcp_calls": "0",
      "api_writes": "2 strokes. (1) pr_create via the fleet-write relay (request fw-20261025T120522Z-66ce63, run 40191599839 success): POST /repos/objectstack-ai/hotclm/pulls (draft) and POST /repos/objectstack-ai/hotclm/issues/112/assignees [zhuangjianguo]. Body read back 8133/8133 bytes identical; assignee read back zhuangjianguo. (2) This os-dev-report comment on #96 via scripts/pm/post-stamped.mjs. The branch push is git, not REST. Local-only writes on the demo servers: test data, and a sys_user_permission_set clm_admin grant to the dev admin on the throwaway :3096 database.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — src/flows/signature-record.flow.ts comment at create_final_version says is_current is 'deliberately left at its `false` default'; the field default is now true. The flow writes is_current:false explicitly, so behaviour is unchanged (measured in f). Only the comment's words are stale, and the file is outside this card's declared surface. Listed in PR Acceptance notes.",
        "carrier: none · noted, not filed — F16 `executed_upload` answered 403 'This caller may not start this flow' on POST /api/v1/actions/clm_contract/executed_upload (dev admin with clm_admin granted) and on /api/v1/automation/executed_upload/trigger. It was not reproduced through the Console toolbar button and not compared on main, so no class a reach is established. Dedupe words: executed_upload, may not start this flow, backfill 403.",
        "carrier: none · noted, not filed — requester contract page: the browser console shows 403 on GET /api/v1/data/sys_approval_request (Approvals tab). This diff touches no page or permission, and it was not compared on main. Dedupe words: sys_approval_request 403 requester."
      ],
      "deviations": [
        "Proposed DESIGN.md §03 line for ruling step 1 (not edited, governed): in the clm_contract_version row, replace `is_current boolean` with `is_current boolean(每份合同至多一个当前版本:标记一个即取消其余,hook 强制,各入口一致;新的谈判版本默认为当前;final_signed 不夺取当前标记)`. It is in the PR's Acceptance notes.",
        "origin/main moved to a7239e8 (#111: README.md, scripts/demo.mjs) after the branch point 7b736a0. There is no overlap and no conflict, so it was not merged. The before boot ran at 7b736a0 so that it compares like with like.",
        "The commit carries the session's Co-Authored-By and Claude-Session trailers, as the dispatch ordered (this overrides os-dev.md's model-free trailer rule for this run).",
        "Worktree /home/claude/hotclm-issue-96 had node_modules removed and was then removed with `git worktree remove` (no --force needed). The temporary main worktree in the scratchpad was also removed. All dev servers I started were stopped by process group."
      ]
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed — PR #112 · 2026-10-25T12:09Z

    reading value
    PR #112 MERGED, squash ef93d9b on main, merged at its ACCEPT head 8b3c6f0
    authority maintainer, project thread, verbatim: 「你可以自己审核的就自己合并」

    Release: ruling step 2 (code) is delivered — one current version per contract, new versions default current, enforced by contract-version.hook.ts on every door. What stays on this card: ruling step 1, the DESIGN.md §03 is_current line and the docs/design/00 §5.5 guard wording (governed). The seat drafts it in one design-doc PR together with the other ruled governed lines (#100 §04, #38 §03 field lines); the maintainer merges that PR, and it closes this card. State: pm:dispatched → pm:queue, assignee cleared.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 25, 2026

    @objectstack-fleet
    ContributorAuthor

    Maintainer-action: merge PR #120 — the governed design-doc PR carrying this card's remaining ruled line (code already landed: PR #112). It closes this card.

    State: pm:queue → pm:awaiting-maintainer (no dev work left).


    Generated by Claude Code

  12. added a commit that references this issue on Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions