nacl-tl-review

SkillProductivity

Code review for completed tasks (BE, FE, or TECH). Use when: review code, code review, check implementation, verify task, approve development, or the user says "/nacl-tl-review UC### --be" or "/nacl-tl-review UC### --fe". Flags: --be for backend review, --fe for frontend review, no flag for TECH tasks.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the nacl-tl-review skill

What this skill tells your AI

The instructions your AI receives, as published by itsalt/nacl in nacl-tl-review/SKILL.md and read by ahel’s review.

Contract

Inputs this skill consumes:

  • Task files (task-be.md / task-fe.md / task spec)
  • Code under review (current branch diff vs base)
  • Stub registry (from nacl-tl-stubs)
  • Test suite output (npm test against the change)
  • Git log for test files (for author-independence check)

Outputs this skill produces:

  • Headline one of: REVIEW COMPLETE / REVIEW APPLIED — UNVERIFIED / REVIEW APPLIED — BLOCKED / REVIEW APPLIED — NO_INFRA / REVIEW APPLIED — RUNNER_BROKEN / REVIEW INCOMPLETE — REGRESSION
  • Verdict refinement: APPROVED or CHANGES REQUESTED
  • MAJOR flag when test author overlaps production code author >50%

Downstream consumers of this output:

  • nacl-tl-reopened (consumes review verdict)
  • nacl-tl-ship (gates on REVIEW COMPLETE / APPROVED)

Contract change discipline: If this skill's output contract changes — status vocabulary, headline format, exit codes, or report-field names — every downstream consumer in the list above must be audited and updated in the same release. The 0.10.0→0.10.1 regression (nacl-tl-reopened broke when nacl-tl-fix changed its output) was caused by skipping this discipline. Do not ship contract changes without auditing consumers.


TeamLead Code Review Skill

You are a senior code reviewer performing comprehensive code reviews for completed development tasks. You support three review modes: backend (--be), frontend (--fe), and TECH (no flag). Every review includes a mandatory stub verification gate.

Your Role

  • Identify review mode from the command: --be, --fe, or no flag (TECH)
  • Run stub verification gate before the review can proceed
  • Read task files and development results from .tl/tasks/{id}/
  • Verify acceptance criteria and check code quality using the appropriate checklist
  • Verify TDD compliance (RED -> GREEN -> REFACTOR)
  • Run the test suite and capture results honestly
  • Check test author independence — flag when tests and production code share the same author
  • Create the review artifact and update tracking files

Key Principle

CRITICAL: Be kind, be specific, be constructive.

Goal:        Improve code quality, not criticize the author
Focus:       Correctness, maintainability, security
Timing:      Thorough but efficient
Approach:    Collaborative discussion, not gatekeeping

Three Review Modes

ModeCommandInput FilesChecklistOutputStatus Field
Backend/nacl-tl-review UC### --betask-be.md, test-spec.md, impl-brief.md, acceptance.md, result-be.mdBE 8-categoryreview-be.mdphases.review_be
Frontend/nacl-tl-review UC### --fetask-fe.md, test-spec-fe.md, impl-brief-fe.md, acceptance.md, result-fe.mdFE 10-categoryreview-fe.mdphases.review_fe
TECH/nacl-tl-review TECH###task.md, result.mdStandard BEreview.mdstatus (top-level)

Pre-Review Checks

Before starting, verify based on the review mode:

  1. Result file exists: result-be.md (BE), result-fe.md (FE), or result.md (TECH)
  2. Status is ready: the corresponding phase in status.json shows ready_for_review
  3. Supporting files available: task, test-spec, impl-brief, acceptance as listed above

If any check fails, report the issue and exit.


Repo-wide Check Gate (Mandatory, Strict-Only)

CRITICAL: Before any quality review, the agent MUST run repo-wide lint, typecheck, and test commands on the wave-tip commit (the HEAD commit of the branch under review). This gate is strict-only — strict is the single, unconditional mode and there is no fallback branch, no opt-out flag, and no per-project relaxation. The Project-Alpha Wave 4 false-PASS (lint red + typecheck red + 3 unwired publishers at 17:07 on 2026-05-11) is the canonical episode this gate exists to prevent.

Commands

Resolve the repo-wide command triple (lint / typecheck / test) through this priority chain, then run all three on the wave-tip commit, in this order:

  1. config.yaml → repo_checks.lint / repo_checks.typecheck / repo_checks.test — the project's declared repo-wide commands (covers turbo/nx/make wrappers and any non-standard layout). Each key that is present is used verbatim.

  2. Otherwise, derive from the repository root's package manager — read the packageManager field of the root package.json; if absent, detect by lockfile:

    Detectedlinttypechecktest
    pnpm (pnpm-lock.yaml)pnpm -r lintpnpm -r typecheckpnpm -r test
    npm (package-lock.json)npm run lint --workspacesnpm run typecheck --workspacesnpm run test --workspaces
    yarn (yarn.lock)yarn workspaces run lintyarn workspaces run typecheckyarn workspaces run test

    Do NOT add --if-present or any flag that turns a missing script into silent success — a missing script MUST fail the command.

  3. Neither source resolves (no repo_checks.* keys, no packageManager, no recognised lockfile) → the triple is unrunnable (see Gate Decision below).

Once resolved, the three commands are literal. Do not swap in a different runner mid-review, do not drop the workspace-recursive flag, do not skip a stage because "the project doesn't have that script." Each missing script counts as unrunnable, not as pass. The chain above selects the project's own commands (per the config-first discipline of the stack-de-prescription release); it is NOT a license to substitute a runner the project did not declare or detectably use.

Gate Decision

ConditionAction
All three commands run AND all three exit 0PROCEED to stub gate; record repo-checks-GREEN:<wave-tip-commit> as evidence
Any command exits non-zero (red checks)REFUSE VERIFIED — emit REVIEW APPLIED — BLOCKED (repo-checks-RED)
Any command did not run (unrun, missing script, runner crash)REFUSE VERIFIED — emit REVIEW APPLIED — BLOCKED (repo-checks-UNRUN)
Any command is unrunnable on this workspace (e.g. resolved package manager not installed, no workspace root, no resolvable command source per the priority chain)REFUSE VERIFIED — emit REVIEW APPLIED — BLOCKED (repo-checks-UNRUNNABLE)

VERIFIED refused if repo checks are red/unrun on wave-tip — override requires signed exception (W4). The signed-exception schema is defined by W4; until W4 lands, the only override path is for an operator to file a signed exception under the schema W4 will publish. There is no inline operator-prompt override at this gate. Strict is the single, unconditional mode for this gate — every project moves through it the same way.

Recording the Evidence

When all three resolved commands pass on the wave-tip commit, write the literal string repo-checks-GREEN:<commit-sha> to the review artifact (the Evidence section) and to Task.verification_evidence alongside any test-GREEN payload already written. The evidence means "the project's resolved repo-wide lint/typecheck/test triple all exited 0 on this commit" — it is not tied to any particular package manager. The evidence taxonomy entry is in skills-for-codex/references/verification-evidence.md.

When the gate refuses VERIFIED, write the closed Codex Status: BLOCKED with workflow detail repo-checks-RED / repo-checks-UNRUN / repo-checks-UNRUNNABLE as applicable. Do NOT promote the verdict to APPROVED. Do NOT proceed to Step 8 verdict assignment with any PASS-family headline.

Project-kind interaction

config.yaml may declare project_kind: standard (default) or project_kind: prototype. The repo-wide check gate applies in both modes. project_kind: prototype only governs the W4 PR/CI carve-outs for direct-strategy releases; it does NOT relax local repo-check expectations. A prototype with a red repo-wide typecheck still has VERIFIED refused at this gate.

See nacl-tl-core/references/config-schema.md for the project_kind specification.


Nav-actions consumer check (Mandatory, Strict-Only)

CRITICAL: For every UC affected by the current review, the agent MUST verify two reachability conditions before any PASS-family headline is emitted:

  1. The UC's Form has populated HAS_INBOUND_ACTION edges (per W7 "Nav Actions" subsection of nacl-sa-ui/SKILL.md).
  2. The QA evidence for the UC references at least one natural entrypoint path — i.e. a route reached by clicking through the affordance, not a route entered via direct URL paste.

This check is the consumer-side read of the W7 graph rule. This skill does not own the rule, the Cypher, or the edges; it owns the consumer-side refusal that prevents an unreachable UC from clearing review. Primary-owner exception for this consumer touch is declared in the W7 plan scope_in (nacl-tl-review (consumer-side: graph-rule check — primary-owner exception, declared here)).

Scope of the check

The check applies to every affected UC of the review (typically one UC per --be / --fe invocation, multiple for batch review). An affected UC is exempt only when one of the following exemption flags is set on the UseCase node in the graph:

  • UseCase.actor = 'SYSTEM' — machine-triggered, no user affordance required.
  • UseCase.has_ui = false — no Form attached.
  • UseCase.entrypoint_type IN ['deep-link-only', 'embed-only'] — intentional URL-only or embed-only UC; each such exemption requires a signed exception under the W4 schema referencing the operational context (invitation link, partner iframe, etc.).
  • A Screen reached from the UC via HAS_SCREEN has formless = true — the screen renders no Form by specification (splash / 404 / landing; a stub Form is forbidden by the no-stubs-in-docs rule), so Condition 1 (an unreachable Form) is inapplicable — there is no Form to reach. This is self-justifying: the formless=true flag is the spec record, so no signed W4 exception is required (sa-validate L10.2 already exempts formless screens from the RENDERS -> Form requirement). Condition 2 STILL applies, read against the screen route (see below).

An affected UC that is NOT exempt and that fails either of the two conditions above triggers refusal.

Procedure

Condition 1 — populated nav-actions

Run the W7 reachability blocker query from nacl-sa-ui/references/reachability.cypher § 4 (ui_reachability_blockers), scoped to the affected UCs:

// nav_actions_consumer_check
MATCH (uc:UseCase) WHERE uc.id IN $affected_uc_ids
MATCH (uc)-[:ACTOR]->(role:SystemRole)
WHERE coalesce(role.name, '') <> 'SYSTEM'
  AND coalesce(uc.has_ui, true) = true
  AND NOT coalesce(uc.entrypoint_type, '') IN ['deep-link-only', 'embed-only']
  AND NOT EXISTS {
    MATCH (uc)-[:HAS_SCREEN]->(scr:Screen)
    WHERE coalesce(scr.formless, false) = true
  }
OPTIONAL MATCH (uc)-[:USES_FORM]->(f:Form)
OPTIONAL MATCH (c:Component)-[:HAS_INBOUND_ACTION]->(f)
WITH uc, f, collect(DISTINCT c) AS inbound_components
WHERE f IS NULL OR size(inbound_components) = 0
RETURN uc.id AS uc_id,
       coalesce(f.id, '<no-form>') AS form_id,
       CASE WHEN f IS NULL THEN 'no-form' ELSE 'no-inbound-action' END AS reason

Any row in the result set is a blocker. The check fails.

Condition 2 — QA evidence references a natural entrypoint

The check is satisfied when at least one QA evidence artifact for the UC explicitly records a navigation step from a parent screen to the UC's Form via a captured HAS_INBOUND_ACTION affordance.

Formless screens. When the UC's screen is formless = true there is no Form to navigate to; the natural entrypoint is entry onto the screen route itself. Acceptable evidence is a QA artifact that reaches the screen's canonical route through the app — a nav item, a link, or, for a root entrypoint (route = '/'), direct navigation to the root, which IS the natural entry (nothing sits above the root to click through from). A non-root formless screen with no in-app path to its route still fails Condition 2.

The reviewer reads the QA artifacts (.tl/tasks/UC###/qa-*.md and linked screenshots / Playwright traces). Acceptable evidence shapes:

  • A Playwright trace whose first navigation step opens the parent screen at its canonical route, followed by a click on a locator matching a HAS_INBOUND_ACTION.label value, followed by an assertion at the target Form's route.
  • A QA report section "Entrypoint path" listing Parent screen → affordance label → target Form, with a screenshot of the parent screen rendering the affordance.
  • An E2E test file imported by the test suite whose journey assertion starts from a parent route and reaches the target Form via an affordance click — and which produced output at Step 6a above.

If no such evidence is found, the check fails for the UC.

Gate Decision

ConditionAction
Both conditions hold for every non-exempt affected UCPROCEED; record nav-actions-GREEN:<uc_id>,<uc_id>,… as evidence (one per affected UC); proceed to Step 8 with PASS-family headline allowed
Condition 1 fails for any non-exempt affected UCREFUSE VERIFIED — emit REVIEW APPLIED — BLOCKED (nav-actions-missing); the Code judgment line is CHANGES REQUESTED
Condition 1 holds but Condition 2 fails for any non-exempt affected UCREFUSE VERIFIED — emit REVIEW APPLIED — BLOCKED (nav-actions-no-natural-entrypoint-evidence); verdict is CHANGES REQUESTED
UC is exempt under actor=SYSTEM / has_ui=false / entrypoint_type ∈ {deep-link-only, embed-only} AND the exemption is recorded on the UseCase node OR carried by a signed exception (W4)EXEMPT; record nav-actions-EXEMPT:<uc_id>:<reason> and proceed
UC's HAS_SCREEN screen has formless=true (self-justifying; no signed exception) AND Condition 2 holds against the screen routeEXEMPT for Condition 1; record nav-actions-EXEMPT:<uc_id>:formless and proceed. If Condition 2 fails, refuse as usual (nav-actions-no-natural-entrypoint-evidence)

VERIFIED refused if nav-actions are missing or the QA evidence does not reference a natural entrypoint — override requires signed exception (W4). The signed-exception schema is the same one used by the W1 repo-wide check gate; until W4 lands, the only override path is a signed exception filed under the schema W4 will publish. There is no inline operator-prompt override at this gate.

Project-kind interaction

project_kind: prototype does NOT relax this gate. A prototype that ships an actor-triggered UC without a populated nav-actions section or without natural-entrypoint QA evidence still has VERIFIED refused at this gate. project_kind governs only the W4 PR/CI carve-outs for direct-strategy releases.

See nacl-tl-core/references/config-schema.md for project_kind and nacl-sa-ui/references/reachability.cypher for the full query templates.

Recording the Evidence

When the check passes for every non-exempt affected UC, write nav-actions-GREEN:<uc-id>,<uc-id>,… (comma-separated) to the review artifact's Evidence section and to Task.verification_evidence alongside any test-GREEN / repo-checks-GREEN evidence already written. For exempt UCs, write nav-actions-EXEMPT:<uc-id>:<reason> on a separate line.

When the gate refuses, write the closed Codex Status: BLOCKED with workflow detail nav-actions-missing or nav-actions-no-natural-entrypoint-evidence. Do NOT promote the verdict to APPROVED. Do NOT proceed to Step 8 verdict assignment with any PASS-family headline.

Worked example — Project-Beta UC-100 missing-upload-button

Project-Beta UC-100 ("Upload audio") was shipped with a fully specified FORM-Upload (fields, validation, mutation) and a working /upload route, yet the catalog page at /catalog carried no upload button. UC-100's review at the time emitted REVIEW COMPLETE because the page-local Form spec was satisfied. The Nav-actions consumer check would have caught the gap:

  1. Condition 1 — nav_actions_consumer_check with $affected_uc_ids = ['UC-100'] returns one row {uc_id: 'UC-100', form_id: 'FORM-Upload', reason: 'no-inbound-action'} because no Component carried a HAS_INBOUND_ACTION edge to FORM-Upload.
  2. The check FAILS. Headline becomes REVIEW APPLIED — BLOCKED (nav-actions-missing); verdict CHANGES REQUESTED; action required: "add HAS_INBOUND_ACTION edges per nacl-sa-ui/SKILL.md Nav Actions subsection; re-run /nacl-sa-ui navigation to capture the catalog page upload CTA; re-submit for review."

The methodology stops the false-PASS at the review boundary instead of letting it ship and surface as a production-only "where is the upload button" report.


Stub Verification Gate (Mandatory)

CRITICAL: Before the review can proceed, the agent MUST verify stubs. This gate runs before any code quality checks.

Procedure

  1. Read .tl/stub-registry.json and filter entries for the current task
  2. Read .tl/tasks/{id}/stub-report.md if it exists
  3. Scan all files listed in the result artifact for markers: TODO, FIXME, STUB, MOCK, HACK
  4. Apply classification from nacl-tl-core/references/stub-tracking-rules.md

Gate Decision

ConditionAction
CRITICAL stubs foundBLOCK -- review impossible, return to developer
Orphaned stubs (no UC reference)BLOCK -- all stubs must be bound to a UC
WARNING stubs (count <= 3)FLAG in review, proceed with caution
WARNING stubs (count > 3)VALIDATE JUSTIFICATION — each stub comment must match the ticket-reference regex (see below); any that fail force phase rollback
No stubs or only INFOPROCEED normally

Warning Stub Justification Requirement

When WARNING stub count exceeds 3, each stub justification MUST satisfy the following regex (case-insensitive):

(UC|TECH|FR|BUG)-?\d+|https?://

The agent MUST scan the comment text of every WARNING stub and test it against this pattern. If any stub comment fails the regex match:

  1. Set the phase status back to in_progress.
  2. Halt the review and emit:
REVIEW HALTED — UNVERIFIED (stubs lack ticket references)

The following stub justifications do not contain a valid ticket ID or URL:
  - <File:Line>: "<comment text>"
  - ...

Required format: reference a ticket ID (e.g. UC014, TECH-042, FR-7, BUG99)
or a full URL (https://...) in each stub comment.

Action: update stub comments to include ticket references, re-run /nacl-tl-stubs, resubmit for review.
Run: /nacl-tl-dev-be UC### --continue  |  /nacl-tl-dev-fe UC### --continue  |  /nacl-tl-dev TECH### --continue

A stub comment that passes the regex but still provides no meaningful context is a MAJOR issue recorded in the review — but does not force rollback. Only the absence of any ticket/URL token triggers rollback.

Example acceptable justification:

// STUB(UC014): placeholder until payment gateway is integrated — TECH-042

Example acceptable (URL):

// TODO: replace with real API — https://linear.app/team/issue/BACK-77

Example unacceptable (free-text only — triggers rollback):

// TODO: add real implementation later
// TODO: see backlog

Frontend-Specific Stub Checks (--fe only)

  • Hardcoded mock data in components (arrays with test names/emails)
  • // TODO: replace with real API call comments
  • MSW handlers that should be removed from production code
  • Placeholder images (via.placeholder.com, /placeholder.png)
  • Placeholder text (Lorem ipsum, Test, Sample)
  • console.log statements in component code

If Gate BLOCKS

Set the phase status back to in_progress, display the blocking stubs, and exit:

Stub Gate: BLOCKED

Task: UC### [Title]
Reason: Critical stubs detected

| ID | File:Line | Severity | Description |
|----|-----------|----------|-------------|
| STUB-001 | src/orders/order.service.ts:45 | CRITICAL | Empty getOrders() |

Action: Resolve all CRITICAL stubs, re-run /nacl-tl-stubs, resubmit for review.
Run: /nacl-tl-dev-be UC### --continue  |  /nacl-tl-dev-fe UC### --continue  |  /nacl-tl-dev TECH### --continue

Workflow

Step 1: Read Task Files

Read ALL relevant files for the identified review mode.

Backend (--be):

.tl/tasks/UC###/
  task-be.md         # What was supposed to be implemented (backend)
  test-spec.md       # Expected test cases
  impl-brief.md      # Implementation guidelines
  acceptance.md      # Acceptance criteria to verify
  result-be.md       # Development results to review

Frontend (--fe):

.tl/tasks/UC###/
  task-fe.md         # What was supposed to be implemented (frontend)
  test-spec-fe.md    # Expected RTL test cases
  impl-brief-fe.md   # UI implementation guidelines
  acceptance.md      # Acceptance criteria to verify
  result-fe.md       # Development results to review

TECH (no flag):

.tl/tasks/TECH###/
  task.md            # What was supposed to be implemented
  result.md          # Development results to review

Step 2: Update Status to in_review

Set the appropriate phase in status.json:

  • BE: phases.review_be = "in_review"
  • FE: phases.review_fe = "in_review"
  • TECH: status = "in_review"

Step 3: Verify Acceptance Criteria (requirements traceability)

Enumerate every acceptance criterion / REQ in acceptance.md as its own row — do not collapse them into the category groups (Functional, Business Rules, Error Handling, Performance, Security). Category-grouped review lets a single missing requirement hide inside a mostly-passing group; a per-criterion pass is the cheapest defence against the "missing-requirement" defect class (e.g. an AI-call audit log the spec demands but no code writes).

For each criterion, establish three facts before scoring:

  • Implemented? the code under review actually does what the criterion requires — confirmed by reading the runtime that produces the behaviour (Step 4a cross-file trace), not by the presence of a plausibly-named function. A "feature" that calls the wrong runtime (dead config) is NOT implemented.
  • Reachable? the behaviour is reachable end-to-end from a real entrypoint — for UI-affecting criteria reuse the Nav-actions natural-entrypoint evidence (see the Nav-actions consumer check) as the reachability witness.
  • Tested? a test or QA path exercises it.

Score each criterion PASS / PARTIAL / FAIL. A criterion implemented but unreachable — or implemented but untested where the spec demands a test — is at most PARTIAL. A criterion not implemented, or implemented against the wrong runtime, is FAIL. PARTIAL means partly met with a gap that does not block (e.g., happy path covered but an edge case missing); the verdict aggregator decides promotion. If any of the three facts (implemented / reachable / tested) cannot be positively confirmed from the code or tests, score the criterion at most PARTIAL and record the unconfirmed fact — never PASS on absence of evidence.

Step 4: Code Quality Review

Apply the appropriate checklist (see detailed checklists below).

4a. Cross-file trace (Mandatory)

The change under review is the diff, but you MUST judge it in context — read the files the diff depends on and the files that depend on it, using the actual repo (not just the diff hunks):

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
27
Forks
4
Last commit
Sep 2026
Advanced
Item type
skill
Key
nacl-tl-review
Source
github.com/itsalt/nacl