Repository navigation
Send for Approval, Start Signing and Activate are offered while their precondition is unmet, then refused after the click — grey them out with disabled - #173
Merged
Conversation
…while the hook would refuse them The three transition buttons were gated on status only, so legal counsel and the records manager were offered a primary button that answered 422 after the press. Each now declares `disabled` over roll-ups on the contract itself: open_deviation_count (existing) plus three new summary counts that mirror the hook guards' own child filters — approved_legal_review_count, current_clean_version_count and final_signed_version_count. The hook guards are unchanged and keep refusing as the server-side control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
Contributor
Author
席位核对 — ACCEPT · head
|
| check | reading |
|---|---|
| shape | draft → main, rebased on 0159171; mergeable clean |
| CI on the head | both Validate check-runs success on 8b79798 = PR head.sha |
| scope | 4 files (+120/−14): three roll-up summaries on clm_contract (approved_legal_review_count, current_clean_version_count, final_signed_version_count), each with the child filter its hook guard uses, readonly in the rollup group with en/zh-CN labels and help; disabled on 送审 / 发起签署 / 生效. Within the claim's surface. contract.hook.ts untouched, so the server-side refusal stands (REST still 422). Lint 0 warnings |
| the defect | measured in zh-CN with the declared staff. Before: all four presses in the card's table answered 422. After: each button is greyed (「对此记录不可用」) until its precondition holds, then the press succeeds (F1–F4b). Switching the current version from clean to redline greys 发起签署 again (F5). Seed roll-ups equal their SQL child counts on 120/120 contracts |
| seat call — the remainder | C: close #169 on this merge (commit message Fixes #169). All four rows of the card's table are mirrored. Activation's other guard, "a completed round whose formalities cover the type's", compares a child multiselect with a parent field, which no summary filter can express. So 生效 can still be enabled and then refused for that one reason, with the hook's sentence. The authored disabled reason is the platform half the card already routes to the maintainer (objectstack#24018 / #24034 B′, ruled not planned); the seat raises it there, not in this lane |
| governed text | §03 roll-up list and the state-machine note go to seat PR #120 |
| observation | the archive-freeze comment in contract.hook.ts still says "five summary"; there are now eight. Comment drift only, no card |
Landing: under the maintainer's merge authorization (project thread: 「你可以自己审核的就自己合并」).
Generated by Claude Code
zhuangjianguo
marked this pull request as ready for review
October 27, 2026 10:47
zhuangjianguo
pushed a commit
that referenced
this pull request
Oct 27, 2026
…can succeed (#169, PR #173) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
This was referenced Oct 27, 2026
Draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #169
Clause-②: no
Metadata-protocol: none
Send for Approval (送审), Start Signing (发起签署) and Activate (生效) were shown whenever the status matched. If a precondition was unmet, the press answered
422 INVALID_STATE. Each button now declaresdisabled, so it is greyed out until the record says the press can succeed. The hook guards are unchanged and still refuse the press on the server.Why
Part of: one precondition is still checked only after the press. Activate also needs a completed signature round whoseformalities_donecovers the contract'sexecution_formalities. That compares a child's multiselect with a field on the parent. A summaryfiltercannot express that comparison, so no roll-up can carry it. Measured below as F4a. The card's table lists four refusals. All four are now mirrored.What changed
src/objects/contract.object.ts: three new roll-upsummaryfields onclm_contract. Each copies theversion_count/open_deviation_countpattern (readonly,scale: 0,min: 0, grouprollup, explicitrelationshipField, nomax). Each uses the same child filter as the hook guard it mirrors.approved_legal_review_countclm_reviewwhere{ stage: 'legal', decision: 'approved' }current_clean_version_countclm_contract_versionwhere{ kind: 'clean', is_current: true }final_signed_version_countclm_contract_versionwhere{ kind: 'final_signed' }src/actions/contract-lifecycle.actions.ts:transition(...)takes an optionaldisabledpredicate.send_for_approval:record.open_deviation_count > 0 || record.approved_legal_review_count == 0start_signing:record.current_clean_version_count == 0activate_contract:record.final_signed_version_count == 0The descriptions of
send_for_approvalandstart_signingnow say when the action becomes possible.src/translations/{en,zh-CN}/objects.contract.ts: the three fields' label and help text in both bundles, and the two updated descriptions.Platform facts this relies on, read at
@objectstack/spec@18.2.0:summaryOperations.filteris a fullFilterConditionSchema.aggregateSummaryValue(packages/objectql/src/summary-aggregate.ts) ANDs it with the parent foreign-key match, so a filter on two child fields works.ActionSchema.disabledtakes the same three forms asvisible. The liveness ledger lists it asliveon all six rendering surfaces.aria-describedbydescription. There is no authored reason. That is the platform half the card leaves out (objectstack#24018 / #24034 B').is_currentmoves between versions incontract-version.hook.tsthrough the engine. Unsetting the old version's flag is a child update, so the roll-up is recomputed then too. Measured in F5.Measured in the browser (Chromium
/opt/pw-browsers/chromium, zh-CN,pnpm demo:zhon a throwaway DB, port 3150)Before: origin/main
e7b56da, with README-way personas (create-user, sys_user_position, set-user-manager, change-password). After:8b79798, which is this branch rebased on0159171, signed in as the declared demo staff from #171 (requesterN / counselN / records@example.com). The commits in between (#170, #171) touch none of these files. Every reading was taken signed in as the persona. Setup writes (a review, a deviation decision, version uploads, a signature) went through the REST API, as the persona who would make them.422, toast "An approved legal review is required before the contract enters approval."disabled, tooltip 「对此记录不可用」422"1 deviation(s) are still open; ..."disabled422"A current clean version is required before signing."disabled422"A completed signature round is required before activation."disabledFlips, after:
201)POST .../send_for_approval200, toast 「已送审,进入审批。」, status in_approval,approved_legal_review_count= 1200)200, 「已送审,进入审批。」201;current_clean_version_count0 to 1)200, 「已进入签署。」. The header then shows 生效disabled(no final_signed yet)201;final_signed_version_count0 to 1)422"A completed signature round is required before activation." This is the hook-only guard named abovesenttocompleted,200)200, 「合同已生效。」, header now 发起续签is_currentunset by the version hook); 发起签署disabledThe hook is unchanged and still refuses. A REST press that bypasses the greyed button answers
422as before:POST /api/v1/actions/clm_contract/start_signingon DPA-2026-0001 (current version is a redline):422 INVALID_STATE"A current clean version is required before signing."send_for_approvalon MSA-2026-0003 (1 open deviation):422 INVALID_STATE"1 deviation(s) are still open; ...".Seed values compared with SQL: for all 120 contracts, each roll-up equals the SQL count of its filtered children:
approved_legal_review_countcurrent_clean_version_countfinal_signed_version_countopen_deviation_countNo column is null. The seed holds no versions (README), so both version counts read an honest 0. After all the writes above, all 120 still match. The server log has no "Roll-up summary recompute failed" line.
Browser console: no
disabledpredicate warning. The only warnings are thevisible"conditional predicate failed ... safe default" ones, which appear on main as well (before run).Gates (head
8b79798)Governed text, for the seat's design-doc PR #120 (not touched here)
DESIGN.md §03, the
clm_contractrow, ending: "· 汇总:version_count · open_deviation_count · approved_legal_review_count(legal审查approved条数)· current_clean_version_count(kind: clean且is_current的版本条数)· final_signed_version_count(kind: final_signed版本条数)· overdue_obligation_count · planned_amount · actual_amount".Proposed sentence under the §03 state-machine table: "送审 / 发起签署 / 生效 三个按钮以
disabled读上述汇总,前置条件未满足时置灰;守卫仍在 hook 中直接读子记录并拒绝,汇总只是界面便利。「签署记录 completed 且 formalities_done 覆盖类型 execution_formalities」无法写成汇总过滤,仍只在按下后由 hook 拒绝。"Acceptance notes
contract.hook.ts(archive freeze) says "the engine recomputes the fivesummary". There are now eight. That file belongs to Child record names are stored in English, so a zh-CN user reads "v2 · Clean", "Legal · Legal Counsel 1", "Wet ink · Completed" #157's claim, so it is not edited here.🤖 Generated with Claude Code
https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn