From e2d5531274156551d7ddeb8d992dd7b4c0a0971c Mon Sep 17 00:00:00 2001 From: Sinity Date: Sun, 9 Aug 2026 16:28:07 +0200 Subject: [PATCH 1/7] fix(preflight): count all raw parse-error values Problem: blank and whitespace-only raw_sessions.parse_error values were omitted from the source distribution and eligibility counts.\n\nWhat changed: count every non-NULL parse_error value in the production preflight projection and update the route assertion to cover empty and whitespace text.\n\nCompatibility/migration: no schema or storage mutation; the preflight remains read-only.\n\nCo-Authored-By: Claude --- devtools/preflight_ledger.py | 6 +++--- tests/unit/devtools/test_preflight_ledger.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/devtools/preflight_ledger.py b/devtools/preflight_ledger.py index 06c265dc2d..f6e8fac2d2 100644 --- a/devtools/preflight_ledger.py +++ b/devtools/preflight_ledger.py @@ -114,7 +114,7 @@ def _source_distribution(root: Path) -> dict[str, object]: c.status AS census_status, CASE WHEN c.raw_id IS NULL THEN 1 ELSE 0 END AS coverage_unknown, CASE WHEN c.status IN ('failed', 'non_session') THEN 1 ELSE 0 END AS terminal, - CASE WHEN (r.parse_error IS NOT NULL AND TRIM(r.parse_error) != '') + CASE WHEN r.parse_error IS NOT NULL OR LOWER(COALESCE(r.validation_status, '')) = 'failed' THEN 1 ELSE 0 END AS failure, CASE WHEN c.status = 'complete' AND c.member_count > 0 THEN 1 ELSE 0 END AS census_eligible @@ -122,7 +122,7 @@ def _source_distribution(root: Path) -> dict[str, object]: LEFT JOIN raw_membership_census AS c ON c.raw_id = r.raw_id ) SELECT origin, COUNT(*), COALESCE(SUM(blob_size), 0), - COALESCE(SUM(parse_error IS NOT NULL AND TRIM(parse_error) != ''), 0), + COALESCE(SUM(parse_error IS NOT NULL), 0), COALESCE(SUM(validation_status = 'failed'), 0), COALESCE(SUM(revision_authority = 'quarantined'), 0), COALESCE(SUM(CASE WHEN revision_authority = 'quarantined' THEN blob_size ELSE 0 END), 0), @@ -149,7 +149,7 @@ def _source_distribution(root: Path) -> dict[str, object]: totals = conn.execute( """ SELECT COUNT(*), COALESCE(SUM(blob_size), 0), - COALESCE(SUM(parse_error IS NOT NULL AND TRIM(parse_error) != ''), 0), + COALESCE(SUM(parse_error IS NOT NULL), 0), COALESCE(SUM(LOWER(COALESCE(validation_status, '')) = 'failed'), 0), COALESCE(SUM(revision_authority = 'quarantined'), 0), COALESCE(SUM(CASE WHEN revision_authority = 'quarantined' THEN blob_size ELSE 0 END), 0), diff --git a/tests/unit/devtools/test_preflight_ledger.py b/tests/unit/devtools/test_preflight_ledger.py index c64b2f095f..9dfb63564c 100644 --- a/tests/unit/devtools/test_preflight_ledger.py +++ b/tests/unit/devtools/test_preflight_ledger.py @@ -224,9 +224,9 @@ def test_preflight_ignores_blank_parse_errors_in_origin_and_totals(tmp_path: Pat by_origin = {str(item["origin"]): item for item in (_mapping(value) for value in _list(source["by_origin"]))} origin = by_origin["codex-session"] eligibility = _mapping(origin["eligibility"]) - assert totals["parse_failures"] == 1 - assert origin["parse_failures"] == 1 - assert eligibility["actionable_count"] == 1 + assert totals["parse_failures"] == 3 + assert origin["parse_failures"] == 3 + assert eligibility["actionable_count"] == 3 def test_preflight_blocks_unexplained_raw_failure_lifecycle(tmp_path: Path) -> None: From f095128bbc0006399d36c17c056ca77b785d9b60 Mon Sep 17 00:00:00 2001 From: Sinity Date: Sun, 9 Aug 2026 16:28:39 +0200 Subject: [PATCH 2/7] fix(preflight): gate replay candidates against blocked work Problem: the replay preflight failed whenever any candidate existed, even when every candidate was blocked by authority or resource conditions.\n\nWhat changed: compare executable candidates with blocked candidates and exercise both outcomes through build_preflight_ledger.\n\nCompatibility/migration: no schema or storage mutation; blocked replay work remains visible as a warning.\n\nCo-Authored-By: Claude --- devtools/preflight_ledger.py | 2 +- tests/unit/devtools/test_preflight_ledger.py | 38 ++++++++++++++++---- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/devtools/preflight_ledger.py b/devtools/preflight_ledger.py index f6e8fac2d2..db330d484e 100644 --- a/devtools/preflight_ledger.py +++ b/devtools/preflight_ledger.py @@ -365,7 +365,7 @@ def _replay_preflight(root: Path, *, limit: int) -> dict[str, object]: ) candidate_count = _count(payload.get("candidate_count")) blocked_count = _count(payload.get("blocked_candidate_count")) - state = "fail" if candidate_count else "warn" if blocked_count else "pass" + state = "fail" if candidate_count > blocked_count else "warn" if blocked_count else "pass" return _status( state=state, reason=( diff --git a/tests/unit/devtools/test_preflight_ledger.py b/tests/unit/devtools/test_preflight_ledger.py index 9dfb63564c..d85857c913 100644 --- a/tests/unit/devtools/test_preflight_ledger.py +++ b/tests/unit/devtools/test_preflight_ledger.py @@ -1,6 +1,7 @@ from __future__ import annotations import sqlite3 +from collections.abc import Callable from datetime import UTC, datetime from pathlib import Path from typing import cast @@ -24,8 +25,15 @@ def _list(value: object) -> list[object]: return cast(list[object], value) -def _mixed_replay_backlog(*_args: object, **_kwargs: object) -> dict[str, object]: - return {"available": True, "candidate_count": 2, "blocked_candidate_count": 5} +def _replay_backlog(candidate_count: int, blocked_candidate_count: int) -> Callable[..., dict[str, object]]: + def backlog(*_args: object, **_kwargs: object) -> dict[str, object]: + return { + "available": True, + "candidate_count": candidate_count, + "blocked_candidate_count": blocked_candidate_count, + } + + return backlog def _initialize_all_tiers(root: Path) -> None: @@ -181,19 +189,35 @@ def test_preflight_fails_closed_on_missing_census_relation(tmp_path: Path) -> No assert "raw_membership_census" in reason -def test_preflight_fails_when_executable_replay_candidates_coexist_with_blocked( +def test_preflight_warns_when_blocked_replay_candidates_outnumber_executable( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: - monkeypatch.setattr(preflight_ledger, "raw_materialization_replay_backlog", _mixed_replay_backlog) + _initialize_all_tiers(tmp_path) + monkeypatch.setattr(preflight_ledger, "raw_materialization_replay_backlog", _replay_backlog(2, 5)) - replay = preflight_ledger._replay_preflight(tmp_path, limit=10) + report = build_preflight_ledger(tmp_path, limit=10) + replay = _mapping(_mapping(report["checks"])["replay_backlog"]) - assert replay["state"] == "fail" + assert replay["state"] == "warn" assert replay["candidate_count"] == 2 assert replay["blocked_candidate_count"] == 5 -def test_preflight_ignores_blank_parse_errors_in_origin_and_totals(tmp_path: Path) -> None: +def test_preflight_fails_when_executable_replay_candidates_outnumber_blocked( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + _initialize_all_tiers(tmp_path) + monkeypatch.setattr(preflight_ledger, "raw_materialization_replay_backlog", _replay_backlog(5, 2)) + + report = build_preflight_ledger(tmp_path, limit=10) + replay = _mapping(_mapping(report["checks"])["replay_backlog"]) + + assert replay["state"] == "fail" + assert replay["candidate_count"] == 5 + assert replay["blocked_candidate_count"] == 2 + + +def test_preflight_reports_every_non_null_raw_parse_error(tmp_path: Path) -> None: _initialize_all_tiers(tmp_path) _insert_raws( tmp_path, From 4c7556527f128b451ef69adbf8c0a33ba61c38a9 Mon Sep 17 00:00:00 2001 From: Sinity Date: Mon, 10 Aug 2026 00:52:03 +0200 Subject: [PATCH 3/7] chore(beads): track preflight predicate contract --- .beads/issues.jsonl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 60753d2351..5b07cfedf3 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,3 +1,4 @@ +{"_type":"issue","id":"polylogue-r4jiu","title":"verification: complete source-index coverage ground-truth integration","description":"The parser-census readiness guard is now fail-closed, but source-index coverage still needs its own ground-truth universe wired through the verification registry. Complete the residual from polylogue-in24n without allowing the census ledger to define the population being audited.","acceptance_criteria":"1. The source-index coverage universe is derived from raw logical heads in source.db, not from the census ledger under audit.\\n2. Every raw logical head absent from the index is either indexed or has an explicit typed parse failure, unsupported/non-session disposition, quarantine blocker, or other accepted terminal state.\\n3. A red mutation that removes a raw head from the derived census while leaving source.db unchanged makes the check fail.\\n4. Focused registry tests and devtools verify --quick pass.","notes":"Residual successor created while publishing the parser-census readiness guard. The guard is merged only as a partial prerequisite; do not close this successor until the verification oracle itself uses the raw logical-head universe and its anti-vacuity mutation is green.","status":"open","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T22:42:50Z","created_by":"Sinity","updated_at":"2026-08-09T22:42:50Z","dependencies":[{"issue_id":"polylogue-r4jiu","depends_on_id":"polylogue-in24n","type":"discovered-from","created_at":"2026-08-09T22:42:58Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-dyica.1","title":"reindex: persist typed raw-failure evidence and CAS retry authority","description":"Implement the typed raw-failure and Codex CAS-frontier residual from the stopped-daemon census. Preserve Claude partial JSONL, unknown decode, unknown export without session, and Codex CAS frontier evidence through live ingest, revision governance, repair selection, and status.","acceptance_criteria":"1. LiveBatchProcessor and mark_raw_parse_failed persist typed raw_artifacts for Claude partial JSONL, unknown JSON decode, unknown export without session, and Codex CAS frontier outcomes. 2. CAS/frontier failures use typed retryable authority and preserve current legacy selectors. 3. Production-route tests prove durable evidence, lifecycle/status projection, and repair candidate gating, with red twins. 4. devtools verify passes on the exact head. 5. Any remaining live population or migration/apply work is carried by an open named successor before this child is closed.","status":"open","priority":0,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T14:44:19Z","created_by":"Sinity","updated_at":"2026-08-09T14:44:19Z","labels":["area:reindex","area:sources","delivery:reindex"],"dependencies":[{"issue_id":"polylogue-dyica.1","depends_on_id":"polylogue-dyica","type":"parent-child","created_at":"2026-08-09T14:44:19Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-g8v5z","title":"decision: bind incident concepts to executable registry checks","description":"Resolve the identity boundary between the executable ARCHIVE_VERIFICATION_CHECKS registry and the conceptual registry_checks catalog in docs/plans/reindex-incident-coverage.json. Current evidence shows 27 executable check names and 25 conceptual ledger IDs with no overlap, no invariant-identity field, and five archive-registry incident bindings absent from the ledger. The reindex registry subset cannot honestly cross-check incident bindings until this mapping contract is explicit.","design":"Choose and record one typed mapping authority: either add explicit executable_check_names to each ledger check catalog entry, add a registry-owned incident binding projection consumed by the ledger, or narrow the subset with a named disposition. Preserve conceptual ledger IDs for campaign coverage and executable registry names for predicates. Do not rename either vocabulary implicitly or match by prose/source strings.","acceptance_criteria":"1. The mapping authority and vocabulary ownership are recorded in a structured schema or typed registry field. 2. Every conceptual incident registry check maps to one or more executable ARCHIVE_VERIFICATION_CHECKS or has a typed non-executable disposition. 3. Every executable incident binding used by candidate or daemon gates maps back to a ledger concept with no orphan or duplicate mapping. 4. Red-twin, candidate-runner, daemon-schedule, waiver, and live-receipt metadata remain owned by ArchiveVerificationCheckSpec. 5. Focused mutation tests fail on one missing mapping, one extra mapping, and one duplicate mapping. 6. The reindex registry subset can then cross-check incident bindings without importing Beads or parsing prose.","status":"open","priority":0,"issue_type":"decision","owner":"ezo.dev@gmail.com","created_at":"2026-08-07T23:51:28Z","created_by":"Sinity","updated_at":"2026-08-07T23:51:28Z","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"polylogue-eqq02","title":"devtools: guard required reindex proof edges","description":"Add an executable graph guard for the reindex proof-edge matrix. The policy must reject removal of any required live-proof blocking edge and must bind the edge matrix to the phase graph used by preflight and terminal proof.","design":"Define the required edge matrix as structured policy data or a typed fixture consumed by devtools lab policy bead-graph. Add a negative mutation test that removes one edge and fails, plus a positive check for the current graph. Keep this guard separate from the live production proof receipts.","acceptance_criteria":"1. The twelve required live-proof blocking edges are represented by structured policy data. 2. The positive graph check passes on the current Beads snapshot. 3. Removing any required edge fails the policy or fixture check. 4. The guard is consumed by reindex preflight and terminal proof readiness. 5. Focused tests and devtools verify --quick pass.","notes":"Created from Codex P1 review finding 3734483475 on PR #3872. Existing phase edges remain present, but their required-edge guard was not executable.\nClosure evidence: merged PR 3881 at merge commit a85bb6eb5ac74bfddd458c12e29642b2695fe775. The guard passed 43 focused graph tests and all 24 quick verification steps. Live receipts remain separate.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-08-07T08:44:35Z","created_by":"Sinity","updated_at":"2026-08-07T23:12:28Z","started_at":"2026-08-07T09:48:30Z","closed_at":"2026-08-07T23:11:42Z","close_reason":"Merged PR #3881 () adds the typed twelve-edge required-proof matrix, fail-closed missing-edge checks, preflight and terminal-proof bindings, and mutation coverage. Verified with 43 focused graph tests and all 24 quick-gate steps. Live receipts remain open under their own Beads.","labels":["area:devtools","lane:reindex"],"dependencies":[{"issue_id":"polylogue-eqq02","depends_on_id":"polylogue-reindex-proof-edge-correction","type":"discovered-from","created_at":"2026-08-07T10:44:34Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":2,"comment_count":0} @@ -169,6 +170,8 @@ {"_type":"issue","id":"polylogue-tf2.1","title":"Rerun forensics on current archive; price origin_reported providers","description":"Rerun scripts/agent_forensics.py against the current archive (v23+); price origin_reported providers via the vendored LiteLLM catalog (match last path segment); all-provider headline or explicitly-labeled per-provenance figures that cannot be misread; record deltas vs 06-27; verify chart SVGs render. Cache-inclusion must be disambiguated (Codex input INCLUDES cached ~96%; see bd memories). Also blocked on logical-session token attribution — the headline must not be double-counted.","notes":"Correction to close_reason monetary values: stored/provider-priced subset was $239,453.14; catalog API-equivalent was $318,650.88; origin_reported catalog estimate was $79,197.74. The original close_reason text lost dollar-prefixed digits due shell expansion, not measurement drift.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:33Z","created_by":"Sinity","updated_at":"2026-07-31T22:35:43Z","started_at":"2026-07-03T09:28:10Z","closed_at":"2026-07-03T09:59:02Z","close_reason":"Completed with blocker caveat preserved: scripts/agent_forensics.py now prices origin_reported rows through the shared vendored LiteLLM pricing catalog while preserving stored provenance; report separates stored/provider-priced cost from catalog API-equivalent estimates and carries logical-session/cache caveats instead of claiming final billing reconciliation. Regenerated current artifact at .agent/demos/agent-forensics against /home/sinity/.local/share/polylogue schema v23: 16,498 physical sessions, 4,142,175 messages, 356.5B tokens, ,453.14 stored/provider-priced subset, ,650.88 catalog API-equivalent, and ,197.74 origin_reported catalog estimate. SVG parse check passed for 9 charts; devtools test tests/unit/scripts/test_agent_forensics.py passed; devtools verify --quick passed run 20260703T095718Z-quick-753466-96559776; devloop-review clean. Remaining final-reconciliation blocker stays open as polylogue-4ts.2.","labels":["area:usage","campaign"],"dependencies":[{"issue_id":"polylogue-tf2.1","depends_on_id":"polylogue-4ts.2","type":"blocks","created_at":"2026-07-03T06:32:45Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-tf2.1","depends_on_id":"polylogue-sru.7","type":"blocks","created_at":"2026-07-03T06:31:33Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-tf2.1","depends_on_id":"polylogue-tf2","type":"parent-child","created_at":"2026-07-03T06:31:33Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"polylogue-tf2","title":"Campaign: agent-forensics regeneration + all-provider repricing","description":"Regenerate the agent-forensics packet on the current archive with an honest all-provider headline. The 2026-06-27 report (546.6B tokens, $89,368 API-list equivalent, 216x cache amplification) is the most stranger-legible artifact on any shelf, but its numbers are pre-dedup stale and the headline prices only the priced-provenance subset (Claude Code cost_usd rows); Codex/ChatGPT/Gemini are origin_reported token counts with no dollar value (operator estimate ~$150K all-provider). Sequenced after claim-vs-evidence per operator direction 2026-07-02.","design":"Current slice design: turn the existing agent-forensics/cost headline into a product-backed all-provider repricing artifact. First inspect devtools/scripts and polylogue analyze surfaces for agent_forensics/cost code. Use active archive usage headline (detail=headline) for authoritative physical_session and logical_session_model_high_water token totals. Keep priced-provenance dollars and origin-reported token estimates separate: do not multiply every token by one blended price without a labeled lane. Add or reuse a shared pricing/projection helper so the demo artifact is regenerated from Polylogue product code, not ad hoc SQL. Acceptance for this slice: the generated agent-forensics artifact names archive root/schema, includes physical vs logical token grain, separates priced subset from origin-reported estimate lanes, gives reproduction commands, and has focused tests for any new repricing helper/surface.","acceptance_criteria":"Terminal state: regenerated forensics packet on the current archive with an honest all-provider headline (priced subset AND origin-reported estimate lanes separated), agent_forensics.py folded into polylogue analyze (tf2.2), artifact on the demo shelf with reproduction commands, cold-reader gate passed. Epic closes only when that artifact is recorded.","status":"closed","priority":0,"issue_type":"epic","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:32Z","created_by":"Sinity","updated_at":"2026-07-31T22:35:43Z","started_at":"2026-07-03T18:47:23Z","closed_at":"2026-07-03T19:06:44Z","close_reason":"Completed: provider usage headline now exposes product-backed pricing lanes in polylogue analyze usage --detail headline, separating stored/provider-priced cost from catalog API-equivalent estimates for origin_reported rows. Regenerated the current .agent/demos/agent-forensics artifact against /home/sinity/.local/share/polylogue schema v23: physical-session tokens 395,320,980,423; logical high-water tokens 288,741,229,728; stored/provider-priced USD 243,392.189328; catalog API-equivalent USD 337,565.031618; priced lane 13,889 rows / 12,331 sessions / 12,650 matched rows; origin_reported lane 2,308 rows / 2,270 sessions / 2,302 matched rows. Verification: live polylogue --plain analyze usage --detail headline --format json --limit 0 wrote /realm/tmp/polylogue-usage-headline-pricing-current.json; devtools test tests/unit/storage/test_provider_usage_report.py tests/unit/cli/test_diagnostics.py passed 23 tests; devtools verify --quick passed run 20260703T190553Z-quick-2226137-d91d4e8f; devtools workspace demo-shelf --json reported ok. Non-claim preserved: this is not final billing reconciliation and physical/logical token grains stay explicitly separated.","labels":["area:usage","campaign","size:M","spine"],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-sru","title":"Campaign: claim-vs-evidence report to finding-grade","description":"Terminal state: an externally publishable finding ('how often do coding agents proceed past failed tool calls, by model/tool') with stated sample frame, calibrated markers, benign/consequential split, seeded stranger-runnable reproduction, and a passed cold-reader gate. Slice closure is NOT campaign closure; this epic stays top-of-frame until its terminal state is recorded.\\n\\nState as of 2026-07-03 after calibrated active-archive regeneration: archive root /home/sinity/.local/share/polylogue, index schema v23, 41,886 structured failures total, 5,000 origin-stratified failures inspected (3,746 claude-code-session, 1,247 codex-session, 7 claude-ai-export), 100 unpaired structured failures. Marker vocabulary was tightened to avoid broad issue/fix/block/gitignored false positives. Immediate next-turn totals: acknowledged=420, silent_proceed=1,205, ambiguous=3,375 (2,624 wordless tool continuations; 751 prose without marker). Lower-bound silent rate is 24.1%; among classified immediate next turns, silent rate is 74.2%. Next-3 sensitivity window, stopping before the next user message, finds 302 acknowledgments that appear only after the next turn; window3 silent lower bound is 37.0%. Calibration: 50 hand-labeled immediate-next-turn rows, acknowledged-marker precision=1.0, recall=0.8421052631578947, invalid rows=0. Artifact: .agent/demos/claim-vs-evidence/claim-vs-evidence.report.json.","notes":"2026-07-03 update: methodology package is now cold-read gated. .agent/demos/claim-vs-evidence contains aggregate live evidence, public-summary.json, PUBLIC_REPRODUCTION.md, COLD_READER_GATE.md, and COLD_READ_RESULT.md. Seeded reproduction is meaningful, not empty: 4 structured failures, 2 acknowledged follow-ups, 2 silent-proceed follow-ups, 0 unpaired. Cold-reader subagent PASS recovered claim/non-claim, sample frame, rates, calibration, caveats, and reproduction commands from the artifact directory only. Remaining campaign child: polylogue-sru.1 productizes action-unit outcome/followup_class capability.","status":"closed","priority":0,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:26Z","created_by":"Sinity","updated_at":"2026-07-31T22:35:43Z","closed_at":"2026-07-03T09:28:09Z","close_reason":"Completed: all seven campaign children are closed. The claim-vs-evidence finding now has bounded sample-frame reporting, calibrated marker precision/recall, handler-class and next-3 sensitivity splits, meaningful seeded reproduction, cold-reader PASS, and productized action-unit followup_class/followup_message_ref query capability. Current artifact lives under .agent/demos/claim-vs-evidence and was regenerated against /home/sinity/.local/share/polylogue schema v23.","labels":["area:substrate","campaign"],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"polylogue-agbgr","title":"preflight: classify blocked replay and all raw parse-error evidence","description":"The reindex preflight ledger must distinguish executable replay candidates from blocked candidates and must count every non-null raw parse-error marker, including empty and whitespace values, so readiness cannot be falsely green.","acceptance_criteria":"1. Replay preflight fails only when executable candidates outnumber blocked candidates; a fully blocked population remains a visible warning.\\n2. Every non-null raw_sessions.parse_error value is represented in source distribution and actionable eligibility counts.\\n3. Focused preflight ledger tests cover both replay orderings and blank/whitespace parse-error values.\\n4. devtools verify --quick passes.\\n5. The ledger remains read-only and does not authorize live replay or migration.","notes":"Unique WIP lane completed on feature/fix/preflight-predicate-corrections. This is a preflight correctness change only; live source remediation remains separately gated.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T22:52:03Z","created_by":"Sinity","updated_at":"2026-08-09T22:52:03Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"polylogue-8iuna","title":"daemon: make raw parse recovery probe fail closed and index-aware","description":"The raw parse recovery convergence probe must be a trustworthy readiness signal rather than a best-effort diagnostic. Preserve active-index selection, distinguish a clean no-backlog result from probe failure, and keep the route on the daemon-owned production seam.","acceptance_criteria":"1. Probe failures are typed and fail closed; an exception cannot be reported as a clean empty backlog.\\n2. Probe queries follow the active index generation and do not silently inspect a stale index.\\n3. A clean no-backlog route reports an explicit empty result without false debt.\\n4. Focused daemon recovery tests and devtools verify --quick pass.\\n5. This task covers implementation and proof only; live archive recovery remains separately gated.","notes":"Unique WIP lane completed on feature/fix/raw-recovery-probe-authority. The implementation does not authorize live recovery or close any live-operation receipt.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T22:47:39Z","created_by":"Sinity","updated_at":"2026-08-09T22:47:39Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-brb07","title":"Backfill durable message assertion owners before reindex","description":"After message identity and user-state owner-scope changes, existing durable message marks and annotations may have target_ref=message:\u003cid\u003e but no session scope_ref. Before any source freeze or index rebuild, inventory those rows, resolve each message owner from the rebuildable index while it exists, and persist canonical session ownership in user.db. Preserve annotation-batch:\u003cid\u003e provenance, reject ambiguous or missing owners into a typed report, and run only through a verified-backup, transactional, idempotent daemon-owned actuator. This is the deferred successor from polylogue-slshy / PR #3898.","acceptance_criteria":"1. Read-only census reports every legacy message mark/annotation with missing session scope, grouped by resolvable, ambiguous, missing, and already-canonical outcomes, with exact counts and row identities. 2. Apply is authorized only after a verified user.db backup and a frozen census digest; it updates only resolvable rows, preserves target_ref and annotation-batch:\u003cid\u003e scope_ref provenance, and stores canonical session ownership in the designated durable owner field. 3. Ambiguous or missing owners remain unchanged and are emitted as typed residuals; no guessed prefix or message-content match is accepted. 4. Re-running the actuator is a no-op with the same digest and receipt, and crash/failure leaves a recoverable transaction state. 5. Focused real user-tier tests cover legacy rows, batch-scoped annotations, ambiguity, backup/rollback, idempotency, and cold reopen; devtools verify --quick passes. 6. A fresh read-only census proves zero resolvable legacy rows remain before source freeze; residuals are linked to named follow-up beads.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T20:20:58Z","created_by":"Sinity","updated_at":"2026-08-09T20:20:58Z","dependencies":[{"issue_id":"polylogue-brb07","depends_on_id":"polylogue-slshy","type":"discovered-from","created_at":"2026-08-09T20:23:22Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-6qjc.1","title":"daemon: persist judgment scheduler receipts and queue health","description":"Complete the additive scheduler receipt and assertion-candidate queue health slice after the judgment actor implementation. Preserve current daemon lifecycle events and expose completed, parked, failed, retryable, and bounded-result state through API, daemon status, CLI, and surfaces.","acceptance_criteria":"1. Scheduler outcomes persist typed receipt rows in ops.db with status, reason, retryability, batch bound, and result counters. 2. Receipt writes are failure-contained and scheduler state remains retryable after transient errors or restart. 3. API, daemon status, CLI, and payload surfaces project parked-pending and scheduler-stalled states from the receipt authority. 4. Real daemon/API/status tests and devtools verify pass on the exact head. 5. No production mutation is performed by the implementation lane; any live deployment remains a named successor.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T14:44:23Z","created_by":"Sinity","updated_at":"2026-08-09T14:44:23Z","labels":["area:orchestration","horizon:mid"],"dependencies":[{"issue_id":"polylogue-6qjc.1","depends_on_id":"polylogue-6qjc","type":"parent-child","created_at":"2026-08-09T14:44:23Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-reindex-preflight-authorization.1","title":"reindex: correct source parse-error and replay preflight predicates","description":"Port the two current-master preflight predicate corrections: count every non-NULL raw_sessions.parse_error, including empty text, as failure evidence; and report replay preflight as fail only when candidate_count exceeds blocked_count. Preserve the existing raw-failure preflight route and current authority gates.","acceptance_criteria":"1. The production preflight source-distribution route counts every non-NULL parse_error, including empty text, and a red twin fails if NULL-only or trimmed-text semantics return. 2. Replay preflight reports fail only when candidate_count \u003e blocked_count, warns for blocked-only work, and preserves existing raw-failure preflight behavior. 3. Focused preflight tests and devtools verify --quick pass on the exact head. 4. No production mutation occurs in this implementation slice. 5. Any remaining preflight authorization scope stays on polylogue-reindex-preflight-authorization.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T14:44:15Z","created_by":"Sinity","updated_at":"2026-08-09T14:44:15Z","labels":["area:maintenance","lane:reindex"],"dependencies":[{"issue_id":"polylogue-reindex-preflight-authorization.1","depends_on_id":"polylogue-reindex-preflight-authorization","type":"parent-child","created_at":"2026-08-09T14:44:15Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} From 21e805ffd7b36dca1b431281a2dc5164468e6908 Mon Sep 17 00:00:00 2001 From: Sinity Date: Mon, 10 Aug 2026 01:12:58 +0200 Subject: [PATCH 4/7] chore(beads): bind preflight fix to campaign child --- .beads/issues.jsonl | 3 --- 1 file changed, 3 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 5b07cfedf3..60753d2351 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,4 +1,3 @@ -{"_type":"issue","id":"polylogue-r4jiu","title":"verification: complete source-index coverage ground-truth integration","description":"The parser-census readiness guard is now fail-closed, but source-index coverage still needs its own ground-truth universe wired through the verification registry. Complete the residual from polylogue-in24n without allowing the census ledger to define the population being audited.","acceptance_criteria":"1. The source-index coverage universe is derived from raw logical heads in source.db, not from the census ledger under audit.\\n2. Every raw logical head absent from the index is either indexed or has an explicit typed parse failure, unsupported/non-session disposition, quarantine blocker, or other accepted terminal state.\\n3. A red mutation that removes a raw head from the derived census while leaving source.db unchanged makes the check fail.\\n4. Focused registry tests and devtools verify --quick pass.","notes":"Residual successor created while publishing the parser-census readiness guard. The guard is merged only as a partial prerequisite; do not close this successor until the verification oracle itself uses the raw logical-head universe and its anti-vacuity mutation is green.","status":"open","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T22:42:50Z","created_by":"Sinity","updated_at":"2026-08-09T22:42:50Z","dependencies":[{"issue_id":"polylogue-r4jiu","depends_on_id":"polylogue-in24n","type":"discovered-from","created_at":"2026-08-09T22:42:58Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-dyica.1","title":"reindex: persist typed raw-failure evidence and CAS retry authority","description":"Implement the typed raw-failure and Codex CAS-frontier residual from the stopped-daemon census. Preserve Claude partial JSONL, unknown decode, unknown export without session, and Codex CAS frontier evidence through live ingest, revision governance, repair selection, and status.","acceptance_criteria":"1. LiveBatchProcessor and mark_raw_parse_failed persist typed raw_artifacts for Claude partial JSONL, unknown JSON decode, unknown export without session, and Codex CAS frontier outcomes. 2. CAS/frontier failures use typed retryable authority and preserve current legacy selectors. 3. Production-route tests prove durable evidence, lifecycle/status projection, and repair candidate gating, with red twins. 4. devtools verify passes on the exact head. 5. Any remaining live population or migration/apply work is carried by an open named successor before this child is closed.","status":"open","priority":0,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T14:44:19Z","created_by":"Sinity","updated_at":"2026-08-09T14:44:19Z","labels":["area:reindex","area:sources","delivery:reindex"],"dependencies":[{"issue_id":"polylogue-dyica.1","depends_on_id":"polylogue-dyica","type":"parent-child","created_at":"2026-08-09T14:44:19Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-g8v5z","title":"decision: bind incident concepts to executable registry checks","description":"Resolve the identity boundary between the executable ARCHIVE_VERIFICATION_CHECKS registry and the conceptual registry_checks catalog in docs/plans/reindex-incident-coverage.json. Current evidence shows 27 executable check names and 25 conceptual ledger IDs with no overlap, no invariant-identity field, and five archive-registry incident bindings absent from the ledger. The reindex registry subset cannot honestly cross-check incident bindings until this mapping contract is explicit.","design":"Choose and record one typed mapping authority: either add explicit executable_check_names to each ledger check catalog entry, add a registry-owned incident binding projection consumed by the ledger, or narrow the subset with a named disposition. Preserve conceptual ledger IDs for campaign coverage and executable registry names for predicates. Do not rename either vocabulary implicitly or match by prose/source strings.","acceptance_criteria":"1. The mapping authority and vocabulary ownership are recorded in a structured schema or typed registry field. 2. Every conceptual incident registry check maps to one or more executable ARCHIVE_VERIFICATION_CHECKS or has a typed non-executable disposition. 3. Every executable incident binding used by candidate or daemon gates maps back to a ledger concept with no orphan or duplicate mapping. 4. Red-twin, candidate-runner, daemon-schedule, waiver, and live-receipt metadata remain owned by ArchiveVerificationCheckSpec. 5. Focused mutation tests fail on one missing mapping, one extra mapping, and one duplicate mapping. 6. The reindex registry subset can then cross-check incident bindings without importing Beads or parsing prose.","status":"open","priority":0,"issue_type":"decision","owner":"ezo.dev@gmail.com","created_at":"2026-08-07T23:51:28Z","created_by":"Sinity","updated_at":"2026-08-07T23:51:28Z","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"polylogue-eqq02","title":"devtools: guard required reindex proof edges","description":"Add an executable graph guard for the reindex proof-edge matrix. The policy must reject removal of any required live-proof blocking edge and must bind the edge matrix to the phase graph used by preflight and terminal proof.","design":"Define the required edge matrix as structured policy data or a typed fixture consumed by devtools lab policy bead-graph. Add a negative mutation test that removes one edge and fails, plus a positive check for the current graph. Keep this guard separate from the live production proof receipts.","acceptance_criteria":"1. The twelve required live-proof blocking edges are represented by structured policy data. 2. The positive graph check passes on the current Beads snapshot. 3. Removing any required edge fails the policy or fixture check. 4. The guard is consumed by reindex preflight and terminal proof readiness. 5. Focused tests and devtools verify --quick pass.","notes":"Created from Codex P1 review finding 3734483475 on PR #3872. Existing phase edges remain present, but their required-edge guard was not executable.\nClosure evidence: merged PR 3881 at merge commit a85bb6eb5ac74bfddd458c12e29642b2695fe775. The guard passed 43 focused graph tests and all 24 quick verification steps. Live receipts remain separate.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-08-07T08:44:35Z","created_by":"Sinity","updated_at":"2026-08-07T23:12:28Z","started_at":"2026-08-07T09:48:30Z","closed_at":"2026-08-07T23:11:42Z","close_reason":"Merged PR #3881 () adds the typed twelve-edge required-proof matrix, fail-closed missing-edge checks, preflight and terminal-proof bindings, and mutation coverage. Verified with 43 focused graph tests and all 24 quick-gate steps. Live receipts remain open under their own Beads.","labels":["area:devtools","lane:reindex"],"dependencies":[{"issue_id":"polylogue-eqq02","depends_on_id":"polylogue-reindex-proof-edge-correction","type":"discovered-from","created_at":"2026-08-07T10:44:34Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":2,"comment_count":0} @@ -170,8 +169,6 @@ {"_type":"issue","id":"polylogue-tf2.1","title":"Rerun forensics on current archive; price origin_reported providers","description":"Rerun scripts/agent_forensics.py against the current archive (v23+); price origin_reported providers via the vendored LiteLLM catalog (match last path segment); all-provider headline or explicitly-labeled per-provenance figures that cannot be misread; record deltas vs 06-27; verify chart SVGs render. Cache-inclusion must be disambiguated (Codex input INCLUDES cached ~96%; see bd memories). Also blocked on logical-session token attribution — the headline must not be double-counted.","notes":"Correction to close_reason monetary values: stored/provider-priced subset was $239,453.14; catalog API-equivalent was $318,650.88; origin_reported catalog estimate was $79,197.74. The original close_reason text lost dollar-prefixed digits due shell expansion, not measurement drift.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:33Z","created_by":"Sinity","updated_at":"2026-07-31T22:35:43Z","started_at":"2026-07-03T09:28:10Z","closed_at":"2026-07-03T09:59:02Z","close_reason":"Completed with blocker caveat preserved: scripts/agent_forensics.py now prices origin_reported rows through the shared vendored LiteLLM pricing catalog while preserving stored provenance; report separates stored/provider-priced cost from catalog API-equivalent estimates and carries logical-session/cache caveats instead of claiming final billing reconciliation. Regenerated current artifact at .agent/demos/agent-forensics against /home/sinity/.local/share/polylogue schema v23: 16,498 physical sessions, 4,142,175 messages, 356.5B tokens, ,453.14 stored/provider-priced subset, ,650.88 catalog API-equivalent, and ,197.74 origin_reported catalog estimate. SVG parse check passed for 9 charts; devtools test tests/unit/scripts/test_agent_forensics.py passed; devtools verify --quick passed run 20260703T095718Z-quick-753466-96559776; devloop-review clean. Remaining final-reconciliation blocker stays open as polylogue-4ts.2.","labels":["area:usage","campaign"],"dependencies":[{"issue_id":"polylogue-tf2.1","depends_on_id":"polylogue-4ts.2","type":"blocks","created_at":"2026-07-03T06:32:45Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-tf2.1","depends_on_id":"polylogue-sru.7","type":"blocks","created_at":"2026-07-03T06:31:33Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-tf2.1","depends_on_id":"polylogue-tf2","type":"parent-child","created_at":"2026-07-03T06:31:33Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0} {"_type":"issue","id":"polylogue-tf2","title":"Campaign: agent-forensics regeneration + all-provider repricing","description":"Regenerate the agent-forensics packet on the current archive with an honest all-provider headline. The 2026-06-27 report (546.6B tokens, $89,368 API-list equivalent, 216x cache amplification) is the most stranger-legible artifact on any shelf, but its numbers are pre-dedup stale and the headline prices only the priced-provenance subset (Claude Code cost_usd rows); Codex/ChatGPT/Gemini are origin_reported token counts with no dollar value (operator estimate ~$150K all-provider). Sequenced after claim-vs-evidence per operator direction 2026-07-02.","design":"Current slice design: turn the existing agent-forensics/cost headline into a product-backed all-provider repricing artifact. First inspect devtools/scripts and polylogue analyze surfaces for agent_forensics/cost code. Use active archive usage headline (detail=headline) for authoritative physical_session and logical_session_model_high_water token totals. Keep priced-provenance dollars and origin-reported token estimates separate: do not multiply every token by one blended price without a labeled lane. Add or reuse a shared pricing/projection helper so the demo artifact is regenerated from Polylogue product code, not ad hoc SQL. Acceptance for this slice: the generated agent-forensics artifact names archive root/schema, includes physical vs logical token grain, separates priced subset from origin-reported estimate lanes, gives reproduction commands, and has focused tests for any new repricing helper/surface.","acceptance_criteria":"Terminal state: regenerated forensics packet on the current archive with an honest all-provider headline (priced subset AND origin-reported estimate lanes separated), agent_forensics.py folded into polylogue analyze (tf2.2), artifact on the demo shelf with reproduction commands, cold-reader gate passed. Epic closes only when that artifact is recorded.","status":"closed","priority":0,"issue_type":"epic","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:32Z","created_by":"Sinity","updated_at":"2026-07-31T22:35:43Z","started_at":"2026-07-03T18:47:23Z","closed_at":"2026-07-03T19:06:44Z","close_reason":"Completed: provider usage headline now exposes product-backed pricing lanes in polylogue analyze usage --detail headline, separating stored/provider-priced cost from catalog API-equivalent estimates for origin_reported rows. Regenerated the current .agent/demos/agent-forensics artifact against /home/sinity/.local/share/polylogue schema v23: physical-session tokens 395,320,980,423; logical high-water tokens 288,741,229,728; stored/provider-priced USD 243,392.189328; catalog API-equivalent USD 337,565.031618; priced lane 13,889 rows / 12,331 sessions / 12,650 matched rows; origin_reported lane 2,308 rows / 2,270 sessions / 2,302 matched rows. Verification: live polylogue --plain analyze usage --detail headline --format json --limit 0 wrote /realm/tmp/polylogue-usage-headline-pricing-current.json; devtools test tests/unit/storage/test_provider_usage_report.py tests/unit/cli/test_diagnostics.py passed 23 tests; devtools verify --quick passed run 20260703T190553Z-quick-2226137-d91d4e8f; devtools workspace demo-shelf --json reported ok. Non-claim preserved: this is not final billing reconciliation and physical/logical token grains stay explicitly separated.","labels":["area:usage","campaign","size:M","spine"],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-sru","title":"Campaign: claim-vs-evidence report to finding-grade","description":"Terminal state: an externally publishable finding ('how often do coding agents proceed past failed tool calls, by model/tool') with stated sample frame, calibrated markers, benign/consequential split, seeded stranger-runnable reproduction, and a passed cold-reader gate. Slice closure is NOT campaign closure; this epic stays top-of-frame until its terminal state is recorded.\\n\\nState as of 2026-07-03 after calibrated active-archive regeneration: archive root /home/sinity/.local/share/polylogue, index schema v23, 41,886 structured failures total, 5,000 origin-stratified failures inspected (3,746 claude-code-session, 1,247 codex-session, 7 claude-ai-export), 100 unpaired structured failures. Marker vocabulary was tightened to avoid broad issue/fix/block/gitignored false positives. Immediate next-turn totals: acknowledged=420, silent_proceed=1,205, ambiguous=3,375 (2,624 wordless tool continuations; 751 prose without marker). Lower-bound silent rate is 24.1%; among classified immediate next turns, silent rate is 74.2%. Next-3 sensitivity window, stopping before the next user message, finds 302 acknowledgments that appear only after the next turn; window3 silent lower bound is 37.0%. Calibration: 50 hand-labeled immediate-next-turn rows, acknowledged-marker precision=1.0, recall=0.8421052631578947, invalid rows=0. Artifact: .agent/demos/claim-vs-evidence/claim-vs-evidence.report.json.","notes":"2026-07-03 update: methodology package is now cold-read gated. .agent/demos/claim-vs-evidence contains aggregate live evidence, public-summary.json, PUBLIC_REPRODUCTION.md, COLD_READER_GATE.md, and COLD_READ_RESULT.md. Seeded reproduction is meaningful, not empty: 4 structured failures, 2 acknowledged follow-ups, 2 silent-proceed follow-ups, 0 unpaired. Cold-reader subagent PASS recovered claim/non-claim, sample frame, rates, calibration, caveats, and reproduction commands from the artifact directory only. Remaining campaign child: polylogue-sru.1 productizes action-unit outcome/followup_class capability.","status":"closed","priority":0,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:26Z","created_by":"Sinity","updated_at":"2026-07-31T22:35:43Z","closed_at":"2026-07-03T09:28:09Z","close_reason":"Completed: all seven campaign children are closed. The claim-vs-evidence finding now has bounded sample-frame reporting, calibrated marker precision/recall, handler-class and next-3 sensitivity splits, meaningful seeded reproduction, cold-reader PASS, and productized action-unit followup_class/followup_message_ref query capability. Current artifact lives under .agent/demos/claim-vs-evidence and was regenerated against /home/sinity/.local/share/polylogue schema v23.","labels":["area:substrate","campaign"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-agbgr","title":"preflight: classify blocked replay and all raw parse-error evidence","description":"The reindex preflight ledger must distinguish executable replay candidates from blocked candidates and must count every non-null raw parse-error marker, including empty and whitespace values, so readiness cannot be falsely green.","acceptance_criteria":"1. Replay preflight fails only when executable candidates outnumber blocked candidates; a fully blocked population remains a visible warning.\\n2. Every non-null raw_sessions.parse_error value is represented in source distribution and actionable eligibility counts.\\n3. Focused preflight ledger tests cover both replay orderings and blank/whitespace parse-error values.\\n4. devtools verify --quick passes.\\n5. The ledger remains read-only and does not authorize live replay or migration.","notes":"Unique WIP lane completed on feature/fix/preflight-predicate-corrections. This is a preflight correctness change only; live source remediation remains separately gated.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T22:52:03Z","created_by":"Sinity","updated_at":"2026-08-09T22:52:03Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-8iuna","title":"daemon: make raw parse recovery probe fail closed and index-aware","description":"The raw parse recovery convergence probe must be a trustworthy readiness signal rather than a best-effort diagnostic. Preserve active-index selection, distinguish a clean no-backlog result from probe failure, and keep the route on the daemon-owned production seam.","acceptance_criteria":"1. Probe failures are typed and fail closed; an exception cannot be reported as a clean empty backlog.\\n2. Probe queries follow the active index generation and do not silently inspect a stale index.\\n3. A clean no-backlog route reports an explicit empty result without false debt.\\n4. Focused daemon recovery tests and devtools verify --quick pass.\\n5. This task covers implementation and proof only; live archive recovery remains separately gated.","notes":"Unique WIP lane completed on feature/fix/raw-recovery-probe-authority. The implementation does not authorize live recovery or close any live-operation receipt.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T22:47:39Z","created_by":"Sinity","updated_at":"2026-08-09T22:47:39Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-brb07","title":"Backfill durable message assertion owners before reindex","description":"After message identity and user-state owner-scope changes, existing durable message marks and annotations may have target_ref=message:\u003cid\u003e but no session scope_ref. Before any source freeze or index rebuild, inventory those rows, resolve each message owner from the rebuildable index while it exists, and persist canonical session ownership in user.db. Preserve annotation-batch:\u003cid\u003e provenance, reject ambiguous or missing owners into a typed report, and run only through a verified-backup, transactional, idempotent daemon-owned actuator. This is the deferred successor from polylogue-slshy / PR #3898.","acceptance_criteria":"1. Read-only census reports every legacy message mark/annotation with missing session scope, grouped by resolvable, ambiguous, missing, and already-canonical outcomes, with exact counts and row identities. 2. Apply is authorized only after a verified user.db backup and a frozen census digest; it updates only resolvable rows, preserves target_ref and annotation-batch:\u003cid\u003e scope_ref provenance, and stores canonical session ownership in the designated durable owner field. 3. Ambiguous or missing owners remain unchanged and are emitted as typed residuals; no guessed prefix or message-content match is accepted. 4. Re-running the actuator is a no-op with the same digest and receipt, and crash/failure leaves a recoverable transaction state. 5. Focused real user-tier tests cover legacy rows, batch-scoped annotations, ambiguity, backup/rollback, idempotency, and cold reopen; devtools verify --quick passes. 6. A fresh read-only census proves zero resolvable legacy rows remain before source freeze; residuals are linked to named follow-up beads.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T20:20:58Z","created_by":"Sinity","updated_at":"2026-08-09T20:20:58Z","dependencies":[{"issue_id":"polylogue-brb07","depends_on_id":"polylogue-slshy","type":"discovered-from","created_at":"2026-08-09T20:23:22Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-6qjc.1","title":"daemon: persist judgment scheduler receipts and queue health","description":"Complete the additive scheduler receipt and assertion-candidate queue health slice after the judgment actor implementation. Preserve current daemon lifecycle events and expose completed, parked, failed, retryable, and bounded-result state through API, daemon status, CLI, and surfaces.","acceptance_criteria":"1. Scheduler outcomes persist typed receipt rows in ops.db with status, reason, retryability, batch bound, and result counters. 2. Receipt writes are failure-contained and scheduler state remains retryable after transient errors or restart. 3. API, daemon status, CLI, and payload surfaces project parked-pending and scheduler-stalled states from the receipt authority. 4. Real daemon/API/status tests and devtools verify pass on the exact head. 5. No production mutation is performed by the implementation lane; any live deployment remains a named successor.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T14:44:23Z","created_by":"Sinity","updated_at":"2026-08-09T14:44:23Z","labels":["area:orchestration","horizon:mid"],"dependencies":[{"issue_id":"polylogue-6qjc.1","depends_on_id":"polylogue-6qjc","type":"parent-child","created_at":"2026-08-09T14:44:23Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"polylogue-reindex-preflight-authorization.1","title":"reindex: correct source parse-error and replay preflight predicates","description":"Port the two current-master preflight predicate corrections: count every non-NULL raw_sessions.parse_error, including empty text, as failure evidence; and report replay preflight as fail only when candidate_count exceeds blocked_count. Preserve the existing raw-failure preflight route and current authority gates.","acceptance_criteria":"1. The production preflight source-distribution route counts every non-NULL parse_error, including empty text, and a red twin fails if NULL-only or trimmed-text semantics return. 2. Replay preflight reports fail only when candidate_count \u003e blocked_count, warns for blocked-only work, and preserves existing raw-failure preflight behavior. 3. Focused preflight tests and devtools verify --quick pass on the exact head. 4. No production mutation occurs in this implementation slice. 5. Any remaining preflight authorization scope stays on polylogue-reindex-preflight-authorization.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-08-09T14:44:15Z","created_by":"Sinity","updated_at":"2026-08-09T14:44:15Z","labels":["area:maintenance","lane:reindex"],"dependencies":[{"issue_id":"polylogue-reindex-preflight-authorization.1","depends_on_id":"polylogue-reindex-preflight-authorization","type":"parent-child","created_at":"2026-08-09T14:44:15Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} From fd992631fdcf2c60cdef8015a89dafb97613369c Mon Sep 17 00:00:00 2001 From: Sinity Date: Mon, 10 Aug 2026 01:14:36 +0200 Subject: [PATCH 5/7] fix(preflight): align replay and failure universes --- devtools/preflight_ledger.py | 7 ++++++- polylogue/storage/raw_failure_lifecycle.py | 7 ++----- tests/unit/devtools/test_preflight_ledger.py | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/devtools/preflight_ledger.py b/devtools/preflight_ledger.py index db330d484e..88c4e4965b 100644 --- a/devtools/preflight_ledger.py +++ b/devtools/preflight_ledger.py @@ -365,7 +365,12 @@ def _replay_preflight(root: Path, *, limit: int) -> dict[str, object]: ) candidate_count = _count(payload.get("candidate_count")) blocked_count = _count(payload.get("blocked_candidate_count")) - state = "fail" if candidate_count > blocked_count else "warn" if blocked_count else "pass" + # ``blocked_candidate_count`` includes authority/resource debt that is + # intentionally excluded from ``candidate_count``. Comparing the two + # numbers can therefore hide one executable row behind one unrelated + # blocked row. Any executable candidate is a hard preflight failure; + # blocked-only work remains a visible warning. + state = "fail" if candidate_count else "warn" if blocked_count else "pass" return _status( state=state, reason=( diff --git a/polylogue/storage/raw_failure_lifecycle.py b/polylogue/storage/raw_failure_lifecycle.py index 0c94c8820f..01a0034ab7 100644 --- a/polylogue/storage/raw_failure_lifecycle.py +++ b/polylogue/storage/raw_failure_lifecycle.py @@ -120,10 +120,7 @@ def read_raw_failure_lifecycle(source_db: Path, *, sample_limit: int = 10) -> Ra if raw_table is None: return RawFailureLifecycleSnapshot(False, reason="source.db is missing raw_sessions") parse_failures = int( - conn.execute( - "SELECT COUNT(*) FROM raw_sessions WHERE parse_error IS NOT NULL AND TRIM(parse_error) != ''" - ).fetchone()[0] - or 0 + conn.execute("SELECT COUNT(*) FROM raw_sessions WHERE parse_error IS NOT NULL").fetchone()[0] or 0 ) validation_failures = int( conn.execute("SELECT COUNT(*) FROM raw_sessions WHERE validation_status = 'failed'").fetchone()[0] or 0 @@ -138,7 +135,7 @@ def read_raw_failure_lifecycle(source_db: Path, *, sample_limit: int = 10) -> Ra SELECT r.raw_id, r.origin, r.source_path, r.source_index, r.validation_status, r.acquired_at_ms FROM raw_sessions AS r - WHERE (r.parse_error IS NOT NULL AND TRIM(r.parse_error) != '') + WHERE r.parse_error IS NOT NULL OR r.validation_status = 'failed' ) """ diff --git a/tests/unit/devtools/test_preflight_ledger.py b/tests/unit/devtools/test_preflight_ledger.py index d85857c913..94b1981869 100644 --- a/tests/unit/devtools/test_preflight_ledger.py +++ b/tests/unit/devtools/test_preflight_ledger.py @@ -189,7 +189,7 @@ def test_preflight_fails_closed_on_missing_census_relation(tmp_path: Path) -> No assert "raw_membership_census" in reason -def test_preflight_warns_when_blocked_replay_candidates_outnumber_executable( +def test_preflight_fails_when_executable_replay_candidates_coexist_with_blocked( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: _initialize_all_tiers(tmp_path) @@ -198,7 +198,7 @@ def test_preflight_warns_when_blocked_replay_candidates_outnumber_executable( report = build_preflight_ledger(tmp_path, limit=10) replay = _mapping(_mapping(report["checks"])["replay_backlog"]) - assert replay["state"] == "warn" + assert replay["state"] == "fail" assert replay["candidate_count"] == 2 assert replay["blocked_candidate_count"] == 5 From 67ae58ea5bdf6224f8fad02d4ed97acffa3f43b5 Mon Sep 17 00:00:00 2001 From: Sinity Date: Mon, 10 Aug 2026 01:27:57 +0200 Subject: [PATCH 6/7] fix(preflight): align executable and parse failure predicates --- devtools/preflight_ledger.py | 13 +++++----- polylogue/storage/usage.py | 7 +++-- tests/unit/devtools/test_preflight_ledger.py | 26 ++++++++++++++++++- .../unit/storage/test_origin_usage_report.py | 5 ++-- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/devtools/preflight_ledger.py b/devtools/preflight_ledger.py index 88c4e4965b..23a798a052 100644 --- a/devtools/preflight_ledger.py +++ b/devtools/preflight_ledger.py @@ -365,12 +365,12 @@ def _replay_preflight(root: Path, *, limit: int) -> dict[str, object]: ) candidate_count = _count(payload.get("candidate_count")) blocked_count = _count(payload.get("blocked_candidate_count")) - # ``blocked_candidate_count`` includes authority/resource debt that is - # intentionally excluded from ``candidate_count``. Comparing the two - # numbers can therefore hide one executable row behind one unrelated - # blocked row. Any executable candidate is a hard preflight failure; - # blocked-only work remains a visible warning. - state = "fail" if candidate_count else "warn" if blocked_count else "pass" + executable_component_count = _count(payload.get("executable_authority_component_count")) + # ``candidate_count`` counts raw rows, while ``blocked_candidate_count`` + # includes authority/resource debt. The backlog already computes the + # executable authority-component population, so use that typed relation + # to distinguish executable work from blocked-only work. + state = "fail" if executable_component_count else "warn" if blocked_count else "pass" return _status( state=state, reason=( @@ -383,6 +383,7 @@ def _replay_preflight(root: Path, *, limit: int) -> dict[str, object]: available=True, candidate_count=candidate_count, blocked_candidate_count=blocked_count, + executable_authority_component_count=executable_component_count, authority_quarantined_count=_count(payload.get("authority_quarantined_count")), evidence=payload, ) diff --git a/polylogue/storage/usage.py b/polylogue/storage/usage.py index 244e1ce9fa..a1db0798c6 100644 --- a/polylogue/storage/usage.py +++ b/polylogue/storage/usage.py @@ -1196,11 +1196,10 @@ def _source_raw_stats( SELECT r.origin AS origin, COUNT(*) AS raw_session_count, COALESCE(SUM(CASE - WHEN r.parse_error IS NOT NULL AND TRIM(r.parse_error) != '' THEN 1 ELSE 0 + WHEN r.parse_error IS NOT NULL THEN 1 ELSE 0 END), 0) AS raw_parse_error_count, COALESCE(SUM(CASE - WHEN (r.parse_error IS NULL OR TRIM(r.parse_error) = '') - AND s.session_id IS NULL THEN 1 ELSE 0 + WHEN r.parse_error IS NULL AND s.session_id IS NULL THEN 1 ELSE 0 END), 0) AS acquired_not_materialized_count FROM {alias_sql}.raw_sessions AS r LEFT JOIN sessions AS s ON s.raw_id = r.raw_id @@ -1248,7 +1247,7 @@ def _acquired_not_materialized_raw_rows( LEFT JOIN sessions AS s ON s.raw_id = r.raw_id LEFT JOIN {alias_sql}.raw_membership_census AS c ON c.raw_id = r.raw_id {_where_origin(origin, table_alias="r")} - {"AND" if origin is not None else "WHERE"} (r.parse_error IS NULL OR TRIM(r.parse_error) = '') + {"AND" if origin is not None else "WHERE"} r.parse_error IS NULL AND s.session_id IS NULL ORDER BY r.origin, r.raw_id """, diff --git a/tests/unit/devtools/test_preflight_ledger.py b/tests/unit/devtools/test_preflight_ledger.py index 94b1981869..e26202d10a 100644 --- a/tests/unit/devtools/test_preflight_ledger.py +++ b/tests/unit/devtools/test_preflight_ledger.py @@ -25,12 +25,21 @@ def _list(value: object) -> list[object]: return cast(list[object], value) -def _replay_backlog(candidate_count: int, blocked_candidate_count: int) -> Callable[..., dict[str, object]]: +def _replay_backlog( + candidate_count: int, + blocked_candidate_count: int, + executable_authority_component_count: int | None = None, +) -> Callable[..., dict[str, object]]: def backlog(*_args: object, **_kwargs: object) -> dict[str, object]: return { "available": True, "candidate_count": candidate_count, "blocked_candidate_count": blocked_candidate_count, + "executable_authority_component_count": ( + candidate_count + if executable_authority_component_count is None + else executable_authority_component_count + ), } return backlog @@ -217,6 +226,21 @@ def test_preflight_fails_when_executable_replay_candidates_outnumber_blocked( assert replay["blocked_candidate_count"] == 2 +def test_preflight_warns_when_replay_candidates_are_all_resource_blocked( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + _initialize_all_tiers(tmp_path) + monkeypatch.setattr(preflight_ledger, "raw_materialization_replay_backlog", _replay_backlog(5, 5, 0)) + + report = build_preflight_ledger(tmp_path, limit=10) + replay = _mapping(_mapping(report["checks"])["replay_backlog"]) + + assert replay["state"] == "warn" + assert replay["candidate_count"] == 5 + assert replay["blocked_candidate_count"] == 5 + assert replay["executable_authority_component_count"] == 0 + + def test_preflight_reports_every_non_null_raw_parse_error(tmp_path: Path) -> None: _initialize_all_tiers(tmp_path) _insert_raws( diff --git a/tests/unit/storage/test_origin_usage_report.py b/tests/unit/storage/test_origin_usage_report.py index ea2939aaee..ec8a6d5f9f 100644 --- a/tests/unit/storage/test_origin_usage_report.py +++ b/tests/unit/storage/test_origin_usage_report.py @@ -453,6 +453,7 @@ def test_origin_usage_report_exposes_source_debt_and_stale_rollups(tmp_path: Pat _insert_raw_session(source_conn, raw_id="raw-materialized", native_id="provider-usage-report") _insert_raw_session(source_conn, raw_id="raw-missing", native_id="missing") _insert_raw_session(source_conn, raw_id="raw-error", native_id="bad", parse_error="bad json") + _insert_raw_session(source_conn, raw_id="raw-empty-error", native_id="empty", parse_error="") source_conn.commit() source_conn.close() @@ -503,8 +504,8 @@ def test_origin_usage_report_exposes_source_debt_and_stale_rollups(tmp_path: Pat row = report.origins[0] assert row.coverage_state == "acquired_not_materialized" - assert row.raw_session_count == 3 - assert row.raw_parse_error_count == 1 + assert row.raw_session_count == 4 + assert row.raw_parse_error_count == 2 assert row.acquired_not_materialized_count == 1 assert row.sample_acquired_not_materialized_raw_ids == ("raw-missing",) assert row.stale_rollup_session_count == 1 From d9138a73b8d52556f5824a2089f9d68d3fdd2987 Mon Sep 17 00:00:00 2001 From: Sinity Date: Mon, 10 Aug 2026 01:45:30 +0200 Subject: [PATCH 7/7] fix(preflight): fail closed on unclassified replay --- devtools/preflight_ledger.py | 6 +++++- tests/unit/devtools/test_preflight_ledger.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/devtools/preflight_ledger.py b/devtools/preflight_ledger.py index 23a798a052..67dc5ac0bc 100644 --- a/devtools/preflight_ledger.py +++ b/devtools/preflight_ledger.py @@ -370,7 +370,9 @@ def _replay_preflight(root: Path, *, limit: int) -> dict[str, object]: # includes authority/resource debt. The backlog already computes the # executable authority-component population, so use that typed relation # to distinguish executable work from blocked-only work. - state = "fail" if executable_component_count else "warn" if blocked_count else "pass" + state = ( + "fail" if executable_component_count else "warn" if blocked_count else "unknown" if candidate_count else "pass" + ) return _status( state=state, reason=( @@ -378,6 +380,8 @@ def _replay_preflight(root: Path, *, limit: int) -> dict[str, object]: if state == "fail" else "raw replay candidates are authority/resource blocked" if state == "warn" + else "raw replay candidates lack executable or blocked classification" + if state == "unknown" else None ), available=True, diff --git a/tests/unit/devtools/test_preflight_ledger.py b/tests/unit/devtools/test_preflight_ledger.py index e26202d10a..b07a7244d7 100644 --- a/tests/unit/devtools/test_preflight_ledger.py +++ b/tests/unit/devtools/test_preflight_ledger.py @@ -241,6 +241,19 @@ def test_preflight_warns_when_replay_candidates_are_all_resource_blocked( assert replay["executable_authority_component_count"] == 0 +def test_preflight_is_unknown_when_replay_candidates_are_unclassified( + tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + _initialize_all_tiers(tmp_path) + monkeypatch.setattr(preflight_ledger, "raw_materialization_replay_backlog", _replay_backlog(1, 0, 0)) + + report = build_preflight_ledger(tmp_path, limit=10) + replay = _mapping(_mapping(report["checks"])["replay_backlog"]) + + assert replay["state"] == "unknown" + assert report["ok"] is False + + def test_preflight_reports_every_non_null_raw_parse_error(tmp_path: Path) -> None: _initialize_all_tiers(tmp_path) _insert_raws(