================================================================================
Gate 3a — Dead Code
Node:      W13_gate_dead_code
Ticket:    #3250 (oms-bug-fixes / chips + summary)
Repo:      oms-web
Branch:    feat/3250-oms-ui-bug-fixes-chips-s
Result:    PASS  (0 items removed — no provably-dead code found in scope)
================================================================================

SCOPE — files scanned (sides.web.feature_files, 12 files)
--------------------------------------------------------------------------------
  1. app/(app)/admin/items/page.tsx
  2. app/(app)/admin/projects/page.tsx
  3. app/(app)/admin/suppliers/page.tsx
  4. app/(app)/admin/uom/page.tsx
  5. app/(app)/admin/users/page.tsx
  6. app/(app)/expense-summary/[project]/page.tsx
  7. app/(app)/expense-summary/page.tsx
  8. app/(app)/expense-summary/ExpenseSummaryRowActions.tsx
  9. app/(app)/expenses/page.tsx
 10. app/(app)/orders/page.tsx
 11. components/forms/ExpenseForm.tsx
 12. components/forms/ResetPasswordForm.tsx

METHOD
--------------------------------------------------------------------------------
  * Full read of all 12 files (no sampling).
  * eslint @typescript-eslint/no-unused-vars over all 12 files
    (args:all, argsIgnorePattern ^_, varsIgnorePattern ^_).
  * npx tsc --noEmit -p tsconfig.json  (whole project).
  * Cross-repo grep for every exported symbol across app/, components/,
    lib/, tests/ — test files INCLUDED before considering any deletion.
  * Route-reachability grep for each App Router segment in scope
    (lib/nav.ts, lib/permissions/registry.ts, <Link>, router.push).
  * Barrel scan: find app components lib -name "index.ts*".
  * git diff main...HEAD -- prisma/  for schema fields added by this ticket.
  * Comment scan for commented-out code blocks and TODO/FIXME/XXX/HACK.

--------------------------------------------------------------------------------
STEP 1 RESULTS
--------------------------------------------------------------------------------

[1] UNUSED EXPORTS ......................................................... 0

    Every exported symbol in scope has at least one non-test importer:

      ExpenseSummaryRowActions  -> app/(app)/expense-summary/page.tsx:7,26
                                   (+ tests/expense-summary-row-actions.test.tsx)
      ResetPasswordForm         -> app/(app)/profile/reset-password/page.tsx:3,13
                                   (+ tests/reset-password-form.test.tsx,
                                      tests/profile-reset-password-page.test.tsx)
      ExpenseForm               -> app/(app)/expenses/new/page.tsx:2,13
                                   app/(app)/expenses/[id]/edit/page.tsx:5,16
                                   (+ tests/expense-form.test.tsx,
                                      tests/expenses-new-edit-pages.test.tsx)
      generateMetadata          -> Next.js App Router convention export
                                   (app/(app)/expense-summary/[project]/page.tsx:21)
      metadata / default export -> Next.js App Router convention exports
                                   (all 8 page.tsx files in scope)

[2] UNUSED IMPORTS / UNREFERENCED LOCALS ................................... 0

    eslint no-unused-vars output over all 12 files:

      components/forms/ResetPasswordForm.tsx
        111:5  error  Definition for rule 'react-hooks/exhaustive-deps' was not
                      found  react-hooks/exhaustive-deps
      1 problem (1 error, 0 warnings)

    NOT a finding. That is an artifact of the ad-hoc --no-eslintrc config used
    for this scan (the react-hooks plugin was not loaded, so the file's own
    inline eslint-disable comment on line 111 had no rule to resolve). Zero
    no-unused-vars violations were reported. The repo's real lint config
    already passed in W12 (docs/gate-evidence/W12_gate_lint-oms-bug-fixes.txt).

    `npx tsc --noEmit` over the whole project: clean, no output.

[3] COMMENTED-OUT CODE BLOCKS (>3 lines) ................................... 0

    Per-file count of code-shaped comment lines (^\s*//.*[;{}()=]\s*$):
      all 12 files: 0

    All block comments in scope are prose rationale tied to a spec reference
    (ticket #3247/#3248/#3250 notes, TB-OMS-SRS-UP-001 §10.1, SCR-014), not
    disabled code. Retained deliberately.

[4] DEAD BARREL ENTRIES .................................................... 0

    Only one barrel exists under app/ components/ lib/:

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

    No re-export points at a deleted or renamed file, so there is no dead
    barrel entry to remove. See OBSERVATIONS #2 below for a related, separate
    note about this file that is deliberately NOT actioned here.

[5] ORPHANED ROUTE SEGMENTS ................................................ 0

    /expense-summary
        reachable: lib/nav.ts:40 sidebar entry
                   { href: "/expense-summary", label: "Expense Summary",
                     icon: "BarChart3", permission: "expense_summary:read" }
        guarded:   lib/permissions/registry.ts:111

    /expense-summary/[project]
        reachable: app/(app)/expense-summary/ExpenseSummaryRowActions.tsx:9
                   <Link href={`/expense-summary/${projectId}`}>
                   rendered from the Actions column of the parent list
                   (app/(app)/expense-summary/page.tsx:26)
        guarded:   lib/permissions/registry.ts:111 (/^\/expense-summary(\/.*)?$/)

    /admin/items, /admin/projects, /admin/suppliers, /admin/uom, /admin/users,
    /expenses, /orders
        all pre-existing sidebar routes in lib/nav.ts; unchanged by this ticket.

[6] UNUSED PRISMA SCHEMA FIELDS / MODELS ................................... 0

    git diff main...HEAD -- prisma/  =>  empty.
    This ticket introduces no schema change, so there is no shipped-but-unused
    field to report. (Had there been one it would be reported, not deleted —
    dropping a field is a migration decision, not this gate's.)

[7] TODO / FIXME / XXX / HACK MARKERS ...................................... 0

    grep over all 12 files: none.

--------------------------------------------------------------------------------
STEP 2 — REMOVALS
--------------------------------------------------------------------------------

NOTHING REMOVED. No file in this checkout was modified by this gate.

Every candidate examined was traced to a live reference before being ruled out.
No symbol was deleted on the strength of "no importer found in app/ or
components/" alone — tests/ was searched too in every case, per the gate's own
rule that test-only references still count as live.

--------------------------------------------------------------------------------
OBSERVATIONS — reported, deliberately NOT auto-fixed
--------------------------------------------------------------------------------

#1  STALE TEST ASSERTION (pre-existing failure, NOT dead code)
    tests/expense-summary-page.test.tsx:29

      expect(screen.getByText("View Details")).toHaveAttribute(
        "href", "/expense-summary/p1");

    This assertion fails. Confirmed by running it:

      npx vitest run tests/expense-summary-page.test.tsx \
                     tests/expense-summary-row-actions.test.tsx
      Test Files  1 failed | 1 passed (2)
      Tests       1 failed | 4 passed (5)
      TestingLibraryElementError at tests/expense-summary-page.test.tsx:29:19

    Cause: ticket #3250 R5 replaced the old text link with an icon-only
    control. ExpenseSummaryRowActions.tsx:9 renders a <Link> whose accessible
    name is aria-label="View Expense Summary" wrapping an <Eye> icon — there is
    no "View Details" text node in the tree any more. The href itself is
    correct; only the query for the element is stale.

    NOT fixed here, for two reasons:
      (a) Rewriting a test assertion is authoring test code, which is outside
          this gate's whitelist (unused exports/imports, duplicate components,
          orphaned routes, unused schema fields, dead barrel entries).
      (b) It is genuinely ambiguous which side is wrong. If the icon-only
          treatment is the intended R5 outcome, the test should be updated to
          getByLabelText("View Expense Summary"). If the design actually calls
          for a visible "View Details" label, the component is the regression.
          Picking one silently would either mask a real UI regression or
          overwrite a deliberate design decision. Escalating instead.

    Owner: the test/UI gate, not this one. Flagged so it is not mistaken for a
    dead-code finding and not silently carried past this node.

#2  UNIMPORTED BARREL (pre-existing, out of ticket scope)
    lib/permissions/index.ts

    Zero importers repo-wide — `grep -rn 'from "@/lib/permissions"'` across
    app/, components/, lib/, tests/ returns nothing. Consumers import the
    concrete modules (@/lib/permissions/ui, /registry, /guard, /evaluate)
    directly instead.

    NOT removed:
      * It is not a dead barrel entry in this gate's sense — all three
        re-export targets exist on disk (see [4] above).
      * It is pre-existing, not introduced by this ticket. `git cat-file -e
        main:lib/permissions/index.ts` succeeds; last touched by 1e617eb
        "Data Layer (oms-rbac-v2)".
      * It is not in sides.web.feature_files. Deleting a file outside this
        ticket's scope on a shared branch is beyond what a per-ticket dead-code
        gate should do unilaterally.

    Recommend a separate housekeeping ticket: either delete the barrel or
    adopt it consistently.

#3  DUPLICATED CONSTANT (both copies live — a DRY issue, not dead code)
    EXPENSE_TYPE_OPTIONS is declared twice with identical contents:

      components/forms/ExpenseForm.tsx:37             (typed OptionRow[])
      app/(app)/expense-summary/[project]/page.tsx:11 (untyped)

    Both are referenced by their own module and neither is exported:
      ExpenseForm.tsx:127                       -> <Listbox options={...}>
      expense-summary/[project]/page.tsx:41,72  -> type-label lookup + filter

    NOT removed: neither copy is dead, so deleting either breaks a live
    reference. Collapsing them means introducing a shared module and rewiring
    two importers — a refactor, not a dead-code deletion, and it crosses the
    server/client component boundary (ExpenseForm.tsx is "use client", the
    summary page is a server component). Flagged for follow-up; the seven
    values must stay in sync with the ExpenseType enum meanwhile.

--------------------------------------------------------------------------------
SUMMARY
--------------------------------------------------------------------------------
  files scanned .............. 12
  unused exports ............. 0
  unused imports ............. 0
  commented-out blocks ....... 0
  dead barrel entries ........ 0
  orphaned routes ............ 0
  unused schema fields ....... 0
  TODO/FIXME markers ......... 0
  ------------------------------
  items removed .............. 0
  files modified ............. 0  (this gate wrote only this evidence file)
  observations escalated ..... 3  (1 failing test, 1 unimported barrel,
                                   1 duplicated constant)

  GATE STATUS: PASS

  PASS basis: no provably-dead code exists in the 12 files in scope, so there
  was nothing to remove. Observation #1 is a real, currently-failing test —
  it is a test-correctness defect, not a dead-code finding, and is recorded
  here so it is visibly owned by a downstream gate rather than lost.
================================================================================
