ci-fresh-checkout-gitignored-state-file-unit-tests
I've written the solution to ~/SOLUTION.md.
One important note on verification: I could not execute the repo tests here. The Hermes4Friends/infrastructure repository is private and not checked out anywhere on this machine, and git clone fails because no GitHub credentials are available. So the "Verification" section in the solution documents the exact commands and the expected before/after numbers (from the CI run and the known-good commit 403172a), rather than a live run I performed. If you give me a checkout of the repo, I'll run the fix end-to-end and confirm the numbers.
~/SOLUTION.md)Root cause: known-friends.json is gitignored (.gitignore:34) and absent on a fresh CI checkout. Four tests all depend on it, via three distinct mechanisms:
STATE_FILE captured at import; missing file → load_friends_data() raises FileNotFoundError → parser.error prints the state-file message instead of unknown friend 'nonexistentfriend'.sync_keys() early-returns rc 0 with errors=['State file not found…'] when the file is missing, so list_keys() → RuntimeError (GAP-032) never fires._REPO_STATE_FILE hardcoded to the real repo-root file; subprocess reads the real file so parent monkeypatch can't help.Fix (test-side only, no production changes), driven by the tracked known-friends.example.json:
1. monkeypatch.setattr(gen_compose, 'STATE_FILE', <tmp_path copy>) so main() reaches the unknown-friend lookup → exit 2.
2. Pass a tmp_path copy of known-friends.example.json as the sync state-file arg → proceeds to list_keys() → rc 1 + clean error line.
3. New repo_state_copy fixture copies the example → REPO_ROOT/known-friends.json for the duration of the two fallback tests, then restores/deletes in teardown (subprocess and _repo_state_count() both read the same real file → agree on 2 friends).
The markdown includes self-contained fixture code for all three files and a fresh-checkout verification procedure (mv known-friends.json away → run suite → restore).
# Evidence - Problem class: ci-fresh-checkout-gitignored-state-file-unit-tests - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-27T21:46:14.730Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Hermes4Friends CI #405 unit tests failed on a fresh checkout while local pytest was green. Root cause: 4 tests depend on the repo-root known-friends.json state file which is GITIGNORED (.gitignore:34) and absent in CI. Failing tests: (1) test_gen_compose.py::TestCLIArgs::test_unknown_friend_exits_two_with_clear_message \u2014 gen-compose.py module-level STATE_FILE (os.environ.get('H4F_STATE_FILE', str(REPO_ROOT/'known-friends.json'))) captured at import; when the file is missing, load_friends_data() raises FileNotFoundError and parser.error prints the state-file message instead of the unknown-friend message. (2) test_openrouter_cli_safety.py::test_sync_missing_key_clean_error_no_traceback \u2014 openrouter.py sync_keys() returns EARLY with result[errors]=['State file not found: ...'] rc 0 when the state file is missing, so the missing-key RuntimeError (GAP-032 path) never fires; the test needs the state file to EXIST so sync proceeds to list_keys() \u2192 RuntimeError \u2192 main() catches \u2192 rc 1. (3)+(4) test_provisioner_cli.py fallback tests x2 \u2014 provisioner.py _REPO_STATE_FILE is hardcoded to Path(__file__).resolve().parent.parent.parent/'known-friends.json', absent in CI; the subprocess reads the REAL file so parent-process monkeypatch won't help.", "environment": "Hermes4Friends/infrastructure, GitHub Actions ubuntu-latest, Python 3.12, pytest", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "ci-fresh-checkout-gitignored-state-file-unit-tests", "provider": "openrouter", "solved_at": "2026-08-27T21:46:14.730Z", "version": "origin main 5abd58e (2026-08-27)"}I've written the solution to ~/SOLUTION.md.
One important note on verification: I could not execute the repo tests here. The Hermes4Friends/infrastructure repository is private and not checked out anywhere on this machine, and git clone fails because no GitHub credentials are available. So the "Verification" section in the solution documents the exact commands and the expected before/after numbers (from the CI run and the known-good commit 403172a), rather than a live run I performed. If you give me a checkout of the repo, I'll run the fix end-to-end and confirm the numbers.
~/SOLUTION.md)Root cause: known-friends.json is gitignored (.gitignore:34) and absent on a fresh CI checkout. Four tests all depend on it, via three distinct mechanisms:
STATE_FILE captured at import; missing file → load_friends_data() raises FileNotFoundError → parser.error prints the state-file message instead of unknown friend 'nonexistentfriend'.sync_keys() early-returns rc 0 with errors=['State file not found…'] when the file is missing, so list_keys() → RuntimeError (GAP-032) never fires._REPO_STATE_FILE hardcoded to the real repo-root file; subprocess reads the real file so parent monkeypatch can't help.Fix (test-side only, no production changes), driven by the tracked known-friends.example.json:
1. monkeypatch.setattr(gen_compose, 'STATE_FILE', <tmp_path copy>) so main() reaches the unknown-friend lookup → exit 2.
2. Pass a tmp_path copy of known-friends.example.json as the sync state-file arg → proceeds to list_keys() → rc 1 + clean error line.
3. New repo_state_copy fixture copies the example → REPO_ROOT/known-friends.json for the duration of the two fallback tests, then restores/deletes in teardown (subprocess and _repo_state_count() both read the same real file → agree on 2 friends).
The markdown includes self-contained fixture code for all three files and a fresh-checkout verification procedure (mv known-friends.json away → run suite → restore).
# Evidence - Problem class: ci-fresh-checkout-gitignored-state-file-unit-tests - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-27T21:46:14.730Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Hermes4Friends CI #405 unit tests failed on a fresh checkout while local pytest was green. Root cause: 4 tests depend on the repo-root known-friends.json state file which is GITIGNORED (.gitignore:34) and absent in CI. Failing tests: (1) test_gen_compose.py::TestCLIArgs::test_unknown_friend_exits_two_with_clear_message \u2014 gen-compose.py module-level STATE_FILE (os.environ.get('H4F_STATE_FILE', str(REPO_ROOT/'known-friends.json'))) captured at import; when the file is missing, load_friends_data() raises FileNotFoundError and parser.error prints the state-file message instead of the unknown-friend message. (2) test_openrouter_cli_safety.py::test_sync_missing_key_clean_error_no_traceback \u2014 openrouter.py sync_keys() returns EARLY with result[errors]=['State file not found: ...'] rc 0 when the state file is missing, so the missing-key RuntimeError (GAP-032 path) never fires; the test needs the state file to EXIST so sync proceeds to list_keys() \u2192 RuntimeError \u2192 main() catches \u2192 rc 1. (3)+(4) test_provisioner_cli.py fallback tests x2 \u2014 provisioner.py _REPO_STATE_FILE is hardcoded to Path(__file__).resolve().parent.parent.parent/'known-friends.json', absent in CI; the subprocess reads the REAL file so parent-process monkeypatch won't help.", "environment": "Hermes4Friends/infrastructure, GitHub Actions ubuntu-latest, Python 3.12, pytest", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "ci-fresh-checkout-gitignored-state-file-unit-tests", "provider": "openrouter", "solved_at": "2026-08-27T21:46:14.730Z", "version": "origin main 5abd58e (2026-08-27)"}