Skip to content

A review saved with decision Approved leaves 结论时间 (decided_at) empty — the deviation stamps it, the review does not #159

Closed

Description

@objectstack-fleet

Filing gate: ① user-visible defect, reproduced in the browser on @objectstack 18.2.0 (hotclm PR #155 branch).

Symptom. Legal counsel creates a review on 审查与偏离 with 结论 = 通过 and saves. The row reads decision: approved, decided_at: null; 结论时间 stays empty on the page.

Where. clm_review.decided_at (src/objects/review.object.ts) has no stamping hook and no description. clm_deviation stamps its own decided_at / decided_by when it is decided (src/objects/contract.hook.ts, the deviation guard); clm_signature stamps completed_at since #145. DESIGN.md §03 lists decided_at on the review with no "manual" note.

Expected. Saving a review whose decision leaves pending stamps decided_at (unless the user typed one), the way the deviation and the signing round do.

Business reason. The review page and any report on review turnaround read when legal decided; with the field empty, a decided review carries no decision time at all and the lawyer has to type it by hand.

Reader. hotclm execution seat (PM seat #36).

Duplicate search. hotclm issues, all states, "decided_at review": 0 hits; #138/#145 (signature completed_at) is the sibling, closed.

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage — 2026-10-27

    Filed from the 18.2.0 browser pass (hotclm PR #155, landed as 21f2319). Defect, user-visible, reproduced: accepted.

    Route: app-side, in the deviation and signing-round pattern. Stamp clm_review.decided_at when decision leaves pending, unless the user typed one, and give the field a description. DESIGN.md §03 needs no change.

    State: → pm:queue + bug.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 17
    Ruling-ref: none
    Session: session_017nzWFRUo2U7evMkPdVniAn
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-159-review-decided-at
    Worktree: hotclm-issue-159
    Domain: repo:hotclm (single-lane sister repo — no domain:*)
    Seat: repo:hotclm#1
    File surface: src/objects/contract.hook.ts (review stamping, in the deviation pattern) · src/objects/review.object.ts (description of decided_at) · translations for that description if the i18n gate asks — 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 review record (when legal decided) | none | every lawyer deciding a review
    Thread-read: 6437440077
    Premise: re-measured by the dev on origin/main 21f2319 (@objectstack 18.2.0) with README personas first
    Serial constraints cleared: Triaged 2026-10-27; round 17 dispatches #134, #127, #64 and #159 together on disjoint files.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 159,
      "status": "done",
      "branch": "claude/issue-159-review-decided-at",
      "pr": "https://github.com/objectstack-ai/hotclm/pull/163",
      "session": "session_017nzWFRUo2U7evMkPdVniAn",
      "premise_still_valid": true,
      "summary": "Premise re-measured on origin/main 21f2319 (18.2.0) as Legal Counsel 1 in zh-CN Chromium: a review created with 结论 = 通过 stored decided_at null, and the 结论时间 column was absent from the contract's review grid. New hook review_decision_stamp in src/objects/contract.hook.ts (clm_review, beforeInsert + beforeUpdate, priority 200), in the deviation pattern: when a write gives the review a decision (approved / changes_requested / rejected) different from its previous one and no decided_at is present in the write or on the row, it stamps now. It never overwrites or clears a value. decided_at got a description in review.object.ts, and the i18n gate asked for its zh-CN help, which was added along with the en line. No decided_by exists on clm_review or in DESIGN.md §03 (the reviewer decides), so none was added. Back to pending: allowed (§03 gives the review decision no transition table) and the stamp is left in place, matching the deviation's fill-only, never-erase stamp. A re-decision after that keeps the first time; see open_questions. One step beyond the card's wording: a decided-to-decided change on a row with an empty decided_at (the rows this defect left behind) is stamped too.",
      "tests": "No unit-test harness in this app; behaviour measured on 18.2.0, pnpm demo:zh --port 3144, fresh DB before (21f2319) and after (4041dd1). Persona: admin create-user Legal Counsel 1 -> 200 (mustChangePassword true), sys_user_position clm_legal_counsel -> 201, persona change-password -> 200, security/explain clm_review create allowed. BROWSER before: DPA-2026-0005 › 审查与偏离 › 新建, 结论=通过, POST clm_review 201, row {decision: approved, decided_at: null}; the record page shows no 结论时间. BROWSER after: same steps, decided_at 2026-10-27T09:04:05.678Z; the record page reads 结论时间 2026/10/27 上午9:04, and the grid shows the column. Typed 2026/10/01 09:30 -> kept as 2026-10-01T09:30:00.000Z. Pending (待定) -> decided_at null. Edit pending -> 通过 -> stamped 09:05:42.961Z, and the page shows it. Edit back to 待定 -> stamp left in place. API before/after as the persona: POST approved null -> stamped; POST approved + typed kept/kept; POST pending and POST with no decision null/null; PATCH pending->changes_requested null -> stamped; PATCH ->pending null -> left in place; PATCH pending->rejected + typed kept/kept; PATCH comments only unchanged/unchanged; after only: re-decide after the back-edge keeps the first time; approved->rejected on a cleared row -> stamped. Seed: 67 reviews (60 seeded + 7 measured); exactly 4 have decided_at on or after 2026-10-27, all from the measurement; 0 decided reviews are empty. The seed summary is identical before and after (inserted 830, errored 404: the README's documented unnamed personas). Browser console: the same 404 and 401 resource lines before and after. No ablation: there is no test file to pin; before/after is the proof.",
      "gates": "Final head 4041dd1, exit codes captured before any pipe: pnpm install EXIT=0; pnpm validate EXIT=0 (Validation passed); pnpm lint EXIT=0 (1 warning(s), 6 suggestion(s): the one warning is main's security-controlled-by-parent-owner-policy-without-opt-in, so no new warning); pnpm typecheck EXIT=0; pnpm lint:i18n-gate EXIT=0 (0 missing keys across 2 locale(s)); CLM_DEMO_SEED=1 pnpm validate EXIT=0. Mid-way, before the translation: lint:i18n-gate EXIT=1 on [zh-CN] objects.clm_review.fields.decided_at.help, and lint showed a second warning for the same key; both cleared. PR check-runs on 4041dd1: Validate in_progress at report time. No dispatch-gates derivation: this is a sister repo with no scripts/pm/dispatch-gates.mjs, and the gate list is AGENTS.md's.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — fleet-write relay: pr_create objectstack-ai/hotclm (#163); comment on objectstack-ai/hotclm#159 (this report). git push of the branch is not a REST write.",
      "open_questions": [
        {
          "question": "When a review's decision goes back to pending, should decided_at stay (as shipped), be cleared, or should the back-edge be refused?",
          "options": [
            "A keep the stamp (shipped): matches the deviation's fill-only stamp and never erases a typed time, but a review decided again after pending keeps its first decision time",
            "B clear decided_at on the edge into pending, unless the same write sets one: a later re-decision gets a fresh time, but a typed time is erased and a hook writes null into a user-editable field",
            "C refuse decided -> pending, the deviation's 'decided once' rule: a new transition table on clm_review.decision that DESIGN.md §03 does not give, which is product semantics and a §03 change"
          ],
          "recommendation": "A, because it is the deviation's stamping behaviour, needs no §03 change, and the lawyer can correct the editable field. Revisit with B if review-turnaround reports show re-decided reviews."
        }
      ],
      "out_of_scope_findings": [
        "class: none (renderer observation) · reach: browser, contract › 审查与偏离 review grid: the configured decided_at column is omitted while every row's value is empty (before the fix), and appears once one row has a value · carrier: none — noted in PR Acceptance notes, not filed"
      ]
    }
  4. added a commit that references this issue on Oct 27, 2026
    91a79dd
  5. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling-ref: none (triaged defect, comment 6437440077)

    Landed — PR #163 · 2026-10-27

    reading value
    PR #163 MERGED (squash on main), merged at its ACCEPT head 4041dd1; Fixes #159 closes this card
    authority maintainer, project thread, verbatim: 「你可以自己审核的就自己合并」

    Release: a review saved with a decision now records 结论时间 automatically; a typed time is kept. State: pm:dispatched removed, assignee cleared.


    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

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions