Skip to content

[Decision] Finance cannot record its finance review before the contract is approved, though §04 grants it RCU on finance-stage reviews #190

Open

Description

@objectstack-fleet

Ruled: 6607878401 · letter D · 2026-11-03T15:28:05Z

Raised by #186's dev (PR #189), measured on @objectstack/* 18.2.0, before and after that PR.

The conflict

  • DESIGN.md §04 matrix: clm_review · clm_finance RCU(stage=finance). src/profiles/finance.profile.ts declares review_finance_stage_insert / _update.
  • clm_review is controlled_by_parent on clm_contract. On 18.2.0, writing a child needs edit on its master.
  • Finance's contract edit window opens at approved (contract_finance_post_approval). Before that, the routed sharing rule (contract_finance_routed, PR The finance approver can open the contract it is asked to approve #153) gives finance read only.
  • So on a contract in in_review or in_approval, which is exactly when a finance review happens, finance@'s PATCH on its own finance-stage review answers 403 'requires edit access to its master record'. On an active contract, the same PATCH answers 200.

Interim: since PR #189, the demo deals the 7 pre-approval finance reviews to the legal head, who can write them.

Options

A. Keep the grants; write it down. §04 says legal records the finance review on finance's behalf until approval. No new grant. The demo already reads this way. Cost: finance cannot sign its own review in the window where it matters; legal types it in.

B. Give finance edit on contracts routed to it (contract_finance_routed read → edit), with field-level security locking every contract field, so in practice only the children open up. Cost: widens a sharing rule ruled in round 16, and every new contract field must remember the finance lock.

C. Ask the platform for a child write that does not need master edit (a controlled_by_parent exception, for example a per-child permission that admits a write to rows the caller may read the master of). Cost: an upstream card and a wait. It is a platform semantic, not a defect.

Dev's lean: A for now (no new grant). Seat's lean: B is the shape the business wants (finance signs its own review), but it is a §04 change; A is the honest interim.

Activity

  1. zhuangjianguo commented on Nov 3, 2026

    @zhuangjianguo
    Collaborator

    Ruling: batch #10 item 2 · letter D · maintainer 「同意」 2026-11-03T15:28:05Z

    D — finance records its review through a declared action; A (legal types it, PR #189) stays until D lands. Not B, not C.

    What the director checked before recording (hotclm main 7e7c2dc, 18.2.0; objectstack main):

    • The refusal is ADR-0055 §3's master-write check (plugin-security security-plugin-cbp-write-gate.ts): a controlled_by_parent detail is written only by a caller who may edit its master. That is the platform's declared semantic, the same as Salesforce's, so C would ask for an ADR change that applies to every detail object of every app. Not filed.
    • The approval lock (F5 lockRecord: true) holds only the contract row itself (plugin-approvals lifecycle-hooks.ts), not its children; the lock is not what refuses finance.
    • B's real cost: route_finance is stamped at submission, so an edit-level routed rule lets finance edit the contract from in_review on. Field locks are per set, not per row (A finance controller cannot launch a contract — clm_finance's field locks also apply to the draft they create #127), so either the finance lock covers every contract field, which ends finance's post-approval RU, or it keeps today's legal-field lock and finance can change amount, title, dates while legal is still reviewing. Amount drives the routing matrix. Not taken.
    • hotclm already has the shape: the lifecycle buttons (contract-lifecycle.actions.ts) and the backfill dialog (contract-backfill.actions.ts) are declared actions gated by requiredPermissions whose body writes system-elevated; the records manager's 发起签署 on a contract it can only read ([Decision] Who presses Start Signing? Records holds the capability but cannot read an approved contract, legal can read it but lacks the capability, and clm_admin cannot write the contract #100, ruling A) is exactly this case.

    Execution after the ruling (lane):

    1. Add a record_finance_review action on clm_contract: a dialog with decision, risk_level_assessed, comments; requiredPermissions on a token the finance set already holds; shown while the contract is in_review or in_approval; the body (system-elevated) creates the caller's stage: 'finance' review with reviewer = the caller, or updates it when one exists. It writes nothing on the contract.
    2. Measure with the finance demo account: the action records a review on an in_review contract (200) and the review shows under 审查与偏离; a direct PATCH on the contract and a direct POST of a clm_review row still answer 403; a requester does not see the button.
    3. Demo data: move the 7 pre-approval finance reviews back to the finance controller once the action exists.
    4. §04 matrix cell clm_review · clm_finance: keep RCU(stage=finance) and add 「经「记录财务审查」动作」 on the governed DESIGN.md PR.

    No platform card. Doc: https://claude.ai/artifact/QT2nrniJjuZMbwiT5v26Xq


    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

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions