feat(fb-36): search filter args (--media / --ingested-after / --doc-id + 4 existing) #127

Merged
altair823 merged 11 commits from feat/fb-36-search-filters into main 2026-05-10 02:02:27 +00:00
Owner

Summary

  • adds 7 filter flags on kebab search and the equivalent inputs on mcp__kebab__search:
    • existing SearchFilters fields exposed: --tag (repeatable, OR-within), --lang, --path-glob, --trust-min
    • new fields: --media (csv, md alias), --ingested-after (RFC3339 UTC), --doc-id
  • AND combinator across flags; OR within --tag and --media
  • filter layer: SQLite WHERE for lexical (incl. media via CASE WHEN json_type='text' to handle both unit and tuple MediaType serde shapes), over-fetch + filter_chunks post-filter for vector (shared kebab-store-sqlite::filter_chunks helper)
  • wire shape unchanged — input-only feature; search_response.v1 and search_hit.v1 untouched
  • invalid --ingested-after / unknown trust_minerror.v1.code = config_invalid (CLI) / invalid_input (MCP); unknown --media value → empty hits, no error
  • --trust-min accepts primary | secondary | generated (matches actual kebab_core::TrustLevel variants)

Test plan

  • cargo test --workspace --no-fail-fast -j 1 — green
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • new tests: 6 lexical (media / ingested_after / doc_id / AND / unknown / default), 3 store-sqlite filter unit tests + 2 vector hybrid mirror (#[ignore] for AVX), 4 CLI integration, 2 MCP
  • manual smoke: --media md (alias), --ingested-after garbage (config_invalid + exit 2), --ingested-after 2030-01-01T00:00:00Z (no hits), --doc-id <id> (scope), --tag rust (frontmatter)

Architectural notes

  • SearchFilters 3 fields are additive with #[serde(default)] — old JSON without the new keys deserializes cleanly.
  • MediaType JSON has two shapes ("markdown" for unit variants, {"image":"png"} for tuple variants); the SQL CASE WHEN json_type='text' THEN json_extract($) ELSE (first object key) END extracts a unified kind string.
  • Vector retriever delegates to kebab-store-sqlite::SqliteStore::filter_chunks, which gained the same 3 WHERE arms — single source of truth for the filter SQL across lexical's SQL builder and vector's post-filter.
  • path_glob remains a Rust post-filter — unchanged from before fb-36.
  • --trust-min plan/spec drafts mentioned Trusted/Reviewed/Hearsay/Untrusted; actual kebab_core::TrustLevel variants are Primary/Secondary/Generated. Implementation and docs use the real variants.
  • No new HOTFIXES entry — additive minor, no contract drift.

Files of interest

  • spec: docs/superpowers/specs/2026-05-10-p9-fb-36-search-filters-design.md
  • plan: docs/superpowers/plans/2026-05-10-p9-fb-36-search-filters.md
  • core: crates/kebab-core/src/search.rs (SearchFilters)
  • search: crates/kebab-search/src/lexical.rs + kebab-store-sqlite/src/filters.rs (shared filter_chunks)
  • CLI: crates/kebab-cli/src/main.rs (Cmd::Search)
  • MCP: crates/kebab-mcp/src/tools/search.rs (SearchInput)
## Summary - adds 7 filter flags on `kebab search` and the equivalent inputs on `mcp__kebab__search`: - existing `SearchFilters` fields exposed: `--tag` (repeatable, OR-within), `--lang`, `--path-glob`, `--trust-min` - new fields: `--media` (csv, `md` alias), `--ingested-after` (RFC3339 UTC), `--doc-id` - AND combinator across flags; OR within `--tag` and `--media` - filter layer: SQLite WHERE for lexical (incl. media via `CASE WHEN json_type='text'` to handle both unit and tuple `MediaType` serde shapes), over-fetch + `filter_chunks` post-filter for vector (shared `kebab-store-sqlite::filter_chunks` helper) - wire shape unchanged — input-only feature; `search_response.v1` and `search_hit.v1` untouched - invalid `--ingested-after` / unknown `trust_min` → `error.v1.code = config_invalid` (CLI) / `invalid_input` (MCP); unknown `--media` value → empty hits, no error - `--trust-min` accepts `primary | secondary | generated` (matches actual `kebab_core::TrustLevel` variants) ## Test plan - [x] `cargo test --workspace --no-fail-fast -j 1` — green - [x] `cargo clippy --workspace --all-targets -- -D warnings` — clean - [x] new tests: 6 lexical (media / ingested_after / doc_id / AND / unknown / default), 3 store-sqlite filter unit tests + 2 vector hybrid mirror (#[ignore] for AVX), 4 CLI integration, 2 MCP - [x] manual smoke: `--media md` (alias), `--ingested-after garbage` (config_invalid + exit 2), `--ingested-after 2030-01-01T00:00:00Z` (no hits), `--doc-id <id>` (scope), `--tag rust` (frontmatter) ## Architectural notes - `SearchFilters` 3 fields are additive with `#[serde(default)]` — old JSON without the new keys deserializes cleanly. - `MediaType` JSON has two shapes (`"markdown"` for unit variants, `{"image":"png"}` for tuple variants); the SQL `CASE WHEN json_type='text' THEN json_extract($) ELSE (first object key) END` extracts a unified kind string. - Vector retriever delegates to `kebab-store-sqlite::SqliteStore::filter_chunks`, which gained the same 3 WHERE arms — single source of truth for the filter SQL across lexical's SQL builder and vector's post-filter. - `path_glob` remains a Rust post-filter — unchanged from before fb-36. - `--trust-min` plan/spec drafts mentioned `Trusted/Reviewed/Hearsay/Untrusted`; actual `kebab_core::TrustLevel` variants are `Primary/Secondary/Generated`. Implementation and docs use the real variants. - No new HOTFIXES entry — additive minor, no contract drift. ## Files of interest - spec: `docs/superpowers/specs/2026-05-10-p9-fb-36-search-filters-design.md` - plan: `docs/superpowers/plans/2026-05-10-p9-fb-36-search-filters.md` - core: `crates/kebab-core/src/search.rs` (SearchFilters) - search: `crates/kebab-search/src/lexical.rs` + `kebab-store-sqlite/src/filters.rs` (shared filter_chunks) - CLI: `crates/kebab-cli/src/main.rs` (Cmd::Search) - MCP: `crates/kebab-mcp/src/tools/search.rs` (SearchInput)
altair823 added 10 commits 2026-05-09 19:35:21 +00:00
`kebab search` 에 7 flag 노출 (기존 4 + 신규 3):
- --tag (반복) / --lang / --path-glob / --trust-min (기존 SearchFilters)
- --media (csv) / --ingested-after (RFC3339) / --doc-id (신규)

filter layer = SQLite WHERE (lexical) + over-fetch+post-filter
(vector). AND 결합. wire schema 무변경 (input only).

`SearchFilters` 3 필드 additive (#[serde(default)] 로 backwards-
compat). MCP SearchInput 7 optional 필드 추가. invalid RFC3339 →
error.v1.code = config_invalid.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9 tasks: SearchFilters extension, lexical SQL WHERE, vector
filter_chunks mirror, CLI 7 flags, integration tests, MCP
SearchInput extension, workspace test/clippy, docs, smoke+PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 additive optional fields. #[serde(default)] preserves
backwards compat for older JSON without the new keys.
MEDIA_KINDS const exposes canonical "markdown"/"pdf"/"image"/
"audio"/"other" labels for downstream alias normalization.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SQL WHERE clause extension. media uses CASE WHEN json_type='text'
to handle both unit (\`"markdown"\`) and tuple (\`{"image":"png"}\`)
MediaType serde shapes. ingested_after relies on RFC3339 lexicographic
ordering with UTC Z (per fb-32 ingest invariant). doc_id is a simple
equality. AND combinator with existing tags / lang / trust filters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per code review on 2c80e2a. manual-repeat-n lint triggers
for Rust 1.94+ when repeat().take() can be expressed as
repeat_n directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
filter_chunks helper in kebab-store-sqlite extended with the same 3
WHERE clauses as lexical. Vector still over-fetches k*2 then
post-filters via SqliteStore::filter_chunks; small k can return < k
hits when filters drop a lot — agent is expected to widen k or
paginate. AND combinator with existing filters.

- kebab-store-sqlite/src/filters.rs: media IN-list subquery, ingested_after
  lexicographic >= compare, doc_id equality; mirrors lexical SQL arms
- 3 direct unit tests (filter_chunks_media_type/ingested_after/doc_id)
  that run without AVX/Lance
- common/mod.rs: insert_doc / insert_doc_with_media / run_vector_search
  helpers on HybridEnv for integration-test use
- hybrid.rs: 2 new #[ignore = "requires AVX..."] integration tests
  (vector_filter_by_media, vector_filter_by_doc_id)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 new flags: --tag (repeatable), --lang, --path-glob,
--trust-min (value_enum), --media (csv with `md` alias),
--ingested-after (RFC3339; config_invalid on parse fail),
--doc-id. Dispatch translates clap values into SearchFilters
and propagates structured errors through the existing
StructuredError wrapper from fb-34.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cover: --doc-id scoping, --ingested-after validation error,
--media md alias, --tag repeatable + frontmatter parsing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7 new optional inputs on SearchInput: tags, lang, path_glob,
trust_min, media, ingested_after, doc_id. Validation surfaces as
error.v1 code = invalid_input via StructuredError. Dispatch builds
SearchFilters from the inputs and forwards through the existing
search_with_opts_with_config facade.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 requested changes 2026-05-09 19:41:35 +00:00
Dismissed
claude-reviewer-01 left a comment
Member

fb-36 round 1 — overall solid. SearchFilters extension, filter_chunks extension, lexical SQL extension, CLI/MCP dispatch, and tests all line up with the spec, and cargo test -p kebab-store-sqlite filter_chunks + -p kebab-search --test lexical + -p kebab-cli --test wire_search_filters all green locally. Lexical and vector go through identical SQL fragments for the 3 new arms (subquery IN (SELECT d2.doc_id FROM documents d2 JOIN assets a ...) for media, d.updated_at >= ? for ingested_after, d.doc_id = ? for doc_id), so behavior parity is preserved. Wire schema unchanged, MCP SearchInput extended additively, #[serde(default)] on the new SearchFilters fields keeps backwards compat.

Three changes requested before merge:

1. (Important) README documentation drift on --tag

README.md kebab search row says: "--tag / --media 는 각각 , 구분 다중 값 OR 매칭". This is wrong about --tag. The CLI declares:

#[arg(long)]
tag: Vec<String>,

i.e. repeatable but not value_delimiter = ','. Only --media is csv. Spec correctly says --tag rust --tag async (repeatable). Either:

  • fix the README sentence to "--tag 는 반복 (--tag a --tag b), --media, 구분", or
  • add value_delimiter = ',' to tag and update the spec.

The first is the smaller / spec-compliant fix.

2. (Important) --ingested-after accepts non-UTC offsets but compares lexicographically

Spec §Filter layer says "ingested_after: d.updated_at >= ? (RFC3339 lexicographic compare; UTC Z 가정)". The CLI flag doc also says "(UTC)". But the implementation in crates/kebab-cli/src/main.rs:686-712 and crates/kebab-mcp/src/tools/search.rs:74-89 parses any RFC3339 — including offsets like +09:00 — and crates/kebab-search/src/lexical.rs:352-358 / crates/kebab-store-sqlite/src/filters.rs:159-165 then formats the OffsetDateTime with its original offset, e.g. 2026-04-01T00:00:00+09:00. A lexicographic >= against DB values that always store Z is wrong: ASCII '+' (0x2B) < 'Z' (0x5A), so 2026-04-01T00:00:00+09:00 >= 2026-04-01T00:00:00Z evaluates true even though the actual instant is 9 hours earlier than the stored ones — the filter silently misses recent docs.

Pick one:

  • Normalize to UTC before formatting (recommended, smallest change):
    let formatted = after
        .to_offset(time::UtcOffset::UTC)
        .format(&time::format_description::well_known::Rfc3339)
        .expect("OffsetDateTime formats to RFC3339");
    
    applied in both crates/kebab-search/src/lexical.rs and crates/kebab-store-sqlite/src/filters.rs.
  • Reject non-UTC offsets at parse time in CLI + MCP with config_invalid / invalid_input.

The first preserves the documented "any RFC3339 accepted" surface and just fixes the comparison. Since both retrievers format the timestamp themselves, both call sites need the change.

3. (Important — test gap) Multi-value --tag not exercised

Spec test plan line 172: "kebab search Q --tag rust --tag async --json IN-list 동작". crates/kebab-cli/tests/wire_search_filters.rs::search_with_tag_filter_matches_frontmatter_tags only uses single --tag rust. Add a case that ingests three docs (tag=rust, tag=async, tag=other), runs --tag rust --tag async, and asserts both tagged docs surface but the third does not. This protects the tags_any IN-list behavior from regression (esp. given the README's CSV claim makes it tempting to add value_delimiter = ',' later, which would silently change semantics for --tag rust,async).

Minor (nice-to-have, not blocking)

  • crates/kebab-mcp/src/tools/search.rs:164 writes the string literal "error.v1"; matches kebab_app::ERROR_V1_ID but using the constant (as crates/kebab-cli/src/main.rs:697 does) is more consistent with the rest of the codebase and survives a future schema-id rename.
  • The lexical media SQL uses f.doc_id IN (SELECT d2.doc_id FROM documents d2 JOIN assets a ...) even though the outer query already joins documents d. A simpler JOIN assets a ON a.asset_id = d.asset_id + WHERE CASE ... END IN (...) would match the existing tag/lang/trust pattern. The vector path can keep the subquery since its outer query is different. Skip if you prefer the current shape — vector and lexical SQL would diverge slightly but both are already idempotent.
fb-36 round 1 — overall solid. SearchFilters extension, `filter_chunks` extension, lexical SQL extension, CLI/MCP dispatch, and tests all line up with the spec, and `cargo test -p kebab-store-sqlite filter_chunks` + `-p kebab-search --test lexical` + `-p kebab-cli --test wire_search_filters` all green locally. Lexical and vector go through identical SQL fragments for the 3 new arms (subquery `IN (SELECT d2.doc_id FROM documents d2 JOIN assets a ...)` for media, `d.updated_at >= ?` for ingested_after, `d.doc_id = ?` for doc_id), so behavior parity is preserved. Wire schema unchanged, MCP `SearchInput` extended additively, `#[serde(default)]` on the new `SearchFilters` fields keeps backwards compat. Three changes requested before merge: ### 1. (Important) README documentation drift on `--tag` README.md `kebab search` row says: "`--tag` / `--media` 는 각각 `,` 구분 다중 값 OR 매칭". This is wrong about `--tag`. The CLI declares: ```rust #[arg(long)] tag: Vec<String>, ``` i.e. repeatable but **not** `value_delimiter = ','`. Only `--media` is csv. Spec correctly says `--tag rust --tag async` (repeatable). Either: - fix the README sentence to "`--tag` 는 반복 (`--tag a --tag b`), `--media` 는 `,` 구분", or - add `value_delimiter = ','` to `tag` and update the spec. The first is the smaller / spec-compliant fix. ### 2. (Important) `--ingested-after` accepts non-UTC offsets but compares lexicographically Spec §Filter layer says "ingested_after: d.updated_at >= ? (RFC3339 lexicographic compare; UTC `Z` 가정)". The CLI flag doc also says "(UTC)". But the implementation in `crates/kebab-cli/src/main.rs:686-712` and `crates/kebab-mcp/src/tools/search.rs:74-89` parses any RFC3339 — including offsets like `+09:00` — and `crates/kebab-search/src/lexical.rs:352-358` / `crates/kebab-store-sqlite/src/filters.rs:159-165` then formats the `OffsetDateTime` with its **original offset**, e.g. `2026-04-01T00:00:00+09:00`. A lexicographic `>=` against DB values that always store `Z` is wrong: ASCII `'+'` (0x2B) < `'Z'` (0x5A), so `2026-04-01T00:00:00+09:00 >= 2026-04-01T00:00:00Z` evaluates true even though the actual instant is 9 hours earlier than the stored ones — the filter silently misses recent docs. Pick one: - **Normalize to UTC** before formatting (recommended, smallest change): ```rust let formatted = after .to_offset(time::UtcOffset::UTC) .format(&time::format_description::well_known::Rfc3339) .expect("OffsetDateTime formats to RFC3339"); ``` applied in both `crates/kebab-search/src/lexical.rs` and `crates/kebab-store-sqlite/src/filters.rs`. - Reject non-UTC offsets at parse time in CLI + MCP with `config_invalid` / `invalid_input`. The first preserves the documented "any RFC3339 accepted" surface and just fixes the comparison. Since both retrievers format the timestamp themselves, both call sites need the change. ### 3. (Important — test gap) Multi-value `--tag` not exercised Spec test plan line 172: "`kebab search Q --tag rust --tag async --json` IN-list 동작". `crates/kebab-cli/tests/wire_search_filters.rs::search_with_tag_filter_matches_frontmatter_tags` only uses single `--tag rust`. Add a case that ingests three docs (tag=`rust`, tag=`async`, tag=`other`), runs `--tag rust --tag async`, and asserts both tagged docs surface but the third does not. This protects the `tags_any` IN-list behavior from regression (esp. given the README's CSV claim makes it tempting to add `value_delimiter = ','` later, which would silently change semantics for `--tag rust,async`). ### Minor (nice-to-have, not blocking) - `crates/kebab-mcp/src/tools/search.rs:164` writes the string literal `"error.v1"`; matches `kebab_app::ERROR_V1_ID` but using the constant (as `crates/kebab-cli/src/main.rs:697` does) is more consistent with the rest of the codebase and survives a future schema-id rename. - The lexical media SQL uses `f.doc_id IN (SELECT d2.doc_id FROM documents d2 JOIN assets a ...)` even though the outer query already joins `documents d`. A simpler `JOIN assets a ON a.asset_id = d.asset_id` + `WHERE CASE ... END IN (...)` would match the existing tag/lang/trust pattern. The vector path can keep the subquery since its outer query is different. Skip if you prefer the current shape — vector and lexical SQL would diverge slightly but both are already idempotent.
altair823 added 1 commit 2026-05-09 19:48:05 +00:00
- ingested_after: convert OffsetDateTime to UTC before formatting
  so non-Z offsets compare correctly against UTC TEXT storage
  (lexical.rs + filters.rs)
- README: --tag is repeatable-only, not csv (only --media is csv)
- test(cli): add multi-value --tag OR-within IN-list coverage
- test(store): add UTC-offset regression test for ingested_after
- mcp: use ERROR_V1_ID const instead of hardcoded "error.v1"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
claude-reviewer-01 approved these changes 2026-05-09 19:57:00 +00:00
claude-reviewer-01 left a comment
Member

Round 2 review — all round 1 fixes verified, no follow-ons.

Round 1 verification (commit 84287d0):

  1. --ingested-after non-UTC offset: to_offset(time::UtcOffset::UTC) applied at both SQL-formatting sites (crates/kebab-search/src/lexical.rs:357, crates/kebab-store-sqlite/src/filters.rs:164). Comments updated to explain the lex-compare bug (+ 0x2B < Z 0x5A in ASCII).
  2. README --tag rewritten as repeatable-only (only --media is csv).
  3. Multi-tag OR test added — search_with_two_tag_filters_returns_or_within_tags in wire_search_filters.rs:233. Asserts a.md (rust) ∪ b.md (async), excludes c.md (no tags).
  4. ERROR_V1_ID const used in kebab-mcp/src/tools/search.rs:166.
  5. Bonus — regression test filter_chunks_ingested_after_non_utc_offset_compares_as_instant (filters.rs:675) seeds a doc at 2026-04-01T01:00:00Z and queries 2026-04-01T05:00:00+09:00 (== 2026-03-31T20:00:00Z); doc must match. Tight, surgical regression coverage.

Round 2 follow-on probing — nothing actionable found:

  • Negative-offset edge case: to_offset(UTC) produces the canonical Z form regardless of source offset sign. The time crate's RFC3339 well-known formatter consistently outputs ...Z for UTC instants. No new edge case.
  • CLI/MCP dispatch path: both parse RFC3339 → OffsetDateTime (preserving offset) → SearchFilters → SQL formatter. Fix is at the SQL formatter (the right layer — keep OffsetDateTime semantically rich until the storage boundary). Confirmed by grep across CLI / MCP / search / store crates.
  • HOTFIXES entry: not needed. The fb-36 spec's Risks / notes doesn't actually call out a "UTC Z 가정" rule — only the in-code comments did, and they've been updated. The behavior fix lands in the same PR before merge, so it's not a post-merge deviation.
  • lexical.rs parallel test for non-UTC offset: lexical.rs uses identical SQL-formatting code as filter_chunks. Existing lexical_filter_by_ingested_after covers UTC, and the filter_chunks regression test covers the structural bug. Adding a duplicate at the lexical-integration layer is low marginal value — acceptable.
  • updated_at vs ingested_after naming: ingest commits update updated_at, so the column semantically tracks last-ingest time. Fine.

Verification:

  • cargo clippy --workspace --all-targets -- -D warnings → clean
  • cargo test --workspace --no-fail-fast -j 1 → all green, no FAIL lines

LGTM. Ready to merge.

Round 2 review — all round 1 fixes verified, no follow-ons. **Round 1 verification (commit 84287d0):** 1. `--ingested-after` non-UTC offset: `to_offset(time::UtcOffset::UTC)` applied at both SQL-formatting sites (`crates/kebab-search/src/lexical.rs:357`, `crates/kebab-store-sqlite/src/filters.rs:164`). Comments updated to explain the lex-compare bug (`+` 0x2B < `Z` 0x5A in ASCII). 2. README `--tag` rewritten as repeatable-only (only `--media` is csv). 3. Multi-tag OR test added — `search_with_two_tag_filters_returns_or_within_tags` in `wire_search_filters.rs:233`. Asserts a.md (rust) ∪ b.md (async), excludes c.md (no tags). 4. `ERROR_V1_ID` const used in `kebab-mcp/src/tools/search.rs:166`. 5. Bonus — regression test `filter_chunks_ingested_after_non_utc_offset_compares_as_instant` (filters.rs:675) seeds a doc at `2026-04-01T01:00:00Z` and queries `2026-04-01T05:00:00+09:00` (== `2026-03-31T20:00:00Z`); doc must match. Tight, surgical regression coverage. **Round 2 follow-on probing — nothing actionable found:** - *Negative-offset edge case*: `to_offset(UTC)` produces the canonical `Z` form regardless of source offset sign. The `time` crate's RFC3339 well-known formatter consistently outputs `...Z` for UTC instants. No new edge case. - *CLI/MCP dispatch path*: both parse RFC3339 → `OffsetDateTime` (preserving offset) → `SearchFilters` → SQL formatter. Fix is at the SQL formatter (the right layer — keep `OffsetDateTime` semantically rich until the storage boundary). Confirmed by grep across CLI / MCP / search / store crates. - *HOTFIXES entry*: not needed. The fb-36 spec's `Risks / notes` doesn't actually call out a "UTC Z 가정" rule — only the in-code comments did, and they've been updated. The behavior fix lands in the same PR before merge, so it's not a post-merge deviation. - *lexical.rs parallel test for non-UTC offset*: lexical.rs uses identical SQL-formatting code as filter_chunks. Existing `lexical_filter_by_ingested_after` covers UTC, and the filter_chunks regression test covers the structural bug. Adding a duplicate at the lexical-integration layer is low marginal value — acceptable. - *`updated_at` vs `ingested_after` naming*: ingest commits update `updated_at`, so the column semantically tracks last-ingest time. Fine. **Verification:** - `cargo clippy --workspace --all-targets -- -D warnings` → clean - `cargo test --workspace --no-fail-fast -j 1` → all green, no FAIL lines LGTM. Ready to merge.
altair823 merged commit a72c6f307c into main 2026-05-10 02:02:27 +00:00
altair823 deleted branch feat/fb-36-search-filters 2026-05-10 02:02:28 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: altair823-org/kebab#127