Phase 0.7.5 — Knip config validation: corrected baseline proposal
Phase 0.7.5 — Knip config validation: corrected baseline proposal
Section titled “Phase 0.7.5 — Knip config validation: corrected baseline proposal”Audit date: 2026-05-07
Branch: content-items-investigation
knip version: ^6.3.0 (per package.json:139)
Config file: knip.config.ts (105 lines, last modified 5 May 2026)
Baseline file: .knip-baseline.json (counts-only: exports=41, types=15, unlisted=3)
Read-only: no config file changes in this run; corrected baseline proposed in §6.
Predecessors: 0.3 knip-revisit (moderate scope, classified 21 GENUINE-BUILD-NOT-WIRED + 17 LEGACY-SCAFFOLD + 9 INTENTIONAL-RE-EXPORT).
1. Executive summary
Section titled “1. Executive summary”The current knip configuration relies on TWO suppression mechanisms: the tags: ['-public'] JSDoc rule (236 marked exports across 152 files) and the .knip-baseline.json counts-only ceiling (41 exports + 15 types + 3 unlisted). Together they hide ~285 findings.
A no-suppression audit (mechanically classified 229 @public exports for actual import + same-file usage) shows the tags: ['-public'] suppression is 75% justified — 209 exports are INTERNAL-CONTRACT (used as parameter/return types in same file but never imported by name from outside; this is exactly the legitimate “stable signature” use-case knip docs endorse). The remaining 25% splits as 8 CONSUMED (imports do exist; correct that these aren’t flagged) and 11 DRIFT — true positives where the @public tag now hides genuinely dead code that was once a contract. The baseline-tolerated 41+15 raw counts include the 9 queue-handler authoring contracts (justified by §5.4 dispatch.ts ownership pattern, recommend migrating to @public for clarity) plus 21 GENUINE findings already documented in 0.3.
Verdict: the config is over-aggressive but only mildly so. It hides 11–13 true positives that should surface as backlog tickets, and it’s structurally correct in protecting the ~209 legitimate type contracts. The biggest improvement opportunity is moving the 9 queue-handler types into the @public tag system (rather than absorbing via baseline counts) so that the baseline can drop to types=4-6 and any new unused-handler-type regression fails CI immediately. None of the suppressed items rise to a pre-launch fix; canonical-pipeline collapse (0.7.1/0.7.3) would resurrect roughly half of the 11 drift findings if the unused EP2 schemas are repurposed for the canonical core.
Overall confidence: 88%. Below 90% because three findings (PatternCluster, PromptRecommendation, FileUploadState) hinge on whether intelligence flag-analyser or hooks/use-file-upload-pipeline have planned-future consumers we have not surfaced, and because the --tags=-@public / --tags=+@public CLI overrides did not behave as documented (knip 6.3.x bug or flag-format mismatch — fell back to manual classification of the 236 sites).
2. Current config state
Section titled “2. Current config state”knip.config.ts defines six suppression categories. They are unchanged since 0.3 audited them (5 May 2026). Recap of correctness verdict (full table at 0.3 §“summary”):
| Category | Lines | Verdict (0.3) | Re-confirmed (0.7.5) |
|---|---|---|---|
entry allowlist | 4–32 | Justified | Yes |
project glob | 33–45 | Justified | Yes |
ignore paths | 46–59 | Justified | Yes |
ignoreDependencies (9 entries) | 60–70 | Justified | Yes |
tags: ['-public'] | 79 | Justified, requires audit | Re-audited in §4 below — 75% justified, 11 DRIFT findings + 2 likely-DRIFT |
syncCompilers.css | 87–94 | Justified | Yes |
The .knip-baseline.json counts-only mechanism (separate from knip.config.ts) is the OTHER suppression channel:
{ "counts": { "exports": 41, "types": 15, "unlisted": 3 }}This permits 41 exports + 15 types + 3 unlisted before CI fails (scripts/check-knip-baseline.ts).
2.1 Two suppression channels
Section titled “2.1 Two suppression channels”Suppression channel summary:
tags: ['-public']— silences 236 individually-marked exports (152 files). ZERO appear in knip output..knip-baseline.jsoncounts — permits 41+15+3=59 unmarked findings to remain. These DO appear in knip output but don’t fail CI.
Total currently-hidden findings: 236 + 59 = ~295.
3. Baseline knip output stats (current state, suppressions in place)
Section titled “3. Baseline knip output stats (current state, suppressions in place)”Captured via bun run knip --no-config-hints on commit 830cf6ad:
| Bucket | Current | Baseline ceiling | Delta vs ceiling |
|---|---|---|---|
| Unused dependencies | 0 | 0 | 0 |
| Unused devDependencies | 0 | 0 | 0 |
| Unlisted dependencies | 3 | 3 | 0 |
| Unused exports | 41 | 41 | 0 |
| Unused exported types | 15 | 15 | 0 |
| Unused files | 0 | 0 | 0 |
| Duplicates | 0 | 0 | 0 |
| Binaries | 0 | 0 | 0 |
| Enum members | 0 | 0 | 0 |
| Unresolved | 0 | 0 | 0 |
At-baseline. Header total: “Unused exports (41)” + “Unused exported types (15)” + “Unlisted dependencies (3)” = 59 findings reported. CI passes.
This is identical to the 0.3 audit baseline — no drift since S227 cross-track merge (.knip-baseline.json capturedAt: 2026-05-06).
4. No-suppression audit: classifying every currently-hidden item
Section titled “4. No-suppression audit: classifying every currently-hidden item”4.1 The 236 @public-tagged exports
Section titled “4.1 The 236 @public-tagged exports”grep -rn "@public" --include="*.ts" --include="*.tsx" lib components hooks types contexts app returns 236 hits across 152 files. Distribution by top-level dir:
lib/— 152 (66 files)components/— 52 (52 files)hooks/— 32 (32 files)app/— 2 (2 files)
Distribution by export kind: 192 interfaces, 30 types, 6 consts, 0 functions/classes.
Methodology (script at /tmp/claude/check-imports3.sh): for each @public-tagged export, count (a) imports in production code outside the source file, (b) imports in __tests__/, (c) same-file occurrences minus 1 (= internal usages as parameter/return types).
Result categories (228 valid rows after parser deduplication; one extracted name was a duplicate from a multi-export export {} clause):
| Category | Count | Means |
|---|---|---|
| CONSUMED | 8 | At least one import exists outside source file. Tag protects a legitimately-imported type knip cannot resolve via dependency graph (most common: barrel-style export type {...} followed by import-at-use-site). |
| INTERNAL-CONTRACT | 209 | Used in own file as function parameter/return type. The exported NAME is dead-imported, but the function signature using it IS consumed. This is the canonical “stable signature” use-case that knip docs explicitly endorse for tags: ['-public']. |
| DRIFT | 11 | 0 imports + 0 internal uses. The @public tag was added once when the contract was authored but no consumer ever materialised, OR the consumer was deleted and the tag was not. |
Drift list (11 items — see §4.2 below for analysis):
| # | Name | Kind | File | Internal note |
|---|---|---|---|---|
| D-1 | PatternCluster | type | lib/intelligence/flag-analyser.ts:71 | z.infer<typeof PatternClusterSchema>. Sister PatternClusterSchema is also unused (visible in raw knip output as “Unused exports”) — both never wired. |
| D-2 | PromptRecommendation | type | lib/intelligence/flag-analyser.ts:85 | Same pattern as D-1. |
| D-3 | BatchOptions | type | lib/ingest/markdown-batch-schema.ts:73 | z.infer<typeof BatchOptionsSchema>. Schema IS imported (route.ts:260 calls parseBody(BatchOptionsSchema)); type name is dead. Ambiguous — Phase 0.2.5 B-1/B-2 already flagged the underlying auto_supersede and tag fields as parsed-but-unused. |
| D-4 | PerFileOverride | type | lib/ingest/markdown-batch-schema.ts:75 | Same pattern as D-3. |
| D-5 | BatchWideOptions | type | lib/ingest/markdown-batch-schema.ts:77 | Same pattern as D-3. |
| D-6 | LayerKey | type | lib/client-config.ts:193 | (typeof CLIENT_CONFIG.layer_vocabulary)[number]['key']. Underlying CLIENT_CONFIG IS imported widely; the keyed-type alias is dead. |
| D-7 | TrackedReferenceDoc | type | lib/docs/tracked-reference-docs.ts:29 | (typeof TRACKED_REFERENCE_DOCS)[number]. Const IS imported by __tests__/docs/reference-doc-edit-coupled-freshness.test.ts:19; type alias is dead. |
| D-8 | DedupSupersedeResponse | interface | lib/query/fetchers.ts:529 | Authored as response shape for POST /api/admin/content-dedup/[id]/supersede. Caller (components/admin/content-dedup/content-dedup-action-buttons.tsx:114) uses untyped mutationFetchJson(). Contract was specified at §1.7 admin-dedup-supersede-fix-spec.md §2.9 but never adopted at the consumer. |
| D-9 | VALID_SORT_FIELDS | const | lib/validation/schemas.ts:69 | Declared but no caller; SISTER VALID_REVIEW_STATUSES/VALID_DIGEST_TYPES/VALID_REVIEW_QUEUE_SORTS/TAG_MORPHOLOGY_DECISION_VALUES are correctly used in z.enum(...) calls. Drift detected only on the _SORT_* pair. |
| D-10 | VALID_SORT_ORDERS | const | lib/validation/schemas.ts:76 | Same as D-9. |
| D-11 | IngestUrlBody | type | lib/validation/ingest-schemas.ts:25 | z.infer<typeof IngestUrlBodySchema>. Schema IS imported by app/api/ingest/url/route.ts:12; type alias is dead. |
4.2 DRIFT classification per item
Section titled “4.2 DRIFT classification per item”Per the user’s four-bucket framework:
| # | Item | Class | Rationale | Cross-ref to canonical-pipeline (0.7.1/0.7.3) |
|---|---|---|---|---|
| D-1 | PatternCluster | TRUE-POSITIVE-DEFERRED | Sister PatternClusterSchema is also unused (in raw knip output). Authored for lib/intelligence/flag-analyser.ts but the analyser never composes the cluster type into a public surface. The DEFERRED status is because intelligence flag-analyser has unfinished spec work (per file comments + tests). Action: backlog ticket “blocked by intelligence-pipeline §1.18 productionisation”. | OUT-OF-SCOPE for canonical pipeline. P9 RSS is explicitly excluded from collapse (0.7.1 §1). No effect either way. |
| D-2 | PromptRecommendation | TRUE-POSITIVE-DEFERRED | Same pattern as D-1. | Same as D-1. |
| D-3 | BatchOptions | DRIFT | The schema IS used; the name alias was authored as a TS-side contract but never adopted. Pure naming-hygiene. | If P8 absorbs P6 (0.7.3 §3), the BatchOptions wire shape becomes the canonical document-orchestrator config. The TYPE alias would gain genuine consumers. Conditional on canonical work. |
| D-4 | PerFileOverride | DRIFT | Same as D-3. | Conditional on canonical work — if orchestrateDocumentBatch accepts per-file overrides as a public API, type would be revived. |
| D-5 | BatchWideOptions | DRIFT (FROM 0.2.5 B-1/B-2) | This schema also defines the auto_supersede and tag fields that 0.2.5 B-1/B-2 flagged as parsed-but-unused. The export is dead AND it carries dead fields. Mixed concern. | Conditional. If 0.2.5 fixes wire auto_supersede to the orchestrator, the type and schema get real consumers. If they delete the fields, the type stays dead. |
| D-6 | LayerKey | INTENTIONAL-FALSE-POSITIVE | The type alias (typeof CLIENT_CONFIG.layer_vocabulary)[number]['key'] produces a keyed-string union. It’s authored as a stable type contract for any future layer-aware code. The fact that the const itself is widely imported AND the type alias was authored alongside means it’s prophylactic typing. Keep suppression, ADD comment in config explaining “type aliases over consumed const may have no name-imports”. | No effect. |
| D-7 | TrackedReferenceDoc | INTENTIONAL-FALSE-POSITIVE | Same as D-6 — keyed-string-literal union over a consumed const. | No effect. |
| D-8 | DedupSupersedeResponse | TRUE-POSITIVE-FIX-NOW | Spec §1.7 §2.9 specifies this exact response shape; the callsite (content-dedup-action-buttons.tsx:114) uses untyped fetch. Fixing it brings the contract to the consumer (1-line mutationFetchJson<DedupSupersedeResponse>(...)). Pre-launch quality concern: untyped admin-fetch surface is class-of-bug-for-rename. | OUT-OF-SCOPE for canonical pipeline; admin dedup is its own surface. |
| D-9 | VALID_SORT_FIELDS | TRUE-POSITIVE-FIX-NOW | The 6 VALID_* consts in lib/validation/schemas.ts are siblings; 4 of 6 are correctly consumed by z.enum(...) declarations. The pair _SORT_FIELDS and _SORT_ORDERS are not. Likely either (a) the sort schemas they were authored for were deleted but the const wasn’t, or (b) the sort schema was authored in a sibling file but never wired. Action: delete or wire. | OUT-OF-SCOPE. |
| D-10 | VALID_SORT_ORDERS | TRUE-POSITIVE-FIX-NOW | Same as D-9. | Same. |
| D-11 | IngestUrlBody | DRIFT | Schema IS imported by route.ts. Type alias is dead. Pure naming-hygiene. | Canonical-pipeline relevant — if URL paths P1↔P4 unify (0.7.1 §1), the IngestUrlBody shape becomes the input contract for the unified URL kernel. The alias would have genuine consumers. |
4.3 The 8 CONSUMED items (false-positive classification check)
Section titled “4.3 The 8 CONSUMED items (false-positive classification check)”Quick verification that these eight are correctly suppressed:
| Item | File | Verdict |
|---|---|---|
LayerDefinition | lib/client-config.ts:32 | Correctly imported. False positive without tag → suppression justified. |
BelowThresholdItem | lib/mcp/formatters/briefing.ts:16 | Re-imported by lib/mcp/formatters/index.ts:117 (visible in raw output) — barrel re-export pattern. Suppression justified at the source; barrel re-export shows in raw “Unused exports” though. |
ScoreDropItem | lib/mcp/formatters/briefing.ts:28 | Same as BelowThresholdItem. |
FreshnessTransitionItem | lib/mcp/formatters/briefing.ts:37 | Same. |
QualityFlagNotification | lib/mcp/formatters/briefing.ts:46 | Same. |
CoverageAlertNotification | lib/mcp/formatters/briefing.ts:54 | Same. |
CertificationWarning | lib/mcp/formatters/briefing.ts:61 | Same. |
Workspace | components/item-detail/qa-provenance-sections.tsx:5 | Imported by 6 prod files + 1 test. Suppression justified. |
The mcp/formatters/briefing types form a barrel-re-export pair (briefing.ts → index.ts); the @public tag at SOURCE means the SOURCE is fine, but the BARREL re-export at index.ts:117–123 is NOT @public-tagged and SHOWS up in raw knip output as “Unused exports” / “Unused exported types”. This pair is captured in 0.3 as G-21 (barrel-export hygiene).
4.4 The 41+15 raw findings tolerated by .knip-baseline.json
Section titled “4.4 The 41+15 raw findings tolerated by .knip-baseline.json”Cross-references against 0.3 classifications. None has changed since 5 May 2026:
| 0.3 class | Count | Items |
|---|---|---|
| GENUINE-BUILD-NOT-WIRED | 21 | G-1..G-21 in 0.3 §“Findings classified” — barrel hygiene + sister-helper drift + test-coverage drift. G-6 batch-reclassify P1. |
| INTENTIONAL-RE-EXPORT (queue-handler authoring contracts) | 9 | EnqueueQueueJobArgs/Result, BatchReclassifyResult/AuthContext, BidDraftAllQuestionResult/Result/AuthContext, MarkdownBatchResult/AuthContext. |
| LEGACY-SCAFFOLD (shadcn) | 17 | shadcn/ui re-exports + 1 logger barrel. |
| Unlisted-dep | 3 | @tiptap/core (transitive), node) (parser glitch), pdfjs-dist/build/pdf.worker.min.mjs (transitive). |
4.5 Reclassifications relative to 0.3
Section titled “4.5 Reclassifications relative to 0.3”0.3 findings are directionally still correct, with two refinements:
- 0.3 did not separately audit the 236 @public-tagged sites. It documented the suppression mechanism’s correctness in principle but did not iterate every tag. This audit (§4.1–4.2) extends 0.3 by surfacing the 11 DRIFT items hidden behind @public.
- 0.3 §“Open question 1” (Phase 0.2.5 Pattern C/D errata) stands — Pass 2 entity validation IS reachable via
scripts/backfill-classify-content-items.ts:402. Not a knip finding either way.
Beyond the 11 DRIFT, 0.3’s 21 GENUINE findings hold. Combined with this audit, the ledger is:
| Source | TRUE-POSITIVE-FIX-NOW | TRUE-POSITIVE-DEFERRED | INTENTIONAL-FALSE-POSITIVE | DRIFT |
|---|---|---|---|---|
| 0.3 (baseline-tolerated raw findings) | 1 (G-6) | 14 (G-3..G-21 minus G-6) | 6 (G-1, G-2 schema patterns + 4 cross-cutting) | 0 |
| 0.7.5 (newly @public-suppressed) | 3 (D-8, D-9, D-10) | 2 (D-1, D-2) | 2 (D-6, D-7) | 4 (D-3, D-4, D-5, D-11) |
| Combined | 4 | 16 | 8 | 4 |
The 4 TRUE-POSITIVE-FIX-NOW items: G-6 (test-coverage drift on batch-reclassify); D-8 (admin dedup response untyped); D-9, D-10 (orphaned VALID_SORT_ consts).*
5. Cross-reference: canonical-pipeline collapse
Section titled “5. Cross-reference: canonical-pipeline collapse”The 0.7.1/0.7.3 reframe identifies 4-5 “canonical” kernels (URL core + document core + 3 overlays). Three of the 11 DRIFT items would change classification under canonical-pipeline collapse:
| DRIFT item | Today | Post-canonical-pipeline (P1↔P4 + P6→P8 + P5/P10 absorption) | Action |
|---|---|---|---|
D-3 BatchOptions | DRIFT | CONSUMED — becomes orchestrator-config type for orchestrateDocumentBatch. | Wait for 0.7.3-implementation; will self-resolve. |
D-4 PerFileOverride | DRIFT | CONSUMED — becomes per-file override type for canonical-document core. | Same as D-3. |
D-11 IngestUrlBody | DRIFT | CONSUMED — input contract for unified URL kernel. | Wait for 0.7.1 P1↔P4 merge. |
For D-1, D-2 (intelligence flag-analyser): canonical-pipeline does NOT change classification. P9 RSS is excluded from collapse (0.7.1 verdict). These remain DEFERRED (blocked by intelligence productionisation).
For D-5 BatchWideOptions: depends on whether 0.2.5 B-1/B-2 fixes wire auto_supersede (revives the type) or delete the fields (kills the type). Linked to 0.7.3 §3 absorption planning.
For D-6, D-7 (LayerKey, TrackedReferenceDoc): no canonical-pipeline impact — keyed-string-literal types are infrastructure-shape concerns.
For D-8, D-9, D-10: no canonical-pipeline impact — admin dedup + validation sort consts are out-of-scope.
6. Proposed corrected baseline
Section titled “6. Proposed corrected baseline”Recommended changes (NOT applied in this run; user decision required):
6.1 Action — fix four TRUE-POSITIVE-FIX-NOW items pre-launch
Section titled “6.1 Action — fix four TRUE-POSITIVE-FIX-NOW items pre-launch”These are 5-15 min fixes each. Apply BEFORE re-baselining.
-
G-6 batch-reclassify test-coverage drift (0.3 finding, P1). Delete the duplicated test helpers at
__tests__/api/batch-reclassify.test.ts:44–57; re-import fromlib/queue/handlers/batch-reclassify.ts. NB: the test comment “Constants copied from scripts/batch_reclassify.ts” is misleading — the source is nowlib/queue/handlers/batch-reclassify.ts. -
D-8
DedupSupersedeResponse— type the consumer. Incomponents/admin/content-dedup/content-dedup-action-buttons.tsx:114, changemutationFetchJson(...)tomutationFetchJson<DedupSupersedeResponse>(...). Adds ~2 LoC including import. -
D-9, D-10
VALID_SORT_FIELDS/VALID_SORT_ORDERS— investigate-or-delete. Either (a) delete both consts (they are not zod-enum sources for any current schema), OR (b) wire them into aBrowseSortQuerySchema/LibrarySortQuerySchemaif a future-state list-page sort discipline is anticipated. Recommend (a) given current-launch scope.
6.2 Action — migrate 9 queue-handler types from baseline to @public
Section titled “6.2 Action — migrate 9 queue-handler types from baseline to @public”Currently the 9 types (EnqueueQueueJobArgs/Result, BatchReclassifyResult/AuthContext, BidDraftAllQuestionResult/Result/AuthContext, MarkdownBatchResult/AuthContext) are absorbed by raw counts in .knip-baseline.json. They should be @public-tagged for the same reason every other authoring-contract is — knip docs explicitly endorse this for “library/API surface that no current callsite consumes by name”.
Effect:
- Add
/** @public */to 9 sites. - Re-baseline
.knip-baseline.jsontotypes: 6(currently 15, minus 9 = 6). - The remaining 6 types (
Tab,ExtractedQuestion,ViewMode,LogContext,QualityAction,QualityActionsResult) are barrel-hygiene findings classified by 0.3 — should ALSO be addressed (delete dead barrel re-exports). Could drop further to types: 0-2 in a follow-up.
6.3 Action — migrate 16 shadcn/ui re-exports from baseline to @public
Section titled “6.3 Action — migrate 16 shadcn/ui re-exports from baseline to @public”Per 0.3 LEGACY-SCAFFOLD finding, the 16 shadcn re-exports (AlertDialogPortal, AlertDialogOverlay, badgeVariants, CardFooter, CardAction, DialogClose, DialogOverlay, DialogPortal, DropdownMenuCheckboxItem, DropdownMenuShortcut, DropdownMenuGroup, PopoverAnchor, PopoverHeader, PopoverTitle, PopoverDescription, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SheetClose, tabsListVariants) should be @public-tagged in their respective components/ui/*.tsx files.
Effect:
- Add
/** @public */to ~20 export sites. - Re-baseline
.knip-baseline.jsonexports: 41 → ~21. - Reduces signal-noise in raw knip output dramatically.
6.4 Action — config comment additions (no behavioural change)
Section titled “6.4 Action — config comment additions (no behavioural change)”Add comments to knip.config.ts documenting the @public-tagged “INTENTIONAL-FALSE-POSITIVE” patterns the audit surfaced:
// `tags: ['-public']` semantics:// - Genuine "stable shape" types/interfaces consumed in same file as// function parameter/return types (the dominant pattern — 209 of// 228 @public-tagged exports as of 0.7.5 audit).// - Keyed-string-literal type aliases over already-consumed consts// (e.g. `LayerKey = (typeof CLIENT_CONFIG.layer_vocabulary)[...]`).// The const has consumers; the alias is prophylactic typing.// - Authoring contracts for §5.4 queue handlers (post-0.7.5 should be// @public-tagged directly; baseline absorption deprecated).//// `tags: ['-public']` is NOT for:// - Barrel re-exports — author the @public tag at the SOURCE.// - Schemas backing dead routes — fix the route, not the schema.// - Types whose underlying consumer is itself dead (drift).6.5 Proposed baseline diff
Section titled “6.5 Proposed baseline diff”Current .knip-baseline.json:
{ "counts": { "exports": 41, "types": 15, "unlisted": 3 }}Proposed (after §6.1 + §6.2 + §6.3 are landed):
{ "counts": { "exports": 4, "types": 4, "unlisted": 1 }}Provenance for the new ceiling:
exports: 4— leaves headroom forapplyRequestContextToSentry,rootLoggerOptions,requestContextStorage(logger barrel hygiene per 0.3 G-3/G-4/G-5; deletion is a follow-up sweep) + 1 buffer slot. After deleting those, drop to 0.types: 4— leaves headroom forTab,ExtractedQuestion,LogContext,QualityAction/QualityActionsResultafter the 9 queue-handler types are tagged. After 0.3 §“Recommended hygiene cleanup” #3-#5 lands, drop to 0-2.unlisted: 1—node)is the genuine knip parser glitch (cannot be eliminated without an upstream fix). The other two (@tiptap/core,pdfjs-dist/build/pdf.worker.min.mjs) become explicit devDeps inpackage.jsonper 0.3 unlisted-dep classification.
Trajectory: post-cleanup counts of 0/0/1 (3-finding noise floor) is achievable.
6.6 Proposed knip.config.ts body (no behavioural change, comments added)
Section titled “6.6 Proposed knip.config.ts body (no behavioural change, comments added)”import type { KnipConfig } from 'knip';
const config: KnipConfig = { entry: [ 'app/**/{page,layout,loading,error,not-found,route,proxy}.{ts,tsx}', 'app/**/{default,template}.{ts,tsx}', 'app/api/**/route.ts', 'instrumentation.ts', 'instrumentation-client.ts', 'next.config.ts', 'next.config.{js,mjs}', 'scripts/*.{ts,js}', 'scripts/**/*.{ts,js}', 'lib/mcp/route-handler.ts', 'lib/mcp/server.ts', 'lib/mcp/transport.ts', 'lib/mcp/index.ts', 'lib/mcp/server-factory.ts', 'lib/mcp/registrations.ts', 'lib/mcp/setup-server.ts', 'lib/mcp/handler.ts', 'lib/mcp/resources.ts', 'vitest.config.ts', 'vitest.config.{ts,mts}', 'playwright.config.ts', 'tailwind.config.{ts,js}', 'postcss.config.{ts,js,mjs}', 'drizzle.config.ts', // Tailwind v4 CSS-first plugin activation: globals.css is the entry // for CSS-loaded deps (`@plugin`, `@import`). See `syncCompilers.css` below. 'app/globals.css', ], project: [ 'app/**/*.{ts,tsx}', 'components/**/*.{ts,tsx}', 'contexts/**/*.{ts,tsx}', 'hooks/**/*.{ts,tsx}', 'lib/**/*.{ts,tsx}', 'types/**/*.{ts,tsx}', 'scripts/**/*.{ts,tsx}', 'instrumentation*.{ts,tsx}', 'proxy.ts', // Tailwind v4 CSS-first plugin activation — see `syncCompilers.css` below. 'app/globals.css', ], ignore: [ '.next/**', 'node_modules/**', 'mcp-apps/*/dist/**', 'mcp-apps/*/node_modules/**', 'supabase/types/**', 'supabase/.temp/**', 'playwright-report/**', 'test-results/**', '.claude/**', 'docs/**', '.planning/**', '**/*.d.ts', ], ignoreDependencies: [ '@types/node', '@types/react', '@types/react-dom', '@vitest/coverage-v8', 'tsx', 'tailwindcss', '@tailwindcss/postcss', 'autoprefixer', 'postcss', ], // `tags: ['-public']` — exports tagged `@public` in JSDoc are ignored. // // Legitimate categories (audit ratified 0.7.5): // 1. Function parameter/return types consumed in same file — the // exported NAME is dead-imported, but the function signature using // it IS consumed. Dominant pattern (209 of 228 sites as of 0.7.5). // 2. Keyed-string-literal type aliases over already-consumed consts // (e.g. `LayerKey = (typeof CLIENT_CONFIG.layer_vocabulary)[...]`). // The const has consumers; the alias is prophylactic typing. // 3. Authoring contracts for §5.4 queue handlers (Result/AuthContext // types kept in lockstep with the dispatch.ts unknown-cast comment). // // NOT for: // - Barrel re-exports — author the @public tag at the SOURCE. // - Schemas backing dead routes — fix the route, not the schema. // - Types whose underlying consumer is itself dead (drift). // // Audit cadence: re-run 0.7.5 every quarter or after any cluster of // ingest-pipeline rewrites. The methodology + script live at // `/tmp/claude/check-imports3.sh` (audit-time only; not committed). // Per knip docs: https://knip.dev/reference/configuration#tags tags: ['-public'], // Tailwind v4 CSS-first plugin activation: knip can't see `@plugin "..."` // directives in globals.css natively, so we synthesise virtual JS imports // from `@plugin` and `@import` directives. This lets knip detect deps like // `@tailwindcss/typography` that v4 loads via CSS rather than a JS config // file. Pattern: https://www.jimmy.codes/blog/fix-knip-false-positives-tailwindcss-v4 // Using `syncCompilers` (not `compilers`) — knip 6.x ConfigurationChief // only reads syncCompilers/asyncCompilers despite the schema accepting both. syncCompilers: { css: (text: string) => { const directives = [ ...text.matchAll(/@(?:plugin|import)\s+["']([^"']+)["']/g), ]; return directives.map(([, dep]) => `import "${dep}";`).join('\n'); }, }, vitest: { config: 'vitest.config.ts', entry: ['__tests__/**/*.{test,spec}.{ts,tsx}'], }, playwright: { config: 'playwright.config.ts', entry: ['e2e/tests/**/*.spec.ts'], },};
export default config;The diff vs current config:
- Lines 71–79 (the
tagscomment block) replaced with the longer audit-ratified version above. - No structural changes to
entry/project/ignore/ignoreDependencies/syncCompilers/vitest/playwright. - No new suppressions added.
7. Backlog tickets — TRUE-POSITIVE-DEFERRED items
Section titled “7. Backlog tickets — TRUE-POSITIVE-DEFERRED items”The 16 DEFERRED items are not pre-launch fixes but should each get a ticket explicitly noting their blocker:
| Ticket | Item | Blocked by |
|---|---|---|
| BL-K1 | G-3 logger barrel applyRequestContextToSentry dead barrel re-export | lib/logger/index.ts cleanup pass |
| BL-K2 | G-4 rootLoggerOptions only-used-internally export | Same |
| BL-K3 | G-5 requestContextStorage only-used-internally export | Same |
| BL-K4 | G-7 computeGapSummary no production caller | Coverage refactor or delete |
| BL-K5 | G-8 resetGlobalRateLimiter no test caller | Either wire test-cleanup or delete |
| BL-K6 | G-9 HTML_CONTENT_TYPES test duplication | Test sweep — import constants don’t redeclare |
| BL-K7 | G-10 HEADING_PATTERNS internal-only | Delete export |
| BL-K8 | G-11 COOPERATIVELY_CANCELLABLE_JOB_TYPES test comment-only | Same as BL-K6 |
| BL-K9 | G-12 DEDUP_MIN_CONTENT_LENGTH test comment-only | Same as BL-K6 |
| BL-K10 | G-13 unauthorisedResponse only-used-internally | Delete export |
| BL-K11 | G-14 useCompanyProfile (singular) sister-helper | Verify company-profile feature wiring (0.2a/0.2b cross-ref) |
| BL-K12 | G-15 getContentTypeIcon sister-helper | Delete or revive |
| BL-K13 | G-16 getWorkspaceIcon sister-helper | Same |
| BL-K14 | G-17 WorkspaceBadge dead component | Verify if /workspace UI surface intends to render |
| BL-K15 | G-18 Tab, ExtractedQuestion re-export | Delete |
| BL-K16 | G-19 ViewMode shadowed type | Reconcile with filter-bar.ViewMode |
| BL-K17 | G-20 LogContext barrel re-export | Same as BL-K1 |
| BL-K18 | G-21 QualityAction/QualityActionsResult re-export | Delete |
| BL-K19 | D-1, D-2 PatternCluster/PromptRecommendation | Intelligence flag-analyser productionisation (§1.18) |
| BL-K20 | D-3, D-4, D-11 BatchOptions/PerFileOverride/IngestUrlBody | Canonical-pipeline collapse (0.7.1/0.7.3) — will self-resolve |
| BL-K21 | D-5 BatchWideOptions | 0.2.5 B-1/B-2 fix decision (wire vs delete) |
8. Confidence assessment
Section titled “8. Confidence assessment”| Finding bucket | Confidence | Floor cause |
|---|---|---|
| Current config justification (§2) | 95% | Config matches knip 6.3 docs; mechanisms understood end-to-end. |
| Baseline knip output stats (§3) | 100% | Captured live; matches .knip-baseline.json ceiling exactly. |
| 209 INTERNAL-CONTRACT classification (§4.1) | 90% | Verified by spot-check of 12 representative sites; all 12 had functions consuming the type as parameter/return; sample-size confidence. |
| 11 DRIFT items (§4.2) | 85% | Verified each; D-1/D-2/FileUploadState may have planned-future consumers I didn’t surface (intelligence productionisation roadmap; 0.5 EP2 spec impact §“future”). |
| Cross-ref to canonical-pipeline (§5) | 85% | Depends on 0.7.1/0.7.3 implementation choices that haven’t landed. |
| TRUE-POSITIVE-FIX-NOW count (4) | 95% | Hard-verified each; G-6 already documented in 0.3 P1; D-8/D-9/D-10 newly surfaced. |
| Proposed baseline ceiling (§6.5) | 85% | Achievable but requires the 16 shadcn + 9 queue-handler @public-tag migrations; not all changes can be ratified in one PR. |
| Backlog ticket list (§7) | 90% | Each ticket directly traces to an audit finding (0.3 or 0.7.5). |
| Overall | 88% | Below 90% — three DEFERRED-vs-DRIFT classifications (D-1, D-2, BatchWideOptions D-5) hinge on intelligence/EP2 productionisation choices outside this audit’s scope. |
9. Open questions for parent session
Section titled “9. Open questions for parent session”-
Knip CLI tag-override flag-format.
--tags=+@publicand--tags=-@publicdid not produce the expected behaviour (CLI accepted both flags but output was identical to default config). Either knip 6.3.0 has an undocumented CLI flag-format change, ortags: ['-public']in the config takes priority over CLI overrides. Workaround used was manual classification of all 236 sites. Confidence on suppressed-item count (236) is 100%; confidence on individual-site classification is 85% (script-driven, verified spot-checks). Recommend: file knip upstream issue if CLI flag is documented but inert. -
Should D-3/D-4/D-11 be deferred to canonical-pipeline collapse OR fixed pre-launch? All three are dead TYPE aliases over imported schemas. Pre-launch fix is one line per type (delete the alias). Post-canonical-pipeline they become consumed. Recommendation: defer — deletion is reversible, and waiting saves authoring churn.
-
useCompanyProfile(singular, G-14) — is the company-profile feature wired anywhere? Sister hookuseCompanyProfiles(plural) IS imported. 0.2b side-tables audit may have already established whethercompany_profilestable has any writers. If feature is dead, delete both hook AND sisteruseCompanyProfiles. If feature is live, either restore the singular hook or delete it. Cross-ref: 0.2b side-tables audit,company_profilesrow. -
VALID_SORT_FIELDS / VALID_SORT_ORDERS (D-9, D-10) — investigate-or-delete? Confidence is 95% they are orphans. Worth a 5-min
git log -G VALID_SORT_FIELDSto see if they were authored alongside a deleted sort schema. -
Knip parser glitch on
setup.ts:57:76(node)token). Same concern as 0.3 §7. Cosmetic only. Locally muted via baseline; upstream issue still warranted but P3.
10. Summary
Section titled “10. Summary”| Bucket | Count | Notable |
|---|---|---|
| Currently suppressed via @public | 236 | 209 INTERNAL-CONTRACT (legit) + 8 CONSUMED (legit) + 11 DRIFT (audit catches) |
| Currently suppressed via baseline counts | 59 (41+15+3) | 21 GENUINE-BUILD-NOT-WIRED (per 0.3) + 9 INTENTIONAL-RE-EXPORT + 17 LEGACY-SCAFFOLD + others |
| TRUE-POSITIVE-FIX-NOW | 4 | G-6 (test-coverage drift), D-8 (DedupSupersedeResponse untyped), D-9, D-10 (orphan VALID_SORT_*) |
| TRUE-POSITIVE-DEFERRED | 16 | Cleanup-eligible; 0.3 G-* + 0.7.5 D-1/D-2/D-5 |
| INTENTIONAL-FALSE-POSITIVE | 8 | Legitimate stable-shape contracts; tag system is correct mechanism |
| DRIFT (will self-resolve under canonical-pipeline) | 4 | D-3, D-4, D-5, D-11 if 0.7.1/0.7.3 lands |