Project

General

Profile

Feature #3248 » W13_gate_dead_code-oms-ui-bug-fx.txt

Bot AI, 08/30/2026 03:46 PM

 
================================================================================
Gate 3a — Dead Code
Node: W13_gate_dead_code
Ticket: #3248 (oms-ui-ux-and-functional)
Branch: feat/3248-oms-ui-ux-and-functional
Repo: cross-repo-orchestration/oms-web (Next.js 14 App Router / Tailwind)
Result: PASS — 0 items removed
================================================================================

SUMMARY
-------
55 entries in sides.web.feature_files were scanned across the 7 in-scope
dead-code categories. No provably dead code was found, so nothing was removed.

Five items are REPORTED (not deleted) under the node instruction "report what
you are unsure about instead of deleting it" and the gate's Step 2 "report,
don't delete" rules: one redundant export modifier, two design tokens carried
over from #3247 with zero current call sites, one component variant reachable
only from tests, one unused barrel file, and the two pre-existing orphaned
schema column groups this gate has flagged on every prior ticket.

The tree is byte-for-byte unchanged by this gate apart from this evidence file
(`git diff --stat` empty; `git status` shows only untracked gate-evidence files
from W11/W12 and this one).


FILES SCANNED (55, verbatim from sides.web.feature_files)
---------------------------------------------------------
All 55 paths were confirmed to exist on disk (0 missing).

app/admin/items/[id]/edit/page.tsx app/admin/uom/[id]/edit/page.tsx
app/admin/items/[id]/page.tsx app/admin/uom/[id]/page.tsx
app/admin/items/new/page.tsx app/admin/uom/new/page.tsx
app/admin/items/page.tsx app/admin/uom/page.tsx
app/admin/projects/[id]/edit/page.tsx app/admin/users/[id]/edit/page.tsx
app/admin/projects/[id]/page.tsx app/admin/users/[id]/page.tsx
app/admin/projects/new/page.tsx app/admin/users/new/page.tsx
app/admin/projects/page.tsx app/admin/users/page.tsx
app/admin/suppliers/[id]/edit/page.tsx app/expense-summary/[project]/page.tsx
app/admin/suppliers/[id]/page.tsx app/expense-summary/page.tsx
app/admin/suppliers/new/page.tsx app/expenses/ExpenseRowActions.tsx
app/admin/suppliers/page.tsx app/expenses/[id]/edit/page.tsx
app/expenses/new/page.tsx app/expenses/page.tsx
app/orders/OrderRowActions.tsx app/orders/[id]/page.tsx
app/orders/new/page.tsx app/orders/page.tsx
components/forms/ExpenseForm.tsx components/forms/ItemForm.tsx
components/forms/OrderForm.tsx components/forms/OrderFulfillmentForm.tsx
components/forms/ProjectForm.tsx components/forms/SupplierForm.tsx
components/forms/UomForm.tsx components/forms/UserForm.tsx
components/ui/DataTable.tsx components/ui/FilterBar.tsx
components/ui/ListToolbar.tsx components/ui/QuickCreateModal.tsx
components/ui/RowActions.tsx components/ui/StatusBadge.tsx
components/ui/fields/SelectField.tsx components/ui/fields/TextField.tsx
components/ui/icons/SortIcon.tsx tailwind.config.ts
docs/design/oms-screens-standalone.html docs/design/users-screens-standalone.html
docs/specs/ticket-3248-design.md
tests/admin-items-page.test.tsx tests/admin-users-page.test.tsx
tests/expenses-page.test.tsx tests/item-form.test.tsx
tests/quick-create-modal.test.tsx

The three docs/ entries (2 design HTML bundles + 1 spec markdown) are reference
inputs, not compiled sources — no export/import/route/schema surface, so
categories 1-2 and 4-6 do not apply to them. They were checked for category 3
and 7 only (see CHECK 3 / CHECK 7).


================================================================================
CHECK 1 — Unused imports / unused local declarations
================================================================================
Method: compiler-authoritative, not grep.

$ npx tsc --noEmit --noUnusedLocals --noUnusedParameters \
--incremental false -p tsconfig.json
(no output) EXIT=0

Detector sanity-check (proving the flags were live and not silently satisfied
by a stale incremental cache) — a throwaway unused const was appended to
lib/params.ts and the same command re-run:

lib/params.ts(67,7): error TS6133: '__deadcheck' is declared but its value
is never read.

Reverted immediately via `git checkout lib/params.ts`; `git diff --stat
lib/params.ts` confirms the file is unmodified.

tsconfig.json's `include` is `**/*.ts` / `**/*.tsx`, so this pass covers app/,
components/, lib/, tests/, middleware.ts and prisma/ — a strict superset of the
52 compiled feature files.

RESULT: 0 unused imports, 0 unused locals, 0 unused parameters.


================================================================================
CHECK 2 — Exported symbols never imported elsewhere
================================================================================
Every top-level `export` in the 52 compiled feature files was enumerated, then
cross-referenced against app/, components/, lib/, tests/, middleware.ts and
prisma/. Tests were included deliberately — the gate forbids deleting anything
referenced only by a test.

symbol refs referencing files
---------------------- ---- ---------------------------------------------
ExpenseRowActions 8 self, app/expenses/page.tsx, test
OrderRowActions 6 self, app/orders/page.tsx, test
ExpenseForm 37 7 files
ItemForm 46 14 files
OrderForm 28 7 files
OrderFulfillmentForm 27 6 files
ProjectForm 39 10 files
SupplierForm 44 15 files
UomForm 38 10 files
UserForm 35 8 files
Column (type) 22 11 files
DataTable 30 13 files
FilterField (type) 6 self, ListToolbar.tsx, test
FilterBar 17 5 files
ListToolbar 28 12 files
QuickCreateModal 25 12 files
RowActions 35 14 files
StatusBadge 25 10 files
SelectField 13 self, Listbox.tsx, FilterBar.tsx, test
TextField 32 8 files
SortIcon 9 self, DataTable.tsx, test
StatusBadgeVariant (type) 2 self only <-- see REPORTED #1

Framework-contract exports (Next.js resolves these by convention, never by
import, so a zero-importer count is expected and correct):
- `export default` in all 30 page.tsx files
- `export const metadata` in 26 page.tsx files
- `export async function generateMetadata` in app/expense-summary/[project]/
page.tsx and app/orders/[id]/page.tsx
- `export default config` in tailwind.config.ts (read by tailwindcss/postcss)

RESULT: 0 dead exports removed. 1 redundant export modifier reported.


================================================================================
CHECK 3 — Commented-out code blocks (>3 lines)
================================================================================
Searched app/, components/, lib/ for runs of `//`-prefixed lines opening with a
code token (const|let|var|function|return|import|export|if|<|{|}):

lib/actions/expenses.ts:31 "// constraint requires exists by construction..."
lib/permissions/ui.ts:15 "// import this file — it pulls in Prisma..."
lib/auth/password.ts:5 "// constraint so the same code works in both..."

All three are prose sentences that happen to begin with a keyword-like word;
none is commented-out code. None is in a feature file.

Separately checked, and NOT counted as commented-out code:
- prisma/schema.prisma lines 112-119 — the 8-line comment block replacing the
dropped `Item.modelNo` field. This is a deliberate tombstone recording the
W03_schema_review C1 tier ruling (and explicitly warning that Uom.symbol /
Supplier.supplierNo are gated on a pg_dump confirmation that has NOT landed).
It is documentation of a removal, not dormant code awaiting re-enablement.
- docs/design/*.html — reference design bundles; HTML comments in a vendored
design artifact are not this repo's source.

RESULT: 0 commented-out blocks.


================================================================================
CHECK 4 — Dead barrel (index.ts) re-exports
================================================================================
The repo has exactly one barrel: lib/permissions/index.ts (not in feature_files).

export * from "./registry"; -> lib/permissions/registry.ts EXISTS
export * from "./evaluate"; -> lib/permissions/evaluate.ts EXISTS
export * from "./guard"; -> lib/permissions/guard.ts EXISTS

The gate defines a dead barrel entry as a re-export "pointing at deleted/renamed
files". All three targets exist, so there is no dead entry to remove.

REPORTED #4 (unchanged from the #3247 run): the barrel file itself has zero
importers — every consumer imports the submodule directly. Deleting the whole
file is a public-API decision about a module this ticket did not touch.

RESULT: 0 barrel entries removed.


================================================================================
CHECK 5 — Orphaned App Router segments
================================================================================
All 33 route files under app/ were enumerated, then every route in feature_files
was matched against static hrefs, template-literal hrefs, redirect()/
router.push() targets, and the permission-filtered nav table in lib/nav.ts.

route family literals found in source
------------------ --------------------------------------------------------
/admin/items "/admin/items", "/admin/items/new",
`/admin/items/${id}`, `/admin/items/${id}/edit`,
`/admin/items?${p.toString()}`
/admin/projects same five shapes
/admin/suppliers same five shapes
/admin/uom same five shapes
/admin/users same five shapes
/expense-summary "/expense-summary", `/expense-summary/${r.projectId}`,
`/expense-summary/${routeParams.project}?...`
/expenses "/expenses", "/expenses/new", `/expenses/${id}/edit`
/orders "/orders", "/orders/new", `/orders/${id}`,
`/orders/${orderId}`, `/orders/${r.id}`

Every one of the 30 feature-file route segments — including all five newly-added
`[id]` view pages and all five `[id]/edit` pages per master, plus
app/orders/[id]/page.tsx — is reached by at least one link or nav entry.

Side observation (NOT a dead-code finding, no action taken): lib/actions/
expenses.ts:98 calls `revalidatePath("/expenses/${id}")`, but there is no
app/expenses/[id]/page.tsx — Expenses has an edit route only, as
ExpenseRowActions.tsx's own comment states. A revalidatePath against a
non-existent path is a harmless no-op, and lib/actions/expenses.ts is not in
feature_files. Recorded here so it isn't lost, not fixed by this gate.

RESULT: 0 orphaned route segments.


================================================================================
CHECK 6 — Unused Prisma schema models / fields
================================================================================
Scoped first to what THIS ticket changed (git diff c9e1fbf..HEAD -- prisma/):

prisma/schema.prisma 10 +/-
migrations/20260830060000_remove_item_modelno/ 19 +
prisma/seed.ts 4 +/-

This ticket ADDS no schema field. Its only schema change is a REMOVAL —
`Item.modelNo` (ticket #3248 req 14) — i.e. this ticket already deleted the one
piece of orphaned schema in its own scope, with a migration, before this gate
ran. Verified there is no stranded reference to it:

$ grep -rn modelNo app components lib tests prisma
tests/schemas.test.ts:100-103 regression test asserting itemSchema no longer
carries modelNo (intentional, keep)
migrations/20260825145455_oms/migration.sql:53 original CREATE (history)
migrations/20260830060000_remove_item_modelno/* this ticket's DROP + its
documented rollback note

No app/ or components/ reference remains, and `tsc --noEmit` is clean — a
leftover `item.modelNo` read would be a compile error, not a silent survivor.

Earlier-branch fields (User.mobile, Attachment.updatedAt @default, Role
@@unique([id, userType]), User's composite role FK, the two User indexes) were
re-verified as still fully wired by lib/queries/users.ts, lib/validation/
schemas.ts, components/forms/UserForm.tsx and app/admin/users/page.tsx.

REPORTED #5 (pre-existing, NOT added or touched by this ticket, NOT removed):
Expense.approvedBy (String?)
Expense.approvedAt (DateTime?)
Expense.approvedById (String?)
Expense.approvedByUser (relation)

Zero references outside prisma/schema.prisma, the migration SQL, and prior
gate-evidence write-ups. Not removed, on two independent grounds:
(a) the gate's Step 2 states outright that deleting a schema field is a
migration decision this gate does not make unilaterally; and
(b) the schema documents the intent — the legacy free-text approver kept
alongside the newer approvedById FK until a follow-up migration
backfills a human-decided name->user mapping.
Consistent with how this ticket's own author handled the analogous case: the
modelNo tombstone comment explicitly refuses to drop Uom.symbol /
Supplier.supplierNo until a pg_dump of every populated environment is
confirmed. This repo's convention is that an unread column is evidence to
gather, not licence to drop.

Per the gate's PASS rule, a reported-but-unremoved schema field does not block
PASS.

RESULT: 0 schema fields removed by this gate; 4 reported.


================================================================================
CHECK 7 — TODO / FIXME markers (report, do not remove)
================================================================================
$ grep -rnE 'TODO|FIXME|XXX|HACK' --include='*.ts' --include='*.tsx' \
--include='*.css' app components lib tests
(none)

RESULT: 0 incomplete-implementation markers.


================================================================================
CHECK 8 — Duplicate components / orphaned component chains / dead styles
================================================================================
Importer fan-in was computed for all 41 non-route .tsx files, counting src/ and
tests/ referrers separately so a component alive only in tests would stand out:

src=1 ExpenseRowActions, OrderRowActions, SortIcon, ItemRowActions,
ProjectRowActions, SupplierRowActions, UomRowActions, UserRowActions
src=2 LogoutButton, DeleteConfirmModal, RepeaterTable, SelectField,
Sidebar, ConfirmModal
src=3+ everything else (max: PageHeader at 29)

Minimum src fan-in across the whole component tree = 1. No component has zero
src referrers, so nothing is alive only in tests and nothing is transitively
dead. Each src=1 case was traced to a live route:
ExpenseRowActions -> app/expenses/page.tsx LIVE
OrderRowActions -> app/orders/page.tsx LIVE
SortIcon -> DataTable -> 8 list pages LIVE
*RowActions (5) -> their own master list page LIVE

Duplicate definitions:
$ find app components -name '*.tsx' | xargs -n1 basename | sort | uniq -d
page.tsx (App Router convention — one per segment, not a duplicate)
$ duplicated exported function names across files
generateMetadata (Next.js convention export, one per dynamic segment)
No component is defined twice. No near-duplicate pair: SelectField wraps
Listbox rather than re-implementing it, and FilterBar composes Listbox +
DatePicker rather than forking them.

app/globals.css — all 10 component classes are referenced from TSX:
.btn 28, .btn-primary 12, .btn-secondary 16, .btn-danger 1, .field-input 12,
.field-control 2, .field-label 15, .field-error 21, .card 8, .link 18
No dead CSS rules.

tailwind.config.ts design tokens — every token this ticket ADDED is wired:
text.subtle 6 uses (filter labels, order-detail info labels)
text.helper 1 use ExpenseForm.tsx:170 attachment empty state
border.dashed 1 use ExpenseForm.tsx:170 (`border-border-dashed`;
no collision with Tailwind's built-in
`border-dashed` style utility, which the same
className also uses, correctly)
status.success 3 uses (changed value, not a new key)
status.successSubtle 1 use StatusBadge.tsx:22 PILL_CLASSES.success
Two tokens inherited from #3247 have zero uses — see REPORTED #2.

REPORTED #3 / carried forward: EXPENSE_TYPE_OPTIONS and MAX_UPLOAD_BYTES are
still duplicated verbatim across live files (app/expense-summary/[project]/
page.tsx:11 + components/forms/ExpenseForm.tsx:36; ExpenseForm.tsx:46 +
OrderFulfillmentForm.tsx:37). Both copies of each are USED, so neither is dead
code — de-duplicating means creating a new shared module, which is a DRY
refactor and explicitly outside this gate's whitelist.

RESULT: 0 duplicate components removed, 0 dead style rules.


================================================================================
REPORTED — NOT REMOVED (5 items)
================================================================================
1. components/ui/StatusBadge.tsx:45 — `export type StatusBadgeVariant`
Imported by nothing outside the file, but genuinely referenced in-file at
line 65 as StatusBadge's `variant?:` prop type. Only the `export` keyword is
redundant. The symbol is not dead, and dropping `export` would narrow the
public prop-type surface of an exported component for zero dead-code
benefit. UNSURE -> reported. (Same finding as the #3247 run; line moved
41 -> 45.)

2. tailwind.config.ts — `accent.subtleHover` (#f0e8dc) and `accent.selected`
(#e2cdb0): zero references anywhere in app/, components/, lib/ or tests/,
as `accent-subtleHover`/`accent-selected` classes or as raw hex.
NOT removed, deliberately:
- Both were added by ticket #3247 from its design spec's unmapped-token
list, for surfaces that do not exist yet (a selected tab-pill segment;
a secondary/Cancel hover fill — .btn-secondary currently hovers to
accent.subtle, not accent.subtleHover). This is the design-token
analogue of the gate's own "a schema field may be intentionally added
ahead of the code that will use it next ticket" carve-out.
- An unused theme key is inert: Tailwind's JIT emits classes by scanning
`content`, so an unreferenced token generates no CSS. There is no
bundle-size or runtime cost to recover by deleting it.
- Deleting a measured design token is a design-system decision, and both
predate this ticket.
UNSURE -> reported, per the node instruction. Flagging for whoever owns the
token set: either wire them or retire them in a dedicated pass.

3. StatusBadge's `"pill"` variant (the default branch + the PILL_CLASSES table
at StatusBadge.tsx:19-27) has no application call site — all 8 in-app
`<StatusBadge>` usages pass variant="plain" (5 masters + Users),
variant="dot" (Orders list + OrderFulfillmentForm) or variant="text"
(Expenses). It is exercised only by tests/StatusBadge.test.tsx, which
renders the default. NOT removed: the gate states outright "Do NOT remove
anything referenced only by test files", and it is also the documented
fallback for any future caller not covered by #3247's finding F1.
Consequence worth noting: status.successSubtle (added this ticket) is
likewise reachable only through that pill path today.

4. lib/permissions/index.ts — barrel file with zero importers. All three
re-export targets exist, so this is NOT a "dead barrel entry" as the gate
defines it, and the file is not in feature_files. Reported only.

5. Expense.approvedBy / approvedAt / approvedById / approvedByUser — orphaned
columns. See CHECK 6. Removal is a migration; out of this gate's authority.


================================================================================
REMOVED (0 items)
================================================================================
Nothing was removed. No finding in any of the 7 categories was provably dead.

Worth stating plainly, since a zero-removal result can read as a gate that
didn't look: this ticket's own author had already performed the one real
deletion in scope — Item.modelNo, dropped with a migration, a rollback note, a
regression test, and the dependent `required` attribute in ItemForm.tsx
corrected. CHECK 6 verified that removal is complete and leaves no stranded
reference, rather than re-finding it.


================================================================================
POST-GATE VERIFICATION
================================================================================
$ git diff --stat (empty — no tracked file modified)
$ git status --short only untracked docs/gate-evidence/
W11/W12 files from the preceding gates,
plus this file
$ npx tsc --noEmit -p tsconfig.json EXIT=0
$ npx next lint ✔ No ESLint warnings or errors
$ npx vitest run Test Files 86 passed (86)
Tests 630 passed (630)

GATE STATUS: PASS
================================================================================
(4-4/8)