Skip to content

fix(tests): hermetic kanban dispatch tests + default_assignee spawn regression - #43

Merged
sahilm-ai merged 1 commit into
mainfrom
kanban/t_259adc02
Jun 3, 2026
Merged

sahilm-ai merged 1 commit into
mainfrom
kanban/t_259adc02

Conversation

@sahilm-ai

@sahilm-ai sahilm-ai commented May 29, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

CI test (4) shard failed on every PR (confirmed on #41, #42) with deterministic failures in tests/hermes_cli/test_kanban_default_assignee.py. Two independent root causes, both surfacing as order/shard-dependent failures.

Root cause 1 — real source regression (dispatch_once)

dispatch_once checked profile_exists(row["assignee"]) — the stale DB snapshot, still None after default_assignee auto-assignment — instead of the effective row_assignee. Every auto-assigned task therefore fell into skipped_nonspawnable and never spawned.

This was the correct row_assignee form in NousResearch#27145, accidentally reverted to row["assignee"] by #34 (3146a5e81). The two default_assignee tests fail standalone, proving this is a logic bug, not test ordering. Fix: check row_assignee.

Root cause 2 — non-hermetic fixtures (del sys.modules reimport)

Three kanban test files (test_kanban_default_assignee.py, test_kanban_cli_dispatch_passthrough.py, test_kanban_per_profile_cap.py) did del sys.modules[...] + reimport in their isolation fixture.

kanban_db resolves HERMES_HOME lazily at call time (via kanban_home() → get_default_hermes_root()), so the reimport was unnecessary — and harmful. It created a second hermes_cli.kanban_db module object. Sibling files that captured the module at import time (e.g. test_kanban_core_functionality.py's top-level import ... as kb) then read process-global state (_recent_worker_exits) from the OLD module, while an in-test import ... as _kb resolved the NEW one. That split flipped test_detect_crashed_workers_protocol_violation_auto_blocks (_record_worker_exit wrote one global, detect_crashed_workers read the other) depending on test/shard order.

Fix: drop the reimport in all three fixtures. The fresh HERMES_HOME monkeypatch is sufficient.

Verification

  • All 3 target failures now pass.
  • Every tests/hermes_cli/test_kanban_*.py file passes per-file (CI's run_tests_parallel.py model).
  • Previously-polluting in-process combinations (offender files + core_functionality) now pass in any order.
  • ruff check . green.

Assertions were left untouched — they encode the real dispatcher contract; only the isolation and the source bug were fixed.

skip-review: false

Summary by CodeRabbit

  • Bug Fixes

    • Auto-assigned tasks are no longer treated as non-spawnable or quarantined under a stale assignee; dispatch and crash-loop quarantine now respect the effective assignee.
  • Tests

    • Improved fixture hermeticity and reliability for kanban board tests.
    • Added an integration test verifying quarantine logic honors effective assignees for auto-assigned tasks.

@coderabbitai

coderabbitai Bot commented May 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba7f08ab-4285-4288-9f5f-783774a1524c

📥 Commits

Reviewing files that changed from the base of the PR and between 3c3ce6da405c723497bfaee8e3ad1c754137b605 and 4081853.

📒 Files selected for processing (5)
  • hermes_cli/kanban_db.py
  • tests/hermes_cli/test_kanban_cli_dispatch_passthrough.py
  • tests/hermes_cli/test_kanban_default_assignee.py
  • tests/hermes_cli/test_kanban_dispatcher_crash_breaker.py
  • tests/hermes_cli/test_kanban_per_profile_cap.py
💤 Files with no reviewable changes (5)
  • tests/hermes_cli/test_kanban_dispatcher_crash_breaker.py
  • tests/hermes_cli/test_kanban_default_assignee.py
  • hermes_cli/kanban_db.py
  • tests/hermes_cli/test_kanban_per_profile_cap.py
  • tests/hermes_cli/test_kanban_cli_dispatch_passthrough.py

📝 Walkthrough

Walkthrough

dispatch_once now uses the task's effective assignee (row_assignee) for spawnability and quarantine checks; quarantine bookkeeping calls were updated to use row_assignee. Tests were refactored to rely on lazy HERMES_HOME resolution (removing sys.modules purging) and a new integration test verifies quarantine behavior for auto-assigned tasks.

Changes

Dispatcher Fix and Test Hermetic Isolation

Layer / File(s) Summary
Dispatcher assignee validation fix
hermes_cli/kanban_db.py
Update dispatch_once to use the effective assignee (row_assignee) for profile/spawn checks and crash-loop quarantine decisions.
Crash-loop quarantine integration test
tests/hermes_cli/test_kanban_dispatcher_crash_breaker.py
Add test_quarantine_checks_effective_assignee_for_auto_assigned_task asserting quarantine checks and recorded quarantine_blocked use the effective assignee for auto-assigned tasks.
Test fixture hermeticity refactor
tests/hermes_cli/test_kanban_cli_dispatch_passthrough.py, tests/hermes_cli/test_kanban_default_assignee.py, tests/hermes_cli/test_kanban_per_profile_cap.py
Remove sys.modules purging from isolated_kanban_home/isolated_kanban_home_with_profiles fixtures, expand hermeticity docstrings, and adjust imports to rely on lazy HERMES_HOME resolution.

Sequence Diagram(s)

(omitted — changes are small and already summarized above)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • sahilm-ti/hermes-agent#19: Modifies related crash-loop/quarantine control flow in hermes_cli/kanban_db.py; connected to assignee/quarantine behavior.

Poem

"i’m a rabbit in the code-burrow, twitching my nose,
found a stale assignee where the wild default grows,
now dispatch sees the real name — neat and bright,
tests cleaned of module-scrubs sleep sound at night,
carrots for CI, and no more spawn-time woes."

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and specifically describes the main changes: fixing hermetic kanban dispatch tests and a default_assignee spawn regression.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kanban/t_259adc02

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 29, 2026 •

Copy link
Copy Markdown

🔎 Lint report: kanban/t_259adc02 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9760 on HEAD, 9760 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5053 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@hermes_cli/kanban_db.py`:
- Around line 8321-8327: The crash-breaker path still reads the stale snapshot
row["assignee"] for quarantining and telemetry; replace those usages with the
effective assignee variable row_assignee so the same resolved fallback is used
everywhere: change calls to is_assignee_quarantined(conn, row["assignee"]) to
is_assignee_quarantined(conn, row_assignee), replace
quarantine_blocked.append(..., row["assignee"]) to use row_assignee, and pass
row_assignee into mark_quarantine_probe_task(..., row["assignee"], ...) so
quarantine checks and probe/blocked telemetry reflect the actual assignee; keep
profile_exists(row_assignee) as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e1cc8c4c-1eda-4da9-9e98-50155bac76c3

📥 Commits

Reviewing files that changed from the base of the PR and between 62a2d5886d1b0dd0b76d3589066dd560dd03df3f and 3c3ce6da405c723497bfaee8e3ad1c754137b605.

📒 Files selected for processing (4)
  • hermes_cli/kanban_db.py
  • tests/hermes_cli/test_kanban_cli_dispatch_passthrough.py
  • tests/hermes_cli/test_kanban_default_assignee.py
  • tests/hermes_cli/test_kanban_per_profile_cap.py

Comment thread hermes_cli/kanban_db.py
Comment on lines +8321 to +8327
# Check the EFFECTIVE assignee (row_assignee), not the stale DB
# snapshot (row["assignee"]). After default_assignee auto-assignment
# row_assignee holds the fallback profile while row["assignee"] is
# still None — using the snapshot here would route every
# auto-assigned task into skipped_nonspawnable and never spawn it
# (#27145 regression reintroduced by #34).
if profile_exists is not None and not profile_exists(row_assignee):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the effective assignee for the rest of the dispatch path too.

This fixes the profile_exists(...) gate, but the same stale-snapshot problem still exists a few lines below in the crash-breaker path: is_assignee_quarantined(conn, row["assignee"]), quarantine_blocked.append(..., row["assignee"]), and mark_quarantine_probe_task(..., row["assignee"], ...) still read row["assignee"]. For tasks auto-assigned this tick, that value is still None, so quarantined default assignees can bypass the breaker and the probe/blocked telemetry is wrong.

Suggested fix
-        if crash_breaker_enabled and not dry_run:
-            blocked_q, is_probe = is_assignee_quarantined(conn, row["assignee"])
+        if crash_breaker_enabled and not dry_run:
+            blocked_q, is_probe = is_assignee_quarantined(conn, row_assignee)
             if blocked_q:
-                result.quarantine_blocked.append((row["id"], row["assignee"]))
+                result.quarantine_blocked.append((row["id"], row_assignee))
                 continue
@@
         if is_probe:
             try:
-                mark_quarantine_probe_task(conn, row["assignee"], claimed.id)
+                mark_quarantine_probe_task(
+                    conn, claimed.assignee or row_assignee, claimed.id
+                )
             except Exception:
                 pass
-            result.quarantine_probes.append((claimed.id, row["assignee"]))
+            result.quarantine_probes.append(
+                (claimed.id, claimed.assignee or row_assignee)
+            )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hermes_cli/kanban_db.py` around lines 8321 - 8327, The crash-breaker path
still reads the stale snapshot row["assignee"] for quarantining and telemetry;
replace those usages with the effective assignee variable row_assignee so the
same resolved fallback is used everywhere: change calls to
is_assignee_quarantined(conn, row["assignee"]) to is_assignee_quarantined(conn,
row_assignee), replace quarantine_blocked.append(..., row["assignee"]) to use
row_assignee, and pass row_assignee into mark_quarantine_probe_task(...,
row["assignee"], ...) so quarantine checks and probe/blocked telemetry reflect
the actual assignee; keep profile_exists(row_assignee) as-is.

@sahilm-ti

Copy link
Copy Markdown
Owner

auto-review: approved, awaiting human merge + kanban_approve.

Rebase verified. 39 to 1 commit ahead; 4 files (+42/-18); MERGEABLE. The core row["assignee"] to row_assignee fix is in scope and consistent with every other reference in dispatch_once (lines 8263/8302/8343/8385/8390) — the old snapshot read was the outlier. Test-fixture changes drop the non-hermetic del sys.modules[...] + reimport pattern (correct: kanban_db resolves HERMES_HOME lazily at call time, so the fresh env is picked up without a reimport that would split process-global state).

Two red CI shards are pre-existing flakes, NOT caused by this diff:

  • test (4) → tests/hermes_cli/test_kanban_core_functionality.py: all 167 tests pass (dots to 98%), then a teardown hang (RC=143, lands in the "no tests ran / timeout before collection" bucket). Reproduced identically on main 62a2d5886 with none of PR fix(tests): hermetic kanban dispatch tests + default_assignee spawn regression #43's changes.
  • test (2) → tests/gateway/test_telegram_topic_mode.py::test_group_new_keeps_existing_reset_semantics_when_dm_topic_mode_enabled: a gateway/telegram test (unrelated to kanban dispatch), passes in isolation, fails only under full-suite cross-file state pollution.

All blocking gates green (ruff enforcement, ty diff, nix ubuntu+macos, check-attribution, check-common-ancestor, e2e, Windows footguns, supply-chain, CodeRabbit). Safe to merge; the UNSTABLE mergeStateStatus is from unrelated infra flakes, not this PR.

@sahilm-ti
sahilm-ti force-pushed the kanban/t_259adc02 branch from 3c3ce6d to a271d80 Compare June 3, 2026 15:34
sahilm-ai added a commit that referenced this pull request Jun 3, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
…e spawn regression

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.
@sahilm-ti
sahilm-ti force-pushed the kanban/t_259adc02 branch from a271d80 to 4081853 Compare June 3, 2026 17:49
@sahilm-ti

Copy link
Copy Markdown
Owner

auto-review: approved, awaiting human merge + kanban_approve.

Matrix checks (U1–U5, C1–C6): all pass. In-scope (kanban_db.py + 4 kanban test files), no deletions, no secrets, mergeStateStatus CLEAN, all CI shards green, no new type-ignore/cast, regression test added, commit identity sahilm-ai.

Code-quality (role-reviewer): APPROVED, no violations. The 4-line quarantine-path change routes is_assignee_quarantined / quarantine_blocked / mark_quarantine_probe_task / quarantine_probes through the effective row_assignee (in scope at 8402–8425, defaulted at 8324) — consistent with the spawn gate. New test asserts at the dispatch_once public boundary that a default_assignee auto-routed task is blocked under its effective assignee, not spawned.

@sahilm-ai
sahilm-ai merged commit 0b107fe into main Jun 3, 2026
24 checks passed
@sahilm-ai
sahilm-ai deleted the kanban/t_259adc02 branch June 3, 2026 18:08
sahilm-ti pushed a commit that referenced this pull request Jun 5, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 5, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 15, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 15, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 17, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 17, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 22, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jun 22, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 3, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 3, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 13, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 15, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 15, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 17, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 17, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 21, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 21, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 23, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 23, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 28, 2026
…artbeat enforcement (#46)

test_dispatch_once_stale_disabled_when_timeout_zero stored os.getpid() as
worker_pid with a 5h-old started_at and no heartbeat, then called
dispatch_once(stale_timeout_seconds=0). dispatch_once runs
enforce_missing_heartbeat independently of stale_timeout_seconds, which
os.kill(SIGTERM)'d the stored PID = the pytest process itself, killing
pytest before it printed its summary (raw RC=143). The parallel harness
then scraped 0 passed/0 failed and bucketed the file as 'no tests ran',
turning test(4) red on #43/#44/#45 — broken-main from the upstream rebase.

Fix: set a recent last_heartbeat_at on the run so enforce_missing_heartbeat
skips the task. This test isolates STALE detection, not heartbeat
enforcement. Also hardened test_enforce_max_runtime_integrates_with_dispatch
(same os.getpid() footgun on its real-os.kill dispatch_once call).

Test-only change. Verified: raw pytest RC=0, 166 passed 1 skipped.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Jul 28, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Aug 24, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
sahilm-ti pushed a commit that referenced this pull request Sep 2, 2026
…e spawn regression (#43)

Two distinct bugs surfaced as the test(4) CI shard failing on every PR:

1. Real source regression (not pollution): dispatch_once checked
   profile_exists(row["assignee"]) — the stale DB snapshot, still None
   after default_assignee auto-assignment — instead of the effective
   row_assignee. Every auto-assigned task fell into skipped_nonspawnable
   and never spawned. #34 (3146a5e) reverted the correct NousResearch#27145 fix.
   Fixes test_unassigned_task_auto_assigned_with_default_assignee and
   test_dry_run_with_default_assignee_reports_without_mutating (these
   fail standalone, proving it's a logic bug, not ordering).

2. Non-hermetic fixtures: three kanban test files (default_assignee,
   cli_dispatch_passthrough, per_profile_cap) did del sys.modules[...]
   + reimport in their isolation fixture. kanban_db resolves HERMES_HOME
   lazily at call time, so the reimport was unnecessary — and it created
   a SECOND hermes_cli.kanban_db module object. Sibling files that
   captured the module at import time (test_kanban_core_functionality's
   top-level 'import ... as kb') then read process-global state
   (_recent_worker_exits) from the OLD module while 'import ... as _kb'
   inside the test resolved the NEW one. This split flipped
   test_detect_crashed_workers_protocol_violation_auto_blocks depending
   on file order. Removing the reimport restores hermeticity.

Verified: all tests/hermes_cli/test_kanban_*.py pass per-file (CI model)
and the previously-polluting in-process combinations now pass in any
order.

Co-authored-by: Sahil (AI) <266772320+sahilm-ai@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants