
**You ARE the reviewer - review directly.** Do not invoke any flow-next skill,
`flowctl <backend>` review command, or a nested agent/backend to perform this
review: this prompt already reached you through that machinery, and nesting it
fails inside the sandbox (app-server init) and can only self-review. Read the
diff and the repository yourself and produce the verdict in this session.

# Implementation Review: Branch Changes vs main

Review all changes on the current branch compared to main.

**Context:** You have full access to read files from the repository. The changed
paths below are the complete, exact scope of this review. Read the change with `git diff aaaaaaa..bbbbbbb`.
Explore the
codebase as needed to understand context and verify implementations. Nothing is
pre-truncated for you — fetch what you need.

## Focus Areas
auth and sessions

Pay special attention to these areas during review.

## Changed Files (`git diff --numstat`)
```
 3 files changed, 10 insertions(+), 2 deletions(-)
```

## What to review

Review this change against what was asked: the task or spec, its acceptance criteria, and the
request it came from. Look for these four things only:

1. **Wrong behaviour** in a scenario the request covers, including its edge cases (empty or
   malformed input, boundaries, concurrency the change takes part in).
2. **Regressions** in behaviour the change touches: its callers, shared or persisted state,
   data written by earlier versions.
3. **Security holes** the change opens.
4. **Overengineering in what this change added**: machinery, options, abstractions or code paths
   the request does not need. Report these as P2 with what to remove; never ask for more.

Do not review style, naming, DRY, architecture taste, or hardening beyond what the request
needs (extra shutdown paths, retries, timeouts, monitoring). Mention such observations as FYI at
most.

Every blocking finding names a concrete failing scenario: this input or state, this wrong
result. A finding that cannot name one is FYI.

Only flag issues in the **changed code** - not pre-existing patterns.

## Verdict Scope

Your VERDICT only considers P0 and P1 findings that are **introduced** by this changeset or
**directly broken** by it, and pre-existing issues that would **block shipping** this change.
P2 and P3 findings never block: list them, and the author decides.

Do NOT mark NEEDS_WORK for:
- Pre-existing issues unrelated to the change
- "Nice to have" improvements outside the change scope
- Style nitpicks in untouched code

You MAY mention these as "FYI" observations without affecting the verdict.

**Comment-as-alibi:** A comment that exists to justify a workaround or narrate
around a hack is itself a finding: it flags the underlying code. Judge severity
from the workaround, not the prose — well-written justification does not lower
it. Rewriting or deleting the comment while keeping the workaround does not
resolve the finding; the fix is the code, or the constraint encoded as an
assert, a test, or a lint rule. Never flag licensed comments: license headers,
external-constraint notes, lint suppressions with reasons, public API
contracts, issue links.

## Code-smell baseline (always-on, judgement calls — repo standards override; skip what tooling enforces)
Beyond correctness, name any of these you spot and quote the hunk (each a heuristic, never a hard violation):
Long Method · Large Class · Long Parameter List · Duplicated Code · Feature Envy (uses another object's data more than its own) · Data Clumps (same values always passed together — wants a type) · Primitive Obsession (bare primitives where a small type belongs) · Speculative Generality · Middle Man / pass-through (forwards the same arguments to another call of the same shape — a layer hiding nothing).

## Requirements coverage (only if the spec has R-IDs like `- **R1:** ...`)
If R-IDs are present, read the epic's `## Acceptance Criteria` (tolerate legacy `## Acceptance` / `## Acceptance criteria`) and emit:
| R-ID | Status | Evidence |
Status ∈ met / partial / not-addressed / deferred. After the table emit `Unaddressed R-IDs: [...]`. A non-deferred `not-addressed` R-ID forces NEEDS_WORK. If no R-IDs anywhere, skip this block entirely.
## Confidence (pick ONE anchor; no interpolation)
- **100** — definitive from code alone (mechanical: off-by-one, wrong type, swapped args).
- **75** — full path traced; a normal caller hits it; reproducible from the diff.
- **50** — depends on conditions visible but not confirmable here (e.g. can this be null? callers not in diff).
- **25** — needs runtime conditions with no direct evidence.
- **0** — speculative; don't file.
Suppression gate: drop findings below 75, EXCEPT P0 at 50+ (those survive). Emit a `Suppressed findings:` count when any dropped.
## Introduced vs pre-existing
Classify each finding: **introduced** (this diff caused or newly exposed it) or **pre_existing** (already on base, untouched — a finding on an unchanged line is pre_existing by default; confirm with `git blame`/base-file read when cheap).
Verdict gate: only `introduced` findings affect the verdict — a review whose survivors are all `pre_existing` ships. List pre-existing under `## Pre-existing issues (not blocking this verdict)` as `[sev, confidence N, introduced=false] file:line — summary`; never drop them. End with `Classification counts: N introduced, M pre_existing.`
## Protected artifacts
NEVER recommend deleting / gitignoring / removing these committed pipeline paths (flag bad CONTENT inside them, never their existence): `.flow/*`, `.flow/bin/*`, `.flow/memory/*`, `.flow/specs/*.md`, `.flow/tasks/*.md`, `docs/plans/*`, `docs/solutions/*`. Discard any such finding during synthesis; emit a `Protected-path filter:` count when any dropped.
## Output Format

For each surviving finding:
- **Severity**: P0 / P1 / P2 / P3
- **Confidence**: 0 / 25 / 50 / 75 / 100
- **Classification**: introduced / pre_existing
- **File:Line**: `path:line`, or `-` when repo-wide
- **R-IDs**: `[R1, R2]`, or `[]` when none
- **Problem**: What's wrong
- **Suggestion**: How to fix

Put `pre_existing` findings under `## Pre-existing issues (not blocking this verdict)`; never drop them.

After the findings list, emit:
- The `## Requirements coverage` table and `Unaddressed R-IDs:` line (only when the spec uses R-IDs; otherwise skip).
- A `Suppressed findings:` line tallying anchors dropped by the gate (omit when nothing was suppressed).
- A `Classification counts:` line tallying `introduced` vs `pre_existing` survivors, e.g. `Classification counts: 2 introduced, 4 pre_existing.`.
- A `Protected-path filter:` line tallying findings dropped by the protected-path filter (omit when nothing was dropped).

Be critical. Find real issues.

**Verdict gate:** only `introduced` findings affect the verdict. A review whose sole surviving findings are all `pre_existing` MUST ship. Any non-deferred `not-addressed` R-ID also forces NEEDS_WORK regardless of other findings.

## Structured tallies (fenced JSON)
After the findings (and before the verdict tag), emit exactly ONE fenced json
code block containing a single JSON object. Omit keys that do not apply; never
invent counts. Do NOT put the <verdict> tag inside the block.

Schema keys (all optional):
- `suppressed_count`: object mapping anchor strings ("0"|"25"|"50"|"75"|"100") to ints
- `classification_counts`: `{"introduced": int, "pre_existing": int}`
- `unaddressed`: array of R-ID strings (use [] when none remain unaddressed)
- `deep_findings`: array of finding objects (deep-pass only; omit on primary reviews)

Example (wrap the next line in a json fence):
{"suppressed_count":{"50":3,"25":7},"classification_counts":{"introduced":2,"pre_existing":4},"unaddressed":["R3","R5"]}

Prose tally lines (`Suppressed findings:`, `Classification counts:`, `Unaddressed R-IDs:`)
remain accepted as a logged fallback when this block is omitted.
**REQUIRED**: End your response with exactly one verdict tag:
- `<verdict>SHIP</verdict>` - Ready to merge (no blocking `introduced` findings, all R-IDs met or deferred)
- `<verdict>NEEDS_WORK</verdict>` - `introduced` issues or unaddressed R-IDs must be fixed first
- `<verdict>MAJOR_RETHINK</verdict>` - Fundamental problems, reconsider approach
- `<verdict>NEEDS_HUMAN</verdict>` - A human must adjudicate a design judgment

Use NEEDS_HUMAN only for a design judgment needing human authority; never as a
soft NEEDS_WORK. MAJOR_RETHINK remains "the approach is wrong" and requires redesign.
