Repository navigation
The contract page's new-version form defaults "Current" off, and two versions of one contract can both be current - #112
Merged
Conversation
…rrent A version saved as offered on the contract page was not current (`defaultValue: false`), so a clean copy did not satisfy the approved -> signing guard, and nothing kept the flag exclusive: two versions of one contract could both be current. Ruled 1A 2A on #96 (comment 6395827965). `is_current` now defaults to true, and a new `contract_version_current` hook (afterInsert / afterUpdate, runAs system) un-marks every other current version of the contract when a row is current after the write. A `final_signed` row keeps the flag only while it is the contract's only version (the F16 backfill) and is otherwise stored false, so the clean version stays current and signing -> approved remains re-enterable. The writes are system writes because requesters and records hold create, not edit, on versions (same precedent as `deviation_gate`). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
Contributor
Author
席位核对 — ACCEPT · head
|
| check | reading |
|---|---|
| shape | draft → main, line 1 Part of #96 — ruling step 2 (code) …, no closing keyword; assignee zhuangjianguo |
| CI on the head | both Validate check-runs success on 8b3c6f0 = PR head.sha |
| scope | 3 files (+96/−4): new contract-version.hook.ts, its registration in hooks.ts, is_current defaultValue: true; contract.hook.ts untouched; nothing governed |
| the ruling | 6395827965 step 2: afterInsert/afterUpdate, runAs: 'system', a current row un-marks its siblings, final_signed keeps the flag only as the contract's sole version, default true — all present; the hook judges the committed row (re-read), and its own false writes exit at the first check, so no recursion |
| measured (dev, 18.1.0, real boots) | main: default false, signing guard 422, two current rows; branch: form switch on, v1→v2→v3 leaves one current (admin and requester; requester's direct PATCH 403, so the un-marking is the system write), final_signed with siblings stored false, sole final_signed true, approved → signing 200, F7's explicit false and the signing → approved → signing round trip intact; no new boot warning |
| not measured | F16 through its own flow (403 "This caller may not start this flow" — the known executed_upload refusal tracked on #43 / objectstack#25643); its only-version write was measured directly |
| stays on #96 | ruling step 1 — the DESIGN.md §03 line and docs/design/00 §5.5 wording (governed; proposed text in the PR's Acceptance notes) |
| seat follow-up | signature-record.flow.ts comment says is_current is "left at its false default"; behaviour unchanged (F7 writes false explicitly), wording now stale — joins the #95 remainder |
Landing: under the maintainer's merge authorization (project thread: 「你可以自己审核的就自己合并」).
Generated by Claude Code
This was referenced Oct 25, 2026
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 #96 — ruling step 2 (code): at most one current version per contract, new versions default current
Clause-②: no
Metadata-protocol: none
Ruling-ref: issue comment 6395827965 (letters 1A 2A), carrying out the plan in os-dev-report 6093639240. Ruling step 1 (the
DESIGN.md§03 line and thedocs/design/00§5.5 guard wording) touches governed files, so it is not in this PR. The maintainer edits those files separately, and #96 remains open for that half.What changed
src/objects/contract-version.hook.ts(new): acontract_version_currenthook onclm_contract_version. It runs onafterInsertandafterUpdatewithrunAs: 'system', re-reads the committed row, and does nothing unless that row is current. Then:final_signedrow: every other current version of the same contract is un-marked.final_signedrow: it keepsis_current: trueonly while it is the contract's only version, which is the F16 backfill case. If the contract has other versions, the row is storedfalseand the other versions are left alone. This means filing an executed copy never takes the flag off the clean version, sosigning → approvedcan still be re-entered.deviation_gate.is_current: false, and it returns at the first check for those.src/objects/hooks.ts: registers the new hook.src/objects/contract-version.object.ts:is_currentnow hasdefaultValue: true(it wasfalse), and the comments explain the rule. There is no change to schema shape, seed or translations. The field's help text is unchanged.contract.hook.tsis not touched.Evidence (HTTP and browser)
Two
pnpm demoboots, each on a clean.objectstack/dataand the same 18.1.0 lockfile: this branch at8b3c6f0, andmainat7b736a0for the before picture. HTTP checks used/api/v1/data. Browser checks used Playwright with Chromium at/opt/pw-browsers/chromium. The rows below were read back withGET /api/v1/data/clm_contract_version?filter={contract}.Before (
main7b736a0):POSTv1cleanwith nois_currentkey → storedis_current=false.PATCH status: signing→422 INVALID_STATE "A current clean version is required before signing."draftand v3clean, both withis_current: true, leaves both current:v1 false, v2 true, v3 true.aria-checked=false.After (this branch):
aria-checked=true(screenshot taken). This was the same for the dev admin and for the requester.POSTv1cleanwith no key →v1 true.internal_redline→v1 false, v2 true.clean→v1 false, v2 false, v3 true.cleanthrough the form on NDA-2026-0012 (POST /api/v1/data/clm_contract_version → 201) givesv1 clean false, v2 final_signed false, v3 clean true. The Versions list shows the check only on v3./api/v1/auth/admin/create-userwithpermissionSet: clm_requesterand holds create but not edit on versions.POSTv1draft→v1 true.POSTv2internal_redline→v1 false, v2 true. Read back as admin, the result is the same.PATCHof v1{is_current: true}→403 PERMISSION_DENIED. This shows the un-marking only works as a system write.cleanthrough the form (201) →v1 false, v2 false, v3 true.final_signed:POSTv2final_signedwith no key → storedv2 false, andv1 cleanstaystrue. A laterPATCHof v2{is_current: true}→200, and it reads backfalsewith v1 stilltrue.POSTv1final_signedwith no key →v1 true, because it is the only version. A later v2clean→v1 false, v2 true.PATCH status approved → signing→200. In the browser, Start Signing on NDA-2026-0012 sendsPOST /api/v1/actions/clm_contract/start_signing → 200 {"success":true}, and the status reads backsigning.signing, inserting a completed wet-inkclm_signatureruns F7, which files v5final_signedwith its explicitis_current: false. Read back:v3 clean true, v4 counterparty_redline false (explicit false on insert, kept), v5 final_signed false.signing → approved→200, andapproved → signingagain →200.Boot log. The same warning set appears on both boots. Timestamps, random ids and ports were normalised; seed-row ids and record indexes were masked. The boot-only section runs up to the seed summary. Main has 249 unique lines and the branch 248.
diffshows exactly one extra line, on main:Port 3097 is in use — serving on 3098. A stray process of mine caused it, not the code. The branch boot adds no warning. The compiled artifact showscontract_version_currentwas lowered to a body, not bundled.Browser console on the contract page is the same on both trees: one 404, one 401, and five
[object-ui] conditional predicate failed to evaluatewarnings for header actions.Gates (on
8b3c6f0, each exit code captured before any pipe)Acceptance notes
clm_contract_versionrow, replaceis_current booleanwith:is_current boolean(每份合同至多一个当前版本:标记一个即取消其余,hook 强制,各入口一致;新的谈判版本默认为当前;final_signed 不夺取当前标记).The same edit aligns the
docs/design/00§5.5 guard wording.src/flows/signature-record.flow.ts's comment atcreate_final_versionsaysis_currentis "deliberately left at itsfalsedefault". The flow writesis_current: falseexplicitly, so its behaviour is unchanged (measured in (f)). Only the words "itsfalsedefault" no longer describe the field. The file is outside this card's declared surface, so it is not edited here. Carrier: none.POST /api/v1/actions/clm_contract/executed_uploadand/api/v1/automation/executed_upload/triggerboth answered403 "This caller may not start this flow"for the dev admin (the action route afterclm_adminwas granted to it). The (d) "only version keeps the flag" rule was measured with the same write F16 makes (afinal_signedv1 inserted on a contract with no versions). I did not investigate the 403 further. It is outside this diff, and I have not reproduced it as a user would through the Console button.403onGET /api/v1/data/sys_approval_request(the Approvals tab). This diff touches no page or permission. I did not compare it on main. Noted, not filed.origin/mainby Turn on the platform's scheduled work forpnpm demo; README says how a deployment does the same #111 only (README.mdandscripts/demo.mjs), with no overlap and no conflict.🤖 Generated with Claude Code
https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn