Skip to content

Commit 08d201a

Browse files
test(dogfood): the persona matrix hangs its invoice lines off an unpaid invoice (#24832)
Refs #24780 Clause-②: no **This is row 3 of #24780** (triage pointer `6286191020`): the stale fixture in `showcase-crud-persona-matrix.dogfood.test.ts`. Row 1 is PR #24805, which landed as `c56115bf9`. Row 2 belongs to #24749. #24780 remains open: the PM closes it once rows 1 and 3 have both landed. ## What changes One fixture line in `packages/qa/dogfood/test/showcase-crud-persona-matrix.dogfood.test.ts`, in `beforeAll`: - **Before:** `seed.invoiceId = await firstId('showcase_invoice')`, which takes whichever invoice a `limit: 1` read returns first. - **After:** the first invoice whose `status` is not `paid`. That is the state the showcase's paid-invoice line lock reads (the `showcase_guard_paid_invoice_line_*` hooks test `header.status === 'paid'`). It follows the pattern of the `[#18682]` account choice directly above it, and the new comment explains why. The lock from PR #24731 is unchanged. This PR changes no case assertion, no other dogfood file, and nothing under `examples/app-showcase/**` or `packages/spec/**`. ## Why - The admin payload control creates a `showcase_invoice_line` under `seed.invoiceId` and asserts a status below 300. Since PR #24731, the showcase refuses a line insert under a paid invoice with a 400: "This invoice is paid, so its lines are locked: a line cannot be added to it." - `firstId` does not pick the same invoice each time. On `ab9890169` I measured three boots. The `limit: 1` read returned INV-1012 (sent), then INV-1008 (sent), then INV-1005 (paid). The ids are random and differ on every boot. The unlimited read returned insertion order every time, with INV-1001 first. The seed holds 12 invoices, and 5 of them are paid. So the control fails on some boots and passes on others. - CI shows the same pattern. Shard 3/3 on `74f78159af` was red in push run 39376439272 and green in schedule run 39378039597. On `a43405d596` it was red in schedule run 39384364728. I also read four `main` runs from before `576d0f3733`, and shard 3/3 was green in all of them. ## Evidence Every run used `pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 FILE` under `os-verify-lock`, after building the closure with `turbo run build --filter='@objectstack/dogfood^...'`. This file belongs only to the `isolated` project. The gate runs `turbo run test --filter=@objectstack/dogfood` with `OS_TEST_SHARD=k/3`. On an unmodified file, red or green comes down to which invoice the boot happens to draw. So the red/green comparison uses an uncommitted scratch copy whose only change forces the parent to a paid invoice (`where: { status: 'paid' }`): | tree | parent | result | |---|---|---| | `4e0f5f50d` (`576d0f3733^`) | forced paid | `Tests 46 passed (46)`, VERDICT command-exit 0 | | `576d0f373` (PR #24731) | forced paid | FAIL: "admin control: the showcase_invoice_line payload is VALID (...) got {"error":"This invoice is paid, so its lines are locked: a line cannot be added to it.","object":"showcase_invoice_line"}: expected 400 to be less than 300", VERDICT command-exit 1 | | `ab9890169` (`main`, the base) | forced paid | the same FAIL at the assertion CI cites (`:369`), VERDICT command-exit 1 | | `8c65e505a` (the fix) | the fix | `Tests 46 passed (46)`, VERDICT command-exit 0 | | `0503d47c6` (final head, `main` merged) | the fix | `Tests 46 passed (46)` on each of two runs | Only `examples/app-showcase`, a changeset and one docs file differ between the two bisect trees, and the dogfood suite loads the showcase from source. So a single built closure served both legs, and the matrix file is byte-identical across the pair. **Which lines hang off a seeded invoice.** I ran a probe on `8c65e505a`: a scratch copy with one extra reporting case, not committed. Only `showcase_contributor` creates a line. That persona's `showcase_invoice` row runs first, and its line hangs off its own invoice, whose status is `draft`. The only line under a seeded invoice is the admin control's, so fixing this one parent fixes every place in the file with this cause. No ablation: product behaviour does not change. ## Gates (final head `0503d47c6`) - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 56 commands from 1 changed path. All 56 ran, each with its exit code captured before any pipe. `--ran`: "56 derived famil(ies) accounted for — 56 run, 0 NOT-MEASURED (a DERIVED zero — all 56 recorded an exit code and none of them is 3)." - `check:dual-build-cjs-loads` first exited 3 (PREREQUISITE NOT MET: 8 packages had no `dist`). I built those 8 and re-ran it: exit 0, "112 published require entry point(s) across 69 package(s) load". - `pnpm lint` (`eslint . --no-inline-config`): exit 0, no findings. - `pnpm --filter @objectstack/dogfood run typecheck`: exit 0. `tsc --listFilesOnly` lists the edited file. - `check-nul-bytes: OK (scanned 12537 text file(s) ...; no raw ASCII control bytes)`. ## Changeset `skip-changeset`: the diff is one test file in `@objectstack/dogfood`, which is `private: true` and publishes nothing. ## Acceptance notes - The file's other seeded parents (`showcase_product`, `showcase_project`, `showcase_expense_report`, `showcase_team`) still use `firstId`, so they are also drawn at random on each boot. Today no rule makes any of those choices refuse a payload, and every pre-lock run I read was green. If a state rule is added to one of those objects, its parent should be chosen the same way. --- _Generated by [Claude Code](https://claude.ai/code/session_01LmjU2x1faLZ39DVTFyVca6)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8a058d8 commit 08d201a

1 file changed

Lines changed: 13 additions & 1 deletion

File tree

‎packages/qa/dogfood/test/showcase-crud-persona-matrix.dogfood.test.ts‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,19 @@ describe('showcase: persona × CRUD-cell matrix (#9481)', () => {
324324
);
325325
seed.productId = await firstId('showcase_product');
326326
seed.projectId = await firstId('showcase_project');
327-
seed.invoiceId = await firstId('showcase_invoice');
327+
// NOT `firstId` either, for the same reason as the account: the showcase
328+
// locks a PAID invoice's lines (its `showcase_guard_paid_invoice_line_*`
329+
// hooks), so a line can be neither added under one nor removed from one.
330+
// `firstId` takes whichever invoice a `limit: 1` read returns, and with
331+
// random ids that is a different invoice on every boot — several seeded
332+
// invoices are paid, so the admin control below failed on some boots and
333+
// not others. Every line this file creates under a seeded invoice hangs
334+
// off this one, so the parent is chosen by the state the lock reads.
335+
seed.invoiceId = String(
336+
(await ql.find('showcase_invoice', {
337+
where: { status: { $ne: 'paid' } }, limit: 1, context: SYS,
338+
}))?.[0]?.id ?? '',
339+
);
328340
seed.expenseReportId = await firstId('showcase_expense_report');
329341
seed.teamId = await firstId('showcase_team');
330342
expect(

0 commit comments

Comments
 (0)