Skip to content

gh-security: unused-code triage & GitHub security visibility (2026-06-21)

Re-filed S504 (ruling R9), from reference/: dated triage (2026-06-21), point-in-time.

import { Aside } from “@astrojs/starlight/components”;

1. GitHub security visibility (unsandboxed gh, scope repo)

Section titled “1. GitHub security visibility (unsandboxed gh, scope repo)”
SurfaceStateAPI-visible?
Code scanning — CodeQL security2 open, 18 fixedyes (/code-scanning/alerts)
Dependabot0 openyes
Secret scanning0 openyes
CodeQL code-quality (maintainability/reliability) + AI = the 128/23/10as seen in UINO — dashboard-only
  • Default setup = query_suite: default, threat_model: remotesecurity queries only; every REST alert (all states) is a security rule, zero quality rules.
  • 2 open: js/incomplete-sanitization (lib/supabase/escape.ts), js/incomplete-multi-character-sanitization (a test file).
  • “Security wave” PRs #18–#43 were CodeQL Autofix; #43 reverted the breakages.
  • Code Quality = separate product, public preview now, GA 2026‑07‑20 (paid). Findings live only in the “Code quality” tab (Standard + AI sections), not the REST API. Enable via repo Settings → Security → Code quality (UI only; needs Actions; consumes Actions minutes).
  • Local tooling under-reports the maintainability axis: repo eslint finds 4 unused-vars total (sets no-unused-vars: warn, ignores scripts/**+supabase/**, skips _-prefixed). knip tracks unused exports (different axis). So the 70-imports/21-vars are not reproducible from current local config without tightening it.

2. Triage of 184 knip-flagged unused exports/types

Section titled “2. Triage of 184 knip-flagged unused exports/types”

124 non-vendored symbols classified by a 31-agent fan-out (+60 auto-kept: shadcn/ui, tools/ast-dataflow type-barrel — relocated from lib/ast-dataflow in S393 bl-360).

ClassCount
KEEP_API (live, reached structurally)45
BUILT_NOT_WIRED (finished, no consumer yet)65
DEAD (genuinely unused)14

The classifier anchored “built-not-wired” on in-code task IDs, some of which may pre-date the procurement/sector-intelligence pivot and be superseded, not deferred. Before wiring or backlogging any cluster, check each task ID against the live roadmap / state-of-the-product: on-roadmap → keep; superseded → reclassify DEAD.

Built-not-wired clusters (each needs the pre-pivot check)

Section titled “Built-not-wired clusters (each needs the pre-pivot check)”
ClusternIn-code anchorPre-pivot risk
A — API response-validation rollout (*ResponseSchema + defineRoute)52OPS-T1 R-WP21validate — large parked batch
B — MCP union output schemas (lib/mcp/formatters/search)5B-INV-37/M37low — externally blocked (SDK z.union)
C — feed flag-analyser + starter-packs (lib/intelligence)4S155 WP3validate — pivot-sensitive
D — edit-intent write-back (lib/edit-intent)2ID-59 {59.8/9/13}low — Task 59 active
E — Q&A corpus promotion (lib/q-a-pairs)2Task 59 {59.22–25}low — hot, landing now
F — dedup gate (lib/dedup/content-dedup.ts)2OPS-3/s183validate — if cancelled → DEAD
G — workspaces icons/badge (components/workspace)4T4 (TODO(T4))validate
H — company-profile detail page (useCompanyProfile)1none (route exists)decision: build page or delete hook+route
I — drafting / cost / quality-actions3none (“Phase 3”)highest rot risk — no owner
J — pipeline-run polling (lib/query/fetchers)1nonelow — wire or delete pair

DELETED (0 refs, tsc-green): getContentTypeIcon, LAYER_VALUES, hasEditorialNotes(+EDITORIAL_NOTE_PATTERNS). DEMOTED (dropped export, used in-file): requestContextStorage, HEADING_PATTERNS, HTML_CONTENT_TYPES, hasGarbledKeywords, contentTypeSortKey, UploadFileSuggestedLayer. knip exports 111→103, types 73→72; .knip-baseline.json re-based. Verified: tsc green · 56 tests · detect_changes risk=low/0 processes.

EXCLUDED (deferred): extractFromUrl ({112.13}), computeGapSummary (P1-29), the HighlightCategory/CitationsData type-chains (knip flags one member but sibling Transcript*/ProcurementResponseMetadata are exported+0-ref yet unflagged — needs knip.config types/ review), coverage-guide-card (NOT orphaned — CoverageGuideCard live via coverage-guide-tabcoverage-tabs.tsx; agent over-reached, caught by tsc).

4. S387 follow-up resolutions (pre-pivot 2nd pass + H/I/J + type-chain + CodeQL quality)

Section titled “4. S387 follow-up resolutions (pre-pivot 2nd pass + H/I/J + type-chain + CodeQL quality)”

Executed the S384 plan (session ran as “S387”). 4 commits on gh-security, pushed + tagged s387-knip-cleanup; full suite green (13948 pass / 0 fail).

CommitThreadWhat
5d71f7d11+4knip cleanup, 9 symbols (2 deleted, 7 demoted); exports 103→100, types 74→68
9187b3043-Iretired dead quality-actions module (+test) + formatCostUSD; types 68→66
6f2d8bb03-Hbuilt app/intelligence/profiles/[id] detail/edit page; wired useCompanyProfile; exports 100→99
93d8cec22fixed CodeQL smart-quote regex bug (degraded to ASCII dupes)
ClusterVerdictAction
C intelligence-feed (S155 WP3)KEEP_DEFERRED — on-roadmapnone; 4 zero-ref contract types stay deferred
F dedup (OPS-3/s183)triage WAS WRONG → keep-livededup is SHIPPED; every export live via dynamic await import('@/lib/dedup'). Demoted 1 internal const (DEDUP_MIN_CONTENT_LENGTH)
G workspace (T4)MIXEDDELETED 2 true orphans (WorkspaceBadge, getWorkspaceIcon); kept-live WorkspaceSelector; 8-symbol T4 island kept-deferred → new backlog item (keep-vs-retire pending T4 redesign vs per-type-launcher pivot)
H company-profileBUILTdetail/edit page; wired orphaned useCompanyProfile
I drafting/cost/quality-actionsRETIRED (partial)deleted quality-actions.ts+test + formatCostUSD; estimateQuestionCost + non-streaming draftResponse are LIVE — kept (2 more over-reaches)
J pipeline-run pollingDEFER (not wire, not retire)IS the cocoindex single-run progress poller but host-less (EP2 markdown-batch UI removed). Reuse fetchPipelineRun when non-blocking /api/upload is built → ID-56 {56.12}
type-chain (content.ts/procurement-metadata.ts)premise false (rg false-zero)demoted HighlightCategory/CitationsData + cluster-E Skip*/PromotionFailure* in-file; no knip.config change

⚠️ Meta-finding — static-analysis over-reach (5 caught this session)

Section titled “⚠️ Meta-finding — static-analysis over-reach (5 caught this session)”

The static-0-ref signal produced 5 false “dead” calls, all caught by adversarial re-validation before deletion: coverage-guide-card + WorkspaceSelector (live via JSX chains), cluster-F dedup entirely (live via dynamic await import()), estimateQuestionCost + draftResponse (live via indirect callers). Root cause: static analysis is blind to (1) dynamic imports, (2) JSX render-chains, (3) sandboxed-rg false-zeros on read-denied files. Trust tsc (includes test files) + read the actual call sites before any deletion. Validates the mandatory 2nd pass.

Thread 2 — CodeQL Code Quality reproduced locally

Section titled “Thread 2 — CodeQL Code Quality reproduced locally”

Dashboard-only findings reproduced via CodeQL CLI → SARIF (javascript-code-quality-extended.qls): 128 maintainability = EXACT match (note-level); 8/23 reliability (GitHub folds extra server-side queries); 10 “AI” not CLI-reproducible. 119/136 cosmetic; no empty-catch findings (silent-failure policing holds). 1 genuine bug fixed (smart-quote regex). Outstanding (S387): the eslint-tightening decision (drop scripts/+supabase/ ignores, add unused-imports, raise to error) to make these locally enforceable. Resolved S391 — see §5.

5. S391 closeouts — clusters G + J retired, eslint-tightening adopted

Section titled “5. S391 closeouts — clusters G + J retired, eslint-tightening adopted”

S391 (theme-14 / ID-121 stream-2, merged via PR #47 → main on 22/06/2026, branch s391-security-closeouts) lands the three remaining decisions from §4 — both deferred clusters and the outstanding recurrence-prevention layer. The CodeQL classification work itself does not change; this section records the dispositions and the ledger movement.

CommitDecisionOutcome
a58879f5 + 9bb4fd88Cluster G — T4 workspace island RETIRED8 symbols / 4 src + 2 test files / −1043 LOC. Removed: WorkspaceCreateDialog, WorkspaceCard, WorkspaceWithCounts, WorkspaceColourPicker, WorkspaceIconPicker, WORKSPACE_ICONS, WorkspaceIconName, ICON_MAP. The live /workspaces route renders the per-type launcher (useLauncherTypes); WorkspaceSelector is kept (live via organise-section). Closes bl-351.
37ebe7faCluster J — item-J pipeline-run poller RETIREDRemoved GET /api/pipeline-runs/[id] + its test, fetchPipelineRun, and pipelineRuns.detail. ID-56 {56.12} shipped a separate folder-drop status route, so the generic poller never gained a consumer. The pipeline_runs table + server-side writes are preserved. Carries a note on bl-61 (EP3 retrofit) that the retired endpoint must not be assumed by the EP3 progress UI — rebuild against the folder-drop status pattern instead.
2d0e7b81Thread 2 outstanding — eslint unused-imports gate ADOPTEDUn-ignore scripts/ + supabase/; promote unused-imports/no-unused-imports + unused-imports/no-unused-vars to error (^_ exempt). 13 imports auto-fixed, 6 vars/args handled, 5 scope-creep sites inline-disabled with reasons. The 18 unused-code findings are now locally enforceable; the recurrence-prevention layer is in place.

knip impact. Exports 99 → 97 (a DROP — never trips the baseline gate per /runbooks/ci/ §6, which fails only on EXCEED). .knip-baseline.json is safe to leave at 99 or rebase opportunistically to 97 per §6.3.

Hosted security alerts. 3 → 0 open at HEAD (the three false-positive / by-design findings dismissed with documented reasons via PATCH …/code-scanning/alerts/{n}). Verified per the ID-121 {121.1} RESEARCH §8 audit trail.

What remains for ID-121. The genuine-fix core from §5 (above — remote-property-injection ×4, the 2 useless-comparison + 1 unreachable + 1 unused-state warnings, 22 commented-out blocks), the cosmetic bucket (110 note-level — return-style + TODOs, staff-engineer assessment in hand), and the AI-suggestions / posture waves. Tracked as ID-121 resolution waves A–E in /specs/id-121-security-quality-baseline/plan/.