Add the exclude-superseded search filter (Q3, #108) - #115
Conversation
Implement Q3 of the corrected query-surface epic (audit finding F5): search and search-receipt accept --exclude-superseded, dropping matches whose record lifecycle is superseded while the default keeps them as first-class hits. The filter runs inside the same gated read transaction as the match, composes with both query grammars, and search receipts record exclude_superseded beside query_mode and the query digest so every result-affecting parameter is bound and filtered results are replayable. This is a read-time lifecycle filter, not revocation; revocation suppression remains a projection-build input. Security: supersession becomes expressible from search and receipts state which mode ran, instead of superseded records being indistinguishable hits. Compatibility: additive flag, defaulted keyword, and optional receipt field; default behavior and all pinned fixtures unchanged. Proven end to end with a synthetic slice replayed by run_conformance.sh. For issue #108; decision recorded in docs/decisions/0026.
|
@codex review |
Reviewer's GuideIntroduces an additive Sequence diagram for gated supersession-filtered searchsequenceDiagram
participant Caller
participant CLI
participant Projection
participant SQLite
Caller->>CLI: search_records(index_path, query, exclude_superseded)
CLI->>Projection: _read_index(index_path)
Projection->>SQLite: Match query in verified read transaction
SQLite-->>Projection: Matching record IDs
opt exclude_superseded
Projection->>SQLite: SELECT record_id FROM records WHERE lifecycle = 'superseded'
SQLite-->>Projection: Superseded record IDs
Projection-->>Projection: Remove superseded matches
end
Projection-->>CLI: record_ids
CLI-->>Caller: Search results
Sequence diagram for replayable search receipt bindingsequenceDiagram
participant Caller
participant Projection
participant SQLite
Caller->>Projection: search_receipt(index_path, query, literal, exclude_superseded)
Projection->>SQLite: Match query in verified read transaction
SQLite-->>Projection: Filtered record IDs
Projection->>SQLite: SELECT source_record_set_digest FROM projection_metadata
SQLite-->>Projection: Source digest
Projection-->>Caller: Receipt with query_mode, query_digest, exclude_superseded, record_ids
Flow diagram for default and filtered search behaviorflowchart LR
A[Search query] --> B{--exclude-superseded?}
B -->|No| C[Return all matching lifecycles]
B -->|Yes| D[Drop lifecycle = superseded]
D --> E[Return remaining matches]
C --> F[Receipt records exclude_superseded = false]
E --> G[Receipt records exclude_superseded = true]
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
PR Summary by QodoAdd opt-in superseded filtering to search
AI Description
Diagram
High-Level Assessment
Files changed (15)
|
Code Review by Qodo
1.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eea8b1027b
ℹ️ 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".
…hanged Process the current-head required-reviewer batch from PR #115 (Qodo, Codex P2): - Raw-mode exclusion now predicates lifecycle in SQL alongside the FTS match, and literal-mode exclusion bounds its lookups by the post-filtered candidates, so no filtered search materializes every superseded record ID or does work proportional to the projection. - Default search receipts omit exclude_superseded entirely, restoring the exact pre-filter v1 shape for consumers pinned to the earlier schema; only filtered receipts carry the field. Validated on this head: 610 tests OK and run_conformance.sh OK with the regenerated supersession slice. For issue #108; decisions recorded in docs/decisions/0026.
… exclusion Address the Sourcery security-lint thread on PR #115: replace the placeholder-count f-string IN query with one parameterized primary-key lifecycle lookup per post-filtered candidate. No search path builds SQL from string concatenation, and the work stays bounded by matched rows rather than the projection. Validated: 610 tests OK, run_conformance.sh OK.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 718ec1f224
ℹ️ 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".
Address the current-head Codex P2 on PR #115: the optional exclude_superseded property accepted false from external producers even though omission is the contract's only representation of the default, and such a receipt would also lose the pre-filter shape pinned v1 consumers expect. The property is now const true; a receipt carrying exclude_superseded: false fails schema validation. Validated: 610 tests OK, run_conformance.sh OK.
|
@codex review |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Summary
Implements Q3 of the corrected query-surface epic (audit finding F5): an
--exclude-supersededfilter on bothsearchandsearch-receipt, with receipt binding. Closes #108.Superseded records remain first-class hits by default; the flag is the caller's opt-in and drops matches whose
lifecyclecolumn issuperseded. The filter runs inside the same gated read transaction as the match (same verified snapshot), composes with both query grammars, and search receipts recordexclude_superseded(optional boolean in the v1 schema, always set on new receipts) besidequery_modeand the query digest — so every result-affecting parameter is bound and filtered results are replayable.Explicitly a read-time lifecycle filter, not revocation: revocation suppression remains a projection-build input (M6 stays open as separate work).
Contract and compatibility impact
supersededis excluded; draft/rejected/sealed are unaffected.Security and privacy impact
Validation
python3 -m unittest discover -s tests— 610 tests OK (3 new)../scripts/run_conformance.sh— OK, including the newrun_search_supersession_slice.py --checkreplay (5 operations: both-lifecycles default, filtered survivor, literal composition, receipt binding).Tracking
docs/decisions/0026-exclude-superseded-search-filter.mddocs/contracts/v0-filesystem-and-projections.mdfixtures/synthetic/search-supersession/v1/expected-receipt.jsonSummary by Sourcery
Add opt-in superseded-record filtering to search while preserving default results and making filtered receipts replayable.
New Features:
--exclude-supersededfilter tosearchandsearch-receipt, supporting both raw and literal query modes.Enhancements:
supersededlifecycle when requested.CI:
Documentation:
Tests: