swarph-cli 0.72.2__tar.gz → 0.72.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swarph_cli-0.72.2/src/swarph_cli.egg-info → swarph_cli-0.72.4}/PKG-INFO +1 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/pyproject.toml +1 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/mesh.py +40 -16
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/spawn.py +7 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/guide/GUIDE.md +10 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/scripts/wake_watchdog.py +4 -4
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-watchdog.service +1 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-watchdog.timer +1 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli.egg-info/SOURCES.txt +1 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_1006_board_publisher.py +74 -0
- swarph_cli-0.72.4/tests/test_1010_strand_only.py +225 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_1013_spawn_channel.py +25 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_sidecar.py +18 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_sidecar_cursor_decoupled.py +9 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_sidecar_wake_survives_read.py +9 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_monitor_cli.py +8 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_monitor_state_split.py +9 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_tmux_wake_runstate_defer.py +7 -2
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_tmux_wake_session_reanchor.py +21 -10
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_tmux_wake_stale.py +8 -1
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_tmux_wake_submit_verify.py +15 -4
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/LICENSE +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/README.md +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/setup.cfg +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/__main__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/backends.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/claude_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/codex_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/pack.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/prices.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/providers.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/quality.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/refresh_prices.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/rules.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/runner.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/signal_score.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/bench/validate.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/channel.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/_content.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/bench.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/board.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/board_merge_check.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/cell_probe.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/cell_selfcheck.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/codegraph_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/codex_hook_output.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/codex_waker.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/dreaming.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/gh_route.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/group.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/guide.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/hook_interpreter.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/install_codex_hooks.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/install_opencode_plugin.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/install_wake_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/memory_emit_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/monitor.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/peer_reply_drain.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/postcompact_hook_output.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/version.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/wake_hook_output.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/console_safe.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dm_frame.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/candidates.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/clone.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/enrich.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/index_check.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/notify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/organize.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/probes.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/report.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/run.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/slm.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/transcripts.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/dreaming/verify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gateway_default.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/gh_identity.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/identity.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/operator/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/operator/__main__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/operator/api.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/operator/cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/operator/config.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/operator/fmt.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/orphan_daemons.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/pane_probe.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/opencode/plugin.js +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/_shim.cmd +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/postcompact-recall-grok.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/postcompact-recall.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/posttooluse-emit-antigravity.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/posttooluse-emit-claude.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/posttooluse-emit-grok.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/posttooluse-emit.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/posttooluse-recall.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/precompact-flag.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/preinvocation-recall-antigravity.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/payloads/postcompact/sessionstart-recall.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_executor.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_executor_windows.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_reconciliation.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_service_host.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_service_payload.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_service_reply.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/peer_staging.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/query_filters.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/scripts/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/scripts/dm_notify_filter.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/scripts/ensure_monitor.sh +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/scripts/install_codex_waker_windows.ps1 +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/scripts/install_monitor_task_windows.ps1 +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/skills/i-have-adhd/LICENSE +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/skills/i-have-adhd/SKILL.md +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/source_text.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/codex-waker.default +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/peer-reply-drain.default +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-codex-outbox@.service +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-codex-outbox@.timer +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-codex-waker@.service +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-codex-waker@.timer +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-monitor-reexec.path +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-monitor-reexec.service +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-monitor@.service +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-peer-reply-drain@.service +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-peer-reply-drain@.timer +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/timeline_paths.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli/tokens.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_1006_session_board.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_1017_muse_tui.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_124_register_merge.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_126_pending_from_complete.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_132_ensure_monitor_state_dir.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_138_memory_navigate.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_139_tool_probe.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_183_card_anchor.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_184_notify_honesty.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_201_win32_bash_refusal.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_243_onboard_per_peer_token.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_307_task4_ask_reply.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_312_codegraph_fuzzy_verb.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_319_refusal_exit_codes.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_323_mistral_backend.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_332_report_organize_findings.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_356_query_filters.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_397_gh_identity_router.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_397_router_preflight.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_402_one_identity_resolver.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_467b_onboard_operator_credential.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_472_register_caller_binding.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_484_codex_queue_sink.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_523_guide.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_524_conftest_hermeticity.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_532_accept_flag.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_535_version_capability.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_538_signal_bench.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_546_default_gateway.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_547_verbs_from_registry.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_548_gateway_remainder.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_552_codegraph_gateway.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_555_relay_row_shape.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_556_relay_freshness.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_559_edges_truncated.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_564_bootstrap_first_peer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_578_no_machine_specific_host_defaults.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_579_register_bootstrap_message.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_591_cli_step_graph.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_644_monitor_supervision.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_648_install_unit.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_654_reexec.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_656_owned_slm.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_684_dreaming_verb.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_689_pkg_version_order.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_715_grok_wake.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_716_timeline_one_path.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_723_grok_0251.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_724_ps1_ascii_or_bom.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_725_stdio_reconfigure.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_726_grok_limit_screen.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_729_arm_check_delivery_gap.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_729_dm_once.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_729_wake_watchdog.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_734_dreaming_enrich_degrade.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_735_dm_mcp_tools.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_739_wake_writer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_740_edit_project.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_762_cards_edit_priority.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_764_enrich_collapse.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_801_confirm_flow_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_802_stage_history.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_825_codegraph_hook_noise.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_825_install_posttooluse_only.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_825_remaining_cap_shred_bind.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_829_counterfactual_column.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_830_hook_binding_version.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_84_cli_labels.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_866_doctrine_guide.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_872_identity_refuses_not_warns.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_874_source_text.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_888_opencode_data_dir_can_fail.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_937_dreaming_notify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_938_organize_line_limit.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_941_bench_backends.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_941_harness_342.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_945_same_line_pairing.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_955_prompt_audit.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_957_auth_http.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_959_venv_interpreter.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_960_channel.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_960_ensure_monitor_heartbeat.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_961_cursor_grok_footer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_961_loud_stop.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_963_plugin_manifest.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_964_channel_cell.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_965_mesh_wait.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_975_channel_hop.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_backends.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_claude_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_codex_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_pack.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_prices.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_quality.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_runner.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_bench_validate.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_board_card_thread.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_board_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_board_merge_check.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_board_obligation_close.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_brain_ask_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_brain_ask_env_diagnosis.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_brain_ask_identity_explicitness.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_cell_selfcheck.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_channel_poll_never_breaks_dms.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_channel_wake_policy_filter.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_codegraph_caller_scope.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_codegraph_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_codex_waker.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_console_encoding_e2e.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_content_composition.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_cursor_membrane.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_daemon_console_encoding.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_ensure_monitor_no_peer_default.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_gateway_message_idempotency.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_gh_route_doctor_mesh_name.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_group_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_guide_commands_parse.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_guide_selfcheck.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_heartbeat_check.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_legacy_generation_removal.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_verify.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_win32_bash_wrapper.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_hooks_win32_command_path.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_import_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_inbox_identity_provenance.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_init_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_init_provider_menu.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_install_codex_hooks.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_install_postcompact_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_install_wake_hook.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_main.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_main_unknown_verb_guard.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mcp_missing_hint.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_memory_emit_snippet.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_memory_sync_membrane.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_originate_thread_623.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_send_unknown_peer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_mesh_sidecar_muse_sink.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_monitor_channel_poll.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_monitor_daemon_collision.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_monitor_self_name_verification.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_muse_membrane.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_muse_own_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_obligation_close_is_surfaced.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_opencode_membrane.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_opencode_plugin.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_operator_me.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_orphan_daemons.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_packaged_artifacts_exist.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_packaged_skills.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_executor.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_executor_windows.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_reply_drain_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_reply_drain_supervisor.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_reply_outbox.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_reply_transport.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_service_e2e.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_service_host.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_service_payload.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_peer_service_reply.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_postcompact_recall.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_process_liveness.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_readme_claims_no_gateway_default.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_schedule_create_contract.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_security.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_service_app.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_service_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_shipped_units_match_the_cli.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_identity_stamp.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_subprocess_decode_encoding.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_token_file_one_parser.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_token_precedence_explicit_first.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_unified_token_resolver.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_version_command.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_vibe_membrane.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_watchdog_stale_peers.py +0 -0
- {swarph_cli-0.72.2 → swarph_cli-0.72.4}/tests/test_windows_waker_installer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.4
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.72.
|
|
7
|
+
version = "0.72.4"
|
|
8
8
|
description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -1483,6 +1483,10 @@ class TmuxSink(Sink):
|
|
|
1483
1483
|
def deliver(self, state: "MonitorState", dms: list, up_to_id: int) -> Optional[bool]:
|
|
1484
1484
|
led = state.ledger(self.name)
|
|
1485
1485
|
self.failure_reason = None
|
|
1486
|
+
# #1010: the deferral cause, named for the monitor's DEFERRED log —
|
|
1487
|
+
# a hardcoded cause is a lie on every path that defers for another
|
|
1488
|
+
# reason (the standing-wake hold defers with a CLEAR composer).
|
|
1489
|
+
self.deferred_reason = None
|
|
1486
1490
|
# #723: a rate-limit or usage-limit screen is not deliverable. An
|
|
1487
1491
|
# empty composer beside "Retry failed: rate limit" used to inject
|
|
1488
1492
|
# again, and the 1.0.44 upgrade modal (no Grok footer) used to
|
|
@@ -1601,21 +1605,36 @@ class TmuxSink(Sink):
|
|
|
1601
1605
|
if ok is None:
|
|
1602
1606
|
return None # human adopted mid-settle: defer
|
|
1603
1607
|
return False # unreadable: loud failure
|
|
1604
|
-
#
|
|
1605
|
-
#
|
|
1606
|
-
#
|
|
1607
|
-
#
|
|
1608
|
-
#
|
|
1609
|
-
#
|
|
1610
|
-
#
|
|
1611
|
-
#
|
|
1612
|
-
#
|
|
1613
|
-
#
|
|
1614
|
-
#
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1608
|
+
# #1010 STRAND-ONLY (lab's ruling after the 5th FAIL,
|
|
1609
|
+
# science-claude #1101): this return was the ONLY
|
|
1610
|
+
# delivery report backed by no fresh keystroke, and it
|
|
1611
|
+
# STRANDED the DM batch it reported. The ledger cursor
|
|
1612
|
+
# advanced to the newest id, the monitor then owed
|
|
1613
|
+
# nothing, and this poll was the last one that would
|
|
1614
|
+
# ever look at the batch — measured by droplet on
|
|
1615
|
+
# friendly-coder: its tail was down, typing was its only
|
|
1616
|
+
# wake, and the standing-wake claim "delivered" every
|
|
1617
|
+
# DM with ZERO keystrokes while the cell idled at an
|
|
1618
|
+
# empty prompt, forever. Fix WITHOUT classification:
|
|
1619
|
+
# report the hold, not a delivery. deliver returns None
|
|
1620
|
+
# — the cursor does not advance, the batch stays OWED
|
|
1621
|
+
# and is retried on every poll — and BASE'S OWN stale
|
|
1622
|
+
# bound below (_WAKE_STALE_S, 600 s from the injection)
|
|
1623
|
+
# re-injects and types at the first idle poll past it.
|
|
1624
|
+
# Bounded, loud, never silently dropped; no pane
|
|
1625
|
+
# classifier is consulted, so every pane keeps base's
|
|
1626
|
+
# behaviour. The anti-stack property survives: zero
|
|
1627
|
+
# keystrokes while the window stands.
|
|
1628
|
+
print(f"[monitor] {self.name}: standing wake inside its "
|
|
1629
|
+
f"{_WAKE_STALE_S:.0f}s trust window (injected "
|
|
1630
|
+
f"{time.time() - injected_at:.0f}s ago) — DM held "
|
|
1631
|
+
f"owed, zero keys this poll; the stale bound "
|
|
1632
|
+
f"re-injects and types")
|
|
1633
|
+
self.deferred_reason = (
|
|
1634
|
+
f"standing wake inside the {_WAKE_STALE_S:.0f}s "
|
|
1635
|
+
"trust window — DM held owed, the stale bound "
|
|
1636
|
+
"re-injects and types")
|
|
1637
|
+
return None
|
|
1619
1638
|
if composer == "busy":
|
|
1620
1639
|
# Human text shares the composer (possibly merged into our
|
|
1621
1640
|
# wake) — an Enter here submits THEIR line (#403's shape).
|
|
@@ -3333,8 +3352,13 @@ def _monitor_deliver(state: MonitorState) -> None:
|
|
|
3333
3352
|
state.gateway, state.token, state.self_name, ticks, len(dms)
|
|
3334
3353
|
)
|
|
3335
3354
|
changed = True
|
|
3355
|
+
# #1010: name the deferral's real cause — a hardcoded
|
|
3356
|
+
# "composer holds human text" is a lie on the standing-wake
|
|
3357
|
+
# hold, which defers with a CLEAR composer.
|
|
3358
|
+
detail = getattr(sink, "deferred_reason", None) \
|
|
3359
|
+
or "composer holds human text"
|
|
3336
3360
|
print(f"{state.log_prefix} delivery DEFERRED for {sink.name} "
|
|
3337
|
-
f"(
|
|
3361
|
+
f"({detail}); wake stays owed, "
|
|
3338
3362
|
f"no failure counted",
|
|
3339
3363
|
flush=True)
|
|
3340
3364
|
continue
|
|
@@ -581,9 +581,16 @@ def _spawn_env_base(cell: Cell) -> dict[str, str]:
|
|
|
581
581
|
# NOTE: the marketplace/validity gate lives in _validate_channel, which
|
|
582
582
|
# _build_claude_argv (and the muse env builder) run. This base stays a
|
|
583
583
|
# pure reflection of the resolved mode so every provider's env agrees.
|
|
584
|
+
# #1022: SWARPH_CHANNEL must be exported too, whatever the mode's source.
|
|
585
|
+
# channel_opted_in() (channel.py) gates on SWARPH_CHANNEL alone, so a
|
|
586
|
+
# mode that came from cell.yaml — not from the parent env — left the
|
|
587
|
+
# session with SWARPH_CHANNEL_CELL set and the channel deaf: the server
|
|
588
|
+
# never declared claude/channel (droplet 4 days, gridiron on lab).
|
|
584
589
|
if mode in {"allowlisted", "dev"}:
|
|
590
|
+
env["SWARPH_CHANNEL"] = mode
|
|
585
591
|
env["SWARPH_CHANNEL_CELL"] = cell.name
|
|
586
592
|
else:
|
|
593
|
+
env.pop("SWARPH_CHANNEL", None)
|
|
587
594
|
env.pop("SWARPH_CHANNEL_CELL", None)
|
|
588
595
|
return env
|
|
589
596
|
|
|
@@ -23,6 +23,7 @@ Read the topic you need. You do not need to read this top to bottom.
|
|
|
23
23
|
| [Check your own setup](#check-your-own-setup) | commands with their expected answers |
|
|
24
24
|
| [How to](#how-to) | tasks, phrased the way you'd ask for them |
|
|
25
25
|
| [Glossary](#glossary) | the words this mesh uses |
|
|
26
|
+
| [Architecture overview](#architecture-overview) | the five layers, the six rules, and how a change ships |
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
@@ -55,6 +56,15 @@ want, run the command.
|
|
|
55
56
|
| see what a wake hook would print | `swarph wake-hook-output` |
|
|
56
57
|
| search this guide | `swarph guide --search <word>` |
|
|
57
58
|
| learn the standard of evidence | `swarph guide doctrine` |
|
|
59
|
+
| see how the stack fits together | see [Architecture overview](#architecture-overview) |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Architecture overview
|
|
64
|
+
|
|
65
|
+
The five layers, the six rules, the delivery pipeline, shadow-to-graduate,
|
|
66
|
+
the security posture, and the stack-versus-off-the-shelf table are in
|
|
67
|
+
[docs/architecture-overview.md](../../../docs/architecture-overview.md).
|
|
58
68
|
|
|
59
69
|
---
|
|
60
70
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""IMMUNE (cell watchdog), card #729. Every pass, a cell with nobody reading its inbox is an outage.
|
|
2
2
|
|
|
3
3
|
One DM per outage. A live watcher clears it, so the next gap can alert again.
|
|
4
4
|
"""
|
|
@@ -360,17 +360,17 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
360
360
|
for name in alert:
|
|
361
361
|
print(f"outage {name}", flush=True)
|
|
362
362
|
dm_rc = mesh_send(
|
|
363
|
-
swarph, name, sender, "your DM wake is dead, re-arm", token_file)
|
|
363
|
+
swarph, name, sender, "IMMUNE (cell watchdog): your DM wake is dead, re-arm", token_file)
|
|
364
364
|
dm_ok = dm_rc == 0
|
|
365
365
|
card_argv = [swarph, "board", "cards", "say", "729", "--as", sender,
|
|
366
|
-
"--to", name, "--content", f"{name}: DM wake is dead, re-arm"]
|
|
366
|
+
"--to", name, "--content", f"IMMUNE (cell watchdog) — {name}: DM wake is dead, re-arm"]
|
|
367
367
|
if token_file:
|
|
368
368
|
card_argv.extend(["--token-file", token_file])
|
|
369
369
|
card = subprocess.run(card_argv, check=False)
|
|
370
370
|
esc_ok = True
|
|
371
371
|
if escalate and escalate != name:
|
|
372
372
|
esc_rc = mesh_send(
|
|
373
|
-
swarph, escalate, sender, f"{name}: DM wake is dead, re-arm",
|
|
373
|
+
swarph, escalate, sender, f"IMMUNE (cell watchdog) — {name}: DM wake is dead, re-arm",
|
|
374
374
|
token_file)
|
|
375
375
|
esc_ok = esc_rc == 0
|
|
376
376
|
if dm_ok and card.returncode == 0 and esc_ok:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[Unit]
|
|
2
|
-
Description=Swarph watchdog one-shot check (stranded-session recovery)
|
|
2
|
+
Description=IMMUNE (cell watchdog): Swarph watchdog one-shot check (stranded-session recovery)
|
|
3
3
|
Documentation=https://github.com/BrainSurfing-tech/swarph-cli
|
|
4
4
|
After=network-online.target
|
|
5
5
|
Wants=network-online.target
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[Unit]
|
|
2
|
-
Description=Run swarph watchdog every 5 minutes (stranded-session recovery)
|
|
2
|
+
Description=Run IMMUNE (cell watchdog): swarph watchdog every 5 minutes (stranded-session recovery)
|
|
3
3
|
Documentation=https://github.com/BrainSurfing-tech/swarph-cli
|
|
4
4
|
Requires=swarph-watchdog.service
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.72.
|
|
3
|
+
Version: 0.72.4
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, per-invocation `gh` identity routing, a silent DM-wake hook, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -188,6 +188,7 @@ src/swarph_cli/systemd/swarph-watchdog.service
|
|
|
188
188
|
src/swarph_cli/systemd/swarph-watchdog.timer
|
|
189
189
|
tests/test_1006_board_publisher.py
|
|
190
190
|
tests/test_1006_session_board.py
|
|
191
|
+
tests/test_1010_strand_only.py
|
|
191
192
|
tests/test_1013_spawn_channel.py
|
|
192
193
|
tests/test_1017_muse_tui.py
|
|
193
194
|
tests/test_124_register_merge.py
|
|
@@ -346,3 +346,77 @@ def test_in_session_marker_sets_the_flag_and_strips_the_title():
|
|
|
346
346
|
assert "[in-session]" not in marked["title"]
|
|
347
347
|
assert "[commander]" not in marked["title"]
|
|
348
348
|
assert plain["in_session"] is False
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def _commander_obligation(oid, holder="commander", step="build", accept="PASS=x | FAIL=y", title="Do it"):
|
|
352
|
+
return {
|
|
353
|
+
"id": oid,
|
|
354
|
+
"holder": holder,
|
|
355
|
+
"card_id": 291,
|
|
356
|
+
"state": "open",
|
|
357
|
+
"step": step,
|
|
358
|
+
"accept": f"[commander] {title} | {accept}",
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def test_tap_closable_commander_rows_render_yes_no():
|
|
363
|
+
"""card #291 ruling_1157 (1): a tap-closable commander row (build or
|
|
364
|
+
step-less) renders as yes/no with the fixed mapping yes=pass, no=fail —
|
|
365
|
+
even when the row carries its own prose options."""
|
|
366
|
+
pub = _load()
|
|
367
|
+
rows = pub.commander_rows([
|
|
368
|
+
_commander_obligation(1, step="build"),
|
|
369
|
+
_commander_obligation(2, step=None),
|
|
370
|
+
])
|
|
371
|
+
assert [r["step"] for r in rows] == ["build", None]
|
|
372
|
+
by_cell = {}
|
|
373
|
+
for row in rows:
|
|
374
|
+
row["title"] = "Do it"
|
|
375
|
+
row["options"] = [{"label": "Prose", "text": "discuss first", "rec": True}]
|
|
376
|
+
by_cell.setdefault(row["cell"], []).append(row)
|
|
377
|
+
questions = pub.build_board._questions(by_cell["commander"])
|
|
378
|
+
assert len(questions) == 2
|
|
379
|
+
for q in questions:
|
|
380
|
+
assert [(o["label"], o["text"], o["outcome"]) for o in q["options"]] == [
|
|
381
|
+
("Yes", "yes", "pass"),
|
|
382
|
+
("No", "no", "fail"),
|
|
383
|
+
], "RED: tap-closable rows render yes/no, never row prose"
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
def test_validate_plan_review_rows_keep_display_only_options():
|
|
387
|
+
"""card #291 ruling_1157 (1): validate/plan-review commander rows are
|
|
388
|
+
NOT taps — their options stay prose and every option carries
|
|
389
|
+
outcome None (display-only, closes nothing)."""
|
|
390
|
+
pub = _load()
|
|
391
|
+
rows = pub.commander_rows([
|
|
392
|
+
_commander_obligation(3, step="validate"),
|
|
393
|
+
_commander_obligation(4, step="plan-review"),
|
|
394
|
+
])
|
|
395
|
+
by_cell = {}
|
|
396
|
+
for row in rows:
|
|
397
|
+
row["title"] = "Check it"
|
|
398
|
+
row["options"] = [{"label": "Prose", "text": "discuss first", "rec": True}]
|
|
399
|
+
by_cell.setdefault(row["cell"], []).append(row)
|
|
400
|
+
questions = pub.build_board._questions(by_cell["commander"])
|
|
401
|
+
assert len(questions) == 2
|
|
402
|
+
for q in questions:
|
|
403
|
+
assert all(o.get("outcome") is None for o in q["options"]), \
|
|
404
|
+
"RED: no prose option closes PASS by default"
|
|
405
|
+
assert [o["label"] for o in q["options"]] == ["Prose"]
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def test_default_options_are_display_only():
|
|
409
|
+
"""The three fallback prose options carry outcome None on every row."""
|
|
410
|
+
pub = _load()
|
|
411
|
+
rows = pub.commander_rows([_commander_obligation(5, step="build")])
|
|
412
|
+
row = dict(rows[0])
|
|
413
|
+
row["title"] = "Do it"
|
|
414
|
+
row.pop("options", None)
|
|
415
|
+
other = dict(row, cell="drop-on-meta-edge", holder="drop-on-meta-edge")
|
|
416
|
+
for q in pub.build_board._questions([row, other]):
|
|
417
|
+
if q["to_node"] == "commander":
|
|
418
|
+
assert [o["outcome"] for o in q["options"]] == ["pass", "fail"]
|
|
419
|
+
else:
|
|
420
|
+
assert [o["label"] for o in q["options"]] == [
|
|
421
|
+
"Answer on the card", "Ask for a narrower question", "Park it"]
|
|
422
|
+
assert all(o["outcome"] is None for o in q["options"])
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""#1010 STRAND-ONLY (lab's ruling after science-claude's #1101 FAIL, the
|
|
2
|
+
5th on PR 534): PR 534 ships NO pane idle/busy classifier change — every
|
|
3
|
+
pane keeps base 0.72.3's behaviour — and the strand is fixed in the
|
|
4
|
+
LEDGER layer alone.
|
|
5
|
+
|
|
6
|
+
THE STRAND (measured by droplet on friendly-coder): the tmux sink's
|
|
7
|
+
standing-wake path returned True with ZERO keystrokes. The monitor
|
|
8
|
+
advanced `last_delivered_id`, owed nothing from then on, and the DM
|
|
9
|
+
batch was never looked at again — every DM "delivered" in the log while
|
|
10
|
+
the cell idled at an empty prompt, typing its only wake, forever. The
|
|
11
|
+
repro that opened #1010: an ANSWERED wake, a monitor RESTART, a new DM.
|
|
12
|
+
|
|
13
|
+
THE FIX (no classification): the standing-wake hold reports the hold,
|
|
14
|
+
not a delivery. deliver returns None — the cursor does not advance, the
|
|
15
|
+
batch stays OWED and is retried on every poll — and BASE'S OWN stale
|
|
16
|
+
bound (_WAKE_STALE_S = 600 s from the injection) re-injects and types
|
|
17
|
+
at the first idle poll past it. Bounded, loud, never silently dropped.
|
|
18
|
+
|
|
19
|
+
>>> RED on e445877 (base 0.72.3): the monitor-level repro below never
|
|
20
|
+
typed — the first poll returned True with zero keystrokes, the cursor
|
|
21
|
+
advanced, and every later poll owed nothing (assert wake_calls == 1
|
|
22
|
+
fails with 0). The unit pins of the hold returned True there too.
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import pathlib
|
|
27
|
+
import time
|
|
28
|
+
|
|
29
|
+
import swarph_cli.commands.mesh as mesh
|
|
30
|
+
import swarph_cli.commands.watchdog as watchdog
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class _StubState:
|
|
34
|
+
def __init__(self):
|
|
35
|
+
self.gateway = "http://gw:8788"
|
|
36
|
+
self.self_name = "cursor-lin"
|
|
37
|
+
self.token = "tok"
|
|
38
|
+
self._ledgers: dict = {}
|
|
39
|
+
|
|
40
|
+
def ledger(self, name: str) -> dict:
|
|
41
|
+
return self._ledgers.setdefault(
|
|
42
|
+
name, {"last_delivered_id": 0, "last_delivery_at": 0.0,
|
|
43
|
+
"consecutive_failures": 0})
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _rig(monkeypatch, *, composer="clear", unread=3,
|
|
47
|
+
session_created=None, running=False):
|
|
48
|
+
"""Pin every observation deliver() makes; record the keystrokes.
|
|
49
|
+
|
|
50
|
+
running defaults to False: the #1010 repro is the ANSWERED wake — the
|
|
51
|
+
turn already ran, the pane idles at an empty prompt. The rig pins
|
|
52
|
+
`_capture_pane_lines` too: the conftest guard fails any unmocked tmux
|
|
53
|
+
call, and deliver() reads the pane for the grok-block check before
|
|
54
|
+
any of this."""
|
|
55
|
+
calls = {"wake": 0, "enter": 0}
|
|
56
|
+
monkeypatch.setattr(mesh, "_capture_pane_lines", lambda t: ["row"])
|
|
57
|
+
monkeypatch.setattr(mesh, "_composer_state", lambda t: composer)
|
|
58
|
+
monkeypatch.setattr(mesh, "_tmux_session_created", lambda t: session_created)
|
|
59
|
+
monkeypatch.setattr(mesh, "_agent_running", lambda t: running)
|
|
60
|
+
monkeypatch.setattr(watchdog, "_gateway_unread_count",
|
|
61
|
+
lambda *a, **k: unread)
|
|
62
|
+
|
|
63
|
+
def fake_wake(target):
|
|
64
|
+
calls["wake"] += 1
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
def fake_enter(target):
|
|
68
|
+
calls["enter"] += 1
|
|
69
|
+
return True
|
|
70
|
+
|
|
71
|
+
monkeypatch.setattr(mesh, "_tmux_wake", fake_wake)
|
|
72
|
+
monkeypatch.setattr(mesh, "_tmux_enter", fake_enter)
|
|
73
|
+
return calls
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _owed_state(injected_at=None):
|
|
77
|
+
state = _StubState()
|
|
78
|
+
led = state.ledger("tmux:cursor-lin")
|
|
79
|
+
led["wake_outstanding"] = True
|
|
80
|
+
if injected_at is not None:
|
|
81
|
+
led["last_wake_injected_at"] = injected_at
|
|
82
|
+
return state
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
# ── the hold: loud, bounded, zero keystrokes, nothing marked delivered ───
|
|
86
|
+
|
|
87
|
+
def test_standing_wake_hold_is_loud_bounded_and_keeps_the_dm_owed(
|
|
88
|
+
monkeypatch, capsys):
|
|
89
|
+
"""#1010 clause 2: a DM suppressed by a standing wake is NEVER
|
|
90
|
+
marked delivered while untyped. The hold says what it is doing — the
|
|
91
|
+
trust window, the wake's age, and that the stale bound types — and
|
|
92
|
+
returns None, so the monitor's cursor stays put and the batch is
|
|
93
|
+
retried next poll. >>> RED on e445877: this returned True — delivery
|
|
94
|
+
reported, zero keystrokes, the DM stranded."""
|
|
95
|
+
now = time.time()
|
|
96
|
+
calls = _rig(monkeypatch, composer="clear", unread=3,
|
|
97
|
+
session_created=now - 7200, running=False)
|
|
98
|
+
state = _owed_state(injected_at=now - 60)
|
|
99
|
+
sink = mesh.TmuxSink("cursor-lin")
|
|
100
|
+
|
|
101
|
+
assert sink.deliver(state, [{"id": 9}], 9) is None
|
|
102
|
+
assert calls["wake"] == 0 and calls["enter"] == 0, "zero keys inside the window"
|
|
103
|
+
led = state.ledger("tmux:cursor-lin")
|
|
104
|
+
assert led["wake_outstanding"] is True, "the standing wake is undisturbed"
|
|
105
|
+
out = capsys.readouterr().out
|
|
106
|
+
assert "standing wake inside its 600s trust window" in out, out
|
|
107
|
+
assert "DM held owed" in out
|
|
108
|
+
assert "zero keys" in out
|
|
109
|
+
assert "re-injects and types" in out
|
|
110
|
+
# the monitor's DEFERRED line names the real cause, not human text
|
|
111
|
+
assert "standing wake" in (sink.deferred_reason or "")
|
|
112
|
+
assert "human text" not in (sink.deferred_reason or "")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_no_keystroke_sooner_than_base_inside_the_window(monkeypatch):
|
|
116
|
+
"""The FAIL arm: no keystroke SOONER than base. Repeated polls inside
|
|
117
|
+
the trust window type nothing — the anti-stack property the
|
|
118
|
+
edge-trigger exists for (#312) survives the hold. Base stacked zero
|
|
119
|
+
keys here too; the difference is only that base also claimed
|
|
120
|
+
delivery."""
|
|
121
|
+
now = time.time()
|
|
122
|
+
calls = _rig(monkeypatch, composer="clear", unread=3,
|
|
123
|
+
session_created=now - 7200, running=False)
|
|
124
|
+
state = _owed_state(injected_at=now - 60)
|
|
125
|
+
sink = mesh.TmuxSink("cursor-lin")
|
|
126
|
+
for _ in range(5):
|
|
127
|
+
assert sink.deliver(state, [{"id": 9}], 9) is None
|
|
128
|
+
assert calls["wake"] == 0 and calls["enter"] == 0
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_held_dm_is_typed_when_the_600s_window_lapses(monkeypatch):
|
|
132
|
+
"""#1010 clause 2, the other arm: the held DM does not stay held
|
|
133
|
+
forever — BASE'S OWN stale bound (a wake undrained for
|
|
134
|
+
_WAKE_STALE_S) re-injects, and the first idle poll past the bound
|
|
135
|
+
carries a real keystroke. The DM is then delivered for real."""
|
|
136
|
+
now = time.time()
|
|
137
|
+
calls = _rig(monkeypatch, composer="clear", unread=3,
|
|
138
|
+
session_created=now - 7200, running=False)
|
|
139
|
+
state = _owed_state(injected_at=now - 601)
|
|
140
|
+
sink = mesh.TmuxSink("cursor-lin")
|
|
141
|
+
|
|
142
|
+
assert sink.deliver(state, [{"id": 9}], 9) is True
|
|
143
|
+
assert calls["wake"] == 1, "the stale bound re-injects — a keystroke"
|
|
144
|
+
led = state.ledger("tmux:cursor-lin")
|
|
145
|
+
assert led["last_wake_injected_at"] > now - 5, "the retry re-anchors"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# ── the original repro, at the monitor: answered wake, restart, new DM ────
|
|
149
|
+
|
|
150
|
+
class _MonitorStubState(_StubState):
|
|
151
|
+
"""The poll-loop pass reads: sinks, the observed cursor, the ledgers,
|
|
152
|
+
the idle-guard clock, and the inbox log for replay."""
|
|
153
|
+
|
|
154
|
+
def __init__(self, observed_id, delivered_id, ledgers=None, inbox_log=None):
|
|
155
|
+
super().__init__()
|
|
156
|
+
if ledgers is not None:
|
|
157
|
+
self._ledgers = ledgers # the restart shape: one persisted ledger
|
|
158
|
+
self.sinks = [mesh.TmuxSink("cursor-lin")]
|
|
159
|
+
self.ledgers = self._ledgers
|
|
160
|
+
self.observed = {"last_msg_id": observed_id}
|
|
161
|
+
self.min_interval_s = 60
|
|
162
|
+
self.deliveries: dict = {}
|
|
163
|
+
self.ledgers_path = pathlib.Path("/dev/null")
|
|
164
|
+
self.log_prefix = "[test]"
|
|
165
|
+
self.inbox_log_path = inbox_log or pathlib.Path(
|
|
166
|
+
"/tmp/1010-strand-no-such-inbox.log")
|
|
167
|
+
self.replay_limit = 50
|
|
168
|
+
led = self.ledger("tmux:cursor-lin")
|
|
169
|
+
led["last_delivered_id"] = delivered_id
|
|
170
|
+
led["last_delivery_at"] = time.time() - 3600
|
|
171
|
+
led["wake_outstanding"] = True
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _poll(monkeypatch, state, unread):
|
|
175
|
+
monkeypatch.setattr(watchdog, "_gateway_unread_count",
|
|
176
|
+
lambda *a, **k: unread)
|
|
177
|
+
writes = []
|
|
178
|
+
monkeypatch.setattr(mesh, "_write_ledgers_atomic",
|
|
179
|
+
lambda p, d: writes.append(dict(d)))
|
|
180
|
+
mesh._monitor_deliver(state)
|
|
181
|
+
return writes
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def test_the_original_repro_types_by_600s_even_after_a_restart(monkeypatch,
|
|
185
|
+
capsys):
|
|
186
|
+
"""THE #1010 repro, end to end through the poll loop: an ANSWERED
|
|
187
|
+
wake (turn ran and finished; the flag stands, injected 60 s ago), a
|
|
188
|
+
monitor RESTART (a fresh state over the SAME ledger), a new DM.
|
|
189
|
+
|
|
190
|
+
At the head: the first poll HOLDS (zero keys, cursor unmoved, loud
|
|
191
|
+
line); 600 s later the stale bound re-injects — ONE keystroke — and
|
|
192
|
+
the ledger finally advances. Nothing strands and nothing types
|
|
193
|
+
sooner than base.
|
|
194
|
+
|
|
195
|
+
>>> RED on e445877: the first poll reported delivery with ZERO
|
|
196
|
+
keystrokes, the cursor advanced to 10, and every later poll owed
|
|
197
|
+
nothing — the DM was never typed (wake_calls stays 0)."""
|
|
198
|
+
now = time.time()
|
|
199
|
+
calls = _rig(monkeypatch, composer="clear", unread=3,
|
|
200
|
+
session_created=now - 7200, running=False)
|
|
201
|
+
|
|
202
|
+
# an answered wake, 60 s inside its trust window; the monitor owes DM 10
|
|
203
|
+
ledgers: dict = {}
|
|
204
|
+
state = _MonitorStubState(observed_id=10, delivered_id=9, ledgers=ledgers)
|
|
205
|
+
state.ledger("tmux:cursor-lin")["last_wake_injected_at"] = now - 60
|
|
206
|
+
|
|
207
|
+
_poll(monkeypatch, state, unread=3) # poll 1: the hold
|
|
208
|
+
led = ledgers["tmux:cursor-lin"]
|
|
209
|
+
assert led["last_delivered_id"] == 9, "nothing marked delivered untyped"
|
|
210
|
+
assert calls["wake"] == 0 and calls["enter"] == 0
|
|
211
|
+
assert "DM held owed" in capsys.readouterr().out
|
|
212
|
+
assert led.get("deferred_ticks") == 1, "the deferral is counted, not a failure"
|
|
213
|
+
|
|
214
|
+
# monitor restart: a fresh state over the SAME persisted ledger
|
|
215
|
+
state2 = _MonitorStubState(observed_id=10, delivered_id=9, ledgers=ledgers)
|
|
216
|
+
# 600 s pass; the same injection is now past base's stale bound
|
|
217
|
+
ledgers["tmux:cursor-lin"]["last_wake_injected_at"] = time.time() - 601
|
|
218
|
+
|
|
219
|
+
_poll(monkeypatch, state2, unread=3) # poll 2: past the bound
|
|
220
|
+
assert calls["wake"] == 1, "the stale bound re-injects and TYPES"
|
|
221
|
+
assert ledgers["tmux:cursor-lin"]["last_delivered_id"] == 10
|
|
222
|
+
|
|
223
|
+
_poll(monkeypatch, state2, unread=3) # poll 3: owes nothing now
|
|
224
|
+
assert calls["wake"] == 1, "delivered for real — no repeat keystroke"
|
|
225
|
+
assert "delivered to tmux:cursor-lin up to id 10" in capsys.readouterr().out
|
|
@@ -244,3 +244,28 @@ def test_parent_channel_cell_does_not_reach_a_different_cell(tmp_path, monkeypat
|
|
|
244
244
|
assert rc == 0
|
|
245
245
|
assert env_added.get("SWARPH_CHANNEL_CELL") == "science-claude"
|
|
246
246
|
|
|
247
|
+
|
|
248
|
+
def test_field_channel_exports_swarph_channel_so_serve_is_not_deaf(tmp_path, monkeypatch, capsys):
|
|
249
|
+
"""Card #1022. A mode that came from cell.yaml must reach channel-serve:
|
|
250
|
+
the spawned env carries SWARPH_CHANNEL=mode (not just SWARPH_CHANNEL_CELL),
|
|
251
|
+
and channel_opted_in() is True under that env. On 7afd16b the field path
|
|
252
|
+
set only SWARPH_CHANNEL_CELL, so the server never declared claude/channel
|
|
253
|
+
and the cell ran deaf (droplet ~4 days, gridiron on lab).
|
|
254
|
+
"""
|
|
255
|
+
from swarph_cli.channel import channel_opted_in
|
|
256
|
+
|
|
257
|
+
_registry(tmp_path, monkeypatch, with_swarph=True)
|
|
258
|
+
monkeypatch.delenv("SWARPH_CHANNEL", raising=False)
|
|
259
|
+
p = _cell_yaml(tmp_path, "claude", channel="allowlisted", name="gridiron")
|
|
260
|
+
rc, argv, env_added = _print(tmp_path, p, capsys)
|
|
261
|
+
assert rc == 0
|
|
262
|
+
assert "--channels" in argv and "plugin:swarph@swarph" in argv
|
|
263
|
+
# The env handed to claude names the mode, whatever its source was.
|
|
264
|
+
assert env_added.get("SWARPH_CHANNEL") == "allowlisted"
|
|
265
|
+
assert env_added.get("SWARPH_CHANNEL_CELL") == "gridiron"
|
|
266
|
+
# And the server's own gate agrees under exactly that env.
|
|
267
|
+
with monkeypatch.context() as ctx:
|
|
268
|
+
ctx.setenv("SWARPH_CHANNEL", env_added["SWARPH_CHANNEL"])
|
|
269
|
+
ctx.setenv("SWARPH_CHANNEL_CELL", env_added["SWARPH_CHANNEL_CELL"])
|
|
270
|
+
assert channel_opted_in() is True
|
|
271
|
+
|
|
@@ -10,6 +10,11 @@ import pytest
|
|
|
10
10
|
|
|
11
11
|
from swarph_cli.commands import mesh
|
|
12
12
|
|
|
13
|
+
#: The real capture seam, taken at import before any autouse fixture pins
|
|
14
|
+
#: it (#1010 strand-only hermeticity): the #533 test below asserts the
|
|
15
|
+
#: leading capture-pane call that its own subprocess stub must serve.
|
|
16
|
+
_REAL_CAPTURE_PANE_LINES = mesh._capture_pane_lines
|
|
17
|
+
|
|
13
18
|
|
|
14
19
|
@pytest.fixture(autouse=True)
|
|
15
20
|
def _clean_composer(monkeypatch):
|
|
@@ -17,6 +22,15 @@ def _clean_composer(monkeypatch):
|
|
|
17
22
|
default every composer to OBSERVED-CLEAN so the gate stays out of the
|
|
18
23
|
way. The gate's own matrix lives in test_tmux_wake_submit_verify.py."""
|
|
19
24
|
monkeypatch.setattr(mesh, "_composer_state", lambda t: "clear")
|
|
25
|
+
# #1010 strand-only hermeticity (#1083): the grok-block probe, the
|
|
26
|
+
# run-state read and the session-age read inside deliver() reach the
|
|
27
|
+
# REAL tmux binary when unpatched — a bare CI runner and a box with
|
|
28
|
+
# live cells must read the suite the same way. A missing pane reads
|
|
29
|
+
# unreadable at base; False/None keep the same falsy fall-through
|
|
30
|
+
# these tests pin.
|
|
31
|
+
monkeypatch.setattr(mesh, "_capture_pane_lines", lambda t: None)
|
|
32
|
+
monkeypatch.setattr(mesh, "_agent_running", lambda t: False)
|
|
33
|
+
monkeypatch.setattr(mesh, "_tmux_session_created", lambda t: None)
|
|
20
34
|
|
|
21
35
|
|
|
22
36
|
def _state(tmp_path: Path) -> mesh.MeshSidecarState:
|
|
@@ -49,6 +63,10 @@ def test_tmux_wake_sends_literal_prompt_then_submits_and_verifies(monkeypatch):
|
|
|
49
63
|
lambda command, **kwargs: calls.append((command, kwargs)) or Result(),
|
|
50
64
|
)
|
|
51
65
|
monkeypatch.setattr(mesh.time, "sleep", lambda _s: None)
|
|
66
|
+
# #1010 strand-only hermeticity: the autouse fixture pins the capture
|
|
67
|
+
# seam so no OTHER pane read reaches the real binary; this test's own
|
|
68
|
+
# subprocess stub serves the leading capture-pane call it asserts.
|
|
69
|
+
monkeypatch.setattr(mesh, "_capture_pane_lines", _REAL_CAPTURE_PANE_LINES)
|
|
52
70
|
# The verifier is now a projection of the four-way composer state; the
|
|
53
71
|
# autouse fixture stubs that state. Record the consultation instead of
|
|
54
72
|
# expecting a raw capture-pane call in the sequence.
|
|
@@ -28,6 +28,15 @@ def _clean_composer(monkeypatch):
|
|
|
28
28
|
default every composer to OBSERVED-CLEAN so the gate stays out of the
|
|
29
29
|
way. The gate's own matrix lives in test_tmux_wake_submit_verify.py."""
|
|
30
30
|
monkeypatch.setattr(mesh, "_composer_state", lambda t: "clear")
|
|
31
|
+
# #1010 strand-only hermeticity (#1083): the grok-block probe, the
|
|
32
|
+
# run-state read and the session-age read inside deliver() reach the
|
|
33
|
+
# REAL tmux binary when unpatched — a bare CI runner and a box with
|
|
34
|
+
# live cells must read the suite the same way. A missing pane reads
|
|
35
|
+
# unreadable at base; False/None keep the same falsy fall-through
|
|
36
|
+
# these tests pin.
|
|
37
|
+
monkeypatch.setattr(mesh, "_capture_pane_lines", lambda t: None)
|
|
38
|
+
monkeypatch.setattr(mesh, "_agent_running", lambda t: False)
|
|
39
|
+
monkeypatch.setattr(mesh, "_tmux_session_created", lambda t: None)
|
|
31
40
|
|
|
32
41
|
|
|
33
42
|
def _state(tmp_path, wake_min_interval_s=0):
|
|
@@ -20,6 +20,15 @@ def _clean_composer(monkeypatch):
|
|
|
20
20
|
default every composer to OBSERVED-CLEAN so the gate stays out of the
|
|
21
21
|
way. The gate's own matrix lives in test_tmux_wake_submit_verify.py."""
|
|
22
22
|
monkeypatch.setattr(mesh, "_composer_state", lambda t: "clear")
|
|
23
|
+
# #1010 strand-only hermeticity (#1083): the grok-block probe, the
|
|
24
|
+
# run-state read and the session-age read inside deliver() reach the
|
|
25
|
+
# REAL tmux binary when unpatched — a bare CI runner and a box with
|
|
26
|
+
# live cells must read the suite the same way. A missing pane reads
|
|
27
|
+
# unreadable at base; False/None keep the same falsy fall-through
|
|
28
|
+
# these tests pin.
|
|
29
|
+
monkeypatch.setattr(mesh, "_capture_pane_lines", lambda t: None)
|
|
30
|
+
monkeypatch.setattr(mesh, "_agent_running", lambda t: False)
|
|
31
|
+
monkeypatch.setattr(mesh, "_tmux_session_created", lambda t: None)
|
|
23
32
|
|
|
24
33
|
|
|
25
34
|
def _state(tmp_path, wake_min_interval_s=0):
|
|
@@ -25,8 +25,15 @@ from swarph_cli.commands import mesh, monitor
|
|
|
25
25
|
def _clean_composer(monkeypatch):
|
|
26
26
|
"""These tests pin CLI/ledger mechanics, not the politeness gate —
|
|
27
27
|
default every composer to OBSERVED-CLEAN so the gate stays out of the
|
|
28
|
-
way. The gate's own matrix lives in test_tmux_wake_submit_verify.py.
|
|
28
|
+
way. The gate's own matrix lives in test_tmux_wake_submit_verify.py.
|
|
29
|
+
#1010 strand-only hermeticity (#1083): every pane named by this rig
|
|
30
|
+
is synthetic — an unpatched capture/run-state/session read reaches
|
|
31
|
+
the REAL tmux binary. A missing pane reads unreadable at base;
|
|
32
|
+
False/None keep the same falsy fall-through these tests pin."""
|
|
29
33
|
monkeypatch.setattr(mesh, "_composer_state", lambda t: "clear")
|
|
34
|
+
monkeypatch.setattr(mesh, "_capture_pane_lines", lambda t: None)
|
|
35
|
+
monkeypatch.setattr(mesh, "_agent_running", lambda t: False)
|
|
36
|
+
monkeypatch.setattr(mesh, "_tmux_session_created", lambda t: None)
|
|
30
37
|
|
|
31
38
|
|
|
32
39
|
def _env(monkeypatch):
|