Skip to content

Backlog Triage Disposition Board

Generated 2026-06-26 — 15 backlog records verified against current code + 1 security/quality (CodeQL/knip) sweep.

Headline: 2 to close outright, 4 trivial quick-wins landable this session, 1 to ride the ID-45 zero-row window; the rest are correctly parked/blocked. Zero security or correctness impact in the CodeQL sweep — ~26 of ~37 findings are idiomatic false-positives.


Sorted with actionable items at the top (close / quick-win / ride-window first, then parked, then bigger).

bl-idtitleverdictdispositioneffortrationale
308PullMD-parity for manually-added references (ID-110)superseded-staleCLOSE NOWtrivialPullMD fully retired (id-129 decommission migration, zero code refs); id-112 Trafilatura already converges both URL paths on one TRAFILATURA_CONFIG. No TS PullMD client warranted. Record’s own notes concur.
165Persist Pydantic exception sub-class to pipeline_runs.resultalready-doneCLOSE NOWtrivialBoth halves shipped: Option-D redaction (flow.py:471-497) + Option-B fine pydantic_class persisted to pipeline_runs.result.error_detail as ID-61.4 (flow.py:434-468/3875 + record/route.ts:221). Nothing left to decide.
314Clarify/drop dedup_status:'clean' in /api/ingest/urlstill-validQUICK WINtrivialHardcoded constant (route.ts:62,320); no dedup in reference path; RPC’s already_existed ignored in new-write branch. Drop the field (or surface already_existed). ID-110 close-gate.
371Re-add pullmd-free Playwright/Chromium image-baking CI guardstill-validQUICK WINtrivialid-129 commit 75d9146e deleted the Playwright/Chromium image-bake assertion as collateral with the (correct) pullmd grep removal. No replacement. Trivial defense-in-depth grep restore on onprem-deploy.yml.
369Add qa_dedup_proposer_failed to pipeline error-class vocabstill-validQUICK WINtrivialClassifier (flow.py:369) can return a value missing from the Python tuple (flow.py:236-243) AND the TS Zod enum (error-classes.ts:27-34). Safe today (proposer failure swallowed) but a footgun before flow-fatal promotion. 4-point fix: two arrays + Inv-25 comment + test length 6→7.
46run_quality_scan inserts flag_type=‘classification_low’ not in CHECK enumstill-validQUICK WINsmallLatent SQLSTATE 23514: function body inserts 'classification_low' (squash:4871,4901) which the CHECK (squash:6836) rejects. No callers yet. Add value to CHECK enum (or remap to low_quality) + test.
325Durable stale-citation marker on citations tablestill-validRIDE ID-45smallcitations table has no stale column; UC4 re-anchor (route.ts:689-700) explicitly notes “no stale column to set”, emits only a transient warning. One-column ALTER + write-site update, best timed with the ID-45 re-ingest zero-row window per the record.
316Revisit summary_data disposition at content_items→reference cutoverstill-validKEEP PARKEDsmallLive TS writer (generateSummary) + many live readers; cocoindex does NOT populate it; no ontology spec subsumes it. Unblocks when: an ontology lane explicitly replaces structured summaries.
310Server-side progress surface for sync /api/uploadstill-validKEEP PARKEDmediumSync path still uses cosmetic STEP_ADVANCE_INTERVAL timer; route is single synchronous response. pipeline_runs writes exist server-side but no sync-upload client polls them. Unblocks when: prioritised as UX work (convert route to async+poll or stream).
169Runbook: absent error_class, expected Vercel 400, Cloud Run monitoringstill-validKEEP PARKEDtrivialCode behaviour is live + accurate (flow.py:3794-3808); ~15min doc-only item. Before writing: re-point “Cloud Run monitoring” → Coolify/IONOS (Cloud Run torn down S298). Promote when the ops/observability runbook is next edited (ID-61/T13).
176Resolve cocoindex operation-value vocabulary case mismatchstill-validKEEP PARKEDtrivialDormant _emit_upsert_log uses uppercase INSERT/UPDATE vs cocoindex’s lowercase upsert; helper unwired. Unblocks when: wired under ID-61/T13 (cocoindex still exposes no per-UPSERT callback at 1.0.7). Clean stale Cloud Run docstring at that time.
162Evaluate cocoindex num_reprocesses vs KH _FlowRetryCounterstill-validKEEP PARKEDsmall_FlowRetryCounter live (flow.py:577/3343); S299 blocker holds — num_reprocesses reachable only outside app_main, webhook fires inside. Unblocks when: engine API exposes the counter at emission time (not met at 1.0.7).
374Verify reference_items FK-tolerance on clean platform standupneeds-more-infoKEEP PARKEDsmallCited FK + {75.17} converge path are live/current. Premise is an unconfirmed S415 cross-DB test-state contamination artefact, NOT a reproducible clean-standup defect. Unblocks when: re-run on next clean ID-127 / ID-45 standup walk (cannot reproduce statically).
326Block/page citation re-indexing after content editsstill-validCONVERT TO TASKlargeUC4 deliberately skips block/page re-anchor (route.ts:703-705) pending the Claude block-splitter (out of scope). Real but large; no observed consumer regression. Convert to a task scoped under the block-splitter work when a drift consumer-break is seen.
304Mount QARevisionHistory on a q_a_pairs detail surfacestill-validMERGEsmallComponent built+tested with all backing infra live (table/fetcher/key/route); gap is a missing q_a_pairs detail host (admin only has dedup-proposals). Merge into whatever task creates a q_a_pairs detail page/drawer.

CLOSE NOW — done or stale, no work needed

Section titled “CLOSE NOW — done or stale, no work needed”
  • bl-308 — superseded: PullMD retired (id-129), Trafilatura already converges both URL paths (id-112). Prime close candidate.
  • bl-165 — already shipped as ID-61.4 (Option-D redaction + Option-B error_detail persistence both landed).

QUICK WINS — ready, trivial/small, no ID-45 dependency (in-session candidates)

Section titled “QUICK WINS — ready, trivial/small, no ID-45 dependency (in-session candidates)”
  • bl-314 (trivial) — drop/replace hardcoded dedup_status:'clean' in app/api/ingest/url/route.ts; ID-110 close-gate.
  • bl-371 (trivial) — restore the pullmd-free + Playwright/Chromium grep guard in .github/workflows/onprem-deploy.yml.
  • bl-369 (trivial) — add qa_dedup_proposer_failed to both vocab arrays (flow.py:236-243, error-classes.ts:27-34) + bump test length 6→7 + Inv-25 comment.
  • bl-46 (small) — migration: add classification_low to ingestion_quality_log_flag_type_check (or remap to low_quality) + regression test for run_quality_scan.

Suggested batch: bl-314 + bl-371 + bl-369 are pure trivial edits; bl-46 is a one migration + test. All four are independent and land cleanly in one hygiene-adjacent session.

RIDE THE ID-45 ZERO-ROW WINDOW — schema items timed to the cutover

Section titled “RIDE THE ID-45 ZERO-ROW WINDOW — schema items timed to the cutover”
  • bl-325 (small) — add a durable stale/is_stale column to citations + set it in the UC4 re-anchor lost-text branch (app/api/items/[id]/route.ts:689-700). Cheap while tables are sparse; the record explicitly asks to ride this window.

KEEP PARKED — genuinely blocked/deferred (with unblock trigger)

Section titled “KEEP PARKED — genuinely blocked/deferred (with unblock trigger)”
  • bl-316 — unblocks when an ontology lane explicitly replaces structured summaries.
  • bl-310 — unblocks when sync-upload UX is prioritised (async+poll pipeline_runs, or stream).
  • bl-169 — doc-only; promote when the Coolify/IONOS ops+observability runbook is next edited (re-point Cloud Run framing first).
  • bl-176 — unblocks when _emit_upsert_log is wired under ID-61/T13 (cocoindex still has no per-UPSERT callback at 1.0.7).
  • bl-162 — unblocks if/when cocoindex exposes num_reprocesses at webhook-emission point.
  • bl-374 — see Disagreements below; ride the next clean ID-127/ID-45 standup walk.

CONVERT TO TASK / MERGE — bigger or host-dependent

Section titled “CONVERT TO TASK / MERGE — bigger or host-dependent”
  • bl-326 (large) → CONVERT to a task under the Claude block-splitter work; the block/page re-index gap is by-design until that lands. No consumer regression observed yet, so not urgent.
  • bl-304 (small) → MERGE into the task that introduces a q_a_pairs detail page/drawer; the component and all infra are ready, only a host surface is missing.

SECURITY / QUALITY CLEANUP — CodeQL buckets + knip baseline plan

Section titled “SECURITY / QUALITY CLEANUP — CodeQL buckets + knip baseline plan”

Overall severity: LOW / cosmetic. Zero security, zero correctness impact. ~26 of ~37 findings are false-positives or intentional-and-documented.

FALSE POSITIVES — do NOT touch (idiomatic / load-bearing):

  • 13× Protocol ... stub bodies (flow_context.py 124/125/177/178/272-274; test stub classes) — Ellipsis is the typed-stub convention. CodeQL “statement has no effect” is a known FP. Rewriting to pass would NOT silence it and is semantically identical. Suppress at source if anything.
  • 2× BaseException handlers (test_platform_manifest_gate.py:191, test_cocoindex_flow_live_ingest.py:221) — already carry # noqa: BLE001 + comment; deliberate binder-thread error surfacing. Accept.
  • 2× server.py rate-limit globals (server.py:172/173) — CONFIRMED FP; both are mutated via global in _rate_limit_allows()/reset_rate_limit_state(). The limiter works. Do NOT “fix”.
  • 1× PDF byte-literal wrap (test_pdf_zero_archetype.py:76) — deliberate line-wrapping of one PDF dict, not a missing comma.
  • 1× ast-dataflow fixture import (tools/ast-dataflow/__tests__/fixtures/05-importers/caller-unused.ts:2) — the unused import IS the fixture’s purpose (input for the importers query). MUST preserve; add the fixtures dir to knip/eslint/CodeQL ignores.
  • 1× unreachable retry-return (extraction.py:916 _anthropic_retry) — tenacity reraise=True makes the implicit None unreachable. Optional: append raise AssertionError('unreachable').

GENUINE but trivial (one-line, no behaviour change) — batch into ONE low-priority hygiene PR:

  • 12× except: pass needing a # best-effort: … comment (10 in .claude/skills/ + tooling, only docx.py tmpfile cleanup + extract_tender_questions.py:344 weight-parse in pipeline path; both intentional).
  • Delete duplicate import json (test_cocoindex_flow_write_path.py:3290).
  • Delete leftover _OQ_PARENT_SH (test_crash_injection.py:37) — copy-paste cruft (siblings actually use it).
  • Drop 2 dead stores (extract_conflict_context.py:153,173).
  • KEEP _PIPELINE_ERROR_CLASSES (flow.py:236) — test-synced spec mirror of lib/pipeline/error-classes.ts; add # noqa/keep-alive, do NOT delete. (Note: bl-369 above adds the 7th class to this same mirror.)

knip baseline plan (TS/JS only — does NOT clear in-file Python/TS unused imports):

  1. Triage 86 findings by language first; bun run knip shows only the TS file/export/dep layer.
  2. TS unused imports/locals → bun lint --fix (ESLint no-unused-vars), review diffs.
  3. Python unused imports/locals → no ruff/autoflake config exists; add ruff (F401/F841) OR autoflake --remove-all-unused-imports on scripts/**.py, review diffs.
  4. Prefer DELETE for ordinary dead imports; reserve baseline-acknowledge for load-bearing exceptions.
  5. Load-bearing — IGNORE, never auto-delete: tools/ast-dataflow/__tests__/fixtures/** (add to knip.config.ts ignore + eslint/CodeQL path filter — currently NOT excluded); re-export/barrel shims (e.g. lib/taxonomy/taxonomy.ts); _PIPELINE_ERROR_CLASSES.
  6. Sequence: extend ignores → ESLint --fix → ruff/autoflake → re-run bun run knip + bun run test + pytest scripts/tests/ → land as one hygiene PR.

  • bl-374 (needs-more-info) — The only non-binary verdict. The cited FK (reference_items_source_document_id_fkey) and the {75.17} converge-by-walk path are confirmed live/current, so it is NOT stale. BUT the original S415 failure looks like a cross-DB test-state contamination artefact (a STAGING source_document_id a196e2d8… landed in a PROD reference_items row during manual walk-proof edits), not a reproducible clean-standup defect. By design, source_document_id is a deterministic uuid5('sd:'+url) co-declared with the ri row in the same component, so the source_document always exists on a clean walk — hence no FK tolerance is needed.

    • What to check: run a clean ID-127 platform standup pipeline walk (same clean-DB window as ID-45 / ID-127.11) and confirm _ingest_url_body completes with no reference_items_source_document_id_fkey violation. Cannot be settled statically — keep parked to ride that window. If it reproduces on a genuinely clean DB, escalate to a real bug + add targeted FK tolerance; if not, close as test-state artefact.
  • No other verifier dissent: the remaining 14 verdicts (1 already-done, 1 superseded-stale, 12 still-valid) are all backed by concrete file:line evidence against current code.