## Code Review

### expert_build/propose.py:cmd_propose_beliefs
VERDICT: CONCERN
CORRECTNESS: QUESTIONABLE
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: COVERED
INTEGRATION: WIRED
REASONING: The core refactor — writing proposals and saving processed entries per-batch instead of all-at-once — is correct and achieves the crash-resilience goal. However, there is one bug:

**Bug: `appended` is always `True`.** Line `appended = output.exists() and output.stat().st_size > 0` is evaluated *after* the header/separator has already been written to the file. At that point the file always exists and is non-empty, so the final print always says "Appended to" even when a new file was just created. The fix is to compute `appended` *before* the header-writing block.

**Minor inefficiency:** `_save_processed` is called with the growing `successful_entries` list each batch, re-hashing all previously processed entries. This is O(n²) in total entry hashes across batches. Not a bug — the output is correct — but for large runs it's needlessly slow. Passing only the new batch's entries and merging the result would be cleaner.

The regex change (`r"^### (?:\[ACCEPT/REJECT\]|\[?(?:ACCEPT|REJECT)\]?) (\S+)"`) correctly handles the `[ACCEPT/REJECT]` placeholder the LLM outputs, which the old regex missed. The skip-until-next-heading logic is preserved correctly.
---

### tests/test_propose.py
VERDICT: PASS
CORRECTNESS: VALID
SPEC_COMPLIANCE: N/A
ISSUE_COMPLIANCE: N/A
BELIEF_COMPLIANCE: N/A
TEST_COVERAGE: COVERED
INTEGRATION: WIRED
REASONING: Six tests that cover the key behaviors of the refactor: crash recovery (batch 1 survives batch 2 failure), all-batches-succeed happy path, dedup filtering per batch, failed-batch entries not marked processed, the regex fix for `[ACCEPT/REJECT]`, and append-to-existing-file mode. Each test properly mocks external dependencies (`invoke_sync`, `check_model_available`, `_load_existing_beliefs`, `_has_embeddings`). The `work_dir` fixture correctly creates the `.expert-build` directory that the code expects. No test covers the `appended` display-message bug noted above, but that's cosmetic.
---

### SELF_REVIEW
LIMITATIONS: Could not verify `invoke_sync` signature or error behavior since it was not found in the observations — reviewed based on mock usage in tests. Did not see the full `_load_processed` or `_filter_unprocessed` implementations, so I relied on the `_save_processed` observation to reason about the processed-entries data shape.
---

### FEATURE_REQUESTS
- Include the full function body for helper functions referenced in the diff (e.g., `_load_processed`, `_filter_unprocessed`) so reviewers can verify data-shape assumptions at boundaries.
---
