Skip to content

feat(056): carry the filter into export, not the time window - #283

Merged
guan4tou2 merged 5 commits into
mainfrom
feat/056-filtered-evidence-export
Oct 8, 2026
Merged

guan4tou2 merged 5 commits into
mainfrom
feat/056-filtered-evidence-export

Conversation

@guan4tou2

Copy link
Copy Markdown
Owner

The defect

HttpHistoryPanel built its export subset from the oldest and newest loaded
row's timestamps, and ExportSubset had no shape that could hold a predicate —
only all and time-range:

const timestamps = filtered.map((flow) => flow.timestamp)
return { format: 'har', subset: {
  kind: 'time-range',
  since: Math.min(...timestamps),
  before: Math.max(...timestamps) + 1,
  ...(hostFilter ? { targetId: hostFilter } : {}) } }

So method, status and text filters were dropped on the way out. Both directions
hurt a handover: unrelated traffic inside that window entered the artifact, and
matches past the loaded page (AUTO_LOAD_MAX_FLOWS = 5000) did not.

The change

ExportSubset.selection carries the view's real conditions, and
resolveExportSelection re-reads them against the recorded events, paging to
the end rather than trusting what the renderer had loaded. An incomplete page
throws instead of silently exporting a subset:

if (page.hasMore && !cursor) throw new Error('Incomplete export query')

queryHttpFlowPage applies method/host/status/text in SQL and bounds reads by
the preview snapshot's rowid, so preview and execute see one dataset. The
preview names the conditions before anything is written, controls that only
change presentation are no longer mistaken for a selection, and a bundle
carrying less than the whole chain says so in its manifest.

Provenance

Ported from codex/evidence-workflow-completion (ee92e95e, 2026-09-29), which
never opened a PR and had drifted 179 commits behind main. That commit's
unrelated halves — HTTP capture status hook, browser proxy status, visibility
lifecycle — are deliberately left behind. Numbered 041 there; main took 041 for
session-target-binding, and 055 went to spec/055-terminal-session-rotation
(#280) in a parallel session, so this is 056.

Found while porting

  • The HAR path exported every flow in the snapshot. exportHar takes
    since/before/targetId and a selection's predicates fit none of them, so the
    har branch passed nothing. 506 entries for a 505-flow selection — the same
    widening, surviving in the format where it is least visible. The ported
    commit's own test caught this, which means it was red when written: no PR,
    so no gate ever ran on it.
  • The preview dialog inherited whitespace-nowrap from the toolbar despite
    being fixed. Never showed before because every preview line was a short
    label or a number; the condition list and projection notice are prose, and at
    560px the notice needed 773px. English only — zh-TW breaks between characters
    and wrapped anyway, so that locale passed throughout.
  • The bundle README had been flattened by the ported commit, losing which
    tier is primary evidence. Restored, with its projection paragraph merged in.
  • timeline.exportSliceUnfiltered ("Visible time range, filter not applied") is
    gone — the slice export now carries the filter, so there is nothing to disown.

Verification

All five gates in CI's order, on the merged state:

gate result
typecheck pass
verify:specs pass
verify:architecture pass — 297 files, every export reachable
verify:i18n pass — 2 removed strings, nothing asserts them
npm test 3127 passed, 0 failed, 24 skipped

e2e run locally (CI skips it when an earlier gate fails, and this branch changes
an export contract): filtered-export.spec.ts and export-preview.spec.ts,
5 passed.

🤖 Generated with Claude Code

guan4tou2 and others added 5 commits October 7, 2026 18:20
The HTTP view built its export subset from the oldest and newest *loaded*
row's timestamps (`HttpHistoryPanel`), and `ExportSubset` had no shape that
could hold a predicate — only `all` and `time-range`. So method, status and
text filters were dropped on the way out: unrelated traffic inside that
window entered the artifact, and matches past the loaded page did not.

Adds `ExportSubset.selection`, carrying the view's real conditions, and
`resolveExportSelection`, which re-reads them against the recorded events
and pages to the end rather than trusting what the renderer had loaded. An
incomplete page throws instead of silently exporting a subset.
`queryHttpFlowPage` applies method/host/status/text in SQL and bounds reads
by the preview snapshot's rowid, so preview and execute see one dataset.

A bundle carrying less than the whole chain now says so in its manifest.

Ported from codex/evidence-workflow-completion (ee92e95, 2026-09-29), which
never opened a PR and had drifted 179 commits behind main. Renumbered 041 to
055 — main took 041 for session-target-binding. The unrelated halves of that
commit (HTTP capture status hook, browser proxy status, visibility lifecycle)
are deliberately left behind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`exportHar` takes since/before/targetId, and a selection's predicates
(method, status, text) cannot be written as any of those — so the har
branch of executeExportPlan passed nothing and the artifact carried every
flow the snapshot held. The plan had already resolved the right events;
nothing handed them over. 506 entries for a 505-flow selection, which is
the widening this spec exists to stop, surviving in the one format where
it is least visible.

exportHar now takes the plan's approved ids, like the json, ndjson and
bundle paths do.

Also here, from porting ee92e95 onto today's main:

- Restore the bundle README's tier explanation. The ported commit had
  flattened it and lost which tier is primary evidence; the projection
  paragraph it added is kept, rewritten to sit with the original text.
- `timeline.exportSliceUnfiltered` ("Visible time range, filter not
  applied") is gone: the slice export now carries the filter, so there
  is nothing to disown. Its test asserts the new contract instead.
- export-preview-truth picks the JSON option by role — the selection
  format `<select>` means a bare text match now finds its `<option>`s too.
- filtered-export closes the body index before rmSync; closeDB() leaves
  that handle open and Windows then fails the cleanup, not the assertions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The toolbar sets `whitespace-nowrap`, and the export dialog inherits it
through the DOM even though it is `fixed` — which never showed before,
because every line in the preview was a short label or a number. The
condition list and the projection notice are prose: at 560px the notice
needed 773px and simply overflowed.

Found by measuring rather than guessing — the first fix went on the subset
span, which was not the element overflowing. The dialog now wraps.

Only English failed. zh-TW breaks between characters, so it wrapped under
nowrap and the e2e spec passed in that locale throughout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tion

`spec/055-terminal-session-rotation` took 055 in another session and is
already pushed; this branch was not, so it moves. verify:specs compares
against origin/main only, and neither branch is on main yet — so both were
green in isolation and the collision would have surfaced as a conflict in
whichever merged second.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 076cc154-452f-465d-8945-9d8a76613d45
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@guan4tou2
guan4tou2 merged commit b034e11 into main Oct 8, 2026
5 checks passed
@guan4tou2
guan4tou2 deleted the feat/056-filtered-evidence-export branch October 8, 2026 02:57
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Resolves the CHANGELOG conflict this PR hit when #283 landed. Both sides
added entries at the top of `## Unreleased`: this branch's two (terminal
enrolment, lane visibility) and main's one (filtered export). All three are
kept, newest first, which is the order main already uses — 412 entries at
the merge base, +2 here, +1 from main, 415 now.

Resolved from the branch-cleanup session rather than this branch's own: its
worktree is gone and the session that opened the PR is no longer running, so
there was nobody to hand it back to. The conflict was caused by #283, which
that session merged.

Merged main in rather than rebasing — this branch is shared and a rewrite
would strand anything still pointing at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
feat(056): carry the filter into export, not the time window
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Resolves the CHANGELOG conflict this PR hit when #283 landed. Both sides
added entries at the top of `## Unreleased`: this branch's two (terminal
enrolment, lane visibility) and main's one (filtered export). All three are
kept, newest first, which is the order main already uses — 412 entries at
the merge base, +2 here, +1 from main, 415 now.

Resolved from the branch-cleanup session rather than this branch's own: its
worktree is gone and the session that opened the PR is no longer running, so
there was nobody to hand it back to. The conflict was caused by #283, which
that session merged.

Merged main in rather than rebasing — this branch is shared and a rewrite
would strand anything still pointing at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
feat(056): carry the filter into export, not the time window
guan4tou2 added a commit that referenced this pull request Oct 8, 2026
Resolves the CHANGELOG conflict this PR hit when #283 landed. Both sides
added entries at the top of `## Unreleased`: this branch's two (terminal
enrolment, lane visibility) and main's one (filtered export). All three are
kept, newest first, which is the order main already uses — 412 entries at
the merge base, +2 here, +1 from main, 415 now.

Resolved from the branch-cleanup session rather than this branch's own: its
worktree is gone and the session that opened the PR is no longer running, so
there was nobody to hand it back to. The conflict was caused by #283, which
that session merged.

Merged main in rather than rebasing — this branch is shared and a rewrite
would strand anything still pointing at it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant