Phase 4: Knowledge tiering — include_cold param on list_notes #190

Closed
opened 2026-03-17 03:08:09 +00:00 by forgejo_admin · 0 comments

Lineage

plan-2026-03-16-knowledge-architecture → Phase 4 (Knowledge Tiering — list_notes Default Exclusion)

Repo

forgejo_admin/pal-e-docs

User Story

As a session startup hook querying list_notes(project="pal-e-agency"),
I want completed/historical notes to be excluded by default,
so that the response is ~60 notes instead of ~131 and I don't burn 21K tokens on dead weight every session.

Context

list_notes currently returns ALL notes matching filters — no concept of lifecycle tiering. The pal-e-agency project has ~131 notes, but ~70 are completed phases, done TODOs, or deprecated notes that aren't relevant to active work. Session injection pays the full cost every time.

Tiering rules (computed, not stored):

  • Hot/Warm: Notes with status NOT in the cold set — always returned by default
  • Cold: Notes with status in {completed, done, deprecated, deferred, archived} — excluded by default
  • include_cold=true: Returns everything (backward compatible opt-in)

This is the simple, first-pass rule (status-based only). Parent-chain recursive CTE (notes under completed milestones) is a stretch goal for a subphase.

File Targets

Files to modify:

  • src/pal_e_docs/routes/notes.py line 360-410 (list_notes endpoint) — add include_cold: bool = Query(False, ...) param. Define COLD_STATUSES = {"completed", "done", "deprecated", "deferred", "archived"} as a module-level constant. When include_cold is False, add .filter(Note.status.notin_(COLD_STATUSES)) to the query. The filter should be applied AFTER existing filters (tags, project, note_type, status, parent_slug) so explicit status=completed still works even with include_cold=False.

Important edge case: When the caller explicitly passes status=completed (or any cold status), they clearly want cold notes. In this case, include_cold filtering should NOT override the explicit status filter. Implementation: skip the cold exclusion filter when status is explicitly provided.

Files NOT to touch:

  • src/pal_e_docs/routes/notes.py search endpoints — semantic_search and search_notes are unaffected
  • src/pal_e_docs/models.py — no schema changes
  • Any SDK or MCP files — those get separate PRs

Acceptance Criteria

  • New include_cold boolean query param on GET /notes — default false
  • COLD_STATUSES constant defined at module level: {"completed", "done", "deprecated", "deferred", "archived"}
  • When include_cold=false (default), notes with status in COLD_STATUSES are excluded
  • When include_cold=true, all notes returned (existing behavior)
  • When status=completed is explicitly provided, cold exclusion is skipped (explicit status overrides)
  • parent_slug queries still work correctly (child notes of a parent returned regardless of cold status if include_cold=true)
  • Semantic search and full-text search endpoints are NOT affected
  • All existing tests pass (pytest tests/)

Test Expectations

  • New test: list_notes with default params excludes completed/done/deprecated notes
  • New test: list_notes(include_cold=true) returns all notes including completed
  • New test: list_notes(status=completed) returns completed notes even with include_cold=false
  • New test: list_notes(project=X) with mix of hot and cold notes returns only hot by default
  • Existing tests all pass: pytest tests/ -x -q

Constraints

  • Match existing query parameter style in list_notes (FastAPI Query params)
  • COLD_STATUSES should be a frozenset for immutability and O(1) lookup
  • Do not add parent-chain (CTE) filtering — that's a stretch goal for a subphase
  • Keep the filter logic simple and readable — one line .filter() added to the query
  • No Alembic migration needed

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • project-pal-e-docs — project this affects
  • plan-2026-03-16-knowledge-architecture — parent plan
  • phase-2026-03-16-2-milestone-note-type — prerequisite (milestone note_type exists)
### Lineage `plan-2026-03-16-knowledge-architecture` → Phase 4 (Knowledge Tiering — list_notes Default Exclusion) ### Repo `forgejo_admin/pal-e-docs` ### User Story As a session startup hook querying `list_notes(project="pal-e-agency")`, I want completed/historical notes to be excluded by default, so that the response is ~60 notes instead of ~131 and I don't burn 21K tokens on dead weight every session. ### Context `list_notes` currently returns ALL notes matching filters — no concept of lifecycle tiering. The pal-e-agency project has ~131 notes, but ~70 are completed phases, done TODOs, or deprecated notes that aren't relevant to active work. Session injection pays the full cost every time. Tiering rules (computed, not stored): - **Hot/Warm**: Notes with status NOT in the cold set — always returned by default - **Cold**: Notes with status in `{completed, done, deprecated, deferred, archived}` — excluded by default - **include_cold=true**: Returns everything (backward compatible opt-in) This is the simple, first-pass rule (status-based only). Parent-chain recursive CTE (notes under completed milestones) is a stretch goal for a subphase. ### File Targets Files to modify: - `src/pal_e_docs/routes/notes.py` line 360-410 (`list_notes` endpoint) — add `include_cold: bool = Query(False, ...)` param. Define `COLD_STATUSES = {"completed", "done", "deprecated", "deferred", "archived"}` as a module-level constant. When `include_cold` is False, add `.filter(Note.status.notin_(COLD_STATUSES))` to the query. The filter should be applied AFTER existing filters (tags, project, note_type, status, parent_slug) so explicit `status=completed` still works even with `include_cold=False`. **Important edge case**: When the caller explicitly passes `status=completed` (or any cold status), they clearly want cold notes. In this case, `include_cold` filtering should NOT override the explicit status filter. Implementation: skip the cold exclusion filter when `status` is explicitly provided. Files NOT to touch: - `src/pal_e_docs/routes/notes.py` search endpoints — semantic_search and search_notes are unaffected - `src/pal_e_docs/models.py` — no schema changes - Any SDK or MCP files — those get separate PRs ### Acceptance Criteria - [ ] New `include_cold` boolean query param on `GET /notes` — default `false` - [ ] `COLD_STATUSES` constant defined at module level: `{"completed", "done", "deprecated", "deferred", "archived"}` - [ ] When `include_cold=false` (default), notes with status in COLD_STATUSES are excluded - [ ] When `include_cold=true`, all notes returned (existing behavior) - [ ] When `status=completed` is explicitly provided, cold exclusion is skipped (explicit status overrides) - [ ] `parent_slug` queries still work correctly (child notes of a parent returned regardless of cold status if include_cold=true) - [ ] Semantic search and full-text search endpoints are NOT affected - [ ] All existing tests pass (`pytest tests/`) ### Test Expectations - [ ] New test: `list_notes` with default params excludes completed/done/deprecated notes - [ ] New test: `list_notes(include_cold=true)` returns all notes including completed - [ ] New test: `list_notes(status=completed)` returns completed notes even with include_cold=false - [ ] New test: `list_notes(project=X)` with mix of hot and cold notes returns only hot by default - [ ] Existing tests all pass: `pytest tests/ -x -q` ### Constraints - Match existing query parameter style in `list_notes` (FastAPI Query params) - `COLD_STATUSES` should be a frozenset for immutability and O(1) lookup - Do not add parent-chain (CTE) filtering — that's a stretch goal for a subphase - Keep the filter logic simple and readable — one line `.filter()` added to the query - No Alembic migration needed ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `project-pal-e-docs` — project this affects - `plan-2026-03-16-knowledge-architecture` — parent plan - `phase-2026-03-16-2-milestone-note-type` — prerequisite (milestone note_type exists)
forgejo_admin 2026-03-17 03:14:47 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/pal-e-api#190
No description provided.