Repository navigation
Conversation
…HOME
The live-system guards decide "is this production?" from
_real_platform_state_root(), which read os.path.expanduser("~") — on POSIX
just $HOME. But monkeypatch.setenv("HOME", tmp_path) is THE hermetic
isolation idiom here (51 test files). So under that idiom a test's own
tmpdir WAS the production root, and a hermetic board at
<tmp>/.hermes/kanban.db WAS the live board: #853's connect() gate refused
it.
Measured red, 2 files / 24 tests:
tests/gateway/test_kanban_dispatcher_standby.py 21 errors
tests/tools/test_execute_code_session_provenance.py 3 failed (child proc)
Anchor on the passwd entry instead. It is a property of the UID, so it does
not move when a process rewrites $HOME — which is exactly the discriminator
between "the operator's real root" and "a test redirected HOME here". The
old docstring's requirement (not reachable via a monkeypatchable Path.home)
is preserved; $HOME only ever aliased the passwd entry when nothing had
redirected it. Falls back to expanduser when pwd is unavailable (Windows) or
names a non-existent dir, because a bogus anchor would point the deny-list
at a root nothing resolves to and disarm the guard silently.
Fixed at the shared definition, so both members of the class get it: the
kanban board gate and hermes_state's state.db guard read the same function.
Verified:
standby 21 passed (was 21 errors); provenance 8 passed (was 3 failed)
measured FP trip set: 2 files -> 0 (harness re-run, not grepped)
two-door control on the #858 stack: 6/6 live doors REFUSED, effect-free
(no .init.lock, no .bak, no ghost db), non-live control still ALLOWED
real ~/.hermes still refused from a test context, incl. under a
redirected $HOME; fleet-brick check ALLOWED (production not bricked)
mutation battery 4/4 KILLED (revert to expanduser; Path.home(); account
home = $HOME; account home always None)
tests/hermes_state/ + kanban guard suite: 294 passed, 1 skipped
Card t_c64b9d44. Found by argus reviewing #858; the defect is #853's.
Collaborator
Author
FleetReviewReviewed with 2 of 3 model families — openai unavailable. Confidence: 3/5 Findings
FleetReview provenance · models: C=claude-code-opus-5, D=grok-4.6, G=grok-4.6 · cost: $5.87 · duration: 22m 36s · rounds: 1 · files examined: 2 |
Kyzcreig
added a commit
that referenced
this pull request
Sep 22, 2026
fork/main landed multi-repository operator survivors (#865 family): both claim flags became `action="append"` and each value may carry a `<workspace-relative-repo>=` qualifier, and `_verified_explicit` changed shape from "return one ref" to "return {repository-key-or-None: ref}". This branch had changed the SAME function to bind each claim to the card. Neither side is droppable, so both are kept: * `_verified_explicit(task_id, ...)` keeps the per-claim loop and the qualifier split from fork/main, and applies the binding, the RemoteUnavailable split and the unbound/weak-corroboration recording to EACH claim before it is filed under its repository key. * `_external` keeps fork/main's multi-ref explicit branch and this branch's `_reusable(previous)` gate on the cleanup path -- an unbound claim still never becomes standing delete authority. * `complete_task` takes `Sequence[str]` claims AND `survivor_unbound`. * The `--survivor-ref`/`--survivor-pr` help carries both contracts: the task-naming requirement and the repeatable `<repo>=` qualifier. Test-side: fork/main added 17 happy-path tests driving `survivor_pr=PR` against the `remote` fixture, whose `headRefName` is UNRELATED by design so this file's refusal tests keep their teeth. Under the binding those claims are correctly refused, so each now calls the existing `names_card(remote, tid)` helper -- the same declawing r2 applied to the three pre-existing happy paths. No production behaviour is relaxed for them; the refusal tests are untouched. `test_the_help_documents_the_task_naming_requirement` tracks the new `[REPO=]` metavars. Verified (python3.14, PYTEST_ADDOPTS cleared, private --basetemp, serial): 226 passed -- survivor + external-survivor + binding + stale-bases + authority + tools/test_kanban_tool_survivor + pr-gate Refs: kanban t_de2e348e.
Collaborator
Author
Collaborator
Author
|
Reopened — closed one step early: #874 is still in the merge queue, not merged. Will close by content once it lands. — apollo |
Collaborator
Author
|
Landed by content on main via stack tip #874 (merged 2026-09-23T03:27:59Z; this head is an ancestor of it). Closing the ghost PR — apollo/fr-pause-0922. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the FALSE POSITIVE in #853's
connect()gate. Found by argus reviewing#858; the defect is #853's, so it lands on #853's branch and #858 inherits it.
The bug
Both live-system guards decide "is this production?" from
hermes_state._real_platform_state_root(), which reados.path.expanduser("~")— on POSIX, just
$HOME.But
monkeypatch.setenv("HOME", tmp_path)is THE hermetic-isolation idiom inthis repo (51 test files use it). Under that idiom the test's own tmpdir IS the
platform-default production root for the process, so a hermetic board at
<tmp>/.hermes/kanban.dbIS the live board — and the gate refused it.Measured red, 2 files / 24 tests:
tests/gateway/test_kanban_dispatcher_standby.pyLiveBoardWriteRefusedat setuptests/tools/test_execute_code_session_provenance.pyThe fix — 4 functional lines
Anchor on the passwd entry instead of
$HOME. It is a property of the UID,so it does not move when a process rewrites
$HOME— which is exactly thediscriminator between "the operator's real root" and "a test redirected HOME
here".
This is a structural discriminator, not a per-test marker. A
@pytest.mark.live_system_guard_bypassequivalent was the obvious seam (thestate.db guard has one) but it is a remember-to-do-it mitigation — the same
shape as the opt-in
HERMES_KANBAN_SANDBOX=1that already failed twice(2026-08-08, 2026-09-21). A guard that fires on the standard isolation idiom
teaches people to disarm it globally; keeping it precise is what keeps it armed.
The old docstring's actual requirement — not reachable through a monkeypatchable
Path.home()— is preserved.$HOMEonly ever aliased the passwd entry whennothing had redirected it.
Falls back to
expanduserwhenpwdis unavailable (Windows) or names anon-existent dir (service accounts, some container images): a bogus anchor would
point the deny-list at a root nothing resolves to and disarm the guard silently.
Fixed at the shared definition, so both members of the class get it — the
kanban board gate and
hermes_state'sstate.dbguard read the same function.Verification
.init.lock, no.bak, no ghost db), non-live scratch control still ALLOWED~/.hermes/kanban.dbfrom a live worker env — production not bricked$HOME-redirecting kanban files, not grepped)test_kanban*.pyAcceptance 3 note: argus's
argus_two_door.pydeclares its synthetic live boardproduction by faking
$HOME— the exact classification this PR removes, so itdies on its own seed assert. Rather than weaken its assertions I re-ran the same
six doors with the root declared through
hermes_state._STATE_DB_GUARD_EXTRA_DENY_ROOTS, the documented injection pointtests/conftest.pyand the guard's own test suite already use.Acceptance 7 note: the card predicted 1023 passed. The base tree measures the
same 1019 / 5 / 3 — that count was taken against a different tree state, not
regressed by this PR. The failure sets diff clean, so the delta this change
causes is zero.
Mutation battery (each a different way to get the anchor wrong):
M4 matters on its own: it proves the fallback is gated, not load-bearing by
accident.
New tests (
tests/hermes_state/test_production_root_anchor.py, 8 tests) pinboth directions. A test that only pinned "the tmpdir isn't production" would
pass just as well if the guard went blind entirely — the failure mode that is
far worse than the false positive — so the real account root is pinned as
still-production, including while
$HOMEis redirected.Card t_c64b9d44.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.