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 #41

Description

@zhuangjianguo

Found while browser-verifying card 09 (#39). Not a defect in the jobs — a consequence of them existing that the seed does not account for. Filed unassigned, out of scope for #39.

The documented workflow that now breaks

README.md tells the evaluator to re-run the demo:

Every dataset is an upsert, so create the accounts and run pnpm demo again and their contracts are handed over.

That works on a freshly seeded database. It stops working once card 09's daily jobs have run once, because those jobs are the declared writer of two statuses the fixture also declares, and the state machines refuse the way back.

Reproduction, measured on claude/issue-39-post-signature-jobs @ 83eda0a, 17.4.0, better-sqlite3

  1. pnpm demo on an empty database — 820 ok / 0 errors.
  2. Run the sweeps once each: POST /api/v1/automation/expiration_sweep/trigger, POST /api/v1/automation/payment_overdue/trigger.
  3. pnpm demo again.

Boot banner on step 3:

⚠ Seeds:   app.objectstack.hotclm 818 ok / 2 errors ⚠
  ✗ Failed to write clm_contract record #99 (title=Data Processing Agreement — Fernway Cleaning):
    hook 'contract_state_machine' threw: A expired contract is closed; its status cannot
    change to active. Start a renewal or an amendment instead.
  ✗ Failed to write clm_payment_plan record #2 (contract+seq=["…","3"]):
    hook 'payment_plan_state_machine' threw: Payment instalment status cannot go from
    overdue to planned. Allowed from overdue: partial, paid.

Two rows are dropped and every other row still loads, so the run looks almost clean — the same "the summary reads like a clean load" shape #39's acceptance criteria warn about.

Why it happens

The fixture writes status as a literal on every upsert. Once a job has moved a row on:

  • expiration_sweep (F13) moves an active contract past its end date to expired. §03 makes expired terminal, so re-asserting the fixture's active is refused.
  • payment_overdue (F11) moves a due or partial instalment past its planned date to overdue. §03 gives overdue only → partial / → paid, so re-asserting planned is refused.

Both refusals are correct: the state machines are doing exactly what DESIGN.md §03 asks. It is the fixture's unconditional status that has no answer for "this row has since moved on".

The two rows are the ones whose dates the jobs act on, so the count grows as the demo database ages: any contract that expires and any instalment that falls into arrears joins the set.

What a fix has to decide (hence: not a rider on #39)

Whichever way it goes it is a change to card 08's seed, and it needs a product answer first:

  • A — leave status out of the upsert on re-seed. The fixture stops fighting the jobs, and a demo database shows the lifecycle actually moving. Costs the guarantee that pnpm demo restores a known corpus.
  • B — re-seed onto a clean database only, and say so in the README instead of promising re-runnability. Cheapest, and honest, but it takes away the account-handover workflow the README currently recommends.
  • C — keep the promise and make the seed reset the row first (overdue → paid → … is not reachable either, so this means a system-context reset, not a transition). Most machinery, and it puts a second writer on the columns Card 09 — F9 activation · F3/F4/F10–F14 scheduled jobs · F16 executed upload (M3) #39 gave exactly one.

I have no view worth acting on between them; A looks smallest but it changes what "the demo dataset" means, which is a §10 question.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions