|
================================================================================
|
|
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
|
|
================================================================================
|