Repository navigation
DRAFT — polis-jobs: the built-in queue sweep (off unless POLIS_JOBS_SWEEP=1; needs 000026, P-083) - #2981
Draft
colinmegill wants to merge 37 commits into
Draft
DRAFT — polis-jobs: the built-in queue sweep (off unless POLIS_JOBS_SWEEP=1; needs 000026, P-083)#2981colinmegill wants to merge 37 commits into
colinmegill wants to merge 37 commits into
Conversation
… functions, views, ledger) — P-078 PR-A Schema change, ruling R-A. No data change: the seed row (version 0, agree_value -1) states today's storage convention, so every reader that consults it computes what it computes today. 000023_vote_convention.sql adds, in one transaction: the vote_convention singleton (updated in place) with its append-only history and a monotonic guard; the schema_migrations ledger with 000000-000022 backfilled as pre-ledger and this file's own row (sha256 of the file without its ledger-marker line); vote_convention_current() (STABLE, SECURITY DEFINER); vote_semantic()/vote_storage() (IMMUTABLE, STRICT); vote_insert() (SECURITY DEFINER, lock_timeout 2 s as a function SET clause, FOR SHARE, expected-version check, the 000006 rule maintains votes_latest_unique); the votes_semantic and votes_latest_unique_semantic views; grants to the 000021 coordinator roles when they exist, recorded in the ledger row. vote_insert is revoked from PUBLIC. Named SQLSTATEs P0780-P0784, P0789. down/000023_drop_vote_convention.sql drops exactly those objects and refuses (P0789) once the convention has moved or a later migration is in the ledger. down/test_000023_down.sh runs 11 cases on a disposable PostgreSQL 17. docs/vote-convention.md: grants, restore-detection rule, runbook, and how the server and engine readers bind to the row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… view grants, ledger checksum CI Review fixes, batched into one change of 000023's bytes: - vote_insert refuses (P0791) when the convention row is missing instead of storing NULL votes; DELETE/TRUNCATE on vote_convention refuse (P0790); TRUNCATE on the history refuses (P0781); a row put back after a forced removal must continue the history (the guard now also runs on INSERT); the guard stamps changed_at/changed_by. - The coordinator observer no longer gets SELECT on the two semantic views (they read votes with the owner's rights). - Catalog comments and the ledger note carry no internal ids. - server/postgres/check_ledger_checksums.py and a CI workflow recompute the self-checksum of every migration from 000023 on; the runbook gains the operator pre-apply check. - docs: the un-flip's precondition (every writer through vote_insert) and the proposed table locks for its preamble; 55P03 scope; READ COMMITTED; pre-ledger rows are asserted, not observed; down-file precondition. - Tests (15): a writer blocked by the flip then writes +1 under version 1; restore detection against the held un-flip file when present; the permanence cases; the checker. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… a convention it was not built for Failing first. Pins, before the change that makes them pass: - server: a startup check that reads public.vote_convention_current() and refuses no table, no row, an unknown contract and the other sign, naming the exact declare command; the import worker refuses before consuming. - engine: the same decision for the math poller, the math pipeline stage and the UMAP stage; the stage fakes answer the two startup queries. - coordinator: the same decision as a pure function; the schema census grows by the three tables migration 000023 adds (625 columns). - migration 000023: the row is written only on an empty database; a database holding votes is left undeclared with the DECLARE_NEEDED notice; the declare operation at both signs and its refusals; the shell entry point's status line; the down file from seeded, undeclared and declared databases; the restore rule knows "undeclared". - the sign lint treats the migration, its reversal, the operation and this test as the database's own chokepoint. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…o start against a convention it was not built for Migration 000023 (P-078 PR-A, ruling R-A 2026-10-05) gives the database one row, public.vote_convention, naming which stored vote value means "agree". - The migration writes the row ONLY on an empty database (version 0, agree -1, operation seed-empty). A database that already holds votes is left undeclared, with NOTICE DECLARE_NEEDED naming the one command. - The operator declares an existing database once: make vote-convention-declare AGREE=-1 (server/bin/vote-convention-declare.sh, server/postgres/operations/vote_convention_declare.sql). AGREE=+1 writes (1, +1) as the first state for a deployment that reversed its own signs. make vote-convention-status reports GUARD_NEEDED / DECLARE_NEEDED / GUARDED. - Every reader of votes checks the row before its first vote read and refuses to start on no table, no row, an unknown contract, or a sign other than the one it was built for: the server (index.ts), the import worker, the math poller, the math pipeline stage, the UMAP stage and the commentgraph CLI, the Delphi job poller, and the coordinator (at startup and at every source snapshot). The messages name the command and the guide (docs/vote-convention-upgrade.md). - The row and its history record the operation that wrote them and the operation file's ledger checksum; vote_convention_current() carries the contract version; the monotonic guard admits (0, -1) and a declared (1, +1) as first states; the down file reverts an undeclared database too. - The ledger checker covers operation files; the coordinator's typed rows and census include the three new tables; the characterization harness leaves the permanent tables alone; the queue crate's fixture accepts later server migrations. - Docs: docs/vote-convention-upgrade.md (what other deployments see and run), docs/vote-convention.md, docs/migrations.md, docs/upgrading.md, CHANGELOG, README. No vote value changes. No read, write, export or API response changes. Applying the migration to production is a separate, explicit step by the owner, before the release that reads the row is deployed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Hosted CI's vote-sign lint flagged server/bin/vote-convention-declare.sh: it names the sign it writes (AGREE=-1 / +1) and exists only to run the declare operation, which is already registered as the database chokepoint. The local lint run had preceded `git add`, and the lint scans tracked files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…job table on edge; 000024 is reserved) The migration, its reversal, the down test and its compose file move from 000023 to 000025, with every reference, pin and the two ledger self-checksums (the migration's and the declare operation's) regenerated. The chain neither requires nor records 000024, which another change holds. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…n-wt # Conflicts: # queue-rs/tests/jobs_integration.rs
…rapper, and the lock the migration takes Corrections from the operating-surface review of #2944: - The migration ledger records what the catalog shows for every earlier file (000000..000023: 'verified' when the file's signature object is present, 'unverified' when it is not, the probe named in the note) instead of asserting them as applied. The migration refuses (P0780) without the vote tables from 000000 and 000006 and needs nothing later; 000024 is neither required nor recorded. The down file keys its later-migration refusal on ledger-era rows (64-hex checksums). - The header and the guide say what the file locks: AccessShareLock on votes and votes_latest_unique until COMMIT (the empty-table checks), compatible with ordinary traffic, rolled back after the 5 s lock budget behind an ACCESS EXCLUSIVE holder; nothing on the vote tables is rewritten. - server/postgres/bin/apply-migration.sh covers 000025: seal from down/000025-files.sha256, PostgreSQL 17, the login owns the vote tables, the vote tables exist, no convention object exists yet, no old transaction, free disk; the budgets; a post-check of the ledger row and the convention state (DECLARE_NEEDED / GUARDED). Docs route the apply through it. - run_delphi.py runs polismath/check_vote_convention.py as its first stage, before the reset that removes previous results, so a job launched directly or by an older poller refuses with nothing changed. The commentgraph CLI's test-postgres exits 1 on a refusal and prints the operator message; the docs claim only that command. - The guide says the checks are made at startup (and at the job boundary), that the import worker and the Python processes check DATABASE_URL only, and that this release does not serve a +1 database. - The down test covers the chain 000000..000023 then 000025, the verified ledger, a copy without the dormant 000019/000021/000023, the prerequisite refusal and the wrapper (preflight-only, an old transaction, an ACCESS EXCLUSIVE holder, the apply, a second run, the seal). The census pins 000023 and the renumbered 000025. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… and the renumbered 000025 The census test enumerates the migrations directory and binds every file's bytes, so it had been red since 000023_create_delphi_foundation.sql merged without a census. Measured on PostgreSQL 17.11 with the full chain applied to a fresh database: eight new relations (delphi_jobs, delphi_job_aliases, delphi_job_inputs, delphi_current, delphi_job_guards, delphi_provider_requests, polis_queue_logs, delphi_foundation_install), the four columns 000023 adds to the 000019 tables, and the constraints and indexes they change. 95 relation types, 694 columns. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…e standard library; the commentgraph CLI builds a real PostgresConfig Found by the composed-image rehearsal: run by file path from run_delphi.py, polismath/check_vote_convention.py had its own package directory first on sys.path, where polismath/types.py shadowed the standard library's types and every run crashed before the check. The script drops that entry before its imports and run_delphi.py sets PYTHONPATH before the stage. The commentgraph CLI's test-postgres passed a dict where PostgresClient needs a PostgresConfig (pre-existing on edge), so its refusal path was unreachable in the image. The guide states the exit codes and which lines show at the default log level. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… first, with its own refusal rows Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Edge brought 000024 (the large worker class, polis-queue/3). The queue integration test keeps the prefix check, now 000000-000024; files after it (the vote convention, 000025) are in no template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… the census measures it Edge merged 000024 (the large worker class, polis-queue/3), which this branch had treated as held elsewhere. Corrections, nothing else: - 000025's ledger gains a row for 000024_create_polis_queue_large_class, probed by public.polis_queue_large_class_install (verified when present, unverified with the probe named when not, as for every earlier file). Comments, docs/migrations.md, docs/vote-convention.md and the checker's docstring say 000000..000024. Resealed: the ledger self-checksum and down/000025-files.sha256. - test_000025_down.py: the chain is 000000..000024 (no 000020); the pol.is shaped copy leaves out 000019, 000021, 000023 and 000024; the wrapper case expects 24 verified earlier files. - The coordinator schema census, measured again on PostgreSQL 17.11 with 000000..000025 applied to a fresh database: the only differences are 000024's (polis_queue_large_class_install; the widened kind, stage, worker_class and contract checks; pq_stage_large; the /3 default). 96 relations, 697 columns; 000025 pointers moved up one line. - The apply wrapper's header and docs/vote-census.md (which named the vote convention migration by its old number) are updated. The wrapper still covers 000019, 000023 and 000025; 000024 has no apply policy there and is left to its own change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…fore 000025 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… Rust tests The required campaign compares the Rust test names it runs with coordinator-rs/ci/inventory-v2.json exactly. tests/vote_convention.rs added seven tests that the inventory did not list, so the campaign's candidate gate failed on 'unexpected' names (on this branch since those tests were added). The identities are appended; no existing entry changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… not refused The startup check exited 1 on any failure to read the convention, including ECONNREFUSED while postgres was still starting. Under compose (the e2e stack, make start) the server then restarted with a new address, and nginx, which resolves `server` once, answered 502 for every request: the hosted E2E run failed that way (server log: "failed to read the database's vote convention connect ECONNREFUSED", then a restart; every spec's cy.visit got 502). The read is now retried every 2 s for about a minute when the database does not answer, as the server tolerated before the check existed. A refusal (no table, no row, the other sign, an unknown contract) still exits at once. Checked on the build box with the e2e compose stack: postgres held back 20 s, the server logs "could not read the database's vote convention (attempt 1 of 30); retrying in 2 s: connect ECONNREFUSED ...", then "vote convention: version 0, agree stored as -1" and "Server started"; restarts 0; nginx GET / and /api/v3/participationInit 200. One forced server restart on the unchanged stack reproduces the 502 (new container address, nginx upstream unreachable). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Edge brought the math poller's large class as a queue child (#2973) and the per-class CDK worker groups (#2974). One conflict in delphi/scripts/math_poller.py: _build_service keeps the vote convention check before it builds the service, with edge's simplified constructor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
server/postgres/bin/apply-migration.sh refused 000024 ("has no apply
policy here"), so an existing database had no checked path from
polis-queue/2 to /3. The wrapper now accepts 000024:
- seal: down/000024-files.sha256
- rights: superuser or SET membership in polis_queue_owner (as 000023)
- chain: 000023 installed and polis_queue_install reads polis-queue/2
(a second run is refused here, since the install then reads /3)
- rows: every queue and job table is empty (000024 alters the queue
tables' CHECK constraints, ACCESS EXCLUSIVE until COMMIT)
- lock line: names the four queue tables; no lock on conversations
- post-check: polis_queue_install reads polis-queue/3
The usage text now prints the whole header (it was cut at line 60).
test_000024_down.sh gains check (w): refused without 000023 and with a
queued job (catalog unchanged both times); --preflight-only passes and
changes nothing; the apply exits 0 with post-check /3 and the same
schema dump as a plain psql apply; a second run is refused at preflight.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… schema change) pq_sweep deletes one bounded page of expired queue history per call (P-083's bounds), recorded in a new polis_queue_sweeps ledger; pq_class_parked lists a class's parked jobs with their unproven attempts (P-086 restart-safe rediscovery); pq_queue_usage reports the queue's bytes and the last finished sweep; pq_class_depth gains oldest_eligible_at and answers polis-queue/4. Three indexes serve the sweep's scans. The contract version stays polis-queue/3. Sealed down script and its test (forward, backward byte-identical, refusals, the chain unwinding through 000024 and 000023). The poller's depth decoder accepts the /4 reply; the server and queue-rs tests learn the new functions and the jobs_v4 template. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…o queue/retention-000026
…rows are reported, not refused Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…needs migration 000026) The daemon runs retention itself, page by page through pq_sweep, only when its claim pass has nothing to start (cost-reduction plan P-083: the sweep never goes ahead of a job). The SQL decides cadence (once per 24 h per env), the single sweeper and every bound; each finished sweep is one polis_jobs.sweep/1 line with its counts. POLIS_JOBS_SWEEP_MAX_PAGES (100) and POLIS_JOBS_SWEEP_CHECK_SECONDS (900) bound it. On a database without 000026 the sweep says so once and turns itself off. Stacked on the 000026 draft: a schema-dependent change, draft too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…row; the large-class child checks it The row is the only truth for the stored vote sign: STORAGE_AGREE_VALUE never overrides it, and a build for the other sign refuses. Seven campaign tests had reversed the votes with a raw UPDATE and launched the coordinator at +1 while the row still said (0, -1), so this PR's coordinator refused them. - conftest: declare_convention() moves the row to the next version with the other sign (the transition its triggers admit, recorded in the history); reverse_votes() stores every vote with the other sign and leaves the row. - Polarity through database ingress (three fixtures), the rebuild schedule and the tie key: votes reversed AND the row declared +1, then the +1 run; the -1 build is shown to refuse (#mismatch). The "negative" control is the opposite votes under the same declaration (votes reversed again, +1 run), instead of the same votes read under the wrong sign. - The node reader's deliberately different third namespace is the same conversation with every vote reversed (row unchanged), not a run under the other sign. - math_poller --job (the large-class rebuild child): the same startup check as the poller, before it builds the service that reads votes; a refusal exits 2 (EXIT_JOB_ENV_INVALID) with the operator message. Test: tests/poller/test_rebuild_child_convention.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Edge gave the apply wrapper a policy for 000024 (#2975). One conflict in server/postgres/bin/apply-migration.sh: the wrapper now covers 000019, 000023, 000024 and 000025, each with its own seal, rights, chain, rows, lock line and post-check, unchanged from the two sides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
# Conflicts: # server/postgres/bin/apply-migration.sh
…eft 'latest' to the job ids' order) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
… (a grep that exits early made pipefail flaky) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
#2978 is now built on #2944 and merges after it: 000026 records itself in the migration ledger 000025 creates, so the combined apply wrapper lands here, carrying #2944's 000025 entry and adding 000026's. Conflicts, resolved: - server/postgres/bin/apply-migration.sh: #2944's wrapper (000019, 000023, 000024, 000025) plus the 000026 entry, with the corrections that follow in the next commit (every file of the seal, the ledger self-checksum, 000026's rights, chain on 000025's ledger row, post-check on the ledger). - queue-rs/tests/jobs_integration.rs: the 000000-000024 chain check from #2944; the jobs_v4 template applies 000025 then 000026. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…breaker, and retains by reachability Corrections from the connections map (cost-reduction notes; findings #716, #721, #728, decisions #729 and #758). Schema change, sealed; nothing is applied anywhere by this commit. 000026_create_polis_queue_retention.sql - Ledger: its last statement inserts its own public.schema_migrations row (self-checksum, as every file from 000025 on must); its guard refuses without 000025's row ("migration ledger missing") and when the ledger already records 000026 or later. The queue owner never touches the ledger: the guard and the insert run as the applying login. - Dead-job breaker (decision #729), replacing 000024's latch read from surviving rows: polis_queue_breakers holds a durable per-(env, zid, product) count kept by a trigger (pq_breaker_record) as jobs end. Three consecutive dead jobs under one image open it; pd_enqueue answers `poisoned` (same reply, naming the latest dead job) for 24 hours, then admits ONE probe; the probe succeeding closes it, dying re-opens it for 24 hours, a cancelled probe frees the slot; a new image resets it. Seeded at apply from the queue's history. - Retention by reachability (decision #758), replacing fixed-days-only deletion: pq_retention_reached marks every job something that matters reaches (unfinished, pinned, alias, current pointer, held guard, a head's run, unproven exit, open provider request, dead under an open breaker, or an input or parent of a reached job, transitively). Rules are data in polis_queue_retention_policy (kind, keep_days, keep_last, action), so a retention change is an UPDATE. Every kind ships as dry_run: pq_sweep reports would_<kind> counts and deletes nothing. A kind set to delete goes in two phases: tombstone (polis_queue_tombstones; restorable, and restored automatically when the row is reached or kept by policy again), then purge after the tombstone grace. Bounded per page. The sweep keeps every dead job its open breaker counts. - The down drops all of it, restores 000024's pd_enqueue from the recorded baseline, removes 000026's ledger row, refuses once a purge has deleted anything (dry runs and tombstones are reversible) and refuses while the ledger records a later migration. 000025's down already refuses while 000026's row is there; 000024's refuses the /4 catalog. Resealed. test_000026_down.sh (run on mm2, PostgreSQL 17): dry run, policy change by UPDATE, tombstone/restore/purge, a pinned job's inputs survive, the breaker's open / poisoned / sweep-keeps / 24 h probe / probe death / probe success / new image / cancelled probe, the seed from 000024-era history, the down refusals and order, the chain 000019..000026 up/down/up byte for byte one file at a time, the wrapper, and the populated chain through the wrapper with each step's lock held by another session (each apply waits, times out, changes nothing; 000024-000026 apply beside a conversations writer). Census: measured again on PostgreSQL 17.11 with 000000..000026 applied to a fresh database; the only differences are 000026's (five tables, three indexes). 101 relations, 729 columns. queue-rs foundation test names the new objects. docs/migrations.md and docs/queue-substrate.md give the order and the contract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Brings the corrected 000026: its ledger row, the durable dead-job breaker and retention by reachability (policy as data, dry run by default, tombstone then purge), with #2944's vote convention and the combined apply wrapper underneath. No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…es; the integration test follows retention by reachability 000026 now retains by reachability with the policy as data, every kind a dry run as shipped, and deletion in two phases (decision #758). The daemon's `polis_jobs.sweep/1` line keeps its deleted counts and adds `jobs_tombstoned`, `logs_tombstoned`, `bindings_tombstoned`, `tombstones_restored`, `dry_run` and `would` (the would_<kind> counts the SQL reports for kinds still dry run). Unit tests for both line shapes. jobs_integration: the sweep test now proves the shipped dry run (the line says it would delete the older rebuild; nothing goes), an UPDATE of polis_queue_retention_policy turning deletion on (no migration), the next day's sweep tombstoning without deleting, and the purge after the grace (the older rebuild goes with its attempt and logs; the latest stays with its manifest row; three ledger rows; then not_due). README updated, with the breaker that replaces 000024's latch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
…nt, chain scope, sign lint) - coordinator-rs census: polis_queue_tombstones.ref is `r#ref` (a Rust keyword), as `r#type` and `r#mod` already are. - 000026: pq_breaker_record and pq_retention_reached pin TimeZone=UTC like every other function the migration adds (queue-substrate test 39 holds every new pq_ function to both pins); its function count is 35 with 000026. Resealed (ledger self-checksum, down/000026-files.sha256, census hash); no line moved. - test_000025_down.py: its chain case covers the files through 000025; 000026 on is proven by test_000026_down.sh. - test_000026_down.sh: no `head -1` (the vote-sign lint reads it as a minus-one literal); 0 new sites. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s
Delphi Coverage Report
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Observable changes: with
POLIS_JOBS_SWEEP=1(default 0, off) and migration 000026 applied, an idlepolis-jobsworker deletes expired queue history once a day per queue env and prints onepolis_jobs.sweep/1line per sweep (counts of jobs, attempts, log rows, bindings, runs and ledger rows deleted; pages; what stopped it). With the flag on and 000026 absent it printspolis_jobs sweep off: …once and carries on. Nothing changes with the flag off. Draft: it stands on the 000026 schema ruling (#2978). Not a schema change itself.Corrections from the connections map
Observable changes (updated): with
POLIS_JOBS_SWEEP=1and the corrected 000026, a sweep deletes nothing as shipped: every retention rule is a dry run and thepolis_jobs.sweep/1line reportsdry_run: trueandwouldcounts (would_job_succeeded,would_logs_failed, ...). Once an operator turns a rule on (an UPDATE ofpolis_queue_retention_policy, no migration), rows are first tombstoned (restorable) and purged by a later sweep after the grace; the line addsjobs_tombstoned,logs_tombstoned,bindings_tombstonedandtombstones_restoredto the deleted counts. The sweep never deletes the dead jobs an open dead-job breaker counts (#729).Merge order: #2944, then #2978, then this PR (each merged into the next, never rebased).
queue-rs/src/jobs/sweep.rs:sweep_linebuilds the line; unit testsa_dry_run_line_carries_the_would_counts_and_deletes_nothing,a_deleting_line_has_no_would_counts.queue-rs/tests/jobs_integration.rs:the_built_in_sweep_dry_runs_then_tombstones_then_purges(real daemon, real 000025+000026 template): the shipped dry run deletes nothing; the policy UPDATE; the next day's sweep tombstones; after the grace the purge takes the older rebuild with its attempt and logs and keeps the latest with its manifest row; three ledger rows; not_due.Gates on mm2 at
85848fe1b: queue-rs fmt, clippy-D warnings(both feature sets), unit (43, including the two new line tests) andjobs_integration(25, including the rewritten sweep test) against PostgreSQL 17; down tests 000023, 000024, 000026; the composed chain proof (delphi/tests/poller/chain_proof.py: route, run, finalize, promote, cancel, SIGTERM, SIGKILL, cancel running, three deaths -> poisoned, new commit admits) on 000000..000026 with this branch's daemon: every step held. #2978's gates cover the schema.Original description (superseded where the corrections above say so)
What it is
Cost-reduction plan P-083, PR 2 ("built-in queue_sweep"). The sweep runs inside the daemon: no child process, no DSN handed out. After the claim pass, if it found nothing to start (or the worker is at its concurrency), the main loop asks
pq_sweep(env, sweep_id, page, max_pages)for one bounded page; the next page on the next pass. That is the plan's lane-2 rule (a sweep never goes ahead of a job) without a queue row. The SQL decides the rest: cadence (one sweep per 24 h per env,not_dueotherwise), a single sweeper (busy), abandoned sweeps, every retention bound and page size (#2978 has the table).POLIS_JOBS_SWEEP_MAX_PAGES(100, 1..1000) bounds one sweep;POLIS_JOBS_SWEEP_CHECK_SECONDS(900, 1..86400) is how often an idle worker asks whether one is due. The finished sweep's counts also sit inpolis_queue_sweeps, whichpq_queue_usagereads forsweep_age_ms.Where the plan did not survive contact with the code
P-083 makes the sweep a queue job (stage
queue_sweep, lane 2, keyed by date, rescheduling itself). Every claimable job belongs to a conversation on the merged schema (polis_queue_runs.zid,delphi_jobs.zidNOT NULL with foreign keys;pq_claimjoinsdelphi_jobs), so the sweep is built in instead and its schedule lives in SQL. Details in #2978.Gates (mm2)
cargo fmt --check, clippy-D warningsboth feature sets, unit (the sweep settings),jobs_integrationagainst postgres:17 including two new tests:the_built_in_sweep_removes_expired_history_and_keeps_the_latest(two finished rebuilds aged 31 days: the older one goes with its attempts and logs, the latest stays with only its manifest row, onesweep/1line, the ledger row, thennot_due) andthe_sweep_turns_itself_off_without_000026(on /3: one line, the worker keeps running and finishes a job): pass.test_000022.shfails on edge too, unrelated).test_gateandsign_lint: pass.Stacked on #2978 (branch
queue/retention-000026); its commits show here until it lands.🤖 Generated with Claude Code
https://claude.ai/code/session_018NVGBuYCk4EZmiz4csUv9s