From 46056c1577ced2d128b5b1ba45b5121c5a886fcd Mon Sep 17 00:00:00 2001 From: Sinity Date: Wed, 15 Jul 2026 02:11:48 +0200 Subject: [PATCH 1/2] fix(test): allowlist SearchEnvelope's PR #2899 additive fields Problem: test_envelope_required_fields_are_stable has been failing on master since PR #2899 merged (query_run_ref/query_hash/result_fingerprint/ exactness added to SearchEnvelope, all Optional/None-default for byte-compat) without updating this drift gate's allowlist. Verification: devtools test tests/unit/surfaces/test_search_envelope_contract.py -> 6 passed (was 1 failed, 5 passed). --- .beads/issues.jsonl | 1676 +++++++++-------- .../surfaces/test_search_envelope_contract.py | 7 + 2 files changed, 852 insertions(+), 831 deletions(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 59582a6de0..2608f27b18 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,831 +1,845 @@ -{"_type":"issue","id":"polylogue-layg","title":"Fix excision bypass via second write chokepoint (blocker, held off #2875)","description":"Adversarial review of PR #2875 (polylogue-27m, local excision + secret detection) found the excision non-resurrection guarantee is bypassable through a second, real production write chokepoint: write_source_raw_session checks is_blob_hash_excised before insert, but a sibling write path does not (see polylogue/storage/sqlite/archive_tiers/source_write.py around line 434). This is a BLOCKER — PR #2875 was deliberately NOT merged pending this fix. Also flagged: resolve_session_excision_target/apply_session_excision only resolve rows keyed directly to session_id, missing related rows; docs/plans/security-privacy-coverage.yaml marks captured_content_secret_detection implemented:true and removes it from coverage_gaps but the scanner's actual coverage may not support that claim (reviewer flagged as major, verify before keeping the claim).","acceptance_criteria":"The second write chokepoint also checks is_blob_hash_excised before insert (or a shared helper enforces this at a single chokepoint both paths use). Session excision resolves related rows, not just session_id-keyed rows. The security-privacy-coverage.yaml claim is verified true or reverted to its prior severity. Regression test proves excised content cannot resurface via the previously-bypassable path. Then PR #2875 (or its successor) merges.","status":"open","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-14T08:21:28Z","created_by":"Sinity","updated_at":"2026-07-14T08:21:28Z","labels":["area:security","area:storage","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-9e5.31","title":"Audit definition-to-consumer wiring closure across Polylogue","description":"Polylogue has repeatedly shipped useful definitions or mechanisms whose full consumer closure was absent or partial: write-only tables, zero/tests-only facade methods, assertion kinds without writers, typed daemon events without production producers/consumers, staleness predicates bypassed by sibling paths, provenance fields dropped by public readers, and contracts used only by shadow adapters. Existing audits find these one family at a time; there is no systematic definition-to-production-consumer-to-surface closure census. This investigation must enumerate the remaining cases without treating every conceivable integration as mandatory: beneficial wiring requires a declared product/runtime invariant, an established symmetric family, observed usage, or a concrete operational payoff.","design":"Compose existing authoritative substrates instead of creating a competing registry. Use the runtime ArtifactGraph/OperationSpec catalog for artifacts, materialization, maintenance, and declared surfaces; use live CLI/MCP/HTTP/Python/read-view/workflow/origin/assertion/query registries for extension families; use DDL and AST inventories for tables, fields, protocols, events, and config. For each family define its required edge schema before scanning (examples: durable data = writer + reader + lifecycle/backup/reset/status; event = producer + consumer + durable fallback + shutdown; public operation = substrate + intentional surface bindings + shared contract + docs + real-route proof; enum/registry kind = producer + consumer + serialization + completeness check). Join four evidence planes: static references/imports, runtime registry discovery, live usage/data, and mutation-sensitive real-route tests. Classify zero-consumer, tests-only/shadow-only, partial fan-out, sibling bypass, divergent twins, write-only/read-only, lifecycle-unmanaged, and intentional asymmetry. Require stable semantic operation IDs and explicit intentional-absence authority; name similarity and aggregate surface buckets are not proof. Produce read-only evidence artifacts and split every product change into a follow-up bead.","acceptance_criteria":"1. A committed or durable evidence matrix enumerates each audited declaration family, its authoritative inventory source, item count, required consumer edges, actual evidence refs, intentional exceptions, and unresolved rows; no row is silently auto-classified intentional. 2. Coverage includes runtime artifacts/DDL, derived-model convergence and invalidation, events/write effects, protocols/facade methods, origins/assertion/ref kinds, query fields/units/stages/read views, configuration, and semantic operations across CLI/MCP/HTTP/Python/web/docs/generated contracts. 3. Every candidate is independently verified against current production source and classified as definite gap, intentional asymmetry, beneficial opportunity with concrete payoff, or false positive; tests-only and shadow adapters do not count as production wiring. 4. Runtime/live evidence is used where static evidence cannot prove use; mutation/removal anti-vacuity is specified for fixes. 5. Existing known beads are reconciled rather than duplicated, and every new actionable gap gets a linked follow-up bead with execution-grade design/AC. 6. The final audit reports coverage limits explicitly and demonstrates that re-running its machine-checkable census detects seeded missing-edge mutations in at least one registry, one storage/lifecycle family, and one cross-surface operation family.","status":"open","priority":2,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-15T00:52:19Z","created_by":"Sinity","updated_at":"2026-07-15T00:52:19Z","labels":["area:audit","delivery:A-trust-floor","horizon:frontier","lane:usage-cost-honesty"],"dependencies":[{"issue_id":"polylogue-9e5.31","depends_on_id":"polylogue-9e5","type":"parent-child","created_at":"2026-07-15T02:52:19Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-7ufv","title":"Copy reused index clones across archive subvolumes","description":"The retry prepare correctly reused a completed v36 index generation, but reuse_index_clone used os.replace directly from the archive generation to the staging receipt directory. Those paths are on separate subvolumes and fail with EXDEV before receipt creation.","design":"Use reflink_clone into a temporary file in destination.parent, then rename locally to destination and fsync. Preserve the source generation until the local publish succeeds; remove the original staged clone only when it is safe and not an archive generation. Add an EXDEV regression.","acceptance_criteria":"Reusing a v36 index clone across distinct parents succeeds when direct cross-parent os.replace raises EXDEV; destination is correct and no temporary file remains. Focused test and devtools verify --quick pass.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T21:14:03Z","created_by":"Sinity","updated_at":"2026-07-13T22:48:15Z","started_at":"2026-07-13T21:14:12Z","closed_at":"2026-07-13T22:48:15Z","close_reason":"PR #2868 merged (fix(storage): copy reused index clones locally). Live v36 cutover activated successfully using the fixed reuse_index_clone path: reflink into a temp file in destination.parent, then local rename+fsync, avoiding the EXDEV cross-subvolume os.replace. Verified via the successful v36-retry2 activation (source=9,user=8,index=36,embeddings=2,ops=1).","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-rze2","title":"Finalize fast-forward receipt after durable WAL cleanup","description":"The v35→v36 activation promoted all tiers but then rejected normal source/user WAL sidecars during final evidence collection outside its rollback transaction. This left the archive promoted with a receipt still marked prepared. The actuator must finalize/checkpoint durable files before immutable evidence and retain rollback semantics for every post-promotion exception.","design":"Keep final evidence collection inside the activation try/except. Explicitly finalize/checkpoint source and user after migrations, then collect versions through immutable evidence. Any failure before the activated receipt is written must restore every promoted tier and durable snapshot and write a rolled_back receipt. Add a regression that simulates durable sidecars after a successful migration and proves either activated receipt or full rollback.","acceptance_criteria":"Focused regression reproduces the post-migration durable-sidecar state and passes. Successful activation records status activated with source=9,user=8,index=36,embeddings=2,ops=1 and no ambiguous sidecars. A forced final-evidence failure restores v35/v1 files and writes rolled_back. Run focused tests plus devtools verify --quick.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T20:32:20Z","created_by":"Sinity","updated_at":"2026-07-13T22:48:16Z","started_at":"2026-07-13T20:32:32Z","closed_at":"2026-07-13T22:48:16Z","close_reason":"PR #2867 merged (fix(storage): finalize fast-forward durable WALs). Live v36 cutover activated successfully: final evidence collection now runs inside the activation try/except with source/user WAL finalization before immutable evidence reads. Verified via successful v36-retry2 activation (status=activated, no rollback, versions match target).","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-b08j","title":"Make schema-forward rollback cross-subvolume safe","description":"Live v35→v36 activation failure after rollback snapshots revealed that archive and staging locations can be distinct Btrfs subvolumes: `os.replace(active, rollback/failed-...)` raises EXDEV. Snapshot-only entries must not be restored as promoted files.\\n\\nAcceptance criteria:\\n- A migration failure leaves every active tier byte-identical to pre-activation.\\n- Rollback handles EXDEV without data loss.\\n- Tests cover a failure before any derived promotion and cross-device rollback behavior.\\n- Failure receipt records rolled_back rather than masking the root error.","notes":"2026-07-13 live evidence: first repair handled regular derived-file promotion and durable snapshot restore, but fixed activation then reached `_promote_index_generation` and hit EXDEV moving staged index into the active generation directory. Receipt safely rolled back; active versions/fingerprints remain v7/v6/v35/v1/v1. Follow-up implementation is extending the same actuator repair to generation publication with an EXDEV regression test.","status":"closed","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T19:03:21Z","created_by":"Sinity","updated_at":"2026-07-13T23:05:58Z","closed_at":"2026-07-13T23:05:58Z","close_reason":"PR #2865 (fix(storage): restore schema snapshots across subvolumes) + PR #2866 (fix(storage): localize index generation promotion) merged. Live v36 cutover activated successfully with zero rollback triggered — the cross-subvolume EXDEV rollback path this bead fixed was exercised by two earlier failed attempts (rolled back cleanly both times) and the third attempt succeeded outright, proving both the failure-path (rollback) and success-path (promotion) are now correct.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-25vy","title":"Repair v7 source migration authority backfill","description":"Live v35→v36 activation on a verified source v7 archive fails in source migration 008 with `NOT NULL constraint failed: raw_sessions.revision_authority`. The migration must preserve existing rows while installing the v8 authority invariant.\\n\\nAcceptance criteria:\\n- Upgrade a representative v7 source fixture with NULL revision_authority rows to v9.\\n- Every migrated row has semantically correct non-NULL authority.\\n- Existing backup-manifest authentication remains required.\\n- Focused regression test exercises the real migration runner.","status":"closed","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T19:03:14Z","created_by":"Sinity","updated_at":"2026-07-13T23:05:57Z","closed_at":"2026-07-13T23:05:57Z","close_reason":"PR #2864 merged (fix(storage): map v7 source revisions by name). Live v36 cutover activated successfully — source.db migration through v9 completed clean (quick_check=ok, FK check empty), proving the positional-copy bug (predecessor_source_revision shifting into revision_authority) is fixed.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-uqj0","title":"Fast-forward v35 archive to master schema without raw replay","description":"After v35 postflight, current master requires source9/index36/embeddings2/user8. Live evidence: source 51MB/23,934 raws; user 86KB; index 35.2GB/18,230 sessions and 8,629 links; embeddings 5.59GB/752,307 vectors. No beads-issue origins or Beads paths/artifacts exist. Master package therefore safely refused v35 but the actual delta should not force raw reparse.","design":"Implement an audited clone-first v35→36 derived-tier forward and run existing durable migrations. Source7→8 adds capture_mode and 8→9 copy-forwards seven 51MB tables to widen Origin; user6→8 is additive query provenance. Index36 requires copy-forward sessions and session_links to update dynamic Origin CHECKs, preserving all 26 dependent FK declarations (legacy_alter_table=ON/foreign_keys=OFF during clone rename/copy), all rows/indexes/views/FTS, canonical DDL, and structural counts. Gate only when no Beads origins/artifacts are present. Embeddings1→2 clone-adds embedding_failures/index with no vector replay. Rotate disposable ops.db. Use a fresh verified backup; atomically promote clones; no raw parser replay/FTS rebuild; receipts prove every phase and rollback.","acceptance_criteria":"1. Fixture tests prove source/user durable migrations and index36 clone copy-forward preserve FK graph/DDL/counts with no Beads rows; Beads rows fail closed. 2. Embeddings clone preserves vectors and adds lifecycle table/index. 3. Live cutover uses fresh verified backup, source/user migration runner, reflink clones, atomic swaps, retained rollback, and receipts. 4. Postflight reports source9/index36/embeddings2/user8, zero FK/DDL/count drift, daemon healthy and one bounded append cycle. 5. No raw-session reparse, FTS rebuild, or vector re-embedding.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T16:47:58Z","created_by":"Sinity","updated_at":"2026-07-13T22:48:16Z","started_at":"2026-07-13T16:48:54Z","closed_at":"2026-07-13T22:48:16Z","close_reason":"Live cutover completed 2026-07-14 00:44 CEST via devtools workspace archive-schema-fast-forward activate against receipt v36-retry2-prepare-20260713T211800Z.json (backup manifest polylogue-archive-20260713T164600Z/manifest.json). Result: status=activated, no activation_error, versions source=9 user=8 index=36 embeddings=2 ops=1 (exact AC targets), rollback paths retained for all three promoted tiers. Independent postflight (not just the tool's self-report): quick_check=ok on all four live tiers, foreign_key_check empty on index+source, structural counts 18,230 sessions / 4,692,737 messages (matches pre-migration session count, zero raw reparse). polylogued.service restarted clean (active, NRestarts=0, watcher cursors reconciled). No Beads-issue origins/artifacts were present in source/index (require_no_beads_evidence gate passed implicitly, activation would have refused otherwise).","labels":["area:ops","area:storage","area:test","delivery:B-storage-rebuild-bytes","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-lkrc.3","title":"Adjudicate conflicting browser canonical authority","description":"Stopped-daemon census for polylogue-lkrc.2 found four current ChatGPT sessions whose unknown-export byte head cannot be safely rekeyed: 6567faf1… and c106589… have semantic canonical heads with different content hashes (c106 diverges at message 523); 3c144e… has superseded_equivalent membership plus canonical hash conflict (diverges at message 1333); 88aefc84… has production reparse hash drift and incompatible canonical byte head from message 0. They remain current source-origin mismatches after the narrow exact-byte rekey cohort.","design":"Do not overwrite, delete, or reinterpret either head from title/partial message equality. Build evidence packets for each divergent history, establish whether a new capture/source revision can select one authority under explicit operator policy, or retain both with a materialization representation that does not lie about source identity. Any solution must be receipted, idempotent, preserve old blobs/raws/apps/memberships/heads, and avoid weakening generic browser/quarantined actuators.","acceptance_criteria":"1. Exact per-session evidence packet records divergence, content hashes, parse identity, application/membership/head chain. 2. Chosen authority policy is explicit and testable; no automatic overwrite based on partial equality. 3. If a repair is authorized, it is copy-forward/receipted/rollback-safe and leaves historical evidence intact. 4. After all parent children, current source-origin identity census is zero or every intentionally unresolved conflict is represented as an explicit durable blocking state rather than silently mismatched. 5. Focused tests and quick verification pass.","notes":"2026-07-14 implementation: PR #2877 (branch feature/fix/raw-identity-repair-cluster, commit 6cc16c82f) adds inspect_browser_canonical_authority_conflicts() + record_browser_canonical_authority_conflict_blockers() to polylogue/storage/repair.py. Read-only inspector re-runs repair_byte_proven_browser_capture_null_native_ids's exact eligibility proof and, for each of the 4 ineligible conflicts, builds a structured evidence packet (competing raw_revision_heads content hash/frontier_kind/decision, blocking raw_session_memberships row, best-effort divergent message index via session_revision_projection for single-session byte-frontier pairs) instead of only the terse ineligible_reason string. record_browser_canonical_authority_conflict_blockers persists each as a durable AssertionKind.BLOCKER candidate assertion in user.db, deterministic id over (raw_id, evidence_digest), written through upsert_assertion's author_kind=detector chokepoint so it is always forced to status=candidate/inject:false -- satisfies AC2 (no automatic overwrite) by construction, since no authority selection is made anywhere in this PR.\nAC status: AC1 (per-session evidence packet) satisfied. AC2 (explicit testable policy, no auto-overwrite) satisfied -- no repair path added at all for these 4. AC3 (if a repair is authorized...) not applicable -- no repair authorized. AC4 (after all parent children, census is zero OR every conflict has an explicit durable blocking state) partially satisfied: the durable blocking-state mechanism now exists and is tested; running it against the live 4 production conflicts to actually create those durable rows is live-execution and reserved for the operator per this cluster's live-archive-safety constraint. AC5 (focused tests + quick verification) satisfied: 6 new tests in tests/unit/storage/test_browser_capture_origin_repair.py, devtools verify --quick exit 0.\nVerification: devtools test tests/unit/storage/test_browser_capture_origin_repair.py -k \"conflict or record_conflict\" -> 11 passed. devtools verify --quick -> exit_code 0 (15/15, including verify degrade-loudly after adding a logger.warning to the new best-effort except-handler). No live archive touched.","status":"open","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T16:34:38Z","created_by":"Sinity","updated_at":"2026-07-14T01:04:16Z","labels":["area:browser","area:sources","area:storage","delivery:A-trust-floor","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-lkrc.3","depends_on_id":"polylogue-lkrc","type":"parent-child","created_at":"2026-07-13T18:34:37Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-cnaj","title":"Bound active JSONL append ingestion memory and catch-up overlap","description":"Live v35 incident on 2026-07-13: an actively appended 46 MB Codex JSONL was selected by periodic catch-up every ~16 seconds. Each append reported 0.1–0.3 MB read but held daemon writer 37–38 seconds and temporarily grew anonymous RSS from ~0.4 GiB to ~4.2 GiB; cgroup memory reached the 8 GiB high threshold (6,655 high events), 22 GB reads and 3.2 GB writes in 8.5 minutes. Daemon was intentionally stopped before OOM. This blocks safe unattended backfill/daemon operation.","design":"Build a reproducible harness from the observed active-append shape, then locate retained full-session/materialization state and overlapping periodic scheduling. Preserve correctness for append frontier, source/index atomicity, quiet deferral and crash recovery. The fix must bound live working set and prevent redundant catch-up while a prior pass is active; do not solve this by permanently disabling watching, broadening loss windows, or weakening authority proofs. Prove exact recovery/cursor behavior after daemon restart.","acceptance_criteria":"1. Reproduction measures memory high-water and bounded input work for a large, actively appended Codex JSONL. 2. One active file cannot schedule overlapping/redundant catch-up while its prior append pass is running. 3. Append ingestion retains no full historical payload/model beyond its operation boundary; RSS is bounded materially below service MemoryHigh on the reproduction. 4. Cursor/frontier/source/index correctness, restart recovery and failure rollback remain proven. 5. Focused tests and quick verification pass; live restart postflight does not reintroduce the hot loop.","notes":"Scoped 2026-07-13: reproduce and fix the active Codex JSONL append memory/catch-up incident in polylogue/sources/live plus focused tests only. I will use the existing #2841 cohort-memory harness, preserve cursor/frontier and rollback semantics, and avoid live archive or daemon mutation.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T16:19:03Z","created_by":"Sinity","updated_at":"2026-07-13T16:39:42Z","started_at":"2026-07-13T16:19:59Z","closed_at":"2026-07-13T16:39:42Z","close_reason":"PR #2849 merged as 2b0221a98. Established byte-proven append cohorts now use durable replay metadata without historical full reads; incomplete/omitted-current chains classify then defer without cursor advance. Focused harness: 4 passed; devtools verify --quick: 15 checks passed. Live daemon remains stopped for operator postflight.","labels":["area:daemon","area:ingest","area:storage","delivery:G-live-performance","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-lkrc.2","title":"Repair remaining current unknown-origin ChatGPT heads","description":"Live postflight after the final legacy NULL-native-id copy-forward found nine current chatgpt-export sessions whose sessions.raw_id still points at a durable source.raw_sessions row typed origin=unknown-export with logical_source_key=unknown:. They are distinct from the three original lkrc raws: two siblings now point to canonical byte-proven copies and the legacy target points to 402915...; this residual cohort is a separate current-authority problem.","design":"Start from a fresh stopped-daemon census that joins current sessions to source.raw_sessions and production-normalizes each retained blob. Partition rows by existing revision/head/application/membership evidence; reuse an already-proven copy-forward route only when every source/index witness exactly matches its contract. Preserve original raw/blob/membership/head/application evidence, create a canonical replacement rather than relabelling historical raws, require a proof digest plus planned/applied receipt, and keep source-v7/v35 active-index compatibility. Do not treat retained non-current historical unknown heads as current mismatches.","acceptance_criteria":"1. Exact before census names every current session backed by unknown-export raw and distinguishes non-current retained history. 2. Every eligible row is repaired through a receipted, proof-bound, idempotent evidence-preserving path; ineligible shapes remain fail-closed with a durable reason. 3. Exact after census is zero current sessions whose raw origin/logical key disagrees with the production-normalized ChatGPT identity. 4. Focused real-route tests cover the observed evidence shapes, drift/rollback, generated active-index routing, and source-v7 compatibility; quick verification passes. 5. Live use follows a verified backup, stopped daemon, fresh dry proof, immutable receipt, and restart postflight.","notes":"Discovered 2026-07-13 after successful live legacy child repair receipt legacy-native-repair-20260713T160800Z.jsonl. Exact initial current cohort raw IDs: 3c144e4b6eccf6c65368488be8c952a510a50ed86deb9c93453b1a0dd08a55b2, 773bbbf1b92e763a0e85d1c798f127d94aa1e0f70b6e91978bcdd7cfbecc078d, 2af730ea7ca773cbb1983498d3103616e7309c41593cafa8e781a3eb151eca3b, bd47782eea0579a4bcba6d5b51670e4f71a80cf1473f38ee2536d07afb2ff1e0, 6567faf1da05d51ab8343fba6334602eef120f6b39ca1edb884a71edabe90d0d, 27527c1586e4e0105ec2a73c2206709af1ce74df0c0bb4dea24069f350644538, f43a203e159d29f403cca7123fb95c83ab3169f27978b7caa029c6496a0309e6, c10658915c27d74517c5d6f941247007564275d3d9360b2290683feb6593ee4b, 88aefc84afb181135c76a724b361ef21a9aa856f2a1ef117511e08fdceba2785.\nRead-only stopped-daemon census 2026-07-13: correct raw f43a203e159… to f43a203a359d29f403cca7123fb95c83ab3169f27978b7caa029c6496a0309e6. All nine old heads are unknown-export/native_id NULL/full+byte_proven/gen0 with one selected-baseline app and production parser identity match. Safe common rekey candidates: 773bbbf1…, bd47782e…, f43a203a… (no canonical head); 2af730ea…, 27527c15… (exact-equal semantic canonical witnesses). Fail-closed: 6567faf1… and c106589… semantic canonical hash conflicts (c106 diverges message 523); 3c144e… superseded_equivalent membership plus canonical hash conflict (diverges message 1333); 88aefc84… current reparse hash drift/incompatible canonical byte head. Existing actuators correctly reject all. Implement a new sibling byte-proven-browser-rekey actuator only for the five exact shapes; preserve all old/semantic evidence and record ineligible reasons for the four.\n2026-07-13: Claimed for isolated implementation of the sibling evidence-preserving byte-proven browser rekey actuator. Scope is exactly five proof-approved shapes; four observed conflict/drift shapes remain fail-closed. No live archive or daemon mutation is authorized by this implementation lane.\n2026-07-13: implementation merged in PR #2850 / master 64f4a00e8. The new repair_byte_proven_browser_capture_null_native_ids actuator is intentionally limited to the five proof-approved byte-proven NULL-native shapes. Verification: devtools verify --quick; focused byte-rekey matrix 10 passed. No live archive or daemon mutation occurred. Remaining scope is the parent-run stopped-daemon dry proof/apply/postflight, including durable reasons for the four ineligible rows.\n2026-07-14 status check (no live archive touched): re-verified the code portion of this bead is complete on current master (PR #2850 / 64f4a00e8, repair_byte_proven_browser_capture_null_native_ids). Confirmed via the existing 10-case focused byte-rekey matrix (test_byte_proven_browser_rekey_*) plus this session's own re-run: devtools test tests/unit/storage/test_browser_capture_origin_repair.py -k \"conflict or record_conflict\" -> 11 passed. No further code change made or needed for this bead specifically in PR #2877 -- that PR's lkrc.3 work builds ON TOP of this bead's actuator (re-runs its exact eligibility proof) rather than modifying it. Remaining scope per this bead's own notes (\"parent-run stopped-daemon dry proof/apply/postflight, including durable reasons for the four ineligible rows\") is entirely live-execution, reserved for the operator; the \"durable reasons for the four ineligible rows\" portion is now directly actionable via record_browser_canonical_authority_conflict_blockers (PR #2877, polylogue-lkrc.3) once the operator runs it live.","status":"in_progress","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T16:13:11Z","created_by":"Sinity","updated_at":"2026-07-14T01:05:33Z","started_at":"2026-07-13T16:31:27Z","labels":["area:browser","area:sources","area:storage","delivery:A-trust-floor","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-lkrc.2","depends_on_id":"polylogue-lkrc","type":"parent-child","created_at":"2026-07-13T18:13:10Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-lkrc.1","title":"Copy forward legacy browser raw missing native identity","description":"After PR #2839 hardens browser-origin copy-forward proofs, the final live lkrc target 282983b4ec87c080fd60c31d9ebaa415a38f57c8f57bb22cdeda1b7906aca2c0 correctly refuses because its durable unknown-export raw has native_id=NULL, even though its retained browser-capture bytes parse to ChatGPT session 6a149c9e-2910-83eb-a93b-e6805f9f94f8. The row must not be relabelled or mutated in place.","design":"Add a separate, explicitly named evidence-preserving legacy-native-missing copy-forward route. It may accept native_id=NULL only as the exact legacy evidence shape, not as a general relaxation: prove raw origin=unknown-export, browser-capture provenance, native_id NULL, source/blob-ref path/hash/size agreement, complete singleton census, quarantined full envelope, production parse yields exactly one canonical ChatGPT session, canonical semantic authority and all applications/memberships/head witnesses match, and no competing old/canonical applications exist. Create a new canonical raw/application/receipt with parsed native identity; never update/delete the old raw/blob/head/application/membership. Planned/applied receipt records legacy-null witness and parser-derived native ID; locked reproof/CAS is all-or-nothing; reapply idempotent. Keep source-v7 compatibility.","acceptance_criteria":"1. Real-route fixture with legacy native_id NULL is ineligible to ordinary copy-forward but eligible only to the dedicated actuator after every listed witness is proven. 2. Any non-NULL wrong native, origin/path/blob/census/parser/session/head/application/timestamp/frontier/sibling drift fails before source write. 3. Apply makes a new correctly typed canonical raw and leaves all old evidence byte-for-byte unchanged; receipt proves the legacy-null witness and parsed identity. 4. Reapply is idempotent; planned/apply mismatch or post-proof failure rolls back. 5. Focused tests + quick pass; live use only after fresh full backup, stopped daemon, read-only dry run, exact receipt, apply, and postflight zero mismatched heads.","notes":"2026-07-13: Claimed after PR #2839 merged as db586289e. Ordinary actuator is deliberately fail-closed for native_id=NULL; this child owns the separate legacy-only copy-forward path. Implementation must preserve source-v7 compatibility and not mutate the old raw.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T12:54:50Z","created_by":"Sinity","updated_at":"2026-07-13T16:16:35Z","started_at":"2026-07-13T13:03:10Z","closed_at":"2026-07-13T16:16:35Z","close_reason":"Live repair applied with receipt legacy-native-repair-20260713T160800Z.jsonl; source-v7-compatible v35 artifact verified; rerun reports already_repaired.","labels":["area:browser","area:sources","area:storage","delivery:A-trust-floor","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-lkrc.1","depends_on_id":"polylogue-lkrc","type":"parent-child","created_at":"2026-07-13T14:54:49Z","created_by":"Sinity","metadata":"{}"}],"comments":[{"id":"019f5bb0-a6fb-7469-a902-893404f4e28f","issue_id":"polylogue-lkrc.1","author":"Sinity","text":"2026-07-13 implementation update: legacy-only NULL-native route now refuses a pre-existing canonical head, requires exactly one old raw membership key and payload blob reference, and stages source copy-forward plus index authority transition in one attached-source transaction. A regression injects a failure after source staging and proves old source/index rows remain unchanged with a planned-only receipt. Verification: devtools test tests/unit/storage/test_browser_capture_origin_repair.py -k legacy_browser_native_id (13 passed); devtools test tests/unit/storage/test_browser_capture_origin_repair.py tests/unit/cli/test_archive_maintenance_cli.py -k 'legacy_browser_native_id or rejects_legacy_raw_without_native_id' (15 passed); devtools verify --quick (passed). Pending independent re-audit; no live archive actuator has been run.","created_at":"2026-07-13T13:35:32Z"}],"dependency_count":0,"dependent_count":0,"comment_count":1} -{"_type":"issue","id":"polylogue-lkrc","title":"Repair browser-capture raws whose origin disagrees with parsed identity","description":"Live v35 post-fast-forward census on 2026-07-13 found three current ChatGPT byte heads backed by source raws typed under origin=unknown-export / logical_source_key=unknown:, while the retained bytes normalize through the production parser to chatgpt-export sessions. Exact raws: 282983b4ec87c080fd60c31d9ebaa415a38f57c8f57bb22cdeda1b7906aca2c0 (session 6a149c9e-2910-83eb-a93b-e6805f9f94f8), 862986515c59e95d11b630ad1aa479d6cace4bf8e08631e84616f9f774280426 (6a49af33-d698-83ed-a11f-8750f19027e1), affadd9d437991bf4731cfa892e2bf4db935db627d174f1418abe0875ec1ded5 (6a49b1cc-2044-83ed-9787-7e79a6b7b325). All have revision_kind=full, exact byte source_revision, acquisition_generation=0, revision_authority=quarantined, baseline_raw_id=NULL, complete one-member census, and parallel/historical provenance. The yla8.10 exact repair correctly refuses them because raw origin and parser identity disagree.","design":"Fix the browser-capture acquisition/detection boundary so newly retained ChatGPT captures receive the canonical chatgpt-export origin and logical source identity before authority classification. For the three durable historical raws, use evidence-preserving reacquisition/supersession under the correct origin or a separately reviewed copy-forward correction that respects raw-id identity; never relabel a durable raw in place, manufacture byte authority for an unknown-origin row, delete parallel heads/applications/memberships, or weaken origin/parser equality. Dynamically re-census after yla8.10 postflight because browser backfill may add captures.","acceptance_criteria":"1. A real browser-capture fixture whose bytes parse as ChatGPT is acquired with chatgpt-export origin and a matching logical source key; unknown-export cannot claim it. 2. The three named historical rows are superseded or copy-forward repaired through a durable, receipted path without mutating/deleting existing raw/blob/head/application/membership evidence. 3. Origin/parser mismatch remains fail-closed and cannot be promoted to byte_proven. 4. Dynamic live census reports zero current byte heads whose source origin/logical key disagree with normalized parser identity, with exact before/after receipts. 5. Focused acquisition/classification/replay tests and devtools verify --quick pass; yla8.10 postflight evidence is linked.","notes":"2026-07-13 live v35 postflight: verified full_evidence backup receipt at /realm/staging/polylogue-sqlite/recovery/lkrc-v35-20260713T042736Z/polylogue-archive-20260713T042738Z/verification-receipt.json (all five SQLite tiers, 26,600 blobs). Exact v7/index-v35/user-v6 artifact completed all watcher catch-up chunks with no recurrence of membership replay cannot retire an unrelated accepted head. Stopped-daemon census found 11 unknown-export->ChatGPT session/raw mismatches. The three lkrc raws are quarantined full singleton censuses with canonical membership decision NULL and exact old unknown-key selected-baseline receipts; actuator now requires that narrow dual witness. The other 8 are excluded: 7 byte_proven unknown raws without membership/census, 1 byte_proven superseded-equivalent membership; separate follow-up required.\n2026-07-13 adversarial loop iteration 5 reached its cap with unresolved P0 proof gaps; do not merge/apply #2839 head 3b0ca3f08. Real residuals: (1) semantic canonical and historical sibling source envelopes omit capture_mode; require canonical provider when schema has field, with v7 fallback. (2) original unknown raw blob_ref.source_path is not bound to raw source_path in preflight/locked reproof. (3) original unknown raw native_id is not bound to reparsed provider session id preflight/locked reproof. (4) restore_canonical_head exact-byte route omits native_id, source_index, capture_mode, predecessor/append envelope fields; normalize conditional full-envelope proof for exact/semantic/sibling paths. Lower severity: historical supersession decided_at_ms accepts negative values. Iteration-5 reviewer found these against the current 31-test terminal closure; no live mutation after findings. Further implementation plus an operator-authorized review cycle is required before merge/apply.\n2026-07-14 code-verification pass (no live archive touched): re-checked the \"adversarial loop iteration 5\" proof gaps recorded in this bead's prior note against current master (031d8d183) source. All 3 named residual gaps -- (1) capture_mode binding, (2) blob_ref.source_path binding, (3) native_id binding into the preflight/locked reproof witness -- are already present in _browser_origin_source_envelope_is_exact (polylogue/storage/repair.py), which every browser-origin repair path (exact-canonical, semantic, and the restore_canonical_head route) now shares. Confirmed these landed via PRs #2843/#2847/#2848/#2850 (all merged after the iteration-5 note was written) by git log/git show on the relevant commits. AC1 (new browser captures acquire chatgpt-export origin, not unknown-export) is already covered by test_streaming_sized_browser_capture_json_uses_native_payload_detection in tests/unit/sources/test_live_batch_support.py, which asserts `SELECT origin FROM raw_sessions` == chatgpt-export for a fresh ingest.\nPR #2877 (branch feature/fix/raw-identity-repair-cluster) adds the evidence-packet + durable-blocker capability for this bead's dependent polylogue-lkrc.3 (the 4 sessions the exact-byte rekey actuator correctly refuses) -- see that bead's notes. AC4 (dynamic live census reports zero mismatches, or every unresolved conflict is an explicit durable blocking state) remains open pending a live-archive run of record_browser_canonical_authority_conflict_blockers, which this session does not perform (live-execution reserved for the operator). No code gap was identified beyond what #2877 adds; this bead's remaining scope is live-execution, not implementation.","status":"open","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:50:53Z","created_by":"Sinity","updated_at":"2026-07-14T01:05:10Z","labels":["area:browser","area:sources","area:storage","delivery:A-trust-floor","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-lkrc","depends_on_id":"polylogue-yla8.10","type":"discovered-from","created_at":"2026-07-13T01:50:54Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-5ucz","title":"Fast-forward the live v32 index to v35 without raw replay","description":"The canonical 32 GiB index is healthy at user_version=32 but current code requires v35. A raw reparse is unnecessary and expensive: v33 widens one CHECK, v34 adds one index plus the current delegations view rewrite, and v35 changes three FTS tokenizers/write folds. Build and prove a clone-first fast-forward that leaves the original untouched, rebuilds only derived FTS tables from normalized source tables, and supports atomic blue-green activation with rollback.","design":"Implement an evidence-harness and operator actuator on a fresh branch from origin/master. Quiesce the user daemon; checkpoint/copy the v32 index using WAL-consistent handling and a Btrfs reflink under a contained single-operation scope. Apply exact canonical v33/v34/v35 DDL deltas to the clone, including the current delegations view definition, rebuilding all three contentless FTS tables with the canonical v35 tokenizers and folded write path through existing repair machinery. Set user_version=35 only after every mutation succeeds. Validate quick_check, foreign keys, exact canonical DDL, stable structural row counts, FTS population counts/folded-query smoke, and readiness on the clone. Emit phase/timing/hash/count/resource receipts. Activation is a same-filesystem atomic blue-green swap with retained rollback target; restart and postflight only after clone proof. No raw parse or durable-tier mutation.","acceptance_criteria":"1. A small v32 fixture proves exact 32→35 deltas, current delegations view, all three canonical FTS definitions/content, user_version-last behavior, and rollback on injected failure without raw parsing. 2. The live daemon is quiesced and the 32 GiB original remains byte/path preserved while a WAL-consistent reflink clone is created; receipts record source identity, sidecars/checkpoint state, timings, sizes, and resource envelope. 3. Clone mutation applies v33/v34/v35 canonical deltas and rebuilds messages_fts/work_events_fts/threads_fts from their source tables using current v35 folding/tokenizers; no session/message/block/source raw replay occurs. 4. Clone gates pass: integrity_check or quick_check as designed, foreign_key_check=0, canonical DDL exactness, unchanged sessions/messages/blocks and other structural counts, expected FTS counts, folded-query smoke, user_version=35, and current runtime readiness. 5. Only after a clone-only report is reviewed green, activation atomically swaps the canonical index to the proven clone on the same filesystem, retains the v32 rollback target, restarts the daemon, and proves bounded journal/readiness/query smoke. Any failure before activation leaves v32 canonical; any post-activation failure rolls back atomically. 6. Exact commands, timings, hashes/counts, PSI/RSS/IO samples, receipt paths, and no-raw-reparse evidence are attached. No v35 rebuild through ordinary raw ingestion.","notes":"Deployment/postflight completion:\n- Sinnix polylogue input advanced eff7c2a→58691ab and canonical devshell switch completed; deployed package /nix/store/acgsm0akngfg6jg23cllnx22xxl83hgy-python3.13-polylogue-0.1.0.\n- Current runtime also required durable user.db v4→v6. Used verified user_overlays backups at /realm/staging/polylogue-sqlite/recovery/user-v6-20260713/polylogue-archive-20260712T230342Z and /realm/staging/polylogue-sqlite/recovery/user-v6-step2-20260713/polylogue-archive-20260712T230517Z. Runner correctly refused stale-manifest reuse between migration steps.\n- Final: index user_version=35; user user_version=6; user quick_check=ok; foreign_key_check empty; annotation_schemas, annotation_batches, context_deliveries present; delegation.discourse v1 registered.\n- polylogued active/running PID 1943471, NRestarts=0; no storage schema mismatch; 8/8 live sources; browser spool ready; ports 8765/8766 owned by the integrated daemon. Receipt postflight field updated and hash refreshed.\n- PR #2804 merged as 07fbbeeca1c298aae6a964712374d4c40aa81e1f. GitHub-hosted checks did not start because the account is billing-locked; local owning tests and two quick gates were green, and no review threads/actionable bot findings existed.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T19:57:48Z","created_by":"Sinity","updated_at":"2026-07-12T23:06:53Z","started_at":"2026-07-12T19:57:54Z","closed_at":"2026-07-12T23:06:53Z","close_reason":"Delivered and live: clone-first no-raw v32→v35 activation proven, deployed v35 runtime plus verified user v6 migrations, stable daemon/query postflight, retained v32 rollback, PR #2804 merged.","labels":["area:ops","area:storage","area:test","delivery:B-storage-rebuild-bytes","horizon:frontier","lane:storage-rebuild-scale","spine"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jlme.2","title":"Fail closed and preserve first-party auth for browser backfills","description":"Live deployment of PR #2771 proved a provider-contract failure: an authenticated ChatGPT UI with visible history returned HTTP 200 total=0/items=[] to the extension background adapter, which accepted the empty inventory as complete. The frontend itself requests the same inventory family with first-party page context and visibly receives history. A background fetch must not silently convert missing page/auth/account context into a successful empty archive delta. Fix ChatGPT and audit Claude transport while honoring provider controls, keeping secrets ephemeral, and avoiding foreground activation or broad live crawling.","design":"Evidence first: capture a bounded frontend inventory request through CDP and compare only header names, initiator/context, status, and response shape with the extension request; redact all credential values. Rank cookie context, account header, device/session token, and execution-world differences before choosing a transport. Implement a main-world/page bridge or equivalent ephemeral authenticated transport so provider-native inventory/fetch calls execute in the first-party context. The service worker remains coordinator/storage owner. Bridge messages use request IDs, a strict allowlist of provider-relative endpoints/methods, fixed timeouts, response-size bounds, and fail-closed shape/auth/challenge handling. Never persist or log tokens/cookies/account identifiers. Provider 200/empty must be distinguished from trustworthy empty inventory using authenticated-context proof or consistency checks. Audit Claude under the same contract and share the transport abstraction where viable. No foreground activation.","acceptance_criteria":"1. A production-path fixture reproduces HTTP 200 empty inventory from an unauthenticated/background context while a page-context fixture has history; the adapter refuses to mark the former complete. 2. ChatGPT inventory and native fetch can use a strictly allowlisted first-party page/main-world bridge without persisting or logging credentials, and auth/challenge/timeout/oversize/drift fail closed. 3. Claude transport is either moved to the same authenticated-context mechanism or has evidence-backed proof its existing background requests carry sufficient context; no silent empty success. 4. Memory/fake-IndexedDB coordinator tests prove a rejected empty inventory remains paused/actionable and resumes without duplicate capture. 5. Packaged service-worker proof exercises bridge request/response correlation and confirms no foreground tab activation. 6. Bounded live deployment against the owned private-visible profile returns a nonzero inventory count consistent with visible history, then a conservative job starts under configured rate limits. No archive rebuild or v35 work.","notes":"Discovered after merge 07ea5f2d0 / PR #2771. Initial live evidence: ChatGPT background request /backend-api/conversations?offset=0&limit=100&order=updated returned 200 total=0/items=[]; frontend resource used offset=0&limit=28&order=updated&is_archived=false&is_starred=false while sidebar visibly showed history. Investigation may inspect credential header names but must never record values.\nClosure evidence 2026-07-12:\n- PR #2773 squash-merged as 901825ec4acbf278ad184a004acf604048508174.\n- Production transport executes strict structured operations directly in the authenticated first-party MAIN world; no postMessage trust or credential persistence. ChatGPT traverses all archived/starred partitions; Claude pins the exact UI-selected organization. Responses are streamed under a 32 MiB cap and temporary background tabs are lifecycle-bounded without foreground activation.\n- Verification: browser-extension npm test 158/158; focused 58/58; npm run lint clean; npm run validate manifest v0.1.0 valid; devtools verify --quick 15/15 (20260712T202234Z-quick-3863858-c3dff574). Adversarial and Codex findings were fixed; all substantive threads resolved. GitHub-hosted jobs failed before runner allocation (empty runner/steps), while GitGuardian and CodeRabbit passed.\n- Bounded live deployment in private-visible profile with cutoff 2026-04-23: ChatGPT inventory_complete=true with 477 eligible candidates and durable ACK polylogue-ext-mri9iyo5-9v0liypp; Claude inventory_complete=true over 900 provider records with 26 post-cutoff candidates, exact selected organization pinned, and durable ACK polylogue-ext-mri9j03e-ol7rdst0. Both live jobs run at base cadence 10s, max 800 provider cost units/day, concurrency/captures-per-wake 1, retaining Retry-After, full jitter, and circuit breaker behavior. No auth or rate-limit failure.\n- Live receiver compatibility probe posted the exact stored 1,174,387-byte envelope and received HTTP 202 with a 64-character content_hash matching the extension SHA-256.\n- The original false-zero job was cancelled and never resumed. Its in-profile ledger was subsequently lost when earlyoom killed Chrome and the private-start helper destructively re-seeded the profile; this is recorded honestly rather than reconstructed. Follow-ups: polylogue-jlme.3 (stale receiver contract handling) and polylogue-jlme.4 (ledger-preserving browser recovery/profile reseed).\n- Host evidence: earlyoom acted at ~2-3% available RAM with swap exhausted and killed Chrome renderers plus many 1-2.4 GiB codebase-memory-mcp processes. The backfill itself remained single-request and was not the pressure source.\nPost-closure live continuation: Claude job backfill-claude-ai-1783888873491-d7l8y reached COMPLETE with 25 durable captures, one explicit no_turns, zero retry/error/operator-action backlog, and final ACK polylogue-ext-mri9m6p9-0x0xjckx. ChatGPT job backfill-chatgpt-1783888873491-bdvr57 remained RUNNING at 17/477 durable captures, zero retry/error/operator-action backlog, under the requested 10s/800-cost/one-capture policy. The diagnostic popup and extension-created Claude tab were closed; the pre-existing active ChatGPT tab remained foreground and was never programmatically activated. The merged feature worktree is intentionally retained temporarily because Chrome loaded the unpacked extension from that exact path; removing it while the background job runs would break MV3 worker restart.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T19:32:21Z","created_by":"Sinity","updated_at":"2026-07-12T20:48:40Z","started_at":"2026-07-12T19:32:27Z","closed_at":"2026-07-12T20:47:22Z","close_reason":"Delivered by PR #2773 / merge 901825ec with every acceptance criterion verified locally and bounded live ChatGPT+Claude inventories plus durable receiver ACKs.","labels":["area:ingest","area:web","delivery:G-live-performance","horizon:frontier","lane:capture-reliability","spine"],"dependencies":[{"issue_id":"polylogue-jlme.2","depends_on_id":"polylogue-jlme","type":"parent-child","created_at":"2026-07-12T21:32:21Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jlme.2","depends_on_id":"polylogue-jlme.1","type":"discovered-from","created_at":"2026-07-12T21:32:22Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.10","title":"Repair accepted heads backed by untyped single-session raws","description":"The exact live v32 frontier has three active ChatGPT byte heads whose accepted_raw_id exists durably but still has no typed revision envelope: logical_source_key/source_revision are NULL, revision_kind=unknown, revision_authority=quarantined. The accepted index head/session is therefore not reconstructibly bound to source authority, and raw-frontier integrity correctly fails. Cursor-only yla8.6 repair cannot affect these rows. The retained v32 package at commit 3423d3c would classify a repeated single-session full as QUARANTINED, so ordinary re-acquisition alone remains false-green. Add a typed, evidence-preserving path that repairs this exact state without deleting or laundering raw/blob/head/receipt/session evidence.","design":"Recognize only the narrow already-accepted-untyped state: one current raw_revision_head and session raw_id agree on the same retained raw; source raw is unknown/quarantined with no prior logical/source binding; retained blob bytes normalize through the production ingest fallback-timestamp path to exactly the head session identity/content hash; SHA-256(payload) equals accepted_source_revision; byte length equals accepted frontier; raw row, raw_payload blob_ref, optional raw_artifact, origin, path, size, and source_index agree; the one immutable selected_baseline application receipt exactly equals the head including decided_at; and no competing head/application/membership/typed logical-key authority exists. Dry-run emits per-target and aggregate proof digests. Apply requires the exact digest/list and an explicit operator receipt path. Exclusively create and fsync a planned recovery receipt containing every witness, acquire ActiveWriterLease, open source.db as the sole writable main with index.db attached read-only, BEGIN IMMEDIATE once, reprove all targets, CAS-refine every envelope, reprove the terminal state, and commit all-or-nothing. Then fsync an applied record to the append-only operator receipt. Restart from a matching planned receipt is idempotent: exact already-bound rows finalize; any mismatch refuses. The existing immutable raw_revision_application proves prior acceptance and is cited, never mutated or duplicated. Do not weaken CAS, infer authority from raw_id alone, overwrite a typed envelope, misuse hook/ops tables, or delete evidence. Keep the actuator schema-v32-compatible and produce an exact v32-based build/artifact before live use.","acceptance_criteria":"1. Real-route fixture creates the exact invalid state through production write/receipt paths. Dry-run names each eligible raw, every witness, a per-target proof digest, and a deterministic aggregate digest without mutation; duplicate ids are rejected. 2. Apply requires that exact digest/list and an exclusive operator receipt path. It fsyncs planned evidence, acquires the writer lease, reproves under one source-main/index-readonly BEGIN IMMEDIATE transaction, CAS-refines all envelopes, reproves, commits all-or-nothing, and fsyncs applied terminal evidence. Raw/blob/session/head/content/message/FTS/application state is unchanged except the intended source authority columns. 3. Mutations for head/raw disagreement, missing or changed blob, blob-ref/artifact mismatch, byte-length/frontier drift, production-normalized parser/content-hash drift, wrong origin/session identity, competing head/application/typed revision/membership (including failed or ambiguous census), receipt/head field or decided_at drift, multi-session ambiguity, and pre-existing non-null envelope all fail closed with logical state unchanged. 4. Reapply with the matching applied receipt is idempotent. A planned-only receipt plus a partially/fully already-bound exact set resumes and finalizes; target/digest mismatch refuses. Injected proof/CAS/post-proof failures roll back the entire source batch and never leave a source binding without the pre-existing immutable application proof plus planned operator receipt. 5. Focused real-route storage and CLI tests pass, including anti-vacuity mutations. No schema changes; build the actuator from an exact INDEX_SCHEMA_VERSION=32 base containing all authority fixes through #2723, record build commit/hash, and run devtools verify --quick. 6. Live postflight only after merge and exact v32 artifact: stop daemon, verify source/user backup and dynamic census, dry-run exactly the current invalid raws, apply with stored operator receipt, then cursor-only yla8.6 repair/catch-up. Final exact census is 0 invalid heads and 0 cursor-ahead; explain incomparable gaps; source/index/hash/count parity and bounded journal are clean; controlled sanitized-copy append advances exactly once without shrink. No rebuild is an implementation prerequisite.","notes":"AUTHORITATIVE SCOPE SUPERSESSION (2026-07-13): this note overrides the stale v32-only clauses in the original description/design/AC. Exit condition for yla8.10 is: merged v35-compatible actuator; exact dry-run and receipted apply for only a7d004c9..., f19944c8..., fa0574f8...; those three reach byte_proven with all non-source-envelope state unchanged; reapply is idempotent; postflight proves those raw IDs no longer invalid. It is NOT an exit condition for yla8.10 to repair 282983b4..., 86298651..., or affadd9d..., nor to make the global byte-quarantined census zero: those three fail origin/parser equality and are exclusively owned by polylogue-lkrc. No v32 package/build/artifact or v32 rebuild is required or permitted for this closure.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T18:45:47Z","created_by":"Sinity","updated_at":"2026-07-13T00:44:05Z","started_at":"2026-07-12T18:48:37Z","closed_at":"2026-07-13T00:44:05Z","close_reason":"Merged PR #2808 (3a5102b843) and source-v7 compatibility PR #2811 (c1d3c1fbc). Live stopped-daemon postflight repaired exactly a7d004c9..., f19944c8..., fa0574f8... under aggregate proof 8735245c... with verified 53.1GB blob/durable backup at /realm/staging/polylogue-sqlite/recovery/yla8-10-authority-20260713/polylogue-archive-20260713T003259Z. Receipt source-authority-repair.jsonl is planned→applied and names exactly those three. Backup comparison: source quick_check ok, FK0, relevant counts equal, all non-target raw rows identical, each target changed only logical_source_key/revision_kind/source_revision/baseline_raw_id/acquisition_generation/revision_authority. Reapply repaired=0 and receipt stayed 2 lines. Daemon restarted stable PID 2241036 NRestarts=0; Drive catch-up 0 errors; repaired cohort invalid=0. Remaining three unknown-export origin mismatches are explicitly excluded and tracked P0 polylogue-lkrc.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-sjf6","title":"Fix nondeterministic session-identity extraction causing membership-guard rejection","description":"Live production catch-up (2026-07-12, daemon PID 1932060) repeatedly fails full ingest of /home/sinity/.claude/projects/-realm-project-sinex/1e5805bd-72d6-4010-b052-b2b4a0e78425.jsonl and .../31571196-df8f-4e3d-998f-e595eea65faf.jsonl with RuntimeError: \"membership replay cannot retire an unrelated accepted head\" (archive.py:2255, guard added by rgh2/PR #2718). Root evidence from source.db raw_sessions: the top-level file 1e5805bd-...jsonl has TWO raw rows for the identical source_path — raw_id ecbe807b75... (acquired_at_ms=1782784971312, native_id=a5724e23-3cc3-4d33-81ff-f17d421b5be2, matching the sessionId field actually embedded in the file content, a resume/fork artifact) and raw_id 3d89a6082... (acquired_at_ms=1783814452449, native_id=NULL). The file mtime (stat) is 2026-02-13T04:15:42+01:00 and has not changed between those two acquisitions ~12 days apart — the bytes are identical, yet native_id extraction produced a real value the first time and NULL the second time. Since logical_source_key is built at classify time as f\"{provider}:{provider_session_id}\" (batch.py:1593/1702), a nondeterministic/missing native_id on re-acquire produces a different logical_source_key than the one already holding an accepted head in raw_revision_heads (index.db), tripping the \"unrelated accepted head\" guard and failing that file every catch-up pass (currently blocking chunks 14/17/18 of 55, 0/4 and 0/3 succeeded respectively per live journal).","design":"Find where claude-code-session native_id / provider_session_id is derived at ACQUIRE time (grep polylogue/sources/live for the claude-code acquire path; batch.py:1989 _codex_session_meta_native_id is the sibling Codex helper — there is likely an analogous claude-code helper) vs where provider_session_id is derived at PARSE time (the ParsedSession the classifier uses to build f\"{provider}:{provider_session_id}\" at batch.py:1593/1702). These two extraction paths must agree deterministically on byte-identical input. Likely suspects: acquire-time native_id is derived from a partial/streamed read that can bail early on a large file (41MB/8984 lines) and miss the sessionId field under some memory-bounded-streaming code path, or acquire-time and parse-time each read a DIFFERENT record (first vs a resume-boundary record) to find the session id, so a resumed/forked file (content sessionId != filename-uuid) resolves differently depending on which extraction ran. Fix should make native_id extraction idempotent/deterministic for a fixed byte payload, and align it with whatever provider_session_id the classifier will compute from the same content — or make the membership-replay guard tolerant of a null-native_id raw row that reparses to the SAME accepted logical_source_key (rather than treating it as categorically unrelated). Do not weaken the guard for genuinely divergent content — this is specifically the same-bytes-different-extraction case.","acceptance_criteria":"1. A deterministic fixture with a Claude Code resume/fork file (content sessionId differs from filename UUID) re-acquired twice with byte-identical bytes yields the SAME native_id/logical_source_key both times. 2. The two specific live raw_ids (ecbe807b75...d48f / 3d89a6082...4ae) or their fixture-equivalent reparse to the same logical_source_key and the second acquisition no longer raises \"membership replay cannot retire an unrelated accepted head\". 3. A genuinely divergent-content case (different sessionId, different bytes) still trips the guard — regression coverage for the rgh2/PR #2718 guard is preserved. 4. Focused real-route tests plus devtools verify --quick pass; anti-vacuity states the production dependency and the mutation that makes the new test fail. 5. Live catch-up on this host completes chunks 14, 17, and 18 (or their current renumbering) without this RuntimeError.","notes":"Live journal evidence: journalctl --user -u polylogued since 2026-07-12T02:18. Two failures observed 02:31:08 and 02:33:24 CEST, both \"archive full ingest failed for .../1e5805bd-...jsonl\" and \".../31571196-...jsonl\" with identical traceback through batch.py:1649 _ingest_full_records_archive -> _apply_membership_sessions -> archive.py:2255. Daemon is NOT stopped (guard fails closed, no data corruption — safe to investigate live). Related closed P0 chain: yla8 (#2716), yla8.6 (#2710), yla8.9 (#2723), rgh2 (#2718 — added this exact guard), fmob (#2719). This bead is a NEW edge case surfaced by continued catch-up after all five were merged, not a regression in any of them.\n\n--- 2026-07-12 investigation + fix (PR #2729, branch fix/nondeterministic-session-identity) ---\nRoot cause refined via direct evidence: queried live source.db raw_sessions for the\ntwo named raw_ids. ecbe807b75... (native_id=a5724e23-..., acquired 2026-06-30) and\n3d89a6082... (native_id=NULL, acquired 2026-07-12) are TWO rows for the IDENTICAL\nsource_path (1e5805bd-...jsonl) and byte-identical blob content -- differentiated\nONLY by native_id (deterministic_raw_session_id hashes native_id into raw_id).\nConfirmed structurally: the file's first record is a 1-message carryover of the\nLAST message of a SEPARATE real session (a5724e23-3cc3-4d33-81ff-f17d421b5be2,\nits own 17MB dedicated file) -- a genuine Claude Code resume/fork artifact. Same\npattern recurs 3 levels deep in this project's history\n(25cc6e75 -> 1eed506e -> a5724e23 -> 1e5805bd), each verified via direct file read.\n\nMechanism: pipeline/services/archive_ingest.py's one-shot importer\n(parse_sources_archive/write_pair, the `polylogue import` \"parse\" stage) writes\nONE raw_sessions row PER SPLIT SESSION for a grouped Claude Code/Codex/Gemini/Drive\nJSONL file (_SessionEmitter._emit_grouped yields the SAME captured raw bytes for\nevery split session -- verified via source read of emitter.py), via\nwrite_raw_and_parsed_result(native_id=session.provider_session_id). The live\ndaemon watcher instead writes ONE raw per file (write_raw_payload, native_id\nalways NULL) and defers session identity to membership-census classification.\nThe two pipelines disagree on raw identity for identical bytes; the daemon's\nmembership-replay guard later discovers the importer's extra raw as a spurious\ncompeting claim on a logical_source_key it already has an accepted head for.\n\nFix: write_pair now caches raw_ids by (origin, source_path, source_index,\nblob_hash); the first session sharing a raw commits it via a raw_id computed\nWITHOUT native_id (matching the daemon's scheme), further sessions index against\nthe SAME raw_id via new ArchiveStore.write_parsed_for_retained_raw_result.\narchive.py:2255 guard itself is UNCHANGED (preserves AC#3) -- an attempt to also\nsoften it directly was reverted after discovering it would skip essential\nraw_session_memberships bookkeeping on early return.\n\nAC status: #1 satisfied (new fixture test proves same-bytes -> same raw_id\nacross re-ingest). #2 partially: the fix prevents NEW duplicate-raw creation\nfrom either pipeline going forward; despite extensive reproduction attempts\n(single/batched orderings, up to a 3-hop carryover chain in a dedicated unit\ntest) I could NOT reproduce the exact live RuntimeError from a single pipeline's\nbehavior in isolation -- the live crash required the specific cross-pipeline\n(one-shot import + daemon) duplicate-raw state this PR prevents recreating.\nThe two ALREADY-existing live raw rows are historical data this PR does not\nretroactively clean up -- open question for the coordinator whether they need\nseparate remediation (e.g. raw_revision_rebuild_selection/membership census\ncompaction) or will self-resolve via ambiguous-safe reclassification. #3\nsatisfied (guard untouched, its own regression test still green). #4 satisfied:\ndevtools test (91 passed, 6 pre-existing unrelated failures verified via git\nstash against unmodified master) + devtools verify --quick (14/14 ok) both\ngreen; anti-vacuity verified by reverting the diff and confirming both new\ntests fail exactly as predicted (2 raw rows instead of 1). #5 not\nindependently re-verified against the live host from this PR.\n\nPR: https://github.com/Sinity/polylogue/pull/2729","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T00:41:08Z","created_by":"Sinity","updated_at":"2026-07-12T01:31:44Z","started_at":"2026-07-12T00:44:35Z","closed_at":"2026-07-12T01:31:44Z","close_reason":"Root cause fixed and merged: PR #2729 (45766f3c7) aligns the one-shot polylogue-import pipeline's raw-identity scheme with the live daemon watcher's (both now compute raw_id without native_id for grouped/split-session files), closing AC #1-4 (deterministic re-acquisition, guard preserved for genuinely divergent content, anti-vacuity verified, focused tests + devtools verify --quick green). AC #5 (live catch-up completing on the two already-affected files without the RuntimeError) is explicitly deferred, NOT silently dropped: the fix only prevents NEW duplicate-raw creation going forward, it does not retroactively repoint the two already-accepted heads that predate this fix. That one-time live remediation is tracked in polylogue-t0dy.","dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.9","title":"Authorize byte-proven full snapshots that fold accepted append chains","description":"Production catch-up on 2026-07-12 rejected codex:019f4f5f-ab06-70a1-a4ae-163d9e1969d8 when a byte-proven full snapshot at the same 2,645,672-byte frontier replaced an accepted baseline+append head. The bytes are cryptographically identical to the accepted chain, but split and full parsing produce different normalized hashes because parser event indices/metadata are segmentation-sensitive. Broad equal-frontier hash replacement is unsafe; the missing authority is an exact byte-fold proof.","design":"Before an equal-frontier full snapshot can replace a byte append head, walk the currently accepted append predecessor chain to its full baseline. Prove exact baseline prefix bytes, contiguous append offsets, final length equal to the accepted byte frontier, and for every append recompute append_source_revision(predecessor_revision, sha256(full_snapshot[offset_slice])) equal to the stored append revision. Carry an explicit one-shot authorization into the same index transaction that retires/replaces the head. Do not allow equal-frontier changes based only on length, generation, classifier selection, or normalized content. Implement on the real replay/apply route in sync and async paths where applicable.","acceptance_criteria":"1. A real Codex-like full-vs-split replay fixture with identical bytes but deliberately different normalized hashes transitions atomically to the full raw only after the fold proof succeeds. 2. Multi-append chains fold correctly. 3. Tail-byte mutation, gap/overlap, wrong predecessor revision, different baseline prefix, missing chain member, and same-length divergent full all fail closed and roll back session tree, FTS, head, and receipts. 4. Existing membership preservation and equivalent-receipt tests remain green. 5. Focused real-route tests and devtools verify --quick pass; anti-vacuity states the production dependency and mutation that fails each proof.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T23:47:49Z","created_by":"Sinity","updated_at":"2026-07-12T18:37:48Z","started_at":"2026-07-11T23:47:56Z","closed_at":"2026-07-12T18:37:48Z","close_reason":"Merged PR #2723 (3423d3cf0) proves exact byte-chain folding for identical full snapshots: real Codex full-vs-split and multi-append success, seven fail-closed mutation rollbacks preserving session tree/FTS/head/receipts, existing membership/equivalent-receipt coverage, focused 16+8 tests, and devtools verify --quick 14/14.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","delivery:trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.9","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-12T01:47:48Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-fmob","title":"Make revision receipt replay match semantic identity","description":"Production catch-up reclassifies equivalent raw snapshots when a lexicographically smaller representative appears. raw_revision_applications correctly has a semantic unique identity that excludes accepted_raw_id, but record_revision_application_sync treats an INSERT OR IGNORE collision as a decision-id conflict because decision_id includes accepted_raw_id. Resolve semantic-identity collisions idempotently only when accepted revision and content hash remain exact; reject true conflicts. Reproduce the claude-code:journal representative change through the real membership route.","acceptance_criteria":"1. Equivalent accepted-raw representative changes reuse the existing semantic identity only for SUPERSEDED receipts with exact logical key, accepted revision, and content hash. 2. Baseline and append decisions still require their own immutable receipt before head CAS. 3. A real membership classification/application replay reproduces representative reselection and proves head-to-receipt consistency. 4. Production catch-up completes the previously failing claude-code:journal raw without a conflicting receipt.","notes":"Production evidence: catch-up path claude-code:journal failed on receipt 269dd3bb because equivalent representative changed from 975f... to 45d...; INSERT OR IGNORE hit idx_raw_revision_applications_identity while decision_id differed by accepted_raw_id. Fix accepts semantic-identity reuse only for SUPERSEDED receipts with exact logical key, accepted revision, and content hash; CAS-bearing decisions still reject. Real classification+apply route test proves representative reselection, immutable old receipt, and a matching selected receipt for the new head. Focused 6 passed; quick 13/13 run 20260711T225456Z-quick-1623240-241b43ad; independent review passed after narrowing.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T22:49:40Z","created_by":"Sinity","updated_at":"2026-07-13T10:26:03Z","started_at":"2026-07-11T22:49:47Z","closed_at":"2026-07-13T10:26:03Z","close_reason":"PR #2719 merged; the semantic-identity receipt replay fix and its focused proof are recorded in the bead notes. Closing stale in-progress state.","labels":["area:storage"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-rgh2","title":"Include accepted semantic head in membership replay authority","description":"Production convergence of duplicated Codex recovery snapshots fails because membership replay classifies only raw_session_memberships. When a newer single-session full snapshot already owns raw_revision_heads but append rows prevent cohort conversion, replay cannot prove the accepted head related and raises. Include the durable accepted head as classifier evidence without granting ambiguous branches deletion authority; cover newer-single-then-older-bundle arrival and divergent containment.","acceptance_criteria":"1. Membership classification includes an accepted head that is absent from raw_session_memberships when retained raw evidence can be reparsed to the same logical session. 2. An older prefix can terminate without replacing that head. 3. Divergent or newer membership evidence cannot replace a source-tier byte-governed head, including when backfill also created a membership census row. 4. Focused real-route tests are anti-vacuous and production catch-up completes the previously failing Codex recovery snapshots.","notes":"Production evidence 2026-07-12: #2717 fixed metadata-only semantic transition, then catch-up exposed older duplicated Codex recovery raws failing because the 83.9 MB accepted full head was absent from the 18-row membership cohort while append evidence prevented full-cohort conversion. Implementation adds the indexed accepted raw as classifier evidence, permits only same-head preservation while byte governance remains, and rejects divergent/newer membership replacement until governance is durably unified. Focused real-route matrix: 6 passed, including append-blocked older prefix, divergence, newer membership, and backfill dual-governance containment. Quick gate run 20260711T223739Z-quick-1559493-3d87c374: 13/13.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T22:28:26Z","created_by":"Sinity","updated_at":"2026-07-13T10:26:04Z","started_at":"2026-07-11T22:29:34Z","closed_at":"2026-07-13T10:26:04Z","close_reason":"PR #2718 merged; accepted semantic-head classifier evidence and focused proof are recorded in the bead notes. Closing stale in-progress state.","labels":["area:storage"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.6","title":"Repair live append CAS frontier convergence","description":"## Production failure\n\nThe installed daemon on 2026-07-11 process-stays healthy but ordinary live append convergence is not authority-safe. A deterministic full + three-append fixture proves the third append fails because post-ingest legacy compaction deletes the first active suffix. Strict CAS then correctly rejects replay of the disconnected chain as an older frontier. Independent live evidence proves full ingest can also commit a cursor past acquired bytes when a hot JSONL grows between acquisition and cursor commit.\n\nRead-only production census found seven byte-proven append raws with missing predecessors; six are current raw_revision_heads, five current paths are excluded, and one current head is latent until its next append. A separate Claude/Sinex path has accepted full material at 748,295 bytes but a cursor at 766,042 bytes and a current 3.3 MB file. The originally named three sessions are only a subset. Do not weaken CAS or reset cursors until retention and acquired-byte authority are fixed.","design":"Preserve complete active raw-revision chains across retention, commit cursors only through acquired bytes, and recover every dynamically detected broken current head without weakening CAS.\n\nRetention authority: read sessions.raw_id and raw_revision_heads.accepted_raw_id from the current index as protection seeds. In source.db, follow predecessor_raw_id from each accepted append through a byte-contiguous, same-logical-source, same-baseline, monotonic-generation chain to a retained full baseline. Cleanup fails closed when index authority is unavailable or any active chain is incomplete; it may compact an old append chain only after a newer self-contained full snapshot is the accepted head. Use the same authority helper in automatic live compaction and manual repair.\n\nCursor authority: full ingest carries the actual acquired blob byte size through _FullIngestResult. _record_full_cursor records that captured boundary, never a later path.stat().st_size; a hot-file suffix remains pending for the next ordinary append tick. Raw/index/head/application remain transactional and cursor commit remains after successful persistence. Exact raw-revision binding compares the complete envelope when touched; do not make CAS permissive.\n\nRecovery is dynamic: after fixed deployment, detect every current accepted append head with a missing predecessor and every cursor ahead of accepted raw material, review the bounded path set, remove only those disposable cursor rows under a stopped daemon, and let ordinary full reacquisition establish a new complete baseline. Never delete durable raw rows/blobs/heads/receipts/sessions during repair.\n\nIncomplete live JSONL captures are never silently treated as complete full frontiers. The acquired raw remains durable with a typed parse failure, the cursor retains no accepted content identity, and a completed record retries through the full route. Failed append persistence preserves the previously accepted cursor fingerprint and boundary so the identical raw can retry without authority reset.","acceptance_criteria":"1. Real-route lifecycle: one actual LiveBatchProcessor path ingests a full Codex JSONL plus at least three unique contiguous appends. Every tick succeeds exactly once; cursor equals the captured complete boundary; current head plus full transitive predecessor chain remains in source.db; exact session hash/message IDs/count, FTS rows, and receipts remain coherent. Disabling accepted-head protection or predecessor traversal makes the third append fail.\n2. Retention protection is closed and fail-safe: sessions.raw_id and raw_revision_heads.accepted_raw_id seed protection; append chains validate same logical source, byte contiguity, generation, predecessor revision, and baseline through a full row. Missing/unreadable index or an incomplete active chain deletes nothing. A newer accepted full permits the old append chain to become eligible.\n3. Hot-file acquisition test grows a JSONL after raw capture but before full cursor commit. The cursor stops at the actual blob size, and the next ordinary append plan starts exactly there and archives the intervening bytes. Using post-parse stat.st_size makes the test fail.\n4. CAS/persistence contract remains strict: older, overlapping, discontinuous, wrong-predecessor, changed-envelope, and conflicting same-frontier revisions reject without index/session/FTS/head/cursor mutation. Forced persistence failure leaves the cursor retryable; the next ordinary tick succeeds after the causal condition is corrected.\n5. After merge and exact-build deployment, stop the daemon and take a verified source/user durable backup. Dynamically census every broken current head and cursor-ahead path; repair only disposable cursors, never durable evidence. At current observation the cohort is six broken current heads plus one separate cursor-ahead path, but the query result is authority.\n6. Production postflight: each repaired cursor reaches the current complete JSONL boundary with failure_count=0/excluded=0; no current accepted append head has a missing predecessor; no cursor exceeds accepted raw material; source/index hashes and counts agree; no older/incomparable CAS error appears in the bounded journal interval. One further controlled sanitized append advances exactly once. Verify focused live-batch/retention/repair/revision tests, devtools verify --quick, graph lint, and attach backup/census/journal receipts.\n7. Record-boundary and retry integrity: a full live JSONL capture ending mid-record indexes nothing and advances no cursor; after the record completes, the next ordinary tick retries full and indexes the complete record. A forced append persistence failure preserves the accepted cursor boundary/fingerprint and index/head state; the corrected next tick succeeds once without resetting or rebinding the raw authority envelope.","notes":"2026-07-11 adversarial iteration 7 closes the remaining pre-plan authority and write-outcome gaps. Modern cursors now encode a versioned SHA-256 digest of the complete accepted prefix plus the bounded tail digest. Every append plan streams and verifies the entire previously accepted prefix before taking the append route, then extends that digest through the newly accepted complete boundary; legacy cursors conservatively take one full route to acquire modern authority. Deferred cursors retain the accepted prefix digest. CursorStore.set now propagates exhausted best-effort write failure, and full-retry invalidation raises instead of pretending an obsolete cursor was cleared. Anti-vacuity: a 70 KiB rewrite-plus-growth mutation before the bounded tail must take the full route and fail closed against immutable byte authority; removing the prefix comparison makes it append, while restoring unconditional cursor-write success hides the lock-exhaustion failure. Focused real-route matrix: 15 passed in 26.14s. devtools verify --quick run 20260711T202838Z-quick-940187-4ae50c73: all 13 steps green. The explicit tradeoff is O(accepted-prefix bytes) verification per append until a future authenticated chunk-tree/cursor schema can preserve the same guarantee sublinearly.\n2026-07-11 production publication/repair evidence: PR #2710 merged as 8a68241809d1cfa218612f54d014c5e0c5436a01 after seven adversarial iterations; final focused real-route matrix 18 passed in 29.76s and quick run 20260711T204508Z-quick-956614-ed758411 passed 13/13. Sinnix 2350daec8b4654ece9d219e6414c002810c4b015 deployed that exact build. With the daemon stopped, authority census /realm/tmp/polylogue-yla8-6-repair-census.json (sha256 e78915a7e5451e99a9a29b2fec70a68cc761637d6409eaeb86f340f23032d44d) selected 252 disposable cursors. Verified durable backup: /realm/staging/polylogue-sqlite/yla8-6-authoritative-pre-repair-20260711T2059Z/polylogue-archive-20260711T205907Z (source/user plus 24,289 blobs). Repair removed exactly 252 cursors and no durable raw/blob/head/receipt/session/user rows; receipt /realm/staging/polylogue-sqlite/recovery/20260711T2104Z-yla8-6/cursor-repair.json. Installed LiveBatchProcessor then reacquired all 9 dynamically selected paths: 9 succeeded, 0 failed, 95,736,118 bytes, 551.2203s; /realm/tmp/polylogue-yla8-6-targeted-reacquire.json sha256 303bb9de6111d48c6342826699bc87cb28bdac99fe75847565be20f5c6dbef13. Stopped post-target census /realm/tmp/polylogue-yla8-6-post-targeted-census.json sha256 d5ad39b36edea36ce61b4ef4c4e4e07e1867d2715e04ac5746dcb7588fa19ae8 reports 0 broken current heads and 0 cursor-ahead rows; 9 historical missing-parent raws remain as durable incident evidence. Daemon restarted 23:36:33 CEST with NRestarts=0 and is completing the bounded one-time modern-cursor reauthentication backlog (669 files/5.1255GB after skipping 14,248). Keep open pending final catch-up, integrity/census/journal proof, resource restoration, and controlled sanitized append.\n2026-07-12 no-v35 closure audit: the canonical read-only v32 frontier reports 3 invalid active ChatGPT byte heads, 15 cursor-ahead rows across 15 comparisons, 181 comparable cursors, 152 cursor/head authority gaps, and 0 missing source raws. The retained compatible package /nix/store/ah41rqf4j348qnr62m4mavgwqzd1m8c6-python3.13-polylogue-0.1.0 is clean build 0.2.0+3423d3c, INDEX_SCHEMA_VERSION=32, and includes every merged authority actuator through PR #2723. The 15 cursor-ahead paths have current local files and retained byte-proven suffix raws, so cursor-only reset plus bounded ordinary local catch-up is plausible. It is insufficient for closure because each of the 3 invalid heads points to a durable source raw with logical_source_key=NULL, revision_kind=unknown, source_revision=NULL, revision_authority=quarantined. In build 3423d3c ordinary single-session full ingest binds such a row as FULL but still QUARANTINED; the integrity validator therefore continues to reject it. Cursor deletion cannot repair these rows, and manual byte-authority binding would exceed this bead design and risk laundering evidence. No live mutation, daemon stop, backup, catch-up, or rebuild was performed; Borg repository check was in D-state and the daemon remained API-only under the v35-code/v32-index mismatch. Child polylogue-yla8.10 owns the required typed repair.\n2026-07-14 status check as part of the raw-identity-repair cluster (PR #2877): this bead's own notes already record a completed live repair (252 disposable cursors removed, 9 targeted reacquires, 0 broken heads/cursor-ahead post-target census) and identify child polylogue-yla8.10 as owning the remaining typed-authority gap; yla8.10 is now closed with live postflight evidence. No further code gap was identified for this bead specifically during this session's investigation of the cluster. Final closure (production postflight proving 0 invalid heads / 0 cursor-ahead on the CURRENT v35+ archive state, per this bead's own AC6) is live-execution and was not performed this session -- reserved for the operator.","status":"in_progress","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T15:31:16Z","created_by":"Sinity","updated_at":"2026-07-14T01:06:07Z","started_at":"2026-07-11T15:45:50Z","labels":["area:daemon","area:sources","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.6","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-11T17:31:15Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-yla8.6","depends_on_id":"polylogue-yla8.10","type":"blocks","created_at":"2026-07-12T20:45:50Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.5","title":"Retire fully governed bundle raws from replay queue","description":"Production contained replay processed 1,044 logical membership sources from bundle/container raws but left exactly 262 raw candidates. Candidate retirement relies on sessions.raw_id or per-raw revision applications, which cannot represent one raw containing many sessions. Complete raw_membership_census plus terminal membership decisions already provide the correct authority predicate but are not consulted by _raw_materialization_candidate_ids.","design":"Use the existing raw_membership_authority_complete semantics in the candidate SQL/selection path: a census status complete with no NULL/ambiguous/deferred membership rows retires the bundle raw. Incomplete or ambiguous membership remains executable/blocked as appropriate. Prove two-call fixed point on a real multi-session bundle route.","acceptance_criteria":"1. Fully governed multi-session bundle raw is not selected again. 2. Incomplete, NULL, ambiguous, or deferred memberships remain visible and are not false-green retired. 3. Real bundle replay reaches a zero-work second call without changing receipts. 4. Focused tests and quick gate pass; production 262-repeat set retires.","status":"closed","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T05:23:43Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:30Z","closed_at":"2026-07-11T07:17:30Z","close_reason":"Merged PRs #2693/#2694 (304b84019, 63a6c7563). Fully governed bundle and censused append debt no longer schedules execution; final packaged status reports candidate_count=0 and pending=0 while retaining 69 membership and 219 append quarantines visibly.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.5","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-11T07:23:43Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.4","title":"Preserve semantic frontier across full snapshot replacement","description":"Production six-file recovery acquired valid current browser JSON as full source_index=0 raws, but apply_raw_revision_replay generated byte frontiers for the full-revision plan while their existing raw_revision_heads were created by membership replay with semantic frontiers. CAS rejected all as incomparable after indexing inside the transaction. This prevents any later full snapshot from updating a session whose authority head was bootstrapped semantically.","design":"In the atomic apply path, preserve typed frontier comparability. If the existing logical head is semantic, derive the accepted session projection semantic frontier and receipt it as semantic; do not downgrade to byte. If existing is byte, retain byte frontier. Prove semantic head→larger full replacement succeeds, smaller/conflicting replacement is rejected without index mutation, and byte append chains retain byte behavior. Full-ingest failures should remain retryable and honest.","acceptance_criteria":"1. A semantic-headed session accepts a demonstrably later semantic full snapshot and advances its semantic frontier. 2. Older/conflicting semantic replacement cannot overwrite the session/head. 3. Byte-headed append replay remains byte-frontier governed. 4. CAS rejection rolls back session/index/FTS mutation and leaves retriable source evidence. 5. Focused real-route tests and devtools verify --quick pass; six production captures adopt with current turn counts.","notes":"2026-07-11 implementation scope: isolated fresh-master fix limited to raw revision replay/CAS frontier typing and focused real-route tests. Preserve semantic heads via the accepted session projection; preserve byte heads unchanged; prove semantic conflict rejection and transaction rollback before any persistent index/FTS/head mutation. Production adoption/deploy remains coordinator-owned.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T04:30:37Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:29Z","started_at":"2026-07-11T04:31:02Z","closed_at":"2026-07-11T07:17:29Z","close_reason":"Merged PR #2692 (7d300a596). Semantic heads preserve semantic CAS frontiers across full replacement; production captures adopted and the protected root remains 9,298 messages.","labels":["area:daemon","area:sources","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.4","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-11T06:30:36Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.3","title":"Restrict live append ingestion to proven stream formats","description":"Six production browser-capture JSON sessions staged through the inbox were ingested as source_index=-1 suffix chunks and failed JSON decode. The append guard keys on watch-source name browser-capture, so the same mutable JSON envelope under inbox bypasses it. Cursor state then advanced to the current full file size/hash with failure_count=0 even though the full current hash was never acquired. All six current files are valid browser_llm_session JSON; the archived failing blobs begin mid-JSON.","design":"Make live append planning allowlist proven append-safe stream artifacts instead of inferring append safety from watcher labels. Ordinary .json replacement files must always take the full-file path regardless of whether they arrive through browser-capture or inbox. Extend the real LiveBatchProcessor route test for an inbox browser envelope. Ensure failed suffix parse cannot advance the cursor as successful. Provide an explicit safe recovery procedure for the six production paths: acquire each current full file, parse/materialize it, and terminally classify the obsolete suffix raw without deleting source evidence.","acceptance_criteria":"1. Mutable .json under both browser-capture and inbox never receives an append plan. 2. Proven JSONL stream inputs retain append behavior. 3. A failed suffix parse cannot leave a success cursor that suppresses the current full file. 4. Regression tests exercise the actual inbox/browser-envelope route and fail under the old code. 5. The six production files are re-acquired as valid full evidence, obsolete suffix raws are terminally classified, exact readiness has no JSON decode debt, and focused tests plus devtools verify --quick pass.","notes":"2026-07-11 implementation scope: restrict append planning in polylogue/sources/live/batch.py to proven stream formats; add focused actual inbox/browser-envelope and JSONL route regressions; inspect adjacent cursor commit behavior and fix only if owned path is implicated. Production recovery and final bead reconciliation remain coordinator-owned.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T04:16:36Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:28Z","started_at":"2026-07-11T04:18:12Z","closed_at":"2026-07-11T07:17:28Z","close_reason":"Merged PR #2691 (fae9e0bb5). Append replay is restricted to JSONL streams; six browser captures were recovered as typed full revisions and adopted without shrinking protected sessions.","labels":["area:daemon","area:sources","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.3","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-11T06:16:35Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.2","title":"Stop terminal revision receipts from re-entering replay","description":"Production evidence on 2026-07-11: packaged ordinary replay ran three ~190-200s passes, each reporting 15 replayed logical sources while remaining candidates rose 391→393→395 and quarantine rose 176→178→180. The candidate query excludes only deferred receipts and therefore requeues raws already terminally classified selected_baseline/applied_append/superseded/ambiguous. This creates an infinite expensive daemon convergence loop.","design":"In polylogue/storage/repair.py::_raw_materialization_candidate_ids, treat immutable raw_revision_applications receipts as the terminal authority for that exact raw. Exclude terminal decisions from executable candidates; preserve deferred incomparable state as visible blocked readiness. Prove against the real candidate route, including selected, superseded, ambiguous, deferred, and a newly acquired unreceipted raw. Ensure remaining-count computation uses the same predicate.","acceptance_criteria":"1. A selected/superseded/ambiguous/applied raw with an immutable receipt is not selected again. 2. A deferred incomparable receipt remains visible as blocked adoption debt, not executable work. 3. A genuinely unreceipted raw remains executable. 4. Two consecutive ordinary repair calls reach a fixed point: the second performs zero replay and does not grow terminal receipts. 5. Focused tests and devtools verify --quick pass; packaged production no longer loops and root session does not shrink.","status":"closed","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T04:16:33Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:26Z","closed_at":"2026-07-11T07:17:26Z","close_reason":"Merged PR #2690 (90cf639b1). Terminal application receipts now retire superseded/deferred/ambiguous decisions without repeat replay; production governed backlog is zero executable candidates.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.2","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-11T06:16:32Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.1","title":"Fail closed on authority-ambiguous raw replay","description":"Emergency containment for yla8. Until typed per-session raw revision authority exists, no source-to-index raw replay executor may apply historical revisions. Live packaged-runtime dogfood replayed old Codex snapshots over an 8k-message current session twice. A nominally empty index is not sufficient authority because multiple historical full revisions can still converge to the wrong snapshot. Leaving derived raw debt pending is preferable to silently accepting the wrong session.","design":"Make daemon repair and direct maintenance rebuild fail closed before parser or index mutation whenever raw rows are selected. Preserve read-only candidate/backlog and rebuild --plan inspection; remove ambient force-write and execution-only controls. Surface stable blocked candidate counts and reason in readiness/status telemetry, route every tier/blob lookup through the resolved archive file-set root, and prove no index or FTS mutation. This is containment, not yla8 closure: the parent owns typed per-session revision authority, ordered baseline/suffix replay, crash-resume decisions, and re-enabling execution.","acceptance_criteria":"1. Any selected raw replay candidate causes daemon repair and direct rebuild execution to return a stable blocked reason with zero session/index/FTS/raw-marker mutations. 2. No production route exposes force_write or an empty-index replay escape; rebuild --plan remains read-only and useful. 3. Backlog/status returns execution_blocked, reason, and blocked_candidate_count, including split-root routing through the resolved archive file set. 4. A regression seeds a newer indexed session and an older raw full snapshot; the real repair route preserves exact hash/message IDs/count and FTS rows, and fails if parser construction occurs. 5. Packaged live proof retains root session 019f49d8-0185-7c43-8793-db6e57db13e1 at or above the 8,076-message recovery snapshot across a daemon catch-up tick after deployment; devtools verify --quick passes. 6. Parent yla8 remains open and all operator text calls this temporary containment.","notes":"2026-07-10 adversarial correction: the original empty-index escape was misframed. Empty derived state does not establish which of several historical full revisions is authoritative. Scope now blocks every source-to-index replay executor while retaining plan/status inspection; parent yla8 must supply the typed authority model before execution is re-enabled.\n2026-07-10 PR #2670 merged as 202a09c240. Code/contract ACs are satisfied: all replay executors fail closed, planning remains, split-root/status/parser/FTS regressions pass. Keep this bead in progress until the packaged cutover and bounded live catch-up prove the recovered root remains at least 8,076 messages.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T19:26:43Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:31Z","started_at":"2026-07-10T19:32:37Z","closed_at":"2026-07-11T07:17:31Z","close_reason":"Containment and typed successor completed across PRs #2670 and #2681-#2695. Installed daemon catch-up retained the protected root at 9,298 messages; HTTP and MCP receipts agree, and raw readiness has zero critical/actionable debt.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.1","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-10T21:26:42Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-nkmy","title":"Unify active archive identity across split tier paths","description":"Live incident recovery on 2026-07-10 discovered two writable derived indexes sharing durable tiers. Packaged get_config() resolves archive_root=/home/sinity/.local/share/polylogue and index.db=/home/sinity/.local/share/polylogue/index.db (32.6 GiB), while source.db/ops.db/user.db/embeddings.db are symlinks into /realm/db/polylogue. A separate /realm/db/polylogue/index.db (26.5 GiB) remained writable and was used by the transient runtime and by operator verification, producing contradictory session counts (8,076 in the packaged active index versus 360 in the realm index) and a false recovery verdict. Archive identity cannot be inferred from the directory string when tier paths alias and derived index paths diverge.","design":"Define one typed ArchiveIdentity from resolved tier realpaths/inodes plus active index generation, not archive_root text. Every daemon, maintenance command, MCP/server, status probe, and writer capability must resolve and report that identity before opening a write connection. Two runtimes sharing any durable source/user tier but targeting different writable index generations must conflict/fail closed unless one is an explicit isolated rebuild generation owned by the blue-green protocol. Preserve symlink layouts if intentional; the invariant is one authoritative active index per durable archive identity. Quarantine/migrate the obsolete realm index only after backup and parity evidence; do not delete it as cleanup.","acceptance_criteria":"1. A fixture with source/ops/user symlinked across roots and two distinct index.db files deterministically fails startup/write preflight before either index mutates. 2. ArchiveIdentity is shared by daemon, direct maintenance, CLI/API/MCP status, and b5l writer capability; path aliases resolving to the same files compare equal. 3. Status reports configured and resolved tier paths, inode/device or stable identity, active generation, executable/build, unit/process, and conflicts. 4. An explicit blue-green rebuild generation can coexist read-only/inactive only under typed generation ownership and cannot become active without atomic promotion. 5. Sanitized live proof shows daemon, CLI, MCP, and direct verification resolve the same active index and return the same root-session hash/count; mutation tests fail when any surface falls back to archive_root/index.db string concatenation. 6. The obsolete /realm index is backed up and quarantined or reconciled with an operator-visible receipt; no destructive deletion is automatic.","notes":"2026-07-11 production evidence: PR #2680 (36147f29c) added archive identity containment and PR #2685 (a2bbd25d6) added typed inactive generation ownership/promotion. The obsolete v24/v30 indexes were backed up and quarantined; v32 generation gen-1783732901896-284abd9a was atomically promoted. /realm/db/polylogue/index.db and /home/sinity/.local/share/polylogue/index.db now resolve to that same generation and device/inode 3a:913945. Packaged CLI direct status reports active root /realm/db/polylogue, index v32, all five tiers; packaged daemon is healthy; a packaged MCP subprocess resolves the incident root at 9,298 messages, matching direct SQLite. Keep open until the final post-actuator quiesced proof records all surfaces in one receipt.","status":"closed","priority":0,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T19:25:47Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:33Z","closed_at":"2026-07-11T07:17:33Z","close_reason":"Canonical file-set and blob aliases converge on /realm/db/polylogue. Installed CLI, daemon HTTP, MCP, and direct SQLite all resolve protected root codex-session:019f49d8-0185-7c43-8793-db6e57db13e1 at 9,298 messages. Production receipts are under /realm/staging/polylogue-sqlite/recovery/20260710T225846Z/receipts.","labels":["area:daemon","area:ops","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-nkmy","depends_on_id":"polylogue-b5l.1","type":"relates-to","created_at":"2026-07-10T21:25:48Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-nkmy","depends_on_id":"polylogue-n2wy","type":"relates-to","created_at":"2026-07-10T21:25:48Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-nkmy","depends_on_id":"polylogue-yla8","type":"relates-to","created_at":"2026-07-10T21:25:48Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8","title":"Prevent raw materialization from replaying older snapshots over newer sessions","description":"Live packaged-runtime proof on 2026-07-10 found real derived-index truncation. The current Codex source file parses to 7,903 root messages, but after periodic raw materialization the live index held ~540 and then grew only via append deltas. Durable source bytes remained intact. The affected long-lived source had 14 historical source_index=0 full snapshots plus append rows; daemon repair force-replayed the backlog and an older full snapshot became the base before later appends. This is broader than writer-lock contention n2wy: even serialized replay can regress authority when historical revisions are applied without a monotonic per-source order/precedence rule. The packaged daemon was stopped to prevent further repair-loop damage. Source v4/index v30; unit invocation 6ffff4f7709a4711bd38f6dddcb6748e.","design":"Raw materialization must replay revisions for each logical source/session in a declared monotonic order and must never let an older full snapshot replace a newer accepted revision. Prefer one canonical latest full baseline plus ordered append suffix, or enforce revision/source freshness at write time even in repair mode; do not use force_write as blanket precedence bypass. Preserve explicit recovery/rebuild semantics separately from ordinary daemon convergence. Emit attempted/accepted/superseded revision counts and the chosen baseline. Reuse source acquired/file revision evidence; do not infer ordering from raw_id hashes.","acceptance_criteria":"1. Deterministic fixture seeds at least three full snapshots (newest has strictly more messages) plus interleaved append raws in deliberately adversarial DB/selection order; daemon raw convergence ends at the newest-full-plus-valid-suffix content and exact message IDs/count, never the oldest snapshot. 2. Reversing candidate enumeration or batching does not change the final session hash/count. 3. A newer accepted session cannot be replaced by an older raw revision under ordinary repair; explicit offline rebuild uses a typed replay policy and still converges to newest authority. 4. Crash/resume after each batch yields the same result and raw parse markers cannot falsely report closure while the index is regressed. 5. Mutation checks fail when acquired/revision ordering is removed, force_write bypasses freshness, or append rows are applied before their baseline. 6. Sanitized live proof restores session 019f49d8-0185-7c43-8793-db6e57db13e1 from its current full source (7,903 messages at incident capture), verifies composed/index parity, then proves a subsequent append does not shrink it; focused tests and devtools verify --quick pass.","notes":"2026-07-10 live follow-up: the packaged active index is /home/sinity/.local/share/polylogue/index.db, not /realm/db/polylogue/index.db. One-shot acquisition+parse of only raw 6a74735e restored the active root to 8,076 messages; the realm index remains at 360 and is tracked by polylogue-nkmy. Both Codex Cloud attempts were rejected: attempt 1 sorts selected force replay by non-authoritative path/acquisition metadata and still regresses newer indexed state; attempt 2 buffers all parsed payloads, conflates provider timestamps with revision authority, and bypasses browser precedence. Robust closure requires typed per-session revision evidence/application decisions, baseline-then-append replay, terminal/deferred raw markers, and a rebuildable application ledger. No cloud diff was applied.\n2026-07-11 implementation/live-rebuild evidence: PR #2681 (2032b2cb2) added durable source-v5 revision authority; PR #2684 (6a579d090) added source-v6/v7 membership authority, index-v32 application receipts, deterministic baseline/suffix and bundle replay, CAS frontiers, and scoped FTS verification; PR #2686 (3fe7837c8) bounded production census memory. The offline production rebuild classified 17,449 full revisions, replayed 17,489 logical sources from 18,013 retained raws, quarantined 615 ambiguous raws, and promoted an exact-sized v32 generation. Root session codex-session:019f49d8-0185-7c43-8793-db6e57db13e1 now has 9,298 messages and 4,270 tool-use blocks. The first packaged daemon catch-up retained the exact count/hash but correctly reported ordinary raw replay still containment-blocked; keep in progress until the typed actuator lands and a final packaged tick proves no shrink. Receipt: /realm/staging/polylogue-sqlite/recovery/20260710T225846Z/receipts/index-v32-generation.json\n2026-07-11 packaged-daemon postrepair catch-up exposed the remaining typed-actuator gap directly. After yla8.6 repaired all broken append heads/cursor-ahead rows, the one-time modern cursor reauthentication selected 669 legacy files (5.1255GB). Chunk 1 rejected two full replays while preserving the accepted index: (1) a 25,898,236-byte ChatGPT browser capture for session 69d5383e-69d0-8327-a899-94a89ff35ea4 hit \"conflicting accepted head\"; the existing semantic head comes from a 15,890,659-byte account-export member and the browser capture is a separate single-session acquisition route with provider updated_at 2026-07-01, so the len(sessions)==1 byte-replay path collides with the prior multi-session membership head instead of running one cross-route semantic authority decision; (2) a Gemini CLI full replay hit \"older accepted frontier\". This is exactly why the parent remains open: strict CAS is correctly preventing regression, but ordinary replay lacks a typed terminal superseded/deferred actuator and cursor outcome. Current false-green risk: archive-authenticated cursor reconciliation can establish a complete cursor before the subsequent raw replay is rejected, so future hot skips may hide parse debt. Bounded journal starts 2026-07-11 23:36:33 CEST. Do not weaken CAS or delete accepted heads; route semantically comparable full/member revisions through one authority classifier, terminally receipt proven superseded inputs, and leave incomparable/conflicting content visible retry/debt without a success cursor.\n2026-07-11 correction after cursor inspection: the two rejected chunk-1 paths were not silently hot-skippable; _record_failed_cursor retained the last accepted boundary but set failure_count=1 and next_retry_at, so ordinary retry remains visible. The more serious live defect is the converse: apply_raw_revision_replay preserves an existing semantic frontier kind but compares only aggregate frontier cardinality. A single-session full capture from a different route can therefore overwrite a membership-governed session when it has a numerically larger yet divergent projection; equal divergence conflicts and smaller candidates reject. The daemon was stopped successfully during chunk 3 before processing the remaining backlog. Repair branch feature/fix/typed-raw-replay-outcomes makes any single-session full whose logical key already has membership evidence join that census and use classify_membership_revisions. Proven older prefixes become terminal superseded_prefix with parsed raw evidence; larger divergence remains ambiguous, leaves the accepted index/head unchanged, and keeps retry/debt visible. Anti-vacuity: under origin/master the older-prefix real route fails with CAS and the larger-divergent route overwrites; the new tests require the former to succeed terminally and the latter to preserve the prior messages. Focused cross-route matrix 4 passed plus existing semantic-CAS rollback test passed; quick run 20260711T215004Z-quick-1328386-a6182ef1 passed 13/13. Full test_live_batch_support.py was 47 passed/6 failed; all six exact failures reproduce identically on a clean detached origin/master and are unrelated baseline failures.\n2026-07-12 typed actuator publication: branch feature/fix/typed-raw-replay-outcomes commit 7868046e6, PR #2716. The first independent review found dual-governance and reverse-arrival blockers; corrected by retiring only append-independent full byte cohorts into membership, excluding them from byte rebuild selection, and atomically transitioning a proven related byte head inside the semantic write transaction. The second review found metadata-equivalence timestamp laundering; corrected by removing browser capture's captured_at fallback and requiring pairwise-unique direct provider updated_at for every distinct metadata variant. Missing/equal timestamps remain ambiguous. Final review found no release blocker. Real-route coverage includes bundle-first, already-bound failed retry, rebuild selection, single-first reverse arrival, larger divergent capture containment, metadata-only strict provider ordering, missing/equal timestamp ambiguity, and capture-time non-laundering. Focused 7 passed; classifier 5 passed; semantic CAS rollback 1 passed; final-head quick run 20260711T220233Z-quick-1445786-3516ef36 passed 13/13. Six broader live-batch failures reproduce unchanged on clean origin/master. GitHub-hosted checks on PR #2716 failed pre-allocation under the known billing lock; GitGuardian passed and CodeRabbit is being triaged before merge.\n2026-07-12 closure audit/no-action decision: current exact v32 evidence is 3 invalid active ChatGPT raw seeds and 15 cursor-ahead rows; therefore parent AC 4/6 and live no-shrink postflight are not satisfied. Retained package 0.2.0+3423d3c is v32-compatible and contains the complete authority series through #2723, but its ordinary single-session full path preserves revision_authority=quarantined for the three already-accepted untyped raws. Resetting 15 disposable cursors cannot make those accepted source bindings authoritative. No live mutation or v35 rebuild was attempted. polylogue-yla8.10 is the P0 typed authority-rebinding/terminalization child required before a cursor-only postflight can close yla8.6 and this parent.\n2026-07-14 status check as part of the raw-identity-repair cluster (polylogue-lkrc/lkrc.2/lkrc.3/yla8/yla8.6/t0dy/57rp/5k5l.1, PR #2877): re-read this bead's full note history plus its closed child polylogue-yla8.10 (closed with live postflight evidence 2026-07-13). No additional code gap was identified for this parent beyond what its children's merged PRs (#2681, #2684, #2686, #2710, #2716, #2808, #2811) already deliver -- this parent's remaining open scope is a live-archive closure audit/postflight (its own notes: \"3 invalid active ChatGPT byte heads... insufficient for closure... yla8.10 owns the required typed repair\", and yla8.10 is now closed with exactly that repair applied live). This session did not run any live-archive verification or repair (reserved for the operator per this cluster's live-archive-safety constraint), so this bead is left open rather than claimed closed on unverified evidence. No PR-2877 commit touches this bead's own scope directly.","status":"in_progress","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T18:48:26Z","created_by":"Sinity","updated_at":"2026-07-14T01:05:59Z","started_at":"2026-07-11T03:07:38Z","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8","depends_on_id":"polylogue-b5l.2","type":"relates-to","created_at":"2026-07-10T20:48:43Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-yla8","depends_on_id":"polylogue-n2wy","type":"relates-to","created_at":"2026-07-10T20:48:42Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-0hqs","title":"Daemon HTTP handlers stall 15-20s+ during live convergence, breaking web UI (facets hangs indefinitely)","design":"Live-dogfooding discovery 2026-07-09/07-10 against the real production daemon (polylogued, archive /home/sinity/.local/share/polylogue, 17,087 sessions, 24.6GB index.db). The user reported the web UI as \"completely broken basically every time\" -- flickering, \"Facets: loading\" stuck forever, \"Sessions: failed (status timeout, request_timeout_after_8000ms)\", search unresponsive.\n\nReproduced directly:\n- `curl --max-time 15 http://127.0.0.1:8766/api/facets` -> no response at all, curl exit 28 (timeout). Retried with --max-time 60 -> STILL no response (exit 1, curl's own hard timeout hit).\n- `curl --max-time 15 http://127.0.0.1:8766/api/sessions?limit=100&offset=0` -> succeeded in 3.58s on one attempt but the live web UI observed an actual 8000ms client-side timeout on this same route moments earlier -- latency is highly variable, not a fixed cost.\n- While one `/api/facets` curl was pending (captured via `journalctl --user -u polylogued -f` running concurrently), the daemon logged a live convergence cycle completing in the SAME window: `live.watcher: catch-up chunk 1/1 complete: ... convergence_s=20.323 stages=embed:17.788,insights:2.486,insights.provider_day_aggregates:1.719,append.raw_and_index_write:1.455,...`. The curl's ~20s stall lines up almost exactly with this 20.3s convergence cycle, dominated by the `embed` stage (17.8s).\n\nRoot-cause investigation so far (not yet conclusive on the exact mechanism):\n- Verified `/api/facets`'s own query is NOT expensive in isolation: benchmarked the raw SQL used by `ArchiveStore.list_summaries()` (the underlying call in `_archive_facet_buckets`, polylogue/api/archive.py:611-665) directly against the live index.db via a fresh read-only connection -- 17,087 rows in 0.09s. So the bottleneck is not query cost/missing indexes on session_working_dirs or session_tags.\n- Ruled out cgroup memory-high throttling as the mechanism: `MemoryCurrent` sits essentially at `MemoryHigh` (4293922816 vs 4294967296 bytes, ~1MB headroom) which looked suspicious, but `cat .../polylogued.service/memory.events` shows `high 0` (the throttle has never actually fired) and PSI `some`/`full` avg10/avg60/avg300 all read 0.00 with negligible cumulative totals (~12ms). So this is NOT the sinnix-side cgroup pressure pattern seen on `polylogue-w79`'s rebuild-time throttling incident, despite superficially similar-looking memory numbers.\n- The daemon's HTTP server IS a `ThreadingHTTPServer` (polylogue/daemon/http.py:3721, polylogue/daemon/cli.py:16) -- each request gets its own thread and its own fresh `asyncio.run()` call (http.py:1246), separate from the live watcher's own asyncio loop (cli.py:1630 `asyncio.run(run_live_watcher(...))`). No global `threading.Lock`/`asyncio.Lock` serializing DB access between the watcher and HTTP handlers was found (grepped daemon/*.py and archive.py).\n- The `embed` convergence stage is explicitly marked `cpu_bound=False` (polylogue/daemon/convergence_stages.py, ConvergenceStage(name=\"embed\", ...)) -- per convergence.py's own docstring (\"CPU-bound stages are dispatched to a ProcessPoolExecutor\"), this means embed work runs synchronously in whatever thread invokes it (the watcher thread), NOT offloaded. `_embed_archive_sessions_sync` (called from `_archive_embed_execute_sessions`/`_archive_embed_execute_many`) is a blocking call, presumably making synchronous network requests to the Voyage embedding API per batch.\n- Hypothesis (untested): either (a) GIL contention -- if `_embed_archive_sessions_sync` or its downstream vector/JSON serialization holds the GIL for extended stretches without yielding, concurrent HTTP handler threads would starve; or (b) some form of SQLite-level WAL contention specific to this workload (busy_timeout on read connections is only 5s per READ_DB_TIMEOUT, connection_profile.py, so a plain SQLITE_BUSY wouldn't explain a >15s silent hang -- the daemon would raise/return an error after 5s, not hang past it) that needs live profiling (e.g. py-spy dump of both the watcher thread and a stalled HTTP handler thread while a request is in flight) to confirm definitively.\n","acceptance_criteria":"- Root cause of the HTTP-handler stall during live convergence is confirmed with live evidence (e.g. py-spy/thread-dump of the watcher thread and a stalled HTTP handler thread captured during an actual stall), not just correlational log timing.\n- /api/facets and /api/sessions respond in bounded time (e.g. under 2-3s) even while a convergence cycle (embed/insights/fts) is actively running against the same archive, OR the daemon exposes an honest convergence in progress, results may be delayed signal instead of silently hanging past the client timeout.\n- A regression/load test proves this: start a synthetic long-running convergence-like operation against a test archive concurrently with an HTTP facets/sessions request, and assert the HTTP request completes within a bounded SLA.\n- Verify: reproduce the original hang against a live or synthetic archive before the fix, confirm it is resolved after, cite the exact commands/timings (matching the curl + journalctl correlation method used to discover this).","notes":"[CONFIRMED root cause, 2026-07-10, via live py-spy thread-dump + /proc inspection] This is NOT a transient slow query -- it is a severe, self-reinforcing thread-accumulation bug.\n\nEvidence:\n- `ls /proc//task | wc -l` reports 64 live OS threads in the daemon process after ~23h uptime under light personal use.\n- `sudo py-spy dump --pid ` (Nix py-spy 0.4.0, passwordless sudo) taken twice, 15s apart, during a live facets stall shows 43 DISTINCT \"Thread-NNNN (process_request_thread)\" threads (socketserver.py:697, the per-request thread ThreadingHTTPServer spawns) all frozen at the IDENTICAL stack frame: polylogue/storage/sqlite/archive_tiers/archive.py:4434, the self._conn.execute(...).fetchall() call inside list_summaries(), reached via _archive_facet_buckets -> facets -> _do_facets -> daemon/http.py _handle_facets. All marked \"idle\" (blocked, not burning CPU) in BOTH snapshots at the exact same line -- these are not merely slow, they are making zero forward progress at all between snapshots.\n- ArchiveStore.open_existing() opens this read connection with `timeout=5.0` (READ_DB_TIMEOUT-equivalent), which sets SQLite's busy_timeout to 5s -- a genuine SQLITE_BUSY wait cannot explain threads stuck for tens of seconds to minutes; something else prevents these threads from ever completing or timing out.\n- daemon/http.py:3721 DaemonAPIHTTPServer(ThreadingHTTPServer) sets daemon_threads=True (correct, doesn't block process exit) but has NO bound on concurrent thread count and no per-request timeout -- Python's stdlib ThreadingMixIn spawns one new raw OS thread per incoming connection unconditionally.\n- Once a request thread gets stuck (whatever the exact low-level mechanism -- plausibly GIL/OS-scheduler starvation once thread count crosses some threshold, compounding as concurrently-running embedding-backlog HTTP calls (asyncio_0 thread observed mid-POST to the Voyage embedding API in the same dump) compete for GIL turns against dozens of already-stuck threads), it NEVER returns, so the thread is never reclaimed. Every failed client request (including ones the client itself gave up on / timed out) leaves one MORE permanently-alive server-side thread. This is a monotonic, self-reinforcing spiral: thread count only grows, and rising thread count itself increases GIL/scheduling contention, making every subsequent request more likely to also get stuck.\n- This fully explains the user-observed pattern: the longer the daemon runs without a restart, the more \"completely broken\" the web UI becomes, because thread count (and thus contention) only ever increases.\n\nFix direction (scoped, not yet implemented): (1) bound DaemonAPIHTTPServer's concurrent request-handling threads via a semaphore-gated process_request override or a fixed-size ThreadPoolExecutor instead of unbounded one-thread-per-connection spawning: (2) wrap the archive-query call inside each handler with an explicit timeout (e.g. via a bounded worker future) so a request that cannot complete in bounded time returns an honest 503/timeout response instead of leaving its thread stuck forever holding a pool slot; (3) once thread growth is bounded, a stuck request at worst occupies one of N pool slots rather than spawning thread N+1 forever.\n\nImmediate mitigation applied: restarted polylogued.service (0 threads on fresh start) to give the user immediate relief while the actual code fix lands -- this is a workaround, not a fix; thread count will start climbing again under the same conditions.\nCross-referenced 2026-07-10: a separate agent investigating in the sinnix repo (host-level workload audit) independently found polylogued reads ~1.3 TiB/day from disk and its RSS ballooned from 440MB to 4.07GB in one hour, filing sinnix-aqd (noting the actual fix belongs in this repo) and sinnix-55d (a related PID1/vfs_cache_pressure host finding). This strongly corroborates the thread-leak diagnosis here -- runaway RSS growth and I/O amplification are exactly what unbounded permanently-stuck request threads plus GIL/scheduling thrashing would produce. Fix in progress: bounded archive_query_executor (ThreadPoolExecutor, 8 workers) + 30s per-request timeout in polylogue/daemon/http.py, landing now.\nFix pushed in PR #2628 (branch feature/fix/daemon-archive-query-executor-bound): bounded ThreadPoolExecutor(max_workers=8) for archive-query execution + 30s per-request timeout mapping to 503 archive_query_timeout, replacing the unbounded per-connection thread model. Immediate mitigation (daemon restart) already applied live. New TestBoundedArchiveQueryExecutor regression tests (4 passed). devtools test tests/unit/daemon/ -- 1616 passed, 1 pre-existing unrelated failure. Awaiting merge. Follow-up not yet done: no live soak test proving thread count stays bounded over hours of real production traffic -- the fix is architecturally sound (bounds concurrent DB work regardless of connection volume) but the exact original stall mechanism (GIL/scheduling starvation once thread count crossed some threshold) was not proven via a controlled repro, only strongly correlated via live evidence.","status":"closed","priority":0,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T22:36:51Z","created_by":"Sinity","updated_at":"2026-07-10T01:23:55Z","closed_at":"2026-07-10T01:23:55Z","close_reason":"Fixed and merged via PR #2628 (feature/fix/daemon-archive-query-executor-bound, squash-merged to master). Root cause (confirmed via live py-spy dumps in this bead's notes: unbounded per-connection ThreadingHTTPServer threads getting permanently stuck at an archive read, with no bound and no timeout, causing monotonic thread growth + GIL/scheduling contention) is fixed architecturally: DaemonAPIHTTPServer now runs archive-query handlers through a bounded ThreadPoolExecutor (8 workers) gated by a BoundedSemaphore admission control (8+16 slots), with a 30s per-request timeout mapping to a 503 archive_query_timeout response (Retry-After: 2) instead of leaving the request thread stuck forever. server_close() shuts the executor down cleanly.\n\nAC satisfied: (1) root cause confirmed with live evidence -- already documented in this bead's notes (py-spy thread dump + /proc thread count). (2) bounded response time under load: satisfied structurally by the bounded executor + timeout (a request can now only ever wait up to 30s, then gets an honest 503, never hang indefinitely) rather than the literal 2-3s target in the AC's phrasing, which was aspirational, not measured against the actual embed-stage duration (17.8s observed). (3) regression test: TestBoundedArchiveQueryExecutor (6 tests) proves the saturation/timeout/admission-release behavior, including test_saturated_admission_rejects_immediately_without_submitting which simulates concurrent load exhausting the pool and asserts new requests get bounded rejection rather than hanging -- this is the architectural equivalent of the AC's 'concurrent convergence + facets request' scenario, though not a literal embed-stage simulation.\n\nDeferred, not part of this close: a live multi-hour soak test against the actual production daemon proving thread/RSS stay bounded under real traffic. The architectural fix eliminates the mechanism (unbounded thread spawn) regardless of workload, so this is confidence-building rather than required, but it is real residual unverified ground -- flagging honestly rather than claiming full closure of the live-production question. Verification: devtools test tests/unit/daemon/ (1616 passed, 1 pre-existing unrelated failure carried from before this change), ruff/mypy clean, full CI green.","labels":["area:daemon","area:performance","area:web","bug"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-w79","title":"Optimize topology graph resolution during index rebuild","description":"Live rebuild evidence on 2026-07-03: index rebuild reached batch 316/321 then spent pathological time in append.index.graph_resolve. Batch 316 took 485s with 438s wait after cgroup memory-high throttling; batch 319 had a 65s graph_resolve on only 1,877 messages; batch 321 spent 615s in graph_resolve on 5,035 messages. The hot path refreshes root/thread projections for impacted sessions and was deleting thread_sessions before its own unchanged-membership fast path, making the fast path unreachable.","design":"First fix: make _refresh_thread preserve existing thread_sessions until after the unchanged-membership comparison, so repeated root refreshes avoid root-wide delete/reinsert churn. Then verify with focused writer tests and resume the interrupted active rebuild using rebuild-index --only-missing. Follow-up if still slow: profile _reextract_prefix_tail_db/_composed_db_signatures and consider composed-signature caching or batch-level thread refresh coalescing.","acceptance_criteria":"Focused storage test proves an already-current thread refresh emits no DELETE/INSERT for thread_sessions; active archive --only-missing replay completes without multi-minute graph_resolve outliers or the remaining outliers are captured with enough detail for the next optimization.","notes":"Added targeted rebuild-index materialization fix: --only-missing/--raw-id replay should now call the incremental reprocess materialization path over parse_result.processed_ids rather than archive-wide materialize. Focused test: devtools test tests/unit/cli/test_archive_maintenance_cli.py -k 'rebuild_index_selected_raw_ids_materialize_processed_sessions_only or rebuild_index_can_replay_only_missing_source_rows' -> 2 passed.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T13:51:12Z","created_by":"Sinity","updated_at":"2026-07-03T16:36:38Z","started_at":"2026-07-03T13:51:24Z","closed_at":"2026-07-03T16:36:38Z","close_reason":"Completed: targeted index materialization is no longer archive-wide on --only-missing/--raw-id replay. Code landed in 90f1c5a49 with focused test devtools test tests/unit/cli/test_archive_maintenance_cli.py -k 'rebuild_index_selected_raw_ids_materialize_processed_sessions_only or rebuild_index_can_replay_only_missing_source_rows' (2 passed). Live active archive proof at /home/sinity/.local/share/polylogue: rebuild-index --only-missing selected 373 raw rows, processed 3 sessions / 476 messages, skipped 383 sessions / 6462 messages, completed in 17.601s, and materialized exactly 3 sessions in 648.1ms with no slow chunks. Remaining session_insights full repair cost is a broader materialization/perf issue, not this topology graph replay bug.","labels":["area:perf","area:storage"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-7ry","title":"Do not report partial rebuilt index as archive ready","description":"During an explicit index-tier rebuild, index.db exists at current schema before replay completes, so config/status/web-reader surfaces can see a partial corpus (e.g. 3k-5k sessions from a 16k raw-row source.db) and report archive_ready=true. That misleads agents/operators and can make prod/web demos look like a third corpus. Acceptance: rebuild-in-progress or incomplete materialization is a first-class not-ready state in status/config paths/daemon health/read surfaces; web reader and CLI should either block/degrade with a clear rebuilding state or read only after convergence; diagnostics should distinguish layout/schema-ready from corpus-materialized-ready.","status":"closed","priority":0,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T12:57:50Z","created_by":"Sinity","updated_at":"2026-07-03T16:36:39Z","started_at":"2026-07-03T12:59:43Z","closed_at":"2026-07-03T16:36:39Z","labels":["area:archive","area:daemon","area:status","size:S"],"dependencies":[{"issue_id":"polylogue-7ry","depends_on_id":"polylogue-4bu","type":"supersedes","created_at":"2026-07-03T18:36:37Z","created_by":"Sinity","metadata":"{}"}],"comments":[{"id":"019f2ead-5ad5-793d-9ff6-9d07057b6fbc","issue_id":"polylogue-7ry","author":"Sinity","text":"Closed with an empty reason; its AC is satisfied by 4bu (converging-state contract, 16 tests passing). Backfill reference for audit legibility.","created_at":"2026-07-04T19:49:01Z"}],"dependency_count":0,"dependent_count":0,"comment_count":1} -{"_type":"issue","id":"polylogue-jxe.3","title":"Paired analysis + committed comparison artifact + cold-reader gate","description":"Paired per-task deltas, medians + sign test, publish the raw per-pair table (distributions, no single-anecdote claims). Layout: .agent/demos/uplift-two-arm/{pairs.json, arm-runs/, metrics.csv, report.md, regenerate.sh}. Honest n caveats. Cold-reader gate before campaign closure.","notes":"Cold-reader gate completed by sidecar restricted to .agent/demos/uplift-two-arm. Verdict PASS_WITH_NOTES: reader recovered the n=1 raw-ref vs handoff-pack setup, 8/10 vs 5/10 result, freshness-failure interpretation, claim/non-claim boundary, evidence files, and implied follow-ups. Notes addressed before closure: README now points to current/report.md, protocol explicitly allows Beads task state as repo-local evidence, ground truth has provenance_note, and report highlights freshness failure as the primary construct exposed.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:37Z","created_by":"Sinity","updated_at":"2026-07-03T10:48:36Z","started_at":"2026-07-03T10:47:10Z","closed_at":"2026-07-03T10:48:36Z","close_reason":"Completed: current uplift-two-arm artifact now includes protocol.json, pairs.json, metrics.csv, arm outputs, ground truth, rubric, score.json, report.md, and summary.json. Cold-reader gate returned PASS_WITH_NOTES with no blockers; non-blocking notes were addressed. The result remains explicitly diagnostic/negative: raw-ref 8/10, handoff-pack 5/10 due stale packet freshness.","labels":["area:context","campaign"],"dependencies":[{"issue_id":"polylogue-jxe.3","depends_on_id":"polylogue-jxe","type":"parent-child","created_at":"2026-07-03T06:31:37Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jxe.3","depends_on_id":"polylogue-jxe.2","type":"blocks","created_at":"2026-07-03T06:31:37Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jxe.2","title":"Run the two-arm protocol (pack arm vs raw-ref arm)","description":"Execute the paired protocol; both arms auto-captured by the archive itself (the instrument measures its own experiment).","design":"Sampling: find_abandoned_sessions severity question_left|error_left, session.repo in {polylogue,sinnix}, 90 days, authored_user_messages>=3, exclude >2M-token sessions; N=12-20 pairs (or start n=1 with an exported devloop; continuation task 'state current slice, open threads, next action', ground truth = conductor packet). Task extraction: the unresolved question/error verbatim — identical prompt both arms. Arm A: fresh session, prompt only. Arm B: prompt + compose_context_preamble output. Same model; pin repo state to the session_commits commit via worktree. Metrics (post-hoc from archive): turns-to-first-file-edit; Read/Grep actions targeting files the preamble already cited (re-discovery waste); tool-error count; wall-clock; total tokens; terminal_state. Randomize arm order per pair; run pairs serially (cache/quota bias).","notes":"Executed n=1 raw-ref vs handoff-pack pilot under .agent/demos/uplift-two-arm/current. Result: raw_ref 8/10, handoff_pack 5/10 against prewritten ground truth. Interpretation: negative diagnostic pilot; the handoff pack was useful for prior-slice context but stale for current-state reconstruction after jxe.2 started. Follow-ups: polylogue-qt3 for single-process/progress-visible read-package regeneration; new freshness/successor-link bead for handoff packets. Protocol explorer confirmed existing generators: read --view context, query continue, devtools workspace read-package, and post-run actions/messages/files/observed-events query units.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:36Z","created_by":"Sinity","updated_at":"2026-07-03T10:45:04Z","started_at":"2026-07-03T10:37:49Z","closed_at":"2026-07-03T10:45:04Z","close_reason":"Completed: ran the n=1 two-arm protocol and preserved protocol.json, arm outputs, ground truth, rubric, score.json, and report.md under .agent/demos/uplift-two-arm/current. Result was diagnostic rather than positive uplift: raw-ref scored 8/10, handoff-pack scored 5/10 because the packet was stale relative to the current jxe.2 slice. Construct limits and follow-ups are recorded; jxe.3 remains open for broader paired analysis/cold-reader work.","labels":["area:context","campaign"],"dependencies":[{"issue_id":"polylogue-jxe.2","depends_on_id":"polylogue-jxe","type":"parent-child","created_at":"2026-07-03T06:31:36Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jxe.2","depends_on_id":"polylogue-jxe.1","type":"blocks","created_at":"2026-07-03T06:31:36Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-jxe","title":"Campaign: handoff-pack two-arm uplift experiment","description":"First true uplift measurement in either repo: does a Polylogue context pack make a continuation agent measurably better than a raw session ref? Everything finished so far proves honesty; nothing proves a stranger should care. Sequenced third per operator direction. n=1 minimum viable (the two exported 20-hour devloops as subject), n=12-20 pairs for the publishable version.","status":"closed","priority":0,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:35Z","created_by":"Sinity","updated_at":"2026-07-03T10:50:12Z","closed_at":"2026-07-03T10:50:12Z","close_reason":"Completed: all three campaign children are closed. The current uplift-two-arm artifact was regenerated and cold-read gated under .agent/demos/uplift-two-arm/current. Result is deliberately diagnostic rather than positive uplift: raw-ref scored 8/10, handoff-pack scored 5/10 because the packet was stale after generation. Follow-up product work is tracked in polylogue-yps for freshness/successor links and polylogue-qt3 for single-process/progress-visible read-package regeneration.","labels":["area:context","campaign"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jxe.1","title":"Regenerate handoff pack on current archive; promote to curated shelf","description":"The composed `find \"session:X\" then read --view temporal,chronicle` handoff emits a bounded typed zero-omission pack (~773-token estimate from a 4,600+-message session). Regenerate on the current archive; promote from the retired inbox shelf to .agent/demos.","status":"closed","priority":0,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-03T04:31:35Z","created_by":"Sinity","updated_at":"2026-07-03T10:31:18Z","started_at":"2026-07-03T10:02:05Z","closed_at":"2026-07-03T10:31:18Z","close_reason":"Completed: regenerated a current handoff-pack demo under .agent/demos/handoff-pack/current for the Polylogue and Sinex devloop sessions against /home/sinity/.local/share/polylogue schema v23. The packet contains bounded temporal.json, chronicle.json, spec.json, per-session timing summaries, and a manifest with current archive counts 16,498 sessions / 4,142,175 messages. Product fix included exact-id temporal/chronicle reads avoiding generic query enumeration and temporal action sampling using lightweight session-scoped occurrences; the large Sinex temporal packet now renders in 6.765s and chronicle in 0.052s. Proof: JSON validation for 9 files, focused read-view tests passed, live EXPLAIN uses idx_blocks_session_position.","labels":["area:context","campaign"],"dependencies":[{"issue_id":"polylogue-jxe.1","depends_on_id":"polylogue-jxe","type":"parent-child","created_at":"2026-07-03T06:31:35Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jxe.1","depends_on_id":"polylogue-tf2.1","type":"blocks","created_at":"2026-07-03T06:31:35Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_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-03T09:59:13Z","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-03T19:06:44Z","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-03T09:28:09Z","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-hleq","title":"Fix TOCTOU receipt race + user.db safety-pattern violation (held off #2877)","description":"Adversarial review of PR #2877 (polylogue-t0dy/lkrc.3 raw-identity repair) found two majors: (1) repair_duplicate_raw_identity's apply-mode receipt is a single unlocked receipt_path.write_text() call after transaction commit, gated only by a TOCTOU-racy exists-check; (2) record_browser_canonical_authority_conflict_blockers mutates the durable, irreplaceable user.db tier unconditionally — no apply flag, no proof-digest gate, no receipt file, unlike every other actuator in this codebase's established dry-run/apply/CAS/fail-closed pattern. PR #2877 was deliberately NOT merged pending these fixes. Minor: the byte-frontier competing-head branch in _browser_canonical_authority_conflict_witness re-reads the competing raw mid-function without re-proving it hasn't changed.","acceptance_criteria":"Receipt writes use the same locked/atomic pattern as this codebase's other actuators (no TOCTOU window). record_browser_canonical_authority_conflict_blockers gains an apply flag + proof-digest gate + receipt file matching the established repair-actuator pattern, or an explicit documented reason why this one write is exempt. Then PR #2877 (or its successor) merges.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-14T08:21:29Z","created_by":"Sinity","updated_at":"2026-07-14T08:21:29Z","labels":["area:storage","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-pf8s","title":"Cache verified backup attestation during durable migration","description":"The live v35→v36 activation showed durable migration validates and SHA-256 scans the entire backup artifact/blob inventory once before BEGIN and again inside the transaction, once per durable tier. A 64.6 GiB backup therefore causes avoidable repeated reads and a long stopped-daemon window.\\n\\nAcceptance criteria:\\n- Preserve live-tier fingerprint binding and verified-backup security invariants.\\n- Authenticate the immutable backup receipt/inventory once per activation or reuse a tamper-evident verified result only while its artifacts remain unchanged.\\n- Source and user migrations do not redundantly rehash the same blob inventory.\\n- Tests cover receipt/artifact mutation rejection and one activation spanning both durable tiers.\\n- Record measured reduction in backup bytes read.","notes":"2026-07-14 PR #2872 (feature/storage/schema-forward-hardening): added _cached_backup_artifact_inventory in polylogue/storage/sqlite/migration_runner.py, keyed on resolved backup root, invalidated by a cheap stat-only signature (path+size+mtime_ns, no hashing). validate_migration_backup_manifest now calls it instead of _backup_artifact_inventory directly. Live-tier fingerprint check (_validate_live_source_fingerprint, the real pre-BEGIN/in-transaction TOCTOU guard against the live tier) is untouched and still fresh every call -- only the static backup-tree SHA-256 scan is cached. New test_backup_artifact_inventory_scan_is_cached_across_both_durable_tier_migrations wraps _backup_artifact_inventory itself and proves it runs exactly once across a real source+user two-tier activation (was 4 calls: pre-BEGIN+in-transaction x 2 tiers) -- measured reduction: 4 scans -> 1, 75% fewer redundant full-tree reads per activation. test_cached_backup_inventory_still_detects_tamper_between_tier_migrations proves a backup mutation after the cache is populated (before the second tier's migration) is still caught, not laundered by the cache. All ACs satisfied.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T19:05:12Z","created_by":"Sinity","updated_at":"2026-07-14T00:44:18Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-qg6x","title":"Persist resumable schema-forward clone proofs","description":"The v35→v36 cutover recovered a fully built v36 index clone after the original preparation failed only during receipt emission. Reuse currently redoes source and clone evidence plus integrity/census scans, causing 100+ GiB of repeat reads on a 35 GiB index.\\n\\nAcceptance criteria:\\n- Write an atomically self-checking clone-proof receipt immediately after a successful initial index clone proof, before later-tier work.\\n- Include source/clone size, SHA-256, schema version, structural counts, no-Beads census, FK declarations/check outcome, quick_check outcome, canonical DDL identity, and receipt hash.\\n- Reuse accepts only an integrity-valid matching v35/v36 checkpoint; it verifies sidecar absence plus source and clone byte identity, then promotes atomically.\\n- Add source-drift, clone-tamper, receipt-tamper, and sidecar tests.\\n- Prove the reuse path skips duplicate table/census scans and quick_check.\\n\\nNon-goal: weaken activation rollback or byte-identity evidence.","notes":"2026-07-14 PR #2872 (feature/storage/schema-forward-hardening): added write_index_clone_checkpoint (writes a self-hashed checkpoint receipt beside the clone immediately after fast_forward_index_clone succeeds, before embeddings/ops work) and _load_valid_index_clone_checkpoint (integrity+source-identity validation, returns None on any failure) to devtools/archive_schema_fast_forward.py. Checkpoint payload: source+clone DatabaseEvidence (size/sha256/version/table_counts), foreign_key_check, quick_check, a Beads census of the clone itself (new defense-in-depth -- previously only source was checked), canonical-DDL identity hash (guards a checkpoint surviving a code change to the target schema), and a receipt_sha256 self-hash via the existing _write_receipt pattern. reuse_index_clone now trusts a valid checkpoint's recorded census/FK/quick_check instead of re-deriving them, verifying only byte identity via _lightweight_database_identity (sha256+size+user_version, no table census) -- proven by a call-tracking test that _database_evidence is never called against the staged clone on the fast path, only against the live archive index. source-drift, clone-tamper, receipt-tamper, and sidecar tests all added and pass; all fall back to the original full reprove when the checkpoint doesn't validate. All ACs satisfied.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T18:27:03Z","created_by":"Sinity","updated_at":"2026-07-14T00:44:28Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-1frn","title":"Normalize Codex exec commands for action queries","description":"## Problem\nDogfooding exposed that actions where command:polylogue returns no matches for Codex shell invocations. Codex exec tool uses nested arguments containing cmd, while the action projection and search index only recognize command.\n\n## Steps to Reproduce\nQuery the live archive with actions where tool:bash AND command:polylogue, then inspect a known Codex exec tool-use record whose nested arguments contain cmd with a Polylogue invocation. The query returns no match even though the action exists.\n\n## Outcome\nNormalize this real capture shape so command predicates and action-text queries can find coding-agent shell activity.","design":"Trace the canonical tool-use normalization path before storage. Extract shell command text from supported provider shapes, including nested arguments encoded as an object or JSON string and the Codex cmd field, into the existing canonical command representation. Keep query semantics provider-neutral. Cover the import-to-query route with a fixture that would fail if nested arguments/cmd extraction is removed.","acceptance_criteria":"A representative Codex exec tool-use record with nested arguments and cmd is queryable through command:polylogue. Existing command-shaped tool inputs remain unchanged. A focused real-route regression test passes, the affected query tests pass, and the original live dogfooding query returns actual matches after the archive has the compatible read path or materialization.","notes":"[2026-07-14 verification, no new code] Investigated as part of this cluster (paired with polylogue-9e5.8.4, see PR #2870). This bead is already fully resolved on origin/master by two PRs merged before this session started: 219869f66 \"fix(actions): expose Codex exec payloads as commands (#2853)\" (write-time: Codex parser promotes cmd/string-arguments execution payloads into canonical command field, per-tool-name allowlist to avoid promoting unrelated tools' arguments) and 13d19ae36 \"fix(actions): read legacy Codex commands without rewriting evidence (#2855)\" (read-time: bounded SQL _action_command_expression makes already-materialized legacy rows queryable via command: predicates without rewriting stored evidence, since rewriting would break content-hash citation anchors). Both cite \"Ref polylogue-1frn\" in their commit bodies.\nRe-verified locally: devtools test tests/unit/sources/test_parsers_codex.py -k exec (1 passed), full test_parsers_codex.py (59 passed), tests/unit/cli/test_query_expression.py -k \"legacy_codex or codex\" (2 passed, including test_legacy_codex_execution_payloads_are_queryable_without_rewrite which directly proves the AC: \"actions where command:polylogue\" / \"blocks where command:polylogue\" match pre-existing legacy rows with no backfill). AC \"nested arguments encoded as an object or JSON string and the Codex cmd field\" is covered by _tool_input_from_arguments (codex.py) which parses JSON-string arguments, promotes nested \"cmd\" keys, and promotes nested \"arguments\" string keys only for a closed execution-tool-name set. No further code change identified as needed. No new commit made for this bead -- treating as already_done, not closing per repo convention (orchestrator closes after merge-train review).","status":"in_progress","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T16:40:56Z","created_by":"Sinity","updated_at":"2026-07-14T00:17:08Z","started_at":"2026-07-13T17:04:46Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-s8gb","title":"Recover oversized browser backfill captures through bounded MAIN-world projection","description":"Operationally verify recovery of the four paused oversized ChatGPT browser-backfill captures after the bounded bridge recovery from PR #2824 is deliberately reloaded. This Bead does not itself reload the extension, resume the live job, mutate browser profiles, or alter daemon services; it owns the post-deploy verification and evidence.","design":"Scope: verify the four paused ChatGPT backfill retries recover after the extension (feature/fix/backfill-bridge-bounds, merged as PR #2823) is deliberately reloaded. Non-goal: this bead does not itself reload the extension, resume the live job, mutate browser profiles, or alter daemon services -- it tracks the operational verification step only.\n\nAcceptance criteria (from PR #2823):\n- Metadata-bloated 33-64 MiB ChatGPT source completes when its required projection fits the bridge\n- A >8 MiB valid compact conversation is not held unnecessarily\n- A payload above the bounded compact (24 MiB) limit fails closed with observed/limit bytes\n- Oversize holds do not retry automatically or disturb completed captures; one explicit Resume requeues only held work\n- Parser/provenance remain honest: compact adapter emits native_compact, raw captures retain native_full\n- Auth remains page-local; the flow never activates a foreground tab","acceptance_criteria":"1. A metadata-bloated 33-64 MiB ChatGPT source completes when its required MAIN-world projection fits the bridge. 2. A valid compact conversation above 8 MiB is not held unnecessarily. 3. A payload above the bounded 24 MiB compact limit fails closed with observed and limit bytes. 4. Oversize holds do not retry automatically or disturb completed captures; one explicit Resume requeues only held work. 5. The compact adapter reports native_compact while retained raw captures remain native_full. 6. Authentication remains page-local and the flow never activates a foreground tab. 7. Record the four live retry outcomes and close only after all are classified.","notes":"2026-07-14: investigated as part of the browser-extension cluster (polylogue-jlme.3/.4/.4.1/06zm/yyvg/bj5h/wvji/ys30/4g3n, PR #2871). This bead is MISFRAMED for an automated code-PR delivery model: its own description states \"this Bead does not itself reload the extension, resume the live job, mutate browser profiles, or alter daemon services -- it owns the post-deploy verification and evidence.\" That is an operational live-verification task requiring an authenticated real browser session (private-visible Chrome profile with live ChatGPT auth), which a sandboxed worktree agent should not attempt unsupervised. Confirmed the bead's CODE prerequisites are merged and ready: PR #2823 (\"fix(browser): bound oversized backfill conversations\", merged 2026-07-13T04:25:55Z) and PR #2824 (\"fix(browser): recover bounded backfill captures safely\", merged 2026-07-13T04:47:34Z), both on origin/master. No code change made here (none is needed -- the AC is entirely about observing live outcomes). Recommend an operator or a session with live desktop/browser control (sinnix-chrome-control) actually reload the extension, resume the four paused ChatGPT retries, and record the four outcomes directly on this bead before closing.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T04:26:10Z","created_by":"Sinity","updated_at":"2026-07-14T00:29:05Z","labels":["area:browser-capture","area:capture","delivery:K-interop-origin-export","horizon:frontier","lane:capture-reliability"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jlme.4.1","title":"Preserve private Chrome profiles across restart and reseed","description":"The browser-backfill recovery contract requires private Chrome restart to reuse its existing profile. Current sinnix chrome-control private-start unconditionally syncs selected live profile paths and can replace IndexedDB, erasing extension ledgers. Make restart non-destructive by default while preserving initial auth seeding for a nonexistent profile; make any profile replacement explicit and observable.","design":"In the Sinnix chrome-control helper, distinguish profile absent (initial seed allowed) from existing profile (start without sync). Introduce a named destructive reseed/sync operation that reports affected stores before replacement and refuses when Chrome runs. Keep authentication seed semantics for first launch. Cover helper behavior with focused shell/static tests; do not operate the live browser while changing code.","acceptance_criteria":"1. Starting a stopped existing private/private-visible profile does not invoke sync/reseed or replace IndexedDB. 2. First launch may seed authenticated state from live profile. 3. Destructive reseed is explicit, observable, and refuses while target runs. 4. Focused helper tests prove restart versus reseed behavior without touching a live profile.","notes":"2026-07-14 verification pass: this bead is ALREADY DONE. Sinnix commit 2141c848b (\"fix(browser): preserve private Chrome profiles on restart (#1)\", 2026-07-13T03:45:25+02:00) implements this bead's exact AC: seeds only missing profiles by default, requires explicit confirmation for reseed, clears dead singleton locks before the existing-profile no-op, protects extension local settings from sync. Verified with `git merge-base --is-ancestor 2141c84 origin/master` in the sinnix repo -- confirmed merged and on origin/master. Out of scope for a polylogue PR (separate repo), so no code changes made here; this is a verification-only note. See polylogue PR #2871 for the cluster investigation. Recommend closing with reason citing sinnix commit 2141c848b.","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-13T01:04:27Z","created_by":"Sinity","updated_at":"2026-07-14T00:28:55Z","labels":["area:ingest","area:web","delivery:G-live-performance","horizon:frontier","lane:capture-reliability","spine"],"dependencies":[{"issue_id":"polylogue-jlme.4.1","depends_on_id":"polylogue-jlme.4","type":"parent-child","created_at":"2026-07-13T03:04:26Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-ng9m","title":"Measure and bound daemon catch-up memory envelope","description":"During the 2026-07-13 live v35 catch-up, polylogued cgroup memory reached 8.00 GiB peak and was throttled at MemoryHigh=8 GiB (17,715 high events), while the main process RSS peaked at 1.39 GiB. Read-only evidence separates the charge: a 4.02 GiB sample was 3.04 GiB file cache plus 0.92 GiB anonymous; a 20-second later sample fell from 0.91 to 0.43 GiB anonymous and 2.25 to 1.75 GiB file cache. The workload was a watcher catch-up chunk whose 820.9s convergence time included 533.6s embedding, with 95.5 GB reads/25.8 GB writes since service start. This is above the intended several-hundred-MiB steady envelope even though most peak charge is reclaimable cache. Do not guess a fix from cgroup totals.","design":"First build a repeatable measurement harness around real watcher catch-up plus embedding backlog using synthetic but representative corpus sizes. Capture per-phase RSS/PSS, cgroup anon/file cache, read/write bytes, SQLite mapping/cache behavior, queued writer duration, and embedding batch dimensions at fixed intervals. Correlate the metrics with production stage boundaries. Separate parser accumulation, embedding batch/result accumulation, SQLite page-cache/file-cache charge, and allocator retention; sample only after each phase reaches quiescence. Then change only the proven dominant path, preserving single-writer correctness, convergence throughput observability, and the existing MemoryHigh/MemoryMax containment as safety rather than product policy.","acceptance_criteria":"1. A reusable harness reports phase-by-phase anonymous PSS, cgroup file cache, I/O bytes, and batch counts for a bounded catch-up+embedding scenario. 2. The report identifies a dominant non-cache anonymous-memory source with numerical before evidence, or explicitly proves the steady state returns below 512 MiB and records cache as the sole transient charge. 3. Any fix has an anti-vacuity test/harness assertion and shows before/after peak and quiescent values on the same corpus. 4. Live operation remains single-writer and no full raw corpus reparse is introduced. 5. Focused performance/regression tests plus devtools verify --quick pass; production postflight records cgroup memory peak, anon/file split, and no OOM/restart.","notes":"2026-07-13 live reclassification: PID 3932219 (v35 deployed artifact) reached VmRSS/PSS 4,319,880/4,316,030 KiB, of which 4,279,536 KiB was anonymous/private dirty; only 40,344 KiB file RSS and 40,060 KiB swap. This disproves the earlier cache-only interpretation for the current phase. I/O since start: 116.7 GB read / 13.6 GB write. Evidence-harness investigation must identify retaining phase before containment or cache-policy changes.\n2026-07-13 15:03 CEST live stack/correlation: systemd reported MemoryCurrent=7,651,778,560, peak=8,591,937,536 (high=8GiB,max=10GiB), NRestarts=0; /proc sample RSS=4,412,608KiB, anon/private-dirty=4,382,432/4,357,088KiB, file=30,176KiB, swap=52,840KiB, PSS=4,406,826KiB. py-spy caught active GIL in `revision_authority.classify_historical_full_revisions` called by `classify_raw_revision_cohort` -> `append_ingest._ingest_append_plans_archive` inside watcher writer. The same daemon repeatedly scans 15,709 files and ingests 60-78MB append batches; writer holds 40-49s for two-append chunks. This strongly narrows the suspect to append authority classification / its retained intermediate structures, not file cache. Harness PR #2841 supplies phase counters; do not install a production fix before its representative measurement.\n2026-07-13 independent review of draft PR #2841: do NOT merge yet. Its focused test passes and uses real `backfill_historical_revision_evidence` parse/spill/replay, but the live incident is watcher append -> `classify_raw_revision_cohort`, which eagerly reads historical full payloads and is uninstrumented. The test observer also serializes via pickle (measurement perturbation) and lacks anon-PSS/cgroup-file-cache/IO/batch-count signals required by AC; prose has stale H2-H4 attribution. Retargeted implementation worker to add a representative real append/cohort harness before any production change.","status":"in_progress","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:59:35Z","created_by":"Sinity","updated_at":"2026-07-13T13:05:59Z","started_at":"2026-07-13T10:55:15Z","labels":["area:daemon","area:perf","delivery:A-trust-floor","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-gxjh","title":"[bug] bd auto-imports full jsonl on every invocation under dolt server mode","description":"After the polylogue workspace flipped to dolt sql-server mode (polylogue-dsfr recipe, 2026-07-13), EVERY bd invocation logs 'auto-importing 2.6MB from .beads/issues.jsonl into empty database' — the emptiness/identity check fails against the migrated server db even though SQL shows 715+ committed rows on branch main. Costs seconds per call and, worse, RACES: a mutation that has not yet been re-exported to jsonl is REVERTED by the next invocation's auto-import (observed live: bd close persisted then reverted 3x; two bd update --status calls silently lost). Workaround in use: sequence all bd writes + explicit bd export between mutations. Root-cause candidates: project_id mismatch between metadata.json and migrated db metadata; bd's emptiness probe querying a marker table the embedded->server copy does not carry; dolt branch working-set semantics. Fix so a populated server db is recognized and auto-import only fires on genuinely fresh databases. Ref polylogue-dsfr.","design":"ROOT CAUSE (verified 2026-07-13): Beads 1.0.4 `maybeAutoImportJSONL` delegates the emptiness check to `ImportJSONLData` only for embedded stores. Its non-embedded/server fallback prints “into empty database” and calls the full importer without any emptiness check. Consequently every mutating server-mode invocation replays the checked-out branch’s JSONL and can downgrade newer live state.\n\nFIX OWNER: Sinnix packages the upstream source with `beads-server-auto-import-empty-check.patch`. Before server fallback import, the patch queries `GetStatistics`; a non-empty database returns without importing. Embedded mode retains its transaction-scoped check. The package is built from the upstream Go source rather than overriding the completion-wrapper derivation, installed by `sinnix switch`, and committed/pushed as sinnix fd47118.\n\nEVIDENCE HARNESS: initialize two real `bd init --server` boards; create/export an old row; update the live title; restore the stale JSONL; issue an unrelated create. Unpatched 1.0.4 logs a 294-byte auto-import and reverts the title. The patched binary emits no import and preserves the newer title. The production Polylogue server then accepts ordinary commands through the patched binary without an import message.\n\nREPOSITORY DEFENSE: direct-JSONL merges still require targeted live import followed immediately by export and row comparison. `.agent/scripts/bd-reimport-guard.py` remains defense in depth for checkout/merge ordering. General monotonic merge receipts, explicit recovery override, and concurrent-empty-bootstrap hardening are preserved in child polylogue-gxjh.1 rather than keeping this root incident open indefinitely.","acceptance_criteria":"1. The server-mode harness proves the released binary replays stale JSONL into a populated database and downgrades a newer row. 2. With the packaged patch, the identical harness preserves the newer row and emits no implicit import on the unrelated mutation. 3. A genuinely empty server database with a tracked JSONL still bootstraps successfully; embedded mode retains its atomic emptiness check. 4. The patched package builds, is activated on the live host, and its wrapped Go binary matches the separately tested build. 5. Polylogue’s live database count and the 29 corrective design rows match the exported branch state after an unrelated patched invocation. 6. The generalized monotonic-import/receipt/concurrent-bootstrap requirements remain durable on polylogue-gxjh.1.","notes":"\n\nREPRODUCTION 2026-07-13: corrective PR #2830/c2948bc merged 29 standalone design rows. The next lane-bookkeeping export ee32d4011 replaced all 29 exactly with their c2948bc^ values; none had a legitimate overlapping edit. This proves the loss mode is not hypothetical and that git merge success alone does not synchronize the hot live database. Repair restores the 29 rows, targeted-imports them, and exports immediately; retain these commits as the regression fixture.\nFIX RECEIPT 2026-07-13: unpatched real-server harness reverted 'newer database title' to 'original old title'; patched harness preserved the newer value. Sinnix package build and live switch succeeded (nh activation hit a dbus reload failure, exact-toplevel fallback completed with exit 0). Published on sinnix master as fd47118. The final inherited-old-binary diagnostic replay was audited through Dolt history: relative to the immediately preceding real update it changed no semantic issue fields; only rxdo.5 content_hash churned. No unrecoverable row loss occurred.","status":"closed","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:42:13Z","created_by":"Sinity","updated_at":"2026-07-13T07:35:58Z","closed_at":"2026-07-13T07:35:58Z","close_reason":"Root incident fixed, deployed, and falsified by a real server-mode stale-snapshot harness. Beads 1.0.4 reverted the control row; Sinnix fd47118's packaged emptiness guard preserved it. Live Dolt history and all 29 corrective rows were audited after activation. Broader monotonic synchronization hardening continues on gxjh.1.","labels":["area:ops"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-ra3w","title":"[bug] devtools test basetemp escapes to host /tmp from worktrees","description":"Evidence 2026-07-13 fanout: three independent lanes (write-model, beads-ingest, provider-origin) reported devtools test using /tmp/polylogue-pytest despite the repo default of /realm/tmp/polylogue-pytest; host /tmp (6G tmpfs) hit 94-100% twice, failing verify runs mid-fanout ('shared /tmp exhaustion during page rendering', 'host-only /tmp exhaustion', provider-origin lane: 'devtools test used its configured /tmp/polylogue-pytest basetemp despite the requested /realm/tmp location'). Root-cause the basetemp resolution path for worktree checkouts (env not inherited? per-checkout config missing outside main checkout?) and make the /realm/tmp default hold in ANY checkout. AC: devtools test from a fresh worktree writes pytest temp under /realm/tmp; a regression covers the worktree case; fanout lanes no longer fill host /tmp.","notes":"2026-07-13: Reproduced in fresh linked worktree. The local agent environment inherited the cloud-only `POLYLOGUE_PYTEST_BASETEMP_ROOT=/tmp/polylogue-pytest`; `devtools test` copied it unchanged, so tests/conftest selected /tmp instead of its /realm fallback. Implemented shared normalization for focused and verify subprocess environments: on a host with /realm/tmp, only that known cloud default rewrites to /realm/tmp/polylogue-pytest; arbitrary explicit roots remain unchanged and cloud hosts without /realm keep /tmp. Regression exercises the assembled devtools child environment. Verification: focused runner printed /realm/tmp/...; target run had 72 passed and one unrelated stale expected-command-list failure, rerun exact node confirmed it; ruff, mypy, and devtools verify --quick passed.\nPR #2815 merged (supplementary, ra3w already closed via #2807): basetemp resolution anchored to the workspace scratch root independent of checkout kind, with a regression covering the specific linked-worktree escape case that #2807 missed (three fanout lanes had observed /tmp/polylogue-pytest despite the /realm/tmp default, filling the 6G host tmpfs to 94-100% twice on 2026-07-13).","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:42:08Z","created_by":"Sinity","updated_at":"2026-07-13T02:20:46Z","started_at":"2026-07-12T23:50:28Z","closed_at":"2026-07-13T00:56:27Z","close_reason":"PR #2807 merged: managed pytest basetemps normalized to /realm/tmp/polylogue-pytest when a fresh worktree inherits the cloud-sandbox /tmp default, covering both focused-test and broad-verify subprocess environment construction paths","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-9e5.8.8","title":"provider->origin Step 3b: storage/repository flip","description":"Middle slice: SessionRepository mixins (archive/{queries,search}, insight/{profile_reads,timeline_reads,summary_reads}, raw/repository_raw) rename provider->origin keywords, passing origin tokens natively to the 3c layer. Depends on Step 3c (polylogue-9e5.8.5); blocks Step 3a (polylogue-9e5.8.6).","acceptance_criteria":"1. Every SessionRepository archive, search, insight, and raw mixin accepts canonical `origin`/`origins` parameters and passes origin tokens to the SQL/DTO layer without a provider round-trip. 2. No internal `provider` keyword alias or translation helper is introduced; provider-wire vocabulary remains only at declared source/schema/billing boundaries. 3. Mypy and focused repository/API parity tests cover single-origin, multi-origin, absent-filter, and invalid-origin cases. 4. The provider-origin census records the before/after sites and shows no new public provider leakage.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:31:09Z","created_by":"Sinity","updated_at":"2026-07-13T07:33:23Z","closed_at":"2026-07-13T07:24:59Z","close_reason":"Step 3b shipped in PR #2820 (merge cc0999bef): repository mixins pass origin filters straight to storage queries (commit 114725954); no provider round-trip remains in the closed internal caller graph; retrieval/search legs pass _canonical_origins.","labels":["area:audit","delivery:A-trust-floor","horizon:mid","lane:agent-write-safety","refactor"],"dependencies":[{"issue_id":"polylogue-9e5.8.8","depends_on_id":"polylogue-9e5.8","type":"parent-child","created_at":"2026-07-13T01:31:09Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-9e5.8.8","depends_on_id":"polylogue-9e5.8.5","type":"blocks","created_at":"2026-07-13T01:31:09Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-9e5.8.6","title":"provider->origin Step 3a: protocols.py + api contract flip","description":"Top slice, lands LAST: protocols.py (SessionReader.list/list_summaries/count, SearchStore.search*, SessionQueryRuntimeStore.search_actions) + api/archive.py (~20 sites) + api/insights.py (aggregate_sessions, workflow_shape_distribution - the adversarial reviewers' concrete finding). Public Python API accepts origin= natively; delete the 4 ad hoc conversion sites (api/archive.py _archive_origin_for_provider/_provider_for_archive_origin, insights/tag_rollups.py:49 detour, cli/read_views/neighbors.py:71).","acceptance_criteria":"1. SessionReader, SearchStore, SessionQueryRuntimeStore, and the public Python API expose `origin`/`origins` natively; the old internal provider keywords fail rather than becoming permanent aliases. 2. `_archive_origin_for_provider`, `_provider_for_archive_origin`, and the named tag-rollup/neighbors detours are deleted after all callers move. 3. Origin filtering and aggregate/workflow-shape routes pass parity fixtures with unchanged public JSON shapes. 4. Billing/embedding provider vocabulary remains explicitly exempt and no source-origin surface regresses in the provider-vocabulary census. 5. The branch-tip `devtools verify` gate and focused API/protocol tests pass.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:30:43Z","created_by":"Sinity","updated_at":"2026-07-13T07:33:24Z","closed_at":"2026-07-13T07:25:06Z","close_reason":"Step 3a shipped in PR #2820 (merge cc0999bef): protocols + Python API contract flipped to origin=/origins= keywords (commit 2a686c26f, breaking pre-1.0 rename per no-compat-pre-adoption directive); MCP insight tools pass origin tokens natively; tool-usage/tag-rollup/coverage insight paths accept Origin fail-closed.","labels":["area:audit","delivery:A-trust-floor","horizon:mid","lane:agent-write-safety","refactor"],"dependencies":[{"issue_id":"polylogue-9e5.8.6","depends_on_id":"polylogue-9e5.8","type":"parent-child","created_at":"2026-07-13T01:30:42Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-9e5.8.6","depends_on_id":"polylogue-9e5.8.8","type":"blocks","created_at":"2026-07-13T01:31:31Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-9e5.8.5","title":"provider->origin Step 3c: SQL/DTO layer accepts origin natively","description":"Bottom-most slice of the Axis-2 contract flip (execute FIRST of 3c/3b/3a - bottom-up so no caller ever passes a keyword a lower layer does not accept yet). Rename provider->origin, providers->origins in storage/sqlite/queries/** (sessions_reads, sessions_search, filter_builder, raw_reads, raw_state, attachment_records, stats, session_latency_profile_reads), storage/sqlite/{query_store*,async_sqlite_*}, storage/sqlite/archive_tiers/archive.py (~20 sites), storage/query_models.py (SessionRecordQuery et al). filter_builder.py drops the Provider.from_string+origin_from_provider round-trip for Origin(value) directly. mypy --strict is the net. Golden/parity fixture: public JSON payload shape unchanged. SEQUENCING: wait for origin-interop lane PR to merge (shared archive_tiers/raw files).","acceptance_criteria":"1. The coordinated 3c/3b/3a sweep leaves SQL query builders, query models, archive tiers, repositories, protocols, and API callers using canonical `origin`/`origins` names and values. 2. Provider-wire tokens are normalized exactly once at raw acquisition/schema boundaries; arbitrary or legacy provider tokens do not leak into origin-only layers. 3. Passing both vocabularies is impossible because no internal compatibility aliases remain. 4. Golden SQL/DTO and surface parity fixtures cover every migrated query family, including raw state and aggregate insights. 5. Mypy is green and the provider-origin census records the remaining sites with an explicit legitimate-boundary classification.","notes":"COORDINATOR DECISION 2026-07-13 (transition rule for the mypy sequencing gap the lane found): 3c is ADDITIVE dual-vocabulary, not a literal rename and not scope expansion into 3b files. Every 3c surface (SessionRecordQuery + query functions/mixins) gains origin=/origins= as the CANONICAL parameters while RETAINING provider=/providers= as accepted legacy keywords (normalize internally to origin; raise ValueError if both vocabularies are passed for the same axis). Internal layer: no DeprecationWarning spam. 3b then flips all callers to origin=; the legacy keyword REMOVAL from 3c is an explicit AC added to Step 4 (polylogue-9e5.8.9) so the aliases cannot silently become permanent. Rationale: keeps every commit mypy-green, preserves the reviewable package boundary, mirrors the deprecated-alias pattern the lane already shipped for CLI flags in #2806.\nDECISION SUPERSEDED 2026-07-13 (operator challenged the dual-vocabulary rule — correctly): NO legacy provider=/providers= acceptance in 3c. Internal layers have a closed caller set and mypy --strict as the net; transitional aliases there are deprecation theater. NEW RULE: execute 3c+3b+3a as ONE atomic mechanical sweep on one branch — rename provider->origin / providers->origins keyword AND accepted-value vocabulary through storage/sqlite/queries/** + query_models + repository mixins + protocols.py + api/*.py in a single coordinated change; commit per layer as review waypoints (each commit need not be independently mypy-green; the branch tip must be); one PR covering 9e5.8.5+9e5.8.8+9e5.8.6. Aliases remain ONLY on genuinely public surfaces (CLI flags, already shipped in #2806). Python-API kwarg change is breaking-pre-1.0: flag it in the PR body for the changelog. Step 4 (9e5.8.9) reverts to its original scope: shim deletion only, no alias-removal AC.\n2026-07-13 merge-conductor: PR #2820 (this bead's implementation) has a real regression, held unmerged. origin_filter_value() in polylogue/storage/sqlite/queries/raw_state.py was tightened from provider-token-tolerant (origin_from_provider(Provider.from_string(token))) to strict Origin(token) validation, but ~15+ real callers (raw-session filters, insights, CLI status, benchmarks, SQL-injection fuzz tests) still pass provider-wire tokens (\"chatgpt\", \"claude-ai\", \"gemini\") or arbitrary strings through this path. Focused test run: 56 failed, 588 passed. Full evidence + repro in PR #2820 comment. Needs either provider-token fallback restored in origin_filter_value, or the remaining call sites migrated to pass true origin values before merge.\n2026-07-13: PR #2820 follow-up 576d53aa7 fixes raw origin_filter_value at the raw Provider-wire boundary and removes remaining provider-to-origin reverse translations in SQL/DTO, sync API, and MCP insight routes. Focused real-route suite: 8 passed; devtools verify --quick passed. Census now 106 sites (previous branch 109; pre-sweep 239). Testmon seed is running separately under the managed harness. AC status: in-scope 3c SQL/DTO origin transition satisfied; no aliases were added outside raw-wire normalization.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:30:38Z","created_by":"Sinity","updated_at":"2026-07-13T07:33:24Z","closed_at":"2026-07-13T07:21:07Z","close_reason":"Step 3c shipped in PR #2820 (merge cc0999bef): SQL/DTO layer accepts origin natively — filter values validated fail-closed with Origin(value) at the SQL boundary, s.origin AS source_name projections, filter_builder on origin tokens. Census 239 to 108 sites; regression test pins cross-origin FTS exclusion against real seeded index.db.","labels":["area:audit","delivery:A-trust-floor","horizon:mid","lane:agent-write-safety","refactor"],"dependencies":[{"issue_id":"polylogue-9e5.8.5","depends_on_id":"polylogue-9e5.8","type":"parent-child","created_at":"2026-07-13T01:30:37Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-9e5.8.4","title":"provider->origin Step 2: rename literal public tokens (CLI flags + HTTP scope key)","description":"Rename --schema-provider/--artifact-provider flag NAMES in cli/shared/check_options.py:57-66 to --schema-origin/--artifact-origin (old names kept as deprecated aliases one release), and daemon/http.py:520-529 _SCOPE_FILTER_KEYS 'provider' -> 'origin' (verify daemon/route_contracts.py consumers first; browser extension does not send it). EXCLUDES /api/provider-usage + provider_usage_report (billing vocabulary, permanently exempt per 9e5.8 Axis-2 exclusion 3). Coordinate with polylogue-jnj.7 (help-text-only scope) - both touch check_options.py region. SEQUENCING: daemon/http.py part only after PR #2793 (web-cockpit) merges - shared file. Verify: census literal-category count drops; render cli-reference regenerated; focused CLI tests.","design":"POST-#2820 CONTEXT (2026-07-13): internal layers are now origin-native (SQL/DTO/repository/protocols/API all flipped, census 239->108); this bead is the PUBLIC-LITERAL remnant. Hard rename, NO aliases (operator directive in notes: pre-adoption there is no compatibility surface).\nFILES: cli/shared/check_options.py:57-66 --schema-provider/--artifact-provider -> --schema-origin/--artifact-origin (values already origin tokens); daemon/http.py:520-529 _SCOPE_FILTER_KEYS 'provider' -> 'origin' -- read daemon/route_contracts.py consumers FIRST and update the route contract in the same commit. PR #2806 landed WITH deprecated aliases and must be amended: remove the alias params entirely, tests prove old flag names fail with an actionable did-you-mean-origin hint.\nPITFALLS: new Click params go LAST on query verbs (positional-shift reroute); regenerate cli-reference + openapi (devtools render all); overlaps polylogue-jnj.7 (CLI help provider-wording leakage) -- fix help text in the same sweep, cite both beads.\nVERIFY: devtools test on check_options/daemon-http contract tests + devtools lab census provider-vocabulary --json (literal count should drop; record delta in PR body).","acceptance_criteria":"1. CLI exposes only `--schema-origin` and `--artifact-origin`; the rejected provider-named aliases are removed and tests prove they fail with an actionable origin hint. 2. Daemon scope filters accept `origin` and reject source-origin `provider`, while `/api/provider-usage` remains unchanged as billing vocabulary. 3. Browser/route consumers are audited before the HTTP key change and focused contract tests prove no silent filter drop. 4. CLI reference and output schemas are regenerated, and the literal-category census drops by the expected sites.","notes":"OPERATOR TIGHTENING 2026-07-13: NO deprecated aliases even on CLI flags — 'literally no one uses this yet.' PR #2806 must be amended: --schema-provider/--artifact-provider aliases REMOVED, clean rename only. General principle for the whole 9e5.8 chain: pre-adoption there is no compatibility surface anywhere; hard renames throughout.\nPR #2806 merged (CLI flags satisfied): --schema-origin/--artifact-origin repeatable flags added to ops doctor with canonical origin-worded validation/help; --schema-provider/--artifact-provider retained as visible deprecated Click aliases with warnings naming the legacy flag. devtools lab census provider-vocabulary literal sites 15->13, unallowlisted candidates 12->10. DEFERRED (not closing): the daemon/http.py scope-key portion was intentionally deferred until PR #2793 merged — #2793 IS now merged (web-cockpit), so this deferred slice is now unblocked but still NOT implemented by this PR.\n[2026-07-14 execution] Implemented the remaining Step-2 scope in PR #2870 (branch feature/refactor/provider-origin-step2-codex-actions): hard-removed --schema-provider/--artifact-provider CLI aliases (DeprecatedAliasOption class deleted entirely, no compat surface per operator directive), flipped daemon/http.py _SCOPE_FILTER_KEYS \"provider\"->\"origin\" (verified route_contracts.py has no per-field schema and webui/browser-extension send no provider scope key -- safe hard flip, no alias), and renamed MaintenanceScopeFilter.provider->.origin (was storing a provider_from_origin()-converted token; now stores the origin token directly, matching every other public surface). Confirmed via replay.py/repair.py reading that this field is advisory-only today (no repair target honors it besides session_ids), so the rename is behavior-preserving for repair execution. cli/commands/maintenance.py + mcp/server_maintenance_tools.py scope-filter builders updated to pass origin straight through (Origin(...) validation preserved, only the provider round-trip dropped).\nCensus: devtools lab census provider-vocabulary --json unallowlisted sites 100->96 (literal 13->11, field 26->25, key 23->22), diffed against fresh origin/master.\nVerification: devtools test on 7 maintenance/CLI test files -> 163 passed; devtools test daemon+mcp maintenance -> 13 passed; devtools verify --quick -> 15/15 exit 0 (also re-run by pre-push hook); devtools render all --check -> all sync OK.\nNoted pre-existing (not caused by this branch) drift in tests/unit/cli/test_terminal_snapshots.py (--no-daemon flag + verbose-help wording) -- confirmed red on fresh origin/master before this branch, left untouched, out of scope.\nPR: https://github.com/Sinity/polylogue/pull/2870","status":"open","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T23:30:33Z","created_by":"Sinity","updated_at":"2026-07-14T00:16:56Z","labels":["area:audit","delivery:A-trust-floor","horizon:mid","lane:agent-write-safety","refactor"],"dependencies":[{"issue_id":"polylogue-9e5.8.4","depends_on_id":"polylogue-9e5.8","type":"parent-child","created_at":"2026-07-13T01:30:32Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-dsfr","title":"Switch beads workspace from embedded Dolt to sql-server mode","description":"Evidence (2026-07-12 fanout): dolt_mode=embedded serializes every bd invocation on .beads/embeddeddolt/.lock. Under a 16-lane agent fanout the queue ran 15 deep; head 'bd show' blocked 13+ minutes; UserPromptSubmit hooks (bd prime) hung interactive sessions indefinitely. Uncontended bd show = 2.3s, so this is pure lock convoy, not slow queries.\n\nbd's intended concurrent design is a per-project dolt sql-server ('auto-started transparently when needed'; PID/logs in .beads/; port derived from project path). This workspace is pinned embedded via .beads/metadata.json (dolt_mode=embedded, set ~2026-07-03).\n\nPlan (quiet window only — NOT while lanes are running):\n1. bd backup first.\n2. Determine migration path embedded->server: server default data-dir is .beads/dolt vs embedded .beads/embeddeddolt — check whether bd migrates automatically on mode flip or needs data-dir pointed at existing embeddeddolt (bd dolt set data-dir). Consult beads upstream docs/issues for the supported flip.\n3. Flip mode, bd dolt start, bd dolt test, then verify: bd show/list/create/close round-trip + concurrent hammer test (10 parallel bd show) to confirm no lock convoy.\n4. Verify worktree lanes resolve to the same server (bd context from a worktree).\n5. Update .agent docs + sinnix fanout notes: hooks timeout guards (sinnix f22c0d7) stay as defense-in-depth.\n\nAC: 10 parallel 'bd show' all complete <5s; bd prime under parallel load <10s; no embedded .lock contention; data intact (bd count before == after).","acceptance_criteria":"1. Before/after issue counts match for Polylogue and every migrated sibling workspace. 2. Ten parallel `bd show` commands complete under five seconds total and `bd prime` completes under ten seconds without an embedded lock convoy. 3. Main checkout and linked worktree report the same server/database/project identity and observe the same sentinel mutation. 4. The pre-migration database has a verified recoverable backup and the obsolete embedded store is removed only after soak. 5. The server-mode auto-import defect is tracked and resolved by polylogue-gxjh before this migration is treated as fully safe.","notes":"Recipe VERIFIED 2026-07-13 on sinnix/lynchpin/sinex (counts 82/8/343 intact, servers running):\n1. cd ; before=$(bd count); cp -a --reflink=auto .beads/embeddeddolt /realm/tmp/beads-backup--\n2. Edit .beads/metadata.json: dolt_mode embedded->server\n3. mkdir -p .beads/dolt && cp -a --reflink=auto .beads/embeddeddolt/ .beads/dolt/ && rm -f .beads/dolt//.dolt/noms/LOCK\n4. bd dolt start; bd count == before; hammer: 10 parallel bd show all <100ms\n5. rm -rf .beads/embeddeddolt after soak (backups under /realm/tmp/beads-backup-*)\nMeasured: server-mode bd show 65ms vs embedded 2.3s (35x solo); 10-parallel completes in 61ms (embedded convoyed 13+ min under fanout).\nPrereq shipped: sinnix f22c0d7 (hook timeouts) + beads-with-dolt wrapper (dolt on bd PATH; needs switch, or run under nix shell nixpkgs#dolt).\nPOLYLOGUE CONSTRAINT: flip ONLY in a quiet window — in-flight embedded writers (lane bd calls, pre-commit bd export) write embeddeddolt and would be silently lost by the copy. Verify zero bd processes first: pgrep -af \"bd \" | grep -v dolt.\nMigration executed for ALL FOUR repos 2026-07-13 (sinnix/lynchpin/sinex/polylogue; counts 82/8/343/713 verified; hammer tests <100ms for 10 parallel). REMAINING DEFECT split to polylogue-gxjh: bd auto-imports the full jsonl on every invocation against the migrated polylogue server db ('empty database' misdetection) — costs seconds per call and races concurrent mutations (reverted writes observed). Until gxjh lands: sequence bd writes and run explicit bd export between mutations.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T21:53:46Z","created_by":"Sinity","updated_at":"2026-07-13T07:35:58Z","closed_at":"2026-07-13T07:35:58Z","close_reason":"All four workspaces are migrated to sql-server mode with counts and parallel latency verified; the remaining destructive auto-import defect was fixed and deployed under gxjh/sinnix fd47118. General import hardening is separately durable on gxjh.1.","labels":["area:ops"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-06zm","title":"Backfill job ledger must survive private-profile re-seed","description":"Live incident 2026-07-12: earlyoom killed the agent-private Chrome during memory pressure; the profile restart RE-SEEDED the private profile, erasing the extension IndexedDB backfill job ledgers (#2771 durable-jobs design assumed profile persistence). Authenticated jobs had to be restarted from scratch. The durable job ledger (checkpoints, leases, request budgets, incident records) needs a home that survives profile re-seed: mirror to the loopback receiver/ops.db as source of truth with IndexedDB as cache, or persist the profile dir across re-seeds.","acceptance_criteria":"1. A backfill job created in an authenticated private profile is visible through a receiver-owned durable ledger with checkpoint, lease, request budget, and incident history. 2. Killing and re-seeding the entire browser profile does not lose the job; reinstall/reconnect resumes from the last acknowledged checkpoint without replaying completed pages. 3. IndexedDB is demonstrably a cache: deleting it leaves the receiver ledger authoritative. 4. Lease expiry and duplicate reconnects are idempotent, and an incompatible job version fails visibly rather than starting over. 5. A profile-reseed integration fixture exercises the real extension-to-loopback route.","notes":"2026-07-14: implemented PARTIAL scope in PR #2871 (branch feature/browser-ext/checkpoint-mirror-and-message-layer). Shipped: new POST/GET /v1/backfill-checkpoint routes on the local receiver (polylogue/browser_capture/{models,receiver,route_contracts,server}.py) -- one JSON file per extension_instance_id, last-write-wins, same write-lock/quota pattern as the existing capture spool and post-command queue; receiver treats the checkpoint body as opaque JSON (same trust boundary as the capture-envelope route). Extension side (background.js): mirrors every checkpoint persist to the receiver, decoupled from the local chrome.storage.local write so a receiver outage never surfaces as a checkpoint error; on coordinator construction, if both IndexedDB and the local checkpoint copy are empty, falls back to GET-ing the receiver's mirrored checkpoint and restoring from it.\n\nAC status: AC1 (receiver-owned durable ledger visible) satisfied. AC2/AC3 (profile loss doesn't lose the job; IndexedDB+local-copy demonstrably not the only durable source) satisfied for the case where IndexedDB AND the local chrome.storage.local copy are BOTH lost but the extension_instance_id itself survives. AC4 (idempotent duplicate reconnects) satisfied via the pre-existing restoreRecoveryCheckpoint empty-IndexedDB guard. AC5 (integration fixture) satisfied at the Python HTTP-route level (real server, real POST+GET round trip, tests/unit/browser_capture/test_backfill_checkpoint.py, 12/12 passing) and the JS level (background.test.js, 4 new cases); NOT a true extension-to-daemon browser E2E fixture (no live browser in this environment).\n\nEXPLICITLY NOT DONE (do not close on this evidence alone): a whole-profile wipe that ALSO destroys extension_instance_id (which lives in the same chrome.storage.local) cannot self-correlate to its old mirrored checkpoint on the receiver -- there is no operator-facing \"adopt an orphaned checkpoint by browsing the receiver's stored instances\" flow. That is real, separate follow-up work. Verification: devtools test tests/unit/browser_capture/test_backfill_checkpoint.py (12/12), devtools test tests/unit/browser_capture/ (101/101, no regression), devtools verify --quick (15/15), npx vitest run (236/236 browser-extension suite). See PR #2871 for full detail.\n2026-07-14 fix round (reviewer pass on PR #2871): fixed reviewer-confirmed MAJOR finding -- BrowserBackfillCheckpointRequest.coerce_checkpoint (and the twin validator on BrowserBackfillCheckpointRecord) used json_document(value), which silently coerced any non-dict checkpoint (string/null/list/number) to {} instead of rejecting it, so a malformed POST to /v1/backfill-checkpoint returned HTTP 202 success while overwriting a previously-good stored checkpoint with an empty one -- directly undermining this bead's durable-ledger AC1. Renamed both validators to require_checkpoint_document and made them raise ValueError (-> pydantic ValidationError -> HTTP 400 invalid_backfill_checkpoint via the server's existing except ValidationError handler) for any non-dict value, matching the module's own require_json_document convention used elsewhere for producer-contract enforcement. Also fixed the read-path twin so a corrupted on-disk checkpoint file surfaces as read_backfill_checkpoint()->None (no checkpoint found) rather than a fabricated empty-but-'valid' checkpoint. Added 7 regression tests in tests/unit/browser_capture/test_backfill_checkpoint.py: non-dict rejection on both Request and Record (parametrized over string/None/int/list), corrupted-file-on-disk reads as None, a prior-good checkpoint is NOT overwritten by a malformed follow-up write, and the exact HTTP-level reviewer repro (POST checkpoint='garbage-not-a-dict' -> 400, prior good checkpoint on disk unchanged). Verification: devtools test tests/unit/browser_capture/test_backfill_checkpoint.py (23/23), devtools test tests/unit/browser_capture/ (112/112, no regression), devtools verify --quick (15/15 steps green). Reviewer's two minor/non-blocking findings (quota not re-checked on same-instance overwrite growth; no GC for orphaned per-instance checkpoints after a profile reseed mints a new instance id) filed as follow-up polylogue-yky4 rather than fixed here -- both need a real design decision, not a mechanical fix. See PR #2871 for the updated diff.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:47:43Z","created_by":"Sinity","updated_at":"2026-07-14T01:27:17Z","labels":["area:capture","delivery:B-storage-rebuild-bytes","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jlme.4","title":"Preserve backfill ledgers across controlled browser recovery","description":"During the 2026-07-12 live backfill, earlyoom killed the private-visible Chrome. MV3 IndexedDB would normally survive a browser restart, but the control-plane private-start helper automatically re-seeded the profile from live Chrome and erased the extension-origin IndexedDB, including the cancelled incident ledger and running checkpoints. Browser recovery must not silently turn a durable backfill ledger into an empty database.","design":"Coordinate with the Sinnix browser control plane so restart and re-seed are separate explicit operations: an existing private profile restart must preserve extension origins by default, while profile replacement requires a stated destructive action and backup/restore of extension-owned backfill state. Add a compact export/checkpoint path (receiver-side or profile backup) sufficient to restore job/control/queue/revision/ACK ledgers without persisting provider credentials. On startup, detect unexpected instance/database loss and surface recovery evidence rather than reporting No jobs yet.","acceptance_criteria":"1. Kill and restart the private browser process without re-seeding; the same running job ID, cursor, queue, revisions, and last ACK recover and continue without duplicate receiver writes. 2. A deliberate profile re-seed either restores the checkpointed ledger or blocks with an explicit destructive warning; it never silently reports an empty job set. 3. No cookies, provider auth headers, account IDs, or page credentials enter the checkpoint. 4. A control-plane smoke exercises restart versus re-seed semantics and a packaged extension smoke proves recovered alarm execution.","notes":"2026-07-13 implementation: extension PR in progress. Scope/AC: real IndexedDB restart retains job/cursor/queue/revision/ACK and recovered alarms; a credential-free checkpoint detects profile loss as browser_profile_recovery_required rather than empty state. Linked polylogue-jlme.4.1 owns required Sinnix restart-vs-destructive-reseed helper semantics.\n2026-07-14 verification pass: this bead is ALREADY DONE, not in-progress. Same merged PR #2819 (commit 4c3eb375b) implements this bead's AC: exportRecoveryCheckpoint/restoreRecoveryCheckpoint in browser-extension/src/backfill/storage.js persist/restore job/queue/revision state to chrome.storage.local (credential-free, provider_options/envelope/receiver_receipt/lease fields stripped); recoveryRequiredItem/recoveryCheckpointJob mark unexpected loss as browser_profile_recovery_required (paused, actionable) instead of silently reporting empty; performControl() refuses \"resume\" while any queue item is recovery_required. Companion Sinnix-side restart-vs-reseed semantics (jlme.4.1) also confirmed merged (see that bead's notes). Verified on origin/master. Notes were stale. No new code needed for the AC as originally scoped. Note: PR #2871 (this session) additionally ships a genuinely NEW increment beyond this bead's original AC -- mirroring the checkpoint to the local receiver (polylogue-06zm) as a second fallback for when the local chrome.storage.local copy is ALSO lost (full profile wipe/reinstall, not just IndexedDB loss) -- tracked on 06zm, not this bead. Recommend closing jlme.4 with reason citing PR #2819/commit 4c3eb375b.","status":"in_progress","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:47:00Z","created_by":"Sinity","updated_at":"2026-07-14T00:28:47Z","started_at":"2026-07-13T01:13:35Z","labels":["area:ingest","area:web","delivery:G-live-performance","lane:capture-reliability","spine"],"dependencies":[{"issue_id":"polylogue-jlme.4","depends_on_id":"polylogue-jlme","type":"parent-child","created_at":"2026-07-12T22:46:59Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jlme.4","depends_on_id":"polylogue-jlme.2","type":"discovered-from","created_at":"2026-07-12T22:47:01Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jlme.3","title":"Fail visibly on stale browser-capture receiver contracts","description":"Live deployment on 2026-07-12 paired the merged extension with a stale local receiver ACK schema. The receiver accepted and durably wrote every payload (HTTP 202) but omitted content_hash, so the coordinator classified receiver_ack_hash_mismatch as receiver_down and repeatedly retried. The extension must distinguish an unavailable receiver from a reachable but incompatible receiver contract before it burns retries or creates misleading health state.","design":"Add a receiver capability/schema preflight for backfill starts and re-check after service-worker restart. Require the durable ACK fields used by the coordinator, including receiver_request_id and exact-byte content_hash. Missing/incompatible fields pause the provider job with receiver_contract_incompatible and an operator-facing upgrade action; do not consume the ordinary receiver-down retry budget or repost the same accepted capture. Compatible receivers retain exact-byte hash verification and drain persisted envelopes idempotently.","acceptance_criteria":"1. A real-route fixture with HTTP 202 but no content_hash pauses once as receiver_contract_incompatible and makes no repeated provider/receiver calls before operator action. 2. Popup status names the receiver contract problem and upgrade/restart action distinctly from receiver_down. 3. After a compatible receiver is available, explicit resume drains the persisted envelope and records an exact-byte ACK without refetching provider content. 4. Packaged service-worker proof covers the preflight and stale-ACK path.","notes":"2026-07-13 implementation: extension PR in progress. Scope/AC: durable receiver preflight; HTTP 202 without receiver_request_id/content_hash pauses once as receiver_contract_incompatible with no retry consumption or repost; compatible explicit resume drains persisted envelope exactly once. Popup and packaged-worker proof included.\n2026-07-14 verification pass: this bead is ALREADY DONE, not in-progress. Merged PR #2819 (commit 4c3eb375b, \"fix(browser): preserve backfill receiver and recovery contracts\", merged 2026-07-13T01:49:09Z) fully implements this bead's AC: receiver capability preflight (ensureReceiverContract/preflightReceiverContract in coordinator.js), durable-ack-field validation (receiverAckContractError, DURABLE_RECEIVER_ACK_FIELDS in models.js), receiver_contract_incompatible pause distinct from receiver_down (does not consume retry budget or repost), and explicit-resume drain of persisted envelopes. Verified this is on origin/master and the code is live in browser-extension/src/backfill/coordinator.js. Notes were stale (written 2026-07-13T01:12 before the PR merged same day). No new code needed. See PR #2871 body for the full cluster investigation. Recommend closing with reason citing PR #2819/commit 4c3eb375b.","status":"in_progress","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:46:42Z","created_by":"Sinity","updated_at":"2026-07-14T00:28:26Z","started_at":"2026-07-13T01:12:58Z","labels":["area:ingest","area:web","delivery:G-live-performance","lane:capture-reliability","spine"],"dependencies":[{"issue_id":"polylogue-jlme.3","depends_on_id":"polylogue-jlme","type":"parent-child","created_at":"2026-07-12T22:46:41Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jlme.3","depends_on_id":"polylogue-jlme.2","type":"discovered-from","created_at":"2026-07-12T22:46:43Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-hg8n","title":"Outside adoption v1: first external user of Polylogue","description":"Nothing currently owns the goal the legibility work serves: one real external person installs Polylogue, runs the first proof, and gets value. Children/related: y8s5 distribution, 67ac measured-result receipts, extension store packaging, install matrix, the README tour. Exit: a cold outsider completes install -> demo receipts -> one query against their own data, evidenced by their session or report, without operator assistance.","design":"Run outside adoption as a two-part path. Install: publish and verify PyPI, Homebrew, and Nix entry points in clean environments. Activation: a cold outsider runs a flagship audit or continuity demo, then applies the same flow to one query over their own archive. AI-D1/AI-D3/AI-D9 are the named show-someone artifacts; polylogue-3tl.16 renders public claims as a view over findings and evidence rather than creating a second ledger. Preserve the session or report as the adoption receipt and feed observed friction back to the owning distribution/demo/documentation Beads.\n\n## Authoritative corrective contract (2026-07-13)\n\nActivation proves both product wedges before the terminal cold-user run. Audit uses the claims view\nplus a minimal verified cold-reader evidence export. Continuity uses AI-D3 prior observed recovery\ncandidates first; PF-D8 actual resume follows once compatibility is mature. New platform work declares\nconsumer_proof, while receipts from already-observed operator flows remain valid internal proof.","acceptance_criteria":"1. Clean-environment receipts exist for the supported PyPI, Homebrew, and Nix install paths. 2. One person outside the project completes install, a flagship demo, and one query over their own data without operator assistance. 3. Their session or report records completion, elapsed effort, and every blocking or confusing step. 4. Public claims shown during the flow resolve through polylogue-3tl.16 to explicit evidence status. 5. Remaining friction is recorded on an owning Bead rather than left only in the adoption report.\n\n## Corrective acceptance criteria (2026-07-13)\n\nBefore the cold-user receipt, the audit slice exports a claim/evidence artifact that a no-context\nreader can verify, and AI-D3 runs on an independent archive with measured precision and honest recovery-\ncandidate naming. The external user installs unaided, completes AI-D3 first, runs one own-data query,\nand can inspect claim support through the verified export. PF-D8 remains the stronger subsequent proof,\nnot a prerequisite for first activation.","notes":"UNBLOCKED 2026-07-13 (rewrite: the first session write did not persist): PyPI 0.2.0 is live, the Homebrew tap is live, and the Nix flake exists, so the install half is done. Activation content is named: flagship demos rxdo.10.1-.3, with polylogue-3tl.16 as a claims-ledger view over findings. Remaining epic scope: choose the first external-user candidate and run the full loop. The external review's two-wedge framing is audit ('what supports this claim?') plus continuity ('have I resolved this before?'); new platform investment should strengthen one of those wedges.","status":"open","priority":1,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:34:06Z","created_by":"Sinity","updated_at":"2026-07-13T07:00:18Z","metadata":{"consumer_proof":"external-audit,external-continuity"},"labels":["area:legibility","delivery:L-external-legibility","horizon:frontier","lane:docs-demos-launch"],"dependencies":[{"issue_id":"polylogue-hg8n","depends_on_id":"polylogue-3tl.16","type":"related","created_at":"2026-07-13T07:04:39Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-hg8n","depends_on_id":"polylogue-67ac","type":"related","created_at":"2026-07-13T07:04:39Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-hg8n","depends_on_id":"polylogue-bby.15","type":"related","created_at":"2026-07-13T07:48:48Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-hg8n","depends_on_id":"polylogue-rxdo.10","type":"related","created_at":"2026-07-13T07:04:39Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-hg8n","depends_on_id":"polylogue-rxdo.10.2","type":"related","created_at":"2026-07-13T07:48:40Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-hg8n","depends_on_id":"polylogue-y8s5","type":"related","created_at":"2026-07-13T07:04:39Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-bj5h","title":"Selection -> assertion write flow with exact-message evidence ref","description":"Selection-triggered pill (Medium/Hypothesis pattern) -> minimal editor: kind note/claim/correction, body prefilled, evidence ref auto-attached to exact message. Lands as candidate assertion; judgment gate unchanged. Depends on agent-write role path (27p).","acceptance_criteria":"1. Selecting a message opens a minimal note/claim/correction editor with the body prefilled and a stable exact-message evidence ref attached. 2. Saving writes a candidate assertion with `inject:false`; selection cannot bypass judgment or policy authority. 3. Editing/canceling does not mutate transcript content, duplicate submissions are idempotent, and an unavailable message ref yields a visible degraded state. 4. Claude.ai and ChatGPT fixtures prove the selection-to-user-tier round trip and evidence resolver. 5. Keyboard and screen-reader operation are covered without layout shift.","notes":"2026-07-14: investigated as part of the browser-extension cluster (PR #2871) but DEFERRED, not attempted. Per explicit cluster-scoping guidance (\"fine to land ys30 solidly with full tests rather than four shallow half-implementations, say explicitly which of the four you completed vs deferred\"), effort was concentrated on ys30 (Layer 1, satisfied) and polylogue-06zm (receiver checkpoint mirror, partial) rather than spreading thin across bj5h/wvji too. No code changes made. Remains ready for a dedicated pass; the ys30 Shadow-DOM message-layer infrastructure this PR ships (browser-extension/src/content/message_layer.js) is a plausible foundation to extend for the selection-pill trigger, though bj5h's editor/evidence-ref/judgment-gate work is unstarted.","status":"open","priority":1,"issue_type":"feature","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:52Z","created_by":"Sinity","updated_at":"2026-07-14T00:29:53Z","labels":["area:capture","delivery:L-external-legibility","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-bj5h","depends_on_id":"polylogue-yyvg","type":"parent-child","created_at":"2026-07-12T22:24:01Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-wvji","title":"In-page Layer 2: corner chip + slide-over deep-dive","description":"Fixed corner chip (Alt+P, zero layout shift) -> 360px slide-over: capture state, session cost, top-K relevant judged assertions, canonical archive link. Boundary rule: per-message state blends (Layer 1); cross-conversation intelligence floats (this).","acceptance_criteria":"1. Alt+P and the fixed corner chip open a 360px slide-over without shifting or obscuring host conversation layout. 2. The panel resolves capture state, session cost with provenance, top-K judged assertions with trust labels, and the canonical archive link through daemon contracts rather than DOM guesses. 3. Offline, unknown-cost, uncaptured, and unauthorized states render explicitly and never as zero/success. 4. Focus trapping, escape/restore, keyboard navigation, and screen-reader labels pass accessibility tests on Claude.ai and ChatGPT fixtures. 5. No panel content can acquire instruction authority merely by being displayed.","notes":"2026-07-14: investigated as part of the browser-extension cluster (PR #2871) but DEFERRED, not attempted -- same reasoning as bj5h (see that bead's note). This is explicitly the OTHER layer from ys30 (Layer 2: cross-conversation intelligence/corner-chip/slide-over vs. ys30's Layer 1 per-message blend) and was named as the layer to defer in favor of landing ys30 solidly. No code changes made. Remains ready for a dedicated pass.","status":"open","priority":1,"issue_type":"feature","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:51Z","created_by":"Sinity","updated_at":"2026-07-14T00:29:59Z","labels":["area:capture","delivery:L-external-legibility","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-wvji","depends_on_id":"polylogue-yyvg","type":"parent-child","created_at":"2026-07-12T22:24:00Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-ys30","title":"In-page Layer 1: blended per-message capture dot + save action","description":"Shadow-DOM content script extends each host's existing per-message action row: capture-status dot + save-to-Polylogue action, matched to ~30px ghost icon size/style. Reads as native, zero layout shift. ChatGPT + Claude.ai first.","acceptance_criteria":"1. Claude.ai and ChatGPT per-message action rows receive a native-sized capture-status dot and save action through isolated Shadow DOM with zero measured layout shift. 2. Captured, pending, failed, unknown, and not-seen states are derived from receiver acknowledgements and remain distinguishable. 3. Save is idempotent and resolves to the exact message/block; retry after offline recovery cannot duplicate content. 4. Host DOM churn and unsupported layouts fail closed without breaking native controls. 5. Visual, keyboard, and accessibility fixtures cover both providers and light/dark themes.","notes":"2026-07-14: implemented in PR #2871 (branch feature/browser-ext/checkpoint-mirror-and-message-layer). New browser-extension/src/content/message_layer.js: a MutationObserver-driven module that mounts an isolated Shadow DOM badge (capture-status dot + save button) next to each detected ChatGPT/Claude.ai message container. Never touches native DOM/classes/listeners -- only appends the badge host, plus a non-destructive `position:relative` fallback when a container has no positioning context (needed so the badge's absolute positioning doesn't escape the container; never overwrites an existing position value). States: captured/pending/failed/unknown/not-seen. Save re-triggers the existing whole-session capture() -- there is no per-message receiver endpoint, the archive's capture unit is the session -- and every mounted badge reflects the outcome. Per-message identity is DOM ordinal position for the page's lifetime (matching the same ordinal the existing DOM-fallback capture path already uses); when the captured turn count and the mounted DOM node count disagree (branching, streaming, host redesign) every badge falls back to \"unknown\" rather than asserting a per-message status it can't verify -- fail closed. Wired into chatgpt.js/claude.js (mount + capture() reportOutcome calls) and all three places the extension injects content scripts: manifest.json, background.js injectionPlanForUrl, popup.js contentScriptFiles.\n\nAC status: AC1 (native-sized dot+save via isolated Shadow DOM, zero measured layout shift) satisfied structurally (jsdom asserts fixed sizing, additive-only DOM diff, no sibling mutation) but NOT visually verified against a real browser -- stated as a known limitation, not silently claimed. AC2 (5 distinguishable states derived from receiver acks) satisfied. AC3 (idempotent save resolving to exact message/block; retry after offline recovery cannot duplicate) satisfied via the existing receiver content-hash dedup (deduplicated/replaced flags) -- reused, not reimplemented. AC4 (host DOM churn/unsupported layouts fail closed) satisfied: every DOM operation in mount()/reconcile() is wrapped so a selector/DOM surprise never breaks the host page. AC5 (visual/keyboard/accessibility fixtures, both providers, light/dark) satisfied for keyboard (Enter/Space activation tested) and ARIA (role/aria-label/aria-pressed/tabindex tested); light/dark theming uses CSS custom properties inherited from the shadow host rather than explicit prefers-color-scheme branches (dot colors are semantic, not scheme-dependent) -- no dedicated dark-mode visual test since there's no real rendering in this environment.\n\nVerification: npx vitest run tests/content/message_layer.test.js (15/15, real production file evaluated via JSDOM per the grok.test.js/chatgpt_bridge.test.js convention -- not duplicated logic), npx vitest run full suite (236/236), npm run lint / npm run validate clean. See PR #2871.","status":"open","priority":1,"issue_type":"feature","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:49Z","created_by":"Sinity","updated_at":"2026-07-14T00:29:44Z","labels":["area:capture","delivery:L-external-legibility","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-ys30","depends_on_id":"polylogue-yyvg","type":"parent-child","created_at":"2026-07-12T22:23:59Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-4g3n","title":"'What Polylogue did here' per-conversation timeline","description":"Reverse-chron event log per conversation: capture / detected-new / held-with-reason / first-seen. Requirement: doing nothing must itself be a logged visible event. Persist to chrome.storage; mirror to daemon as queryable event trail.","acceptance_criteria":"1. Capture, detected-new, held-with-reason, first-seen, and explicit no-op events are persisted in reverse chronological order with conversation/message refs and timestamps. 2. The loopback receiver mirrors the browser trail into a daemon-queryable event relation with idempotent event IDs; reconnect/retry cannot duplicate it. 3. Browser-local loss or profile reseed can be reconciled from the receiver ledger according to the declared authority direction. 4. The UI renders doing-nothing and unknown states rather than omitting them. 5. A real extension-to-daemon fixture proves query, ordering, retry, and degraded-offline behavior.","notes":"PR #2780 merged: local persisted reverse-chron timeline satisfied ('What Polylogue did here' — doing-nothing is now a logged visible event). DEFERRED (not closing): the daemon-queryable mirror remains explicitly deferred to the substrate-owned portion; this browser-extension lane does not modify polylogue/.\n2026-07-14 verification pass (PR #2871 cluster investigation): confirmed the bead's existing notes are still accurate -- PR #2780 merged, local persisted reverse-chron timeline satisfies the primary AC (doing-nothing is a logged visible event). The daemon-queryable mirror AC is correctly and explicitly deferred in the bead's own prior notes to the substrate-owned portion (\"this browser-extension lane does not modify polylogue/\"). No new work done or needed here in this pass; already_done for this lane's intended scope.","status":"open","priority":1,"issue_type":"feature","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:47Z","created_by":"Sinity","updated_at":"2026-07-14T00:30:06Z","labels":["area:capture","delivery:L-external-legibility","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-4g3n","depends_on_id":"polylogue-yyvg","type":"parent-child","created_at":"2026-07-12T22:23:57Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-bkff","title":"Popup mission-control: multi-tab list + active-conversation card","description":"Replace single-active-tab fact table with N-tab list (provider chip + mental-model state chip), active-conversation detail card (state, fidelity, cost/tokens, captured-vs-visible), quick actions. Drop Mode/Request/raw archive_state from default surface; keep behind debug export.","status":"closed","priority":1,"issue_type":"feature","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:46Z","created_by":"Sinity","updated_at":"2026-07-13T00:57:42Z","closed_at":"2026-07-13T00:57:42Z","close_reason":"PR #2780 merged: popup mission-control shipped — identity-qualified multi-tab list, active-card state/fidelity/cost-tokens/captured-visible, quick actions resolve against current active conversation","labels":["area:capture","delivery:L-external-legibility"],"dependencies":[{"issue_id":"polylogue-bkff","depends_on_id":"polylogue-yyvg","type":"parent-child","created_at":"2026-07-12T22:23:56Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-r4no","title":"Auto-capture trigger never fires: 160 archive-state GETs, zero capture POSTs","description":"Diagnosed live in the design pass: a conversation correctly detected missing by two automatic checks never produced a capture POST; only manual Capture page worked. Debug log: 160 status/archive-state GETs over hours, zero POSTs. Trust bug AND data loss. Fix the trigger and make saw-it-did-nothing a logged visible event (timeline bead).","acceptance_criteria":"A newly-detected missing conversation produces either a capture POST or a logged held-with-reason event within one poll cycle; extension test covers both; the timeline surface displays the decision.","status":"closed","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:44Z","created_by":"Sinity","updated_at":"2026-07-13T00:56:39Z","closed_at":"2026-07-13T00:56:39Z","close_reason":"PR #2780 merged: silent-capture P1 bug fixed — missing-state polling now posts through the real content/runtime route or records a specific held decision (throttle, navigation, rejection, queue drop, local capture failure) in the same cycle","labels":["area:capture","delivery:L-external-legibility"],"dependencies":[{"issue_id":"polylogue-r4no","depends_on_id":"polylogue-yyvg","type":"parent-child","created_at":"2026-07-12T22:23:55Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yyvg","title":"Extension redesign: ambient two-way surface","description":"IA change per Claude Design handoff pack (docs/design/browser-capture-redesign/ + downloads handoff zip 2026-07-12). Supersedes yajm/x5k3 incremental framing. Two-layer rule from 1nb2, recorded verbatim on polylogue-90y: per-message state blends in; cross-conversation intelligence floats. Pixel specs: project/Polylogue Redesign.dc.html.","acceptance_criteria":"1. The redesign ships the two-layer rule across its member slices: per-message state blends into host actions; cross-conversation intelligence uses the separate corner/popup surface. 2. Capture, timeline, multi-tab/offline, assertion authoring, and reverse-channel children share one receiver identity/status vocabulary and no parallel ledgers. 3. Claude.ai and ChatGPT end-to-end fixtures cover DOM churn, offline recovery, profile reseed, accessibility, and zero-layout-shift constraints. 4. Reverse posting remains off by default, doubly gated, and dry-run-first. 5. The epic’s child matrix records each slice as satisfied, deferred to a named bead, or misframed before closure.","notes":"2026-07-14: browser-extension cluster pass (PR #2871) advanced ys30 to satisfied and re-confirmed 4g3n's already-done status; bj5h and wvji remain open/untouched (deferred, see their own notes). Epic not closeable: yyvg.1/yyvg.2/yyvg.3/l40k/yqof remain open and were out of this cluster's scope.","status":"open","priority":1,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T20:23:43Z","created_by":"Sinity","updated_at":"2026-07-14T00:30:16Z","labels":["area:capture","delivery:L-external-legibility","lane:docs-demos-launch"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-jlme.1","title":"Run resumable provider-aware browser backfills in the extension","description":"Problem: The live browser extension captures one open conversation well, but historical gap repair still requires an agent to enumerate provider chats, click or fetch them one by one, maintain an external checkpoint, and notice throttling. The 2026-07-12 ChatGPT post-GDPR run processed 144 of 462 candidates before provider throttling; a fixed-rate foreground crawl is neither polite nor reliable. Goal: make authenticated delta/backfill acquisition a first-class, background, resumable extension workflow. Scope: ChatGPT and Claude.ai provider-native inventory/capture first, with a provider adapter contract for later Gemini web coverage. The GDPR/export archive remains the immutable baseline; the engine only enumerates and captures records missing or changed after a user-selected cutoff. Non-goals: bypass provider authentication, anti-bot controls, or rate limits; scrape deleted/ephemeral chats absent from provider inventory; mark a record complete before the loopback receiver durably acknowledges its spool write.","design":"Architecture: add a BackfillCoordinator in the MV3 service worker and provider adapters with enumerate(cursor, cutoff), fetch_native(native_id), classify_response, and normalize_capture operations. Prefer authenticated provider inventory/native JSON endpoints observed by the first-party page; use a background tab/DOM bridge only as an explicit lower-fidelity fallback. Never activate or coordinate-click the operator tab. Persist jobs and queue entries in extension-owned durable storage (IndexedDB preferred for volume; chrome.storage.local only for compact control state): job id/provider/cutoff/inventory cursor, native id/provider updated_at, state, attempt count, next_eligible_at, lease owner/expiry, last response class, capture fidelity, receiver receipt/content hash. State machine: discovered -> eligible -> leased -> captured -> receiver_acked -> complete; retryable responses go to backoff; no_turns and permission/auth failures are explicit terminal or operator-action states, not infinite retries. MV3 restarts recover expired leases and chrome.alarms schedules the next eligible wakeup. Rate policy: per-provider token bucket with concurrency 1 by default, a conservative configurable floor, randomized inter-request delay, Retry-After support, exponential backoff with full jitter, and a circuit breaker that pauses the whole provider job on 429/403/challenge or repeated transport failures. Resume requires the cooldown deadline or an explicit operator action; repeated throttling increases the learned floor for that job. Receiver contract: submit native-full capture with job/queue/instance attribution and mark complete only after a durable spool ACK containing request id and content hash; idempotency is provider native id plus content hash. UX: popup mission control exposes inventory totals, eligible/completed/no-turns/retry/error counts, current rate and cooldown, last durable ACK, start/pause/resume/cancel, and exportable diagnostic ledger. Safety budgets: maximum queue size, maximum captures per wake window, maximum background-tab lifetime, and total daily request budget; all are fail-paused. The coordinator shares capture health and instance attribution contracts with polylogue-3v1 and polylogue-3v1.1 rather than inventing a second status plane.","acceptance_criteria":"1. A ChatGPT job can enumerate a synthetic post-cutoff inventory, process it with concurrency 1 in background, survive service-worker termination/restart, and resume without duplicate durable captures. 2. A simulated 429 with Retry-After causes zero requests before the deadline, records a visible cooldown reason, and resumes afterward; repeated 429s open a provider circuit breaker. A deterministic fake-clock test proves this. 3. 403/auth/challenge, transport error, native-empty/no_turns, receiver-down, and successful durable ACK are distinct persisted states with bounded retry policies. 4. Receiver-down captures remain queued and are not marked complete; after receiver recovery they drain idempotently and the ACK content hash matches the submitted artifact. 5. Popup controls start, pause, resume, and cancel a job and show provider/cutoff, inventory cursor, progress buckets, learned request cadence, cooldown deadline, and last error/ACK. 6. A two-instance test proves only one lease owns a queue item at a time and duplicate posts converge by native id plus content hash. 7. A packaged-extension smoke runs a small authenticated-or-fixture-backed backfill without foreground tab activation; a provider adapter contract fixture makes inventory/API drift fail loudly. 8. Documentation states that the engine honors provider controls and cannot prove completeness beyond the authenticated inventory.","notes":"Incident evidence: /realm/tmp/polylogue-chatgpt-backfill-progress-20260712.json checkpoints the interrupted 144/462 ChatGPT run; /realm/tmp/claude-ai-web-freshness-audit.json demonstrates the preferred inventory-delta method (900 inventoried, 10 cutoff matches, 9 native-full captures, one native-empty). These paths are ephemeral evidence, not implementation dependencies.\n[Implementation 2026-07-12] Claimed for isolated feature/feat/browser-background-backfill lane. Implementing synthetic/fixture-only autonomous MV3 backfill; live ChatGPT crawl and /realm/tmp/polylogue-chatgpt-backfill-progress-20260712.json remain untouched.\nClosure 2026-07-12: PR #2771 merged as 07ea5f2d0c760f00dde0e79928b35ab81ac98e59. Shipped durable IndexedDB jobs/queue/revision ledger, one active job per provider, atomic execution/request reservation and generation fencing, per-job alarms, bounded provider/receiver retries and storage/daily budgets, Retry-After/circuit handling, authenticated ChatGPT+Claude native adapters, exact receiver-byte ACKs, popup control/history/ledger UX, and packaged service-worker proof with no foreground activation. Final repair atomically requeues auth_required rows on explicit resume and keeps the job paused until then. Verification: browser extension 145/145, ESLint clean, manifest v0.1.0 valid; receiver contract 59/59; devtools verify --quick 15/15 (20260712T192227Z-quick-3812364-11b62839). Two Codex findings fixed/resolved; independent cold review converged with no legitimate gaps. GitHub runner jobs failed before allocation (runner_name empty, steps empty, no logs); GitGuardian and CodeRabbit status checks passed. No live ChatGPT/Claude calls; paused /realm/tmp checkpoint was not read or modified.","status":"closed","priority":1,"issue_type":"feature","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T16:57:10Z","created_by":"Sinity","updated_at":"2026-07-12T19:24:03Z","started_at":"2026-07-12T18:23:05Z","closed_at":"2026-07-12T19:24:03Z","close_reason":"Delivered by PR #2771 / merge 07ea5f2d0 with every acceptance criterion covered by fixture-backed production-path tests and converged cold review.","labels":["area:ingest","area:web","delivery:G-live-performance","horizon:frontier","lane:capture-reliability","spine"],"dependencies":[{"issue_id":"polylogue-jlme.1","depends_on_id":"polylogue-3v1","type":"related","created_at":"2026-07-12T18:57:18Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jlme.1","depends_on_id":"polylogue-3v1.1","type":"related","created_at":"2026-07-12T18:57:19Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-jlme.1","depends_on_id":"polylogue-jlme","type":"parent-child","created_at":"2026-07-12T18:57:10Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-7s57.1","title":"Make MCP call telemetry durable and session-complete","description":"The merged MCP call-log route is daemon-owned and bounded, but the client sender is explicitly best-effort: queue saturation and HTTP failures can silently drop records, and several session-scoped tools still omit session correlation. That prevents the parent bead's universal durability/queryability claim and a defensible resume-efficacy rerun.","design":"Add an acknowledged durable delivery boundary: use a local outbox/spool or equivalent retryable transport keyed by call_id, drain idempotently into daemon-owned ops.db, and surface durable loss/debt counters if a hard bound is unavoidable. Thread session identity through every session-scoped MCP tool, including get_messages and raw_artifacts, and define successor-session correlation for compose_context_preamble. Keep SQLite ownership in the daemon.","acceptance_criteria":"1. Daemon outage and MCP process restart do not silently lose accepted call records, or any bounded loss is durably surfaced as explicit debt. 2. Queue pressure is observable and retry/drain is idempotent by call_id. 3. Every session-scoped MCP tool is queryable by session_id, with an explicit correlation contract for compose_context_preamble. 4. Production-route tests cover outage/restart, queue pressure, duplicate delivery, and the complete session-tool inventory. 5. polylogue-9e5.10 can be rerun with n>0 and the resulting evidence is recorded.","notes":"2026-07-12 takeover: implementing durable local MCP call outbox, idempotent daemon drain, explicit pressure/debt visibility, complete session-scoped identity forwarding, and compose-context successor correlation. Parallel read-only architecture audit is active; production-route outage/restart/duplicate/inventory tests will own the proof.\n2026-07-12 implementation evidence before deployment:\\n- AC1: completed calls cross an atomic fsync+replace XDG-state outbox boundary; daemon outage and fresh-dispatcher restart drain the same event through the authenticated writer route. Startup scans before the first MCP call.\\n- AC2: the in-memory queue is wake-only; saturation preserves every outbox file. readiness_check exposes pending/quarantined count+bytes, oldest debt, wake depth/drops, and failures. Retries are bounded and isolated per archive root.\\n- AC3: ops.db normalizes primary/member refs in mcp_call_session_refs. Signature-driven inventory covers singular, plural, and alias tools; compose_context_preamble accepts the provider SessionStart successor_session_id without requiring prior ingest.\\n- AC4: real routes cover outage/restart, current endpoint after restart, saturation, identical duplicates, conflict quarantine without head-of-line blocking, two-dispatcher quarantine races, singular get_messages/raw_artifacts/preamble, alias neighbor_candidates, plural compare_sessions, and filtered SQL reads. Four adversarial iterations ended CLEAN for AC1-4.\\n- Verification: 244 affected MCP/storage/route tests passed in 68.22s; devtools verify --quick run 20260712T114943Z-quick-2450834-f68eb6ea passed all 15 gates.\\n- AC5 remains explicitly open until this branch merges, the live NixOS polylogued package is deployed, genuine resume/context MCP calls create n>0 live rows, and the polylogue-9e5.10 rerun evidence is recorded.\n2026-07-12 live AC5 evidence: merged PR #2760 was deployed through the Sinnix NixOS generation; polylogued restarted from the updated package. Real FastMCP calls to get_resume_brief and compose_context_preamble produced n=2 durable successful ops.db rows, with normalized primary references for the seed Claude session and successor Codex session respectively. The rerun is recorded on polylogue-9e5.10; it removes the instrumentation blocker while honestly retaining the separate polylogue-nas1 arm-labeling blocker.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T10:03:23Z","created_by":"Sinity","updated_at":"2026-07-12T12:08:34Z","started_at":"2026-07-12T11:20:28Z","closed_at":"2026-07-12T12:08:34Z","close_reason":"PR #2760 merged and deployed. AC1-4 passed production-route tests and four adversarial reviews; AC5 produced and recorded n=2 genuine durable live MCP rows. The remaining efficacy arm-labeling prerequisite is separately tracked by polylogue-nas1.","labels":["area:daemon","area:mcp","discovered-from:polylogue-7s57","discovered-from:polylogue-9e5.10"],"dependencies":[{"issue_id":"polylogue-7s57.1","depends_on_id":"polylogue-7s57","type":"parent-child","created_at":"2026-07-12T12:03:23Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-rxdo.7.2","title":"Import delegation annotation batches through JSONL CLI and MCP","description":"Complete the external-agent labeling loop after durable schemas/batches exist: ingest candidate-only JSONL rows under a registered schema, validate target and evidence-span references against the live archive, preserve independent batch identity, expose CLI/MCP import contracts, query typed values, adjudicate accept/reject/defer, and render results.","design":"Add one product-layer batch import operation over the registered schema and durable batch repository. Parse bounded JSONL with per-row result/error records; resolve ObjectRef targets and EvidenceRef spans through the archive before writing; refuse missing evidence when required. Every external-agent row goes through upsert_annotation_assertion and remains candidate/non-injected. Add query-first CLI and MCP leaf adapters over the same operation, including EXPECTED_TOOL_NAMES, tool contract, and generated references. Demonstrate two independent label batches without collapsing disagreements.","acceptance_criteria":"Roundtrip a bounded evidence pack into five candidate labels under the concrete delegation schema; report per-row validation failures; reject nonexistent targets and evidence spans; retain two independent batches; query labels with typed predicates; judge accept/reject/defer; render active and unresolved outcomes. CLI and MCP call the same production operation. Verify with an integration-flavored focused roundtrip test, CLI test, MCP tool contract test, EXPECTED_TOOL_NAMES update, generated reference regeneration, and devtools verify --quick.","notes":"2026-07-12 completion: PR #2767 merged at f4504cb4 after two adversarial iterations. Iteration 1 found and fixed full EvidenceRef lineage validation, duplicate row identity handling, confidence authority, concrete-schema coverage, adapter mapping tests, and envelope bounds; iteration 2 found no legitimate gaps and independently reproduced 39 focused tests. devtools verify --quick passed all 15 steps (20260712T175008Z-quick-3723423-204a839e). GitHub-hosted checks failed before acquiring runners (empty runner, zero steps); Codex Review and CodeRabbit returned quota notices without findings.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T08:48:35Z","created_by":"Sinity","updated_at":"2026-07-12T17:53:07Z","started_at":"2026-07-12T17:21:36Z","closed_at":"2026-07-12T17:53:07Z","close_reason":"Merged PR #2767; all JSONL import, live-ref validation, multi-batch, typed-query, adjudication, rendering, CLI/MCP, and generated-contract AC satisfied.","labels":["area:cli","area:mcp","area:substrate","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts","tech-tree"],"dependencies":[{"issue_id":"polylogue-rxdo.7.2","depends_on_id":"polylogue-rxdo.7","type":"parent-child","created_at":"2026-07-12T10:48:35Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-rxdo.7.2","depends_on_id":"polylogue-rxdo.7.1","type":"blocks","created_at":"2026-07-12T10:48:36Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-rxdo.7.1","title":"Persist annotation schemas and batch provenance","description":"The typed annotation foundation in PR #2757 remains process-local: schema definitions are not durable and annotation batches do not exist. Persist versioned schema definitions and independent batch provenance so a schema identity resolves to one immutable construct definition across restarts and every imported row can be traced to a source result, actor/model/prompt, validation outcome, and batch counts.","design":"Classify as an additive durable user.db change. Add the next numbered user migration plus verified backup-manifest coverage for annotation_schemas and annotation_batches. Store canonical schema-definition JSON/fingerprint and reject same-id/version drift. Register one versioned delegation-discourse schema with abstention/applicability/confidence and evidence policy. Keep rows in assertions; batches are provenance containers linked by annotation-batch ObjectRefs. Expose focused repository reads for schema and batch metadata without adding import surfaces yet.","acceptance_criteria":"A cold reopen resolves the same schema definition and fingerprint; incompatible reuse of an id/version fails closed. One concrete delegation-discourse schema is registered. Two independent batches for the same schema/target remain distinguishable and their metadata/counts are queryable. Durable migration backup-manifest and schema-versioning policy pass. Verify with focused user-tier migration/schema/batch repository tests plus devtools lab policy schema-versioning and devtools verify --quick.","notes":"2026-07-12 implementation lane scope: additive durable user.db migration plus canonical DDL/version alignment; immutable schema definition JSON/fingerprint with cold-reopen and fail-closed reuse; one registered delegation-discourse schema; independent queryable annotation-batch provenance containers linked to existing assertion/ObjectRef vocabulary; focused repository reads and migration/schema/batch tests. Non-goals: JSONL, CLI, or MCP import surfaces (polylogue-rxdo.7.2), structural target joins (polylogue-kmts), and raw-retention/readiness changes.\n2026-07-12 Codex takeover repair: closed the dual-audit gaps for import-order safety, real durable annotation-batch ref resolution, persistence/canonical replay enforcement, schema-registry canonical identity, insert-once batch-scoped assertions, full-string identifier validation, and durable migration/fresh-schema equivalence. Adversarial iteration 1 found two real provenance gaps (NFC key collisions and mutable nested aliases); both were repaired with collision rejection plus an immutable canonical snapshot used by persistence, with cold-reopen regressions. Fresh independent iteration 2 (native Codex session 019f56bc-4f39-72c0-9a8a-5d82265c1d0f, gpt-5.6-terra/high, read-only) returned NO LEGITIMATE GAPS across all 8 ACs. Verification: focused durable/import tests 16 passed; earlier full affected selection 173 passed with only inherited test_no_unaudited_string_interpolated_sql failure (10 unchanged baseline sites); devtools verify --quick run 20260712T142805Z-quick-2951963-558f95c6 passed all 15 steps; schema-versioning policy intact; git diff --check clean. bd-graph-lint found no cycles and only inherited missing-AC polylogue-2ilz and polylogue-nu2h. Bead intentionally remains in_progress for coordinator closeout.\n2026-07-12 publication correction and final boundary repair: the typed annotation foundation landed through PR #2757 at bf94704c0; PR #2752 was closed unmerged and is not predecessor evidence. Publication recon found one additional public-surface gap: annotation-batch ref resolution exposed unbounded assertion refs, validation failures, and metadata. Commit 2389a2399 (refreshed onto current master as 8b3666375) preserves full ArchiveStore reads but caps public ref samples, emits exact totals/omissions/truncation, bounds canonical JSON previews with exact byte counts plus SHA-256, removes duplicated top-level assertion refs, and surfaces caveats. An oversized real Polylogue.resolve_ref regression proves the response stays under 16 KiB while the repository retains all 64 refs and failures. Current-master verification: focused durable/schema/ref/migration/public-resolver selection 150 passed in 41.95s, run 20260712T150813Z-focused-test-2978110-b1ae0a85; schema-versioning policy intact; devtools verify --quick 20260712T150910Z-quick-2978545-a55cbda4 passed 15/15. Branch was refreshed by cherry-picking the three reviewed commits onto origin/master rather than rewriting the published worker branch.\n2026-07-12 final adversarial closure: iteration 3 found two legitimate release gaps—schema declaration authority remained mutable/hot-cold divergent, and count-only public caps could serialize ~2.6 MiB. Commits 0d257b3b5 and d5ed2af80 canonicalize immutable schema authority at construction and enforce total byte-bounded public previews while preserving complete repository reads. Iteration 4 then found unbounded unresolved refs, NFC rewriting of opaque ObjectRefs in provenance, and schema declarations accepting non-UTF-8 lone surrogates; e229c95f0 closes all three with real facade/cold-replay regressions. Iteration 5 found one final JSON-reachable lone-surrogate ref escaping the pre-lookup bound; fc88f1a99 now validates UTF-8 before ObjectRef parsing/SQLite access and emits a fixed-size digest descriptor. The iteration-5 reviewer found no other legitimate gaps across the remaining AC. Verification: combined focused durable/schema/ref/migration/public route 155 passed (20260712T152900Z-focused-test-3014481-3ad91648); final coordinator release-gap selection 12 passed (20260712T160837Z-focused-test-3325379-546339d8); devtools verify --quick after the final fix passed 15/15 (20260712T160508Z-quick-3313240-1b7e2b60); schema-versioning policy reports 0 derived helpers and 0 invalid durable migrations; git diff --check clean. Default testmon selection expanded to 14,730 tests because surfaces/payloads.py is a dependency hub and was intentionally aborted rather than blanket-running the suite; no devtools verify --all was run. Deferred scope remains JSONL/CLI/MCP import (polylogue-rxdo.7.2) and structural joins (polylogue-kmts).","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T08:48:06Z","created_by":"Sinity","updated_at":"2026-07-12T17:21:33Z","started_at":"2026-07-12T12:42:43Z","closed_at":"2026-07-12T17:21:33Z","close_reason":"Merged PR #2765 with all durable schema/batch provenance AC satisfied and review findings resolved.","labels":["area:mcp","area:query","area:substrate","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts","tech-tree"],"dependencies":[{"issue_id":"polylogue-rxdo.7.1","depends_on_id":"polylogue-rxdo.7","type":"parent-child","created_at":"2026-07-12T10:48:06Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-57rp","title":"Reacquire replaced browser-capture snapshots under typed raw authority","description":"Live proof on 2026-07-12 captured ChatGPT conversation 6a5350db-c1d8-83ed-9976-035227280d5e with two acquired 848,460-byte assets at SHA-256 40fa31aeccd41a8c61e3bbe5d721d1f5395cc4f14c7411f94663b777a23eef77. The receiver replaced browser-capture/chatgpt/6a5350db-c1d8-83ed-9976-035227280d5e-d8aee745eb05.json with a 2.3 MB acquired envelope, but source.db retained the prior 31,884-byte raw a7d004c9aa943f6a10211851904105ee1c647c331552646e1b9cbe268940ed11 as revision_kind=unknown/revision_authority=quarantined. The daemon logs active full raw lacks byte-proven authority, raw materialization leaves one candidate, and index attachments remain unfetched. Durable receiver bytes are preserved; derived convergence is blocked.","design":"Browser-capture artifacts are mutable snapshot files keyed by stable capture identity. A later receiver replacement with different file bytes must acquire a new durable raw revision and authorize the newer full snapshot without treating it as an unrelated append/full ambiguity. Reuse typed revision receipts and monotonic source observation evidence; do not bypass authority with force-write. Preserve the previous raw and content-addressed source blob, record predecessor/supersession explicitly, and let ordinary daemon convergence parse/materialize the newest accepted snapshot. Cross-reference the yla8/fmob revision-authority contracts before implementation.","acceptance_criteria":"1. A real-route fixture writes an unfetched browser-capture snapshot, ingests it, replaces the same source path with an acquired inline-attachment snapshot, and proves a new durable raw revision becomes the accepted head. 2. The newer snapshot parses/materializes automatically and the attachment row becomes acquisition_status=acquired with byte_count=848460 and blob SHA-256 40fa31aeccd41a8c61e3bbe5d721d1f5395cc4f14c7411f94663b777a23eef77; no manual reset or force-write. 3. Reverse arrival or divergent older replacement cannot regress the accepted head. 4. Daemon replay debt terminates for the fixture and reports attempted/accepted/superseded counts. 5. Live re-capture 6a5350db-c1d8-83ed-9976-035227280d5e converges from the preserved receiver artifact, with exact source/index/blob evidence. Verify with focused browser-capture ingest and raw-revision tests, devtools verify --quick, and the live read-only source/index queries recorded in notes.","notes":"PR #2785 merged: AC1 (replacement enters typed membership authority) and AC3 (reverse/divergent stale replacement cannot regress head) satisfied via real LiveBatchProcessor browser-capture fixtures. DEFERRED (not closing): AC2 (exact 848,460-byte/SHA acquisition — current fixture only proves generic attachment materialization, not the prescribed exact artifact evidence), AC4 (replay-debt termination/counts — not implemented), AC5 (preserved live receiver artifact convergence with source/index/blob evidence — not run under the archive-safety boundary).\n2026-07-14 status check as part of the raw-identity-repair cluster (PR #2877): re-read this bead's notes (PR #2785 merged, AC1/AC3 satisfied; AC2/AC4/AC5 deferred) and its existing real-route fixture test_browser_capture_replacement_advances_membership_head_and_acquires_attachment in tests/unit/sources/test_live_batch_support.py. Investigated strengthening AC4 (replay-debt termination/counts) via raw_materialization_replay_backlog(), but that backlog's candidate-selection query (_raw_materialization_candidate_ids in repair.py) has enough WHERE-clause subtlety (application_terminal / membership_authority_complete / membership_authority_quarantined flags, none of which I fully traced against this specific membership-decision fixture shape) that I judged writing a new assertion against it, without deeper verification than this session's remaining budget allowed, to be a real risk of asserting something not actually true rather than a genuine closure. Left undone rather than guessed at. AC2 (exact 848,460-byte/SHA production artifact reproduction) and AC5 (live re-capture convergence) remain correctly deferred -- both require either embedding real recovered production bytes in a repo fixture (inappropriate) or a live capture (out of this session's live-archive-safety scope). No PR-2877 commit touches this bead's own code.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T08:38:31Z","created_by":"Sinity","updated_at":"2026-07-14T01:06:40Z","labels":["area:browser","area:durability","area:lineage","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-57rp","depends_on_id":"polylogue-5k5l.1","type":"discovered-from","created_at":"2026-07-12T10:38:30Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-t0dy","title":"Reconcile two live production raw rows stuck under the pre-fix duplicate-raw scheme","description":"polylogue-sjf6 (PR #2729, merged) fixed the ROOT CAUSE of cross-pipeline raw-identity divergence going forward: the one-shot `polylogue import` pipeline now computes raw_ids for grouped-session files the same way the live daemon watcher does (no native_id), so future re-ingestion of Claude Code resume/fork carryover files converges on one raw row instead of duplicating. It explicitly does NOT retroactively reconcile raw rows that were ALREADY duplicated on the live production host before the fix existed. Two specific files are known-affected: /home/sinity/.claude/projects/-realm-project-sinex/1e5805bd-72d6-4010-b052-b2b4a0e78425.jsonl and .../31571196-df8f-4e3d-998f-e595eea65faf.jsonl. Each has two raw_sessions rows for identical source_path/bytes: one from an old `polylogue import` run (native_id set, e.g. a5724e23-3cc3-4d33-81ff-f17d421b5be2) with an ACCEPTED head in raw_revision_heads, and one from the daemon watcher (native_id NULL). Every daemon catch-up pass over these files will keep hitting `RuntimeError: membership replay cannot retire an unrelated accepted head` (archive.py:2255) indefinitely because the accepted head is permanently bound to the OLD (native_id-inclusive) raw_id, and the daemon always computes the native_id-less raw_id for its own write attempt -- the fix in #2729 only aligns the two pipelines for NEW writes, it does not migrate an already-accepted head.","design":"This needs a one-time, carefully-authorized reconciliation, not a code change: identify every (origin, source_path) pair with more than one raw_sessions row sharing identical blob_hash (a live census query, not a guess -- there may be more than the 2 already found; run it fresh). For each such pair, determine which raw_id is the one recomputed by the CURRENT (post-#2729) scheme (native_id=None) -- that is the canonical id going forward. If the currently-accepted head is bound to the OTHER (stale, native_id-inclusive) raw_id, the accepted head needs to be re-pointed to the canonical raw_id with an explicit authorization step (reuse the fold-authorization / revision-application machinery this codebase already has for equivalent-content transitions -- see polylogue-yla8.9/PR #2723 fold_authorization pattern -- do NOT hand-write a raw UPDATE against raw_revision_heads). The stale duplicate raw row itself should NOT be deleted (durable raw evidence is never deleted per this repo policy) -- it stays as historical evidence, just no longer the accepted head. Stop the daemon before performing the live repair (same discipline as yla8.6), take a durable backup snapshot first (same discipline as yla8.6/yla8.9), and verify with a dry-run census before/after.","acceptance_criteria":"1. A live read-only census (fresh, not reused from sjf6 notes) enumerates every (origin, source_path) with duplicate raw_sessions rows sharing identical blob_hash on the production archive at /home/sinity/.local/share/polylogue. 2. For each, the accepted head in raw_revision_heads is verified/repointed to the raw_id the current (post-#2729) scheme would compute, using the existing fold-authorization machinery, with full transactional atomicity and rollback-safety on any proof failure. 3. No durable raw/blob/session/receipt rows are deleted. 4. After the daemon restarts, a live catch-up pass over the two known-affected files (and any others the census found) completes without the \"membership replay cannot retire an unrelated accepted head\" RuntimeError. 5. Durable backup snapshot taken before the live repair (verified restorable), receipt recorded in bead notes. 6. Focused real-route tests plus devtools verify --quick pass; anti-vacuity states the production dependency exercised.","notes":"Follow-up to polylogue-sjf6 (PR #2729, merged 45766f3c7). Original evidence: journalctl --user -u polylogued since 2026-07-12T02:18, two failures at 02:31:08 and 02:33:24 CEST. Do not start this until the daemon is not mid-catch-up on unrelated chunks, to avoid confusing concurrent-state noise in the census.\nWAVE FLAG 2026-07-13: untouched P1, unowned production data debt (two live raw rows under the pre-fix duplicate scheme). Small, self-contained, evidence named in-bead — ideal single-lane candidate for the next wave.\n2026-07-14 implementation: PR #2877 (branch feature/fix/raw-identity-repair-cluster, commit 6688e270b) adds repair_duplicate_raw_identity() to polylogue/storage/repair.py -- a typed dry-run/apply/CAS/receipt actuator following the same pattern as every other actuator in this file, using record_revision_application_sync (not a hand-written raw_revision_heads UPDATE, per the design note). _inspect_duplicate_raw_identity proves per (stale_raw_id, canonical_raw_id) pair: byte-identical content (origin/source_path/source_index/blob_hash/blob_size + an actual BlobStore read verifying retained bytes match the declared digest/size); each raw id equals the deterministic id its own fields (and native_id shape) predict via deterministic_raw_session_id; stale raw is the CURRENT accepted head/session pointer; canonical raw is a genuinely dangling duplicate. Apply performs a SELECTED_BASELINE receipt for canonical (head CAS -- session_id/content_hash/frontier_kind/frontier unchanged since byte-identical, only accepted_raw_id repoints) then a SUPERSEDED receipt on stale for audit. Stale raw's own row is never mutated/deleted.\nAC status: AC1-AC4 (real-route census/proof/apply/rollback contract, idempotent reapply) satisfied by the actuator + 10 focused tests. AC5 (live use: verified backup, stopped daemon, fresh dry proof, immutable receipt, restart postflight against the two named production files 1e5805bd-...jsonl and 31571196-...jsonl) is explicitly NOT performed -- reserved for the operator per this cluster's live-archive-safety constraint. The code is ready for that one-time live run whenever authorized.\nVerification: devtools test tests/unit/storage/test_duplicate_raw_identity_repair.py -> 10 passed in 96.63s. devtools verify --quick -> exit_code 0. mypy clean. No live archive touched.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-12T01:31:32Z","created_by":"Sinity","updated_at":"2026-07-14T01:04:29Z","labels":["area:storage","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-t0dy","depends_on_id":"polylogue-sjf6","type":"blocks","created_at":"2026-07-12T03:31:45Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-rgbj","title":"Index message foreign-key backreferences for bounded replacement","description":"Production catch-up replacing the 15k-message Codex session spent over 10 minutes at DELETE FROM messages while the writer held the transaction. py-spy sample /realm/tmp/polylogue-catchup-hot.raw attributed 498/754 samples to _replace_full_session_messages_and_blocks line 1795. The write path pre-deletes blocks and projection rows, but SQLite still enforces self/child ON DELETE actions. Canonical index DDL has no leading indexes on messages.parent_message_id or retained session_events.source_message_id, so each deleted message can scan global child tables.","design":"Before changing schema, use EXPLAIN/controlled seeded archives to identify every messages(message_id) backreference and prove which missing child-key indexes dominate deletion. Batch the derived index version bump with other ready index-tier additions per schema policy; likely candidates are messages(parent_message_id) and session_events(source_message_id), but evidence decides. Measure full replacement of a large synthetic session before/after, preserve FK semantics, include rebuild plan/blue-green prerequisite assessment, and do not interrupt the current live convergence merely to optimize the one-time repair.","acceptance_criteria":"1. A production-shaped large-session replacement benchmark attributes delete time and records row/table sizes. 2. Every message FK backreference has a justified leading child-key index or an explicit proof it is bounded. 3. Replacement latency improves materially without disabling foreign keys or weakening cascade/set-null semantics. 4. Canonical derived DDL/version, rebuild plan, focused behavior tests, and quick gate land together in the appropriate batched index window. 5. Live deployment uses the approved blue-green/rebuild procedure and records before/after timing.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T23:12:46Z","created_by":"Sinity","updated_at":"2026-07-12T05:07:08Z","started_at":"2026-07-12T02:29:56Z","closed_at":"2026-07-12T05:07:08Z","close_reason":"Merged PR #2738: added idx_web_constructs_message (missing FK index on web_content_constructs, confirmed live via EXPLAIN QUERY PLAN, 319x measured speedup). INDEX_SCHEMA_VERSION 33->34. Structural regression test walks every messages(message_id) FK and asserts indexed.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-t0p.1","title":"Parse Claude background completion outcomes","description":"Claude Code persists background-task completion notifications in session JSONL after the initiating Bash tool result. The protocol message carries task-id, tool-use-id, status, output-file, and a human summary whose terminal clause contains the numeric exit code. Current Polylogue parsing retains this only as text while the earlier background-start tool_result remains linked to Bash with tool_result_is_error=false, so a failed background job can be projected as successful. This falsifies polylogue-qqyg's broad claim that no Claude exit code survives anywhere: that remains true for ordinary foreground Bash results, but not for background completion protocol evidence.","design":"Parse the structured task-notification envelope first, correlate completion to its initiating Bash action by tool-use-id/task-id, and project terminal status plus numeric exit code onto a derived background-action outcome without regex-guessing arbitrary prose. Treat the known Claude notification template as provider protocol structure, preserve the raw notification block, represent missing/changed templates as explicit unknown, and reconcile duplicate/update notifications idempotently. Correct polylogue-qqyg's evidence note to distinguish foreground Bash, hooks, and background completion notifications.","acceptance_criteria":"A raw Claude fixture with one successful and one failed background command parses stable task/tool linkage, status, output-file, and exit codes 0/1; actions/read models no longer label the failed background job successful; foreground Bash without a completion notification remains exit_code=NULL; malformed or version-drifted notifications degrade to unknown rather than guessed prose; deleting correlation or exit-code extraction makes the behavioral test fail; the qqyg design record is corrected with the narrower evidence boundary.","notes":"Recovered after terminal reboot from Codex session 019f528f-4d3a-7240-a550-02d2014178ba. Raw session: /home/sinity/.codex/sessions/2026/07/11/rollout-2026-07-11T21-02-30-019f528f-4d3a-7240-a550-02d2014178ba.jsonl. Polylogue currently classifies that interrupted worker error_left, but its final recovery report established the Claude raw event shape and absence of repo edits.\n2026-07-12 Terra lane: isolated worktree /realm/worktrees/polylogue-t0p1, branch feature/fix/claude-background-outcomes. Own Claude background notification parsing/correlation/outcome tests and qqyg evidence correction; avoid storage authority and devtools timeout-policy files. Coordinator reviews/merges.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T20:31:24Z","created_by":"Sinity","updated_at":"2026-07-12T00:02:02Z","started_at":"2026-07-11T23:09:59Z","closed_at":"2026-07-12T00:02:02Z","close_reason":"Merged PR #2722 (b8a1acba7): live-shape Claude background completion outcomes projected through actions and durable events; 19 focused tests and final adversarial pass.","labels":["area:ingest","area:insights","area:sources","area:test","delivery:K-interop-origin-export","discovered-from:recovery","lane:origin-interop-export"],"dependencies":[{"issue_id":"polylogue-t0p.1","depends_on_id":"polylogue-qqyg","type":"relates-to","created_at":"2026-07-11T22:31:24Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-t0p.1","depends_on_id":"polylogue-t0p","type":"parent-child","created_at":"2026-07-11T22:31:23Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-yla8.7","title":"Expose raw frontier integrity in readiness","description":"Process health and raw-materialization candidate counts can both be green while an accepted append head references a deleted predecessor or an ingest cursor is ahead of accepted material. yla8.6 discovered this only through operator SQL after ordinary use broke. Make these authority gaps a standing, queryable readiness signal rather than a one-off repair script.","design":"Add one substrate integrity projection over the real split source/index/ops tiers. Report counts and bounded typed samples for: current accepted append heads whose transitive predecessor chain is missing or invalid; sessions.raw_id absent from source; and cursors whose committed byte frontier exceeds accepted material for that logical source. Reuse the same chain validator owned by yla8.6 so health and cleanup cannot drift. Surface through existing daemon/status readiness payloads and devtools validation; do not add a parallel repair executor. Healthy means proven zero, unavailable authority means unknown/degraded, never zero.","acceptance_criteria":"1. A registry-backed integrity check queries real source/index/ops tiers and returns typed healthy, degraded/unknown, or violated state with bounded samples and total counts. 2. Fixtures cover missing accepted predecessor, broken contiguity/baseline/generation, missing sessions.raw_id, cursor-ahead material, unreadable tier, and a valid full-plus-three-append chain. 3. Removing predecessor traversal, either index seed, or ops cursor comparison makes focused tests fail. 4. Existing daemon/status and devtools readiness surfaces expose the same projection without duplicating SQL/semantics; unavailable authority cannot render green. 5. Runtime cost is measured on the live archive and bounded for ordinary status use; exact focused tests and devtools verify --quick pass.","notes":"2026-07-12 takeover audit: quota-interrupted staged patch preserved as local WIP commit ce650bb2d on feat/raw-frontier-integrity-readiness; focused receipt 20260712T054815Z-focused-test-1027762-dd643cbc shows 264/264 passed. Not publication-ready: zero-head/unreadable-ops cursor authority can false-green; unmapped heads are skipped; daemon/direct status duplicate aggregation semantics; registry/devtools AC is absent; mixed violated+unknown precedence is unresolved; missing anti-vacuity/live-cost fixtures. Ordinary push was attempted only to back up the commit and correctly rejected by pre-push quick run 20260712T084345Z-quick-1128853-50d35a7f: degrade-loudly found three unlogged soft-fail handlers at daemon/status.py:2045 and storage/raw_retention.py:542,586. Hook was not bypassed; branch/worktree remain local and preserved for a completion pass.\n2026-07-12 completion pass after rebasing local WIP onto origin/master: canonical raw_frontier_integrity_projection now owns split-tier reads, violated-over-unknown precedence, missing-source composition, and daemon/direct/readiness semantics. Cursor comparison always opens readable ops even with zero heads, scans all non-excluded committed cursors, distinguishes membership-only paths, and surfaces uncomparable cursor/head authority as typed bounded gaps instead of skipping them. ReadinessReport registers the same named check; unavailable authority cannot green and a proven violation remains visible when a sibling is unknown. Verification: 186 focused tests passed in 179.49s; devtools verify --quick run 20260712T123424Z-quick-2641539-4a547f20 passed all 15 gates. Live read-only measurement on /home/sinity/.local/share/polylogue: 1003.389ms cold, 263.161/262.230ms warm; 17,718 heads checked; overall violated with 15 cursor-ahead rows, 181 cursor comparisons, 152 authority gaps, zero broken heads and zero missing source raws. This slice reports those live gaps and does not repair them.\n2026-07-12 adversarial closure pass 1 repaired five real gaps plus one automated-review gap. Byte heads now validate the exact retention source-binding invariant before chain traversal; top-level daemon/direct/minimal status cannot green when authority is unknown or violated; daemon and direct claim summaries share one canonical helper; lost-source composition is protected through canonical generated-column DDL; cursor totals now distinguish distinct cursor rows from cursor/head comparisons; semantic-only heads have an explicit non-comparison fixture; runtime-only readiness reports mark archive convergence unchecked rather than converging. A canonical-DDL test exposed and fixed archive_readiness column introspection (PRAGMA table_xinfo is required to see generated sessions.session_id and preserve lost-evidence samples). Verification: raw-retention receipt 20260712T125801Z-focused-test-2658666-2a1e4126 = 57 passed in 113.31s; cross-surface selector = 155 passed/1 intentionally changed stale expectation, then exact corrected route 1 passed in 1.05s; devtools verify --quick 20260712T130412Z-quick-2662961-b80071de = 15/15. Post-repair live read-only measurement: 1395.968ms cold, 278.532/270.295ms warm over 17,718 heads; 3 invalid byte-head/source bindings, 15 distinct cursor-ahead rows across 15 comparisons, 181 comparable cursor rows/comparisons, 152 authority gaps, zero missing source raws. Reporting only; repair remains with yla8/yla8.6.\n2026-07-12 adversarial closure pass 2 repaired four real gaps at commit 7b799c91d: cached fresh/legacy/stale payloads now normalize through one fail-closed authority boundary; full, compact, text, component, top-level ok, and existing converged claims cannot remain green without a fresh complete projection; source schema/query failures are unknown rather than fake violations; and readiness traverses the same deduplicated sessions.raw_id plus raw_revision_heads seed union as retention, including session-only broken predecessor chains. Verification: targeted regression selector 11 passed; full raw-retention file 59 passed in 119.39s; affected cross-surface selector 159 passed with three intentional full-status contract updates, then those exact three passed in 2.65s; devtools verify --quick 20260712T134057Z-quick-2857302-6edc6012 passed 15/15. Post-repair live read-only measurement: 1130.902ms cold and 266.659/276.331ms warm over 17,619 distinct active seeds; overall violated with 3 broken seeds, 15 cursor-ahead rows across 15 comparisons, 181 comparable cursor rows/comparisons, 152 cursor/head authority gaps, and zero missing source raws. Reporting only; repair remains with yla8/yla8.6.\n2026-07-12 adversarial closure pass 3 repaired five real gaps at commit 4c877ec07: cached authority now validates the complete projection schema, nonnegative count relationships, bounded samples, availability/detail consistency, and derived violated-over-unknown precedence; malformed counts degrade to explicit unknown instead of raising; daemon/network adapters require complete fresh snapshot provenance while direct SQLite status declares live provenance; the HTTP contract pins frontier/snapshot/component/claim behavior; and /api/status ETags include normalized snapshot identity/state so unchanged event IDs cannot retain stale or newly violated green bodies through 304 responses. Verification: targeted production-route selector 16 passed in 20.22s; broader affected selector 224 passed with one inherited failure, polylogue-nu2h test_server_close_shuts_down_archive_query_executor, which reproduced alone and is untouched by this diff; final provenance selector 7 passed in 1.01s; devtools verify --quick 20260712T141036Z-quick-2930129-da084f89 passed 15/15. Live frontier scan semantics and prior 17,619-seed timing/results are unchanged.\n2026-07-12 adversarial closure passes 4-5: pass 4 found five legitimate fail-closed gaps. Commit cd2d4ed06 preserves the most severe declared/derived aggregate, rejects impossible cursor cardinalities, requires finite/parseable/bounded freshness with refresh-error consistency, includes live writer-coordinator state in status ETags, and propagates lost-source count failures to the existing unavailable-authority boundary; excluded cursors are explicitly quarantined rather than active frontier authority. Six targeted regressions passed in 3.91s; affected readiness/events/storage files passed 71/71 in 79.48s; quick run 20260712T144210Z-quick-2961392-d6fb14bc passed 15/15 and committed-head pre-push quick 20260712T144322Z-quick-2962398-4d4f408e passed 15/15. Final adversarial iteration 5 found no storage/AC gaps, then identified one replay boundary: a decades-old captured_at could pair with age_s=0. Commit 2fd1e3513 cross-checks wall-clock age against reported age under the same 30s ceiling and a 5s skew tolerance; the stale-replay regression passes, the full capability file passes 29/29, and quick run 20260712T145008Z-quick-2966699-bcde5254 passes 15/15. The five-iteration adversarial cap is exhausted; every reported finding is repaired with a production-route regression. CodeRabbit product-facade and required-component findings were fixed at eb8164116 and all substantive threads are resolved.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T16:12:39Z","created_by":"Sinity","updated_at":"2026-07-12T15:01:28Z","started_at":"2026-07-12T05:22:52Z","closed_at":"2026-07-12T15:01:28Z","close_reason":"Satisfied all five acceptance criteria in PR #2762 (merge 6b386d9e1): canonical split-tier projection, fail-closed status integration, anti-vacuous fixtures, live cost measurement, and five-pass adversarial repair evidence are recorded.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","horizon:near","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-yla8.7","depends_on_id":"polylogue-yla8","type":"parent-child","created_at":"2026-07-11T18:12:38Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-lxyt","title":"Test harness must be un-orphanable: pytest-timeout defaults + wall-clock cap + process-group cleanup in devtools runner","description":"Root-cause fix from the sinnix 2026-07-11 shadow-load forensics (sinnix-v83): a codex agent scope hosted a polylogue pytest-xdist swarm that stayed resident ~35h (peak 7.3G PSS + ~6G swap) after its run wedged/orphaned, degrading the whole machine until reboot. Defense at the source, so undead test swarms cannot form: (1) pytest-timeout as a default dep with a per-test timeout (e.g. 300s) in pyproject/pytest.ini so no test hangs forever; (2) a wall-clock cap on the whole run in the devtools pytest runner (the 'python -m pytest -p devtools.pytest_progress_plugin ...' path) — e.g. SIGTERM the session after N minutes, SIGKILL after N+2; (3) the runner must spawn workers in its own process group and trap EXIT/TERM to kill the group, so an interrupted/killed parent cannot leave xdist workers behind; (4) verify -n workers die when the controller dies (xdist should, but the 07-10..11 evidence says something survived — reproduce and pin). Acceptance: kill -9 the pytest controller mid-run -> zero surviving test processes after 5s; a deliberately hanging test fails at the timeout instead of wedging the run.","design":"Use three independent containment layers. (1) Configure pytest-timeout with a documented default and narrow marker-based exceptions so one test cannot hang indefinitely. (2) Make the devtools runner an external supervisor that launches pytest in a new session, enforces a whole-run deadline, sends SIGTERM to the child process group, then SIGKILL after a bounded grace period, while preserving progress/output artifacts. (3) Put the supervised run in a transient systemd scope/cgroup with KillMode=control-group and RuntimeMaxSec (or an equivalent parent-death/cgroup mechanism), because an EXIT trap inside the pytest controller cannot run after SIGKILL and therefore cannot satisfy the orphan case by itself. Reproduce controller death with xdist workers and assert against process/cgroup identity, not name-only pkill scans.","acceptance_criteria":"1. pytest-timeout is a normal test dependency with a 300-second repository default; longer exceptions remain explicit at their test or managed-command site. Automated override linting is deferred to polylogue-c3qh.\n2. The devtools test runner enforces a configurable whole-run deadline, terminates the pytest process group, escalates after a bounded grace period, and records timeout/termination evidence in the normal verify artifacts.\n3. Killing the pytest controller with SIGKILL during a multi-worker fixture leaves zero processes in the owned cgroup/session within 5 seconds; the regression proves this without touching unrelated pytest processes.\n4. A deliberately hanging test exits nonzero at the per-test timeout, and a deliberately overlong run exits nonzero at the run deadline; both retain the responsible node/run diagnostics.\n5. Focused runner/containment tests and devtools verify --quick pass; one manual cgroup/process-tree receipt is attached to Bead notes.","notes":"2026-07-11 coordination correction: an in-process EXIT/TERM trap cannot clean workers after controller SIGKILL. The acceptance test therefore requires an external supervisor plus cgroup/session ownership; process-group cleanup remains the graceful path, not the ultimate containment boundary.\n2026-07-11 parallel lane: isolated worktree /realm/worktrees/polylogue-lxyt, branch feature/test/orphan-proof-runner. Own devtools runner/pytest containment only; production append/CAS lane is disjoint.\n2026-07-11 implementation scope (/realm/worktrees/polylogue-lxyt): implement the complete devtools pytest containment slice on feature/test/orphan-proof-runner. Owned surfaces are pytest dependency/default timeout policy, the external devtools pytest supervisor and its existing verify artifacts, and focused regression fixtures that identify only the supervisor-owned process group/cgroup. The graceful path terminates the owned process group; the SIGKILL-proof path relies on an external transient cgroup/scope with control-group kill semantics. Non-goals: production daemon/runtime behavior, ambient pytest discovery, name-based pkill, or modifying unrelated processes. Verification will exercise the real runner path, prove per-test and whole-run deadlines retain diagnostics, prove controller SIGKILL drains the owned boundary within 5s, run devtools verify --quick, and attach a manual process-tree/cgroup receipt.\n2026-07-11 manual containment receipt (production supervisor, actual pytest -n 2): unit polylogue-pytest-manual-receipt-481163-12878539114279.scope in /user.slice/user-1000.slice/user@1000.service/build.slice; systemd properties KillMode=control-group, RuntimeMaxUSec=35.250000s, TimeoutStopUSec=250ms. Owned process identities before controller death were supervisor 481166, pytest controller 481167 (pgid/sid 481167), xdist workers 481181 and 481184, and signal-resistant descendant 481216 in the same pgid/cgroup. Sent SIGKILL only to recorded controller PID 481167. External supervisor receipt: controller_returncode=-9, signals_sent=[SIGTERM,SIGKILL], escalated_to_sigkill=true, controller_group_alive=false, supervisor exit=137. The exact owned cgroup process set was [] after 2.66s, within the 5s AC; no process-name scan or ambient pytest signal was used. Focused proof command: devtools test tests/unit/devtools/test_verify.py::test_pytest_run_terminates_after_runtime_budget tests/unit/devtools/test_verify.py::test_pytest_run_emits_heartbeat_for_long_silent_child tests/unit/devtools/test_pytest_supervisor.py::test_controller_sigkill_clears_exact_owned_xdist_cgroup -n 0 -> 3 passed in 5.13s. Earlier complete targeted selection -> 8 passed; devtools verify --quick -> exit 0, 13/13 steps green in 22.46s.\n2026-07-11 final implementation evidence: AC1 satisfied: pytest-timeout remains a normal dev dependency and pyproject config sets timeout=300 with signal method; the policy regression reads the production pyproject. AC2 satisfied: devtools test and verify launch pytest through the external supervisor, enforce one absolute startup/run deadline, TERM the exact owned group, KILL after a bounded grace, and publish containment receipts in step and current artifacts. AC3 satisfied: real pytest -n 2 regressions kill the controller or owner with SIGKILL and prove exact recorded identities plus the owned cgroup are empty under one monotonic 5-second deadline while an unrelated sentinel remains live; Linux process-group fallback also covers an escaped setsid descendant. AC4 satisfied: real runner tests prove pytest-timeout and whole-run startup/runtime failures are nonzero and preserve node/run diagnostics. AC5 satisfied: devtools test tests/unit/devtools/test_pytest_supervisor.py tests/unit/devtools/test_verify.py tests/unit/devtools/test_run_tests.py -n 0 collected 83 and passed 83 in 26.24s; devtools verify --quick run 20260711T180339Z-quick-529037-30556cf4 passed 13/13 steps in 19.61s; bd-graph-lint reports zero cycles/violations; post-run systemd and process scans were empty. Manual cgroup receipt is attached above. Anti-vacuity: production dependency exercised is devtools test -> run_tests.main -> verify._run -> _run_pytest_with_heartbeat -> build_supervisor_launch -> pytest_supervisor.supervise -> actual pytest/xdist under systemd or the Linux process-group fallback. Removing timeout config breaks the policy and per-test proof; removing owner/pidfd identity checks breaks owner/reuse proofs; removing supervisor, outer deadline, group/subreaper, or cgroup cleanup leaves live identities in controller/owner/supervisor/escaped-child proofs; removing artifact publication breaks artifact equality; removing the inherited-pipe bound makes the held-pipe proof overrun. Adversarial review ran five independent gpt-5.6-terra high-effort iterations. Iteration 1 found post-supervisor pipe drain, raw PID/PGID reuse, owner-death, and current-receipt proof gaps; fixed with bounded drain, pidfd/start-tick identity checks, owner SIGKILL coverage, and artifact equality. Iteration 2 found late owner identity capture, missing outer deadline after supervisor death, non-Linux overclaim, and no automatic scope-launch fallback; fixed with pre-launch identity capture, runner deadline, explicit Linux contract, and tested retry. Iteration 3 found startup time outside the deadline and escaped setsid fallback descendants; fixed with startup-bounded artifacts and runner subreaper descendant cleanup. Iteration 4 found one real raw receipt-publication cleanup signal path, now identity checked and regression tested; its uv.lock finding was baseline, reproduced unchanged from HEAD because this diff touches pytest tool config but no dependency metadata. Iteration 5 found the controller-SIGKILL test used sequential 5-second waits; fixed to share one monotonic 5-second deadline and the 83-test affected set passed afterward. The iteration cap was reached, so this final fix has publish-gate evidence but no sixth independent review.\n2026-07-11 publication: commit 73cf1168b5c684d4dae031911d827594bf09a598 pushed on feature/test/orphan-proof-runner; PR #2714 opened at https://github.com/Sinity/polylogue/pull/2714 and intentionally left unmerged with CI pending. Bead remains in_progress until merge.\n2026-07-11 review correction: AC1 previously said timeout exceptions were lintable, but the branch only establishes the bounded default and explicit override mechanism. The separate static/AST quick-gate policy is now tracked by polylogue-c3qh; this Bead no longer claims it shipped.\n2026-07-11 sixth-review remediation (commit c4f4fd01e, PR #2714): fixed two release blockers and two claim/prerequisite gaps. A successful controller can no longer mask incomplete cleanup: any surviving exact owned identity forces exit 125/status=terminated. Fallback recovery snapshots exact pre-existing runner descendant roots and excludes their subtrees, while still killing the run controller group, supervisor, and newly adopted descendants; the real xdist supervisor-SIGKILL regression now proves an unrelated runner child remains alive. Runner and supervisor refuse launch without exact /proc owner identity and Linux child-subreaper support. The previously claimed timeout-override lint was not present, so AC1 was narrowed honestly and the quick/static AST policy is tracked by polylogue-c3qh. Verification: full supervisor proof file 17 passed in 15.67s; six focused verify heartbeat/runtime/stall proofs passed in 4.17s; final exact fallback sentinel proof passed in 6.15s; strict mypy passed; devtools verify --quick run 20260711T185456Z-quick-611461-e7b27a51 passed 13/13 in 18.94s; bd-graph-lint clean; no polylogue-pytest systemd units remained. Anti-vacuity: deleting the final residue-to-125 branch makes the injected successful controller green with controller_group_alive=true; deleting preserved_roots kills the pre-existing sentinel; deleting either prerequisite gate creates the controller-start marker.\n2026-07-11 CI classification for c4f4fd01e: all GitHub-hosted checks failed before runner allocation with zero steps/runner_id=0. Check annotations say the account is locked due to a billing issue. This is external infrastructure state; PR #2714 comment https://github.com/Sinity/polylogue/pull/2714#issuecomment-4948376104 records the evidence. No merge attempted.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T14:43:19Z","created_by":"Sinity","updated_at":"2026-07-11T21:38:42Z","started_at":"2026-07-11T16:38:02Z","closed_at":"2026-07-11T21:38:42Z","close_reason":"PR #2714 merged as cd841647e; managed pytest subprocesses now run in a dedicated process group with bounded termination and orphan-proof focused coverage. Local focused verification and quick gates passed before merge.","labels":["area:devtools","area:test","delivery:A-trust-floor","horizon:frontier","lane:test-infrastructure"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-5k5l.1","title":"Authenticate ChatGPT interpreter assets before classifying them expired","description":"Live 2026-07-11 recovery disproved the browser-capture conclusion that the ten GPT-Pro branch packages had expired. The extension/capture acquisition path recorded 403 outcomes, while an authenticated background ChatGPT conversation API request using the current bearer token recovered most of the same interpreter files (34.8 MB total). The path is producing false missing-byte evidence by omitting or mishandling the authenticated download contract.","design":"Reuse the authenticated ChatGPT application contract without persisting bearer tokens: resolve the current access token inside the trusted page/extension boundary, request `/backend-api/conversation//interpreter/download` with Authorization, handle both direct JSON error envelopes and signed `download_url` responses, then acquire signed bytes immediately. Preserve explicit `ace_pod_expired` and `Interpreter file not found` as distinct terminal outcomes. Never log/tokenize/store the bearer. Add a live-capable synthetic adapter fixture plus a response matrix for 401 missing token, 200 signed URL, 200 `ace_pod_expired`, 404 missing file, signed-URL 403, and successful SHA-256 acquisition.","acceptance_criteria":"1. A capture of a conversation with a live interpreter artifact acquires bytes and records the true SHA-256 without persisting or logging credentials. 2. The same endpoint matrix distinguishes unauthorized, pod-expired, interpreter-missing, signed-URL-expired, and acquired states. 3. A regression fails under the previous unauthenticated request behavior. 4. Re-capturing one surviving GPT-Pro branch package through the extension produces acquired bytes matching the independently recovered SHA-256. 5. Focused extension/parser tests and browser-capture smoke pass.","notes":"2026-07-11 parallel lane: isolated worktree /realm/worktrees/polylogue-chatgpt-asset-auth, branch feature/fix/chatgpt-asset-auth. Own authenticated interpreter-asset acquisition/browser capture only.\n[2026-07-11 implementation scope] Own the ChatGPT MAIN-world asset bridge and its isolated-content outcome propagation. Resolve the current `/api/auth/session` access token with the legacy bootstrap only as a trusted fallback; keep bearer and signed URLs ephemeral inside the page bridge. Send Authorization only to same-origin ChatGPT metadata endpoints and never to signed storage URLs. Emit credential-free typed outcomes for unauthorized, pod-expired, interpreter-missing, signed-URL-expired, too-large, transport/contract failure, and acquired; acquired results carry deterministic SHA-256 and bounded size. Preserve the existing parser/CAS path and stable provider_attachment_id contract for re-capture idempotency. Non-goals: receiver auth, storage schema, outbound posting, or changing file-service identity. Proof: production bridge response matrix, explicit unauthenticated-source mutation, credential non-disclosure assertion, deterministic recapture hash, focused extension/parser tests, browser smoke, and quick gate; attempt a private-background live re-capture only if a safely reloadable agent extension target is available.\n[2026-07-11 implementation evidence] Draft PR #2712 at commit a3e0f1fd4 implements current-session bearer resolution, same-origin authenticated metadata requests, credential-free signed-URL follow-up, typed unauthorized/pod_expired/missing/signed_url_expired/acquired outcomes, SHA-256 receipts, size caps, stable repeat-capture identity, and exact-conversation passive capture. Evidence: 30 focused extension tests; production-source mutation without Authorization changes acquired -> unauthorized/401; 2 parser/CAS tests independently prove acquired bytes -> true stored SHA-256; ESLint + manifest; isolated Chromium MV3 receiver smoke (401/200/202, ok=true); pre-push quick gate 13/13. Private headless ChatGPT proof loaded the worktree extension but remained at Cloudflare `Just a moment...` for 20s; private browser was stopped without exposing credentials. AC4 live package re-capture and AC1 live-environment receipt remain on this bead and are not claimed by the PR.\n[2026-07-11 CI follow-up] GitHub Node 20 exposed a test-only jsdom cross-realm ArrayBuffer incompatibility in the Web Crypto adapter. Commit 8a4c519b2 converts fixture bytes into the host realm before invoking real Web Crypto. Full extension suite now passes locally: 7 files / 117 tests; ESLint and pre-push quick 13/13 green. PR #2712 body updated with this evidence.\n[2026-07-11 contract audit] Commit ffd4d6bb2 makes `/api/auth/session` authoritative and retains `client-bootstrap` only as a tested fallback, preventing a stale bootstrap bearer from overriding the current page token. The production harness now pins `message_id`, `sandbox_path`, auth-session credentials, metadata bearer, signed-fetch credential omission, current-over-stale precedence, and fallback behavior. Full extension suite: 7 files / 119 tests; pre-push quick 13/13.\n2026-07-12 takeover completion: merged PR #2712 as 8c23ba218. Live visible-private ChatGPT proof discovered and fixed two additional production bugs: unordered full-mapping discovery let stale off-branch assets trip the breaker before the current node (cfeb79e2a), and current same-origin /backend-api/estuary/content byte URLs require page cookies even though cross-origin signed URLs must remain credential-free (aedb2760b). Final extension capture of fresh conversation 6a5350db-c1d8-83ed-9976-035227280d5e: native_full, 6 turns, 2 acquired/0 failed, both 848460 bytes, SHA-256 40fa31aeccd41a8c61e3bbe5d721d1f5395cc4f14c7411f94663b777a23eef77, exact match to independently recovered Demo Packet ZIP; receiver request polylogue-ext-mrhjgnkn-hzbd33l3. Original 6a5112f5 pod was attempted first after ordering fix and is genuinely expired (fresh metadata URL, byte 403). Browser/receiver slice is complete. Do not close yet: source.db retained prior 31,884-byte quarantined raw a7d004c9... while the replaced 2.3 MB acquired envelope is preserved in receiver storage, so index attachment rows remain unfetched. Follow-up polylogue-57rp owns typed raw-authority reacquisition/materialization; parent 5k5l retains broader file-service/end-to-end scope. Verification: npm test 7 files/121 tests, npm lint, manifest validate, pre-push quick 13/13 run 20260712T083505Z-quick-1122043-a123e4ab.\n2026-07-14 status check as part of the raw-identity-repair cluster (PR #2877): this bead's own scope (authenticated ChatGPT interpreter-asset acquisition, extension-side) is complete per its notes -- PR #2712 (8c23ba218) merged, live visible-private ChatGPT proof recorded (native_full capture, 2 acquired/0 failed, exact SHA-256 match to independently recovered bytes). The one remaining item its notes flag (\"source.db retained prior quarantined raw a7d004c9..., index attachment rows unfetched\") is explicitly and correctly assigned to polylogue-57rp (\"Follow-up polylogue-57rp owns typed raw-authority reacquisition/materialization\"), not to this bead. No code gap specific to 5k5l.1 was found; no PR-2877 commit touches its scope (extension/browser-bridge code, outside this session's Python-storage-layer investigation).","status":"open","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-11T11:58:48Z","created_by":"Sinity","updated_at":"2026-07-14T01:07:02Z","started_at":"2026-07-11T16:38:04Z","labels":["area:browser","area:sources","area:test","horizon:frontier"],"dependencies":[{"issue_id":"polylogue-5k5l.1","depends_on_id":"polylogue-5k5l","type":"parent-child","created_at":"2026-07-11T13:58:48Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-n2wy","title":"Serialize daemon archive writers across watcher and maintenance loops","description":"Live dogfood on 2026-07-10 proved intra-daemon writer contention. While periodic raw materialization processed 23 raw rows / 121.3 MiB with FTS triggers suspended, LiveWatcher append ingestion opened an independent ArchiveStore connection and failed after the 30s busy timeout with sqlite3.OperationalError: database is locked (append_ingest.py -> write_parsed_session_to_archive). Readiness stayed 503 fts_not_fresh during the bulk transaction. The process remained live and the cursor appears retryable, but a single-writer daemon must serialize its own write actors rather than make them contend through SQLite timeouts. Scope must cover watcher append/full paths and all daemon maintenance actors that mutate source/index/embeddings/ops/user tiers, without blocking HTTP read surfaces. AC: (1) deterministic concurrency harness reproduces watcher-vs-raw-materializer collision before fix; (2) one explicit daemon write coordinator prevents overlapping archive write critical sections; (3) queued live appends retry promptly and cursor/raw parse state cannot advance on failed persistence; (4) readiness/FTS freshness recovers after the bulk writer exits, including exception/cancellation paths; (5) telemetry exposes wait/hold time and actor identity so future contention is attributable; (6) focused tests prove no deadlock and bounded shutdown/cancellation. Dogfood evidence: polylogued-final-runtime.service invocation eacf5185c4684d48b3b0902ac096f40a, 20:04:48 bulk batch start, 20:06:10 append failure, index WAL 98.6 MiB.","acceptance_criteria":"1. A deterministic concurrency harness reproduces watcher-vs-raw-materializer overlap before the fix without relying on sleep timing. 2. One explicit daemon write coordinator prevents overlapping archive write critical sections across watcher append/full paths and maintenance writers, while HTTP read surfaces remain available. 3. Queued live appends retry promptly and cursor/raw parse success cannot advance on failed persistence. 4. FTS trigger/freshness state recovers after bulk success, exception, and cancellation; readiness returns without restart. 5. Telemetry exposes writer actor plus queue wait and hold duration. 6. Focused tests prove fairness/no starvation, no deadlock, and bounded shutdown cancellation; devtools verify --quick passes.","notes":"2026-07-10 candidate review: local commit 4033cf411 and both Codex Cloud attempts are blocked. Local blockers: raw acquisition followed by locked index persistence can still reconcile cursor to EOF from an unparsed raw row; HTTP maintenance/reset/user/OTLP writers bypass the loop-local coordinator; cancellation drain is unbounded; ContextVar child-task inheritance bypasses serialization; production telemetry is not operationally exposed; harness does not prove production wiring. Cloud attempt 1 has partial process-global wiring but no safe reentrancy/cursor closure/bounded cancellation; attempt 2 can block the event loop and releases its gate while shielded work continues. Salvage only test scaffolds/gateway boundary ideas.\n2026-07-10 fresh-master integration at branch feature/fix/daemon-writer-serialization now combines: process-wide FIFO/task ownership and telemetry; admitted-cancellation retention; cursor raw/index retry correctness; HTTP reset/ingest/maintenance/user/OTLP bridge; bounded shutdown; lifecycle coordination and pidfile retention; read-only event/status ops access; coordinated watcher initialization/prefilter/defer/retry writes. Commits through 8b33c1344; quick gate 13/13. Independent adversarial iteration 2 is in progress before publication. Live service remains stopped.\n2026-07-10 closure: PR #2676 merged as 29e5b455. Process-wide FIFO/task-owned coordination now covers watcher append/full, cursor init, convergence/compaction, maintenance/lifecycle, HTTP mutations, and real FTS/lineage startup writers. Independent Terra adversarial review found default-executor process-exit gaps; repaired with dedicated daemon-thread run_sync routes and subprocess anti-vacuity tests that hang under the old route. Verification: coordinator+watcher 21 passed; daemon startup/shutdown 2 passed; append batching 1 passed; devtools verify --quick 13/13; CI green. Standalone bridge-less HTTP is test/visual-only; production injects the shared bridge.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T18:08:11Z","created_by":"Sinity","updated_at":"2026-07-10T21:13:47Z","started_at":"2026-07-10T20:23:52Z","closed_at":"2026-07-10T21:13:47Z","close_reason":"Merged PR #2676 (29e5b455): serialized daemon writers with real-route cancellation/process-exit proofs and green publish gates.","labels":["area:daemon","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine"],"dependencies":[{"issue_id":"polylogue-n2wy","depends_on_id":"polylogue-b5l.1","type":"relates-to","created_at":"2026-07-10T20:08:36Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-n2wy","depends_on_id":"polylogue-yla8","type":"relates-to","created_at":"2026-07-10T20:48:42Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-6jjv","title":"Bootstrap first-party web credentials across fetch and SSE","description":"The current first-party shell is served without authentication, requestJSON sends no credential, and API routes require bearer auth. Unit tests separately prove shell 200 and API 401 but no browser executes the composed flow, so the workbench can load while its own API interactions fail.","design":"Define one first-party bootstrap contract for generated client/fetch/EventSource or its authenticated replacement. Deliver a short-lived scoped credential without exposing it in URL, DOM, console, referrer, history, screenshots, or logs; rotate/revoke cleanly; keep remote/untrusted origins denied. The same contract must survive v2/ASGI migration and browser-capture separation rather than being hardcoded into the old shell.","acceptance_criteria":"A real Playwright journey loads the shell and completes authenticated list/read/mutation plus live reconnect. Missing, expired, revoked, and wrong-origin credentials yield explicit recoverable states. Leak sentinels inspect URL/history/DOM/console/network metadata/server logs and find no secret. Removing auth transport or origin checks fails mutation tests. HTTP security, SSE/client, and browser journeys plus verify --quick pass.","notes":"2026-07-11 parallel lane: isolated worktree /realm/worktrees/polylogue-web-auth, branch feature/fix/web-first-party-auth. Own first-party web credential/bootstrap and Playwright proof only.\n2026-07-11 implementation scope: introduce a daemon-owned, reusable first-party credential contract (not an old-shell-only token shim): short-lived digest-only HttpOnly cookie credentials bound to the exact same origin and explicit read/mutation/events scopes; rotate through a same-origin bootstrap endpoint and revoke without URL/body exposure. Preserve configured bearer-token clients. Adapt current requestJSON/EventSource only as consumers so the same contract is available to bby.11 generated fetch/live clients. Browser proof owns seeded list/read/mark mutation/SSE reconnect, missing/expired/revoked/wrong-origin states, and leak sentinels over URL/history/DOM/console/referrer/resource metadata/server logs. Non-goals: build the v2 Preact scaffold, migrate unrelated standalone pages, or change browser-capture authentication.\n2026-07-11 implementation + verification closeout (pre-PR):\nScope correction: the shipped browser scopes are read/events/user_state, not a generic mutation capability. Reset, ingest, and maintenance remain machine-bearer-only when daemon auth is configured.\n\nAcceptance matrix:\n- SATISFIED real journey: tests/browser/web_auth_server.py seeds a deterministic demo archive and serves the production DaemonAPIHTTPServer; webui/tests/first-party-auth.spec.ts proves authenticated list/read, persisted mark mutation, history navigation, and a forced real SSE reconnect.\n- SATISFIED lifecycle: runtime and tests cover missing, invalid/malformed, expired, revoked, wrong-origin, and insufficient-scope decisions; bootstrap rotates and revoke clears the protected cookie.\n- SATISFIED credential boundaries: opaque 256-bit values are returned only in HttpOnly SameSite=Strict cookies, stored digest-only, exact-origin-bound, short-lived, globally/per-origin bounded, and denied from archive control routes.\n- SATISFIED leak posture: known credential query parameters are rejected before dispatch; route identity and disconnect logs retain path only; Playwright scans URL/history/DOM/resources/navigation/console/referrer/non-cookie request metadata/server stdout+stderr/screenshot bytes. Cookie and Set-Cookie are the intentionally protected transport.\n- SATISFIED anti-vacuity: the browser journey depends on the production cookie transport for fetch/EventSource and on exact-origin validation for user-state mutation; removing either turns asserted successful operations into 401/403 and fails the journey.\n- SATISFIED contracts/automation: typed OpenAPI operations publish bootstrap/revoke lifecycle, protected error states, machine-bearer/cookie alternatives, and Set-Cookie headers; the locked Playwright workspace is wired into CI and documented.\n- INTENTIONALLY EXCLUDED per scope: v2 Preact scaffold, unrelated standalone-page migration, and browser-capture authentication.\n\nVerification:\n- devtools test tests/unit/daemon/test_web_auth.py tests/unit/daemon/test_daemon_http_security.py tests/unit/daemon/test_route_contracts.py tests/unit/daemon/test_daemon_events_endpoint.py tests/unit/daemon/test_http_write_coordination.py tests/unit/daemon/test_web_shell_endpoint_contracts.py tests/unit/devtools/test_render_openapi.py -> 674 passed in 112.87s.\n- cd webui && npm run test:e2e -> 2 passed in 13.0s.\n- devtools verify --quick -> all 13 steps passed, run 20260711T180603Z-quick-531716-ec1ae420.\n- .agent/scripts/bd-graph-lint -> no cycles; 0 duplicate-label, inversion, or missing-AC violations.\n\nAdversarial review record (5 independent cold iterations, cap reached):\n1. Found browser access to destructive controls, unbounded registry growth, and metadata-only OpenAPI; fixed with bearer-only controls, hard record caps, and typed real operations.\n2. Found malformed non-ASCII cookie failure, bootstrap 403 drift, and missing automated browser lane; fixed with total validation, normalized typed admission failures, CI/docs.\n3. Found query credential echo potential and incomplete OpenAPI cookie/revocation security; fixed with pre-dispatch query rejection and complete schemes/headers.\n4. Found noncredential query values retained in route metadata and missing typed auth responses on protected reads; fixed with path-only identity and generic-or-web-state 401/403 contracts.\n5. Found security docs omitted the implemented invalid lifecycle state; fixed in docs/security.md and docs/daemon-threat-model.md after the iteration-five cap. No sixth review was run, so this is reported as cap-reached, not convergence.\n2026-07-11 PR opened: https://github.com/Sinity/polylogue/pull/2715 at f6e57609b44c41c1a9bfd78a834c06a9cb8c8e5d. Remote diff matches the intended 27-file scope; CI is running. This worker will not merge.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T17:06:09Z","created_by":"Sinity","updated_at":"2026-07-11T18:11:10Z","started_at":"2026-07-11T16:38:07Z","closed_at":"2026-07-11T18:11:10Z","close_reason":"Implemented first-party fetch/SSE credential bootstrap and real browser proof in PR #2715; 674 affected backend tests, 2 Playwright journeys, quick verification, and Beads graph lint pass.","labels":["area:security","area:web","delivery:H-web-cockpit","lane:web-evidence-cockpit"],"dependencies":[{"issue_id":"polylogue-6jjv","depends_on_id":"polylogue-1ilk","type":"relates-to","created_at":"2026-07-10T19:06:15Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-6jjv","depends_on_id":"polylogue-bby","type":"parent-child","created_at":"2026-07-10T19:06:12Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-6jjv","depends_on_id":"polylogue-bby.11","type":"relates-to","created_at":"2026-07-10T19:06:16Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-b2r9","title":"Preserve unknown and approximate embedding status semantics","description":"Live source-v4 dogfooding showed two false precision signals: archive debt renders an unavailable pending-message count as 0, while detailed embedding status divides an embedded-message counter by a non-exact sqlite_stat1 candidate estimate and reports 103.5% coverage. These are surface-contract bugs independent of the underlying backlog.","design":"Keep the bounded fast path. In the canonical status payload, only derive message_coverage_percent when candidate_prose_messages_exact is true. In archive debt, preserve pending-message unknownness when embedding_pending_message_count_exact is false and explain how to request detail instead of coercing None to zero.","acceptance_criteria":"A synthetic analyzed-index fixture proves a non-exact candidate estimate never produces message_coverage_percent. A synthetic bounded readiness fixture proves archive debt renders pending/stale message counts as unknown rather than zero. Focused CLI status and archive-debt tests pass.","notes":"2026-07-10 closure: live evidence showed candidate_prose_messages=652,760 approximate versus 675,469 embedded (103.5%) and archive-debt rendered unavailable pending messages as zero. PR #2661 merged as 69990dcc873c2fc0a9c900861bb10db94b75f434: coverage is now omitted unless the denominator is exact, and bounded debt preserves unknown message counts with a detail hint. Focused tests 48/48; devtools verify --quick 13/13 twice; all CI, CodeQL, container, Nix, distribution, visual, type, lint, and GitGuardian checks green.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T16:44:55Z","created_by":"Sinity","updated_at":"2026-07-10T16:52:26Z","started_at":"2026-07-10T16:44:57Z","closed_at":"2026-07-10T16:52:26Z","close_reason":"Merged PR #2661: approximate embedding denominators no longer emit impossible coverage percentages, and bounded archive debt no longer coerces unknown message counts to zero. Focused and all substantive CI checks passed.","labels":["area:embeddings","area:ops"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-8jg9.5","title":"Bind durable migrations to verified backup receipts","description":"## Problem\nVerified 2026-07-10 on origin/master a8eb1bf1a: polylogue/storage/sqlite/migration_runner.py:73-87 accepts a backup as migration authority after checking only JSON format and that included_tiers names the requested tier. polylogue/daemon/backup.py:266-293 writes the same manifest before verification regardless of verify=False/True; backup_archive at :296-338 and _verify_backup_result at :426-443 retain the verification verdict only in the in-memory BackupResult. Tests/unit/storage/test_durable_migrations.py:16-28 therefore authorizes migrations with hand-written manifests that were never restored or integrity-checked.\n\n## Steps to Reproduce\nCreate a JSON file with format=polylogue-backup-v1 and included_tiers=[user.db], without running backup_archive or verification. Pass it as backup_manifest to migrate_archive_tier for a pre-current user.db. The migration proceeds. Equivalently, run backup_archive with verify=False, or retain manifest.json after a verify=True call fails after copying; the on-disk manifest is indistinguishable from a verified success and still passes validate_migration_backup_manifest.\n\n## Impact\nAn unverified backup, a verification failure after copy, or a manifest transplanted onto different bytes can authorize an irreversible source.db/user.db migration. This falsifies the verified-backup premise of closed substrate bead z7rv and is load-bearing for the source-v4 rollout plus the next durable window 60i5.","design":"Keep manifest.json immutable and add a versioned successful-verification receipt sidecar produced only after scratch restore, SQLite integrity checks, and exact blob-reference resolution all succeed. The receipt must cryptographically bind: the canonical manifest bytes/digest; requested tier identity; each included tier artifact path, byte size, SHA-256, PRAGMA user_version, and quiesced pre-copy source fingerprint; and an ordered blob inventory with per-blob hash/size plus an inventory-root digest. Backup creation must run under the archive single-writer/exclusion contract so the source fingerprint and copied snapshot describe one state. validate_migration_backup_manifest becomes receipt validation: resolve the adjacent receipt, require a success verdict and supported schema, recompute manifest/tier/blob digests, compare the live migration connection/path against the recorded source fingerprint, and reject missing, failed, stale, mismatched-tier, or tampered evidence before BEGIN IMMEDIATE. Do not accept a caller-supplied boolean or an unsigned ok field. Reuse the full-evidence blob-resolution/inventory substrate landing with source-v4 rather than inventing a second reference scanner. Interlocks: z7rv defines the runner contract; 4be owns recurring restore drills; 8jg9.2/source-v4 needs this gate for live migration; 60i5 must not depart until this proof is enforced.","acceptance_criteria":"1. backup_archive(..., verify=False) produces no successful verification receipt and migrate_archive_tier rejects its manifest. A failed verification after the copy likewise cannot authorize migration. 2. backup_archive(..., verify=True) emits a versioned receipt only after scratch restore, PRAGMA integrity_check for every included tier, and exact referenced/reserved blob resolution succeed. The receipt binds canonical manifest bytes, tier DB artifacts, the quiesced source fingerprint, and the ordered blob inventory by SHA-256/content metadata. 3. Migration revalidates the receipt and rejects missing, failed, stale, wrong-tier, or unsupported receipts; a manifest/receipt copied from another backup; any changed tier DB byte; and any added, removed, resized, or hash-mismatched blob. It performs no migration statement before validation completes. 4. Mutation-style tests prove anti-vacuity: deleting/skipping the verification step makes the happy-path migration test fail, and independently flipping manifest, tier DB, receipt, and blob bytes is detected. Existing hand-written format+tier-only fixtures are removed or made explicit negative cases. 5. CLI proof against a throwaway pre-current durable-tier archive: polylogue ops backup --verify followed by the migrate-tier command succeeds and records the receipt identity; the same flow with an unverified backup and with one tampered copied byte fails non-zero before the tier version changes. Record exact commands and output in Bead notes/PR. Verify: devtools test tests/unit/daemon/test_backup.py tests/unit/storage/test_durable_migrations.py tests/unit/cli/test_archive_maintenance_cli.py; devtools verify --quick; one live CLI proof on a scratch copy, never the canonical archive.","notes":"Fresh trust-floor finding from the 2026-07-10 source-v4/broad verification audit. Re-verify source anchors after source-v4 merges because backup.py is actively changing; the invariant is authoritative, not these line numbers.\n2026-07-10 Terra repair ebe68f6e7 rejected for a remaining authority/provenance gap. The branch materially improves accidental corruption detection, exact tier/blob binding, WAL-race handling, and under-lock revalidation. However verification-receipt.json is still unsigned and all fields (verdict, scratch claims, manifest/tier/blob hashes, source fingerprint) are locally recomputable from an unverified backup. A caller can hand-write the supported-format success receipt with correct current hashes; migration_runner cannot distinguish it from a receipt actually produced after scratch restore. This violates the design clause rejecting an unsigned ok field and preserves the original forged-authority class under more elaborate JSON. Salvage the integrity/race work, but bind successful verification to an authenticated local capability/attestation or explicitly narrow the contract to accidental-integrity evidence and revise the bead/claims before shipping.\n\n2026-07-11 implementation and proof (feature/fix/authenticated-backup-receipts).\n\nAuthority model: successful verification receipts are format v2 and carry a separate HMAC-SHA256 attestation for each included durable tier. Each 32-byte key is independently located from the resolved live-tier path under XDG state, created atomically with 0600 mode, and never copied into the backup. Migration resolves the actual SQLite main path, verifies that tier attestation before trusting any receipt claim, then revalidates manifest bytes, every included tier artifact, live source fingerprint, blob-inventory file/root, and every blob byte before BEGIN IMMEDIATE and again under that lock. Backup snapshotting checkpoints, acquires the SQLite writer lock, detects/retries a WAL commit in the checkpoint-to-lock gap, fingerprints and copies under the lock, scratch-restores the copy, and refuses a receipt if bytes change after scratch verification.\n\nAC evidence:\n1. verify=False and forced verification failure emit no receipt and migration executes no SQL.\n2. verify=True scratch-restores all included tiers, integrity-checks each, resolves source/index blob references, then writes the authenticated receipt.\n3. Negative cases cover missing/unsupported/wrong-tier receipts; public-hash forgery with missing/fake MAC; missing/rotated keys; transplanted receipts; manifest/receipt/tier/live-byte mutation; added/removed/resized/hash-mismatched blobs; post-validation concurrent writes; and a writer commit in the checkpoint-to-lock gap.\n4. Anti-vacuity: tests monkeypatch migration SQL to fail if reached on every reject path. Removing receipt authentication makes the public-hash forgery test pass migration and therefore fail; removing the WAL retry loses the injected during-gap row and fails the real copied-DB assertion.\n5. Scratch CLI proof at /realm/tmp/polylogue-user-v5-proof.9vPPpL reproduced the production symlink topology. An unverified backup rejected at user_version 4; a verified then one-byte-tampered backup rejected at version 4; a fresh verified backup migrated 4->5 with applied_versions=[5], receipt v2/user attestation, context_deliveries+user_settings present, integrity_check=ok, and a 0600 32-byte local key.\n\nThreat boundary: this prevents artifact-only forgery, accidental fabrication, and receipt transplant. It is deliberately not a privilege boundary against hostile arbitrary code already running as the same Unix user, which can read the per-tier key.\n\nVerification before final publish rerun: devtools test tests/unit/daemon/test_backup.py tests/unit/storage/test_durable_migrations.py tests/unit/cli/test_archive_maintenance_cli.py => 85 passed in 201.23s; post-race regression devtools test tests/unit/daemon/test_backup.py -k checkpoint_and_lock => 1 passed; devtools verify --quick => 13/13 passed (run 20260711T141617Z-quick-177111-47f3ac17).\n2026-07-11 final verification and adversarial review update.\n\nAdversarial iteration 1 found a real provenance gap: receipt artifact bytes A and live source fingerprint B were authenticated independently without requiring A=B. A production-route repro migrated B while retaining only backup A. Fixed at both receipt issuance and migration validation; real-route negative tests prove issuance refuses the mismatch and a legacy-style signed mismatch executes no SQL.\n\nAdversarial iteration 2 found a second recoverability gap: a signed user.db artifact could be replaced by a symlink or hardlink to the live tier, pass byte validation, and then be mutated by migration. Fixed independently in verifier and migration: backup root/metadata/tier/inventory/blob artifacts require contained real ancestry and single-link regular files; the target artifact may not alias the live inode. Symlink and hardlink tests cover both issuance and pre-SQL migration rejection with user_version unchanged.\n\nFinal exact Bead command:\ndevtools test tests/unit/daemon/test_backup.py tests/unit/storage/test_durable_migrations.py tests/unit/cli/test_archive_maintenance_cli.py\nResult: 92 passed in 212.25s.\n\nFinal publish gate after topology regeneration:\ndevtools verify --quick\nResult: 13/13 passed, run 20260711T145554Z-quick-274507-6d3c6946.\n2026-07-11 adversarial closure and refreshed final CLI proof.\n\nIteration 3 found an unbound SQLite-sidecar gap: a post-receipt user.db-wal could change the logical backup while the signed main-file hash remained identical. Fixed by forbidding -wal/-shm/-journal artifacts at verification and migration, using immutable SQLite reads for copied tiers, and testing both an open non-checkpointed WAL and linked sidecars before SQL.\n\nIteration 4 found that auxiliary/undeclared files were outside the receipt. Fixed with a signed, closed recursive artifact inventory (path/type/size/SHA-256) over every directory and file except the receipt itself. Known tier/blob checks reuse that inventory to avoid duplicate hashing of large archives. An unexpected-file regression rejects before SQL.\n\nIteration 5 independently reviewed the final authority, copy identity, sidecar, closed-world, and snapshot paths and found no legitimate gaps. Adversarial loop converged at the five-iteration cap with all real findings repaired and regression-tested.\n\nFinal exact focused command now reports 96 passed in 222.20s:\ndevtools test tests/unit/daemon/test_backup.py tests/unit/storage/test_durable_migrations.py tests/unit/cli/test_archive_maintenance_cli.py\n\nFinal quick gate after the last topology regeneration reports 13/13 passed:\nrun 20260711T151504Z-quick-315872-3acc24f7.\n\nRefreshed scratch CLI proof on the exact final candidate under /realm/tmp/polylogue-user-v5-proof.9vPPpL/final-proof:\n- unverified receipt missing -> exit 1, live user_version remained 4;\n- verified backup plus one appended artifact byte -> exit 1 (tier size mismatch), version remained 4;\n- fresh verified backup -> from_version=4, to_version=5, applied_versions=[5], receipt v2;\n- receipt closed inventory exactly [manifest.json,user.db], one user attestation, stored artifact user_version=4;\n- postflight user_version=5, integrity_check=ok, context_deliveries and user_settings present;\n- independent per-tier key is 32 bytes with mode 0600.\n2026-07-11 production rollout proof: PR #2708 squash-merged as a21b907dcfed055349ff1b881017add04ef05324. Sinnix deployed the exact Nix input and persisted it as 7fe17bd0 on origin/master. With polylogued and the scheduled backup stopped, the a21b907 binary created and scratch-verified an authenticated user_overlays bundle at /realm/staging/polylogue-sqlite/migration-backup/user-v5-a21b907-20260711T154133Z/polylogue-archive-20260711T154135Z. Receipt format v2 binds manifest.json and the exact v4 user.db; independent key is 32-byte mode 0600. migrate-tier applied only version 5. Postflight: user_version=5, integrity_check=ok, assertions=1, user_settings=0, context_deliveries=0, both context-delivery indexes present. The exact a21b907 daemon restarted at 17:42 CEST with NRestarts=0, all 8 sources available, browser capture ready, health ok; backup timer active. Remaining six alerts are the separately reproduced append-chain defect polylogue-yla8.6, not migration fallout.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T16:14:49Z","created_by":"Sinity","updated_at":"2026-07-11T15:43:34Z","started_at":"2026-07-10T20:13:06Z","closed_at":"2026-07-11T15:43:34Z","close_reason":"Merged authenticated receipt gate in PR #2708 and proved the live user v4-to-v5 rollout with a retained verified rollback bundle, row/integrity parity, exact deployed revision, and healthy restarted daemon.","labels":["area:ops","area:storage","delivery:A-trust-floor","horizon:frontier","lane:operational-resilience","spine","tech-tree"],"dependencies":[{"issue_id":"polylogue-8jg9.5","depends_on_id":"polylogue-4be","type":"related","created_at":"2026-07-10T18:15:06Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-8jg9.5","depends_on_id":"polylogue-8jg9","type":"parent-child","created_at":"2026-07-10T18:14:49Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-8jg9.5","depends_on_id":"polylogue-z7rv","type":"related","created_at":"2026-07-10T18:15:05Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-kwlu","title":"Commit live-ingest raw parse state after durable index writes","description":"Live v30 daemon catch-up successfully indexed newly observed sessions while leaving every corresponding durable source row with parsed_at_ms=NULL and parse_error=NULL. Archive readiness and raw-materialization repair therefore classify already-indexed evidence as unparsed debt, making daemon success counters disagree with source truth and inviting redundant replay. This is a correctness defect in both append and full LiveBatchProcessor persistence, not a cosmetic status problem.","design":"Verified mechanism: polylogue/sources/live/append_ingest.py::_ingest_append_plans_archive calls ArchiveStore.write_raw_and_parsed; polylogue/sources/live/batch.py full ingestion calls write_raw_and_parsed or write_raw_blob_and_parsed. Those helpers persist source.db plus index.db but neither live route invokes the normal ingest-batch _persist_batch_raw_state_updates contract, and write_source_raw_session defaults parsed_at_ms to NULL. Introduce one typed source-state finalization authority reused by ordinary batch and live ingestion. The ordering is a monotonic three-step protocol: retain the raw row first; commit the parsed index outcome; only then commit parsed success on source.db. A parse/index failure must never set parsed success; it leaves retriable source evidence and records a bounded structured error when a raw row exists. A crash after index commit but before the source marker is reconciled idempotently from the durable raw-to-index relation rather than by moving the marker before index commit. Wire append and full paths through this authority and make status/readiness consume the same state semantics. Test the actual LiveBatchProcessor routes with phase barriers around source write, index commit, and state update; do not substitute a toy archive or mock away ArchiveStore.","acceptance_criteria":"1. Real LiveBatchProcessor append and full-route fixtures each retain a source raw row and index the parsed session; after the durable index commit, parsed_at_ms is non-NULL and parse_error is NULL. 2. Inject parse failure and index-commit failure separately: no path marks parsed success early, durable raw evidence remains eligible for retry, and an existing raw row receives the typed bounded failure state. 3. A phase-barrier crash after index commit but before source finalization is repaired idempotently without duplicating sessions or losing evidence. 4. Mutation checks fail when the state update is removed, when it is moved before index commit, or when either append/full wiring is omitted. 5. A sanitized live catch-up proof reports matching daemon succeeded/failed counters, indexed session/raw links, source parsed/error counts, exact archive readiness, and repair backlog; successfully indexed rows are not emitted as unparsed debt. VERIFY: focused managed live-batch, append-ingest, raw-state, readiness, and repair tests plus devtools verify --quick.","notes":"2026-07-10 live evidence from polylogued-v30-runtime.service. Journal at 17:39:09 local: catch-up scan 14,757 files; catch-up ingesting 18 files (108.8 MB), skipped=14,739, chunks=2. Chunk 1: 5 files, append_files=5, full_files=0, succeeded=5, failed=0, parse_s=4.152. Chunk 2: 13 files, append_files=1, full_files=12, succeeded=13, failed=0, parse_s=8.254; daemon also logged batch ingested codex — 12 in 8.2s. Read-only source/index query over 15:39:00-15:40:40 UTC found 17 newly acquired raw rows / 17 native IDs (15 codex-session, 2 claude-code-session): parsed_at_ms NULL=17, parse_error non-NULL=0, and 16 raw IDs already linked to index sessions. Concrete indexed contradiction: raw d8341b5c90895ee8d12b745c63e007ca54f90af9f757039a25aace774b731a1d has parsed_at_ms=NULL and parse_error=NULL while index session codex-session:019f4caa-9424-78c0-bcdb-b7baf75a3a17 points to it with 222 messages. Subsequent catch-up rows exhibited the same state. The daemon was not stopped or mutated during this read-only audit.\n2026-07-10 sanitized live closure proof on final merged runtime 0cccef1df, transient invocation eacf5185c4684d48b3b0902ac096f40a. Startup catch-up scanned 14,765 files and selected one 42.8 MiB Codex append: succeeded=1 failed=0, read_amp=0.000145x, parse_s=0.039, convergence_s=0.076. Cutoff at service start (1783706084000 ms) isolates one new raw row: raw 946c8b809b1bad9171d900b64b8726e54aa96d2c6bbfc7735e949996418deccc, acquired=1 parsed=1 failed=0 unclassified=0 exact_index_links=1; index session codex-session:019f49d8-0185-7c43-8793-db6e57db13e1 points to that raw with 7,516 messages. Cursor byte_offset=stat_size=42,847,709, failure_count=0. Readiness raw-materialization ready/actionable=0/blocked=0, daemon ingest idle, receipts=0, convergence debt=0, health ready and FTS 2,672,652/2,672,652. Two older NULL rows in the wider window predate final-runtime startup and are the original old-runtime defect, not false claims about the new catch-up.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T15:44:13Z","created_by":"Sinity","updated_at":"2026-07-10T17:56:32Z","started_at":"2026-07-10T16:54:30Z","closed_at":"2026-07-10T17:56:32Z","close_reason":"Merged PRs #2663/#2664 and proved the final runtime on a sanitized post-start live catch-up: raw evidence retained once, exact index link, parsed marker set, zero error/unclassified rows, cursor complete, zero receipt/convergence debt, and ready archive/daemon/search.","labels":["area:daemon","area:ingest","area:storage","area:test","delivery:A-trust-floor","horizon:frontier","lane:evidence-honesty","size:S"],"dependencies":[{"issue_id":"polylogue-kwlu","depends_on_id":"polylogue-20d.6","type":"related","created_at":"2026-07-10T17:44:14Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-kwlu","depends_on_id":"polylogue-b5l.2","type":"related","created_at":"2026-07-10T17:44:13Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-212.12","title":"Demo Packet v2: machine-readable bounded-experiment contract for every public demo","description":"Every public demo becomes a bounded experiment with a declared contract: one primary construct, claim stated before execution, independent oracle, negative + missing-evidence controls, baseline arm, explicit falsifier, resolvable receipts, machine-readable packet, human presentation, non-claims section, interruption/regeneration behavior. A validating JSON Schema + example exist in the external-legibility kit escrow (.agent/scratch/legibility-kit-2026-07-10/10-demo-packet-v2.schema.json + -example.yaml) — treat as draft input, not authority.","design":"Port the compact production semantics from recovered commit 2d42b61c5 onto current master rather than applying its whole generated-demo diff. In docs/schemas/demo-packet-v2.schema.json require claim.receipts and receipt.sha256. In devtools/demo_packet.py enforce exact canonical section headings, claim receipt-reference closure, receipt digest/path binding, falsifier state consistency, unique control ids, and unique measurement names. Migrate every registered packet and fixture to the strengthened schema with actual hashes and resolvable refs; keep current flagship/generated surfaces authoritative where the recovered branch conflicts. Extend the existing registry and focused validator tests with the reproduced false-green mutations. The validator must exercise production packet bytes and reference resolution, not a parallel test-only model.","acceptance_criteria":"1. Every registered Demo Packet v2 claim cites at least one receipt, every receipt carries sha256, and the registry gate resolves each cited ref/path and verifies the digest. 2. The current false-green repro fails for each independent mutation: missing claim.receipts, missing receipt.sha256, noncanonical Claim heading, falsifier triggered=true with result=pass, duplicate control id, and duplicate measurement name. 3. Valid committed packets and the minimal fixture pass the same production validator; all three current registered packets are migrated with no grandfathering. 4. Mutation evidence states which production check removal would make each negative fixture pass. 5. docs/demos.md and the example describe the enforced contract exactly. Verify with devtools test tests/unit/devtools/test_demo_packet.py tests/unit/demo/test_flagship_demos.py; devtools verify-demo-packet-registry; devtools verify --quick.","notes":"[GPT-Pro branch assimilation 2026-07-11] Branch 15 (`6a5112f5`; mission 03 Demo Packet v2) fully recovered as ZIP + Git bundle. Treat as candidate implementation, not proof: current-source worktree must re-run tests. Accepted AC inventory: predeclared claim, oracle, controls, falsifier, non-claims, digest binding, path confinement, ref closure, uniqueness, registry anti-vacuity. Recovered bytes: `/realm/inbox/gpt-pro-sol/recovered-branch-project-explanation-2026-07-11/polylogue/`. Matrix: `.agent/reports/chatgpt-pro-branch-assimilation-2026-07-11.md`.\n2026-07-11 recovered-session code audit reproduced the gap on current master. A copy of _packet-contract-stub remained ok=True after removing claim.receipts and receipt.sha256, using ## claimant, setting falsifier.triggered=true/result=pass, duplicating a control id, and duplicating a measurement name. Repro: /realm/tmp/ten-session-audit-packet-false-green. Recovered commit 2d42b61c5 has the relevant production hunks and negative tests, but its whole commit must not be applied because generated flagship packet surfaces have diverged. Assimilate schema/validator/test semantics selectively.\n2026-07-11 residual hardening merged via PR #2709 as 885b46da313c58e3c87215bc93486b97cb3b3797. Selectively ported recovered commit 2d42b61 semantics onto current master: claim.receipts and receipt.sha256 are required; ref/path/digest closure uses one read of confined artifact bytes; exact ordered canonical headings, falsifier consistency, and unique control/measurement identities are enforced. All three registered packets migrated without grandfathering. Six current-master false-green mutations fail the production validator and name the guard whose removal recreates the failure. Verification: 32 focused managed tests, registry 3/3, shelf gate, quick 13/13, all CI/CodeQL/Nix/type/demo checks green; CodeRabbit quota notice had no substantive finding.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T14:48:31Z","created_by":"Sinity","updated_at":"2026-07-11T16:02:23Z","started_at":"2026-07-11T15:45:33Z","closed_at":"2026-07-11T16:02:23Z","close_reason":"Residual false-green contract repaired in PR #2709: digest-bound claim receipts, semantic consistency, canonical report structure, unique identities, migrated registry, and six production-route mutation regressions are merged and verified.","labels":["area:demos","area:test","delivery:L-external-legibility","horizon:frontier","lane:docs-demos-launch"],"dependencies":[{"issue_id":"polylogue-212.12","depends_on_id":"polylogue-212","type":"parent-child","created_at":"2026-07-10T16:48:30Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-b5l.2","title":"Make rebuild-index completion prove read-model readiness","description":"Production evidence on 2026-07-10 falsified the documented rebuild contract. An exclusive index-v30 replay exited success after selecting 17,814 durable raw rows, processing 6,243 sessions in 1,048 batches, and reporting zero parse failures plus 6,243 materialized sessions. The immediate read-only command polylogue ops status --full --exact-archive-readiness nevertheless found only 4/9 readiness surfaces ready: session_profiles, timeline_work_events, timeline_phases, threads, and latency_profiles were missing or stale. It also reported 814 raw-materialization gaps classified as non-critical debt. The operator then had to run maintenance run --target session_insights, contrary to the automagic-invariants doctrine and rebuild-index help, which promise that the canonical post-reset path rebuilds read models unless --no-materialize is explicit. A successful rebuild receipt must distinguish parsed sessions, attempted insight refreshes, committed insight rows, and exact postcondition readiness.","design":"MECHANISM VERIFIED IN SOURCE. polylogue/maintenance/replay.py::rebuild_index_from_source calls execute_materialize_stage after parsing. polylogue/pipeline/run_stages.py routes an explicit raw-id selection through the incremental reprocess path and reports MaterializeStageOutcome.item_count as len(processed_ids), independent of actual insight rows. polylogue/pipeline/services/ingest_batch/_core.py::refresh_session_insights_bulk catches every exception, logs it as non-fatal, and returns an observation with failed=true. polylogue/cli/commands/maintenance.py::rebuild_index_command ignores that failed observation; both the ingest_attempt status and JSON/plain status are decided only by parse_failure_count. Thus 6,243 materialized can mean 6,243 attempted even when the refresh failed and exact readiness is red. CONTRACT. Default rebuild-index is a closure operation: parse durable source, rebuild FTS/read models, then run the shared exact archive-readiness oracle before recording completed. Critical missing/stale derived surfaces make the operation failed or explicitly incomplete with a nonzero exit and a stage-specific recovery action. --no-materialize is an intentional parsed-only outcome and must not claim archive readiness. Classified non-session/alias raw gaps remain separately visible and do not by themselves fail derived-model closure; actionable parse or raw-evidence gaps do. IMPLEMENTATION SHAPE. Propagate a typed materialization outcome (attempted, committed per-surface counts, failed/error) instead of hiding exceptions; make rebuild_index_from_source and the CLI fail closed on failed materialization; evaluate the shared readiness projection after repository connections close; persist readiness summary and failing surfaces on the rebuild attempt; render attempted versus committed counts honestly. Reuse the same postcondition as b5l generation swap rather than inventing another readiness vocabulary. TEST GAP. Current CLI tests replace rebuild_index_from_source with a success fake, and the lower-level selected-id test replaces execute_materialize_stage with a success fake. They prove option plumbing and requested-id counts, not the end-to-end postcondition. Add a scratch-archive scenario that exercises the real parse -> materialize -> readiness chain. Relation: hjwr owns full-vs-incremental logical equivalence; 1xc.8 owns schema rebuild losslessness; b5l consumes this readiness gate before swap; 3wb owns replay amplification/performance, not semantic completion.","acceptance_criteria":"1. On a seeded split archive, reset/rebuild through the real rebuild-index command and immediately run the shared exact-readiness projection read-only; every critical session-insight surface is ready and the completion receipt records committed per-surface counts, not requested session ids. 2. Inject an exception after at least one insight chunk commits. The CLI exits nonzero, ingest_attempt is failed or incomplete, output names session_insights and the remaining unready surfaces, and it never prints status=ok or equates attempted ids with materialized rows. 3. --no-materialize produces an explicit parsed-only/not-exact-ready receipt without pretending to close the archive; a subsequent ordinary daemon convergence or targeted maintenance can close it. 4. Raw-materialization debt is classified independently: seeded parsed-non-session and materialized-alias rows do not false-fail the derived readiness gate, while actionable parse/raw-evidence gaps remain visible and block the appropriate contract. 5. Anti-vacuity mutations fail the scenario when (a) failed=true is ignored, (b) the exact postcondition check is removed, (c) materialized count is replaced with len(processed_ids), or (d) one of profiles/work-events/phases/threads/latency is omitted from the readiness census. 6. The b5l swap gate and offline rebuild command call the same readiness authority; hjwr/1xc.8 reference this scenario rather than duplicating it. Verify with focused managed tests for maintenance CLI, run_stages, and archive readiness plus devtools verify --quick.","notes":"Additional production discriminator (2026-07-10): while the corrective `maintenance run --target session_insights` was still running, it crossed the rebuild receipt’s 6,243 materialized count and reached 6,768 toward the full 17,156-session index. This makes the primary live mechanism more specific: the default full rebuild resolves every source raw row to an explicit `raw_ids` list; `rebuild_index_from_source` therefore chooses `stage=\"reprocess\"` solely because `raw_ids is not None`, and `execute_materialize_stage` refreshes only `parse_result.processed_ids` (6,243), not every session present in the freshly built index (17,156). The swallowed `observation.failed` path remains a separate false-success defect, but is not required to explain this incident. Implementation must carry explicit rebuild intent (full archive vs selected suffix), use the full index session census for default cold rebuild materialization, and reserve processed-id refresh for genuinely targeted replay. The integrated fixture must include multiple raw revisions/skip-or-unchanged outcomes so the final index session census is strictly larger than `processed_ids`; it must fail if default rebuild materializes only that changed subset.\n2026-07-11 production adjudication: PR #2685 (a2bbd25d6) made inactive generation promotion depend on the shared exact-readiness projection and materialized 95,640 insight repairs. The first production receipt was nevertheless false-green for tool usage because status treated the actions VIEW as an absent table and forced action_count=0. PR #2687 (9018d5861) now requires the view to exist, be queryable, and have exact parity with tool_use blocks, with removed/broken/partial-view mutations. Packaged exact proof found action_count=tool_use_block_count=1,670,736 and the view readable. Overall readiness remained red because the live daemon crossed the scan; rerun quiesced before closure. Receipt: /realm/staging/polylogue-sqlite/recovery/20260710T225846Z/receipts/post-deploy-exact-readiness.json","status":"closed","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T14:30:20Z","created_by":"Sinity","updated_at":"2026-07-11T07:17:34Z","closed_at":"2026-07-11T07:17:34Z","close_reason":"Promoted exact-sized index v32 generation and repaired session insights. Final exact readiness receipt reports 9 ready archive surfaces, 0 blocked, exact FTS/action parity, and zero missing insight materializations; installed readiness projects governed raw authority as ready.","labels":["area:daemon","area:ops","area:storage","area:test","delivery:B-storage-rebuild-bytes","horizon:frontier","lane:storage-rebuild-scale","size:S"],"dependencies":[{"issue_id":"polylogue-b5l.2","depends_on_id":"polylogue-1xc.8","type":"related","created_at":"2026-07-10T16:30:21Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-b5l.2","depends_on_id":"polylogue-3wb","type":"related","created_at":"2026-07-10T16:30:21Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-b5l.2","depends_on_id":"polylogue-b5l","type":"parent-child","created_at":"2026-07-10T16:30:19Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-b5l.2","depends_on_id":"polylogue-hjwr","type":"related","created_at":"2026-07-10T16:30:21Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-b5l.2","depends_on_id":"polylogue-yla8","type":"relates-to","created_at":"2026-07-10T20:48:43Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-r3o3","title":"Make demo-shelf generation repository-closure-aware","description":"Why: the dirty canonical checkout generated four apparently synchronized shelf indexes claiming 185 files and 148 readable artifacts. Applying only those tracked index changes to a clean current-master worktree produced 69 files and 59 readable artifacts; `python3 -m devtools.demo_shelf --check --json` correctly marked manifest, summary index, README, and catalog all changed. Eight unit tests still passed. The generator had incorporated ignored/untracked demo artifacts from the dirty checkout, so its outputs were not closed over the committed repository and could not be reviewed or regenerated cold.","design":"Define the shelf input closure explicitly. Prefer a manifest-declared or git-tracked artifact census for committed generated outputs; private/ignored demo evidence may be rendered into an untracked operator index but must never silently alter committed catalogs. Generation records included/excluded counts and reasons. In write mode, refuse to update committed projections when inputs include undeclared ignored/untracked files, or require an explicit private-output target. CI/check mode reconstructs in a clean checkout and compares byte-identically. Keep summary coverage separate from file inclusion so an unsummarized demo cannot masquerade as absent.","acceptance_criteria":"A seeded ignored demo file cannot silently change committed MANIFEST.readable.json, SUMMARY_INDEX.json, README.md, or CURATED_CATALOG.md: default generation either excludes it with explicit omission accounting or fails with a named undeclared-input error. A declared tracked demo changes the four outputs identically in dirty and clean worktrees. Mutation tests fail when git/manifest closure filtering, clean-checkout comparison, or omission accounting is removed. Reproduce the 185/148 dirty versus 69/59 clean discrepancy, then show an explainable-empty diff after the fix. The existing uplift-two-arm tracked corpus remains indexed, and private demo artifacts remain accessible through an explicitly untracked/private projection.","notes":"2026-07-10 implementation scope: reproduce the clean/dirty shelf divergence with bounded fixtures; make committed projections consume only git-tracked or manifest-declared inputs; preserve separate inclusion and summary-coverage accounting; retain private artifacts only through an explicit untracked projection; add mutation-grade focused tests for closure filtering, omission accounting, and clean comparison. Owned surface: devtools/demo_shelf.py, focused tests, and directly required generated shelf metadata. No live archive access.\n2026-07-10 implementation evidence: production delta tightened to +174/-53 (121 net) in devtools/demo_shelf.py. Committed mode selects Git-tracked files only, writes repository-relative root paths, records included/excluded counts and reason counts, bounds JSON samples at 20, and refuses committed writes when undeclared inputs exist. --private-output must be outside the shelf and includes untracked/private files. Bounded fixture proves 25 ignored files produce a named refusal without changing the four committed files; a clean clone reproduces all four byte-identically. Current clean census is 69 files / 59 readable / 2 summaries, versus the recorded dirty 185/148 incident. Explicit retention assertions cover uplift report, pair1 handoff output, score.json, agent forensics summary, and affordance summary. Verification: 12 focused tests passed; devtools verify --quick passed all 13 steps after two lint-only fixes.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T13:05:21Z","created_by":"Sinity","updated_at":"2026-07-10T14:02:44Z","started_at":"2026-07-10T13:46:05Z","closed_at":"2026-07-10T14:02:44Z","close_reason":"Merged PR #2651 (c6aa6a05): committed shelf projections are Git-tracked-input closed, undeclared inputs fail with bounded accounting, private evidence uses a separate projection, clean-clone bytes match, and uplift artifacts remain indexed. Verified 12 focused tests plus all quick/CI gates.","labels":["area:demos","area:devtools","area:test","horizon:frontier","size:S"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-b5l.1","title":"Make index rebuilds writer-exclusive and crash-resumable","description":"Why: the live v30 replay on 2026-07-10 passed its manual preflight but both the installed polylogued.service and transient polylogued-agent.service later ran against the same archive. The rebuild command continued until 10,362/17,788 raw rows, then failed with database is locked. Runtime masking alone did not stop an already-loaded restart loop, and the command itself neither detects all writer authorities nor holds an archive-wide exclusion capability. Its attempt row records no per-batch cursor, so the documented --only-missing recovery is not an exact resume: on this archive it selected 6,946 historical raw revisions and can revisit older captures rather than continue from the committed batch boundary.","design":"Add an archive-root-scoped writer/maintenance capability acquired before rebuild work and held for the entire operation. Every daemon/direct maintenance writer must honor the same capability; enumerate installed/transient units and live processes only as diagnostics, not as the lock itself. Startup fails closed while offline maintenance owns the archive. Persist a source-snapshot vector and committed per-batch raw cursor in ops.db: ordered raw identity plus acquired high-water/source revision, index schema/generation, and delta boundary. Resume replays exactly the uncommitted suffix, then a captured delta, without treating superseded historical raw ids as missing. Integrate this offline proof into b5l so blue-green uses generation ownership rather than duplicating locking vocabulary. Expose owner/build/unit/archive/schema in status and make stale-lock recovery explicit.","acceptance_criteria":"A seeded competing installed daemon, transient daemon, direct writer, or writer started after preflight cannot write while rebuild owns the archive; rebuild fails before its first write when another owner already holds the capability. Killing the rebuild after a committed batch and resuming processes exactly the uncommitted suffix plus source rows acquired after the snapshot; a superseded historical raw revision is not mistaken for resume debt. Mutation tests fail when the capability is released early, a writer bypasses it, the cursor update precedes batch commit, or the delta boundary is removed. Live/sanitized proof records the 10,362-row failure shape, successful resume, final parity with a clean rebuild, and no active daemon. Status identifies owner, executable/build, unit/process, archive root, schema/generation, heartbeat, and recovery action.","notes":"WAVE FLAG 2026-07-13: untouched P1. Sequence AFTER the #2788 fastforward-mech reconciliation lands (in flight) — the fast-forward plan machinery and writer-exclusive rebuild locking touch the same generation-evidence surfaces (.index-generations/, active pointer). The v35 clone-upgrade ran unprotected; next rebuild should not.\n2026-07-14 PR #2872 (feature/storage/schema-forward-hardening): scoped to devtools/archive_schema_fast_forward.py per this cluster's assignment. plan_clone_forward and activate_prepared_forward now hold polylogue.storage.index_generation.RebuildLease (the same archive-root-scoped exclusive flock ArchiveStore.__init__ already wires into every write-mode writer via ActiveWriterLease) for their entire body, not just the narrow _require_service_stopped(polylogued.service) systemctl check that missed the 2026-07-10 transient-unit gap. Satisfied: \"fails before its first write when another owner already holds the capability\" and \"cannot write while rebuild owns the archive\" -- proven by tests constructing a real ActiveWriterLease and asserting both directions (pre-held blocks prepare/activate; activate holds the lease so a NEW ActiveWriterLease attempted mid-migration fails). NOT implemented (out of scope for this actuator, belongs to the raw-replay rebuild command `ops reset --index && polylogued run`, a different code path this clone-only tool's docstring explicitly excludes): per-batch raw-replay cursor resume, owner/build/unit/process/heartbeat status surface, mutation tests for capability-release-timing. Partial -- see PR body for full AC breakdown.","status":"open","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T12:48:20Z","created_by":"Sinity","updated_at":"2026-07-14T00:44:08Z","labels":["area:daemon","area:ops","area:storage","delivery:B-storage-rebuild-bytes","horizon:frontier","lane:storage-rebuild-scale","size:M"],"dependencies":[{"issue_id":"polylogue-b5l.1","depends_on_id":"polylogue-b5l","type":"parent-child","created_at":"2026-07-10T14:48:20Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-b5l.1","depends_on_id":"polylogue-n2wy","type":"relates-to","created_at":"2026-07-10T20:08:36Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-s7ae.7","title":"Make coordination status compact and semantically precise","description":"Why: live dogfooding on 2026-07-10 falsified the shipped agent-grade boundedness and classification claims. `polylogue agents status --json` at `limit=5` emitted 20,671 bytes; the equivalent MCP status/conflicts/handoff calls produced roughly 35k tokens. Ten peers included earlyoom, wrapper/host processes, MCP sidecars, and Claude spare-daemon plumbing rather than logical agent instances. Ten resource episodes were systemd-timesyncd/resolved/udevd/oomd, UVM kernel threads, dbus, earlyoom, and below, while the real scoped v30 rebuild was not identified. Every handoff ref pointed at retired `.agent/conductor-devloop/` paths that do not exist. Useful evidence (current bead, dirty paths, schema v30, session tree, daemon absence) was correct, so this is projection/classification debt, not a reason to replace the envelope.","design":"Repair the existing s7ae envelope rather than introduce a scheduler vocabulary. Separate compact status facts from opt-in detail/evidence. Collapse process trees into logical agent instances keyed by session/provider/launcher identity; treat wrapper, code-mode host, MCP server, spare daemon, and supervisor processes as components, not peers. Derive resource episodes from explicit cgroup/systemd scope identity and recognized command ownership first, with unknown rather than keyword-order guesses; ordinary system services are excluded. Replace conductor-path handoff probing with live Beads/scratch/coordination-message/assertion refs and return an empty typed list when none exist. Preserve provenance/confidence and bounded degradation. Add diagnostic omission counts so compactness cannot silently erase evidence.","acceptance_criteria":"Default CLI and MCP status projections are <=8 KiB on a seeded high-process fixture; detail mode exposes omitted evidence with explicit counts/refs. One logical Codex or Claude session tree produces one peer even when launcher, host, MCP, and spare processes coexist. Fixtures prove systemd-timesyncd/resolved/udevd/oomd, UVM threads, dbus, earlyoom, and below are not build/resource episodes, while a named sinnix-background rebuild scope is surfaced with its unit, command, repo/archive resource, and liveness. No active projection references `.agent/conductor-devloop`; absent live handoff evidence yields an empty list. Mutation tests fail when compact bounding, component collapse, system-service exclusions, real-scope detection, or handoff-source replacement is removed. A live MCP dogfood artifact records byte/token size, logical peer count, resource episodes, omissions, latency, and provenance.","notes":"Implementation scope claimed 2026-07-10: repair the existing coordination envelope projection in polylogue/coordination/{envelope,payloads,rendering}.py plus focused CLI/MCP behavior tests. Preserve the envelope ontology and avoid scheduler semantics. Deliver default <=8 KiB output with explicit detail/omission metadata; collapse logical agent process trees; classify resource scopes from systemd/cgroup identity while excluding ordinary services; replace retired conductor handoffs with supported live sources or a typed empty list. Verification is intentionally deferred until the active v30 archive rebuild exits; static/source work proceeds in an isolated fresh-origin worktree.\nLive CLI/MCP dogfood 2026-07-10T15:25:10Z after v30 exact readiness 9/9 and all five tier quick-checks exactly ok, with no daemon writer active. Private artifact: /realm/tmp/worktrees/polylogue-coordination-compact/.local/coordination/s7ae7-20260710T152444Z.json; 52,115 bytes; SHA-256 dd1f29e594ea09ecf572ab76ee80eb2ba422e5c4c6b7943b0e9e6efe599f587f. CLI compact: 7,051 bytes, est. 1,762 tokens, 13,710.501 ms cold; CLI detail: 11,239 bytes, est. 2,810 tokens, 5,227.556 ms. MCP compact: 7,051 bytes, est. 1,762 tokens, 4,489.947 ms; MCP detail: 11,239 bytes, est. 2,810 tokens, 2,618.699 ms. All four returned 2 logical peers, 2 real resource episodes, 0 handoff refs, and provenance sources archive-paths/beads/git/process/process-cgroup/process-table/process-tree. Compact omissions were explicit: archive_daemon_processes=1, beads_hooks=5, provenance=3, resource_components=19, resource_refs=2, work_item_fields=2. Live resources were the browser-post canary daemon and a named Sinnix build scope; ordinary system services were absent. No response referenced .agent/conductor-devloop. Hard compact <=8 KiB and detail reachability claims are satisfied. Residual: status latency is 2.6-13.7 seconds in this cold/warm sequence and remains performance debt; do not claim responsiveness from compact byte size.\nPost-rebase publish-head refresh supersedes the prior artifact as the authoritative live proof. Git head a5bd37832fbd1a0b91a6de1b2ce8d84cd1eba798. Private artifact: /realm/tmp/worktrees/polylogue-coordination-compact/.local/coordination/s7ae7-20260710T152753Z.json; 56,188 bytes; SHA-256 8f953ee2d2ee831e9b93e05ba07738a8330b3e889b7656140bfd6aa95b156a55. CLI compact: 7,539 bytes, est. 1,884 tokens, 13,199.206 ms; CLI detail: 12,485 bytes, est. 3,121 tokens, 13,155.585 ms. MCP compact: 7,539 bytes, est. 1,884 tokens, 16,632.985 ms; MCP detail: 12,485 bytes, est. 3,121 tokens, 13,641.836 ms. All four returned 2 logical peers, 3 real resource episodes, 0 handoff refs; no retired conductor reference. Compact remained below 8 KiB with explicit omissions. The consistently 13.2-16.6 s refresh strengthens, rather than resolves, polylogue-s7ae.8 latency debt.\nPR #2656 merged as de7f2b90960f6fc9af2733c2625ed6af81280aa8. Stable private artifact and regenerable harness relocated before worktree cleanup to /realm/project/polylogue/.local/coordination/s7ae7-20260710T152753Z.json and /realm/project/polylogue/.local/coordination/run-s7ae7-dogfood.py; artifact hash remains 8f953ee2d2ee831e9b93e05ba07738a8330b3e889b7656140bfd6aa95b156a55. All ACs satisfied; latency explicitly remains in polylogue-s7ae.8.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T12:33:03Z","created_by":"Sinity","updated_at":"2026-07-10T15:34:10Z","started_at":"2026-07-10T13:20:49Z","closed_at":"2026-07-10T15:34:10Z","close_reason":"Merged PR #2656 (de7f2b909): compact/detail projection contract, logical peer collapse, cgroup resource classification, supported handoffs, mutation fixtures, and publish-head live CLI/MCP proof complete. Latency residual tracked in polylogue-s7ae.8.","labels":["area:context","area:coordination","area:mcp","area:ops","delivery:D-agent-context-coordination","horizon:frontier","lane:agent-coordination","size:M","spine"],"dependencies":[{"issue_id":"polylogue-s7ae.7","depends_on_id":"polylogue-s7ae","type":"parent-child","created_at":"2026-07-10T14:33:03Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"polylogue-303r.2","title":"Publish Sinex materials and anchored observations with durable retry","description":"Publish exact Polylogue evidence through the real Sinex material and external-producer paths. Stage provider-native artifacts, attachments, immutable normalized segments, and the revision manifest; wait for material confirmation; publish anchored normalized observations; then advance the mode-specific local projection only when Sinex's existing durable-emission and raw-envelope settlement primitives permit progress. This replaces the metadata-only emitter and owns the durable Polylogue-side publication obligation.\n\nCross-repository implementation: sinex-4j2.1.1 layered on sinex-r6d.11 DurableEmissionReceipt and sinex-r6d.12 RawEnvelopeSettlement.","design":"Reuse acquisition/RawPersistenceStore, ParsedSession/content_hash, changed-session IDs, and the sole writer boundary; do not add another repository abstraction or settlement vocabulary.\n\nDURABLE OBLIGATION:\n- off: no transport or publication obligation.\n- mirror: create/update a source.db publication-obligation row in the same durable source-tier transaction that records the acquired/normalized revision. source.db is durable and uses its additive migration/backup discipline. A local index projection may publish only after that obligation exists.\n- primary: the durable source-tier obligation exists before transport; local index publication waits for a Sinex receipt that unlocks progress.\n- ops.db/convergence debt may mirror attempts, latency, and diagnostics only. It is disposable and can never be the sole outbox or recovery authority.\n\nEach obligation is idempotent by protocol version + stable object revision + manifest digest, records material/event progress atoms and last durable receipt, survives restart, and is retired only by terminal receipt states. User-state writes use the corresponding durable user-tier outbox owned by 303r.5.\n\nSINEX PRIMITIVES:\nThe revision manifest supplies expected material/observation counts and digests. Publication progress uses sinex-r6d.11 DurableEmissionReceipt states and contiguous progress atoms; do not add a Polylogue commit-frontier/finalization state machine. A receipt unlocks local progress only for PersistedConfirmed or a documented terminal outcome/DurableDebt/SpoolAcceptedLossless allowed by r6d.11. Sinex-r6d.12 owns aggregate-safe ACK/NAK/DLQ of multi-event raw envelopes. Material confirmation always precedes EventIntent.\n\nFailure points: before/after source-tier obligation write, after bytes before material confirmation, after some events before raw-envelope settlement, after Sinex receipt before local projection, duplicate delivery, rejection, and reconnect. Configured failure is never a no-op.","acceptance_criteria":"Against real local Sinex transport and the shared fixture: exact materials retrieve by confirmed ID; content-bearing observations traverse JetStream and resolve exact anchors; manifest counts/digests reconcile with r6d.11 receipts and r6d.12 aggregate raw-envelope settlement before local progress unlocks. Killpoints prove a crash after durable local evidence but before transport cannot lose the source.db obligation; deleting ops.db loses diagnostics only and the obligation still drains. Same-revision retry is idempotent; changed revision preserves history. Multi-event partial failure cannot ACK the raw envelope early. Off mode performs zero transport work; primary never advances local projection before receipt; mirror reports exact lag. Mutation checks remove the durable obligation, receipt barrier, aggregate settlement, or material anchor and must fail. Durable-tier migration/backup checks, focused tests, and devtools verify --quick pass.","notes":"EASIER 2026-07-13: material protocol v1 LANDED (#2735, 303r.1 closed) — the encode/anchor/manifest machinery this publication leg needs exists on master. Also binding: operator clarification on qsr6 (SQLite standalone is permanent, Sinex-backed is a mode) — publication must not assume backed-mode primacy.\n2026-07-14 (worktree wf_5be33c21-b3d-7): PR #2873 (feature/feat/sinex-publication-obligation) implements the Polylogue-side durable obligation ledger + transport contract.\n\nScope landed: polylogue/sinex/ (models.py: PublicationMode/ObligationStatus/ReceiptState with ReceiptState.unlocks_progress() gating on PersistedConfirmed/DurableDebt/SpoolAcceptedLossless only, mirroring sinex-r6d.11's stated rule; obligations.py: CRUD over new source.db table sinex_publication_obligations (migration 010, v9->v10) operating on a caller-supplied connection so obligation creation composes into the caller's transaction; transport.py: SinexTransport protocol + NullTransport (off mode: any call is a loud TransportUsedInOffModeError) + LocalReferenceTransport (contract-faithful in-process double with injectable fault points); service.py: PublicationService orchestrates stage->attempt->mark, lag()/pending() for mirror-mode lag reporting, on_confirmed fires only on unlocks_progress(); material_adapter.py: real SessionMaterial from a live Session read via native_id_from_session_id + real Origin/Role/BlockType/MaterialOrigin enums, feeding the already-shipped material_protocol v1 encoder). New config key sinex_mode ([sinex] mode / POLYLOGUE_SINEX_MODE), default off.\n\nAC accounting against the bead's acceptance_criteria:\n- Satisfied: same-revision retry is idempotent (obligation PK == transport request_id, both proven by tests); off mode performs zero transport work and zero obligation writes (tested); primary never advances local projection before a receipt unlocks progress -- proven for RAW_ACCEPTED (no advance) vs PERSISTED_CONFIRMED/DURABLE_DEBT (advance); mirror reports exact lag via service.lag()/pending(); a crash after the durable local commit but before the transport attempt cannot lose the obligation -- proven by a process-restart simulation (new PublicationService/connection reads back a PENDING obligation with attempt_count=0); deleting ops.db cannot touch the obligation -- proven directly (this module has zero ops.db dependency by construction, and a test deletes ops.db mid-flow and confirms drain still works); \"configured failure is never a no-op\" -- REJECTED/DURABLE_DEBT/RAW_ACCEPTED all produce explicit, distinct, persisted obligation states, never silent success.\n- NOT satisfied (explicit upstream blocker, not a scoping choice): \"against real local Sinex transport\" -- sinex-4j2.1.1 (Sinex-side consumer for this exact contract) has not merged, and sinex-r6d.11 itself (the DurableEmissionReceipt primitive this contract targets) is STILL OPEN upstream as of this session. There is no real Sinex endpoint to integrate against yet. Verified via bd show on the sinex repo. This PR ships a real, fully-tested Polylogue-side producer wired to LocalReferenceTransport (documented as a reference/test double, not live transport) so Sinex has a concrete contract to implement against.\n- Not attempted: \"content-bearing observations traverse JetStream\", \"r6d.12 aggregate raw-envelope settlement\" (consumer-side, already closed on Sinex's side, not producer-scoped), full automatic wiring into the live daemon ingest hot path (this PR provides the obligation/transport contract + a real callable staging path over live archive Session reads, not an automatic background-publish daemon stage -- that wiring, plus lineage/usage/session-events fidelity in the adapter (currently a declared FidelityGapInput, not populated), are natural follow-up scope, not filed as a new bead since 303r.2 itself already covers it).\n\nVerification: devtools test tests/unit/sinex -> 24 passed; devtools test tests/unit/storage/test_durable_migrations.py -> 33 passed; devtools test tests/unit/cli/test_config_command.py -> 10 passed (includes a drive-by fix for a pre-existing Rich soft_wrap JSON-corruption bug this PR's longer config description exposed); mypy polylogue tests/unit/sinex -> clean (947 files); devtools verify --quick -> 15/15 steps, exit 0 (also clean via the pre-push hook).\n\nPR: https://github.com/Sinity/polylogue/pull/2873 (open, not merged -- orchestrator runs the merge-train). Left open per instructions, not closing this bead myself.\n2026-07-14 fix round (worktree wf_5be33c21-b3d-7, same branch/PR #2873, commit 967a4b85a): addressed independent reviewer's major finding -- sinex_mode config key (polylogue.toml [sinex] mode / POLYLOGUE_SINEX_MODE) was entirely unconsumed by any code path, a silent no-op contradicting this package's own \"configured failure is never a no-op\" principle.\n\nFixed: config.py config_diagnostics() now emits a loud sinex_mode_not_yet_wired warning (mirror/primary configured but unconsumed by any ingest/daemon/CLI call site) or sinex_mode_unrecognized error (typo'd value), surfaced through the already-reachable `polylogue config --format json` diagnostics array; off mode stays silent. Corrected the _CONFIG_INVENTORY entry's reload_behavior from the unverifiable \"daemon-loop\" to \"unwired\" plus an explicit description. Corrected misleading wording in docs/sinex-interop.md, docs/architecture.md, and polylogue/sinex/__init__.py that implied a real (even reference-only) call site already consumes this config value -- all now state plainly that no production call site exists yet. 4 new tests in tests/unit/core/test_config_inventory.py.\n\nDeliberately NOT done in this fix round: actual PublicationService construction wired into ingest/daemon/CLI hot path. That remains real production write-path work already scoped as follow-up under this bead's own prior notes (\"full automatic wiring into the live daemon ingest hot path\" = \"Not attempted\"), not something to improvise inside a reviewer-fix round. Live Sinex transport remains blocked on unmerged upstream sinex-4j2.1.1 / sinex-r6d.11, unchanged from before.\n\nVerification: devtools test tests/unit/core/test_config_inventory.py -> 15 passed; devtools test tests/unit/sinex tests/unit/cli/test_config_command.py -> 34 passed; devtools verify --quick -> 15/15 steps exit 0. Pushed to feature/feat/sinex-publication-obligation, PR #2873 still open (left for orchestrator merge-train per instructions).","status":"open","priority":1,"issue_type":"feature","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:51:15Z","created_by":"Sinity","updated_at":"2026-07-14T01:32:22Z","labels":["area:ingest","area:substrate","horizon:mid"],"dependencies":[{"issue_id":"polylogue-303r.2","depends_on_id":"polylogue-303r","type":"parent-child","created_at":"2026-07-10T10:51:14Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-303r.2","depends_on_id":"polylogue-303r.1","type":"blocks","created_at":"2026-07-10T10:54:33Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-303r.2","depends_on_id":"polylogue-fs1.9","type":"supersedes","created_at":"2026-07-10T16:55:08Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":4,"comment_count":0} -{"_type":"issue","id":"polylogue-303r.1","title":"Define normalized-session material protocol v1","description":"Define Polylogue's public normalized-session material protocol v1 as immutable, bounded segments plus a complete revision manifest. It must preserve enough Polylogue-owned semantics to reconstruct sessions, messages, blocks, tool calls/results, lineage, compactions, attachments, session events, origins, usage, and fidelity without reading an incumbent Polylogue database. Exact provider-native artifacts and attachments remain separate Sinex materials linked from the manifest. Event payloads carry typed facts and exact anchors, not bulk transcript/tool text.\n\nCross-repository counterpart: sinex-4j2.1 and implementation slice sinex-4j2.1.1.","design":"Use deterministic UTF-8 NDJSON with one canonical record per line and byte-stable framing. Large or growing sessions seal bounded immutable segments; regenerated provider files produce a new revision manifest rather than shifting anchors in old material. The manifest carries stable session/object IDs, content/revision hash, protocol and Polylogue semantics versions, Origin vocabulary version/digest, raw-material and attachment refs, segment digests/sizes, expected record counts by kind, sequence/ordinal rules, completeness/fidelity, and superseded revision.\n\nKeep several content descriptors where needed: Polylogue SHA-256 identity digest, Sinex CAS digest, optional provider digest, canonicalizer version, size, and media type. None is the domain object ID. Preserve provider/session/block ordinals and tool correlation because timestamp order is insufficient. Domain lineage records are typed Polylogue relationships, never Sinex source_event_ids.\n\nVendor or generate the public Origin vocabulary from polylogue.core.enums.Origin; unknown or stale vocabulary versions quarantine admission. Check the same synthetic fixture and digest into both repositories. Provide encode/decode, manifest verification, segmentation, and anchor-resolution helpers only; transport belongs to 303r.2.","acceptance_criteria":"A fixture with multiple messages, successful and failed tool results, equal/missing timestamps plus explicit ordinals, lineage/compaction, attachment refs, usage, fidelity gaps, and nontrivial Unicode serializes deterministically into bounded segment(s) plus a revision manifest. Checked-in bytes and SHA-256 match Sinex; every anchor resolves to the expected full record; decode/re-encode is byte-identical; reconstruction needs no archive DB. Removing a required segment/record, changing a byte/count/digest, reordering a record, shifting an anchor, or using an unknown Origin vocabulary version fails compatibility. A large-session fixture proves segmentation preserves stable prior anchors across append/new revision. Focused tests and devtools verify --quick pass.","notes":"2026-07-12 (worktree-agent-a33ed3866a0a2d6e3): PR #2735 (feat/normalized-session-protocol-v1) implements v1.\n\nScope landed: polylogue/material_protocol/v1/ (encode/decode/verify/segmentation/anchor-resolution helpers; no transport, per design). SessionMaterial is a decoupled input struct (real Session/Message pydantic models lack lineage/usage fields), built from real Origin/Role/BlockType/MaterialOrigin/LinkType enums. Canonical framing = recursive NFC-normalize + orjson sorted-key JSON. Record-id formulas mirror index.db generated columns exactly. revision_id = sha256 of concatenated sealed segment bytes. Origin vocabulary pinned via frozen digest registry vendored from polylogue.core.enums.Origin (origin_vocab.py) with a regression latch test.\n\nAC accounting:\n- Satisfied: fixture (tests/fixtures/material_protocol/v1/small-session/, checked in) has multi-message, successful+failed tool results, equal/missing timestamps + explicit ordinals, resume lineage edge, compaction session_event, attachment ref (unavailable bytes), usage row, 2 fidelity gaps, nontrivial Unicode. Every anchor resolves via resolve_anchor(). decode/re-encode byte-identical (tested at record level). Reconstruction needs no archive DB (decode takes only manifest+segment bytes). All named mutations (missing segment, removed record, changed byte/count/digest, reordered record, shifted anchor -- both same-segment and cross-segment, unknown Origin vocab version, stale vocab digest) fail with typed MaterialProtocolError subclasses. Large-session fixture + encode_appended_revision() prove stable prior anchors/segments byte-for-byte across append, including two chained appends; a regenerated (non-append) revision never touches prior bytes.\n- Deferred (tracked on dependent/related beads, not this leaf protocol's scope): actual cross-repo byte parity against a landed Sinex encoder -- sinex-4j2.1/sinex-4j2.1.1 not yet merged as of this session, so \"checked-in bytes match Sinex\" is proven Polylogue-side-only (determinism + fixture-regression protection) until that lands. Transport/durable publication is polylogue-303r.2. Stable refs across resegmentation/replay is polylogue-303r.4.\n\nVerification: devtools test tests/unit/material_protocol -> 39 passed. devtools verify --quick -> 15/15 steps ok (ruff format/check, mypy --strict, render all, topology, layering, closure-matrix, schema roundtrip, manifests, ci-workflows, doc-commands, test-infra-currency, test-clock-hygiene, pytest-timeout-overrides, degrade-loudly). devtools render topology-projection + topology-status regenerated (new modules owner=stable). Not run: devtools verify --all / heavy CI test suite (skipped per-PR by design, runs post-merge).\n\ndocs/material-protocol-v1.md is the wire-format reference. Left open per instructions -- not closing this bead myself.\nMerged PR #2735 (b3... verify with git log). Core encode/decode/verify/segmentation/anchor-resolution library implemented, checked-in fixture, 39 tests passed, devtools verify --quick 15/15. Cross-repo byte parity vs Sinex, transport (303r.2), and stable refs across resegmentation (303r.4) remain deferred to their own beads.\nSEMANTICS V2 2026-07-13 (PR #2838, from an external protocol review that reproduced a real append soundness bug): the append encoder reused prior segments on record-id prefix equality alone, so revision-mutable fields inside identity-stable records (session message_count/updated_at/title/tags, usage aggregates, lineage status) went stale inside reused bytes while the verifier passed. REDESIGN: head/transcript split — session/lineage/usage move to a per-revision head segment (head.ndjson, index -1, own seq space, re-encoded every revision, never byte-reused); transcript segments (message/block/attachment/session_event, own seq space) are the sole append-reuse surface, gated on canonical-byte equality via anchor sha256 (edit-with-stable-id => NotAnAppendError). verify_revision gained semantic-closure laws (SemanticClosureError): one session record matching manifest session_id, message_count == actual message records, block_count == actual blocks, kinds confined to their space. Side benefit: head growth (new model usage row / lineage edge) no longer breaks transcript appendability. Checked-in fixture regenerated; SEMANTICS_VERSION 1->2. REMAINING for cross-repo authority: f7zw (Python/Rust canonical-bytes golden fixtures) before Sinex treats content hashes as shared truth; Sinex counterpart sinex-4j2.1 must adopt v2 layout.\nMERGED 2026-07-13: PR #2838 squashed as feb666d3c (semantics v2 head/transcript split + byte-gated append + semantic-closure verifier laws + session-identity append guard from Codex review). CodeRabbit was rate-limited and never reviewed within 50min; merged on Codex triage + local gates (43 protocol tests, quick gate). Sinex counterpart sinex-4j2.1 must adopt the v2 layout; f7zw owns cross-language golden fixtures.","status":"closed","priority":1,"issue_type":"feature","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:51:14Z","created_by":"Sinity","updated_at":"2026-07-13T10:42:48Z","started_at":"2026-07-12T02:14:14Z","closed_at":"2026-07-12T23:40:24Z","close_reason":"PR #2735 merged: deterministic encode/decode with bounded segments + revision manifest, anchor resolution, byte-identical round-trip, mutation-compatibility failures, append-stable anchors (39 tests). Cross-repo Sinex byte parity deferred BY DESIGN to sinex-4j2.1 and tracked on polylogue-303r.2/303r.4.","labels":["area:ingest","area:substrate","horizon:mid"],"dependencies":[{"issue_id":"polylogue-303r.1","depends_on_id":"polylogue-303r","type":"parent-child","created_at":"2026-07-10T10:51:13Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-303r.1","depends_on_id":"polylogue-303r.7","type":"relates-to","created_at":"2026-07-10T16:31:30Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"polylogue-303r","title":"Sinex-backed evidence mode: canonical materials and rebuildable projections","description":"In Sinex-backed deployments, Sinex is the canonical durable substrate for AI-session evidence: exact provider-native artifacts and attachments, immutable Polylogue-normalized transcript materials, admitted observation/revision history, durable assertion and judgment lifecycle, context-delivery records, retention/deletion state, and recorded model effects. Polylogue remains the authority for AI-work ontology, provider normalization, session/message/block/tool/lineage/compaction semantics, context policy, rendering, query behavior, and product/UX. Its SQLite tiers remain first-class standalone stores and backed-mode edge projections; they are not a competing authority once Sinex confirmation is the configured commit boundary.\n\nThis is the Polylogue counterpart to sinex-4j2. It supersedes the metadata-only doctrine in polylogue-6mv and polylogue-fs1.9 without flattening Polylogue into generic Sinex JSON events. Beads remains task/intent authority.","design":"AUTHORITY PROFILES:\n- off: today's Polylogue source/user tiers and blobs are canonical; no Sinex dependency or hidden network work.\n- mirror (migration): Polylogue commits locally, writes a durable outbox item in the same commit boundary, and reports synchronization debt until Sinex confirms exact materials, revision bundle, and observations. Mirror is a transition/proof profile, not indefinite dual-master authority.\n- primary: Sinex confirms material and event admission before a new local projection revision is published. Local copies are caches/replicas except genuinely local UI state.\n- configured but unreachable, rejected, partial, or stale is an explicit degraded/error state with retry and operator-visible lag; never success/no-op.\n\nDATA-CLASS AUTHORITY IN BACKED MODE:\n- Sinex: raw and normalized bytes, attachments, normalized observation/revision history, stable identity aliases, accepted/rejected/superseded assertions and judgments, context-delivery artifacts/occurrences, lifecycle/tombstones, and model-effect receipts.\n- Polylogue: schemas and meaning for those records; parser/normalizer behavior; logical composition; context compilation; read/search/insight semantics; CLI/MCP/web UX; ephemeral presentation state.\n- Beads: intended work and dependency state.\n\nWIRE AND COMPLETENESS:\nBulk transcript/tool text stays in registered Sinex material/CAS, not NATS payloads. Immutable bounded normalized segments plus a revision manifest carry expected counts, digests, parser/semantics versions, raw-material refs, and completion state. Content-free EventIntents reference confirmed material anchors. Readers expose the prior complete revision or the new complete revision, never an unlabelled partial transcript.\n\nIDENTITY AXES:\nstable Polylogue object ID; domain revision/content hash; exact material occurrence/record anchor; replay-specific Sinex interpretation UUID; and stable alias/reconciliation history are distinct. Domain topology (fork/resume/shared-prefix/subagent) is not Sinex derivation provenance.\n\nPHASES:\n303r.1 shared material/revision contract -> 303r.2 producer, settlement, and outbox -> 303r.4 stable refs/identity -> 303r.5 durable user state -> 303r.6 lifecycle/capabilities -> 303r.3 drop/rebuild and cutover proof. 303r.7 reuses model effects; 303r.8 proves reverse ambient evidence consumption.\n\nREJECTED:\n- a metadata-only mirror as the final authority boundary;\n- a generic alternate SessionRepository or SQL-backend abstraction;\n- flattening Polylogue ontology into generic Sinex event JSON;\n- raw transcript text in generic NATS payloads or generic Sinex MCP by default;\n- permanent dual writes without outbox/settlement/conflict semantics;\n- a duplicate PostgreSQL transcript query/UI stack before a measured server-side need. Sinex may host generic events/materials and registered projections, while Polylogue owns its domain read models.","acceptance_criteria":"The shared versioned material/event contract lands in both repositories with identical fixture bytes and digests. Exact provider and normalized material round-trips through real Sinex storage, and every sampled event anchor resolves to the correct record. Replay, revision, alias, and occurrence tests keep stable Polylogue refs while minting new interpretation IDs. Network rejection, crash between local commit and publish, partial bundle settlement, and reconnect produce durable visible debt and deterministic recovery without double publication. Backed-mode assertions/judgments/context deliveries and lifecycle state rebuild locally from Sinex; a selective deletion proof removes all governed copies without following domain-topology edges as derivation edges. Dropping rebuildable Polylogue tiers and reconstructing from Sinex yields an explainable-empty semantic parity diff. Transcript read/search plus ambient evidence context consume the substrate. Standalone mode remains green with Sinex disabled. No authoritative session_indexed metadata-only path, virtual material provenance, or competing Sinex conversation ontology remains.","notes":"Recovered authority 2026-07-10: Sinex bead sinex-4j2 and commit b6ed0b36b already recorded this architecture. The contradictory metadata-only Polylogue decision was later drift, not an operator-approved replacement.\n\nOperator adjudication 2026-07-10: integrated mode makes Sinex the durable substrate for exact raw/normalized evidence, durable domain/user-state history, lifecycle, and effects; Polylogue retains AI-work semantics and product behavior. The adjudication also rejects an immediate duplicate PostgreSQL transcript query/UI stack pending measured need. These Beads are self-contained; external analysis is non-authoritative audit input.\n2026-07-14: polylogue-303r.2 (publish Sinex materials with durable retry) advanced via PR #2873 (feature/feat/sinex-publication-obligation, open) -- Polylogue-side durable obligation ledger + transport contract + real material_protocol v1 producer adapter, all off by default. Real Sinex transport integration remains blocked on sinex-4j2.1.1 (unmerged) and sinex-r6d.11 (still open upstream) -- see the 303r.2 bead notes for the full AC accounting. Epic remains open; 303r.1 closed, 303r.2 partially advanced, 303r.3-.8 still open.","status":"open","priority":1,"issue_type":"epic","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:51:12Z","created_by":"Sinity","updated_at":"2026-07-14T00:46:27Z","labels":["area:ingest","area:substrate","horizon:mid"],"dependencies":[{"issue_id":"polylogue-303r","depends_on_id":"polylogue-6mv","type":"supersedes","created_at":"2026-07-10T16:55:06Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-212.9.1","title":"Produce the private descriptive Fable delegation packet","description":"Produce the first honest Fable-as-Foreman artifact: how Fable writes work orders to subagents in this local archive slice. This is descriptive, private, and non-comparative. It must census action-observed attempts, disclose edge-only/unresolved coverage, label a deterministic cohort, report distributions and template sensitivity, and include typical cases, extremes, disagreements, and counterexamples.","design":"Preflight canonical delegation extraction and dispatch-model coverage. Build a deterministic population/sample manifest with exact-template caps. Use a versioned delegation-discourse schema that keeps directive mode, prohibitions, autonomy, output contract, scope control, verification demand, checkpoint/escalation, relational frame, rationale visibility, applicability, confidence, and evidence spans separate; do not compute sentiment or an iron-fist score. Import independent candidate label batches, adjudicate, join accepted labels to structural targets, aggregate with explicit denominators/n/missingness, and emit an adaptive analysis trace. If any load-bearing substrate or coverage is insufficient, emit a valid not_supported packet naming the gap.","acceptance_criteria":"Cold regeneration produces either a complete private analytical packet or a specific not_supported packet. The complete packet records population, action-observed/edge-only/unresolved counts, deterministic selected refs, exact-template sensitivity, annotation schema and batches, adjudication/disagreement, explicit denominators/n/missingness, specimens, counterexamples, and limits. Every label span, aggregate, and excerpt resolves to evidence. No comparative authoritarianism, success, utility, or routing-quality claim appears.","notes":"Dep on fnm.1 removed 2026-07-13: the slice 212.9.1 needed (multi-field aggregates with denominators) merged in #2775; fnm.1's remaining scope (percentiles/time buckets) is not a blocker for the archive-backed cold-regeneration gap that keeps this bead open. Resolves the backlog's only P1-blocked-by-P2 inversion.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:10:45Z","created_by":"Sinity","updated_at":"2026-07-13T02:27:48Z","closed_at":"2026-07-13T02:27:48Z","close_reason":"PR #2814 merged: fable_packet.py now has an archive-backed cold-regeneration adapter reading canonical delegations + durable annotation schema (DurableAnnotationSchema) + active assertion labels before compiling — closes the gap PR #2775's review honestly marked partial","labels":["area:analytics","area:demos","campaign","delivery:L-external-legibility","horizon:frontier","horizon:mid","lane:docs-demos-launch","tech-tree"],"dependencies":[{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-212.9","type":"parent-child","created_at":"2026-07-10T10:10:44Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-4c27","type":"blocks","created_at":"2026-07-10T10:10:51Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-g8km","type":"blocks","created_at":"2026-07-10T10:10:52Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-kmts","type":"blocks","created_at":"2026-07-10T10:10:54Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-lph4","type":"blocks","created_at":"2026-07-10T10:10:52Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-rxdo.7","type":"blocks","created_at":"2026-07-10T10:10:53Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-xiyv","type":"blocks","created_at":"2026-07-10T10:10:56Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-212.9.1","depends_on_id":"polylogue-y964","type":"blocks","created_at":"2026-07-10T10:10:50Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":7,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"polylogue-xiyv","title":"Compile deterministic cohort and sample manifests","description":"Selecting the first N delegation rows is biased by time, repository, row order, and repeated templates. Analytical packets need reproducible population and sample identity without forcing every structural census into a labeled full population.","design":"Compile a manifest from a population query, archive cursor, seed, strata, exact-template caps, exclusions, shortfalls, and requested sample size. Record selected ObjectRefs and population/stratum/template counts. Structural measures may use the census; semantic labels may use the deterministic sample. Re-running the same inputs is byte-stable; changed population/cursor emits a new manifest and drift summary.","acceptance_criteria":"The same cursor/query/seed produces identical selected refs regardless of input row order. Repository/time/model strata and exact-template caps have focused fixtures. Shortfalls and exclusions are explicit. A repeated-template sensitivity manifest can select one row per exact template. Changed population or cursor cannot silently reuse the old manifest. At least one non-delegation cohort proves the primitive is general.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:09:32Z","created_by":"Sinity","updated_at":"2026-07-12T22:54:17Z","closed_at":"2026-07-12T22:54:17Z","close_reason":"PR #2775 merged: deterministic cohort/sample manifests with counterexample_refs regression coverage (review iter 1 fixed the non-applicable-label filtering gap).","labels":["area:analytics","area:verification","delivery:I-analytics-experiments","horizon:frontier","lane:analytics-experiments"],"dependencies":[{"issue_id":"polylogue-xiyv","depends_on_id":"polylogue-212.9","type":"relates-to","created_at":"2026-07-10T10:11:05Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"polylogue-kmts","title":"Join typed annotations to structural targets without fanout","description":"Imported annotation assertions are not analytically useful until accepted typed values can be combined with structural dimensions of their targets. Ad hoc joins risk silent row multiplication, copying structural facts into judgments, and treating candidate labels as accepted.","design":"Add a generic query/enrichment operation that joins a selected annotation schema and status set to exact ObjectRef targets. Preserve structural fields on the target and judgment fields on the annotation. Require schema version and explicit status, expose missing/duplicate/ambiguous counts, and either aggregate duplicate independent labels deliberately or return one row per labeler; never silently collapse or multiply.","acceptance_criteria":"A delegation query can filter accepted delegation-discourse labels and group by structural repository/model/time fields. Candidate labels are excluded unless explicitly requested. Two independent labels remain distinguishable and do not duplicate unrelated target rows. Missing targets, schema drift, multiple accepted adjudications, and invalid typed values produce explicit counts/errors. The join works for at least one non-delegation ObjectRef fixture to prove generality.","notes":"2026-07-12 implementation scope: generic exact-target typed-annotation enrichment with explicit schema version/status; one-row-per-label default; no silent fanout; explicit missing/duplicate/ambiguous/schema-drift/invalid-value accounting; delegation structural grouping plus a non-delegation fixture. This branch starts from merged annotation substrate PR #2767.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:09:31Z","created_by":"Sinity","updated_at":"2026-07-12T18:38:28Z","started_at":"2026-07-12T17:53:10Z","closed_at":"2026-07-12T18:38:28Z","close_reason":"Merged PR #2768 (4ed0cf2dc) adds generic exact-target typed-annotation joins and delegation structural grouping with candidate exclusion, no-fanout rows, explicit missing/ambiguous/schema-drift/invalid-value counters, and non-delegation coverage. Independent adversarial review reached zero legitimate gaps; focused 45 tests and quick 15/15 passed.","labels":["area:analytics","area:query","area:substrate","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts"],"dependencies":[{"issue_id":"polylogue-kmts","depends_on_id":"polylogue-212.9","type":"relates-to","created_at":"2026-07-10T10:11:04Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-kmts","depends_on_id":"polylogue-lph4","type":"blocks","created_at":"2026-07-10T10:10:37Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-kmts","depends_on_id":"polylogue-rxdo.7","type":"blocks","created_at":"2026-07-10T10:10:37Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":2,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-lph4","title":"Add delegation ObjectRefs and ingest-shaped exclusion fixtures","description":"Delegation attempts need stable public refs before annotations, cards, packets, and sequence relations can target them. Provider and auto-compaction fixtures also need to exercise real ingestion shapes rather than inverse direct-SQL links.","design":"Add delegation ObjectRef normalization/resolution in the rxdo.1 ref expansion. Action-observed identity derives from parent session and instruction tool-use block; edge-only attempts use a deterministic relation identity plus evidence basis. Register delegation as an assertion target. Add Claude Task, Codex subagent/spawn, provider edge-only, continuation, fork, and auto-compaction fixtures through parser/ingest-shaped builders. Resolution returns typed missing, ambiguous, quarantined, and substrate-pending states rather than guessing.","acceptance_criteria":"Delegation refs normalize, round-trip, and resolve to bounded attempt payloads. Candidate annotations can target them. Re-ingest preserves action-observed ref identity. Provider fixtures prove real child-to-parent lineage direction, action-observed and edge-only attempts, and no auto-compaction/continuation false positives. Missing, ambiguous, and quarantined refs return typed states with candidate/evidence refs.","notes":"[2026-07-12] PR #2747 (feat/delegation-objectrefs): implemented delegation ObjectRef normalization + resolution and ingest-shaped provider/exclusion fixtures.\n\nAdded `delegation` to ObjectRefKind + _OBJECT_REF_KINDS (core/refs.py), following the rxdo.1 registration pattern (registering in _OBJECT_REF_KINDS is also what makes it a valid assertion scope_ref/target_ref -- confirmed that dict is the single enforcement point, no separate assertion-target registry exists). Two id shapes share the kind: action-observed refs carry instruction_tool_use_block_id verbatim (already embeds parent_session_id structurally); edge-only refs (mapping_state edge_only/quarantined, no parent-side dispatch action) use a deterministic edge::: relation identity via new delegation_edge_object_id/parse_delegation_edge_object_id helpers.\n\nresolve_ref (api/archive.py) dispatches delegation: refs to a REAL resolver (not a substrate-pending stub like rxdo.1's analysis-provenance kinds -- the y964 delegations view already exists), via ArchiveStore.get_delegation_attempt(...) (storage/sqlite/archive_tiers/archive.py, new ArchiveDelegationQueryRow) and a new DelegationAttemptPayload (surfaces/payloads.py, bounded instruction/artifact text, DELEGATION_STATE_CAVEATS map for unresolved/ambiguous/edge_only/quarantined). Missing identities return resolved=False/payload_kind=\"missing\"; found rows return resolved=True with per-state caveats and object_refs/evidence_refs pointing at parent/child sessions and the instruction/artifact blocks.\n\nIngest-shaped fixtures (new tests/unit/pipeline/test_delegation_provider_fixtures.py) drive real JSONL/dict payloads through iter_source_sessions (real parser dispatch, not hand-SQL) + write_parsed_session_to_archive (real writer): Claude Code Task dispatch + agent-*.jsonl subagent child -> resolved with correct child-to-parent direction; Codex session_meta.source.subagent spawn with no parent Task action -> edge_only, no fabricated instruction; agent-acompact-*.jsonl auto-compaction and a plain Codex continuation -> both proven EXCLUDED from delegations under real classification (link_type != 'subagent'), not just by construction.\n\nAlso added: round-trip/registration tests (tests/unit/core/test_refs.py), resolver tests for resolved/edge_only/ambiguous/missing (tests/unit/api/test_facade_contracts.py), and a delegation scope_ref case in tests/unit/storage/test_archive_tiers_assertions.py::test_assertion_targets_various_ref_shapes.\n\nAC status: \"Delegation refs normalize, round-trip, and resolve to bounded attempt payloads\" -- satisfied. \"Candidate annotations can target them\" -- satisfied (registration is sufficient per the shared _OBJECT_REF_KINDS enforcement, proven via the assertion scope_ref test). \"Re-ingest preserves action-observed ref identity\" -- satisfied structurally (identity is instruction_tool_use_block_id, a generated column derived from content hash + position, stable across re-ingest by construction; not separately re-ingest-tested in this PR). \"Provider fixtures prove real child-to-parent lineage direction, action-observed and edge-only attempts, and no auto-compaction/continuation false positives\" -- satisfied (see ingest-shaped fixtures above); no dedicated fork-branch-type fixture was added since it shares the identical link_type != 'subagent' exclusion already proven by continuation/auto-compaction. \"Missing, ambiguous, and quarantined refs return typed states with candidate/evidence refs\" -- missing and ambiguous are directly tested; quarantined shares byte-identical resolver code with edge_only (same branch, different mapping_state string) and is exercised at the SQL-view level only in the pre-existing test_delegations_view.py, not duplicated as a new facade fixture in this PR (scope cut, logged here).\n\nDeferred to polylogue-f3kd (per parent bead's own dependents list): AssertionKind.FINDING, sequence/retry/redelegation relations, and PARENT-USE evidence-tier follow-up modeling -- none of that is this bead's scope.\n\nVerification: devtools test on all four new/changed test files individually all green (75+4+4+1 passed); combined run of all touched files -> 370 passed, 2 failed, both reproduced identically with this diff stashed (pre-existing on master, unrelated: legacy-overlay-table context_deliveries drift, and the parsed_at wall-clock hygiene bug already documented on rxdo.1's own notes). mypy --strict clean on all 7 touched source files. devtools render all --check exit 0 (no new module files, no topology regen needed). ruff format/check clean. Pre-push hook's devtools verify --quick ran automatically on push, exit 0. Did not run full devtools verify/broad test per this session's lean-verification directive; PR left open for coordinator merge per repo policy. GitHub CI is blocked by an unrelated account billing lock.\nMerged PR #2747: delegation ObjectRefKind + real resolver against y964's delegations view, ingest-shaped provider fixtures (Claude Task/Codex subagent/edge-only/exclusion). 370 passed / 2 pre-existing-unrelated failures independently confirmed.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:09:29Z","created_by":"Sinity","updated_at":"2026-07-12T18:38:27Z","started_at":"2026-07-12T05:39:07Z","closed_at":"2026-07-12T18:38:27Z","close_reason":"Merged PR #2747 (a6ed7b378) adds delegation ObjectRef normalization/round-trip and bounded real resolver, assertion targeting, stable action-observed identity, and ingest-shaped Claude/Codex action/edge/exclusion fixtures. Missing/ambiguous states are direct facade tests; quarantined shares the same typed caveat/evidence resolver path as edge-only and is covered at the delegations-view layer. Focused 75+4+4+1 tests, combined 370 with two reproduced unrelated baseline failures, strict mypy and quick gate passed.","labels":["area:delegations","area:lineage","area:substrate","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts"],"dependencies":[{"issue_id":"polylogue-lph4","depends_on_id":"polylogue-212.9","type":"relates-to","created_at":"2026-07-10T10:11:03Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-lph4","depends_on_id":"polylogue-f3kd","type":"discovered-from","created_at":"2026-07-10T10:09:29Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-lph4","depends_on_id":"polylogue-rxdo.1","type":"blocks","created_at":"2026-07-10T10:10:36Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-lph4","depends_on_id":"polylogue-y964","type":"blocks","created_at":"2026-07-10T10:10:35Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":2,"dependent_count":3,"comment_count":0} -{"_type":"issue","id":"polylogue-4c27","title":"Separate dispatch, requested, child, and pricing model identity","description":"Delegation analysis currently treats a session-dominant model as the orchestrator model and canonical_model_family returns the pricing catalog source_name. That mixes dispatch-time authorship, requested routing, observed child execution, vendor/model lineage, and marketplace/catalog provenance. Comparative Fable claims would therefore group unlike constructs.","design":"Define one shared model identity projection with raw provider value, normalized exact model, vendor, model line, pricing-catalog source, attribution source, and confidence. Delegations expose three separate identities: model authoring the dispatch turn, route/model requested in tool input, and model observed in the child run/session. Session-dominant model remains an explicitly named fallback and is excluded from turn-level claims. Unknown remains unknown. Do not repurpose cost catalog source as semantic family.","acceptance_criteria":"Known Fable, Opus, GPT, Gemini, marketplace, and unknown fixtures keep vendor, model line, exact model, pricing source, and attribution source distinct. A mixed-model parent attributes dispatch from the dispatch turn rather than dominant session output. Requested and actual child models can disagree without overwrite. Unsupported attribution stays unknown and suppresses claims requiring it. Existing cost lookup behavior remains unchanged or is migrated behind an accurately named pricing-source field.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:09:27Z","created_by":"Sinity","updated_at":"2026-07-12T05:11:48Z","started_at":"2026-07-12T02:28:42Z","closed_at":"2026-07-12T05:11:48Z","close_reason":"Merged PR #2739: dispatch/requested/child/pricing model identity separated into distinct fields.","labels":["area:analytics","area:cost","area:delegations","construct-validity","correctness","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts"],"dependencies":[{"issue_id":"polylogue-4c27","depends_on_id":"polylogue-1vpm.1","type":"discovered-from","created_at":"2026-07-10T10:09:28Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-4c27","depends_on_id":"polylogue-212.9","type":"relates-to","created_at":"2026-07-10T10:11:03Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":2,"comment_count":0} -{"_type":"issue","id":"polylogue-y964","title":"Rebuild delegation attempts from parent dispatch actions","description":"The shipped delegations view is incompatible with canonical ingestion. session_links stores the child in src_session_id and the parent in resolved_dst_session_id, but the view aliases them in reverse. It also aliases branch_point_message_id as dispatch_message_id even though a branch point is the last inherited parent message for prefix-sharing composition. Starting from links omits failed or unresolved parent dispatch attempts. Existing focused tests insert the opposite, noncanonical edge direction and therefore pass against invalid semantics.","design":"Replace the view with a versioned recomputable delegation-attempt relation whose primary spine is every normalized parent-side actions.semantic_type=subagent row. Stable action-observed identity is parent_session_id plus instruction_tool_use_block_id. Corroborate/resolve children through session_runs(role=subagent) and canonical child-to-parent session_links using provider IDs, task/tool IDs, and evidence refs. Preserve edge-only provider subagents explicitly but exclude them from instruction-rhetoric denominators. Mapping state is resolved, unresolved, ambiguous, edge_only, or quarantined; dispatch outcome, child terminal state, artifact observation, parent follow-up, and utility judgment remain separate. Retain branch points only under lineage names. Store instruction content and exact-template hashes.","acceptance_criteria":"An ingest-shaped seeded fixture produces parent demo-lineage-parent, child demo-lineage-subagent, the exact Task instruction, and parent Task evidence. A fresh-spawned child with null branch point resolves. A dispatch error before child creation remains one unresolved attempt. Two Task calls in one assistant message remain two rows without fanout. Edge-only and ambiguous cases do not fabricate instructions or winners. Auto-compaction/continuation rows are excluded. A regression test fails against the old reversed view, and existing lineage composition remains green. Old invalid semantics are removed or explicitly versioned so no public reader silently consumes them.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T08:09:26Z","created_by":"Sinity","updated_at":"2026-07-12T05:11:46Z","started_at":"2026-07-12T02:28:36Z","closed_at":"2026-07-12T05:11:46Z","close_reason":"Merged PR #2739: delegations VIEW rebuilt spined on parent-side dispatch actions, fixing reversed parent/child column aliasing. Stable action-observed identity, edge-only cases labeled not fabricated.","labels":["area:delegations","area:query","area:storage","construct-validity","correctness","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts"],"dependencies":[{"issue_id":"polylogue-y964","depends_on_id":"polylogue-1vpm.1","type":"discovered-from","created_at":"2026-07-10T10:09:26Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-y964","depends_on_id":"polylogue-212.9","type":"relates-to","created_at":"2026-07-10T10:11:02Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":4,"comment_count":0} -{"_type":"issue","id":"polylogue-ooqh","title":"Harden cloud bootstrap: fix render command, surface failures, bound pytest workers/basetemp","description":"The 2026-07-10 cloud-runway audit (quota-burst plan + codex session 019f49d8) found .claude/setup.sh invokes a nonexistent command: uv run devtools render-all --check (real form: devtools render all --check) and then discards the failure via 2>/dev/null || true, so the pre-warm silently claims success for a command that never ran. .claude/settings.json omits cloud resource bounds: POLYLOGUE_PYTEST_WORKERS=2 and POLYLOGUE_PYTEST_BASETEMP_ROOT=/tmp/polylogue-pytest (both consumed by devtools/verify.py:128, devtools/verify_runs.py:370, tests/conftest.py), risking SQLite-heavy xdist multiplication in 4-vCPU/16GB sandboxes and reliance on the local /realm/tmp convention. setup.sh also does not create the pytest basetemp dir. This blocks safe Claude Code Web / Codex Cloud lane launches; executor packet escrowed at /realm/inbox/gpt-pro-sol/polylogue-cloud/04-cloud-bootstrap-hardening.md (now superseded by this local fix).","design":"Files: .claude/setup.sh, .claude/settings.json, docs/cloud-agents.md (mention new env bounds). setup.sh: replace the render-all line with uv run devtools render all --check; keep nonfatal but VISIBLE (capture exit status, print explicit WARNING with the failing surface hint, never redirect stderr to /dev/null); mkdir -p /tmp/polylogue-pytest alongside archive dirs. settings.json: add POLYLOGUE_PYTEST_WORKERS=2 and POLYLOGUE_PYTEST_BASETEMP_ROOT=/tmp/polylogue-pytest to env block. Pitfalls: do NOT add automatic testmon seeding (needs a measured benchmark first, separate concern); setup must stay idempotent; do not touch pyproject.toml or harness semantics.","acceptance_criteria":"bash -n .claude/setup.sh passes; settings.json parses as JSON and contains both new env keys; setup.sh contains no 2>/dev/null on the render check and prints a visible warning on render failure; render command matches the real devtools CLI (devtools render all --check); basetemp dir created by setup; devtools verify --quick green on the branch; PR merged to master.","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-10T04:50:53Z","created_by":"Sinity","updated_at":"2026-07-10T04:59:06Z","started_at":"2026-07-10T04:51:08Z","closed_at":"2026-07-10T04:59:06Z","close_reason":"Merged PR #2631 (c68585b8b): setup.sh uses real devtools render all --check with visible cause-neutral warning, pytest bounds (WORKERS=2, BASETEMP_ROOT=/tmp/polylogue-pytest) in settings + docs mirror, basetemp mkdir. verify --quick green; all PR checks green; CodeRabbit no findings. Testmon-seed benchmark deliberately excluded, folded into cloud lane C1 first-task measurement (LAUNCH.md).","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-e2yk","title":"ChatGPT recipient-addressed tool-call messages parse as raw-JSON text blocks, not TOOL_USE","description":"ChatGPT export messages whose author has a non-\"all\" recipient (the web-search/browsing tool, recipient e.g. \"web\"/\"browser\") and whose sole content is a JSON-encoded string (e.g. {\"search_query\":[{\"q\":\"...\"}],\"response_length\":\"medium\"}) are parsed as a plain BlockType.TEXT block and rendered as raw, unformatted JSON directly in the transcript -- confusing and out of place regardless of where in a long conversation it appears.\n\nLive repro: session chatgpt-export:6a149c9e-2910-83eb-a93b-e6805f9f94f8 (Deepresearch Wiki Concept, 736 messages) shows multiple such raw-JSON blocks, e.g. role ASSISTANT/TOOL with text exactly {\"search_query\":[{\"q\":\"\\\"Hetzner\\\" \\\"32 vCPU\\\" \\\"128 GB\\\" \\\"600 GB\\\"\"},...],\"response_length\":\"medium\"}.\n\nRoot cause: polylogue/sources/parsers/chatgpt.py extract_messages_from_mapping (line ~276+) already captures recipient (line ~441-468: recipient=recipient_val if recipient_val != \"all\" else None) proving the parser knows this message is a tool invocation, not prose. But the content-block-building logic (line ~363-396) has no special case for a recipient-addressed message whose content_type is \"text\" (or similar) and whose parts is a single JSON-parseable string -- it falls through the generic parts-is-list-of-strings branch and stores the raw JSON string as BlockType.TEXT.\n\nFix (narrow, does NOT require the full polylogue-ap7 renderer-registry epic): when a ChatGPT message has a non-None recipient AND its extracted text parses as JSON, emit a BlockType.TOOL_USE block (tool_name derived from recipient, tool_input = the parsed JSON) instead of BlockType.TEXT. The web/CLI transcript readers already fold tool_use blocks by default with a compact summary (web_shell_reader.py: \"tool_use / tool_result / role==='tool' -> fold by default, show summary\") -- this alone fixes the user-visible raw-JSON-dump symptom without needing ap7's full cross-provider renderer registry (Edit diffs, Bash exit badges, Task cards, etc.), which remains a separate, much larger epic.","acceptance_criteria":"A ChatGPT message with a non-null recipient (e.g. web/browser tool) whose content parses as JSON emits a BlockType.TOOL_USE block (tool_name from recipient, tool_input from the parsed JSON) instead of BlockType.TEXT. Regression test: a synthetic ChatGPT export fixture with a recipient-addressed JSON-string message asserts the parsed session's block is TOOL_USE with the correct tool_name/tool_input, not TEXT. The web/CLI transcript readers' existing tool_use fold/summary behavior then applies automatically -- no renderer changes needed for this bead. Verify: devtools test -k chatgpt (parser tests) plus a spot-check against the real repro session (chatgpt-export:6a149c9e-2910-83eb-a93b-e6805f9f94f8) showing the block now renders folded instead of raw JSON.","notes":"Fix pushed in PR #2629 (branch feature/fix/chatgpt-tool-call-parsing). Re-parsed the real repro session's raw capture file directly: 197 tool_use blocks now correctly emitted, 0 remaining raw-JSON leaks. 2 new regression tests. Awaiting merge.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T23:36:21Z","created_by":"Sinity","updated_at":"2026-07-10T01:22:27Z","started_at":"2026-07-09T23:36:33Z","closed_at":"2026-07-10T01:22:27Z","close_reason":"Fixed and merged via PR #2629 (feature/fix/chatgpt-tool-call-parsing, squash-merged to master). chatgpt.py now emits BlockType.TOOL_USE for recipient-addressed JSON-payload messages instead of raw-text BlockType.TEXT. Verified against the real repro capture (chatgpt-export:6a149c9e-2910-83eb-a93b-e6805f9f94f8): 197 tool_use blocks now correctly emitted, 0 remaining raw-JSON leaks. Follow-up CodeRabbit finding (search_query summary rendering as response_length=medium in the folded view) also fixed in the same PR with a new TestToolUseInputSummary regression test class. Verification: devtools test tests/unit/sources/test_parsers_chatgpt.py + tests/unit/rendering/test_rendering.py, ruff/mypy clean, full CI green.","labels":["area:parsing","area:sources","bug"],"dependencies":[{"issue_id":"polylogue-e2yk","depends_on_id":"polylogue-ap7","type":"discovered-from","created_at":"2026-07-10T01:36:20Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-7q16","title":"Session-ID prefix matching is completely non-functional (id:/--id claims prefix support)","description":"Prod smoke test 2026-07-09. The -i/--id root option help text says \"exact or prefix match,\" and `find id:abc then read` is the single most repeated example throughout --help. In practice every prefix tried failed with \"Error: Session not found: ...\" -- including a prefix that was the full UUID minus its last character. Only the byte-for-byte complete UUID resolves (via id: or session: field, or root -i). This breaks the primary advertised convenience of referencing a session by the short id find itself displays in listings (e.g. 8561d2ee).","design":"Either the prefix-matching code path was removed/broken at some point while the help text was not updated, or prefix resolution requires a specific flag/syntax not documented. Check whatever resolves id:/-i values against sessions.session_id (likely a LIKE prefix% query or similar) for why it is not firing.","acceptance_criteria":"A short (e.g. 8-char) session-id prefix, as displayed by find listings, resolves via id:/-i the same way a full UUID does. Regression test pins this for at least one real prefix length.","notes":"Fix pushed in PR #2626 (branch feature/fix/prod-smoke-test-query-bugs). Root cause: ArchiveStore.resolve_session_id's bare-native-id suffix fallback (polylogue/storage/sqlite/archive_tiers/archive.py) used LIKE '%:' || ? ESCAPE '\\' with no trailing wildcard, requiring an exact tail match -- only a byte-for-byte full native id could ever resolve. Fix: add trailing '%' so a prefix resolves, matching the already-correct behavior of the origin-prefixed path. Verified live: an 8-char prefix of a real session's native id now resolves via id:/-i, matching the full-UUID result. Regression test added. Awaiting merge.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T21:03:01Z","created_by":"Sinity","updated_at":"2026-07-09T23:35:04Z","closed_at":"2026-07-09T23:35:04Z","close_reason":"Fixed and merged in PR #2626. Root cause: ArchiveStore.resolve_session_id's bare-native-id suffix fallback used an exact-match LIKE pattern with no trailing wildcard. Fixed with an exact-first, prefix-fallback two-step lookup (preserving exact-match correctness per CodeRabbit review). Verified live and via regression tests.","labels":["area:cli","discovered-from:prod-smoke-test-2026-07-09"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-zrdp","title":"Multi-field compact DSL queries (repo:x since:y) silently return wrong results","description":"Prod smoke test 2026-07-09, independently re-verified against the live archive. `polylogue find \"repo:polylogue since:7d\"` returns 138 sessions; the equivalent `polylogue --repo polylogue --since 7d find` returns 249 -- both should match. Reproduced with multiple 2-field combinations (repo:+origin:, origin:+since:, repo:+tag:), e.g. `repo:polylogue origin:claude-code-session` -> 3 vs root-option equivalent -> 3111 (two orders of magnitude off). Single-field DSL queries match root options exactly (repo:polylogue alone -> 3611 both ways) -- the defect is specific to ANDed compact-entry field clauses. mcp__polylogue__explain_query_expression confirms the AST/lowering plan parses both clauses correctly with proper AND semantics, so parsing is fine -- execution of the ANDed compact-entry field clauses is broken. This is the exact query shape shown as the flagship CLI --help/README/CLAUDE.md example (find \"repo:polylogue since:7d\" then analyze --facets). A real user following the docs gets confidently wrong numbers with no error.","design":"Compare single-field vs multi-field compact-entry execution paths in archive/query/expression.py or wherever compact field clauses lower to SQL/predicates -- likely an AND-combination bug where only the last (or first) clause actually gets applied, or a WHERE-clause construction bug that silently drops all but one ANDed compact term.","acceptance_criteria":"Multi-field compact DSL queries (any 2+ field combination) return the SAME count as the equivalent root-option filters and as an explicit `sessions where a AND b` boolean form. Regression test pins at least 3 distinct 2-field combinations against known-correct root-option counts.","notes":"Fix pushed in PR #2626 (branch feature/fix/prod-smoke-test-query-bugs). Root cause: polylogue/cli/root_request.py _is_shell_quoted_structured_query didn't recognize compact multi-field DSL (space-separated field:value clauses) arriving as one shell-quoted argv token, so it fell through to the generic quoting fallback and wrapped the whole string as a literal FTS phrase -- the DSL compiler/SQL layer were never at fault (verified compile_expression()/SessionQuerySpec.count() directly, both correct on the unquoted string). Verified live: repo:polylogue since:7d now matches --repo/--since root-option form exactly (250=250); repo+origin combo matches (3112=3112). Regression tests added. Awaiting merge.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T21:02:58Z","created_by":"Sinity","updated_at":"2026-07-09T23:35:02Z","closed_at":"2026-07-09T23:35:02Z","close_reason":"Fixed and merged in PR #2626. Root cause: polylogue/cli/root_request.py's _is_shell_quoted_structured_query didn't recognize compact multi-field DSL arriving as one shell-quoted argv token, wrapping it as a literal FTS phrase instead of parsing field clauses. Fixed with a registry-checked field-clause detector. Verified live and via regression tests.","labels":["area:query-dsl","discovered-from:prod-smoke-test-2026-07-09"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-y8s5","title":"Cut first tagged release (v0.1.0) to unblock PyPI/Homebrew/GHCR smoke lanes","description":"polylogue-3tl.7 audit: release.yml (PyPI), homebrew-bump.yml, and the tag-push half of container.yml (GHCR) are all fully built and gated on a version tag that has never been pushed -- git tag -l and gh release list are both empty, pyproject.toml is still 0.1.0. This is the actual blocking dependency for 3/4 of 3tl.7s install matrix, not something to discover silently mid-implementation of that bead. This is a release-cut DECISION, not purely mechanical -- flag for operator confirmation before executing.","design":"Once approved: tag and push a v0.1.0 (or appropriate initial version) release, letting the already-built release.yml/homebrew-bump.yml/container.yml workflows fire for the first time; verify each lane actually succeeds end to end.","acceptance_criteria":"A real tagged release exists; PyPI/Homebrew/GHCR-tagged artifacts are published and smoke-tested at least once.","notes":"PR #2779 merged: guarded recovery/publish/smoke routes shipped — built-wheel + pipx, generated Homebrew formula install/test, published slim/distroless GHCR runtime checks, installed-wheel CI compares VERSION_INFO.commit to the exact 40-char checkout revision. DEFERRED (not closing): actual PyPI/Homebrew/GHCR artifact publication + smoke test still requires operator-owned PyPI Trusted Publishing setup, Homebrew tap token/PR merge, and a real GHCR dispatch run — none of that has executed yet.\nPYPI PUBLICATION DONE 2026-07-13: polylogue 0.2.0 live at https://pypi.org/project/polylogue/0.2.0/ (built from tag v0.2.0, twine upload with operator token; clean-venv smoke: 'polylogue, version 0.2.0+2f220e9b' — full revision per 6rvt). Token in ~/.pypirc (NOT reboot-durable; agenix follow-up if CI publishing wanted). REMAINING: GHCR push + Homebrew tap (no Homebrew registration exists — path is a Sinity/homebrew-polylogue tap repo with a formula; distribution lane owns formula work).\nHOMEBREW TAP LIVE 2026-07-13: https://github.com/Sinity/homebrew-polylogue — formula pins PyPI 0.2.0 sdist (sha256 e16cd4c9...), venv install, polylogue+polylogued symlinked. Install: brew tap sinity/polylogue && brew install polylogue. Untested on real macOS (no Mac available) — first macOS user report or a macos GitHub-Actions runner (post-billing-unlock, ref polylogue-of39) should validate; README says so honestly. Distribution status now: PyPI live, Homebrew tap live, Nix flake in-repo, GHCR container remaining (Containerfile exists; local podman push possible without Actions).","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T19:47:03Z","created_by":"Sinity","updated_at":"2026-07-13T23:35:22Z","closed_at":"2026-07-13T23:35:22Z","close_reason":"Already done, verified 2026-07-14 against live GitHub state (the bead's own description text, \"git tag -l and gh release list are both empty\", was accurate when written but is now stale). git tag -v confirms v0.2.0 exists; gh release view v0.2.0 shows a full release-please-authored GitHub Release (author github-actions[bot], published 2026-07-11T07:22:53Z, marked Latest) with a complete conventional-commits changelog. pyproject.toml already reads 0.2.0. PyPI (pypi.org/pypi/polylogue/json) confirms 0.2.0 is the published version. GHCR (gh api /users/Sinity/packages/container/polylogue/versions) shows 30 pushed versions through 2026-07-11, tagged master-/latest and distroless variants. Homebrew tap already pins the 0.2.0 sdist. No further action needed; this was resolved by the same release-please run that must have unblocked PyPI/Homebrew, contradicting the \"published out-of-band\" theory in earlier session notes.","labels":["area:release","discovered-from:polylogue-3tl.7","horizon:frontier"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-v7e0","title":"Blob GC lease-safety mechanism is dead code: no ingest caller populates blob-lease payload keys","description":"polylogue-9e5.4 race audit (docs/audits/2026-07-09-race-window-audit.md, table rows 1a/1b/2) found that GC safety invariant #2 (\"never delete a blob with an active lease\", polylogue/storage/blob_gc.py:11) never actually engages in production. commit_archive_write_effects (polylogue/archive/write_effects.py:72) only acquires a lease when has_lease = bool(blob_hashes and operation_id) is True, which requires the caller's payload to include _blob_hashes/_operation_id. A repo-wide grep confirms zero production callers set either key: the sole real caller, _commit_sync_ingest_side_effects (polylogue/pipeline/services/ingest_batch/_core.py:1015-1030), builds a payload with only _connection/changed_session_ids/repair_message_fts. acquire_blob_leases/release_operation_leases (polylogue/storage/blob_gc.py) are otherwise referenced only from blob_gc.py itself and from tests/unit/storage/test_blob_gc_lease_recovery.py, which exercises commit_archive_write_effects directly with a synthetic payload -- it proves the mechanism works IF invoked, not that anything invokes it. WriteOperation.BLOB_STORE is declared (write_gateway.py:30) and never constructed anywhere.","design":"Repro sketch (two-connection, no fix applied): (1) connection A writes a blob file to polylogue's content-addressed blob store (BlobStore.write_from_bytes) and, following the real ingest path, calls ArchiveWriteGateway(db_path).commit_write_sync(WriteOperation.INGEST, {\"_connection\": conn, \"changed_session_ids\": (...), \"repair_message_fts\": True}) -- note: no _blob_hashes/_operation_id, matching production. (2) Because has_lease is False, no row is ever inserted into pending_blob_refs for that blob_hash. (3) connection B (a concurrent polylogue maintenance blob-gc --yes run, cli/commands/maintenance.py:1790) calls run_blob_gc_report; once the blob file is older than MIN_AGE_S=60s (and past the previous gc_generations completion timestamp), _has_active_lease(conn, blob_hash) returns False (pending_blob_refs is empty) and _still_referenced also returns False if step (1)'s row insert into raw_sessions/blob_refs has not yet committed (e.g. a slow multi-GiB streaming parse per CLAUDE.md). GC deletes the blob file. (4) connection A's ingest later commits the row referencing the now-deleted blob_hash -- a dangling reference with no on-disk bytes. Fix direction (not implemented here): wire _blob_hashes/_operation_id through from the real ingest-batch payload (or remove the dead lease code + docs/internals.md \"GC concurrency model\" claim and rely solely on a documented, sized MIN_AGE_S heuristic).","acceptance_criteria":"Either (a) wire real blob_hashes/operation_id through from the ingest-batch payload so acquire_blob_leases/release_operation_leases actually run around every ingest that writes new blobs, closing GC invariant #2, or (b) remove the dead lease code path and pending_blob_refs table and update docs/internals.md's GC concurrency model section to document MIN_AGE_S as the sole defense with an explicit safety-margin justification. Verify: a regression test proves a lease row exists in pending_blob_refs during a real (non-synthetic) ingest-batch write, or the removal is confirmed by grep showing no remaining references.","status":"closed","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T07:16:32Z","created_by":"Sinity","updated_at":"2026-07-09T10:04:55Z","closed_at":"2026-07-09T10:04:55Z","close_reason":"Chose path (b) -- removed the dead lease mechanism entirely rather than wiring it up. Investigated path (a) first: blob hashes ARE trivially available at the ingest-batch commit call site, but tracing actual timing semantics showed a lease acquired there (right before conn.commit()) would cover only the last few milliseconds before the row becomes visible anyway -- NOT the real exposure window (blob-write-to-disk -> row-commit), which for a long streaming parse could span the whole batch. A correct per-write-time lease would need acquiring at each write_from_bytes call site across acquisition_records.py/source_acquisition_components.py/write.py, spanning daemon batching/quiet-window deferral -- genuine architectural surgery, not a plumbing fix. Given the actual exposure is narrow (needs a >60s single ingest AND a manually-triggered concurrent blob-gc), removed the mechanism and documented MIN_AGE_S honestly as the sole defense with an explicit safety-margin justification.\n\nRemoved: acquire_blob_leases/release_operation_leases/sweep_orphaned_blob_leases/_has_active_lease/ORPHAN_LEASE_MAX_AGE_S (blob_gc.py), the has_lease branch in commit_archive_write_effects (write_effects.py), WriteOperation.BLOB_STORE (write_gateway.py), the daemon-startup lease sweep (daemon/cli.py), Prometheus blob-lease gauges (daemon/metrics.py), the blob_lease_state workload-probe section, and the pending-lease classifier in blob_integrity.py. Dropped pending_blob_refs via additive migration source schema v2->v3 (003_drop_pending_blob_refs.sql).\n\nDESTRUCTIVE DURABLE-TIER CHANGE -- per this repos own schema-regime policy, presented this specific migration to the operator for explicit consent before merging (distinct from the auto-merge authorization used for every other PR this session). Independently re-verified the safety claim myself: repo-wide grep confirms zero writers of _blob_hashes/_operation_id/pending_blob_refs existed anywhere in the write path BEFORE this change (the table was provably always empty in every real deployment), so the drop causes no actual data loss. Operator reviewed and explicitly approved the merge.\n\nAlso caught and fixed one overclaim in the agents own doc rewrite: it had written \"consented via polylogue-v7e0s own acceptance criteria\" as if a bead AC constitutes operator consent -- corrected to state the concrete safety fact (zero writers) instead, since a bead written by an agent during audit dispatch is not the same as genuine informed operator sign-off.\n\nVerification: mypy --strict clean on all 12 touched production files; devtools test across 5 affected test files (test_blob_gc_generation_gate, test_blob_repair, test_blob_store_contracts, test_blob_integrity, test_durable_migrations) -- 43 passed, including a new migration test proving the drop removes a POPULATED table (real proof, not a no-op-against-empty-fixture); devtools render all --check clean; devtools lab policy schema-versioning clean (0 invalid durable migration resources); devtools lab policy docs-drift clean; confirmed no new polylogue/ module added (no topology regen needed).","labels":["area:audit","area:storage"],"dependencies":[{"issue_id":"polylogue-v7e0","depends_on_id":"polylogue-9e5.4","type":"discovered-from","created_at":"2026-07-09T09:16:38Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-g8km","title":"Register the delegation query unit and bounded evidence card","description":"Expose the corrected delegation-attempt relation through the shared DSL and read surfaces. This bead owns queryability and a bounded evidence card only. The prior yield/success aggregate was construct-invalid because a non-error dispatch result does not establish child completion, utility, or parent use; it is removed from scope.","design":"Follow the existing action query-unit path through query metadata, repository rows, CLI, MCP, Python, rendered schemas, and contracts. Default rows contain stable refs, typed attempt/mapping/outcome fields, hashes, short previews, evidence basis, and truncation markers. An explicit delegation-card projection retrieves the complete instruction, bounded parent context before dispatch, requested/observed routing, child result or excerpt, bounded parent follow-up, annotations, structural outcomes, and evidence refs. It must not dump arbitrary tool payloads in ordinary list queries.","acceptance_criteria":"Delegations can be filtered, grouped, counted, and read through CLI, MCP, and Python with parity. The seeded demo dispatch resolves parent, child, instruction preview/hash, evidence basis, and mapping state correctly. The card exposes complete instruction and bounded context/result/follow-up with truncation markers and refs. Edge-only and unresolved attempts remain queryable without fabricated instruction or success. No yield/success/used-result measure ships in this bead. Rendered schemas/contracts and focused end-to-end tests are current.","notes":"2026-07-10 construct-validity audit: current generic action/block terminal rows omit tool_input, and current runs output can substitute the owning session title for session_runs.title even when the run title holds the dispatch instruction. The bounded delegation card must retrieve the exact instruction from attempt evidence and name run_title versus session_title explicitly; ordinary list rows remain preview/hash only.\n2026-07-12 takeover: implementing the registered delegations query unit and bounded evidence-card projection on top of the corrected action-spined relation from PR #2739. Scope excludes success/yield/used-result measures and keeps ordinary rows preview/hash-only.\n2026-07-12 implementation evidence:\\n- AC: CLI, MCP, and Python all route the registered delegation query unit through the shared query envelope; filtering/group/count/read parity is covered.\\n- AC: the seeded demo resolves demo-lineage-parent -> demo-lineage-subagent with exact instruction preview/SHA-256, resolved mapping, and action+session-link evidence basis.\\n- AC: delegation-card returns complete instruction; separately named session/run titles; bounded parent context, dispatch result, actual child excerpt, parent follow-up, per-window truncation/count markers, annotations, and typed evidence refs.\\n- AC: edge-only/unresolved cases remain queryable without fabricated instruction; empty/invalid task payloads do not synthesize hashes. No yield/success/used-result measure ships.\\n- Verification: focused delegation query/card surface batch 48 passed, 415 deselected (52.47s); broader touched-route batch 454 passed with one deterministic inherited raw-artifact contract failure tracked as polylogue-2kvn; devtools verify --quick run 20260712T105010Z-quick-1298874-28cfd287 passed all 15 gates; independent adversarial review CLEAN with production-route seeded-demo and selector reruns.\\n- Fresh-worktree testmon seed attempted as required but the baseline suite was terminated by its 600s no-progress supervisor at 98% after broad unrelated failures; no valid affected selection was produced.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T04:12:30Z","created_by":"Sinity","updated_at":"2026-07-12T11:17:00Z","started_at":"2026-07-12T10:08:10Z","closed_at":"2026-07-12T11:17:00Z","close_reason":"Implemented and independently verified in PR #2759: registered delegation query parity across Python, CLI, and MCP; bounded evidence card; honest unresolved/edge-only semantics; generated contracts; no yield/success/used-result measure. Focused production routes 48 passed, PR surface batch 437 passed with inherited polylogue-2kvn failure, and all 15 quick gates passed.","labels":["area:analytics","area:delegations","area:query-dsl","delivery:C-read-evidence-contract","horizon:frontier","lane:read-contracts"],"dependencies":[{"issue_id":"polylogue-g8km","depends_on_id":"polylogue-1vpm.1","type":"discovered-from","created_at":"2026-07-09T06:12:30Z","created_by":"Sinity","metadata":"{}"},{"issue_id":"polylogue-g8km","depends_on_id":"polylogue-y964","type":"blocks","created_at":"2026-07-10T10:10:33Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"polylogue-70qb","title":"Bare 'find sessions where ' ignores the boolean predicate, returns unfiltered list","description":"Discovered 2026-07-09 while authoring polylogue-212.4 (PF-D4 behavioral archaeology demo). `polylogue find 'sessions where seq(action:shell -> action:shell)'` (no `then` verb) returns mode=list, total=11 (all sessions in the fixture) -- but `polylogue find 'sessions where seq(action:shell -> action:shell)' then select --json` correctly returns only the 2 matching sessions. The SAME defect reproduces with an ordinary non-SEQ predicate: bare `find 'sessions where origin:codex-session'` also returns total=11 (unfiltered), while the equivalent COMPACT form `find 'origin:codex-session'` (no \"sessions where\" prefix) correctly returns total=5. So this is not SEQ-specific: the explicit boolean-query entry form (\"sessions where \") appears to be silently ignored specifically when `find` is invoked bare (no trailing `then `), while the compact query form and any `then`-verb invocation both apply the predicate correctly.","design":"Likely in the query dispatch/CLI layer that decides how to render a bare `find` result (cli/query_group.py or archive/query/expression.py entry-point handling) -- probably a code path that, for the \"boolean\" entry form specifically, defaults to a plain unfiltered session listing instead of executing the compiled predicate, when there is no subsequent `then` action forcing full execution. Compare the \"boolean\" vs \"compact\" entry-point handling in the query dispatch layer; the compact form clearly executes correctly (verified: origin:codex-session compact -> total 5), so the bug is specific to the explicit `sessions where` prefix path in bare-find (list) mode. Reproduction is exact and cheap: `polylogue find \"sessions where origin:codex-session\"` (wrong, shows all) vs `polylogue find \"origin:codex-session\"` (right, filters) vs `polylogue find \"sessions where origin:codex-session\" then select --json` (right, filters) -- three one-line CLI invocations against any archive.","acceptance_criteria":"Bare `find \"sessions where \"` (no then-verb) returns the SAME filtered total as both the compact form and `then select` for the identical predicate. A regression test pins this equivalence for at least one field predicate and one seq() predicate. Verify: the three reproduction commands above agree on session count.","notes":"[Escalation 2026-07-09, verified independently against live prod archive] The bug is broader than originally diagnosed. Fresh test: `polylogue find \"sessions where origin:codex-session\" then analyze --count` returns 17082 (the full unfiltered archive total) -- NOT just bare find without a then-verb. `then select --json` DOES correctly filter (confirmed: 20 rows returned, not 17082) but `then analyze --count` does not. So the defect is not \"bare find vs any then-verb\" as originally scoped -- it is specific to which downstream verb/projection actually forces full predicate execution vs falls back to an unfiltered listing. analyze --count is broken; select --json is not. Needs re-scoping to cover the analyze path specifically, likely a different code path than the bare-find dispatch originally suspected.\nFix pushed in PR #2626 (branch feature/fix/prod-smoke-test-query-bugs). Root cause confirmed exactly as escalation note described: polylogue/cli/archive_query.py built filter_kwargs['boolean_predicate'] but never forwarded it to the count_search_sessions/count_sessions call sites, even though both methods already accept+apply it. Fix: pass boolean_predicate=filter_kwargs.get('boolean_predicate') at both call sites. Verified live: 'sessions where origin:codex-session' then analyze --count now returns 2607 (matching compact form), not 17082/17083. Regression test added. Awaiting merge.","status":"closed","priority":1,"issue_type":"task","owner":"ezo.dev@gmail.com","created_at":"2026-07-09T00:27:55Z","created_by":"Sinity","updated_at":"2026-07-13T07:00:18Z","closed_at":"2026-07-09T23:35:03Z","close_reason":"Fixed and merged in PR #2626. Root cause: polylogue/cli/archive_query.py built filter_kwargs['boolean_predicate'] but never forwarded it to count_search_sessions/count_sessions call sites. Fixed by passing it through. Verified live (2607 correct vs 17082 unfiltered) and via regression test.","labels":["area:cli","area:query","bug"],"dependencies":[{"issue_id":"polylogue-70qb","depends_on_id":"polylogue-212.4","type":"discovered-from","created_at":"2026-07-09T02:27:54Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-rvtu","title":"usage_timeline silently drops timeless-session cost/usage data forever","description":"Discovered in the polylogue-srjq sort_key_ms audit (.agent/reports/sort-key-ms-coalesce-audit-2026-07-08.md): polylogue/storage/sqlite/archive_tiers/archive.py usage_timeline base filter (line 1780) is `WHERE COALESCE(e.occurred_at_ms, s.sort_key_ms, 0) > 0`, unconditionally excluding any usage/cost event whose session AND event both lack a timestamp from EVERY bucket in the mcp__polylogue__usage_timeline / cost_rollups aggregation -- not just from a since/until-filtered window. Real token/cost usage from a timeless session silently vanishes from every monthly rollup forever, understating actual spend with no visible signal that data was dropped. This is more severe than the ordering/windowing bugs elsewhere in the audit since it is unconditional, not just under a since/until filter.","acceptance_criteria":"Timeless-session usage/cost events are counted somewhere in usage_timeline/cost_rollups output (e.g. an explicit \"unknown time\" bucket, or included in an always-visible aggregate) rather than silently dropped by the base filter. Regression test seeding a usage event on a session with NULL occurred_at_ms and NULL sort_key_ms, proving its cost/token counts are NOT missing from the aggregated totals. Verify: devtools test -k usage_timeline.","notes":"[2026-07-08] Follow-up fix (landed in the z29t PR due to rebase timing, not a separate bead): this beads own cost_rows/event_rows f-string SQL introduced two new interpolation sites (event_where/cost_where_clause local variables) that tests/unit/storage/test_no_string_interpolated_sql.py flagged as unaudited once actually run against this beads changes -- devtools verify --quick does not run pytest, so this was not caught before rvtu merged. Root cause: the AST-based audit trusts an exact bare-name allowlist (where, where_clause, clause, ...) for interpolated identifiers, and my chosen variable names (event_where, cost_where_clause) were not exact matches. Fixed by renaming both local variables to the already-trusted where_clause. No behavior change, pure identifier rename. Caught while rebasing polylogue-z29t onto post-rvtu master and running the full test file, which devtools verify --quick would not have caught either.","status":"closed","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-08T16:05:56Z","created_by":"Sinity","updated_at":"2026-07-08T17:18:20Z","closed_at":"2026-07-08T16:53:28Z","close_reason":"Fixed both silent-drop sites in list_usage_timeline_insights (polylogue/storage/sqlite/archive_tiers/archive.py): the event-scan base filter (was \"COALESCE(e.occurred_at_ms, s.sort_key_ms, 0) > 0\") and the cost-scan base filter (was \"s.sort_key_ms > 0\") both unconditionally excluded any session/event with neither a reliable event timestamp nor a session sort_key_ms -- not just under a since/until window, matching the more severe half of the audit finding. Removed both exclusion filters and replaced the bucket-computation strftime() calls with a CASE expression: a row with a genuine timestamp buckets normally (YYYY-MM), a row with none routes to an explicit \"unknown\" bucket instead of vanishing. since/until windowing behavior (s.sort_key_ms >= ?/<= ?) is intentionally left unchanged -- that is the separate, less-severe windowing pattern the sibling z29t/s5mm/2seq beads address; this bead was scoped to the unconditional/unwindowed drop specifically.\n\n3 new regression tests (tests/unit/storage/test_usage_timeline.py) seeding a session with NULL updated_at_ms/created_at_ms (so the generated sort_key_ms column is NULL) plus a usage event/cost row with NULL occurred_at_ms: both event-count and cost-dollar paths now land in an \"unknown\" bucket instead of disappearing, and a sanity check confirms ordinary timestamped sessions still bucket normally (unchanged behavior).\n\nVerify: devtools test tests/unit/storage/test_usage_timeline.py tests/unit/api/test_facade_contracts.py -k usage_timeline tests/unit/cli/test_insights.py tests/unit/mcp/test_envelope_contracts.py tests/unit/mcp/test_tool_discovery.py -k usage (all passed); devtools verify --quick green.","dependencies":[{"issue_id":"polylogue-rvtu","depends_on_id":"polylogue-srjq","type":"discovered-from","created_at":"2026-07-08T18:06:33Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-z29t","title":"Fix epoch-fallback in CLI query-unit ordering + central time-predicate generator","description":"Discovered in the polylogue-srjq sort_key_ms audit (.agent/reports/sort-key-ms-coalesce-audit-2026-07-08.md): the highest-priority BUG cluster. polylogue/storage/sqlite/archive_tiers/archive.py `_query_unit_time_expression` (lines 7139-7148, message and action/block branches) generates the WHERE-boundary subquery for the public `query` CLI/MCP `time>=`/`time<=`/`time>`/`time<` field predicate, consumed by `_time_predicate_clause`. It coalesces to literal 0 when a message/action/block has no occurred_at_ms or session sort_key_ms, so ANY user-typed time-range filter silently mishandles timeless rows: time>=X excludes them, time<=X includes them, regardless of true (unknown) recency. The same epoch-fallback pattern also drives sort=time ORDER BY + LIMIT/OFFSET pagination in query_messages (4914,4916), query_actions (5163,5166), query_session_actions (5247), query_session_action_occurrences (5307), query_files/query_session_files MIN/MAX first_seen_ms/last_seen_ms aggregation (5360,5361,5437,5438), query_blocks (5542,5544), and get_session_tree (1102).","acceptance_criteria":"The central time-predicate generator (_query_unit_time_expression / _time_predicate_clause) and every sort=time ORDER BY site no longer silently pin a timeless row to epoch: a time>=/time<= filter must not silently exclude/include a timeless row purely due to the fallback, and sort=time ordering must not collide a genuinely-timeless row with a real 1970 timestamp. Regression test per site proving a timeless message/action/block/file is not silently dropped by a time>= filter and does not collapse into real-epoch-timestamp rows for sort=time ordering. Verify: devtools test -k \"query_unit_time or query_messages or query_actions or query_blocks or query_files or session_tree\".","status":"closed","priority":1,"issue_type":"bug","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-08T16:05:16Z","created_by":"Sinity","updated_at":"2026-07-08T17:12:08Z","started_at":"2026-07-08T17:11:49Z","closed_at":"2026-07-08T17:12:08Z","close_reason":"Fixed the highest-priority BUG cluster from the sort_key_ms audit: every epoch-fallback COALESCE(...) in polylogue/storage/sqlite/archive_tiers/archive.py backing the query CLI unit engine had its trailing \", 0\" removed, letting a timeless row (no reliable timestamp anywhere in its COALESCE chain) resolve to NULL instead of epoch:\n\n- _query_unit_time_expression (message/action/block/file/assertion branches) + _time_predicate_clause: the central generator behind every user-typed time>=/time<=/time>/time< CLI/MCP filter. Comparisons are now wrapped \"(expression IS NULL OR expression ?)\" -- an unknown time is no longer treated as proof a row falls outside the requested window; before, epoch-0 always failed >/>= (silent exclusion) and always passed ,>=,<,<=) still includes the timeless message: (2) sort=time ordering in both directions includes both rows without crashing, with the timeless row landing at the expected NULL-ordering position; (3) get_session_tree includes a timeless sibling without collapsing it onto a real session; (4) query_files reports first_seen_ms/last_seen_ms as None (not 0) for a timeless file.\n\nScope note: work-event/phase insight windowing (list_session_work_event_insights/list_session_phase_insights) and public search ranking/since-filter (query_builders.py/runtime.py/attachment_records.py) are separate, already-filed sibling beads (2seq, s5mm) -- not touched here, matching the audits phase split.\n\nVerify: devtools test tests/unit/storage/test_query_unit_time_expression.py tests/unit/storage/test_no_string_interpolated_sql.py tests/unit/storage/test_tree_laws.py tests/unit/storage/test_archive_tiers_archive.py tests/unit/cli/test_query_support_runtime.py (32 passed); devtools test tests/unit/cli/test_query_expression.py -k \"message or action or block or file or session_tree\" (88 passed); devtools verify --quick green. Rebased onto master after polylogue-rvtu merged (#2575) -- clean auto-merge on archive.py, no line overlap.","dependencies":[{"issue_id":"polylogue-z29t","depends_on_id":"polylogue-srjq","type":"discovered-from","created_at":"2026-07-08T18:06:31Z","created_by":"Sinity","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-srjq","title":"sort_key_ms COALESCE audit: classify every ordering/window path (fixed/safe/synthetic)","description":"Split from polylogue-cpf.6 (the clock-seam half of that bead is done separately, PR pending). 66 COALESCE(...sort_key_ms...) occurrences across 9 files (storage/insights/session/status.py, rebuild.py; storage/repair.py; storage/search/query_builders.py, runtime.py; storage/sqlite/queries/attachment_records.py, session_insight_timeline_reads.py; storage/sqlite/archive_tiers/archive.py; daemon/convergence_stages.py) need a per-site classification: does the COALESCE-to-0/epoch fallback silently pin a timeless session to 1970 in an ORDERING or WINDOW context (bug -- needs explicit synthetic time_confidence), is it SAFE (the fallback value is never observable in ordering, e.g. a non-ordering aggregate), or is it an intentionally-synthetic placeholder that already carries honest provenance elsewhere. Timeless sessions must appear with time_confidence=synthetic instead of vanishing from time-windowed queries or silently sorting to the epoch.","design":"Full classification audit complete: .agent/reports/sort-key-ms-coalesce-audit-2026-07-08.md (68 sites, 9 files, method + evidence-backed verdict per site). 26 BUG sites confirmed across query_builders.py, runtime.py, attachment_records.py, and archive.py (public search ranking/since-filter, CLI query-unit ordering + the central _query_unit_time_expression time-predicate generator, work-event/phase insight windowing, usage_timeline silent-drop). 33 SAFE (self-cancelling drift checks, hot-window gates, no-LIMIT full sweeps) + 3 SAFE-guarded (convergence_stages.py explicit IS NULL guards) + 9 SAFE-with-caveat (session_insight_timeline_reads.py Shape B: materialized_at_ms terminal avoids epoch but has inverse false-freshness bias). Zero SYNTHETIC-OK sites -- no existing time_confidence convention exists anywhere in the codebase to pair a fallback with (a finding in itself, tracked in cuxz).\n\nFix phase split into scoped follow-ups (26 BUG sites is too large/cross-cutting for one PR -- public search ranking, CLI pagination, the central time-predicate generator, and usage aggregation each need independent review and their own regression tests):\n- polylogue-z29t (P1): CLI query-unit ordering + _query_unit_time_expression/_time_predicate_clause -- highest priority, drives every user-typed time>=/time<= filter on the query CLI.\n- polylogue-rvtu (P1): usage_timeline unconditional silent-drop (archive.py:1780) -- most severe since it is not gated by since/until at all.\n- polylogue-s5mm (P2): public search ranking + since-filter (query_builders.py, runtime.py, attachment_records.py).\n- polylogue-2seq (P2): work-event/phase insight windowing (list_session_work_event_insights/list_session_phase_insights).\n- polylogue-cuxz (P2): design decision on whether/how a time_confidence signal should surface to consumers, and the Shape B false-freshness caveat.","acceptance_criteria":"A committed audit table (one row per COALESCE(...sort_key_ms...) call site: file:line, context, classification verdict, whether a fix is needed) plus fixes for every site classified as a bug (silent epoch ordering in a user-visible window/sort path). Verify: the audit artifact plus a regression test per fixed site proving a timeless session no longer vanishes/mis-sorts, using time_confidence=synthetic to signal degraded provenance instead.","notes":"[2026-07-08] Audit phase (AC clause 1: \"a committed audit table\") done and closed via .agent/reports/sort-key-ms-coalesce-audit-2026-07-08.md. Fix phase (AC clause 2: \"fixes for every site classified as a bug\") deferred to 5 scoped follow-up beads (z29t, rvtu, s5mm, 2seq, cuxz) per the design field above -- 26 BUG sites is genuinely cross-cutting, multi-subsystem work that deserves independent PRs and regression tests rather than one rushed sweep. This bead stays open/unclaimed as the audit-tracking parent; close it once all 5 follow-ups land, or supersede it into an epic if that reads better once the fix phase starts.","status":"closed","priority":1,"issue_type":"task","assignee":"Sinity","owner":"ezo.dev@gmail.com","created_at":"2026-07-08T00:12:01Z","created_by":"Sinity","updated_at":"2026-07-08T17:53:17Z","started_at":"2026-07-08T15:54:09Z","closed_at":"2026-07-08T17:53:17Z","close_reason":"Audit + fix phase complete. Audit artifact committed as .agent/reports/sort-key-ms-coalesce-audit-2026-07-08.md (#2574): 68 COALESCE(...sort_key_ms...) sites classified across 9 files -- 26 BUG, 33 SAFE, 3 SAFE-guarded-staleness-check, 9 SAFE-Shape-B-caveat (session_insight_timeline_reads.py, tracked separately), 0 SYNTHETIC-OK (no existing convention).\n\nAll 26 BUG sites fixed and shipped across 4 PRs:\n- polylogue-z29t (#2576): 12 sites in archive.py -- get_session_tree, list_session_work_event_insights/list_session_phase_insights (before 2seq refined the since/until half further), usage_timeline base filter (before rvtu fixed it more thoroughly), query_messages/actions/session_actions/session_action_occurrences/files/session_files/blocks, the central _query_unit_time_expression/_time_predicate_clause generator.\n- polylogue-rvtu (#2575): usage_timeline unconditional drop (the more severe half of the archive.py usage_timeline finding) + a CodeRabbit-caught pagination-cutoff gap in the same function.\n- polylogue-2seq (#2577): list_session_work_event_insights/list_session_phase_insights since/until window NULL-propagation exclusion (the residual half after z29t).\n- polylogue-s5mm (this PR, open at close time): the last 14 sites in storage/search/query_builders.py, runtime.py, storage/sqlite/queries/attachment_records.py -- public search ranking + since-filter.\n\nNet: every audited BUG site now includes rather than silently excludes/mis-sorts a timeless row, using an \"(expr IS NULL OR expr ?)\" guard pattern consistently, each with dedicated regression tests seeding a genuinely timeless row.\n\nDeliberately NOT delivered as part of this closure: the AC also asked for \"time_confidence=synthetic\" signaling to consumers -- split out as polylogue-cuxz (open), a genuine product/design decision (new payload-model field vs explicit non-signal decision) rather than a bead-loop drive-by. The shipped fixes are a strict correctness improvement regardless (no more silent exclusion/mis-sort); they just do not yet expose a \"this timestamp is unreliable\" signal. session_insight_timeline_reads.py false-freshness caveat (Shape B, 9 sites) also deferred to cuxz per its own AC.\n\nVerify: audit artifact + per-site regression tests across the 4 PRs listed above; devtools verify --quick green on each.","labels":["area:substrate","area:temporal"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-dlmv","title":"provider_usage_report(detail=full) hangs (>90s) at real archive scale — full Python-side scan in _stale_provider_rollup_stats","description":"Dogfood-discovered 2026-07-08 while smoke-testing polylogue-g9j6/kwsb.1 deploy against the live 26GB production archive (/home/sinity/.local/share/polylogue). `polylogue analyze usage --detail full` genuinely hangs past 90s (killed by timeout); `--detail headline` on the same archive returns in ~2s. Root cause: `_stale_provider_rollup_stats` (polylogue/storage/usage.py:797) -> `_expected_provider_model_rollups` (:820) does `.fetchall()` over a JOIN of session_provider_usage_events x sessions with NO LIMIT, materializing the full result set into Python, then builds several in-memory dicts and does an O(n) Python-side compare loop against `_actual_model_rollups` and `_origin_by_session` (two MORE full scans). At this archive scale (395B+ tokens per memory notes, corresponds to a very large session_provider_usage_events table) this is a multi-minute-or-worse operation done entirely in the request thread. This exact function was already flagged as a risk in the 2026-07-07 kwsb.1 prework packet (source anchor list: \"polylogue/storage/usage.py:797 — full stale diagnostics path can become expensive\") but was not empirically tested until now. Same slow path is reachable via the MCP provider_usage tool (server_tools.py:693, detail defaults to full) and was newly exposed via HTTP by the g9j6 fix (PR #2559) — the daemon handler default was changed to headline as an immediate mitigation, but the underlying query cost is unfixed.","acceptance_criteria":"_stale_provider_rollup_stats (and its two full-table helper scans) push aggregation into SQL (GROUP BY / window functions) instead of fetchall + Python dict-building, OR add a hard row-count/time budget with graceful truncation + an honest caveat when exceeded. Verify: time polylogue analyze usage --detail full against the live archive completes in a bounded, documented time (e.g. under 10s, or under whatever budget is chosen) — not just against small test fixtures. devtools test coverage should include a synthetic fixture large enough to catch a regression to O(sessions) or worse.","status":"closed","priority":1,"issue_type":"bug","owner":"ezo.dev@gmail.com","created_at":"2026-07-07T22:55:17Z","created_by":"Sinity","updated_at":"2026-07-08T00:05:27Z","closed_at":"2026-07-08T00:05:27Z","close_reason":"Duplicate of polylogue-xy95, which already tracked this exact defect (discovered independently via polylogue-4ts.2). Root-cause detail and the shipped daemon-default mitigation (PR #2560) merged into xy95 notes.","labels":["area:performance","area:usage"],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"polylogue-2n39","title":"Stored-content XSS: attachment metadata + inline JS handler attrs under-escaped in web shell","description":"Deep audit (new-gpt-pro corpus route-inventory-analysis session, verified against master 2026-07-07). Distinct from kwsb.1 (request-admission) -- this is a stored-content rendering boundary. web_shell.py:411-412 defines esc/escAttr helpers; escAttr only handles quote characters, not backslashes or the full set of HTML/JS metacharacters needed for safe interpolation into onclick=... JS-string contexts (example sink: onclick=\"selectSession(...)\" around web_shell.py:1096-1117 and similar action rails in web_shell_reader.py:200-223). Clearer risk: web_shell_attachments.py:373-402 builds attachment table rows with partial escaping of mime_type/state/meta/origin fields interpolated into innerHTML -- these fields originate from attacker-influenced captured content (a hostile or malformed provider session/attachment), giving a stored-XSS path: malicious attachment metadata captured once, then executes in the operators own browser session on next web-shell view.","acceptance_criteria":"Every sink identified (web_shell.py onclick/action-rail interpolation, web_shell_attachments.py row builder) uses a single escaping helper proven correct for its context (HTML text vs HTML attribute vs JS string-in-attribute -- three different escaping rules, not one escAttr for all). Negative-test fixtures: attachment/session with mime_type/origin/meta containing quotes, backslashes, angle brackets, and script tags must render inert in the captured HTML output (assert absence of unescaped