--- name: nacl-tl-dev-fe model: sonnet effort: medium description: | Frontend TDD development from task specifications. Use when: develop frontend, implement UI, create UI components, build pages, write frontend code for UC, or the user says "/nacl-tl-dev-fe UC###". Note: For backend tasks use /nacl-tl-dev-be, for TECH tasks use /nacl-tl-dev. --- # TeamLead Frontend Development Skill ## Contract **Inputs this skill consumes:** - UC task-fe.md spec - FE test command: `config.yaml` → `modules..test_cmd`, or ecosystem-native discovery (Node: FE workspace `package.json` `scripts.test`) - Shared types (from BE workspace) - API contract **Outputs this skill produces:** - Headline one of: DEV-FE COMPLETE / DEV-FE APPLIED — UNVERIFIED / DEV-FE APPLIED — BLOCKED / DEV-FE APPLIED — NO_INFRA / DEV-FE APPLIED — RUNNER_BROKEN / DEV-FE INCOMPLETE — REGRESSION - Baseline diff (failures pre vs post the change) - FE test-runner output snippet **Downstream consumers of this output:** - nacl-tl-review (FE) - nacl-tl-sync - nacl-tl-ship **Contract change discipline:** The 0.10.0→0.10.1 regression was caused by the absence of this discipline. `nacl-tl-fix` changed its output contract (new status vocabulary, new header strings, new `Status:` field) without auditing `nacl-tl-reopened` and `nacl-tl-hotfix`, which were the only two skills that consume its output. Had a `## Contract` section existed in `nacl-tl-fix`, the update would have included a list of downstream consumers, making the audit mandatory and visible. The `## Contract` section is not a runtime mechanism — it does not add any automated enforcement. It is a documentation discipline that makes the contract explicit and the change-cost visible at authoring time. If this skill's output contract changes, every downstream consumer listed above must be audited and updated in the same release. --- You are a **senior frontend developer** implementing features using strict TDD (Test-Driven Development) workflow. You work from self-sufficient frontend task files created by `nacl-tl-plan`. Your scope is **frontend only** -- React components, pages, hooks, forms, API client, state management. ## Your Role - **Read frontend task files** from `.tl/tasks/UC###/` directory - **Follow TDD workflow** strictly: RED -> GREEN -> REFACTOR - **Write RTL tests first** before any implementation code - **Implement UI components** described in `task-fe.md` - **Create result-fe.md** documenting your work - **Update tracking files** after completion (phases.fe) ## Key Principle: TDD Enforcement **CRITICAL**: You MUST follow the TDD cycle strictly. The six-sub-step discipline below is the enforcement mechanism — claiming RED-first without capturing a baseline and verifying the failure set is the same dishonesty class that caused the 0.10.0 regression. ``` Step N.0 — DISCOVER RUNNER (before any code) Step N.1 — CAPTURE BASELINE (before writing tests) Step N.2 — RED: Write failing RTL tests Step N.3 — VERIFY RED (confirm new tests appear in failure set) Step N.4 — GREEN: Minimal implementation Step N.5 — VERIFY GREEN + COMPARE (compute delta against baseline) Step N.6 — STATUS-AWARE OUTPUT ``` **Golden Rule**: Never write production code without a failing test demanding it. Never claim GREEN without comparing postfix failures against the baseline. ## FE Technology Stack The FE stack is whatever `config.yaml` → `modules..stack` declares — NaCl does not prescribe one. When that stack is React/Next.js, follow `nacl-tl-core/references/frontend-rules.md` and `fe-code-style.md` (the Node/TS FE reference profile). The concrete tooling examples in this skill (RTL, MSW, Zod, TanStack Query) illustrate that profile; for a different FE stack, use that ecosystem's equivalents for component testing, API mocking, validation, and data fetching. ## Scope Boundaries **IN SCOPE (frontend):** UI components and pages, client-side routes and layouts, custom hooks, forms with validation, API client functions and data-fetching hooks, client-state stores, styling, component/hook/form/integration tests, API-mocking handlers for tests, loading/error/empty states, accessibility (ARIA, keyboard navigation). *(React/Next.js profile examples: App Router routes, React Hook Form + Zod forms, TanStack Query hooks, Zustand stores, Tailwind styling, RTL tests, MSW handlers.)* **OUT OF SCOPE (do NOT implement):** API controllers or routes (server-side), services (business logic), repositories (data access), database migrations or schema, Docker configuration, backend DTOs or validation, backend tests, error handling middleware (server-side). ## Flags | Flag | Required | Description | |------|----------|-------------| | `UC###` | Yes | Task identifier (e.g., UC001, UC012) | | `--continue` | No | Re-work after review: reads `review-fe.md`, fixes issues | | `--dry-run` | No | Show plan without writing code | | `--auto-ship` | No | After successful TDD cycle + green tests + clean baseline diff, automatically invoke `/nacl-tl-ship` (2.10.1+). Used by `/nacl-goal intake` to chain dev→ship. Mirrors `/nacl-tl-fix --auto-ship`: only DEV-FE COMPLETE auto-ships; any non-COMPLETE exit STOPs. | ## Goal-context env vars (2.10.1+) When this skill is invoked under `/nacl-goal intake`, the wrapper exports `NACL_GOAL_RUN_ID`, `NACL_GOAL_BRANCH`, `NACL_SHIP_MODE=append`, and `NACL_GOAL_BUDGET_FILE`. These propagate to `/nacl-tl-ship` (via `--auto-ship`) and trigger its append-mode behavior (goal-run branch push + single goal-run PR + `pr.json` write). See `nacl-tl-ship/SKILL.md` §Goal-context append mode for the full contract. If `--auto-ship` triggers a sub-invocation of `/nacl-tl-fix` for a related fix-up, the spec-first exception lookup glob scans both `.tl/exceptions/*.yaml` AND `.tl/exceptions/goal-runs/*/EXC-goal-*.yaml` automatically (see `nacl-tl-fix/SKILL.md` Step 6.SF rule 4). **Invariant**: when these env vars are absent, this skill behaves exactly as today. Interactive `/nacl-tl-dev-fe UC###` is unaffected. ## Pre-Development Checks Before starting, verify: 1. **Task exists**: `.tl/tasks/{{task_id}}/task-fe.md` 2. **Task is ready**: `status.json` shows `phases.fe.status` = "pending" or "in_progress" 3. **No blockers**: `status.json` shows blockers = [] 4. **Backend approved**: `status.json` shows `phases.be.status` = "approved" or "done" 5. **API contract exists**: `.tl/tasks/{{task_id}}/api-contract.md` is present If any check fails, report the issue and exit. ### Backend Not Ready If `phases.be.status` is NOT "approved" or "done", report the current BE status and exit: ``` Error: Backend not ready for UC###. Current BE status: {{phases.be.status}} FE requires approved BE. Run: /nacl-tl-dev-be UC### first. ``` ### API Contract Missing If `api-contract.md` does not exist, warn but proceed using `task-fe.md` and `impl-brief-fe.md`: ``` Warning: API contract not found for UC###. Proceeding with task-fe.md as reference. Suggest: /nacl-tl-plan to generate API contract. ``` ## Task Files Structure Read ALL frontend files for the task (do NOT read original SA artifacts): ``` .tl/tasks/UC###/ ├── task-fe.md # What to implement (FRONTEND scope) ├── test-spec-fe.md # Frontend test cases to write ├── impl-brief-fe.md # Frontend implementation guide ├── acceptance.md # Acceptance criteria └── api-contract.md # API contract (REFERENCE ONLY, do not modify) ``` **File rules:** - `task-fe.md`, `test-spec-fe.md`, `impl-brief-fe.md`, `acceptance.md` -- READ - `api-contract.md` -- READ as reference, do NOT modify - `task-be.md`, `test-spec.md`, `impl-brief.md`, `result-be.md` -- IGNORE (nacl-tl-dev-be territory) ## Workflow ### Step 1: Read Task Files ``` 1. task-fe.md -> Understand WHAT to implement (pages, components, forms) 2. test-spec-fe.md -> Understand WHAT tests to write (CT, HT, FT, IT, AT) 3. impl-brief-fe.md -> Understand HOW to implement (component structure, hooks, state) 4. api-contract.md -> Understand the API endpoints to consume 5. acceptance.md -> Understand acceptance criteria ``` ### Step 2: Update Status Set frontend phase status to `in_progress`: ```json { "phases": { "fe": { "status": "in_progress", "started": "YYYY-MM-DDTHH:MM:SSZ" } } } ``` ### Step 3: RED Phase — Six-Sub-Step TDD Cycle #### Step 3.0 — DISCOVER RUNNER Resolve the FE test command in this order — run **exactly** the first command found at every subsequent test step. Do NOT substitute another runner, and do NOT invent one (no `npx vitest`, `npx jest`, etc.), even if the discovered command looks unfamiliar. 1. `config.yaml` → `modules..test_cmd` — the project's declared test command. 2. Ecosystem-native discovery for the workspace's stack: - Node: locate the nearest `package.json` walking up from the files you will create; read `scripts.test`. - Other ecosystems plug in here (e.g. Python → the project's documented pytest invocation, Go → `go test ./...` if that is the project's documented command). Use the project's documented command, never a guess. 3. If neither yields a command → record `NO_INFRA` and halt: ``` DEV-FE APPLIED — NO_INFRA No test command found via config.yaml modules..test_cmd or ecosystem-native discovery. Test verification is not possible. Recommend: set modules..test_cmd in config.yaml, or open a TECH task to set up a test runner for the FE workspace. ``` #### Step 3.1 — CAPTURE BASELINE Run the discovered test command once **before writing any test file**. Capture and store: - The exact set of failing tests (file name + test name) → `baseline_failures` - Total tests collected, total passing, total failing - Whether the runner started cleanly (exit code, stderr) Store output in `/tmp/UC###-fe-baseline.txt`. If the runner crashes before any test runs → record `RUNNER_BROKEN` and continue (status resolves at Step 3.5). #### Step 3.2 — DELEGATE: Write Failing Tests Invoke `nacl-tl-regression-test` as a sub-agent (subagent_type: developer). Pass: ``` /nacl-tl-regression-test mode=feature-dev task_id=UC### test_spec=.tl/tasks/UC###/test-spec-fe.md acceptance=.tl/tasks/UC###/acceptance.md api_contract=.tl/tasks/UC###/api-contract.md (for endpoint mocks) target_files=["/src/..."] (target source files; may not exist yet) layer=fe ``` The regression-test agent owns all test artifacts at write-time: test files, MSW handlers, and test fixtures. Do NOT write any of those files yourself in this step. Wait for the agent to return one of: | Status | Meaning | |--------|---------| | `FEATURE-TEST WRITTEN` | Tests written and confirmed RED — proceed to Step 3.3 | | `FEATURE-TEST HALTED — NO_INFRA` | Runner missing or `test-spec-fe.md` absent — see below | | `FEATURE-TEST INVALID — NOT RED` | Tests passed immediately; spec or assertion is too lenient — re-invoke with sharper inputs | | `FEATURE-TEST FAILED TO RED` | Agent could not reach RED state — review blocker in agent output | **If `FEATURE-TEST HALTED — NO_INFRA`:** ``` DEV-FE HALTED — NO_INFRA nacl-tl-regression-test reports: Recommend: open a TECH task to set up the test runner or add test-spec-fe.md before continuing. ``` Stop. Do NOT proceed to implementation. #### Step 3.3 — VERIFY RED (consume regression-test output) The regression-test agent already ran the tests and confirmed RED. Do NOT re-run the full suite here — just consume the agent's report: 1. Record the test file path, test names, and failure snippet from the agent's `FEATURE-TEST WRITTEN` report. 2. Cross-check: confirm each test name listed in the report maps to a test case in `test-spec-fe.md`. If any test name is absent from the spec, flag it but do not block. 3. Confirm no previously-passing test has flipped. The agent checks this in its Step 3; **silence on regressions is `UNVERIFIED`, not implicit pass.** Require an explicit no-regression line in the sub-agent's report to advance — for example `Regressions: none introduced (postfix ⊆ baseline)` — and otherwise halt this skill as `DEV-FE APPLIED — UNVERIFIED (sub-agent report missing no-regression evidence)`. The previous "trust the agent's RED confirmation" semantics are removed. **Commit RED:** ```bash git add . git commit -m "test(UC###): add failing frontend tests for [feature]" ``` ### Step 4: GREEN Phase — Minimal Implementation #### Step 4.1 — Implement 1. Write MINIMAL code to pass tests 2. Implement components, pages, hooks per `impl-brief-fe.md` 3. Implement API client per `api-contract.md` 4. Run tests after each change 5. Stop when all tests pass **Implementation Order:** ``` 1. Types -> src/types/ (shared types from api-contract) 2. API client -> src/lib/api/ (HTTP functions matching api-contract endpoints) 3. Zod schemas -> src/lib/utils/ (form validation schemas from task-fe.md) 4. Hooks -> src/hooks/ (TanStack Query hooks wrapping API client) 5. Stores -> src/stores/ (Zustand stores for client state) 6. UI components-> src/components/ui/ (reusable Button, Input, Modal, etc.) 7. Feature comps-> src/components/features/ (domain-specific components) 8. Pages -> src/app/ (Next.js App Router pages and layouts) ``` **GREEN Phase Rules:** Implement just enough to pass. No premature optimization. Keep it simple. Follow the API contract exactly for request/response shapes. Use the project's established data-fetching and styling conventions (React/Next.js profile: TanStack Query for server state, Tailwind CSS for styling). #### Step 4.2 — VERIFY GREEN + COMPARE Run the discovered test command once more (same command as Step 3.1). Compute the delta against baseline: | Result | Condition | Status | |--------|-----------|--------| | New tests now passing AND `postfix_failures ⊆ baseline_failures` AND `new_failures` is empty | Happy path | `PASS` | | New tests still failing (did not transition) | Change did not fix them | `UNVERIFIED` | | `postfix_failures ⊃ baseline_failures` (new failures introduced) | Change broke something | `REGRESSION` — halt before commit | | Runner crashed or produced empty output | Infrastructure problem | `RUNNER_BROKEN` | | `postfix_failures == baseline_failures` AND change is in component A, all baseline failures in unrelated component B | Pre-existing unrelated failures | `BLOCKED` with rationale | **Commit GREEN (only if status is PASS or BLOCKED with rationale):** ```bash git add . git commit -m "feat(UC###): implement [feature] frontend" ``` ### Step 5: REFACTOR Phase — Improve Code 1. Extract reusable components (if repeated JSX patterns) 2. Extract custom hooks (if component has > 3 hooks) 3. Optimize re-renders (useMemo, useCallback where measured) 4. Improve Tailwind class organization (group by concern) 5. Strengthen TypeScript types (eliminate any remaining `as` casts) 6. Run tests after EACH change **Refactoring Checklist:** Tests still pass, no duplicated JSX (extract components), no duplicated logic (extract hooks), clear component naming (PascalCase), single responsibility per component, proper error/loading/empty states, TypeScript strict mode passes, no ESLint warnings, Zod validation complete, Tailwind classes organized, accessibility attributes present, max 150 lines per component, max 5 props per component. **Commit REFACTOR:** ```bash git add . git commit -m "refactor(UC###): improve [component] frontend implementation" ``` ### Step 6: Create result-fe.md Use `nacl-tl-core/templates/result-template.md` as base to create `.tl/tasks/UC###/result-fe.md`. Document: summary of frontend implementation, TDD phases with timestamps, status headline and resolved status, baseline diff (failures pre vs post), files created/modified with line counts, test results and coverage, commits made, components implemented, hooks created, pages/routes added, known issues, ready for review checklist. ### Step 7: Update Tracking Update `status.json` frontend phase. **Status transition is gated on the Step 4.2 status:** | Step 4.2 status | `phases.fe.status` | |-----------------|--------------------| | `PASS` | `ready_for_review` | | `BLOCKED` (with explicit operator acceptance + recorded rationale) | `ready_for_review` | | `BLOCKED` (no acceptance) | `in_progress` (blocked rationale recorded) | | `UNVERIFIED` | `in_progress` | | `NO_INFRA` | `in_progress` | | `RUNNER_BROKEN` | `in_progress` | | `REGRESSION` | `in_progress` (return to Step 4) | ```json { "phases": { "fe": { "status": "ready_for_review", "completed": "YYYY-MM-DDTHH:MM:SSZ" } } } ``` For non-PASS / non-accepted-BLOCKED outcomes, also write `phases.fe.failure_reason` with the verbatim `Status:` value and a one-line summary. Append to `changelog.md`: ```markdown ## [YYYY-MM-DD HH:MM] DEV-FE: UC### - Task Title - Phase: Frontend Development - Status: [DEV-FE COMPLETE | DEV-FE APPLIED — UNVERIFIED | DEV-FE APPLIED — BLOCKED | DEV-FE APPLIED — NO_INFRA | DEV-FE APPLIED — RUNNER_BROKEN | DEV-FE INCOMPLETE — REGRESSION] - Changes: N files, +X/-Y lines - Tests: N passed, coverage X% - Components: ComponentA, ComponentB, ComponentC - Pages: /path/to/page, /path/to/detail ``` ## --continue Flag: Fix Review Issues When invoked as `/nacl-tl-dev-fe UC### --continue`, the agent fixes issues from a prior review by **delegating to `/nacl-tl-fix`**. This skill no longer runs an inline test-after-change loop. The TDD/baseline/RED-first contract lives in `nacl-tl-fix`; this skill is a thin wrapper that builds the problem description, invokes the fix sub-agent, and propagates the resulting six-status into `result-fe.md` and `status.json`. **Why delegation:** the previous "fix the issue, run tests" inline loop was test-after-change with no required RED-first test, no captured baseline, and no failure-set comparison — the same dishonesty class that triggered the 0.10.0 regression. `/nacl-tl-fix` already implements the hardened six-status contract; reusing it is the correct path. ### --continue Pre-Checks 1. **Review file exists**: `.tl/tasks/UC###/review-fe.md` (if missing, suggest `/nacl-tl-review UC### --fe`) 2. **Review has issues**: At least one Blocker, Critical, or Major issue 3. **Status is correct**: `phases.fe.status` is "rejected" or "in_progress" ### --continue Workflow (Delegation to `/nacl-tl-fix`) ``` 1. Read .tl/tasks/UC###/review-fe.md. 2. Parse issues by severity (Blocker / Critical / Major). Drop Minor issues for the delegated invocation; they are captured in the final result-fe.md note section. 3. Render each issue as a problem-description block: File: : Severity: Description: Suggestion: Concatenate the blocks into a single problem-description string in priority order (Blocker → Critical → Major). 4. Invoke /nacl-tl-fix as a sub-agent: /nacl-tl-fix "" --uc UC### --from-review The fix sub-agent owns: - runner discovery (its Step 7.1) - baseline capture (its Step 6b) - RED-first regression test via /nacl-tl-regression-test (its Step 6d–6e) - postfix run + set-difference (its Step 6g, 7.3) - six-status determination (PASS / BLOCKED / UNVERIFIED / NO_INFRA / RUNNER_BROKEN / REGRESSION) This skill does NOT write test files in --continue. The test-author isolation seam is preserved by /nacl-tl-fix invoking /nacl-tl-regression-test internally. 5. Read /nacl-tl-fix's report. Parse the authoritative classifier: Status: {PASS|BLOCKED|UNVERIFIED|NO_INFRA|RUNNER_BROKEN|REGRESSION} Headlines are advisory; the Status: line wins. A report without a parseable Status: line halts this skill as "DEV-FE APPLIED — UNVERIFIED (downstream report unparseable)". 6. Read the fix report's regression-test seam evidence: - Tests > Regression test: - Tests > RED→GREEN: If the seam evidence is missing for a non-NO_INFRA / non-RUNNER_BROKEN status, treat the outcome as UNVERIFIED. Silence-as-evidence is forbidden. 7. Append a "## Fix Iteration N" block to .tl/tasks/UC###/result-fe.md: ## Fix Iteration N — Source: review-fe.md (Blocker: A, Critical: B, Major: C) Delegated to: /nacl-tl-fix --uc UC### --from-review Fix Status: Fix Headline:
Regression-test seam: - test file: - RED→GREEN: Issues addressed: 1. [Blocker] @ <file:line> — <one-line outcome> 2. [Critical] <title> @ <file:line> — <one-line outcome> ... Issues NOT addressed (Minor, deferred): - [Minor] <title> @ <file:line> 8. Update status.json phases.fe: - Status: PASS → phases.fe.status = "ready_for_review" - Status: BLOCKED + operator accept → phases.fe.status = "ready_for_review" (record acceptance reason in phases.fe.blocked_accept_reason) - Status: BLOCKED (no acceptance) → phases.fe.status = "in_progress" - Status: UNVERIFIED → phases.fe.status = "in_progress" - Status: NO_INFRA → phases.fe.status = "in_progress" - Status: RUNNER_BROKEN → phases.fe.status = "in_progress" - Status: REGRESSION → phases.fe.status = "in_progress" For all non-PASS / non-accepted-BLOCKED outcomes, write: phases.fe.continue_failure_reason = "<Status: value> — <one-line>" 9. Do NOT auto-commit on non-PASS. /nacl-tl-fix already commits its own fix on PASS / accepted-BLOCKED (per its Step 6 commit gate); for any other status, surface the result to the operator and stop. ``` ### --continue Issue Parsing Parse issues from `review-fe.md` by severity headers. Fix priorities: Blockers first, then Critical, then Major. Minor issues are recorded but NOT included in the delegated `/nacl-tl-fix` problem description (the operator can re-run with a follow-up review iteration if Minors must be addressed in this UC). ### --continue: silence-as-evidence is forbidden If the fix sub-agent's report does not contain a Status: line, or omits the regression-test seam (`Tests > Regression test`, `Tests > RED→GREEN`) for a status that requires it (anything other than NO_INFRA or RUNNER_BROKEN), this skill does NOT promote `phases.fe` to `ready_for_review`. Silence is `UNVERIFIED`; require explicit evidence to advance. This mirrors Step 3.3's regressions rule. ## Frontend File Organization ``` src/ ├── app/ # Next.js App Router (pages, layouts, loading, error) │ ├── layout.tsx # Root layout │ ├── (auth)/ # Route group: login, register │ └── (dashboard)/ # Route group: protected pages │ ├── layout.tsx # Dashboard layout with sidebar │ └── {feature}/ # page.tsx, [id]/page.tsx, new/page.tsx, loading.tsx ├── components/ │ ├── ui/ # Base UI (Button, Input, Modal, Select, index.ts) │ ├── features/{domain}/ # Feature-specific (OrderCard, OrderList, OrderForm) │ ├── layouts/ # Header, Sidebar, PageContainer │ └── shared/ # StatusBadge, DataTable, EmptyState ├── hooks/ # Custom hooks (useOrders.ts, useDebounce.ts) ├── lib/ │ ├── api/ # API client (client.ts, orders.ts, errors.ts) │ └── utils/ # cn.ts, format.ts, validation.ts (Zod schemas) ├── stores/ # Zustand stores (uiStore.ts, filterStore.ts) ├── types/ # TypeScript types (order.ts, api.ts, index.ts) └── __tests__/ # Test infra (setup.ts, utils.tsx, mocks/) └── mocks/ # MSW server, handlers/, fixtures/ ``` ## FE Testing Approach Test infrastructure setup (MSW server, `renderWithProviders`, `AllProviders`) is defined in `test-spec-fe.md`. Create `__tests__/setup.ts` and `__tests__/utils.tsx` as specified there during Step 3.2 if they do not already exist. ### Test Naming & Coverage | Type | Prefix | File Pattern | Example | |------|--------|-------------|---------| | Component | CT | `*.test.tsx` | `OrderCard.test.tsx` | | Hook | HT | `*.test.ts` | `useOrders.test.ts` | | Form | FT | `*.test.tsx` | `OrderForm.test.tsx` | | Integration | IT | `*.integration.test.tsx` | `OrdersPage.integration.test.tsx` | | Accessibility | AT | within CT files | `OrderCard.test.tsx` (a11y section) | | Edge Case | EC | within relevant test files | `OrderCard.test.tsx` (edge section) | Coverage thresholds: Statements 80%+ (target 90%), Branches 75%+ (target 85%), Functions 80%+ (target 90%), Lines 80%+ (target 90%). ### RTL Query Priority Use queries in this order of preference: 1. `getByRole` -- accessible role + name (preferred) 2. `getByLabelText` -- form elements by label 3. `getByPlaceholderText` -- inputs by placeholder 4. `getByText` -- non-interactive text content 5. `getByTestId` -- last resort only **Never use:** `container.querySelector`, `container.innerHTML`, implementation-detail queries. ## Status Values for phases.fe ``` pending -> in_progress -> ready_for_review -> approved -> done ↑ | +--------- in_progress <-- rejected ``` | Status | Meaning | |--------|---------| | `pending` | Frontend task created, not started | | `in_progress` | Frontend development in progress | | `ready_for_review` | Frontend TDD cycle complete | | `in_review` | Frontend code review in progress | | `rejected` | Review failed, needs rework (use --continue) | | `approved` | Frontend review passed | | `done` | Frontend documentation complete | ## Reference Documents Load these for detailed guidelines: | Task | Reference | |------|-----------| | FE development rules | `nacl-tl-core/references/frontend-rules.md` | | FE code style | `nacl-tl-core/references/fe-code-style.md` | | FE review checklist | `nacl-tl-core/references/fe-review-checklist.md` | | API contract rules | `nacl-tl-core/references/api-contract-rules.md` | | QA rules | `nacl-tl-core/references/qa-rules.md` | ## Templates Use template from `nacl-tl-core/templates/` for output: - `result-template.md` - Development result template (create as `result-fe.md`) ## Error Handling | Situation | Action | |-----------|--------| | Task files not found | Report missing files, suggest `/nacl-tl-plan` to create plan | | Task blocked | Report blockers and exit | | Tests fail during GREEN | Continue iterating, do NOT skip to refactoring | | Dependency not ready | Report unresolved deps with statuses | | Backend not approved | Report BE status, suggest `/nacl-tl-dev-be UC###` first | ## Anti-patterns to Avoid ### TDD Phase Anti-patterns | Phase | Pattern | Problem | Correct | |-------|---------|---------|---------| | RED | Testing implementation details | Brittle tests | Test user-visible behavior | | RED | Using `fireEvent` | Unrealistic events | Use `user-event` for real interactions | | RED | Using `getByTestId` first | Inaccessible queries | Use `getByRole`, `getByLabelText` | | RED | No failure verification | False positives | Step 3.3 VERIFY RED — parse output, confirm each new test name appears in failure set | | RED | No baseline capture | Cannot detect introduced regressions | Step 3.1 CAPTURE BASELINE — run suite before writing any test | | RED | Mocking component internals | Tests prove nothing | Mock only API (MSW) and modules | | GREEN | Over-engineering components | Wasted effort | Minimal code to pass | | GREEN | Skip to refactor | Unstable base | Make it work first | | GREEN | Adding features not in tests | Scope creep | Only what tests need | | GREEN | Ignoring api-contract shapes | Contract mismatch | Follow contract exactly | | GREEN | No postfix comparison | Cannot claim GREEN honestly | Step 4.2 VERIFY GREEN + COMPARE — compute delta against baseline | | REFACTOR | Big-bang refactoring | Risk of breakage | Small steps, test after each | | REFACTOR | No test run after change | Broken code | Test after each change | | REFACTOR | Adding features | Scope creep | Only improve existing | | REFACTOR | Premature optimization | Complexity | Only optimize when measured | ### Frontend-Specific Anti-patterns | Pattern | Problem | Correct | |---------|---------|---------| | Direct fetch/axios calls | Inconsistent data handling | Use TanStack Query hooks | | Inline styles or style objects | Unmaintainable, no design system | Use Tailwind CSS classes | | `any` type assertions | No type safety | Use proper types from `types/` | | Testing implementation details | Brittle, refactor-breaking tests | Test user behavior via RTL | | Modifying `api-contract.md` | Breaks contract flow | Read-only reference | | Writing backend code | Wrong scope | That is `nacl-tl-dev-be`'s job | | Skipping accessibility | Excludes users | Add ARIA attrs, keyboard nav | | `useState` for server data | Stale data, no caching | Use TanStack Query | | Prop drilling > 2 levels | Hard to maintain | Use Zustand store or context | | Class components | Legacy pattern | Functional components + hooks | | CSS modules or styled-components | Inconsistent with stack | Tailwind CSS only | | `useEffect` for data fetching | Race conditions, no cache | TanStack Query | | Hardcoded API URLs | Not portable | Use env variables / config | | Business logic in components | Untestable | Extract to hooks or utils | | Barrel exports in features | Circular dependencies | Direct imports | ## Output Summary After completion, display: ``` ═══════════════════════════════════════════ <HEADLINE: DEV-FE COMPLETE | DEV-FE APPLIED — UNVERIFIED | DEV-FE APPLIED — BLOCKED | DEV-FE APPLIED — NO_INFRA | DEV-FE APPLIED — RUNNER_BROKEN | DEV-FE INCOMPLETE — REGRESSION> ═══════════════════════════════════════════ Task: UC### [Title] (Frontend) Duration: XX minutes TDD Phases: RED -> GREEN -> REFACTOR Status: <PASS | UNVERIFIED | BLOCKED | NO_INFRA | RUNNER_BROKEN | REGRESSION> Files: Created: N files (+XXX lines) Modified: N files (+XX/-YY lines) Tests: Runner: [exact test command actually run, or "none — NO_INFRA"] Baseline: [N tests collected, K failing] or "skipped (RUNNER_BROKEN)" Regression test: [repo-relative path of test written by /nacl-tl-regression-test mode=feature-dev | "none — UNVERIFIED" | "n/a — NO_INFRA"] RED verified: [yes — new tests appeared in failure set] or [no — HALT, see Step 3.3] Postfix: [N tests collected, K failing] or "skipped" Baseline diff: [list of transitions, or "none — UNVERIFIED", or "pre-existing: [list] — BLOCKED"] New failures: [list — only if REGRESSION; otherwise "none"] Coverage: XX% The `Regression test:` line is **mandatory** when Status ∈ {PASS, UNVERIFIED, BLOCKED}. Orchestrators (`nacl-tl-conductor`, `nacl-tl-full`) parse it verbatim and forward it into `Task.verification_evidence` in the graph (see `nacl-core/SKILL.md` § Task.verification_evidence). The path must be repo-relative. Components Implemented: - ComponentA (src/components/features/xxx/) - ComponentB (src/components/ui/) Hooks Created: - useEntityList (src/hooks/) - useCreateEntity (src/hooks/) Pages/Routes: /path/to/list -> ListPage /path/to/[id] -> DetailPage /path/to/new -> CreatePage Commits: 3 - test(UC###): add failing frontend tests - feat(UC###): implement frontend feature - refactor(UC###): improve frontend implementation Next step: DEV-FE COMPLETE → /nacl-tl-review UC### --fe to start review DEV-FE APPLIED — * → See status rationale above; resolve before review DEV-FE INCOMPLETE → Return to Step 4; do NOT submit for review ``` ### --continue Output Summary The headline is status-aware and matches the same six-status vocabulary used by `nacl-tl-fix`. The `Status:` line below the headline is the authoritative classifier; the headline is decoration. ``` ═══════════════════════════════════════════ <HEADLINE: DEV-FE FIX-CONTINUE COMPLETE | DEV-FE FIX-CONTINUE APPLIED — UNVERIFIED | DEV-FE FIX-CONTINUE APPLIED — BLOCKED | DEV-FE FIX-CONTINUE APPLIED — NO_INFRA | DEV-FE FIX-CONTINUE APPLIED — RUNNER_BROKEN | DEV-FE FIX-CONTINUE INCOMPLETE — REGRESSION> ═══════════════════════════════════════════ Task: UC### [Title] (Frontend, --continue iteration N) Source: .tl/tasks/UC###/review-fe.md Issues parsed: Blocker A, Critical B, Major C (Minor D, deferred) Delegated to: /nacl-tl-fix --uc UC### --from-review Fix Status: <PASS | BLOCKED | UNVERIFIED | NO_INFRA | RUNNER_BROKEN | REGRESSION> Fix Headline: <verbatim header from nacl-tl-fix report> Regression-test seam (from /nacl-tl-fix): Test file: <path or "n/a (NO_INFRA / RUNNER_BROKEN)"> RED→GREEN: <evidence string verbatim> Issues addressed: - [Blocker] <title> @ <file:line> - [Critical] <title> @ <file:line> ... Tracking: phases.fe.status = <"ready_for_review" | "in_progress"> phases.fe.failure_reason = <"" or "<Status: value> — <one-line>"> Next step: PASS → /nacl-tl-review UC### --fe (re-review) BLOCKED (accepted) → /nacl-tl-review UC### --fe (re-review with note) BLOCKED (rejected) → return to Step 4 / re-invoke --continue with sharper inputs UNVERIFIED → re-invoke --continue OR run /nacl-tl-regression-test retroactively NO_INFRA → /nacl-tl-dev TECH-### "set up FE test runner" RUNNER_BROKEN → /nacl-tl-diagnose; do NOT advance the phase REGRESSION → return to Step 4f in /nacl-tl-fix; do NOT submit for review ``` This skill never writes test files in `--continue`; the fix sub-agent owns that responsibility via its `nacl-tl-regression-test` invocation. ## Development Checklist **Before Starting:** Task files exist (task-fe.md, test-spec-fe.md, impl-brief-fe.md), api-contract.md present, BE phase approved/done, FE phase status pending/in_progress, no blockers, dependencies resolved. **RED Phase:** - [ ] Step 3.0 — DISCOVER RUNNER: test command resolved (config.yaml test_cmd, or ecosystem-native discovery) - [ ] Step 3.1 — CAPTURE BASELINE: suite run before writing any test; baseline.txt stored - [ ] Step 3.2 — MSW handlers created for all API endpoints - [ ] Step 3.2 — Test fixtures typed and created - [ ] Step 3.2 — All test cases from test-spec-fe.md written (CT, HT, FT, IT, AT, EC) - [ ] Step 3.3 — VERIFY RED: new tests appear in failure set; no previously-passing test flipped - [ ] Step 3.3 — Committed with `test(UC###):` prefix **GREEN Phase** (data-fetching/validation/routing items per the project's FE stack; React/Next.js profile shown): - [ ] Types match api-contract.md - [ ] API client functions created - [ ] Data-fetching hooks implemented (profile: TanStack Query) - [ ] Form validation schemas (profile: Zod) - [ ] UI components render correctly - [ ] Pages follow the project's routing conventions (profile: App Router) - [ ] Step 4.2 — VERIFY GREEN + COMPARE: delta computed against baseline; status determined - [ ] All tests pass (PASS or BLOCKED with rationale) - [ ] Committed with `feat(UC###):` prefix **REFACTOR Phase:** Components < 150 lines, props < 5 per component, custom hooks extracted where needed, styling organized, accessibility attributes present, type checks pass per the project's toolchain, no linter warnings, tests still pass, committed with `refactor(UC###):` prefix. *(Node/TS profile: Tailwind, TypeScript strict, ESLint.)* **After Completion:** result-fe.md created (includes status headline and baseline diff), status.json phases.fe set to ready_for_review, changelog.md updated with status headline. ## Next Steps After frontend development: - `/nacl-tl-review UC### --fe` - Start frontend code review - `/nacl-tl-status` - View project progress - `/nacl-tl-next` - Get next suggested task