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