From b8b8075268c248dfd631fdd6c1617a82f2eb1467 Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 26 Oct 2026 04:53:31 -0500 Subject: [PATCH] test(server): qualify reassessment backlog and history costs Co-Authored-By: Paperclip --- ...2026-10-24-recurring-server-sleep-stack.md | 12 ++++ ...-native-status-reassessment-sleep-audit.md | 63 +++++++++++++++++++ .../native-status-reassessment-work.test.ts | 33 ++++++++++ 3 files changed, 108 insertions(+) diff --git a/doc/plans/2026-10-24-recurring-server-sleep-stack.md b/doc/plans/2026-10-24-recurring-server-sleep-stack.md index 445a351c558..7dee3ce8faf 100644 --- a/doc/plans/2026-10-24-recurring-server-sleep-stack.md +++ b/doc/plans/2026-10-24-recurring-server-sleep-stack.md @@ -2566,3 +2566,15 @@ The audit retains before/after evidence and the remaining handoff/authority coverage limits. Master is freshly verified at 1fbbef45a8. Discovery/cost proof, startup wiring, periodic removal, remote acceptance, earlier stack findings and the full original recurring-work scope remain incomplete. Nothing merged. + + +Slice 50 scale checkpoint: 10,000 separate selected completed task/run histories +produce zero company candidates (~35 ms); 10,000 actual candidates reconstruct +in 101 bounded queries (~1.56 seconds/2.05 MB), with verified drain/abort behavior. +A retired-review task with large review/comment/approval/dependency/workspace +history settles in ~126 ms and disappears from discovery. The audit preserves +two invalid benchmark-fixture attempts and the corrected fresh-task evidence. +A permanent 103-item backlog test proves real settlement and SQL quiet; all 31 +lifecycle cases and server types pass. Remaining producer/authority audit, +startup integration, periodic removal, remote gates and the full original stack +scope remain open. Nothing merged. diff --git a/doc/plans/2026-10-26-native-status-reassessment-sleep-audit.md b/doc/plans/2026-10-26-native-status-reassessment-sleep-audit.md index 78e730c29dd..a3e731e8c0e 100644 --- a/doc/plans/2026-10-26-native-status-reassessment-sleep-audit.md +++ b/doc/plans/2026-10-26-native-status-reassessment-sleep-audit.md @@ -827,3 +827,66 @@ Remaining acceptance continues to include producer/authority audit, discovery and commit costs, backlog and lifecycle coverage, startup registration, periodic removal, PR publication and exact-head remote gates. The full original stack scope and older unresolved gates remain active. + + +## Selected-history, backlog and commit cost checkpoint (2026-10-26) + +The earlier same-task/superseded-decision benchmark did not establish discovery +cost for selected current history. A dedicated PostgreSQL 17 database now holds +10,000 separate task/run/contract/result/assessment/decision/product bindings. +Every task initially selects its own completed decision; accepted products predate +the assessment. This is distinct from 10,000 obsolete decisions on one task. +Fixture: /tmp/sleep50-scale-fixture.sql and .log/.status; database +paperclip_sleep50_scale_20261026_test (snapshot of the completed corpus database, +plus a separate synthetic company). All fixture inserts and measurements are +local disposable test data, never deployed/customer data. + +At source 51f305f1d1 with the new backlog regression pending: +- Startup discovery: 98.7 ms, three queries, 246 candidates from the original + corpus fixtures. None of the 10,000 completed synthetic tasks was a candidate. +- Synthetic company: zero candidates, one query, 34.8 ms (warm EXPLAIN execution + 33.5 ms); exact task/run scopes: one query each, about 1.8/2.1 ms. +- Changing all synthetic tasks' authoritative status creates 10,000 actual + reassessment candidates. Reconstruction: 101 keyset queries, 1.56 seconds, + approximately 2.05 MB serialized entries. This is total startup/backlog cost, + not a constant-space claim; the coordinator retains outstanding entries. +- Drain after two pages stops at two queries; an already-aborted request makes + zero queries. Interruption is between pages, not cancellation of an active SQL. +- First/last backlog entries both commit real reassessments, disappear from + scoped discovery, and do not replay: 37/36 SQL statements, about 32/15 ms. + +Evidence: /tmp/sleep50-scale-measure.mts, .log/.status (exit 0), and +/tmp/sleep50-scale-{startup,company,issue,run}.plan. No new index was justified by +this selected-history measurement. It is local PostgreSQL evidence, not a remote +network latency or fleet savings claim. + +A second fixture exercises retired-review reassessment with 10,000 resolved +interactions, 10,000 comments, 10,000 linked approved approvals, 1,000 completed +prerequisites sharing a workspace, and 10,000 successful workspace operations. +One historical question forces the comment source-lock path too. Scoped discovery +is one query/about 5.9 ms; complete guarded reassessment uses 83 SQL statements +(including nine NOWAIT queries), takes about 126 ms, completes the task, and then +returns zero candidates. Source locks are scoped to this task and its referenced +prerequisites/workspaces; work grows with that history. The measurement does not +assert that a remote database round trip has the same cost. + +Two failed benchmark attempts are retained. The first manually assigned version +2 while a status-update trigger advanced the actual version to 4, so it measured +the stale-status path and failed the intended completion assertion. A repair that +rewound that already-processed fixture then reused its existing append-only +assessment and hit status_decisions_company_assessment_uq. Neither failure was +waived or changed in production code. A fresh untouched task with the actual +trigger-generated version exercised the intended retired-review path. Evidence: +/tmp/sleep50-task-history-measure.log/.status and +/tmp/sleep50-task-history-final.log/.status (failures), fixture/repair logs under +/tmp/sleep50-task-history-*, and /tmp/sleep50-task-history-fresh.log/.status (exit 0). + +The permanent lifecycle suite now seeds 103 actual retired-review obligations, +verifies full discovery, one-page stop on admission loss, zero-query abort, +coordinator dispatch across batches, exactly one additional decision per task, +no rediscovery, and SQL quiet after settlement. All 31 lifecycle cases pass against +retained history, and server typecheck passes: +/tmp/sleep50-scale-lifecycle.log/.status and /tmp/sleep50-scale-types.log/.status. +All handles are terminal. Startup registration/periodic removal, remaining +producer/authority audit and remote acceptance still remain; the full stack +objective and its earlier unresolved gates are not complete. diff --git a/server/src/__tests__/native-status-reassessment-work.test.ts b/server/src/__tests__/native-status-reassessment-work.test.ts index 161752a132d..45d54f924b3 100644 --- a/server/src/__tests__/native-status-reassessment-work.test.ts +++ b/server/src/__tests__/native-status-reassessment-work.test.ts @@ -125,6 +125,39 @@ describe("native reassessment worker lifecycle", () => { return { issueId, runId, workProductId, decisionId: committed.decision.id }; } + it("bounds discovery by pages and drains a real reassessment backlog to SQL quiet", async () => { + const backlog = []; + for (let index = 0; index < 103; index++) { + const seeded = await seedReview(); + await dismissAutomaticCompletionReviews(db, seeded.issueId); + backlog.push(seeded); + } + const work = nativeStatusReassessmentWork(db), scope = { companyId }; + const expected = new Set(backlog.map(row => row.runId)); + const discovered = await work.load(scope); + expect(discovered.filter(row => expected.has(row.id))).toHaveLength(103); + const debug = db.$client.options.debug; + let queries = 0, admissionChecks = 0; + db.$client.options.debug = (_id, query) => { + if (query.startsWith("select") && query.includes("native_run_finalizations")) queries++; + }; + try { + await expect(work.load(scope, undefined, () => ++admissionChecks <= 1)) + .rejects.toThrow("Native status reassessment discovery stopped"); + expect(queries).toBe(1); + queries = 0; + await expect(work.load(scope, AbortSignal.abort())).rejects.toThrow("Native status reassessment discovery stopped"); + expect(queries).toBe(0); + } finally { db.$client.options.debug = debug; } + await start(); await flush(); + for (const seeded of backlog) { + expect(await status(seeded.issueId)).toBe("done"); + expect(await db.select().from(statusDecisions).where(eq(statusDecisions.issueId, seeded.issueId))).toHaveLength(2); + } + expect((await work.load(scope)).filter(row => expected.has(row.id))).toEqual([]); + await quiet(); + }, 60_000); + it("waits quietly for physical workspace ownership to release before reassessment", async () => { const seeded = await seedReview(); await dismissAutomaticCompletionReviews(db, seeded.issueId);