### expert_build/cli.py
VERDICT: CONCERN
CORRECTNESS: QUESTIONABLE
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: PARTIAL
INTEGRATION: WIRED
REASONING: `--parallel` accepts any `int` including 0 and negative values. `asyncio.Semaphore(0)` will deadlock silently (no coroutine can ever acquire), and negative values raise `ValueError` at construction. Add validation — either `choices` or a post-parse check requiring `parallel >= 1`.

---

### expert_build/summarize.py:_prepare_source
VERDICT: PASS
CORRECTNESS: VALID
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: COVERED
INTEGRATION: WIRED
REASONING: Clean extraction of the file-reading, frontmatter-stripping, and truncation logic. Behavior is identical to the original inline code. All existing tests exercise these paths via `_summarize_one`.

---

### expert_build/summarize.py:_write_entry
VERDICT: PASS
CORRECTNESS: VALID
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: COVERED
INTEGRATION: WIRED
REASONING: Straightforward extraction. Existing tests for entry frontmatter, directory structure, and content all exercise this function. No behavioral change.

---

### expert_build/summarize.py:_summarize_one
VERDICT: CONCERN
CORRECTNESS: QUESTIONABLE
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: PARTIAL
INTEGRATION: WIRED
REASONING: Two issues. (1) The semaphore guards only `invoke()` but the manifest append and `done.add()` happen outside it. In asyncio's single-threaded model this is safe between await points, but it's fragile — if `_write_entry` ever becomes async (e.g., for async file I/O), concurrent manifest appends could corrupt the file. A comment noting the single-threaded safety assumption would be warranted. (2) No test covers the error path in parallel mode — if one of N files fails, the others should still succeed and `processed` should reflect the partial count. The `except Exception` catch-and-continue is correct but untested in the parallel context.

---

### expert_build/summarize.py:cmd_summarize
VERDICT: CONCERN
CORRECTNESS: QUESTIONABLE
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: PARTIAL
INTEGRATION: WIRED
REASONING: `asyncio.run()` from a sync CLI entry point is correct for a CLI tool. However, `asyncio.Semaphore(0)` (from `--parallel 0`) will deadlock — all coroutines block forever on `acquire()`, `asyncio.gather` never returns, and the process hangs. Add `parallel = max(1, parallel)` or validate in the argument parser. The early-return when `to_process` is empty is a nice addition. `getattr(args, "parallel", 1)` is defensive but redundant since the CLI always sets the attribute — acceptable but unnecessary.

---

### tests/test_summarize.py
VERDICT: PASS
CORRECTNESS: VALID
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: PARTIAL
INTEGRATION: WIRED
REASONING: All existing tests properly migrated from `invoke_sync` to `AsyncMock` for `invoke`. The two new parallel tests verify basic multi-file processing and the default `parallel=1` behavior. Missing: (1) no test for `--parallel 0` deadlock, (2) no test that errors in one file don't block others in parallel mode, (3) no test verifying the semaphore actually limits concurrency (admittedly hard to test). The existing coverage is adequate for a first iteration.

---

### SELF_REVIEW
LIMITATIONS: Could not verify whether `caffeinate.hold()` has any interaction with asyncio (it spawns a subprocess via `subprocess.Popen`, which should be fine since it's fire-and-forget). Did not run the test suite to confirm all mocks are correctly wired. Could not inspect whether `invoke` might itself call `asyncio.run()` internally (which would fail inside an already-running loop) — the observation shows it uses `asyncio.create_subprocess_exec`, confirming it's a proper coroutine.

---

### FEATURE_REQUESTS
- Include argparse validation patterns (choices, type functions) in observation data when reviewing CLI argument additions
- Auto-detect and flag `asyncio.Semaphore` constructed with user-controlled values that could be 0

---

**Summary**: The refactor from sync-loop to async+semaphore is well-structured and the test migration is thorough. The one actionable issue is **`--parallel 0` causing a silent deadlock** — either clamp to `max(1, parallel)` or add argument validation. The error-handling path in parallel mode should also get a test.
