Skip to content

The launch wizard offers every business requester a "new counterparty" step that always fails — create_party is refused for clm_requester #133

Closed

Description

@objectstack-fleet

Ruled: 6422701531 · letter A · 2026-10-26T17:19:58Z

Filing class: ① product defect, needs a ruling (it touches §04's clm_party row and §06 F1) — reach: public door, measured in a browser on main f534eef (18.1.0, pnpm demo:zh, accounts made the README way). Reader: the maintainer through the decision box, then the hotclm lane.

Symptom

Business Requester 1 (a plain member, clm_requester only) opens 发起合同, picks a contract type, leaves 相对方 empty — the field's help text says 「选一个已有的相对方;留空则在下一步新建。」 — fills the contract screen, then fills the 新建相对方 screen and presses 提交. The screen answers:

Node 'create_party' failed: create_record(clm_party) failed: You do not have permission to perform this action.

(400 POST /api/v1/automation/contract_intake/runs/…/resume, FLOW_FAILED; server log Access denied: operation 'insert' on object 'clm_party' … positions [org_member, everyone].) Nothing is left behind — create_party runs before any other write — but the requester has filled two screens for a step the app knew they could not take. Since PR #122 every employee is a requester, so this is the main launching population. Legal Counsel 1 takes the same path successfully (NDA-2026-0025 launched with a new counterparty).

Why

§04 gives clm_requester R on clm_party (src/profiles/requester.profile.ts:77), while §06 F1 says 「相对方查找或新建」 and the wizard's first screen and the inline-create screen invite every launcher to create one. The flow header (src/flows/contract-intake.flow.ts, "Every write runs as the launching user") records the refusal as known and keeps the branch because legal and admin launch contracts too — but the screens do not tell a requester the branch is not theirs.

What needs deciding

  • A — requesters may create a counterparty: clm_requester gets C on clm_party (legal keeps U and the risk fields); §04's row changes (governed).
  • B — requesters may not: the first screen's help text and the inline branch say so (choose an existing counterparty, or ask legal to add one), and a requester who leaves it empty is refused on the first screen, before the contract screen, with that sentence.
  • C — the platform is asked for a screen-field visibility condition on the caller's object permission, so the branch is simply not shown to a caller who cannot create.

Dedupe: hotclm issues (all states, 131) grepped for create_party, new counterparty, clm_party … create|requester — hits #13, #4, #110 (built or mention the branch), none reports this.


Filed from the browser regression pass on main (2026-10-26).

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat note for option C: no platform card filed, because the predicate may already exist. @objectstack/formula 18.1.0 registers current_user.can(object, verb) (packages/formula/src/stdlib.ts), and the Console binds the subject's object permissions into expression evaluation (ui/packages/app-shell/src/providers/ExpressionProvider.tsx). Not yet measured: whether a screen field's visibleWhen and a flow decision edge both get that binding at run time. If either does not, that gap is the platform card; the lane measures first.

  2. zhuangjianguo commented on Oct 26, 2026

    @zhuangjianguo
    Collaborator

    Ruling: batch #9 item 1 · letter A · maintainer 「同意」 2026-10-26T17:19:58Z

    A — requesters may create a counterparty. §06 F1 「相对方查找或新建」 and the wizard's own screen text were the design; §04's clm_party row was the omission.

    What the director checked before recording (hotclm main f534eef, objectstack main):

    • clm_requester has allowCreate: false on clm_party (requester.profile.ts), while the intake flow's create_party node writes only name, party_kind, registration_no, contact_name, contact_email.
    • registration_no is unique per organization (§03), so the duplicate guard already exists; the screening fields are separate columns and FLS applies on create as well as update (measured earlier on liability_cap).
    • The seat note on current_user.can(object, verb) (comment 6419331370) concerns option C only; it does not change this ruling, which is about who may create, not whether the branch can be hidden.

    Execution after the ruling (lane):

    1. clm_requester: clm_party → allowCreate: true, allowEdit stays false (editing stays legal's, §04 RCU).
    2. Add readOnly(Party, ['risk_flag', 'risk_note', 'verified_at', 'is_active', 'bank_name']) to the requester set; bank_account and contact_phone stay hidden.
    3. Measure with a real requester account made the README way: launch with a new counterparty succeeds; a write naming risk_flag is refused 403.
    4. §04 clm_party row for clm_requester: R(不含银行与电话) → RC(不含银行与电话;风险与核验字段只读) on the governed DESIGN.md PR; the maintainer merges it. No platform card.

    Doc: https://claude.ai/artifact/VnrFu3yXCg8ynfh1rXtzYk


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 16
    Ruling-ref: 6422701531
    Session: session_017nzWFRUo2U7evMkPdVniAn
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-133-requester-creates-party
    Worktree: hotclm-issue-133
    Domain: repo:hotclm (single-lane sister repo — no domain:*)
    Seat: repo:hotclm#1
    File surface: src/profiles/requester.profile.ts (clm_party allowCreate + readOnly on risk_flag, risk_note, verified_at, is_active, bank_name) · README persona notes only if they describe the counterparty step — stop on breach; explain in the report. Governed DESIGN.md §04 text rides the seat's design-doc PR #120
    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 permission sets (who may create a counterparty) | none known | every requester launching with a new counterparty
    Thread-read: 6422701531
    Premise: measured in the 2026-10-26 browser regression pass with real personas; re-measured by the dev on origin/main first
    Serial constraints cleared: batch 9 ruled 2026-10-26T17:19Z; #133, #134 and #148 dispatched together on disjoint files.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 133,
      "status": "blocked",
      "branch": "claude/issue-133-requester-creates-party",
      "pr": null,
      "session": "session_017nzWFRUo2U7evMkPdVniAn",
      "premise_still_valid": true,
      "summary": "Ruling A is implemented in src/profiles/requester.profile.ts (commit 029d8c6, pushed, no PR): clm_party allowCreate true, allowEdit false, plus readOnly(Party, [risk_flag, risk_note, screening_status, is_active, bank_name]); verified_at no longer exists and maps to screening_status (commit 75fa5a7 replaced verified_at with screening_status + screened_at, and #38 removed screened_at). The requester half works as ruled: measured in Chromium and over the API. BLOCKED on a file-surface breach. Field-level rules on 18.1.0 merge most-permissively ONLY among the sets that declare the field (plugin-security getFieldPermissions), and every member holds clm_requester through the everyone anchor. clm_legal and clm_admin declare only bank_account/contact_phone on Party, and clm_finance's editableOnly does not declare bank_name. So the requester's readOnly lines also bind legal, admin and finance: measured, Legal Counsel 1 lost risk_flag/risk_note/screening_status/is_active/bank_name edits on her own party (200 before, 403 after), and the dev admin is refused risk_flag. That contradicts the ruling's 'legal keeps U and the risk fields'. The fix is mechanical: open(...) lines in legal.profile.ts, admin.profile.ts and finance.profile.ts, which the claim's file surface (requester.profile.ts only, 'stop on breach') does not cover. No PR is opened, because this commit merged alone ships that regression.",
      "tests": "18.1.0, pnpm demo:zh --port 3133, one throwaway DB in the worktree. before = eace613, after = 029d8c6. Personas made the README way as the dev admin: POST /api/v1/auth/admin/create-user x3 → 200 (Business Requester 1, Legal Counsel 1, Finance Controller 1; mustChangePassword true); POST /api/v1/data/sys_user_position → 201 clm_legal_counsel (LC1) and clm_finance_controller (FC1); POST /api/v1/auth/change-password x3 → 200. Every reading below was taken as the persona. Browser: Playwright with Chromium /opt/pw-browsers/chromium, locale zh-CN, sidebar 发起合同. || BR1 browser, BEFORE: picked 双向保密协议 + 阿卡迪亚欧洲有限公司 and left 相对方 empty (help text 「选一个已有的相对方;留空则在下一步新建。」) → 确认 → 合同信息 screen → 提交 → 新建相对方 screen, filled → 提交 → resume 400; the dialog and toast read: Node 'create_party' failed: create_record(clm_party) failed: You do not have permission to perform this action. No party and no contract were left behind. || BR1 browser, AFTER: same clicks → 新建相对方 提交 → resume 200 → 首个版本 → 提交 → resume 200 → the 上传首个版本 object form. Created party 后测相对方丙 (owner BR1, risk_flag none, screening_status not_screened, is_active true, contact 王经理 / wang@example.com) and contract NDA-2026-0022 (draft, owner BR1, party = that party). Network: no status 400 or higher apart from the pre-existing static 404 also present before. || LC1 browser, before and after, unchanged: the same path created 前测法务相对方乙 + NDA-2026-0021 (before) and 后测法务相对方丁 + NDA-2026-0023 (after); each resume answered 200. || BR1 API, after: POST clm_party with name, party_kind, registration_no, contact_name, contact_email → 201, born risk_flag none / screening_status not_screened / is_active true (defaults are applied after the FLS check). POST naming each locked field, one at a time → 403 '[Security] Field write denied: not permitted to edit [F] on clm_party' for F = risk_flag (both 'none' and 'watch'), risk_note, screening_status, is_active, bank_name; the hidden bank_account and contact_phone → 403 the same way. PATCH contact_name / name / risk_flag on a party BR1 created, on LC1's party and on a seeded party → 403 PERMISSION_DENIED (object layer: no edit), 9 of 9. Duplicate registration_no → 409 UNIQUE_VIOLATION. Before: POST clm_party → 403 PERMISSION_DENIED. || Blocked-party guard, as BR1, before and after: headless POST /api/v1/actions/clm_contract/launch_contract naming 德尔塔岭控股 (risk_flag blocked) → 400 FLOW_FAILED at refuse_blocked: 'Counterparty 德尔塔岭控股 is blocked and cannot be put on a new contract: ...'. Headless inline-create as BR1, before → 400 at create_party (permission). || REGRESSION, measured, the reason for blocked. LC1 PATCH on her own party huzlV4OuVIjN4JHG: BEFORE risk_flag+risk_note+screening_status+is_active+bank_name in one write → 200. AFTER, each field alone → 403 'Field write denied: not permitted to edit [F]' for all five; contact_name → 200; bank_account → 200. That last one is the control leg: clm_requester hides bank_account, and legal's own open(Party, [bank_account, contact_phone]) re-opens it, which is exactly the mechanism the fix needs. LC1 POST of a new party with risk_flag watch → 403. Dev admin (admin_full_access, no clm_admin) PATCH risk_flag on a requester-created party → 403 FLS. contact_name on the same row → 200. Finance's bank_name lock is the same mechanism (finance declares no bank_name). It is NOT MEASURED at runtime, because FC1 is refused earlier at the row layer on every party it does not own (see out_of_scope_findings). || security/explain, after: BR1 clm_party create allowed, 'granted by [clm_requester]'; update denied; permission sets clm_requester + member_default, both 'via additive baseline (ADR-0090 D5)', the same as before. LC1: clm_legal direct + clm_requester additive baseline. FC1: clm_finance direct + clm_requester additive baseline; explain now also attributes create on clm_party to clm_requester for finance (and therefore for records): a direct consequence of granting C in the everyone set. || Boot: compared the de-duplicated WARN/ERROR signatures of a second baseline boot (requester.profile.ts checked out at eace613, then restored from HEAD: git diff HEAD empty, blob dcaa3d8 equals HEAD) with the after boot, on the same DB. They are identical except four lines that all fall after the ready banner (log lines 398-410 vs banner 361): my own probes (the 409 duplicate, the row-level denials and the requester update denial). high-privilege / security-anchor / refus / degraded match 0 lines in both.",
      "gates": "head 029d8c6, exit codes captured to files before any pipe: pnpm install exit 0 · pnpm validate exit 0 '✓ Validation passed', 7 warnings (6 approval-approvers-may-resolve-empty + the hierarchy-security note, the same set as main) · pnpm lint exit 0 '6 suggestion(s)', 0 warnings · pnpm typecheck exit 0 · pnpm lint:i18n-gate exit 0 'COVERAGE : 0 missing keys across 2 locale(s)' · CLM_DEMO_SEED=1 pnpm validate exit 0 '✓ Validation passed'. high-privilege / security-anchor match 0 lines in the lint and both validate logs. No PR, therefore no CI check-runs to cite.",
      "dogfood_battery": "n/a — hotclm has no dogfood battery; no PR",
      "mcp_calls": "0",
      "api_writes": "1 — this os-dev-report comment via scripts/pm/post-stamped.mjs (POST /repos/objectstack-ai/hotclm/issues/133/comments). git push of the branch is not a REST write. No pr_create sent.",
      "open_questions": [
        {
          "question": "Ruling A's field locks, placed in clm_requester alone, also lock legal, admin and finance (only declaring sets vote, and everyone holds clm_requester). May the file surface widen so that the sets that must edit those fields say so?",
          "options": [
            "A — widen to legal.profile.ts, admin.profile.ts, finance.profile.ts (+ _grants.ts): one exported list PARTY_ASSESSED_FIELDS = [risk_flag, risk_note, screening_status, is_active, bank_name] used by readOnly in clm_requester and by open in clm_legal and clm_admin, plus open(Party, [bank_name]) in clm_finance (its editableOnly keeps the risk fields read-only). Cost: about 6 lines across 4 files, no new verification surface; the same pattern as CONTRACT_STAMPED_FIELDS and the existing open(Party, [bank_account, contact_phone]). Re-measure LC1 risk_flag edit = 200.",
            "B — ship requester.profile.ts alone, as the ruling's step 2 literally says. Cost: legal and clm_admin can no longer set risk_flag, risk_note, screening_status or is_active, and nobody without system context can flag a party blocked, so the blocked-party guard has no human writer.",
            "C — drop the field locks and grant create only. Cost: a requester can create a party flagged none/clear at will (screening_status clear with no screening), which the ruling explicitly forbids."
          ],
          "recommendation": "A, because it delivers the ruling's stated intent (legal keeps U and the risk fields) with the house discipline already documented in _grants.ts open() and admin.profile.ts ('Every field another set locks or hides is opened here explicitly'). It is a mechanical extension, not a product decision; branch 029d8c6 is the base to resume from."
        },
        {
          "question": "Even with A, legal cannot edit a counterparty a requester created (row layer). Who maintains the risk flag on such a party?",
          "options": [
            "A — a separate card for the pre-existing defect (legal and finance are row-refused on every clm_party they do not own, on main too). #133 lands without it; its screen copy 「之后由法务维护它的风险标记和筛查结果」 stays untrue for requester-created parties until that card lands.",
            "B — fold it into #133's next round: a §04 sharing rule on clm_party granting edit to the legal positions (and finance for banking). Governed §04 wording, so a maintainer decision.",
            "C — modifyAllRecords on clm_party in clm_legal and clm_admin (neither is anchor-bound, so allowed). Changes §04 row scope; a maintainer decision."
          ],
          "recommendation": "A, because the defect predates #133 (measured on eace613: LC1 PATCH of seeded 峰顶翻译 → 403 'You do not have access to this record'), and its fix is a §04 sharing decision that needs its own ruling. Sequence it right after #133, since ruling A makes it user-visible for every new party."
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: public door, PATCH /api/v1/data/clm_party/ID as Legal Counsel 1 on a seeded party (峰顶翻译) → 403 'You do not have access to this record' on main eace613, and the same for Finance Controller 1 with bank_name; server log 'not permitted to update this clm_party record (row-level security)'. §04 gives legal RCU and finance RU(银行信息) on clm_party, but public_read makes writes owner-scoped (explain owd_baseline: 'writes owner-scoped') and no sharing rule or modifyAllRecords covers clm_party, so legal edits only parties it created. Seam: spec: LegalSet/FinanceSet/AdminSet objects.clm_party (no modifyAllRecords; no clm_party rule in src/sharing) → runtime: plugin-security OWD write scope. dedupe: clm_party edit legal, owner-scoped, public_read write, sharing rule party, 法务 相对方 修改",
        "class: a · reach: public door, POST /api/v1/security/explain for Finance Controller 1 on clm_party, on main eace613 → fls 'masked from responses: [bank_account]'. §04 finance RU(银行信息) and README ('the only position that may edit bank details'), but clm_requester hides bank_account and clm_finance never declares it (editableOnly declares only the other fields), so finance cannot read or write the bank account. The same declare-to-vote mechanism as this card's blocker. Seam: spec: FinanceSet fields editableOnly(Party, [bank_name, bank_account]) → runtime: plugin-security getFieldPermissions. dedupe: bank_account finance masked, clm_finance FLS, 银行账号 财务, editableOnly declare",
        "Acceptance note, carrier: #133's next round. src/flows/contract-intake.flow.ts header (the clm_party bullet, 'refused for a requester the same way') goes stale once a requester may create; it is outside this claim's file surface and was left untouched as instructed. The create_party node writes only name, party_kind, registration_no, contact_name, contact_email: none of the locked fields.",
        "Observation, carrier: the seat's DESIGN.md PR #120. §03 field list (clm_party row) still names verified_at; the object has screening_status since 75fa5a7. The same rename applies to the ruling's §04 wording below.",
        "Observation, not filed: granting C in the everyone-bound set gives create on clm_party to every position (finance and records included; explain now attributes finance's create to clm_requester). That is inherent to ruling A; §04's per-set columns can stay as they are, since the matrix lists each set's own grant."
      ],
      "design_s04_proposal": {
        "matrix_row_clm_party_clm_requester_cell": "R(不含银行与电话) → RC(不含银行账号与电话;风险标记、风险说明、筛查结果、启用状态与开户行只读)",
        "fls_table_new_row": "| `clm_party.risk_flag` · `risk_note` · `screening_status` · `is_active` · `bank_name` | clm_requester 只读 | 由法务评定或由筛查连接器写入;发起人新建的相对方生来未标记、未筛查 |",
        "note": "The ruling's own wording was RC(不含银行与电话;风险与核验字段只读). 核验 maps to screening_status (筛查结果), and bank_name (开户行) is read-only, not hidden, so the cell names it. The §03 field list should read screening_status in place of verified_at in the same governed PR."
      }
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment (seat, PM loop round 16) — Ruling-ref: 6422701531

    File surface widens to src/profiles/_grants.ts, legal.profile.ts, admin.profile.ts, finance.profile.ts (in addition to requester.profile.ts), per the dev's measurement on 029d8c6: on 18.1.0 only sets that name a field vote, and every member holds clm_requester, so its read-only lines alone also locked the risk fields for legal and admin — against the ruling's intent that legal keeps maintaining them. The lane exports one list of the assessed party fields; clm_requester applies readOnly, clm_legal and clm_admin apply open, clm_finance opens bank_name and bank_account (§04 RU 银行信息; today bank_account is masked from finance by the same mechanism). No product change beyond the ruling.

    Not in this card: on main, legal and finance cannot edit a counterparty they do not own (owner-scoped writes on clm_party, no sharing rule) — that needs a ruling and goes to the decision box as its own card.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 133,
      "status": "done",
      "branch": "claude/issue-133-requester-creates-party",
      "pr": "https://github.com/objectstack-ai/hotclm/pull/154",
      "session": "session_017nzWFRUo2U7evMkPdVniAn",
      "premise_still_valid": true,
      "summary": "Ruling A, as the seat amended the claim (6423291471). clm_requester gets allowCreate on clm_party; allowEdit stays false. _grants.ts exports PARTY_ASSESSED_FIELDS = [risk_flag, risk_note, screening_status, is_active, bank_name]: clm_requester holds them readOnly, clm_legal and clm_admin open them, and clm_finance opens bank_name and bank_account. The intake flow header's clm_party bullet is corrected (comment only). verified_at maps to screening_status (75fa5a7; screened_at was removed by #38). Re-measured: legal and CLM Admin 1 edit the five fields again (200), finance reads bank_account again, and the requester side is as ruled. One expectation is not met: the dev admin is still refused risk_flag (403 FLS), because it holds no clm_admin. See open_questions. Commits 029d8c6 + d21ffc9; PR #154 is open as a draft (the relay forces draft).",
      "tests": "Setup: 18.1.0, pnpm demo:zh --port 3133, fresh throwaway DB. Personas made the README way: create-user x4 → 200 (Business Requester 1, Legal Counsel 1, Finance Controller 1, CLM Admin 1; mustChangePassword true); sys_user_position → 201 (clm_legal_counsel, clm_finance_controller, clm_admin); change-password x4 → 200; then a second pnpm demo:zh. Every reading was taken as the persona. Browser: Chromium /opt/pw-browsers/chromium, zh-CN. || BR1 browser, head d21ffc9: 发起合同 → 双向保密协议, 相对方 empty → 合同信息 提交 → 新建相对方 提交 → resume 200 → 首个版本 → 200 → 上传首个版本. Created party 二轮相对方戊 (owner BR1, none / not_screened / active) and NDA-2026-0021 (draft). On eace613 the same path answered 400 'Node create_party failed … permission'. || BR1 API: create without the locked fields → 201. POST naming each of risk_flag, risk_note, screening_status, is_active, bank_name, bank_account, contact_phone → 403 'Field write denied: not permitted to edit [F]', 7 of 7. PATCH contact_name on a party BR1 owns, on legal's party and on a seeded party → 403 PERMISSION_DENIED, 3 of 3. Duplicate registration_no → 409 UNIQUE_VIOLATION (measured on 029d8c6). || LC1: PATCH of her own party, each of the five fields alone and all five together → 200 (all 403 on 029d8c6, 200 on eace613). POST of a party flagged watch/hit at birth → 201. Browser launch with a new party → NDA-2026-0022, every resume 200, the same as before. || CLM Admin 1 (clm_admin position): PATCH of all five fields on a party it owns → 200, flagging it blocked. The headless launch guard then refused that party: 400 FLOW_FAILED at refuse_blocked. || Finance Controller 1: explain on clm_party gives fls not_applicable, 'No field-level masking applies' (on eace613: 'masked from responses: [bank_account]'). GET of a seeded party now returns bank_account and bank_name. PATCH bank_name / bank_account on parties it does not own → 403 'You do not have access to this record' (row layer, #152, recorded and not routed around). Finance's field-layer edit is therefore NOT MEASURED. Finance also cannot create a party (POST → 403 Field write denied [name, party_kind], its own editableOnly), so §04 finance stays RU. || Dev admin (admin_full_access + organization_admin_no_bypass + clm_requester + member_default, no clm_admin): PATCH risk_flag → 403 Field write denied, NOT the 200 the dispatch expected. No set it holds opens the field. || Blocked guard: a headless launch by BR1 naming seeded 德尔塔岭控股 → 400 FLOW_FAILED at refuse_blocked, before and after. || security/explain: BR1 create on clm_party allowed, 'granted by [clm_requester]'; update denied; clm_requester and member_default both 'via additive baseline (ADR-0090 D5)', unchanged. || Boot: de-duplicated WARN/ERROR signatures of the eace613 second boot (file checked out, then restored from HEAD, blob hash matched) against the d21ffc9 second boot. Identical except the seeder's inline-budget timing line and three clm_party update denials, which were my probes. high-privilege / security-anchor / refus / degraded / no such table: 0 in both.",
      "gates": "Tree of head d21ffc9 (gates ran on the identical tree just before the commit). Exit codes captured to files before any pipe: pnpm install exit 0 · pnpm validate exit 0 '✓ Validation passed', 7 warnings, the same set as main · pnpm lint exit 0, 6 suggestions, 0 warnings · pnpm typecheck exit 0 · pnpm lint:i18n-gate exit 0 'COVERAGE : 0 missing keys across 2 locale(s)' · CLM_DEMO_SEED=1 pnpm validate exit 0. high-privilege / security-anchor: 0 lines in lint and both validate runs. PR #154 check-runs at report time: Validate completed/success, plus a second Validate run in_progress.",
      "dogfood_battery": "n/a — hotclm has no dogfood battery",
      "mcp_calls": "0",
      "api_writes": "3 relay writes: os-dev-report comment 6423252240 (first round, blocked) · pr_create objectstack-ai/hotclm#154 with assignee zhuangjianguo (fleet-write run 40373555256, body read back identical) · this os-dev-report comment. git push (029d8c6, d21ffc9) is not a REST write.",
      "open_questions": [
        {
          "question": "The dev admin, a platform admin without the clm_admin position, still cannot write the five assessed party fields: 403 FLS, measured. Accept that, or change something?",
          "options": [
            "A — Accept it. Platform admins without clm_admin are governed like any member. That is already true on main for bank_account and contact_phone, which clm_requester hides from the dev admin. The README's CLM administrator holds clm_admin, and that account is measured at 200.",
            "B — A separate card to give the demo's dev admin the clm_admin position (scripts/demo.mjs or README). A demo/onboarding change, outside #133.",
            "C — Drop the field locks. That reverses ruling A."
          ],
          "recommendation": "A. Platform permission sets carry no app field grants, so the app has no metadata spelling for 'platform admin edits CLM fields' other than holding clm_admin. The behaviour matches the existing bank_account/contact_phone mask on main."
        }
      ],
      "out_of_scope_findings": [
        "carrier: #152 (the seat's decision card). On eace613 and on d21ffc9, legal, finance and clm_admin are row-refused on clm_party rows they do not own ('You do not have access to this record'), so a requester-created party is not editable by legal until #152 is decided. Recorded in the flow header and the PR's Acceptance notes.",
        "carrier: the seat's DESIGN.md PR #120. §03's clm_party field list still names verified_at; the proposed §04 wording is in the PR body and below.",
        "Noted, not filed: create via the everyone-bound set reaches every position. Finance's own editableOnly stops it in practice (measured 403); records can create (inferred from its grants, not measured)."
      ],
      "design_s04_proposal": {
        "matrix_row_clm_party_clm_requester_cell": "R(不含银行与电话) → RC(不含银行账号与电话;风险标记、风险说明、筛查结果、启用状态与开户行只读)",
        "fls_table_new_row": "| `clm_party.risk_flag` · `risk_note` · `screening_status` · `is_active` · `bank_name` | clm_requester 只读 | 由法务评定或由筛查连接器写入;发起人新建的相对方生来未标记、未筛查 |",
        "note": "The ruling's wording was RC(不含银行与电话;风险与核验字段只读). 核验 maps to screening_status, and bank_name is read-only, not hidden. §03 should read screening_status in place of verified_at."
      }
    }

    Generated by Claude Code

  7. added a commit that references this issue on Oct 26, 2026
    3b7364f
  8. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling-ref: 6422701531

    Landed — PR #154 · 2026-10-26

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

    Release: a business requester can add a new counterparty while launching a contract. The risk, screening, active and bank-name fields stay read-only for them, so a new party is born unflagged and unscreened. Legal and the CLM administrator keep editing those fields. Editing a party someone else owns is #152. 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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions