fix(insights): finish typed session-PR evidence + wire root: filter - #3431
Conversation
Problem: verifying polylogue-pbuh AC4 (typed session->PR evidence now has readers, per PR #3425) by running `read --view correlation` against a real session in the live archive raised `NameError: name 'SessionCorrelationResult' is not defined` -- the default github_api=True path in _enrich_with_github_api never worked. The class was imported only under `TYPE_CHECKING` (line 11) but constructed at runtime at the function's return statement. This bug predates PR #3425 (present since ac84f73); the existing test suite only exercised github_api=False, so it went uncaught. What changed: import SessionCorrelationResult inside _enrich_with_github_api alongside the existing runtime GitHubRef import, and add a regression test that exercises the default github_api=True path with a mocked `gh` failure (the common case in CI/sandboxes without gh installed). Verification: devtools test tests/unit/cli/test_correlate_view.py (4 passed, including the new regression test); manually confirmed against the live archive (read-only, /realm/db/polylogue/index.db) that `find id:<session> then read --view correlation --format json` now returns typed pr_refs (source=typed_session_ref) and a disagreements list instead of crashing. Co-Authored-By: Claude <noreply@anthropic.com>
Problem: polylogue-cijx.4 decision 4 ("default result unit is the
top-level session") and its split-off follow-up polylogue-oqib found
that `sessions.parent_session_id`/`Session.is_root` are correct and a
plan-level `root: bool | None` field + `.is_root()` fluent builder
already existed, but `root` had no `spec_attr`, no query-DSL grammar
case, and no CLI flag -- completely unreachable from any query surface.
What changed:
- SessionQuerySpec gains `root: bool | None`, wired through
`build_query_spec_from_params`/`query_spec_to_plan` (archive/query/spec.py)
and a new `optional_bool` tri-state parser.
- DSL grammar: `root:true`/`root:false` field clause in the compact-query
transformer (archive/query/expression.py); negation (`-root:...`) is
rejected with a message pointing at `root:false` instead, since the
boolean value already carries polarity.
- CLI: `--root/--no-root` flag (cli/click_option_groups.py), threaded
through the root `cli()` signature per this repo's "new Click params
go last" convention.
- Field metadata/discovery: `EXPRESSION_FIELD_REGISTRY["root"]`
(archive/query/metadata.py) and the generated unknown-field diagnostic
in archive/query/discovery.py + docs/search.md (`devtools render all`).
Deeper bug found while making this reachable: the CLI's actual browse/
search path (`polylogue/cli/archive_query.py`'s `_ArchiveFilterKwargs` ->
`ArchiveStore.list_summaries`/`search_summaries`/`count_sessions`/
`count_search_sessions`/`search_session_ids`/`semantic_summaries`/`stats`/
`stats_by`) is a SQL-level filter path entirely separate from the
`SessionQueryPlan`/`apply_common_filters` post-filter machinery `root`'s
field descriptor was designed against. None of those eight ArchiveStore
methods accepted a `root` kwarg or passed it to `_session_filter_clause`,
so wiring the DSL/CLI/spec layers alone would have produced a flag that
parses successfully but silently filters nothing. Fixed by pushing
`root` into `_session_filter_clause` as a direct SQL predicate
(`sessions.parent_session_id IS [NOT] NULL` -- trivially SQL-pushable,
unlike `continuation`/`sidechain` which derive from `branch_type`) and
threading it through all eight methods plus `_ArchiveFilterKwargs`.
Second bug found during verification: even the `SessionQueryPlan` post-
filter path (used by the Python API's `list_summaries_archive`/`list_archive`)
was silently broken -- `ArchiveSessionSummary` (storage/sqlite/archive_tiers/archive.py)
never carried `parent_id` (the SELECT never projected
`sessions.parent_session_id` and `_summary_from_row` never read it), and
`_summary_to_domain` (archive/query/archive_execution.py) never passed it
to `SessionSummary`, so `is_root` was `True` for every summary row
regardless of actual parent. Fixed by adding `parent_id` to
`ArchiveSessionSummary`, projecting `s.parent_session_id` in both
`read_summary` and `list_summaries`' SELECTs, and threading it through
`_summary_to_domain`.
DEFAULT-BEHAVIOR DECISION: did NOT flip any surface's default result set.
`find`/Python API `list()`/MCP query/daemon HTTP all continue to return
every session (root and child) unless `root:`/`--root`/`.is_root()` is
given explicitly. Justification: flipping the CLI `find` default alone
(cijx.4's suggested narrower option) still has real blast radius --
every existing test, saved query, and demo script that assumes today's
"everything" default would need re-auditing, and the operator's own
framing of AC4 treats reachability as the wedge, not an implicit
behavior change. Exposing the filter without changing the default lets
`polylogue find repo:polylogue root:true` immediately produce the named,
non-fanout view AC4's proof text asks for, without a silent behavior
change for every unfiltered caller. The default question itself is left
open as a deliberate, separately-reviewable follow-up.
Not done (explicitly out of scope, noted for follow-up): `root` is not
wired into `query_unit_session_filters` (the `with <units>` projection's
separate session-filter adapter), and daemon HTTP's `_build_query_spec_params`
named-param allowlist does not include a dedicated `?root=` query param
(the existing `?query=root:true` DSL path already covers it via
`compile_expression_into`). `continuation`/`sidechain`/`has_branches`
remain unreachable exactly as before -- this PR does not touch them.
Verification:
- devtools test tests/unit/cli/test_query_expression.py
tests/unit/core/test_query_fields.py tests/unit/cli/test_archive_query.py
tests/unit/archive/test_archive_execution_filters.py
tests/unit/cli/test_query_exec_laws.py tests/unit/archive/
tests/unit/storage/test_archive_tiers_archive.py
tests/unit/archive/query/test_discovery.py -> all green (new
test_root_filter_partitions_top_level_and_subagent_sessions covers all
eight ArchiveStore methods + the parent_id/is_root wiring bug).
- mypy --strict on every touched module: no issues.
- devtools render all --check: sync OK (docs/cli-reference.md,
docs/search.md regenerated).
- devtools verify --quick: exit 0.
- Manual live verification (read-only, /realm/db/polylogue/index.db):
`find repo:polylogue --root --format json` -> total 1906;
`find repo:polylogue --no-root --format json` -> total 3206;
1906 + 3206 = 5112, the unfiltered total -- confirms the SQL pushdown
partitions the real archive exactly, not just a fixture.
Co-Authored-By: Claude <noreply@anthropic.com>
Captures the bd note updates made while verifying polylogue-pbuh AC4 and polylogue-cijx.1 (PR #3425 merge, correlation_view.py NameError fix, and disposition notes on the four cijx.1 dependents 212.2/xyel/kph/fs1.4). These landed in the main checkout's .beads/issues.jsonl via the cwd-independent bd export path (known hazard) instead of this worktree's copy; re-synced here so the branch carries the current bead state. Co-Authored-By: Claude <noreply@anthropic.com>
polylogue-oqib: reachability (spec_attr/DSL/CLI + the two deeper SQL-pushdown and parent_id-wiring bugs found along the way) is done; narrowed remaining scope to the default-behavior decision only, and lowered priority accordingly. Re-synced from the main checkout's .beads/issues.jsonl (same cwd-independent bd export hazard as the prior beads commit on this branch). Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 74ce554df0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "--root/--no-root", | ||
| "root", | ||
| default=None, | ||
| help=( | ||
| "Only top-level sessions (--root) or only subagent/branch children " | ||
| "(--no-root). Unset (default) selects both, unfiltered by structure." |
There was a problem hiding this comment.
Carry root through daemon query execution
When a daemon is reachable—the normal polylogued run setup—ordinary find pages take _try_emit_daemon_session_page, but _daemon_session_query_params never sends this new flag and _daemon_session_page_supported does not force a local fallback. Even root:true transported as DSL is discarded because polylogue/daemon/http.py::_archive_filter_kwargs_from_spec omits root; consequently --root, --no-root, and the DSL form return unfiltered rows on the daemon path. Thread the tri-state value through both daemon adapters or disable that fast path for root-filtered requests.
AGENTS.md reference: AGENTS.md:L193-L197
Useful? React with 👍 / 👎.
| "since_ms": since_ms, | ||
| "until_ms": until_ms, | ||
| "since_session_id": since_session_id, | ||
| "root": compiled_spec.root, |
There was a problem hiding this comment.
For polylogue --root find ... then analyze --count (and the --no-root equivalent), the count_only branch below bypasses this shared filter_kwargs mapping and manually invokes count_search_sessions/count_sessions without root. The command therefore reports the unpartitioned total even though ordinary local list/search output applies the filter; pass root in both count calls or reuse this mapping.
AGENTS.md reference: AGENTS.md:L193-L197
Useful? React with 👍 / 👎.
| offset=spec.offset, | ||
| cursor=spec.cursor, | ||
| boolean_predicate=spec.boolean_predicate, | ||
| root=spec.root, | ||
| vector_provider=vector_provider, |
There was a problem hiding this comment.
Push root down before plan pagination
When a spec is executed through the Python API/MCP plan path, this activates plan.root, but archive_execution._plan_filter_kwargs still omits it even though the storage readers now accept SQL-level root. The residual filter runs only after _archive_summaries has applied the requested offset and fetched at most limit * 4, so a page whose leading rows are children can return short or empty for root:true despite matching roots later in the archive (and conversely for root:false). Add root to the plan-to-storage kwargs so partitioning occurs before pagination.
AGENTS.md reference: AGENTS.md:L227-L229
Useful? React with 👍 / 👎.
|
Warning Review limit reached
Next review available in: 54 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (18)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
# Conflicts: # .beads/issues.jsonl
…#3438) ## Summary Two independent "computed and discarded" defects, both verified live tonight per the operator's audit theme: - **polylogue-uh9l**: Claude Workflow artifact coverage was computed on every ingest pass by `assembly_claude_code.py:discover_sidecars` and consumed by nothing. Deleted the dead branch and wired the genuinely-running materializer's gap count into `polylogue doctor`'s readiness surface instead. - **polylogue-xyel**: re-verified against current master (not assumed from the bead's original framing) that `session_refs` now has a live production consumer (PR #3425/#3431, already merged) — then built the bead's own remaining, un-satisfied AC: a real D1 "receipts" demo packet. ## Problem **uh9l**: `polylogue-z9gh.6`'s closure claimed "readiness and repair commands no longer report healthy solely because subagents/workflows is classified as a known sidecar." False as written — no readiness/repair command consulted either of the two coverage computations that existed for Claude Workflow artifacts. One (`ClaudeOrchestrationCoverage`/`inventory_claude_orchestration_artifacts`) was fully dead code; the other (`claude_workflow_materializer`'s gap tuple) ran every convergence pass but was only ever logged. **xyel**: the bead's title/framing ("SESSION_REFS HAS NO CONSUMER") predates this repo's own same-night investigation trail (`polylogue-cijx.1`), which found and fixed the actual gap (a NameError that crashed `read --view correlation`'s default GitHub-enrichment path on every real ref). The bead's own literal AC — build and register a real PF-D1 receipts demo, not the packet-contract stub `212.7` shipped — remained unaddressed. ## Solution **uh9l** (3 commits): 1. `refactor(sources)`: delete the dead `orchestration_artifacts`/`orchestration_coverage`/`orchestration_parse_gaps` computation from `discover_sidecars` and its supporting `ClaudeOrchestrationCoverage`/`inventory_claude_orchestration_artifacts` (kept `parse_claude_orchestration_artifact`/`ClaudeOrchestrationArtifact`/`ClaudeOrchestrationFact`, still used by the materializer). 2. `feat(readiness)`: `daemon/convergence_stages.py`'s `claude_workflow` stage now persists each materialization summary into `ops.db`'s existing generic `daemon_stage_events` table (no schema change). `readiness/__init__.py` registers a new `claude_workflow_materialization` `ReadinessCheck` that `polylogue doctor` already surfaces via `get_readiness()`. **xyel** (1 commit + a follow-up type fix): 3. `feat(demos)`: `.agent/demos/d1-receipts/` — resolves a real merged PR (`#3282`) to its authoring/dispatch session structurally via `session_refs`, then checks 4 individually falsifiable PR-body claims against that session's own recorded blocks. 3 supported, 1 explicitly scored `not_supported` (a real, structurally-confirmed gap: a 7-file `devtools test` invocation named in the PR body only ever appears as prose, never as an executed command in this session). Also surfaces a genuine finding: the resolved session is a merge-conductor (0 `Edit`/`Write` tool_use blocks), not the file-editing session. 4. `fix(tests)`: type-narrow a `dict[str, object]` read in the new integration test that `devtools verify --quick`'s `dmypy`-backed mypy step caught (the earlier plain `mypy polylogue` spot-check doesn't cover `tests/`). Beads updated in a final commit: closed `polylogue-uh9l` and `polylogue-xyel` with full AC disposition in their close reasons; filed `polylogue-nt5f` for the one honestly-named remainder (D1's public seed-corpus variant isn't built — `session_refs` pull_request rows are a provider-native capability the deterministic demo seed fixture doesn't currently populate). ## Verification - `devtools test tests/unit/sources/test_assembly_claude_code_history.py tests/unit/sources/test_parsers_claude_code_artifacts.py tests/unit/storage/test_archive_readiness.py tests/unit/daemon/test_convergence_stages.py tests/unit/cli/test_convergence_surface_contract.py tests/unit/cli/test_check.py tests/integration/test_claude_workflow_admission.py tests/unit/devtools/test_demo_packet.py tests/unit/demo/test_tour_packet_contract.py` → 191 passed - `devtools lab policy demo-packet-registry` → "demo packet registry: all 4 entries conform" - `devtools lab policy bead-graph` → exit 0 (dup_labels=0, inversions=0, malformed_wave=0) - `devtools verify --quick` → 20/20 steps green (pre-push hook also ran this clean) - `devtools render all --check` → OK, no drift Ref polylogue-uh9l, polylogue-xyel <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Claude Workflow readiness reporting that identifies missing materialization records, unresolved gaps, and successful convergence. * Added a verification demo documenting pull-request claims, supporting evidence, counterexamples, limitations, and reproduction steps. * **Bug Fixes** * Improved archive readiness handling for missing, malformed, or unavailable status data. * Updated audit records with fixes, deferred work, and newly identified reliability issues. * **Refactor** * Simplified Claude Code history processing by removing obsolete orchestration artifact inventory and coverage reporting. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
…faces (#3442) ## Summary Three beads about polylogue evidence that is already captured and persisted, but unreachable from any CLI/MCP/API surface. This PR wires the genuine remainders: `file_edits`, `session_agent_policies`, and `sessions.display_name` (the Claude Code "slug" wire field). ## Problem - **polylogue-nua7**: `file_edits` (76,272 live rows), `session_agent_policies` (402,879 rows), and `session_refs` (19,024 rows) each had a complete, tested read chain that terminated at `repository/archive/sessions.py` with nothing above it. `session_refs` was already wired by prior PRs #3425/#3431 (`read --view correlation`); `file_edits` and `session_agent_policies` remained unreachable from any CLI/MCP/API surface. Four helpers (`get_file_edit`, `sync_get_file_edits_for_session`, `sync_get_session_refs`, `sync_session_agent_policies_batch`) had zero references anywhere outside their own `def`/`__all__` entry. - **polylogue-cgfy**: the Claude Code `slug` wire field (1,500 sampled occurrences) is captured into `ParsedSession.display_name` and persisted into `sessions.display_name`, but neither `Session` nor `SessionSummary` carried a `display_name` field at all — the value was dropped on every read path. This is the fix for subagent rows rendering as `<uuid-prefix>:agent-<suffix>` instead of a human name. - **polylogue-pbuh**: AC6 asked for a live before/after census of UUID-titled sessions and PR-link counts. Measured read-only against `/realm/db/polylogue/index.db`. ## Solution 1. **`polylogue/api/archive.py`**: added `Polylogue.get_file_edits()` / `get_agent_policies()`, mirroring the existing `get_session_events()` reader pattern (returns `None` for an unknown session, an empty list for a session with no matching rows). 2. **MCP** (`polylogue/mcp/server_cutover.py`): wired both into the existing `get(ref, projection=...)` dispatcher as two new projection values (`"file-edits"`, `"agent-policies"`) alongside the existing `"events"` projection. No new tool or tool contract needed — same six-tool `get` operation. 3. **CLI**: added `read --view file-edits` / `read --view agent-policies`, following the existing `events`/`hooks` view pattern — new handler module `polylogue/cli/read_views/file_edits.py`, registered in `read_view_handlers.py`, `read_view_registry.py`, and the profile metadata in `archive/viewport/profiles.py`. Also required adding entries to `polylogue/surfaces/projection_spec.py`'s `EvidenceFamily`/`READ_VIEW_PROJECTION_FAMILIES` maps — a separate registry from the CLI handler registry that raises "unknown projection view" if a view is missing there. 4. **Dead code**: deleted the four zero-reference helpers named in nua7's audit, plus their now-dangling `sqlite3` imports where nothing else used them. 5. **`display_name` reachability** (polylogue-cgfy), two independent hydration paths: - Async repository path (`storage/hydrators.py`): added `display_name` to `Session`/`SessionSummary` (`archive/session/domain_models.py`) and their runtime mixins' `display_title` property — now falls back `user_title > title > display_name > id[:8]`. - Sync `ArchiveStore` summary path that backs `find`/MCP `get(ref)` default projection (`storage/sqlite/archive_tiers/archive.py`): added `display_name` to `ArchiveSessionSummary`, selected it in `read_summary`'s and `list_summaries`' SQL, and made it a title fallback tier **above** the existing structural-label fallback (polylogue-cijx.4 decision 3) when no provider title exists — `display_name` is real origin evidence (`title_source="origin"`), stronger than a derived structural label. Wired through `api/archive.py::_archive_summary_to_domain`. 6. **pbuh AC6 live census** (read-only against `/realm/db/polylogue/index.db`, no code change — measurement only): - 16,420 Claude Code sessions total; 14,717 carry `title_source='unknown'` (raw-id/structural-label fallback before this PR). - 7,088 of those 16,420 sessions have a captured `display_name`; **6,585 of the 14,717 `title_source='unknown'` sessions (44.7%) now surface a real slug-derived title** instead of a raw id or structural label — this PR's concrete, measured improvement. - `session_events` with `event_type='claude_pr_link'`: 19,140 rows (unchanged by this PR — pr-link reader wiring was already resolved by the earlier #3425/#3431 pass; see pbuh's own notes). - `file_edits`: 76,272 rows; `session_agent_policies`: 402,879 rows; `session_refs`: 19,024 rows (167 distinct sessions) — all now reachable per point 1-3 above. ## AC disposition **polylogue-nua7**: file_edits/session_agent_policies now have real CLI (`read --view file-edits`/`agent-policies`) and MCP (`get(projection=...)`) consumers; session_refs already had one (prior PRs, verified unchanged). All four zero-reference helpers deleted. Satisfied. **polylogue-cgfy**: AC1 (per-key classification recorded in OriginSpec) and AC4 (re-runnable committed enumeration) were already addressed by prior passes per the bead's own notes — not re-verified in this pass, out of this PR's declared surface. AC2's `structuredPatch`/`originalFile`/`oldString` persistence was already done (index v46); this PR adds the missing *read* side (file_edits reachability, point 1-3 above) — the specific "cijx grading rises from observed to checkpointed" wiring is a separate insights-model change (`insights/session_commit.py`-adjacent, in this PR's avoid list) and remains open, noted here as a genuine remainder. AC3 (slug reaches read surfaces) is satisfied — see point 5 above, proven with a measured live census (point 6) and end-to-end tests. AC5 (bytes/row counts per key acquired) is partially covered by the live counts in point 6 but not a full per-key report. **polylogue-pbuh**: AC6 (before/after census) satisfied as a live measurement (point 6) — this is the "after" state; no "before" baseline exists since the parser fix landed in an earlier PR and no un-fixed archive is available to compare against. AC1-AC5 were already resolved in prior passes per the bead's own extensive notes; not re-verified here, out of this PR's declared surface (parsers/claude, assembly_claude_code.py, providers/claude_code*.py were avoided per the task's own instructions). ## Verification - `devtools test tests/unit/mcp/test_server_surfaces.py` — 11 passed, including 3 new tests exercising `get(projection="file-edits")`, `get(projection="agent-policies")`, and the default `get(ref)` display_name fallback through the real MCP `tool_manager` entrypoint against a real `ArchiveStore`-written session. - `devtools test tests/unit/cli/test_file_edits_and_agent_policies_views.py` — 2 passed, full `CliRunner` invocation of `read --view file-edits`/`agent-policies` against a real `ArchiveStore`-written session. - `devtools test tests/unit/storage/test_session_display_name_reaches_repository.py` — 2 passed, proving both `Session` and `SessionSummary` carry `display_name`/`display_title` correctly through the real writer → async repository chain, and that a real title still wins over the slug. - `devtools test tests/unit/storage/test_unread_wire_batch_v46.py tests/unit/storage/test_repository_agent_policies.py` — 13 passed (no regression from dead-helper removal). - `devtools test tests/unit/storage/test_title_source_queryable.py tests/unit/storage/test_archive_tiers_write.py tests/unit/storage/test_archive_tiers_archive.py tests/unit/cli/test_query_exec_laws.py` — 243 passed (no regressions to existing title/summary logic). - `devtools test tests/unit/api/test_facade_contracts.py -k "no_undiscovered or file_edits or agent_polic"` — 3 passed. - Broader affected-area sweep: 28 test files that directly import the touched domain modules (`tests/unit/{api,archive,cli,core,insights,sources,storage,surfaces}/...`) — 863 passed, 2 pre-existing unrelated failures (`test_archive_tiers_api_raw_artifacts_read_source_tier`, 4 parametrized cases of `test_filters_props.py::TestFilterDateParsing`) confirmed to reproduce identically with this branch's changes reverted — stale hardcoded date assertions / a clock-hygiene issue in `archive/filter/filters.py`, untouched by this PR. - `mypy --strict` on every touched file — no issues. - `devtools verify --quick` — exit 0. - `devtools render all --check` — all surfaces sync OK (regenerated `docs/cli-reference.md`, `docs/plans/topology-target.yaml` for the new `polylogue/cli/read_views/file_edits.py` module). Not run: full `devtools verify --all` / whole-directory `tests/unit` sweep (anti-pattern per repo convention — testmon wasn't seeded in this worktree; relying on the targeted + affected-area sweeps above plus CI's post-merge heavy `test` suite). Ref polylogue-nua7, polylogue-cgfy, polylogue-pbuh
Summary
Closes the two named, still-open gaps from tonight's polylogue-pbuh and
polylogue-cijx.4 investigations: (1) verifies and finishes the read-side
wiring for typed session→PR evidence (pbuh AC4), and (2) wires the
root:session-structure filter end-to-end across the query DSL, CLI, and Python
API (cijx.4 AC4 / its follow-up polylogue-oqib).
Problem
Gap 1 (pbuh AC4). polylogue-pbuh's parser-side fix (index v46, PR #3390)
persists Claude Code's
pr-linksidecar record as typedsession_refsevidence, but nothing on the CLI/insights/MCP surface read it — the four
dependent beads (212.2/xyel/kph/fs1.4) were blocked on an inference
mechanism (
session_commits, 0 readers, 2,989 rows of a narrower fact)instead of the typed evidence the provider already supplies.
Gap 2 (cijx.4 AC4 / oqib).
sessions.parent_session_idandSession.is_rootare correct, and a plan-levelroot: bool | Nonefieldplus
.is_root()builder already existed, butroothad nospec_attr,no DSL grammar case, and no CLI flag — completely unreachable from any
query surface, so a default
findmixes 66.1% root sessions with 33.9%subagent/branch children unlabeled.
Solution
Gap 1: A sibling lane's PR #3425 (fix/insights/session-commit-typed-evidence)
had landed the actual read-side fix —
build_correlation_resultnowconsumes
session_refs/claude_bridge_sessiontyped evidence asauthoritative, falling back to regex/time-window heuristics only where no
typed evidence exists, and surfacing disagreements. It was open but
unmerged when this pass started; triaged its 3 non-blocking CodeRabbit P2
findings (filed as follow-up polylogue-2vor) and merged it (5525446).
Verifying the now-merged surface against the live archive
(
find id:<session> then read --view correlation) surfaced a second,independent, pre-existing bug:
_enrich_with_github_api(
polylogue/insights/correlation_view.py) referencedSessionCorrelationResultat runtime while only importing it under
TYPE_CHECKING— every call withthe default
github_api=Trueand any issue/PR ref present raisedNameError. This predates PR #3425 (present sinceac84f734f); theexisting test suite only exercised
github_api=False, so it was nevercaught. Fixed by importing the class at runtime alongside the existing
GitHubRefimport, plus a regression test.Gap 2:
SessionQuerySpec.root: bool | None, wired throughbuild_query_spec_from_params/query_spec_to_plan(newoptional_booltri-state parser in
archive/query/spec.py).root:true/root:falsefield clause (archive/query/expression.py);-root:negation is rejected pointing atroot:falseinstead (the valuealready carries polarity).
--root/--no-rootflag, added last incli()'s signature per thisrepo's "new Click params go last" convention.
EXPRESSION_FIELD_REGISTRY["root"]+ regenerateddocs/cli-reference.md,docs/search.md.Two deeper bugs found while making this reachable (neither was "just
unreachable" — both were silent no-ops even where a plan/spec did carry a
value):
cli/archive_query.py's_ArchiveFilterKwargs→ArchiveStore.list_summaries/search_summaries/count_sessions/count_search_sessions/search_session_ids/semantic_summaries/stats/stats_by) is a SQL-level filter pathentirely separate from the
SessionQueryPlan/apply_common_filterspost-filter machinery
root's field descriptor (requires_post_filter=True)was designed against. None of those eight
ArchiveStoremethods accepteda
rootkwarg. Fixed by pushingrootinto_session_filter_clauseasa direct SQL predicate (
sessions.parent_session_id IS [NOT] NULL—trivially SQL-pushable, unlike
continuation/sidechainwhich derivefrom
branch_type) and threading it through all eight methods.SessionQueryPlanpost-filter path (Python API'slist_summaries_archive/list_archive) was independently broken:ArchiveSessionSummarynever carriedparent_id(the SELECT neverprojected
sessions.parent_session_id,_summary_from_rownever readit), so
is_rootwasTruefor every summary row regardless of actualparent — a
root:truefilter would have silently returned everythingeven once reachable. Fixed by adding
parent_idtoArchiveSessionSummary, projecting the column in bothread_summaryand
list_summaries, and threading it through_summary_to_domain.Default-behavior decision: did not flip any surface's default.
find/Python APIlist()/MCP query/daemon HTTP all continue to returnevery session unless
root:/--root/.is_root()is given explicitly.Flipping even the narrower "CLI
findverb only" option still has realblast radius (every existing test/saved-query/demo-script assuming
today's "everything" default needs re-auditing), and reachability is the
load-bearing wedge —
polylogue find repo:polylogue root:truenowproduces the named, non-fanout view AC4's proof text asks for. The
default question is left open as a deliberate, separately-reviewable
follow-up (narrowed onto polylogue-oqib).
AC disposition
polylogue-pbuh (typed session→PR evidence): AC4 satisfied. Typed
session→PR linkage is reachable from
read --view correlation(CLI/API), verified live against the real archive. AC6 (before/after
UUID-title/PR-link census) is untouched — out of this gap's declared
scope, still open.
polylogue-cijx.1 (repo-identity bead whose notes tracked the
session-commits/pr-link consumer question): the specific blocking concern
its notes raised for 212.2/xyel/kph/fs1.4 ("the producer does not work" /
"0 readers") is resolved. Its own titled AC (repo_id fragmentation) is
unrelated and was already addressed by cijx.4.
212.2 / xyel / kph / fs1.4: unblocked, not closed — each still needs
its own concrete deliverable (demo build, CI hook, CLI/report regen)
beyond "the data is now readable." Noted individually on each bead.
polylogue-cijx.4 AC4: reachability satisfied. Default-behavior
question deferred, narrowed onto polylogue-oqib (priority lowered —
remaining scope is a design decision, not plumbing).
polylogue-oqib: reachability + both deeper bugs satisfied and
fixed. Default-behavior flip not attempted, left open and
explicitly narrowed to that one remaining decision.
Verification
devtools test tests/unit/cli/test_correlate_view.py— 4 passed(including new NameError regression test).
devtools test tests/unit/cli/test_query_expression.py tests/unit/core/test_query_fields.py tests/unit/cli/test_archive_query.py tests/unit/archive/test_archive_execution_filters.py tests/unit/cli/test_query_exec_laws.py tests/unit/archive/ tests/unit/storage/test_archive_tiers_archive.py tests/unit/archive/query/test_discovery.py— all green (newtest_root_filter_partitions_top_level_and_subagent_sessionscovers alleight
ArchiveStoremethods plus theparent_id/is_rootwiring bug).mypy --stricton every touched module — no issues.devtools render all --check— sync OK.devtools verify --quick— exit 0 (also ran automatically via thepre-push hook).
/realm/db/polylogue/index.db):find id:<session> then read --view correlation --format jsonreturnstyped
pr_refs(source=typed_session_ref) plus adisagreementslist;find repo:polylogue --root→ total 1906;find repo:polylogue --no-root→ total 3206; 1906+3206=5112, the unfiltered total.
Not done / follow-ups
path (PR #0 coercion, cross-repo number collision, foreign-trailer
false-disagreement).
root:(whichsurfaces, if any, should default to top-level-only).
rootis not wired intoquery_unit_session_filters(thewith <units>projection's separate session-filter adapter), and daemon HTTP's
_build_query_spec_paramsnamed-param allowlist has no dedicated?root=query param (the existing?query=root:trueDSL path alreadycovers it).
continuation/sidechain/has_branchesremain exactly asunreachable as before this PR.
Ref polylogue-pbuh, polylogue-cijx.1, polylogue-cijx.4, polylogue-oqib.