You are a senior code reviewer preparing to review code changes.

## Code Changes

```diff
diff --git a/expert_build/prompts.py b/expert_build/prompts.py
index 8144a2d..53ff11f 100644
--- a/expert_build/prompts.py
+++ b/expert_build/prompts.py
@@ -73,6 +73,8 @@
 - Include commands, paths, config values when relevant
 - Do NOT include opinions or subjective assessments
 - Aim for 3-8 beliefs per entry (not every sentence is a belief)
+- Set "accept" to true if the claim is well-supported by the source material, \
+false if it is vague, speculative, or poorly supported
 
 ---
 
@@ -83,7 +85,7 @@
 ---
 
 Respond with ONLY this JSON array (no other text):
-[{{"id": "<kebab-case-id>", "claim": "<one-line factual claim>", "source": "<path to entry file>", "source_url": "<url from SOURCE_URL in header, or empty string>"}}]
+[{{"id": "<kebab-case-id>", "claim": "<one-line factual claim>", "accept": true, "source": "<path to entry file>", "source_url": "<url from SOURCE_URL in header, or empty string>"}}]
 """
 
 EXAM_ANSWER = """\
diff --git a/expert_build/propose.py b/expert_build/propose.py
index b7cd699..8de129b 100644
--- a/expert_build/propose.py
+++ b/expert_build/propose.py
@@ -252,10 +252,11 @@ def _build_dedup_context(
 
 
 def auto_accept_proposals(filepath: str):
-    """Rewrite all [ACCEPT/REJECT] markers to [ACCEPT] in a proposals file."""
+    """Rewrite all [ACCEPT/REJECT] and [REJECT] markers to [ACCEPT] in a proposals file."""
     path = Path(filepath)
     text = path.read_text()
     text = re.sub(r'\[ACCEPT/REJECT\]', '[ACCEPT]', text)
+    text = re.sub(r'\[REJECT\]', '[ACCEPT]', text)
     path.write_text(text)
 
 
@@ -364,7 +365,7 @@ def cmd_propose_beliefs(args):
     if not appended:
         with output.open("w") as f:
             f.write("# Proposed Beliefs\n\n")
-            f.write("Edit each entry: change `[ACCEPT/REJECT]` to `[ACCEPT]` or `[REJECT]`.\n")
+            f.write("Review each entry: change `[REJECT]` to `[ACCEPT]` to keep, or vice versa.\n")
             f.write("Then run: `expert-build accept-beliefs`\n\n")
             f.write("---\n\n")
             f.write(f"**Generated:** {date.today().isoformat()}\n")
@@ -440,7 +441,8 @@ async def run_batches():
                 claim = b.get("claim", "")
                 source = b.get("source", "")
                 source_url = b.get("source_url", "")
-                f.write(f"### [ACCEPT/REJECT] {bid}\n")
+                verdict = "[ACCEPT]" if b.get("accept", True) else "[REJECT]"
+                f.write(f"### {verdict} {bid}\n")
                 f.write(f"{claim}\n")
                 f.write(f"- Source: {source}\n")
                 f.write(f"- Source URL: {source_url or 'none'}\n\n")
diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py
index 1ce7775..798c976 100644
--- a/tests/test_pipeline.py
+++ b/tests/test_pipeline.py
@@ -92,6 +92,19 @@ def test_preserves_already_accepted(self, tmp_path):
         assert text.count("[ACCEPT]") == 2
         assert "[ACCEPT/REJECT]" not in text
 
+    def test_converts_reject_to_accept(self, tmp_path):
+        f = tmp_path / "proposals.md"
+        f.write_text(
+            "### [ACCEPT] good-belief\n"
+            "Text\n"
+            "### [REJECT] weak-belief\n"
+            "Text\n"
+        )
+        auto_accept_proposals(str(f))
+        text = f.read_text()
+        assert text.count("[ACCEPT]") == 2
+        assert "[REJECT]" not in text
+
     def test_no_markers_is_noop(self, tmp_path):
         f = tmp_path / "proposals.md"
         original = "### ACCEPT belief-one\nText\n"
diff --git a/tests/test_propose.py b/tests/test_propose.py
index e96eced..42fe6ec 100644
--- a/tests/test_propose.py
+++ b/tests/test_propose.py
@@ -37,10 +37,10 @@ def make_args(input_dir, output="proposed-beliefs.md", batch_size=2, model="test
     )
 
 
-def _json_beliefs(*beliefs):
+def _json_beliefs(*beliefs, accept=True):
     """Helper to build a JSON response from (id, claim) tuples."""
     return json.dumps([
-        {"id": b[0], "claim": b[1], "source": "entry.md", "source_url": ""}
+        {"id": b[0], "claim": b[1], "accept": accept, "source": "entry.md", "source_url": ""}
         for b in beliefs
     ])
 
@@ -315,3 +315,45 @@ def invoke_side_effect(prompt, model=None, timeout=None):
     assert "belief-1" in content
     assert "belief-2" in content
     assert "belief-3" in content
+
+
+def test_accept_verdict_from_llm(entries_dir, work_dir):
+    """LLM's accept=true produces [ACCEPT] in output."""
+    (entries_dir / "entry0.md").write_text("# Entry\nContent")
+
+    output = work_dir / "proposed-beliefs.md"
+    args = make_args(entries_dir, output=str(output), batch_size=5)
+
+    def invoke_side_effect(prompt, model=None, timeout=None):
+        return _json_beliefs(("good-belief", "A solid claim."), accept=True)
+
+    with patch("expert_build.propose.check_model_available", return_value=True), \
+         patch("expert_build.propose.invoke", new_callable=AsyncMock, side_effect=invoke_side_effect), \
+         patch("expert_build.propose._load_existing_beliefs", return_value=[]), \
+         patch("expert_build.propose._has_embeddings", return_value=False):
+        cmd_propose_beliefs(args)
+
+    content = output.read_text()
+    assert "### [ACCEPT] good-belief" in content
+    assert "### [REJECT]" not in content
+
+
+def test_reject_verdict_from_llm(entries_dir, work_dir):
+    """LLM's accept=false produces [REJECT] in output."""
+    (entries_dir / "entry0.md").write_text("# Entry\nContent")
+
+    output = work_dir / "proposed-beliefs.md"
+    args = make_args(entries_dir, output=str(output), batch_size=5)
+
+    def invoke_side_effect(prompt, model=None, timeout=None):
+        return _json_beliefs(("weak-belief", "A vague claim."), accept=False)
+
+    with patch("expert_build.propose.check_model_available", return_value=True), \
+         patch("expert_build.propose.invoke", new_callable=AsyncMock, side_effect=invoke_side_effect), \
+         patch("expert_build.propose._load_existing_beliefs", return_value=[]), \
+         patch("expert_build.propose._has_embeddings", return_value=False):
+        cmd_propose_beliefs(args)
+
+    content = output.read_text()
+    assert "### [REJECT] weak-belief" in content
+    assert "### [ACCEPT]" not in content

```

## Your Task

Analyze the diff and identify what additional information you need to render confident verdicts.
Do NOT render verdicts yet. Only request observations.

## Available Observation Tools

| Tool | Purpose | When to use |
|------|---------|-------------|
| `exception_hierarchy` | Show exception MRO and subclasses | Retry logic, exception handling |
| `raises_analysis` | What exceptions a function raises | New function calls, error paths |
| `call_graph` | What a function calls | Impact analysis |
| `find_usages` | Where a symbol is used (with prod/test split) | Quick integration lookup |
| `find_callers` | Caller analysis with prod/test split and calling context | Method signature changes, return type changes, constructor modifications, integration verification |
| `test_coverage` | Find tests for a file (uses coverage-map if available) | Test coverage claims |
| `coverage_map_tests` | Find tests covering a file (from coverage-map.json) | Precise test coverage from actual execution |
| `coverage_map_files` | Find files covered by tests matching a pattern | Impact analysis for test changes |
| `function_body` | Full source of a function/method | Need complete function context beyond diff hunks |
| `file_imports` | Extract imports from a file | Verify import changes, check dependencies |
| `project_dependencies` | Get pyproject.toml/requirements.txt | Verify new imports have dependencies |
| `related_test_files` | Find test files for a source file | Discover tests by naming, imports, and coverage map |
| `class_hierarchy` | Show base classes and their `__init__` signatures | Class changes its parent, modifies `__init__`, or uses `super()` |
| `symbol_migration` | Check if a rename is complete across the repo | Symbol renamed in diff — verify old name is fully removed |
| `generator_info` | Report whether a function uses `yield` | Function might be a generator — affects return value semantics |

## What to Look For

1. **Exception handling**: Any `retry_if_exception_type`, `except`, or exception class references
2. **New dependencies**: Calls to external libraries where you don't know the error behavior
3. **Behavioral changes**: Modified logic where you need to verify callers/callees
4. **Test claims**: References to tests you can't see in the diff
5. **Inheritance changes**: Class definition changes, new base classes, `super()` calls
6. **Renames**: Symbols that appear to have been renamed in the diff
7. **Factory methods**: Calls to `@classmethod` / `@staticmethod` constructors (e.g. `Result.error(...)`) — request `function_body` to see their implementation

## Output Format

Output a JSON array of observation requests:

```json
[
  {"name": "descriptive_name", "tool": "tool_name", "params": {"param": "value"}},
  ...
]
```

If you don't need any observations (simple changes, all context is in the diff), output:

```json
[]
```

## Examples

For a diff containing `retry_if_exception_type((OSError, httpx.TransportError))`:
```json
[
  {"name": "oserror_subclasses", "tool": "exception_hierarchy", "params": {"class_name": "builtins.OSError"}},
  {"name": "transport_errors", "tool": "exception_hierarchy", "params": {"class_name": "httpx.TransportError"}}
]
```

For a diff adding a new function that calls `oauth_client.get_access_token()`:
```json
[
  {"name": "oauth_exceptions", "tool": "raises_analysis", "params": {"file_path": "src/auth/oauth.py", "function_name": "get_access_token"}}
]
```

For a diff modifying a method but you need the full function to verify:
```json
[
  {"name": "full_getattr", "tool": "function_body", "params": {"file_path": "src/proxy.py", "function_name": "__getattr__"}}
]
```

For a diff changing a method signature or return type (verify all callers):
```json
[
  {"name": "handle_request_callers", "tool": "find_callers", "params": {"symbol": "handle_request"}}
]
```

For a diff adding new imports (e.g., `import httpx`):
```json
[
  {"name": "file_imports", "tool": "file_imports", "params": {"file_path": "src/client.py"}},
  {"name": "project_deps", "tool": "project_dependencies", "params": {}}
]
```

For a diff calling a factory method like `ModuleResult.error_result(msg)`:
```json
[
  {"name": "error_result_body", "tool": "function_body", "params": {"file_path": "src/models.py", "function_name": "error_result"}}
]
```

For a diff where a class changes its parent class:
```json
[
  {"name": "client_hierarchy", "tool": "class_hierarchy", "params": {"class_name": "MyClient", "file_path": "src/client.py"}}
]
```

For a diff that renames a symbol (e.g., `OldClient` to `NewClient`):
```json
[
  {"name": "client_rename", "tool": "symbol_migration", "params": {"old_name": "OldClient", "new_name": "NewClient"}}
]
```

For a diff modifying a function that might be a generator:
```json
[
  {"name": "process_gen", "tool": "generator_info", "params": {"file_path": "src/pipeline.py", "function_name": "process_items"}}
]
```

Now analyze the diff above and output your observation requests as JSON:
