Skip to content

pnpm demo stops being re-runnable once the daily jobs have run: the seed re-asserts statuses the state machines refuse to go back to - #176

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-41-seed-apply-on-create
Oct 27, 2026
Merged

zhuangjianguo merged 1 commit into
mainfrom
claude/issue-41-seed-apply-on-create

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #41
Clause-②: no
Metadata-protocol: none

Ruling-ref: comment 6395830052 (letter A), step 3. The platform card objectstack-ai/objectstack#25761 shipped in 18.2.0 (493a6c4, columns.FIELD.applyOn: 'create' on defineSeed), and main pins 18.2.0 (PR #155). Session session_017nzWFRUo2U7evMkPdVniAn, branch claude/issue-41-seed-apply-on-create, head ab8a2af.

What changed

src/data/contract.seed.ts. columns declares these 18 contract columns applyOn: 'create':

  • status, is_expiring, is_backfilled
  • route_legal_head, route_finance, route_executive, route_gm, approval_status
  • submitted_at, review_started_at, approved_at, signed_at, executed_at, activated_at, closed_at
  • termination_reason, archive_no, archived_at

The set starts from the single-writer family that contract.object.ts documents: "stage timestamps and routing flags … the state machine and the F2/F5/F9–F14 flows", plus is_backfilled (F16). Card 09's jobs are among those writers: F12 writes is_expiring, F13 moves status to expired, F9 stamps activated_at and F14 stamps archived_at. Three more columns are written in the same write as a transition, so they are in the set too: status, termination_reason (Terminate) and archive_no (the number that stamps archived_at). These columns move as one set. A create-only status beside an always approved_at would let a re-run blank the stamp on a contract someone has approved since.

owner_id and legal_owner stay always. They are how the book is dealt to the demo staff.

src/data/post-signature.seed.ts.

  • Obligations: status (F10 writes overdue) and completed_at (stamped on done).
  • Payment instalments: status (F11 writes due and overdue), plus the receipt that partial / paid records: actual_date (stamped by the state machine), actual_amount and invoice_no.

README. "The demo dataset" makes the re-run promise again: it runs after the jobs and after desk work, puts deleted rows back, and does not turn the clock back. Three stated limits:

  • other edited columns revert to the fixture;
  • a decided deviation or signature round is not covered;
  • lifecycle stamps keep their dates while the fixture dates slide forward.

Stale comments. keys.ts (DEMO_USER, CONTRACT_OWNERS, LEGAL_OWNERS, obligationOwnerOf, deviationDeciderOf), contract.seed.ts (owner_id), negotiation.seed.ts (reviewer) and plan-contracts.ts (the rung-1 rationale and the TERM_ENDED_YESTERDAY_PER_BRANCH ⚠️ note) still said "the operator creates the accounts and runs pnpm demo again". They now say that since #171 the platform creates the demo staff before the seed runs.

clm_review.reviewer still names the Dev Admin. This PR does not change it (see Acceptance notes).

Measured: one sequence, origin/main 0159171 against this branch, @objectstack 18.2.0, better-sqlite3, port 3153

Harness (stated as the seat directed). On 18.2.0 the daily jobs cannot be started on demand: POST /api/v1/automation/{obligation_due,payment_overdue,renewal_notice,expiration_sweep,legal_review_sla,turn_stalled}/trigger as the dev admin answers 403 PERMISSION_DENIED "This caller may not start this flow. A flow that runs on its own trigger starts there, or as a sub-flow from a parent flow's subflow node." (objectstack#25643, flow-start-admission.ts). The jobs were therefore fired on their own schedule trigger. A measurement-only edit of src/flows/_daily-sweep.ts:108 set the cron to '* * * * *', which covers all six sweeps, including expiration_sweep's 0 7 * * *. The edit was never committed: it was reverted before each re-run boot and before the commit, and git diff HEAD -- src/flows is 0 bytes. All six sweeps fired (sys_job last_status: success).

Sequence on each tree:

  1. Fresh pnpm demo with the harness.
  2. The six sweeps fire.
  3. Second leg, as the personas: counsel2 terminates Master Services Agreement — Cobalt Pharmaceuticals (Terminate action). records@ archives Supplier Agreement — Beacon Print & Packaging. finance@ marks Lease Agreement — Granite Facilities Post-signature domain: clm_obligation, clm_payment_plan, and the contract roll-ups (card 03, M1) #3 paid. clm.admin@ deletes one obligation and one instalment.
  4. Stop the server, revert the harness, and run pnpm demo again on the same database (--log-level info).
  5. Boot again with the harness, to see whether F12 and F11 re-notify.
reading main this branch
step 1 seed inserted 830, errored 0 inserted 830, errored 0
after the jobs (step 2) instalments overdue 12 → 30 (18 partial flagged) · 1 contract expired (F13) · 1 auto-renew draft · is_expiring true 13 → 14 identical
re-run summary (step 4) WARN [Seeder] Seed loading completed with 3 dropped record(s) and 3 error(s) … {"inserted":2,"updated":20,"skipped":805,"errored":3} INFO [Seeder] Seed loading complete {"inserted":2,"updated":0,"skipped":828,"errored":0}
refused rows ✗ … Master Services Agreement — Cobalt Pharmaceuticals: A terminated contract is closed; its status cannot change to active. · ✗ … Mutual Non-Disclosure Agreement — Basalt Energy: A expired contract is closed; its status cannot change to active. · ✗ clm_payment_plan record #262 …: A paid instalment is settled; its status cannot change to due. none (ERROR [SeedLoader] lines: 0)
F11's 18 instalments overdue → partial ×18 (overdue 30 → 12), silent stay overdue (30)
F12's flag Independent Contractor Agreement — Aisha Bello is_expiring true → false stays true
records' archive archive_no "ARC-41-TEST" → null, archived_at → null: the archive is undone, silently kept
user-deleted obligation and instalment re-created (inserted 2) re-created (inserted 2)
step 5, F12 renewal_notice … selected=25 acted=1: notice count 1 → 2 (re-sent) selected=22 acted=0: notice count stays 1
step 5, F11 payment_overdue … acted=18: clm_payment_overdue 18 → 36 (re-sent) count stays 18

The step 3–4 diff was taken row by row by id (end_date, planned_date and due_date excluded, since they slide by design). Beyond the rows above, main changed nothing else, and the branch changed nothing at all except re-creating the two deleted rows.

Read as the personas in the browser (Chromium /opt/pw-browsers/chromium, zh-CN, signed in through the Console form, branch after the re-run):

  • finance@example.com: overdue instalments total 30, partial 0.
  • counsel2@example.com: the Cobalt contract is terminated, its reason is kept and closed_at is set; the Basalt NDA is expired.
  • records@example.com: the Beacon contract is expired, ARC-41-TEST, archived_at set.
  • Console errors: the pre-login 401 session probe on each sign-in, plus one 404 resource for finance. No error from the pages read.

NOT MEASURED: the requester marking an obligation done. PATCH clm_obligation as requester2@example.com answered 403 "[Security] Access denied: update on 'clm_obligation' requires edit access to its master record (master 'clm_contract' not editable by this user (row-level security))". No alternate route was taken. completed_at create-only is therefore argued from the state machine, not measured.

Gates (worktree hotclm-issue-41; the bytes were then committed unchanged as ab8a2af; each exit code was captured before any pipe)

  • pnpm install → exit 0
  • pnpm validate → exit 0, ✓ Validation passed (1104ms)
  • pnpm lint → exit 0, 6 suggestion(s), 0 warnings, none in src/data
  • 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 (1341ms). This parses the 24 columns keys through defineSeed and SeedSchema; a misspelt key would be refused here.

Acceptance notes

  • clm_review.reviewer still names the Dev Admin. Legal Counsel 1/2 now exist when the seed runs, but the right reviewer depends on the review stage. Legal and compliance would go to the counterparty's counsel. Finance would arguably go to the Finance Controller. Business would go to the requester. scripts/demo.mjs (outside src/data) also mirrors DEMO_USER as the one name it verifies before seeding. So this is not a one-line change, and it is reported rather than made. The comments now say it is open.
  • Residual, not covered by this card. A user decision on a seeded deviation (open → accepted) or signature round is still re-asserted by a re-run, and the state machine may refuse it. This was not measured; the README states it as a limit.
  • Trade-off, stated in the README. The create-only stamps keep the dates they were written with, while start_date, end_date, due_date and planned_date slide forward on each re-run.

🤖 Generated with Claude Code

https://claude.ai/code/session_017nzWFRUo2U7evMkPdVniAn

…sks wrote

The demo datasets now declare the lifecycle columns `applyOn: 'create'`
(@objectstack 18.2.0, objectstack#25761): `status` on contracts,
obligations and payment instalments, `is_expiring`, the stage timestamps
and routing flags, `approval_status`, `is_backfilled`,
`termination_reason`, the archive number and stamp, an obligation's
`completed_at` and an instalment's receipt. The seed writes them when it
creates a row and leaves them alone on a row a re-run matches.

Before, a re-run after the daily jobs walked F11's 18 overdue instalments
back to partial, reset is_expiring so F12 re-sent its notice, and had the
state machines refuse (and drop whole) a contract F13 had expired or legal
had terminated. README states the re-run promise again, with its limits.

Also rewrites the src/data comments that still told the operator to
create the demo accounts and re-run: since #171 the platform creates them
before the seed runs.

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

Copy link
Copy Markdown
Contributor Author

席位核对 — ACCEPT · head ab8a2af · 2026-10-27T11:18Z

check reading
shape draft → main, Fixes #41; mergeable clean
CI on the head both Validate check-runs success on ab8a2af = PR head.sha
scope 6 files (+159/−71), all in src/data/ plus README.md. 24 lifecycle columns get applyOn: 'create' (objectstack#25761, shipped in 18.2.0): 18 on clm_contract as one set, status + completed_at on clm_obligation, and status, actual_date, actual_amount, invoice_no on clm_payment_plan. legal_owner / owner_id stay always, so a re-run still re-deals the book. Nothing governed
the defect measured. On main a second pnpm demo gave {updated 20, errored 3}, with 18 overdue→partial reversals. On the branch it gave {updated 0, errored 0}: job-written values were kept, deleted rows came back, and F12 was not re-sent
README the re-run promise is back, with its three limits stated: lifecycle columns keep their stamped dates while fixture dates slide forward; deleted rows return; staff are re-dealt
stale comments keys.ts, contract.seed.ts, negotiation.seed.ts and plan-contracts.ts now describe demo staff (PR #171), not the two-boot handover
left open the deviation and signature status re-assert was not measured and is noted in the PR. Whether clm_review.reviewer should name a lawyer instead of the dev admin is open and goes to #19's dev. Neither blocks this card

Landing: under the maintainer's merge authorization (project thread: 「你可以自己审核的就自己合并」).


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.

pnpm demo stops being re-runnable once the daily jobs have run: the seed re-asserts statuses the state machines refuse to go back to

2 participants