Skip to content

Header lifecycle actions succeed and the contract page keeps showing the old status and the old button until a manual reload - #105

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-94-header-action-refresh
Oct 25, 2026
Merged

zhuangjianguo merged 1 commit into
mainfrom
claude/issue-94-header-action-refresh

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #94

What changed

src/actions/contract-lifecycle.actions.ts: transition() now sets refreshAfter: true. All five header status transitions use it: Submit, Accept for Review, Send for Approval, Start Signing and Activate. That is one line plus a comment, +8/-0.

Mechanism (measured, card lead confirmed): @objectstack/spec 17.7.0 declares refreshAfter: z.boolean().default(false) (ui/action.zod.ts:1385, materialized at parse). The record page re-reads the record only when it is true. Terminate and Start Renewal already set it, and the five transition() actions did not. This is the app not asking for a refresh. It is not a Console defect, so no platform issue applies. After the change, GET /api/v1/meta/actions serves refreshAfter: true on submit_contract, accept_contract, send_for_approval, start_signing and activate_contract.

Browser readings

Setup: pnpm demo --port 3194 from the worktree, signed in as admin@objectos.ai. Before the run, the dev admin got the clm_admin and clm_legal_counsel positions (POST /api/v1/data/sys_user_position, 201 each) so it could see every gated button. Playwright drove the pre-installed Chromium. On each contract page the script read the current stage ([aria-label="Record path"] [aria-current=step]) and the visible header action buttons, pressed the action, waited 5 s and read them again, then reloaded and read them a third time.

The seeded demo rows fail the state machine's own guards: no version, no legal owner, no approved legal review, no completed signature round, no final_signed version. The first presses answered 422 INVALID_STATE for that reason. The missing child rows were added through the data API (an uploaded sys_file for each version), and every row below is a 200 press.

Before (main @ 449667e):

Action Contract POST answer Toast Header after press (no reload) Header after reload Record re-read after press
Submit 6xV7nvX2HtijCn6b 200 {"success":true} Action completed successfully Draft · [Submit] In Review · [Send for Approval] none
Accept for Review 1EILupHlYfR5I5UA 200 {"success":true} Action completed successfully Submitted · [Accept for Review] In Review · [Send for Approval] none
Send for Approval R6oj7Y7eZJT4sX76 200 {"success":true} Action completed successfully In Review · [Send for Approval] In Approval · [] none
Start Signing Ik_RcazGdUz3a2tz 200 {"success":true} Action completed successfully Approved · [Start Signing] Signing · [Activate] none
Activate juglMfyiqvc2jdR_ 200 {"success":true} Action completed successfully Signing · [Activate] Active · [Terminate, Start Renewal] none

After (this branch, same server with the watcher's rebuild and restart):

Action Contract POST answer Toast Header after press (no reload) Header after reload Record re-read after press
Submit h_0Ue-yWMqvOpLd_ 200 {"success":true} Action completed successfully In Review · [Send for Approval] In Review · [Send for Approval] GET /api/v1/data/clm_contract → 200
Accept for Review 5NW-RLdRdf7QWLR3 200 {"success":true} Action completed successfully In Review · [Send for Approval] In Review · [Send for Approval] GET /api/v1/data/clm_contract → 200
Send for Approval 1EILupHlYfR5I5UA 200 {"success":true} Action completed successfully In Approval · [] In Approval · [] GET /api/v1/data/clm_contract → 200
Start Signing vdt8ulrQ9oNghIaM 200 {"success":true} Action completed successfully Signing · [Activate] Signing · [Activate] GET /api/v1/data/clm_contract → 200
Activate ndw0vjMF8PTBaRg2 200 {"success":true} Action completed successfully Active · [Terminate, Start Renewal] Active · [Terminate, Start Renewal] GET /api/v1/data/clm_contract → 200

After the press, the header matches the post-reload header in every case. Submit lands on In Review rather than Submitted because F2's onward hop runs in the same write: the dev admin now holds a legal-counsel position, so routing assigns it.

Browser console for every successful press, before and after: no errors. The only error lines in either run came from the 422 fixture presses (Failed to load resource: … 422). Each page load also logs the same 9 warnings, identical before and after: 2 component-registry bare-name fallback warnings, plus 7 [object-ui] A conditional predicate failed to evaluate (page:header action "…" visible) … No such key: status, one per header action. See the acceptance notes.

Boot: both boots printed ✓ Server is ready with no degraded capabilities, no no such table and no plugin load failure. The warnings were author-time approval-approver notices, scheduled flows unbound by deployment policy, the seed's deferred-reference notices (the demo personas are not created), and the plain-HTTP OAuth notice. Each server was stopped by process group.

Gates (worktree, 4239466, each exit code captured before any pipe)

pnpm validate: exit 0

  ✓ Validation passed (747ms)

pnpm lint: exit 0

  6 suggestion(s) (697ms)
  platform built-ins: 1132 i18n issue(s) hidden — rerun with --include-platform to audit them

pnpm typecheck: exit 0

> hotclm@0.1.0 typecheck /home/claude/hotclm-issue-94
> tsc --noEmit

pnpm lint:i18n-gate: exit 0

✓ i18n gate
  COVERAGE : 0 missing keys across 2 locale(s)

Acceptance notes

  • Observation, not filed: on every contract page load the Console logs one A conditional predicate failed to evaluate (page:header action "X" visible) … [runtime] No such key: status warning per header action. That is 7 per load, on main and on this branch alike. The buttons still resolve correctly once the record is loaded, as both tables show. It looks like the predicates are evaluated once before the record arrives. The cause is in the Console, this change does not touch it, and it is out of scope for this card.

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn

Submit, Accept for Review, Send for Approval, Start Signing and Activate
answered 200 {"success":true} and toasted success, but the record header
kept the old stage and the old button until a manual reload. The spec
defaults `refreshAfter` to false (materialized at parse) and the record
page re-reads the record only when it is true; Terminate and Start
Renewal already set it. `transition()` now sets it for all five.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · head 4239466 · 2026-10-25T02:55Z

check reading
shape draft → main, line 1 Fixes #94, no other closing keyword in the body; assignee zhuangjianguo
CI on the head both Validate check-runs success on 4239466 = PR head.sha
scope 1 file, src/actions/contract-lifecycle.actions.ts (+8/−0) = the claimed surface; nothing governed
the fix transition() now sets refreshAfter: true on all five lifecycle buttons; Terminate / Start Renewal already did
premise held: @objectstack/spec 17.7.0 defaults refreshAfter to false; the dev measured the record page re-reading the record only when it is true
browser (dev's readings) before: 5/5 presses 200 {"success":true}, header stale until reload, no record GET; after: 5/5 header updates in place, each followed by GET /api/v1/data/clm_contract 200; same 9 console warnings before and after
forward-compat the key is unchanged in @objectstack/spec 18.1.0 (ui/action.zod.ts:1401, z.boolean().default(false)), so the pending 18.1 upgrade does not invalidate it
deviation accepted the commit trailer names the model; it is the session's required attribution line, kept
out of scope the 7-per-load No such key: status predicate warnings → Acceptance notes, carrier: none (no user-visible defect measured)

Landing: under the maintainer's merge authorization (project thread: 「pr 你审核之后可以帮我合并」).


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Header lifecycle actions succeed and the contract page keeps showing the old status and the old button until a manual reload

2 participants