@zerwiz/ymir 0.1.4 → 0.1.7
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.
- package/.agents/README.md +291 -0
- package/.agents/agents/bragi-marketer.md +111 -0
- package/.agents/agents/brokk.md +352 -0
- package/.agents/agents/forseti-reviewer.md +93 -0
- package/.agents/agents/frigg-consent.md +77 -0
- package/.agents/agents/groa-update.md +77 -0
- package/.agents/agents/hnoss-designer.md +69 -0
- package/.agents/agents/huginn-researcher.md +99 -0
- package/.agents/agents/jord-projects.md +78 -0
- package/.agents/agents/kvasir-scout.md +91 -0
- package/.agents/agents/mimir-planner.md +92 -0
- package/.agents/agents/muninn-stow.md +77 -0
- package/.agents/agents/saga-bearings.md +78 -0
- package/.agents/agents/sindri-developer.md +114 -0
- package/.agents/agents/snotra-documenter.md +105 -0
- package/.agents/agents/syn-recovery.md +78 -0
- package/.agents/agents/tyr-check.md +78 -0
- package/.agents/agents/urdh-hold.md +77 -0
- package/.agents/agents/volundr-smith.md +80 -0
- package/.agents/agents/vor-diagnostics.md +77 -0
- package/.agents/assets/agents/naming.md +50 -0
- package/.agents/assets/agents/registry.md +93 -0
- package/.agents/assets/agents/runtime.md +36 -0
- package/.agents/assets/agents/toon-tasks-cli.md +42 -0
- package/.agents/assets/templates/company_entity.template.md +37 -0
- package/.agents/backend/README.md +74 -0
- package/.agents/backend/backends/cmux.sh +649 -0
- package/.agents/backend/backends/herdr-eventwait.py +157 -0
- package/.agents/backend/backends/herdr-workspace-move.py +114 -0
- package/.agents/backend/backends/herdr.sh +3386 -0
- package/.agents/backend/backends/orca.sh +290 -0
- package/.agents/backend/backends/tmux.sh +357 -0
- package/.agents/backend/backends/zellij.sh +700 -0
- package/.agents/backend/fm-afk-launch.sh +654 -0
- package/.agents/backend/fm-afk-return.sh +241 -0
- package/.agents/backend/fm-afk-start.sh +172 -0
- package/.agents/backend/fm-arm-command-policy.mjs +960 -0
- package/.agents/backend/fm-arm-pretool-check.sh +200 -0
- package/.agents/backend/fm-backend-hometag-lib.sh +52 -0
- package/.agents/backend/fm-backend.sh +981 -0
- package/.agents/backend/fm-backlog-handoff.sh +909 -0
- package/.agents/backend/fm-backlog-receive.sh +187 -0
- package/.agents/backend/fm-backlog-transition-lib.sh +779 -0
- package/.agents/backend/fm-bearings-board.sh +204 -0
- package/.agents/backend/fm-bearings-snapshot.sh +546 -0
- package/.agents/backend/fm-bootstrap.sh +1568 -0
- package/.agents/backend/fm-branch-outcome.sh +203 -0
- package/.agents/backend/fm-branch-prompt.sh +101 -0
- package/.agents/backend/fm-brief.sh +452 -0
- package/.agents/backend/fm-busy-event.sh +234 -0
- package/.agents/backend/fm-busy-lib.sh +986 -0
- package/.agents/backend/fm-captain-hold.sh +1001 -0
- package/.agents/backend/fm-cd-command-policy.mjs +153 -0
- package/.agents/backend/fm-cd-pretool-check.sh +190 -0
- package/.agents/backend/fm-check-lib.sh +74 -0
- package/.agents/backend/fm-check-register.sh +42 -0
- package/.agents/backend/fm-check-unregister.sh +52 -0
- package/.agents/backend/fm-classify-lib.sh +1770 -0
- package/.agents/backend/fm-claude-stop-autoarm.sh +334 -0
- package/.agents/backend/fm-composer-lib.sh +1416 -0
- package/.agents/backend/fm-config-inherit-lib.sh +1202 -0
- package/.agents/backend/fm-config-push.sh +254 -0
- package/.agents/backend/fm-control-lib.sh +251 -0
- package/.agents/backend/fm-control.sh +878 -0
- package/.agents/backend/fm-crew-state.sh +625 -0
- package/.agents/backend/fm-cursor-lib.sh +243 -0
- package/.agents/backend/fm-decision-hold.sh +232 -0
- package/.agents/backend/fm-doc-audience-check.sh +269 -0
- package/.agents/backend/fm-dod-lib.sh +67 -0
- package/.agents/backend/fm-ensure-agents-md.sh +253 -0
- package/.agents/backend/fm-extension-launch-barrier.mjs +129 -0
- package/.agents/backend/fm-extension.mjs +2577 -0
- package/.agents/backend/fm-extension.sh +16 -0
- package/.agents/backend/fm-ff-lib.sh +420 -0
- package/.agents/backend/fm-fleet-snapshot.sh +1463 -0
- package/.agents/backend/fm-fleet-sync.sh +458 -0
- package/.agents/backend/fm-fleet-view.sh +96 -0
- package/.agents/backend/fm-gate-refuse-lib.sh +102 -0
- package/.agents/backend/fm-guard.sh +242 -0
- package/.agents/backend/fm-harness.sh +195 -0
- package/.agents/backend/fm-herdr-ci-cleanup.sh +115 -0
- package/.agents/backend/fm-herdr-lab.sh +346 -0
- package/.agents/backend/fm-herdr-session-cleanup.sh +337 -0
- package/.agents/backend/fm-home-seed.sh +984 -0
- package/.agents/backend/fm-home-summary-refresh.sh +255 -0
- package/.agents/backend/fm-hook-host-lib.sh +36 -0
- package/.agents/backend/fm-inactive-reconcile.sh +531 -0
- package/.agents/backend/fm-inbox.sh +399 -0
- package/.agents/backend/fm-install-actionlint.sh +84 -0
- package/.agents/backend/fm-install-herdr.sh +96 -0
- package/.agents/backend/fm-install-shellcheck.sh +84 -0
- package/.agents/backend/fm-install-treehouse.sh +95 -0
- package/.agents/backend/fm-kimi-turnend-hook.sh +276 -0
- package/.agents/backend/fm-lease-lib.sh +218 -0
- package/.agents/backend/fm-lease.sh +189 -0
- package/.agents/backend/fm-line-cap-lib.sh +51 -0
- package/.agents/backend/fm-lint-workflows.sh +137 -0
- package/.agents/backend/fm-lint.sh +591 -0
- package/.agents/backend/fm-lock-lib.sh +104 -0
- package/.agents/backend/fm-lock.sh +107 -0
- package/.agents/backend/fm-marker-lib.sh +12 -0
- package/.agents/backend/fm-merge-local.sh +74 -0
- package/.agents/backend/fm-merge-outcome-lib.sh +138 -0
- package/.agents/backend/fm-nm-run-lib.sh +124 -0
- package/.agents/backend/fm-on.sh +125 -0
- package/.agents/backend/fm-operational-input.sh +253 -0
- package/.agents/backend/fm-peek.sh +46 -0
- package/.agents/backend/fm-pending-reply-lib.sh +1409 -0
- package/.agents/backend/fm-pr-check.sh +135 -0
- package/.agents/backend/fm-pr-lib.sh +1016 -0
- package/.agents/backend/fm-pr-merge.sh +707 -0
- package/.agents/backend/fm-pr-poll.sh +110 -0
- package/.agents/backend/fm-primary-scope-lib.sh +33 -0
- package/.agents/backend/fm-procevent-extension-capture.pl +259 -0
- package/.agents/backend/fm-procevent-lavish.sh +628 -0
- package/.agents/backend/fm-procevent-lib.sh +892 -0
- package/.agents/backend/fm-procevent-quota.sh +290 -0
- package/.agents/backend/fm-procevent-remote-reply.sh +577 -0
- package/.agents/backend/fm-procevent-when.sh +504 -0
- package/.agents/backend/fm-procevent.sh +1466 -0
- package/.agents/backend/fm-project-mode.sh +92 -0
- package/.agents/backend/fm-project-origin-lib.sh +180 -0
- package/.agents/backend/fm-promote.sh +282 -0
- package/.agents/backend/fm-public-followup-emit.sh +260 -0
- package/.agents/backend/fm-public-followup-lib.sh +398 -0
- package/.agents/backend/fm-public-followup.sh +1330 -0
- package/.agents/backend/fm-push-transition-lib.sh +168 -0
- package/.agents/backend/fm-quota-axi-lib.sh +93 -0
- package/.agents/backend/fm-quota-choose.sh +384 -0
- package/.agents/backend/fm-remote-delta-read.sh +189 -0
- package/.agents/backend/fm-remote-doctor.sh +800 -0
- package/.agents/backend/fm-remote-entrypoint.sh +193 -0
- package/.agents/backend/fm-remote-file.sh +234 -0
- package/.agents/backend/fm-remote-home-provision.sh +259 -0
- package/.agents/backend/fm-remote-home-seed.sh +259 -0
- package/.agents/backend/fm-remote-inherit-push.sh +90 -0
- package/.agents/backend/fm-remote-inherit.sh +179 -0
- package/.agents/backend/fm-remote-job-lib.sh +1241 -0
- package/.agents/backend/fm-remote-job-reap-orphans.sh +137 -0
- package/.agents/backend/fm-remote-job-worker.sh +1124 -0
- package/.agents/backend/fm-remote-readiness-lib.sh +44 -0
- package/.agents/backend/fm-remote-secondmate-control.sh +340 -0
- package/.agents/backend/fm-review-diff.sh +158 -0
- package/.agents/backend/fm-secondmate-charter-lib.sh +44 -0
- package/.agents/backend/fm-secondmate-nudge-lib.sh +68 -0
- package/.agents/backend/fm-secondmate-parent-lib.sh +70 -0
- package/.agents/backend/fm-secondmate-reconcile.sh +371 -0
- package/.agents/backend/fm-secondmate-registry-lib.sh +311 -0
- package/.agents/backend/fm-secondmate-report.sh +88 -0
- package/.agents/backend/fm-send.sh +1059 -0
- package/.agents/backend/fm-session-lock-lib.sh +176 -0
- package/.agents/backend/fm-session-start.sh +970 -0
- package/.agents/backend/fm-sessionstart-cursor.sh +40 -0
- package/.agents/backend/fm-sessionstart-nudge.sh +45 -0
- package/.agents/backend/fm-sessionstart-run.sh +145 -0
- package/.agents/backend/fm-spawn.sh +3153 -0
- package/.agents/backend/fm-startup-memory-budget-lib.sh +224 -0
- package/.agents/backend/fm-startup-memory-budget.sh +94 -0
- package/.agents/backend/fm-startup-network.sh +642 -0
- package/.agents/backend/fm-stow-cascade.sh +251 -0
- package/.agents/backend/fm-subagent-pretool-check.sh +207 -0
- package/.agents/backend/fm-supervise-daemon.sh +1732 -0
- package/.agents/backend/fm-supervision-instructions.sh +215 -0
- package/.agents/backend/fm-supervision-lib.sh +90 -0
- package/.agents/backend/fm-supervisor-target-lib.sh +78 -0
- package/.agents/backend/fm-tangle-lib.sh +53 -0
- package/.agents/backend/fm-task-inbox-lib.sh +402 -0
- package/.agents/backend/fm-tasks-axi-lib.sh +123 -0
- package/.agents/backend/fm-teardown.sh +2922 -0
- package/.agents/backend/fm-test-isolation-proof.sh +588 -0
- package/.agents/backend/fm-test-run.sh +2191 -0
- package/.agents/backend/fm-timeout-lib.sh +141 -0
- package/.agents/backend/fm-timing-lib.sh +179 -0
- package/.agents/backend/fm-tmux-lib.sh +291 -0
- package/.agents/backend/fm-tool-update-check.sh +898 -0
- package/.agents/backend/fm-trace-context-lib.sh +227 -0
- package/.agents/backend/fm-transition-lib.sh +103 -0
- package/.agents/backend/fm-turnend-guard-cursor.sh +391 -0
- package/.agents/backend/fm-turnend-guard-grok.sh +90 -0
- package/.agents/backend/fm-turnend-guard.sh +432 -0
- package/.agents/backend/fm-update.sh +110 -0
- package/.agents/backend/fm-vendor-auth-probe.sh +190 -0
- package/.agents/backend/fm-voice-client.py +1373 -0
- package/.agents/backend/fm-voice-relay.py +1256 -0
- package/.agents/backend/fm-wake-drain.sh +592 -0
- package/.agents/backend/fm-wake-grant.sh +127 -0
- package/.agents/backend/fm-wake-lib.sh +1849 -0
- package/.agents/backend/fm-watch-arm.sh +602 -0
- package/.agents/backend/fm-watch-checkpoint.sh +109 -0
- package/.agents/backend/fm-watch.sh +1962 -0
- package/.agents/backend/fm-x-dismiss.sh +116 -0
- package/.agents/backend/fm-x-followup.sh +286 -0
- package/.agents/backend/fm-x-lib.sh +1000 -0
- package/.agents/backend/fm-x-link.sh +234 -0
- package/.agents/backend/fm-x-poll.sh +185 -0
- package/.agents/backend/fm-x-reply.sh +385 -0
- package/.agents/backend/fm_voice_frame.py +166 -0
- package/.agents/backend/fm_voice_records.py +574 -0
- package/.agents/backend/model-bridge.py +360 -0
- package/.agents/backend/opencode-go-bridge.py +30 -0
- package/.agents/bus/README.md +12 -0
- package/.agents/bus/messages.json +1 -0
- package/.agents/config/agents.machine.example.yaml +16 -0
- package/.agents/config/agents.yaml.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +11 -0
- package/.agents/config/eindri-dispatch.json +67 -0
- package/.agents/config/eindri-harness +1 -0
- package/.agents/config/startup-memory-budget +1 -0
- package/.agents/filebrowser/.filebrowser.json +6 -0
- package/.agents/filebrowser/README.md +11 -0
- package/.agents/gateway/README.md +12 -0
- package/.agents/github/README.md +15 -0
- package/.agents/github/webhooks/.gitkeep +0 -0
- package/.agents/github/workflows/.gitkeep +0 -0
- package/.agents/harness/opencode/plugins/lib/rodd-operational-input.js +37 -0
- package/.agents/harness/opencode/plugins/package.json +4 -0
- package/.agents/harness/opencode/plugins/saga-sessionstart.js +77 -0
- package/.agents/harness/opencode/plugins/syn-cd-check.js +61 -0
- package/.agents/harness/opencode/plugins/syn-pretool-check.js +68 -0
- package/.agents/harness/opencode/plugins/syn-turnend-guard.js +105 -0
- package/.agents/harness/opencode/plugins/syn-watch-arm.js +521 -0
- package/.agents/memory/README.md +46 -0
- package/.agents/memory/runes_audit.md +5 -0
- package/.agents/migrations/0001-hodd-layout.sh +38 -0
- package/.agents/migrations/0002-a2a-mcp.sh +27 -0
- package/.agents/migrations/0003-private-data-separation.sh +121 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -0
- package/.agents/migrations/0005-roots-out-of-tree.sh +158 -0
- package/.agents/sandbox/Dockerfile.utgard +19 -0
- package/.agents/sandbox/README.md +14 -0
- package/.agents/sandbox/utgard.config.json +14 -0
- package/.agents/skills/README.md +59 -0
- package/.agents/skills/bragi-marketing/README.md +3 -0
- package/.agents/skills/bragi-marketing/SKILL.md +82 -0
- package/.agents/skills/eindri-homes/README.md +3 -0
- package/.agents/skills/eindri-homes/SKILL.md +291 -0
- package/.agents/skills/eindri-homes/assets/control-plane.md +122 -0
- package/.agents/skills/eindri-homes/assets/dispatch.md +80 -0
- package/.agents/skills/frigg-consent/README.md +3 -0
- package/.agents/skills/frigg-consent/SKILL.md +56 -0
- package/.agents/skills/galdr-ymirsystem/README.md +3 -0
- package/.agents/skills/galdr-ymirsystem/SKILL.md +159 -0
- package/.agents/skills/galdr-ymirsystem/assets/README.md +74 -0
- package/.agents/skills/galdr-ymirsystem/assets/brokk-distro-runtime.md +390 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-method.md +113 -0
- package/.agents/skills/galdr-ymirsystem/assets/build-tool-categories.md +178 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-orchestration.md +518 -0
- package/.agents/skills/galdr-ymirsystem/assets/eindri-profiles.md +136 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/README.md +736 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/claude-code.md +197 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/codex.md +191 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/cursor.md +193 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/opencode.md +262 -0
- package/.agents/skills/galdr-ymirsystem/assets/harness-integration/pi.md +295 -0
- package/.agents/skills/galdr-ymirsystem/assets/hlidskjalf-ui.md +539 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +763 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models/HOST-DATA.example.md +72 -0
- package/.agents/skills/galdr-ymirsystem/assets/local-models.md +274 -0
- package/.agents/skills/galdr-ymirsystem/assets/memory-well.md +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +415 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +133 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/einherjar-spawn.schema.json +81 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/herdr-profile.toml +75 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/pi-profile.yml +101 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot/supervision-tree.yml +163 -0
- package/.agents/skills/galdr-ymirsystem/assets/pi-boot-guide.md +58 -0
- package/.agents/skills/galdr-ymirsystem/assets/porting-upstream-to-norse.md +301 -0
- package/.agents/skills/galdr-ymirsystem/assets/principles.md +385 -0
- package/.agents/skills/galdr-ymirsystem/assets/reference-adoption.md +99 -0
- package/.agents/skills/galdr-ymirsystem/assets/registry.md +379 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-compliance.md +463 -0
- package/.agents/skills/galdr-ymirsystem/assets/runtime-components.md +553 -0
- package/.agents/skills/galdr-ymirsystem/assets/smidja.md +180 -0
- package/.agents/skills/galdr-ymirsystem/schemas/toon-schemas.md +190 -0
- package/.agents/skills/galdr-ymirsystem/scripts/README.md +45 -0
- package/.agents/skills/galdr-ymirsystem/scripts/bench-one.sh +248 -0
- package/.agents/skills/galdr-ymirsystem/scripts/compliance-check.sh +503 -0
- package/.agents/skills/galdr-ymirsystem/scripts/gpu-sample.sh +43 -0
- package/.agents/skills/galdr-ymirsystem/scripts/stop-all.sh +34 -0
- package/.agents/skills/galdr-ymirsystem/scripts/toon-check.py +188 -0
- package/.agents/skills/gjallarhorn-relay/README.md +3 -0
- package/.agents/skills/gjallarhorn-relay/SKILL.md +283 -0
- package/.agents/skills/groa-update/SKILL.md +90 -0
- package/.agents/skills/hamr-adapters/README.md +3 -0
- package/.agents/skills/hamr-adapters/SKILL.md +123 -0
- package/.agents/skills/hamr-adapters/references/common/control-and-recovery.md +37 -0
- package/.agents/skills/hamr-adapters/references/common/dispatch.md +32 -0
- package/.agents/skills/hamr-adapters/references/common/model-and-effort.md +42 -0
- package/.agents/skills/hamr-adapters/references/common/primary-hooks.md +40 -0
- package/.agents/skills/hamr-adapters/references/harness/claude.md +55 -0
- package/.agents/skills/hamr-adapters/references/harness/codex.md +43 -0
- package/.agents/skills/hamr-adapters/references/harness/cursor.md +75 -0
- package/.agents/skills/hamr-adapters/references/harness/grok.md +69 -0
- package/.agents/skills/hamr-adapters/references/harness/kimi.md +51 -0
- package/.agents/skills/hamr-adapters/references/harness/muse.md +70 -0
- package/.agents/skills/hamr-adapters/references/harness/opencode.md +42 -0
- package/.agents/skills/hamr-adapters/references/harness/pi.md +56 -0
- package/.agents/skills/herdr-panes/README.md +3 -0
- package/.agents/skills/herdr-panes/SKILL.md +92 -0
- package/.agents/skills/herdr-panes/assets/herdr-backend.md +346 -0
- package/.agents/skills/herdr-panes/assets/tmux-backend.md +115 -0
- package/.agents/skills/hnoss-design/DESIGN.md +19 -0
- package/.agents/skills/hnoss-design/README.md +3 -0
- package/.agents/skills/hnoss-design/SKILL.md +83 -0
- package/.agents/skills/hvild-afk/README.md +3 -0
- package/.agents/skills/hvild-afk/SKILL.md +241 -0
- package/.agents/skills/jord-projects/README.md +3 -0
- package/.agents/skills/jord-projects/SKILL.md +92 -0
- package/.agents/skills/lifecycle/SKILL.md +56 -0
- package/.agents/skills/lifecycle/smoke_test.sh +57 -0
- package/.agents/skills/lifecycle/start.sh +21 -0
- package/.agents/skills/lifecycle/status.sh +35 -0
- package/.agents/skills/lifecycle/stop.sh +16 -0
- package/.agents/skills/muninn-stow/README.md +3 -0
- package/.agents/skills/muninn-stow/SKILL.md +309 -0
- package/.agents/skills/no-mistakes/SKILL.md +379 -0
- package/.agents/skills/nornir-schedule/README.md +3 -0
- package/.agents/skills/nornir-schedule/SKILL.md +25 -0
- package/.agents/skills/nornir-schedule/assets/events.md +137 -0
- package/.agents/skills/nornir-schedule/assets/quota.md +131 -0
- package/.agents/skills/nsr-compliance/README.md +3 -0
- package/.agents/skills/nsr-compliance/SKILL.md +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/README.md +40 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/git-workflow.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/security.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/RULES/tech-stack.md +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/NSRcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/README.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/README.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/features/SKILL-template.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/SKILL.md +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/create_branch.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/safe_commit.sh +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/git_ops/sync_upstream.sh +6 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/README.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/SKILL.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/smoke_test.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/start.sh +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/status.sh +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/agents_skills/lifecycle/stop.sh +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/config/core_four.yaml +13 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/compliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/README.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/api.md +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/compliance-wiring.md +155 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/BEST_PRACTICES/frontend.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/README.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/clients/template-README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/deploy.sh +49 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/development.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/production.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/envs/staging.env.example +17 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/CI_CD/deployment/tenants/template.env.example +8 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/README.md +26 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/agent.md +7 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/developers/dev-1.md +20 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/linux.md +9 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/macos.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/shared.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/DEVELOPER_SETUP/windows.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/README.md +25 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/_template.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/HOSTING/hosting-1.md +41 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/README.md +21 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/README.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/deployment.md +19 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/disaster-recovery.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/RUNBOOK/ops-tasks.md +14 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/features/README.md +16 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/project-skills.md +146 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/research/software-compliance-research.md +269 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/docs/working-with-agents.md +260 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/AGENTS.md +38 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/ARCHITECTURE.md +36 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/BEST_PRACTICES.md +27 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/CI_CD.md +23 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/FEATURES.md +15 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/README.md +22 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/RULES.md +37 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/STRUCTURE.md +45 -0
- package/.agents/skills/nsr-compliance/assets/nsr/assets/root/TECH_STACK.md +28 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scaffold-spec.md +63 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/scaffold.sh +103 -0
- package/.agents/skills/nsr-compliance/assets/nsr/scripts/validate.sh +52 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/SKILL.md +71 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/config/core_four.yaml +16 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_danger.sh +102 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/check_wiring.sh +69 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/validate_code.sh +29 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/gates/verify_docs.py +66 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/generate.sh +109 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/result_envelope.json +14 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/envelopes/task_envelope.json +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/harness/runner.py +303 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/telemetry/logger.py +112 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/README.md +18 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/config/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/README.md +12 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_env.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_paths.sh +20 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/gates/check_platform.sh +23 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/README.md +11 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/harness/envelopes/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/README.md +10 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/installer/install.sh +125 -0
- package/.agents/skills/nsr-compliance/assets/nsrcompliance/templates/compliance/telemetry/README.md +11 -0
- package/.agents/skills/pr-ops/README.md +3 -0
- package/.agents/skills/pr-ops/SKILL.md +109 -0
- package/.agents/skills/ratatoskr-a2a/README.md +3 -0
- package/.agents/skills/ratatoskr-a2a/SKILL.md +148 -0
- package/.agents/skills/rules-check-drift/SKILL.md +81 -0
- package/.agents/skills/saga-bearings/README.md +3 -0
- package/.agents/skills/saga-bearings/SKILL.md +26 -0
- package/.agents/skills/saga-bearings/assets/bearings.md +161 -0
- package/.agents/skills/saga-bearings/assets/board-template.html +731 -0
- package/.agents/skills/saga-bearings/assets/recap.md +56 -0
- package/.agents/skills/syn-recovery/README.md +3 -0
- package/.agents/skills/syn-recovery/SKILL.md +54 -0
- package/.agents/skills/tyr-check/README.md +3 -0
- package/.agents/skills/tyr-check/SKILL.md +218 -0
- package/.agents/skills/urdh-hold/README.md +3 -0
- package/.agents/skills/urdh-hold/SKILL.md +25 -0
- package/.agents/skills/urdh-hold/assets/decisions.md +15 -0
- package/.agents/skills/urdh-hold/assets/hold.md +54 -0
- package/.agents/skills/vor-diagnostics/README.md +3 -0
- package/.agents/skills/vor-diagnostics/SKILL.md +68 -0
- package/.agents/skills/ymir-host/README.md +3 -0
- package/.agents/skills/ymir-host/SKILL.md +35 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -0
- package/.agents/skills/ymir-host/assets/install.md +69 -0
- package/.agents/skills/ymir-host/assets/omarchy.md +297 -0
- package/.agents/skills/ymir-host/assets/runbooks.md +15 -0
- package/.agents/skills/ymir-host/assets/thjazi.md +220 -0
- package/.agents/skills/ymir-host/assets/update.md +64 -0
- package/.agents/tests/assets/board-render-harness.mjs +117 -0
- package/.agents/tests/cmux-test-safety.sh +51 -0
- package/.agents/tests/fixtures.sh +291 -0
- package/.agents/tests/fm-afk-inject-e2e.test.sh +428 -0
- package/.agents/tests/fm-afk-inject-herdr-e2e.test.sh +536 -0
- package/.agents/tests/fm-afk-launch.test.sh +961 -0
- package/.agents/tests/fm-afk-pi-herdr-return-e2e.test.sh +297 -0
- package/.agents/tests/fm-afk-return.test.sh +283 -0
- package/.agents/tests/fm-arm-pretool-check.test.sh +482 -0
- package/.agents/tests/fm-ask-user-authority.test.sh +42 -0
- package/.agents/tests/fm-backend-autodetect-smoke.test.sh +176 -0
- package/.agents/tests/fm-backend-cmux-smoke.test.sh +188 -0
- package/.agents/tests/fm-backend-cmux.test.sh +1166 -0
- package/.agents/tests/fm-backend-herdr-eventwait-smoke.test.sh +136 -0
- package/.agents/tests/fm-backend-herdr-eventwait.test.py +106 -0
- package/.agents/tests/fm-backend-herdr-focus-flash-e2e.test.sh +409 -0
- package/.agents/tests/fm-backend-herdr-launcher-workspace-e2e.test.sh +437 -0
- package/.agents/tests/fm-backend-herdr-presentation-e2e.test.sh +1424 -0
- package/.agents/tests/fm-backend-herdr-prune-safety-e2e.test.sh +180 -0
- package/.agents/tests/fm-backend-herdr-respawn-idem-e2e.test.sh +182 -0
- package/.agents/tests/fm-backend-herdr-smoke.test.sh +355 -0
- package/.agents/tests/fm-backend-herdr-workspace-per-home-e2e.test.sh +251 -0
- package/.agents/tests/fm-backend-herdr.test.sh +4606 -0
- package/.agents/tests/fm-backend-orca.test.sh +1357 -0
- package/.agents/tests/fm-backend-tmux-smoke.test.sh +173 -0
- package/.agents/tests/fm-backend-zellij-smoke.test.sh +205 -0
- package/.agents/tests/fm-backend-zellij.test.sh +1360 -0
- package/.agents/tests/fm-backend.test.sh +1142 -0
- package/.agents/tests/fm-backlog-atomicity.test.sh +2302 -0
- package/.agents/tests/fm-backlog-handoff.test.sh +1360 -0
- package/.agents/tests/fm-bearings-board-render.test.sh +135 -0
- package/.agents/tests/fm-bearings-board.test.sh +414 -0
- package/.agents/tests/fm-bearings-snapshot.test.sh +1990 -0
- package/.agents/tests/fm-bootstrap-network-parallel.test.sh +316 -0
- package/.agents/tests/fm-bootstrap.test.sh +1178 -0
- package/.agents/tests/fm-branch-supervision.test.sh +552 -0
- package/.agents/tests/fm-brief.test.sh +785 -0
- package/.agents/tests/fm-busy-adapter-wiring.test.sh +324 -0
- package/.agents/tests/fm-busy-state.test.sh +465 -0
- package/.agents/tests/fm-calm-pi-extension.test.sh +3979 -0
- package/.agents/tests/fm-captain-hold-lifecycle.test.sh +1187 -0
- package/.agents/tests/fm-cd-pretool-check.test.sh +400 -0
- package/.agents/tests/fm-check-unregister.test.sh +198 -0
- package/.agents/tests/fm-classify-corr-token.test.sh +543 -0
- package/.agents/tests/fm-classify-decision-key.test.sh +340 -0
- package/.agents/tests/fm-claude-stop-autoarm-live-e2e.test.sh +164 -0
- package/.agents/tests/fm-claude-stop-autoarm.test.sh +1190 -0
- package/.agents/tests/fm-cmux-claude-composer-live-e2e.test.sh +110 -0
- package/.agents/tests/fm-codex-continuity-live-e2e.test.sh +55 -0
- package/.agents/tests/fm-composer-ghost.test.sh +716 -0
- package/.agents/tests/fm-composer-lib.test.sh +666 -0
- package/.agents/tests/fm-composer-matrix-live-e2e.test.sh +220 -0
- package/.agents/tests/fm-control-herdr-smoke.test.sh +149 -0
- package/.agents/tests/fm-control-relaunch.test.sh +1530 -0
- package/.agents/tests/fm-control.test.sh +910 -0
- package/.agents/tests/fm-crew-state.test.sh +1610 -0
- package/.agents/tests/fm-cursor-harness.test.sh +404 -0
- package/.agents/tests/fm-cursor-primary-live-e2e.test.sh +217 -0
- package/.agents/tests/fm-cursor-primary.test.sh +708 -0
- package/.agents/tests/fm-daemon.test.sh +2740 -0
- package/.agents/tests/fm-documentation-audiences.test.sh +141 -0
- package/.agents/tests/fm-ensure-agents-md.test.sh +371 -0
- package/.agents/tests/fm-extension-binding.test.sh +2187 -0
- package/.agents/tests/fm-fleet-snapshot-view.test.sh +816 -0
- package/.agents/tests/fm-fleet-sync.test.sh +721 -0
- package/.agents/tests/fm-gate-refuse.test.sh +356 -0
- package/.agents/tests/fm-gitignore-config.test.sh +89 -0
- package/.agents/tests/fm-gotmp.test.sh +230 -0
- package/.agents/tests/fm-grok-continuity-live-e2e.test.sh +112 -0
- package/.agents/tests/fm-grok-harness.test.sh +117 -0
- package/.agents/tests/fm-grok-stop-live-e2e.test.sh +219 -0
- package/.agents/tests/fm-guard-stale-banner.test.sh +709 -0
- package/.agents/tests/fm-harness-adapter-instructions-live-e2e.test.sh +134 -0
- package/.agents/tests/fm-harness-adapter-references.test.sh +30 -0
- package/.agents/tests/fm-harness-liveness-drift-live-e2e.test.sh +151 -0
- package/.agents/tests/fm-herdr-lab.test.sh +243 -0
- package/.agents/tests/fm-herdr-session-cleanup-e2e.test.sh +146 -0
- package/.agents/tests/fm-herdr-session-cleanup.test.sh +329 -0
- package/.agents/tests/fm-herdr-submit-confirm-live-e2e.test.sh +125 -0
- package/.agents/tests/fm-herdr-version-floor-live-e2e.test.sh +144 -0
- package/.agents/tests/fm-home-summary-refresh.test.sh +971 -0
- package/.agents/tests/fm-inactive-reconcile.test.sh +485 -0
- package/.agents/tests/fm-kimi-harness.test.sh +687 -0
- package/.agents/tests/fm-lint-workflows.test.sh +532 -0
- package/.agents/tests/fm-lint.test.sh +1023 -0
- package/.agents/tests/fm-muse-harness.test.sh +932 -0
- package/.agents/tests/fm-muse-signals-live-e2e.test.sh +205 -0
- package/.agents/tests/fm-no-mistakes-required.test.sh +72 -0
- package/.agents/tests/fm-on.test.sh +507 -0
- package/.agents/tests/fm-opencode-primary-live-e2e.test.sh +357 -0
- package/.agents/tests/fm-operational-input.test.sh +160 -0
- package/.agents/tests/fm-peek-remote.test.sh +110 -0
- package/.agents/tests/fm-pending-reply.test.sh +1288 -0
- package/.agents/tests/fm-pi-branch-extension.test.sh +3182 -0
- package/.agents/tests/fm-pi-branch-live-e2e.test.sh +527 -0
- package/.agents/tests/fm-pi-primary-live-e2e.test.sh +345 -0
- package/.agents/tests/fm-pi-primary-types.test.sh +68 -0
- package/.agents/tests/fm-pi-watch-extension.test.sh +2843 -0
- package/.agents/tests/fm-pr-check-security.test.sh +2140 -0
- package/.agents/tests/fm-pr-merge.test.sh +2135 -0
- package/.agents/tests/fm-procevent-quota.test.sh +225 -0
- package/.agents/tests/fm-procevent-when.test.sh +406 -0
- package/.agents/tests/fm-procevent.test.sh +1745 -0
- package/.agents/tests/fm-project-origin.test.sh +110 -0
- package/.agents/tests/fm-public-followup.test.sh +2272 -0
- package/.agents/tests/fm-quota-array-dispatch-live-e2e.test.sh +526 -0
- package/.agents/tests/fm-quota-choose.test.sh +626 -0
- package/.agents/tests/fm-remote-backlog-handoff.test.sh +453 -0
- package/.agents/tests/fm-remote-doctor.test.sh +625 -0
- package/.agents/tests/fm-remote-entrypoint.test.sh +59 -0
- package/.agents/tests/fm-remote-job-orphan-reap.test.sh +205 -0
- package/.agents/tests/fm-remote-job.test.sh +768 -0
- package/.agents/tests/fm-remote-reply.test.sh +520 -0
- package/.agents/tests/fm-remote-secondmate-lifecycle-e2e.test.sh +1256 -0
- package/.agents/tests/fm-remote-secondmate-parent-binding.test.sh +326 -0
- package/.agents/tests/fm-remote-secondmate-trace-context.test.sh +310 -0
- package/.agents/tests/fm-remote-transport-lanes.test.sh +431 -0
- package/.agents/tests/fm-review-diff.test.sh +176 -0
- package/.agents/tests/fm-secondmate-harness.test.sh +2600 -0
- package/.agents/tests/fm-secondmate-lifecycle-e2e.test.sh +259 -0
- package/.agents/tests/fm-secondmate-liveness.test.sh +559 -0
- package/.agents/tests/fm-secondmate-reconcile.test.sh +732 -0
- package/.agents/tests/fm-secondmate-safety.test.sh +2972 -0
- package/.agents/tests/fm-secondmate-sync.test.sh +913 -0
- package/.agents/tests/fm-send-inbox-doorbell-live-e2e.test.sh +206 -0
- package/.agents/tests/fm-send-inbox.test.sh +352 -0
- package/.agents/tests/fm-send-popup-settle.test.sh +167 -0
- package/.agents/tests/fm-send-remote-delivery.test.sh +796 -0
- package/.agents/tests/fm-send-resolve-key.test.sh +551 -0
- package/.agents/tests/fm-send-secondmate-marker-herdr-e2e.test.sh +187 -0
- package/.agents/tests/fm-send-secondmate-marker.test.sh +278 -0
- package/.agents/tests/fm-send-settle.test.sh +147 -0
- package/.agents/tests/fm-send-strict.test.sh +241 -0
- package/.agents/tests/fm-session-lock-ancestry.test.sh +365 -0
- package/.agents/tests/fm-session-start.test.sh +2515 -0
- package/.agents/tests/fm-sessionstart-hook-live-e2e.test.sh +631 -0
- package/.agents/tests/fm-sessionstart-instruction-refresh-live-e2e.test.sh +230 -0
- package/.agents/tests/fm-sessionstart-nudge.test.sh +1039 -0
- package/.agents/tests/fm-shared-captain-inheritance.test.sh +404 -0
- package/.agents/tests/fm-spawn-batch.test.sh +148 -0
- package/.agents/tests/fm-spawn-dispatch-profile.test.sh +827 -0
- package/.agents/tests/fm-spawn-pool-base-freshen.test.sh +440 -0
- package/.agents/tests/fm-spawn-worktree-settle.test.sh +147 -0
- package/.agents/tests/fm-startup-memory-budget.test.sh +333 -0
- package/.agents/tests/fm-startup-network.test.sh +712 -0
- package/.agents/tests/fm-stow-cascade.test.sh +370 -0
- package/.agents/tests/fm-subagent-pretool-check.test.sh +291 -0
- package/.agents/tests/fm-supervision-events.test.sh +156 -0
- package/.agents/tests/fm-supervision-instructions.test.sh +189 -0
- package/.agents/tests/fm-tangle-guard.test.sh +277 -0
- package/.agents/tests/fm-task-delivery.test.sh +420 -0
- package/.agents/tests/fm-task-inbox.test.sh +513 -0
- package/.agents/tests/fm-teardown-endpoint-safety.test.sh +374 -0
- package/.agents/tests/fm-teardown.test.sh +2665 -0
- package/.agents/tests/fm-test-fixture-cleanup.test.sh +172 -0
- package/.agents/tests/fm-test-fixtures.test.sh +132 -0
- package/.agents/tests/fm-test-isolation-proof.test.sh +278 -0
- package/.agents/tests/fm-test-run.test.sh +1196 -0
- package/.agents/tests/fm-tmux-agent-liveness.test.sh +354 -0
- package/.agents/tests/fm-tmux-submit-busy.test.sh +340 -0
- package/.agents/tests/fm-tool-update-check.test.sh +1044 -0
- package/.agents/tests/fm-trace-context-lib.test.sh +253 -0
- package/.agents/tests/fm-trace-context-spawn.test.sh +581 -0
- package/.agents/tests/fm-transition-lib.test.sh +54 -0
- package/.agents/tests/fm-turnend-guard.test.sh +1822 -0
- package/.agents/tests/fm-update.test.sh +304 -0
- package/.agents/tests/fm-vendor-auth-probe.test.sh +395 -0
- package/.agents/tests/fm-voice-relay.test.sh +4741 -0
- package/.agents/tests/fm-wake-daemon-lifecycle-e2e.test.sh +171 -0
- package/.agents/tests/fm-wake-drain-open-decisions-cursor.test.sh +356 -0
- package/.agents/tests/fm-wake-drain-open-decisions.test.sh +226 -0
- package/.agents/tests/fm-wake-drain-unread-status.test.sh +379 -0
- package/.agents/tests/fm-wake-queue.test.sh +1224 -0
- package/.agents/tests/fm-watch-arm.test.sh +821 -0
- package/.agents/tests/fm-watch-checkpoint.test.sh +87 -0
- package/.agents/tests/fm-watch-recovery-loop.test.sh +223 -0
- package/.agents/tests/fm-watch-triage.test.sh +3889 -0
- package/.agents/tests/fm-watcher-lock.test.sh +1133 -0
- package/.agents/tests/fm-x-mode.test.sh +3042 -0
- package/.agents/tests/gleipnir-guard-pretool-check.test.sh +51 -0
- package/.agents/tests/gleipnir-machine-lock.test.sh +130 -0
- package/.agents/tests/herdr-test-safety.sh +42 -0
- package/.agents/tests/lib.sh +315 -0
- package/.agents/tests/remote-herdr-fixture.sh +125 -0
- package/.agents/tests/secondmate-helpers.sh +193 -0
- package/.agents/tests/smoke.test.sh +93 -0
- package/.agents/tests/wake-helpers.sh +338 -0
- package/.agents/tests/zellij-test-safety.sh +60 -0
- package/.agents/tools/README.md +10 -0
- package/.agents/tools/bin/tasks-cli +267 -0
- package/.agents/tools/tasks-cli.ts +216 -0
- package/AGENTS.md +498 -0
- package/CHANGELOG.md +1913 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +114 -60
- package/RULES/01-domains.md +51 -0
- package/RULES/02-agents.md +78 -0
- package/RULES/03-houses.md +61 -0
- package/RULES/04-hoard.md +97 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +108 -0
- package/RULES/07-config.md +101 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/09-electron.md +58 -0
- package/RULES/README.md +22 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +133 -0
- package/bin/a2a-serve.py +103 -0
- package/bin/a2a-serve.sh +8 -0
- package/bin/a2a-talk.sh +50 -0
- package/bin/a2abridge-ensure.sh +108 -0
- package/bin/agent-run.sh +43 -0
- package/bin/agents-config.sh +256 -0
- package/bin/apodex-smoke-test.sh +105 -0
- package/bin/bifrost-bridge.sh +131 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +112 -0
- package/bin/bootstrap-windows.ps1 +112 -0
- package/bin/branch-guard.sh +64 -0
- package/bin/brokk +73 -0
- package/bin/brokk-classify-lib.sh +1770 -0
- package/bin/brokk-lease-lib.sh +222 -0
- package/bin/brokk-lease.sh +193 -0
- package/bin/brokk-lint.sh +65 -0
- package/bin/brokk-send.sh +51 -0
- package/bin/brokk-update.sh +9 -0
- package/bin/brokk-wake-grant.sh +127 -0
- package/bin/brokk-wake-lib.sh +1849 -0
- package/bin/changelog-assemble.sh +154 -0
- package/bin/changelog-guard.sh +197 -0
- package/bin/crash-sense.sh +173 -0
- package/bin/design-check.sh +80 -0
- package/bin/design-icon.sh +153 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +225 -0
- package/bin/eindri-acclaim.sh +47 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seat.sh +83 -0
- package/bin/eindri-seen.sh +54 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +98 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +158 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/feature-inventory.sh +73 -0
- package/bin/fleet-apply.sh +81 -0
- package/bin/github-deploy.sh +94 -0
- package/bin/gjallarhorn-expose.sh +136 -0
- package/bin/gjallarhorn-notify.sh +71 -0
- package/bin/gjallarhorn-purge.sh +67 -0
- package/bin/gjallarhorn-tunnel.sh +85 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +130 -0
- package/bin/hall-snapshot.sh +111 -0
- package/bin/hamr-harness.sh +246 -0
- package/bin/heimdall-ssh-keys.sh +374 -0
- package/bin/herdr-agents.py +44 -0
- package/bin/herdr-ensure.sh +104 -0
- package/bin/herdr-run.sh +452 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hlidskjalf-agents.sh +172 -0
- package/bin/hlidskjalf-usage.sh +196 -0
- package/bin/hoard-guard.sh +135 -0
- package/bin/hoard-lib.sh +105 -0
- package/bin/hodd.sh +102 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +121 -0
- package/bin/local-model-lock.sh +70 -0
- package/bin/mimir-bridge.py +259 -0
- package/bin/mimir-bridge.sh +100 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir-reflect.sh +27 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +72 -0
- package/bin/mjollnir.sh +104 -0
- package/bin/model-hardware.sh +96 -0
- package/bin/model-resolve.sh +160 -0
- package/bin/models-detect.sh +178 -0
- package/bin/nornir-cron-start.sh +162 -0
- package/bin/nornir-job-daily-briefing.sh +191 -0
- package/bin/nornir-job-git-sync.sh +152 -0
- package/bin/nornir-job-hall-snapshot.sh +28 -0
- package/bin/nornir-job-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-nsr-compliance.sh +54 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/npm-publish.sh +136 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +161 -0
- package/bin/omarchy-plugins.sh +187 -0
- package/bin/omarchy-sense.sh +162 -0
- package/bin/perm-guard.sh +30 -0
- package/bin/pi-agent.sh +68 -0
- package/bin/pi-ensure.sh +77 -0
- package/bin/pi-local.sh +37 -0
- package/bin/pi-model-agnostic.sh +71 -0
- package/bin/pi-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +58 -0
- package/bin/project-git.sh +69 -0
- package/bin/public-guard.sh +71 -0
- package/bin/ratatoskr.sh +49 -0
- package/bin/realm-lib.sh +32 -0
- package/bin/repo-scrub.sh +62 -0
- package/bin/rodd-operational-input.sh +250 -0
- package/bin/runes-append.sh +198 -0
- package/bin/saga-session-start.sh +172 -0
- package/bin/saga-sessionstart-run.sh +79 -0
- package/bin/saga-wake-drain.sh +41 -0
- package/bin/secret-guard.sh +63 -0
- package/bin/sessrumnir-ensure.sh +100 -0
- package/bin/sessrumnir-sync.sh +237 -0
- package/bin/sessrumnir.sh +104 -0
- package/bin/skillopt-setup.sh +76 -0
- package/bin/skuld-branch-outcome.sh +203 -0
- package/bin/skuld-branch-prompt.sh +101 -0
- package/bin/smidja-bootstrap.sh +94 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +89 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-spawn-pretool-check.sh +58 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +203 -0
- package/bin/telegram-bot.sh +82 -0
- package/bin/toolchain.sh +74 -0
- package/bin/ui-truth-check.sh +75 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +298 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +60 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +163 -0
- package/bin/wyrd-db.sh +47 -0
- package/bin/yggdrasil.sh +152 -0
- package/bin/ymir-edit.sh +145 -0
- package/bin/ymir-install.sh +806 -0
- package/bin/ymir-invite.sh +93 -0
- package/bin/ymir-isolation.sh +88 -0
- package/bin/ymir-migrate.sh +61 -0
- package/bin/ymir-plan.sh +356 -0
- package/bin/ymir-platform.sh +348 -0
- package/bin/ymir-say.sh +110 -0
- package/bin/ymir-setup-auth.sh +119 -0
- package/bin/ymir-validate.sh +193 -0
- package/bin/ymir.js +74 -16
- package/docs/Architecture.md +339 -0
- package/docs/design.md +351 -0
- package/docs/installations/README.md +63 -0
- package/docs/installations/ymir-home.md +93 -0
- package/docs/integration.md +105 -0
- package/docs/lore.md +1060 -0
- package/docs/research/agent-harnesses.md +290 -0
- package/docs/runbooks/README.md +19 -0
- package/docs/runbooks/a2a.md +91 -0
- package/docs/runbooks/agent-permissions.md +99 -0
- package/docs/runbooks/agents.md +57 -0
- package/docs/runbooks/models.md +69 -0
- package/docs/runbooks/realm-onboarding.md +60 -0
- package/docs/runbooks/secrets-and-hoard.md +60 -0
- package/docs/runbooks/updates-and-migrations.md +110 -0
- package/docs/runbooks/worktrees-isolation.md +72 -0
- package/docs/session-start.md +105 -0
- package/docs/skillopt-integration.md +321 -0
- package/docs/sync-system.md +66 -0
- package/docs/workspaces.md +104 -0
- package/docs/ymir-rut.md +260 -0
- package/package.json +54 -14
- package/packaging/build.sh +74 -0
- package/packaging/macos/Ymir Installer.command +43 -0
- package/packaging/windows/ymir-setup.nsi +74 -0
- package/scripts/README.md +22 -0
- package/scripts/electron.sh +269 -0
- package/scripts/lower.sh +34 -0
- package/scripts/raise.sh +42 -0
- package/scripts/start.sh +217 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,796 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# fm-send remote-secondmate delivery: the remote inbox leg.
|
|
3
|
+
#
|
|
4
|
+
# A remote steer is delivered by durable record, never by typing its payload:
|
|
5
|
+
# fm-send crosses fm-on.sh to the host-local leg (fm-remote-secondmate-control.sh
|
|
6
|
+
# cmd_send), which writes the message idempotently into the remote home's
|
|
7
|
+
# steering inbox and rings the remote doorbell best-effort. These tests drive
|
|
8
|
+
# the real fm-send + fm-on executables with a stubbed ssh transport that
|
|
9
|
+
# EXECUTES the real host-local leg against a seeded remote-home fixture (the
|
|
10
|
+
# FM_SSH_BIN seam tests/fm-on.test.sh proves preserves exit status), and pin:
|
|
11
|
+
# 1. A remote text steer lands as a durable record in the remote home's
|
|
12
|
+
# steering inbox, marker and corr token in the body, exits 0, and marks
|
|
13
|
+
# the pending-reply expectation delivered at enqueue; a failed doorbell
|
|
14
|
+
# never fails the send.
|
|
15
|
+
# 2. Re-running the identical leg is idempotent: an ambiguous transport
|
|
16
|
+
# (executed remotely, then ssh exit 255) makes fm-send retry the same
|
|
17
|
+
# leg once, and the remote inbox holds exactly ONE record afterwards.
|
|
18
|
+
# 3. A remote --resolve-key answer closes its decision at enqueue.
|
|
19
|
+
# 4. A remote harness-native "/..." steer also rides the inbox: the deleted
|
|
20
|
+
# remote typed-payload plane is gone for every remote text.
|
|
21
|
+
# 5. A real remote failure still fails loudly with the remote leg's own
|
|
22
|
+
# stderr and discards the undelivered expectation.
|
|
23
|
+
# 6. The deleted exit-3-as-delivered remap is GONE: a nonzero remote leg
|
|
24
|
+
# status is a failure, never reported as delivered.
|
|
25
|
+
# 7. Pure transport loss (ssh 255 twice, nothing executed) fails with
|
|
26
|
+
# resend-safe guidance - the deleted "do not resend" trap is gone - and
|
|
27
|
+
# preserves the marked expectation for the record that may have landed.
|
|
28
|
+
# 8. A LOCAL typed-plane send (an explicit backend target or harness-native
|
|
29
|
+
# slash) keeps its exit-3 delivered-unconfirmed contract, never closes a
|
|
30
|
+
# --resolve-key decision unconfirmed, and keeps a marked expectation
|
|
31
|
+
# armed.
|
|
32
|
+
set -u
|
|
33
|
+
|
|
34
|
+
# shellcheck source=tests/lib.sh
|
|
35
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
36
|
+
# shellcheck source=bin/fm-pending-reply-lib.sh
|
|
37
|
+
. "$ROOT/bin/fm-pending-reply-lib.sh"
|
|
38
|
+
# shellcheck source=bin/fm-marker-lib.sh
|
|
39
|
+
. "$ROOT/bin/fm-marker-lib.sh"
|
|
40
|
+
# shellcheck source=bin/fm-task-inbox-lib.sh
|
|
41
|
+
. "$ROOT/bin/fm-task-inbox-lib.sh"
|
|
42
|
+
|
|
43
|
+
SEND="$ROOT/bin/fm-send.sh"
|
|
44
|
+
DRAIN="$ROOT/bin/fm-wake-drain.sh"
|
|
45
|
+
|
|
46
|
+
TMP_ROOT=$(fm_test_tmproot fm-send-remote-delivery)
|
|
47
|
+
TMP_ROOT=$(cd "$TMP_ROOT" && pwd)
|
|
48
|
+
|
|
49
|
+
# Stub tmux for the local typed-plane legs: logs literal typed text to
|
|
50
|
+
# FM_SEND_LOG. The default composer reads empty (clean submit);
|
|
51
|
+
# FM_FAKE_TMUX_PENDING=1 keeps a proven pending composer with no busy footer,
|
|
52
|
+
# so the real submit core exhausts its Enter budget and reports the pending
|
|
53
|
+
# verdict. The ssh stub counts invocations, logs the wire line, and either
|
|
54
|
+
# fails with FM_FAKE_SSH_RC (emitting FM_FAKE_SSH_STDERR as the remote
|
|
55
|
+
# stderr), or decodes the entrypoint argv and executes the REAL host-local
|
|
56
|
+
# command against the decoded remote home - with FM_FAKE_SSH_AMBIGUOUS=1
|
|
57
|
+
# reporting ssh exit 255 after that execution (completion unknown, but the
|
|
58
|
+
# remote leg actually ran).
|
|
59
|
+
make_stubs() { # <dir> -> echoes fakebin dir
|
|
60
|
+
local dir=$1 fb="$1/fakebin"
|
|
61
|
+
mkdir -p "$fb"
|
|
62
|
+
cat > "$fb/tmux" <<'SH'
|
|
63
|
+
#!/usr/bin/env bash
|
|
64
|
+
set -u
|
|
65
|
+
case "${1:-}" in
|
|
66
|
+
send-keys)
|
|
67
|
+
shift
|
|
68
|
+
literal=0
|
|
69
|
+
while [ $# -gt 0 ]; do
|
|
70
|
+
case "$1" in
|
|
71
|
+
-t) shift 2 ;;
|
|
72
|
+
-l) literal=1; shift ;;
|
|
73
|
+
*) break ;;
|
|
74
|
+
esac
|
|
75
|
+
done
|
|
76
|
+
if [ "$literal" = 1 ]; then
|
|
77
|
+
printf '%s' "${1:-}" >> "$FM_SEND_LOG"
|
|
78
|
+
fi
|
|
79
|
+
exit 0 ;;
|
|
80
|
+
display-message)
|
|
81
|
+
for a in "$@"; do case "$a" in *cursor_y*) printf '1\n'; exit 0 ;; esac; done
|
|
82
|
+
printf 'fakepane\n'; exit 0 ;;
|
|
83
|
+
capture-pane)
|
|
84
|
+
if [ "${FM_FAKE_TMUX_PENDING:-0}" = 1 ]; then
|
|
85
|
+
printf '╭────────────╮\n│ > steer │\n╰────────────╯\n'
|
|
86
|
+
else
|
|
87
|
+
printf '╭────╮\n│ │\n╰────╯\n'
|
|
88
|
+
fi
|
|
89
|
+
exit 0 ;;
|
|
90
|
+
list-windows) exit 0 ;;
|
|
91
|
+
esac
|
|
92
|
+
exit 0
|
|
93
|
+
SH
|
|
94
|
+
chmod +x "$fb/tmux"
|
|
95
|
+
cat > "$fb/sleep" <<'SH'
|
|
96
|
+
#!/usr/bin/env bash
|
|
97
|
+
exit 0
|
|
98
|
+
SH
|
|
99
|
+
chmod +x "$fb/sleep"
|
|
100
|
+
cat > "$fb/fake-ssh" <<'SH'
|
|
101
|
+
#!/usr/bin/env bash
|
|
102
|
+
set -u
|
|
103
|
+
cat > /dev/null
|
|
104
|
+
count=$(cat "$FM_SSH_COUNT" 2>/dev/null || echo 0)
|
|
105
|
+
count=$((count + 1))
|
|
106
|
+
printf '%s\n' "$count" > "$FM_SSH_COUNT"
|
|
107
|
+
printf '%s\n' "$*" >> "$FM_SSH_LOG"
|
|
108
|
+
if [ -n "${FM_FAKE_SSH_HANG:-}" ]; then
|
|
109
|
+
# A busy remote lane: the transport attempt never returns on its own. The
|
|
110
|
+
# real sleep, because the stubbed one on PATH returns immediately.
|
|
111
|
+
/bin/sleep "$FM_FAKE_SSH_HANG"
|
|
112
|
+
exit 255
|
|
113
|
+
fi
|
|
114
|
+
if [ "${FM_FAKE_SSH_AFTER_AMBIGUOUS_RC:-0}" -ne 0 ] && [ "$count" -gt 1 ]; then
|
|
115
|
+
exit "$FM_FAKE_SSH_AFTER_AMBIGUOUS_RC"
|
|
116
|
+
fi
|
|
117
|
+
if [ "${FM_FAKE_SSH_RC:-0}" -ne 0 ]; then
|
|
118
|
+
[ -z "${FM_FAKE_SSH_STDERR:-}" ] || printf '%s\n' "$FM_FAKE_SSH_STDERR" >&2
|
|
119
|
+
exit "${FM_FAKE_SSH_RC}"
|
|
120
|
+
fi
|
|
121
|
+
while [ "$#" -gt 0 ]; do
|
|
122
|
+
case "$1" in -o) shift 2 ;; --) shift; break ;; *) exit 90 ;; esac
|
|
123
|
+
done
|
|
124
|
+
shift 2 # host, fm-remote-entrypoint.sh
|
|
125
|
+
home_b64=$3
|
|
126
|
+
argv_b64=$4
|
|
127
|
+
remote_home=$(perl -MMIME::Base64=decode_base64 -e 'print decode_base64($ARGV[0])' "$home_b64")
|
|
128
|
+
rargs=()
|
|
129
|
+
while IFS= read -r -d '' a; do rargs+=("$a"); done \
|
|
130
|
+
< <(perl -MMIME::Base64=decode_base64 -e 'print decode_base64($ARGV[0])' "$argv_b64")
|
|
131
|
+
cmd=${rargs[0]}
|
|
132
|
+
rc=0
|
|
133
|
+
env FM_HOME="$remote_home" FM_ROOT_OVERRIDE="$FM_REMOTE_CODE_ROOT" \
|
|
134
|
+
"$FM_REMOTE_CODE_ROOT/bin/$cmd" "${rargs[@]:1}" || rc=$?
|
|
135
|
+
if [ "${FM_FAKE_SSH_AMBIGUOUS:-0}" = 1 ] \
|
|
136
|
+
|| { [ "${FM_FAKE_SSH_AFTER_AMBIGUOUS_RC:-0}" -ne 0 ] && [ "$count" -eq 1 ]; }; then
|
|
137
|
+
exit 255
|
|
138
|
+
fi
|
|
139
|
+
exit "$rc"
|
|
140
|
+
SH
|
|
141
|
+
chmod +x "$fb/fake-ssh"
|
|
142
|
+
printf '%s\n' "$fb"
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
setup_home() { # <name> -> echoes a fresh home dir with an empty state/
|
|
146
|
+
local home="$TMP_ROOT/$1-$RANDOM"
|
|
147
|
+
mkdir -p "$home/state"
|
|
148
|
+
printf '%s\n' "$home"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
# A seeded remote secondmate home the executed host-local leg validates and
|
|
152
|
+
# writes into: identity marker, Firstmate-checkout shape, and a parent-route
|
|
153
|
+
# endpoint record on Herdr in the dedicated fm-remote session.
|
|
154
|
+
setup_remote_secondmate_home() { # <name> -> echoes remote home dir
|
|
155
|
+
local rh="$TMP_ROOT/$1-rhome"
|
|
156
|
+
mkdir -p "$rh/state/parent-route" "$rh/bin"
|
|
157
|
+
printf 'rsm\n' > "$rh/.fm-secondmate-home"
|
|
158
|
+
printf '# remote secondmate home fixture\n' > "$rh/AGENTS.md"
|
|
159
|
+
fm_write_meta "$rh/state/parent-route/rsm.meta" \
|
|
160
|
+
"window=fm-remote:p1" \
|
|
161
|
+
"worktree=-" \
|
|
162
|
+
"project=-" \
|
|
163
|
+
"backend=herdr" \
|
|
164
|
+
"endpoint_task_id=rsm" \
|
|
165
|
+
"harness=claude" \
|
|
166
|
+
"herdr_session=fm-remote" \
|
|
167
|
+
"herdr_workspace_id=w1" \
|
|
168
|
+
"herdr_tab_id=t1" \
|
|
169
|
+
"herdr_pane_id=p1"
|
|
170
|
+
printf '%s\n' "$rh"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# A parent home with a remote-secondmate task meta plus the registry row
|
|
174
|
+
# fm-on.sh resolves the ssh route from, pointing at <remote-home>.
|
|
175
|
+
setup_remote_parent_home() { # <name> <remote-home> -> echoes home dir
|
|
176
|
+
local home
|
|
177
|
+
home=$(setup_home "$1")
|
|
178
|
+
mkdir -p "$home/data"
|
|
179
|
+
fm_write_meta "$home/state/rsm.meta" \
|
|
180
|
+
"window=fm-remote:p1" \
|
|
181
|
+
"endpoint_task_id=rsm" \
|
|
182
|
+
"harness=claude" \
|
|
183
|
+
"kind=secondmate" \
|
|
184
|
+
"mode=secondmate" \
|
|
185
|
+
"yolo=off" \
|
|
186
|
+
"remote_host=remote-mac" \
|
|
187
|
+
"remote_root=/remote/root" \
|
|
188
|
+
"remote_backend=herdr" \
|
|
189
|
+
"remote_herdr_session=fm-remote" \
|
|
190
|
+
"remote_target=fm-remote:p1"
|
|
191
|
+
cat > "$home/data/secondmates.md" <<EOF
|
|
192
|
+
- rsm - remote test domain (host: remote-mac; root: /remote/root; home: $2; scope: remote testing; projects: alpha; added 2026-08-02)
|
|
193
|
+
EOF
|
|
194
|
+
printf '%s\n' "$home"
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
remote_inbox_records() { # <remote-home>
|
|
198
|
+
find "$1/state/parent-route/rsm.inbox" -maxdepth 1 -name '*.msg' 2>/dev/null
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
# The single non-dot pending-reply record in <home>, or empty.
|
|
202
|
+
pending_record() { # <home>
|
|
203
|
+
find "$1/state/pending-replies" -maxdepth 1 -type f ! -name '.*' 2>/dev/null | head -1
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
drain_out() { # <home>
|
|
207
|
+
FM_STATE_OVERRIDE="$1/state" "$DRAIN" 2>/dev/null
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
send_env() { # <fakebin> <parent-home> <ssh-log> [extra env...] -- <cmd...>
|
|
211
|
+
local fb=$1 home=$2 ssh_log=$3
|
|
212
|
+
shift 3
|
|
213
|
+
env PATH="$fb:$PATH" \
|
|
214
|
+
FM_ROOT_OVERRIDE="$ROOT" FM_HOME="$home" FM_SEND_SETTLE=0 \
|
|
215
|
+
FM_SSH_BIN="$fb/fake-ssh" FM_SSH_LOG="$ssh_log" \
|
|
216
|
+
FM_SSH_COUNT="$ssh_log.count" FM_REMOTE_CODE_ROOT="$ROOT" \
|
|
217
|
+
"$@"
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
test_remote_steer_lands_in_remote_inbox() {
|
|
221
|
+
local dir fb ssh_log home rhome rc err rec recs body pend
|
|
222
|
+
dir="$TMP_ROOT/remote-inbox"; mkdir -p "$dir"
|
|
223
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
224
|
+
rhome=$(setup_remote_secondmate_home remote-inbox)
|
|
225
|
+
home=$(setup_remote_parent_home remote-inbox "$rhome")
|
|
226
|
+
|
|
227
|
+
rc=0
|
|
228
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
229
|
+
"$SEND" rsm "please rename the metric" >"$dir/out" 2>"$dir/err" || rc=$?
|
|
230
|
+
err=$(cat "$dir/err")
|
|
231
|
+
expect_code 0 "$rc" "a durably recorded remote steer must exit 0: $err"
|
|
232
|
+
assert_grep 'fm-remote-entrypoint.sh' "$ssh_log" "the steer should cross the remote transport"
|
|
233
|
+
recs=$(remote_inbox_records "$rhome")
|
|
234
|
+
[ -n "$recs" ] || fail "the steer must land as a record in the remote steering inbox"
|
|
235
|
+
rec=$(printf '%s\n' "$recs" | head -1)
|
|
236
|
+
body=$(cat "$rec")
|
|
237
|
+
case "$body" in
|
|
238
|
+
*"please rename the metric"*) : ;;
|
|
239
|
+
*) fail "the remote record must carry the steer text: $body" ;;
|
|
240
|
+
esac
|
|
241
|
+
printf '%s' "$body" | grep -Eq 'corr=[a-f0-9]{16}' \
|
|
242
|
+
|| fail "the remote record must carry the marked request's corr token: $body"
|
|
243
|
+
case "$body" in
|
|
244
|
+
*"$FM_FROMFIRST_MARK"*) : ;;
|
|
245
|
+
*) fail "the remote record must carry the from-firstmate marker: $body" ;;
|
|
246
|
+
esac
|
|
247
|
+
# The doorbell could not reach the fixture pane (no herdr CLI here); that
|
|
248
|
+
# never fails the send, and the notice still names the durable record.
|
|
249
|
+
assert_contains "$err" "durably recorded" \
|
|
250
|
+
"a failed doorbell must be reported as a notice on a durably sent steer"
|
|
251
|
+
assert_not_contains "$err" "error:" "a durably recorded steer must not carry an error report"
|
|
252
|
+
pend=$(pending_record "$home")
|
|
253
|
+
[ -n "$pend" ] || fail "the marked remote steer must keep its pending-reply expectation"
|
|
254
|
+
[ -n "$(grep '^delivered_epoch=' "$pend" | cut -d= -f2-)" ] \
|
|
255
|
+
|| fail "a recorded remote steer must mark the expectation delivered at enqueue: $(cat "$pend")"
|
|
256
|
+
[ "$(grep '^phase=' "$pend" | tail -1 | cut -d= -f2-)" = awaiting_report ] \
|
|
257
|
+
|| fail "the delivered expectation must await its report: $(cat "$pend")"
|
|
258
|
+
pass "fm-send remote: a text steer lands as a durable remote inbox record and exits 0 at enqueue"
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
test_remote_rerun_is_idempotent() {
|
|
262
|
+
local dir fb ssh_log home rhome rc err count pend corr expected_cmd arg quoted rec ssh_before resend_cmd
|
|
263
|
+
dir="$TMP_ROOT/remote-idem"; mkdir -p "$dir"
|
|
264
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
265
|
+
rhome=$(setup_remote_secondmate_home remote-idem)
|
|
266
|
+
home=$(setup_remote_parent_home remote-idem "$rhome")
|
|
267
|
+
|
|
268
|
+
# Ambiguous transport: the remote leg executes for real, then ssh reports
|
|
269
|
+
# 255 (completion unknown). fm-send retries the identical leg once; the
|
|
270
|
+
# idempotent remote write must land both executions on the same record.
|
|
271
|
+
rc=0
|
|
272
|
+
(
|
|
273
|
+
cd "$TMP_ROOT" || exit 1
|
|
274
|
+
send_env "$fb" "${home#"$TMP_ROOT/"}" "$ssh_log" FM_FAKE_SSH_AMBIGUOUS=1 \
|
|
275
|
+
"$SEND" rsm "please rename the metric"
|
|
276
|
+
) >"$dir/out" 2>"$dir/err" || rc=$?
|
|
277
|
+
err=$(cat "$dir/err")
|
|
278
|
+
[ "$rc" -ne 0 ] || fail "a twice-lost transport must not claim confirmed delivery"
|
|
279
|
+
[ "$(cat "$ssh_log.count")" = 2 ] \
|
|
280
|
+
|| fail "fm-send must retry the identical remote leg exactly once after ssh 255, got $(cat "$ssh_log.count") attempts"
|
|
281
|
+
count=$(remote_inbox_records "$rhome" | grep -c . || true)
|
|
282
|
+
[ "$count" = 1 ] \
|
|
283
|
+
|| fail "re-running the remote leg must dedup onto one record, found $count:"$'\n'"$(remote_inbox_records "$rhome")"
|
|
284
|
+
assert_contains "$err" "Only the correlation-reusing resend below is idempotent" \
|
|
285
|
+
"an unconfirmed remote steer must limit resend safety to correlation reuse"
|
|
286
|
+
assert_not_contains "$err" "do not resend" \
|
|
287
|
+
"the deleted do-not-resend trap must be gone for an unconfirmed remote steer"
|
|
288
|
+
pend=$(pending_record "$home")
|
|
289
|
+
[ -n "$pend" ] || fail "an unconfirmed remote steer must preserve its expectation for the record that may have landed"
|
|
290
|
+
[ "$(grep '^phase=' "$pend" | tail -1 | cut -d= -f2-)" = delivery_unknown ] \
|
|
291
|
+
|| fail "the preserved expectation must record unknown delivery: $(cat "$pend")"
|
|
292
|
+
corr=$(fm_pending_reply_get "$pend" corr_id)
|
|
293
|
+
printf -v quoted '%q' "$home"
|
|
294
|
+
expected_cmd="FM_HOME=$quoted FM_PENDING_REPLY_EXISTING_CORR=$corr"
|
|
295
|
+
for arg in "$SEND" rsm "please rename the metric"; do
|
|
296
|
+
printf -v quoted '%q' "$arg"
|
|
297
|
+
expected_cmd="$expected_cmd $quoted"
|
|
298
|
+
done
|
|
299
|
+
assert_contains "$err" "$expected_cmd" \
|
|
300
|
+
"double transport loss must print the exact correlation-reusing resend command"
|
|
301
|
+
|
|
302
|
+
fm_pending_reply_set "$pend" phase escalated \
|
|
303
|
+
|| fail "could not advance the ambiguous expectation to the escalated fixture phase"
|
|
304
|
+
ssh_before=$(cat "$ssh_log.count")
|
|
305
|
+
rc=0
|
|
306
|
+
send_env "$fb" "$home" "$ssh_log" FM_PENDING_REPLY_EXISTING_CORR="$corr" \
|
|
307
|
+
"$SEND" rsm "please rename the metric" >"$dir/stale-resend.out" 2>"$dir/stale-resend.err" || rc=$?
|
|
308
|
+
[ "$rc" -ne 0 ] || fail "an explicitly requested non-reusable correlation must fail closed"
|
|
309
|
+
assert_contains "$(cat "$dir/stale-resend.err")" "refusing to mint a replacement correlation" \
|
|
310
|
+
"a stale explicit correlation must explain that no replacement was minted"
|
|
311
|
+
[ "$(cat "$ssh_log.count")" = "$ssh_before" ] \
|
|
312
|
+
|| fail "a stale explicit correlation reached the remote transport"
|
|
313
|
+
[ "$(find "$home/state/pending-replies" -maxdepth 1 -type f ! -name '.*' | wc -l | tr -d ' ')" = 1 ] \
|
|
314
|
+
|| fail "a stale explicit correlation minted a replacement expectation"
|
|
315
|
+
[ "$(find "$rhome/state/parent-route/rsm.inbox" -name '*.msg' | wc -l | tr -d ' ')" = 1 ] \
|
|
316
|
+
|| fail "a stale explicit correlation created another remote record"
|
|
317
|
+
fm_pending_reply_set "$pend" phase delivery_unknown \
|
|
318
|
+
|| fail "could not restore the ambiguous expectation for the supported resend"
|
|
319
|
+
|
|
320
|
+
resend_cmd=$(tail -1 "$dir/err")
|
|
321
|
+
rc=0
|
|
322
|
+
(
|
|
323
|
+
unset FM_HOME
|
|
324
|
+
env PATH="$fb:$PATH" FM_ROOT_OVERRIDE="$ROOT" FM_SEND_SETTLE=0 \
|
|
325
|
+
FM_SSH_BIN="$fb/fake-ssh" FM_SSH_LOG="$ssh_log" \
|
|
326
|
+
FM_SSH_COUNT="$ssh_log.count" FM_REMOTE_CODE_ROOT="$ROOT" \
|
|
327
|
+
bash -c "$resend_cmd"
|
|
328
|
+
) >"$dir/resend.out" 2>"$dir/resend.err" || rc=$?
|
|
329
|
+
expect_code 0 "$rc" "the printed correlation-reusing resend must succeed without an inherited FM_HOME"
|
|
330
|
+
count=$(find "$rhome/state/parent-route/rsm.inbox" -name '*.msg' | wc -l | tr -d ' ')
|
|
331
|
+
[ "$count" = 1 ] || fail "the correlation-reusing resend must leave exactly one remote record, found $count"
|
|
332
|
+
rec=$(find "$rhome/state/parent-route/rsm.inbox" -name '*.msg' | head -1)
|
|
333
|
+
grep -F "corr=$corr" "$rec" >/dev/null \
|
|
334
|
+
|| fail "the deduplicated remote record did not preserve correlation $corr"
|
|
335
|
+
[ -n "$(fm_pending_reply_get "$pend" delivered_epoch)" ] \
|
|
336
|
+
|| fail "the successful resend did not confirm pending-reply delivery: $(cat "$pend")"
|
|
337
|
+
[ "$(fm_pending_reply_get "$pend" phase)" = awaiting_report ] \
|
|
338
|
+
|| fail "the successful resend did not restore awaiting_report: $(cat "$pend")"
|
|
339
|
+
pass "fm-send remote: the printed correlation-reusing resend deduplicates onto the same record"
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
test_remote_retry_failure_preserves_ambiguous_expectation() {
|
|
343
|
+
local dir fb ssh_log home rhome rc err pend
|
|
344
|
+
dir="$TMP_ROOT/remote-ambiguous-then-fail"; mkdir -p "$dir"
|
|
345
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
346
|
+
rhome=$(setup_remote_secondmate_home remote-ambiguous-then-fail)
|
|
347
|
+
home=$(setup_remote_parent_home remote-ambiguous-then-fail "$rhome")
|
|
348
|
+
|
|
349
|
+
rc=0
|
|
350
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_AFTER_AMBIGUOUS_RC=1 \
|
|
351
|
+
"$SEND" rsm "please rename the metric" >"$dir/out" 2>"$dir/err" || rc=$?
|
|
352
|
+
err=$(cat "$dir/err")
|
|
353
|
+
[ "$rc" -ne 0 ] || fail "a failed retry after unknown completion must not claim delivery"
|
|
354
|
+
assert_contains "$err" "first transport attempt had unknown completion" \
|
|
355
|
+
"the final error must retain the first attempt's ambiguous completion"
|
|
356
|
+
pend=$(pending_record "$home")
|
|
357
|
+
[ -n "$pend" ] || fail "an ambiguous first attempt must preserve its expectation when the retry fails"
|
|
358
|
+
[ "$(grep '^phase=' "$pend" | tail -1 | cut -d= -f2-)" = delivery_unknown ] \
|
|
359
|
+
|| fail "the ambiguous expectation must remain delivery_unknown after a failed retry: $(cat "$pend")"
|
|
360
|
+
[ "$(remote_inbox_records "$rhome" | grep -c . || true)" = 1 ] \
|
|
361
|
+
|| fail "the first attempt's durable record must remain the sole remote record"
|
|
362
|
+
pass "fm-send remote: a failed retry cannot erase an earlier ambiguous delivery"
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
test_remote_fire_and_forget_never_arms_reply_recovery() {
|
|
366
|
+
local dir fb ssh_log home rhome rc count delivery action
|
|
367
|
+
dir="$TMP_ROOT/remote-fire-and-forget"; mkdir -p "$dir"
|
|
368
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
369
|
+
rhome=$(setup_remote_secondmate_home remote-fire-and-forget)
|
|
370
|
+
home=$(setup_remote_parent_home remote-fire-and-forget "$rhome")
|
|
371
|
+
delivery=0123456789abcdef
|
|
372
|
+
|
|
373
|
+
rc=0
|
|
374
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_AFTER_AMBIGUOUS_RC=1 \
|
|
375
|
+
"$SEND" rsm --fire-and-forget "$delivery" "reconcile your own books" \
|
|
376
|
+
>"$dir/out" 2>"$dir/err" || rc=$?
|
|
377
|
+
expect_code 3 "$rc" "an ambiguous fire-and-forget delivery must report unconfirmed"
|
|
378
|
+
[ "$(find "$home/state/pending-replies" -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')" = 0 ] \
|
|
379
|
+
|| fail "fire-and-forget delivery created a pending-reply expectation"
|
|
380
|
+
count=$(find "$rhome/state/parent-route/rsm.inbox" -name '*.msg' | wc -l | tr -d ' ')
|
|
381
|
+
[ "$count" = 1 ] || fail "the ambiguous fire-and-forget delivery did not land exactly once"
|
|
382
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=0 FM_TASK_INBOX_RING_MAX=0 \
|
|
383
|
+
fm_task_inbox_due_action "$rhome/state/parent-route" rsm)
|
|
384
|
+
[ "$action" = quiet ] || fail "the remote fire-and-forget record armed inbox escalation: $action"
|
|
385
|
+
|
|
386
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
387
|
+
"$SEND" rsm --fire-and-forget "$delivery" "reconcile your own books" \
|
|
388
|
+
>"$dir/retry.out" 2>"$dir/retry.err" \
|
|
389
|
+
|| fail "the fire-and-forget retry failed"
|
|
390
|
+
count=$(find "$rhome/state/parent-route/rsm.inbox" -name '*.msg' | wc -l | tr -d ' ')
|
|
391
|
+
[ "$count" = 1 ] || fail "the same fire-and-forget delivery id created a duplicate remote record"
|
|
392
|
+
grep -F "delivery=$delivery" "$(remote_inbox_records "$rhome" | head -1)" >/dev/null \
|
|
393
|
+
|| fail "the remote record omitted its fire-and-forget delivery identity"
|
|
394
|
+
pass "fm-send remote: fire-and-forget delivery is idempotent without reply recovery"
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
test_remote_send_revalidates_after_retirement_lock() {
|
|
398
|
+
local dir rhome meta lock ready release rc sender_pid holder_pid
|
|
399
|
+
dir="$TMP_ROOT/remote-retire-race"; mkdir -p "$dir"
|
|
400
|
+
rhome=$(setup_remote_secondmate_home remote-retire-race)
|
|
401
|
+
meta="$rhome/state/parent-route/rsm.meta"
|
|
402
|
+
lock="$rhome/state/parent-route/.meta-rsm.lock"
|
|
403
|
+
ready="$dir/lock-ready"
|
|
404
|
+
release="$dir/release-lock"
|
|
405
|
+
FM_STATE_OVERRIDE="$rhome/state/parent-route" bash -c '
|
|
406
|
+
. "$1"
|
|
407
|
+
fm_task_inbox_lock_acquire "$2" || exit 91
|
|
408
|
+
: > "$3"
|
|
409
|
+
while [ ! -e "$4" ]; do sleep 0.05; done
|
|
410
|
+
rm -f "$5"
|
|
411
|
+
fm_lock_release "$2"
|
|
412
|
+
' _ "$ROOT/bin/fm-task-inbox-lib.sh" "$lock" "$ready" "$release" "$meta" &
|
|
413
|
+
holder_pid=$!
|
|
414
|
+
while [ ! -e "$ready" ]; do kill -0 "$holder_pid" 2>/dev/null || fail "metadata-lock holder exited early"; sleep 0.05; done
|
|
415
|
+
|
|
416
|
+
rc=0
|
|
417
|
+
env FM_HOME="$rhome" FM_ROOT_OVERRIDE="$ROOT" \
|
|
418
|
+
"$ROOT/bin/fm-remote-secondmate-control.sh" send rsm "retirement-race steer" \
|
|
419
|
+
>"$dir/out" 2>"$dir/err" &
|
|
420
|
+
sender_pid=$!
|
|
421
|
+
sleep 0.2
|
|
422
|
+
: > "$release"
|
|
423
|
+
wait "$sender_pid" || rc=$?
|
|
424
|
+
wait "$holder_pid" || fail "metadata-lock holder failed"
|
|
425
|
+
[ "$rc" -ne 0 ] || fail "a send must not enqueue after endpoint retirement won the metadata lock"
|
|
426
|
+
[ -z "$(remote_inbox_records "$rhome")" ] \
|
|
427
|
+
|| fail "a send re-created an orphan inbox after endpoint retirement"
|
|
428
|
+
pass "remote control: send revalidates endpoint ownership under the metadata lock"
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
test_remote_send_revalidates_parent_route_after_retirement_lock() {
|
|
432
|
+
local dir fb ssh_log home rhome meta lock ready release rc sender_pid holder_pid
|
|
433
|
+
dir="$TMP_ROOT/remote-parent-retire-race"; mkdir -p "$dir"
|
|
434
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
435
|
+
rhome=$(setup_remote_secondmate_home remote-parent-retire-race)
|
|
436
|
+
home=$(setup_remote_parent_home remote-parent-retire-race "$rhome")
|
|
437
|
+
meta="$home/state/rsm.meta"
|
|
438
|
+
lock="$home/state/.meta-rsm.lock"
|
|
439
|
+
ready="$dir/lock-ready"
|
|
440
|
+
release="$dir/release-lock"
|
|
441
|
+
FM_STATE_OVERRIDE="$home/state" bash -c '
|
|
442
|
+
. "$1"
|
|
443
|
+
fm_task_inbox_lock_acquire "$2" || exit 91
|
|
444
|
+
: > "$3"
|
|
445
|
+
while [ ! -e "$4" ]; do sleep 0.05; done
|
|
446
|
+
rm -f "$5"
|
|
447
|
+
fm_lock_release "$2"
|
|
448
|
+
' _ "$ROOT/bin/fm-task-inbox-lib.sh" "$lock" "$ready" "$release" "$meta" &
|
|
449
|
+
holder_pid=$!
|
|
450
|
+
while [ ! -e "$ready" ]; do kill -0 "$holder_pid" 2>/dev/null || fail "parent metadata-lock holder exited early"; sleep 0.05; done
|
|
451
|
+
|
|
452
|
+
rc=0
|
|
453
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
454
|
+
"$SEND" rsm "parent-retirement-race steer" >"$dir/out" 2>"$dir/err" &
|
|
455
|
+
sender_pid=$!
|
|
456
|
+
sleep 0.2
|
|
457
|
+
: > "$release"
|
|
458
|
+
wait "$sender_pid" || rc=$?
|
|
459
|
+
wait "$holder_pid" || fail "parent metadata-lock holder failed"
|
|
460
|
+
[ "$rc" -ne 0 ] || fail "a remote send must not enqueue after parent retirement won the metadata lock"
|
|
461
|
+
[ -z "$(remote_inbox_records "$rhome")" ] \
|
|
462
|
+
|| fail "a remote send enqueued after its parent route retired"
|
|
463
|
+
[ -z "$(pending_record "$home")" ] \
|
|
464
|
+
|| fail "a parent-route retirement failure left a created pending expectation"
|
|
465
|
+
pass "fm-send remote: enqueue revalidates the parent route under its metadata lock"
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
test_remote_expected_host_revalidates_final_route() {
|
|
469
|
+
local dir fb ssh_log home rhome rc err count
|
|
470
|
+
dir="$TMP_ROOT/remote-expected-host"; mkdir -p "$dir"
|
|
471
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
472
|
+
rhome=$(setup_remote_secondmate_home remote-expected-host)
|
|
473
|
+
home=$(setup_remote_parent_home remote-expected-host "$rhome")
|
|
474
|
+
|
|
475
|
+
rc=0
|
|
476
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
477
|
+
FM_SEND_EXPECTED_SPAWN_GEN="" FM_SEND_EXPECTED_REMOTE_HOST=remote-mac \
|
|
478
|
+
"$SEND" rsm --fire-and-forget 1111111111111111 "matching expected host" \
|
|
479
|
+
>"$dir/match.out" 2>"$dir/match.err" || rc=$?
|
|
480
|
+
expect_code 0 "$rc" "a matching expected remote host must allow delivery"
|
|
481
|
+
count=$(remote_inbox_records "$rhome" | grep -c . || true)
|
|
482
|
+
[ "$count" = 1 ] || fail "a matching expected remote host did not deliver exactly once"
|
|
483
|
+
|
|
484
|
+
rc=0
|
|
485
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
486
|
+
FM_SEND_EXPECTED_SPAWN_GEN="" FM_SEND_EXPECTED_REMOTE_HOST=retired-mac \
|
|
487
|
+
"$SEND" rsm --fire-and-forget 2222222222222222 "stale expected host" \
|
|
488
|
+
>"$dir/mismatch.out" 2>"$dir/mismatch.err" || rc=$?
|
|
489
|
+
[ "$rc" -ne 0 ] || fail "a mismatched expected remote host reported delivery"
|
|
490
|
+
err=$(cat "$dir/mismatch.err")
|
|
491
|
+
assert_contains "$err" "retired or changed route" \
|
|
492
|
+
"a mismatched expected remote host did not report the route replacement: $err"
|
|
493
|
+
count=$(remote_inbox_records "$rhome" | grep -c . || true)
|
|
494
|
+
[ "$count" = 1 ] || fail "a mismatched expected remote host reached the remote inbox"
|
|
495
|
+
pass "fm-send remote: expected host is enforced by final route validation"
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
test_remote_resolve_key_closes_at_enqueue() {
|
|
499
|
+
local dir fb ssh_log home rhome rc out
|
|
500
|
+
dir="$TMP_ROOT/remote-key"; mkdir -p "$dir"
|
|
501
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
502
|
+
rhome=$(setup_remote_secondmate_home remote-key)
|
|
503
|
+
home=$(setup_remote_parent_home remote-key "$rhome")
|
|
504
|
+
printf 'needs-decision [key=upgrade-window]: tonight or the weekend\n' > "$home/state/rsm.status"
|
|
505
|
+
|
|
506
|
+
rc=0
|
|
507
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
508
|
+
"$SEND" rsm --resolve-key upgrade-window "the weekend, freeze Friday" >/dev/null 2>&1 || rc=$?
|
|
509
|
+
expect_code 0 "$rc" "a durably recorded remote answer must exit 0"
|
|
510
|
+
grep -F 'resolved [key=upgrade-window]: answered: the weekend, freeze Friday' "$home/state/rsm.status" >/dev/null \
|
|
511
|
+
|| fail "a recorded remote answer must close the decision at enqueue: $(cat "$home/state/rsm.status")"
|
|
512
|
+
out=$(drain_out "$home")
|
|
513
|
+
if printf '%s' "$out" | grep -F 'OPEN DECISIONS' >/dev/null; then
|
|
514
|
+
fail "the answered decision still lists as open after a recorded remote answer: $out"
|
|
515
|
+
fi
|
|
516
|
+
grep -rqF 'the weekend, freeze Friday' "$rhome/state/parent-route/rsm.inbox" \
|
|
517
|
+
|| fail "the remote answer must land in the remote steering inbox"
|
|
518
|
+
pass "fm-send remote: a --resolve-key answer closes its decision at enqueue"
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
test_remote_slash_rides_inbox() {
|
|
522
|
+
local dir fb ssh_log home rhome rc recs
|
|
523
|
+
dir="$TMP_ROOT/remote-slash"; mkdir -p "$dir"
|
|
524
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
525
|
+
rhome=$(setup_remote_secondmate_home remote-slash)
|
|
526
|
+
home=$(setup_remote_parent_home remote-slash "$rhome")
|
|
527
|
+
|
|
528
|
+
rc=0
|
|
529
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
530
|
+
"$SEND" rsm "/audit the ledger" >/dev/null 2>"$dir/err" || rc=$?
|
|
531
|
+
expect_code 0 "$rc" "a remote harness-native steer must ride the inbox and exit 0"
|
|
532
|
+
recs=$(remote_inbox_records "$rhome")
|
|
533
|
+
[ -n "$recs" ] || fail "a remote '/' steer must land in the remote steering inbox, not a typed plane"
|
|
534
|
+
grep -rqF '/audit the ledger' "$rhome/state/parent-route/rsm.inbox" \
|
|
535
|
+
|| fail "the remote record must carry the harness-native text verbatim"
|
|
536
|
+
pass "fm-send remote: every remote text, harness-native included, rides the inbox"
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
test_remote_real_failure_still_fails() {
|
|
540
|
+
local dir fb ssh_log home rhome rc err
|
|
541
|
+
dir="$TMP_ROOT/remote-fail"; mkdir -p "$dir"
|
|
542
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
543
|
+
rhome=$(setup_remote_secondmate_home remote-fail)
|
|
544
|
+
home=$(setup_remote_parent_home remote-fail "$rhome")
|
|
545
|
+
|
|
546
|
+
rc=0
|
|
547
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_RC=1 \
|
|
548
|
+
FM_FAKE_SSH_STDERR='error: remote secondmate rsm endpoint metadata is invalid; refusing access until it is explicitly migrated' \
|
|
549
|
+
"$SEND" rsm "please rename the metric" >"$dir/out" 2>"$dir/err" || rc=$?
|
|
550
|
+
err=$(cat "$dir/err")
|
|
551
|
+
[ "$rc" -ne 0 ] || fail "a genuinely failed remote send must exit nonzero"
|
|
552
|
+
assert_contains "$err" "steer not sent to remote secondmate rsm" \
|
|
553
|
+
"a real remote failure must still report a real error"
|
|
554
|
+
assert_contains "$err" "endpoint metadata is invalid" \
|
|
555
|
+
"a real remote failure must surface the remote leg's own stderr"
|
|
556
|
+
[ -z "$(pending_record "$home")" ] \
|
|
557
|
+
|| fail "a failed send must discard its undelivered expectation"
|
|
558
|
+
[ -z "$(remote_inbox_records "$rhome")" ] \
|
|
559
|
+
|| fail "a refused remote leg must leave no inbox record"
|
|
560
|
+
pass "fm-send remote: a real remote failure still fails loudly with the remote diagnostics"
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
test_remote_exit3_no_longer_delivered() {
|
|
564
|
+
local dir fb ssh_log home rhome rc err
|
|
565
|
+
dir="$TMP_ROOT/remote-exit3"; mkdir -p "$dir"
|
|
566
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
567
|
+
rhome=$(setup_remote_secondmate_home remote-exit3)
|
|
568
|
+
home=$(setup_remote_parent_home remote-exit3 "$rhome")
|
|
569
|
+
|
|
570
|
+
# The typed-plane remote transport remapped a leg exit 3 to "delivered with
|
|
571
|
+
# confirmation pending". That transport is deleted: any nonzero remote leg
|
|
572
|
+
# status is a failure, never a delivery claim.
|
|
573
|
+
rc=0
|
|
574
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_RC=3 \
|
|
575
|
+
"$SEND" rsm "please rename the metric" >"$dir/out" 2>"$dir/err" || rc=$?
|
|
576
|
+
err=$(cat "$dir/err")
|
|
577
|
+
[ "$rc" -ne 0 ] || fail "a nonzero remote leg must no longer be remapped to delivered"
|
|
578
|
+
assert_not_contains "$err" "delivered to remote secondmate" \
|
|
579
|
+
"the deleted exit-3-as-delivered remap must be gone"
|
|
580
|
+
assert_contains "$err" "steer not sent to remote secondmate rsm" \
|
|
581
|
+
"a failed remote leg must report the steer as not sent"
|
|
582
|
+
[ -z "$(pending_record "$home")" ] \
|
|
583
|
+
|| fail "a failed remote leg must discard its undelivered expectation"
|
|
584
|
+
pass "fm-send remote: exit 3 from the remote leg is a failure, never a delivery claim"
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
test_remote_transport_loss_preserves_expectation() {
|
|
588
|
+
local dir fb ssh_log home rhome rc err pend
|
|
589
|
+
dir="$TMP_ROOT/remote-255"; mkdir -p "$dir"
|
|
590
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
591
|
+
rhome=$(setup_remote_secondmate_home remote-255)
|
|
592
|
+
home=$(setup_remote_parent_home remote-255 "$rhome")
|
|
593
|
+
|
|
594
|
+
rc=0
|
|
595
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_RC=255 \
|
|
596
|
+
"$SEND" rsm "please rename the metric" >"$dir/out" 2>"$dir/err" || rc=$?
|
|
597
|
+
err=$(cat "$dir/err")
|
|
598
|
+
[ "$rc" -ne 0 ] || fail "an unknown-completion transport loss must exit nonzero"
|
|
599
|
+
[ "$(cat "$ssh_log.count")" = 2 ] \
|
|
600
|
+
|| fail "fm-send must retry the identical remote leg once on ssh 255, got $(cat "$ssh_log.count") attempts"
|
|
601
|
+
assert_contains "$err" "Only the correlation-reusing resend below is idempotent" \
|
|
602
|
+
"transport loss must print the supported safe resend boundary"
|
|
603
|
+
assert_not_contains "$err" "do not resend" \
|
|
604
|
+
"the deleted do-not-resend trap must be gone for transport loss"
|
|
605
|
+
pend=$(pending_record "$home")
|
|
606
|
+
[ -n "$pend" ] || fail "transport loss must preserve the expectation for reconciliation"
|
|
607
|
+
[ "$(grep '^phase=' "$pend" | tail -1 | cut -d= -f2-)" = delivery_unknown ] \
|
|
608
|
+
|| fail "transport loss must move the expectation to delivery_unknown: $(cat "$pend")"
|
|
609
|
+
pass "fm-send remote: ssh 255 fails with resend-safe guidance and preserves the expectation"
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
test_remote_send_budget_bounds_busy_lane() {
|
|
613
|
+
local dir fb ssh_log home rhome rc err began elapsed count pend delivery corr ssh_before
|
|
614
|
+
dir="$TMP_ROOT/remote-budget"; mkdir -p "$dir"
|
|
615
|
+
fb=$(make_stubs "$dir"); ssh_log="$dir/ssh.log"; : > "$ssh_log"
|
|
616
|
+
rhome=$(setup_remote_secondmate_home remote-budget)
|
|
617
|
+
home=$(setup_remote_parent_home remote-budget "$rhome")
|
|
618
|
+
delivery=aaaabbbbccccdddd
|
|
619
|
+
|
|
620
|
+
rc=0
|
|
621
|
+
send_env "$fb" "$home" "$ssh_log" FM_SEND_REMOTE_BUDGET=invalid \
|
|
622
|
+
"$SEND" rsm --key Enter >"$dir/key-invalid.out" 2>"$dir/key-invalid.err" || rc=$?
|
|
623
|
+
[ "$rc" -ne 0 ] || fail "an invalid remote key budget must fail"
|
|
624
|
+
assert_contains "$(cat "$dir/key-invalid.err")" "must be a positive integer" \
|
|
625
|
+
"an invalid remote key budget must explain its validation failure"
|
|
626
|
+
[ ! -f "$ssh_log.count" ] || fail "an invalid remote key budget reached the transport"
|
|
627
|
+
|
|
628
|
+
began=$(date +%s)
|
|
629
|
+
rc=0
|
|
630
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_HANG=60 FM_SEND_REMOTE_BUDGET=2 \
|
|
631
|
+
"$SEND" rsm --key Enter >"$dir/key.out" 2>"$dir/key.err" || rc=$?
|
|
632
|
+
elapsed=$(( $(date +%s) - began ))
|
|
633
|
+
expect_code 1 "$rc" "a bounded remote key must preserve the existing failure contract"
|
|
634
|
+
[ "$elapsed" -le 15 ] || fail "the bounded remote key waited ${elapsed}s behind the busy lane"
|
|
635
|
+
assert_contains "$(cat "$dir/key.err")" "completion may be unknown" \
|
|
636
|
+
"a bounded remote key failure must preserve its existing diagnostic"
|
|
637
|
+
[ "$(cat "$ssh_log.count")" = 1 ] \
|
|
638
|
+
|| fail "a bounded remote key must make exactly one transport attempt"
|
|
639
|
+
printf '0\n' > "$ssh_log.count"
|
|
640
|
+
|
|
641
|
+
# T5: a fire-and-forget send to a mate behind a busy lane returns its
|
|
642
|
+
# unconfirmed result within its own budget instead of waiting the lane out.
|
|
643
|
+
began=$(date +%s)
|
|
644
|
+
rc=0
|
|
645
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_HANG=60 FM_SEND_REMOTE_BUDGET=2 \
|
|
646
|
+
"$SEND" rsm --fire-and-forget "$delivery" "reconcile your own books" \
|
|
647
|
+
>"$dir/out" 2>"$dir/err" || rc=$?
|
|
648
|
+
elapsed=$(( $(date +%s) - began ))
|
|
649
|
+
err=$(cat "$dir/err")
|
|
650
|
+
expect_code 3 "$rc" "a budget-bounded fire-and-forget send must report unconfirmed: $err"
|
|
651
|
+
[ "$elapsed" -le 15 ] || fail "the bounded send waited ${elapsed}s behind the busy lane"
|
|
652
|
+
assert_contains "$err" "delivery-id=$delivery" \
|
|
653
|
+
"the bounded unconfirmed result must name the reusable delivery id"
|
|
654
|
+
[ "$(cat "$ssh_log.count")" = 1 ] \
|
|
655
|
+
|| fail "a budget hit must not retry into the same busy lane, got $(cat "$ssh_log.count") attempts"
|
|
656
|
+
|
|
657
|
+
# A retry with the same delivery id against the recovered lane dedups onto
|
|
658
|
+
# the same remote record.
|
|
659
|
+
send_env "$fb" "$home" "$ssh_log" \
|
|
660
|
+
"$SEND" rsm --fire-and-forget "$delivery" "reconcile your own books" \
|
|
661
|
+
>"$dir/retry.out" 2>"$dir/retry.err" \
|
|
662
|
+
|| fail "the same-delivery-id retry after the budget hit failed"
|
|
663
|
+
count=$(remote_inbox_records "$rhome" | grep -c . || true)
|
|
664
|
+
[ "$count" = 1 ] || fail "the same-delivery-id retry did not dedup onto one record, found $count"
|
|
665
|
+
|
|
666
|
+
# A reply-bearing send names the budget and prints the correlation-reusing
|
|
667
|
+
# resend command, with the expectation preserved as delivery-unknown.
|
|
668
|
+
rc=0
|
|
669
|
+
send_env "$fb" "$home" "$ssh_log" FM_FAKE_SSH_HANG=60 FM_SEND_REMOTE_BUDGET=2 \
|
|
670
|
+
"$SEND" rsm "please rename the metric" >"$dir/reply.out" 2>"$dir/reply.err" || rc=$?
|
|
671
|
+
err=$(cat "$dir/reply.err")
|
|
672
|
+
[ "$rc" -ne 0 ] || fail "a budget-bounded reply-bearing send must not claim confirmed delivery"
|
|
673
|
+
assert_contains "$err" "within its 2s budget" \
|
|
674
|
+
"the budget-bounded failure must name the budget that bounded it"
|
|
675
|
+
assert_contains "$err" "Only the correlation-reusing resend below is idempotent" \
|
|
676
|
+
"the budget-bounded failure must print the supported safe resend boundary"
|
|
677
|
+
pend=$(pending_record "$home")
|
|
678
|
+
[ -n "$pend" ] || fail "a budget-bounded reply-bearing send must preserve its expectation"
|
|
679
|
+
[ "$(grep '^phase=' "$pend" | tail -1 | cut -d= -f2-)" = delivery_unknown ] \
|
|
680
|
+
|| fail "the preserved expectation must record unknown delivery: $(cat "$pend")"
|
|
681
|
+
|
|
682
|
+
# Invalid transport configuration fails before a correlation-reusing resend
|
|
683
|
+
# mutates the preserved expectation or reaches the transport.
|
|
684
|
+
corr=$(fm_pending_reply_get "$pend" corr_id)
|
|
685
|
+
cp "$pend" "$dir/pending-before-invalid-budget"
|
|
686
|
+
ssh_before=$(cat "$ssh_log.count")
|
|
687
|
+
rc=0
|
|
688
|
+
send_env "$fb" "$home" "$ssh_log" FM_SEND_REMOTE_BUDGET=invalid \
|
|
689
|
+
FM_PENDING_REPLY_EXISTING_CORR="$corr" \
|
|
690
|
+
"$SEND" rsm "please rename the metric" >"$dir/invalid.out" 2>"$dir/invalid.err" || rc=$?
|
|
691
|
+
[ "$rc" -ne 0 ] || fail "an invalid remote budget must fail the resend"
|
|
692
|
+
assert_contains "$(cat "$dir/invalid.err")" "must be a positive integer" \
|
|
693
|
+
"an invalid remote budget must explain its validation failure"
|
|
694
|
+
[ "$(cat "$ssh_log.count")" = "$ssh_before" ] \
|
|
695
|
+
|| fail "an invalid remote budget reached the remote transport"
|
|
696
|
+
cmp -s "$dir/pending-before-invalid-budget" "$pend" \
|
|
697
|
+
|| fail "an invalid remote budget mutated the reusable pending expectation: $(cat "$pend")"
|
|
698
|
+
pass "fm-send remote: the remote leg is budget-bounded and stays idempotent across the bound"
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
test_local_secondmate_pending_keeps_expectation_armed() {
|
|
702
|
+
local dir fb log home rc rec corr
|
|
703
|
+
dir="$TMP_ROOT/local-pending-expectation"; mkdir -p "$dir"
|
|
704
|
+
fb=$(make_stubs "$dir"); log="$dir/send.log"
|
|
705
|
+
home=$(setup_home local-pending-expectation)
|
|
706
|
+
fm_write_meta "$home/state/lsm.meta" \
|
|
707
|
+
"window=sess:fm-lsm" "harness=claude" "kind=secondmate" "mode=secondmate" "home=$home/sm"
|
|
708
|
+
|
|
709
|
+
# A harness-native slash invocation keeps the typed plane for a LOCAL marked
|
|
710
|
+
# secondmate target, so this pins the kept armed-expectation semantics there.
|
|
711
|
+
: > "$log"
|
|
712
|
+
rc=0
|
|
713
|
+
env PATH="$fb:$PATH" FM_FAKE_TMUX_PENDING=1 \
|
|
714
|
+
FM_ROOT_OVERRIDE="$home" FM_HOME="$home" FM_SEND_LOG="$log" FM_SEND_SETTLE=0 \
|
|
715
|
+
"$SEND" lsm "/audit the ledger" >/dev/null 2>&1 || rc=$?
|
|
716
|
+
expect_code 3 "$rc" "an unconfirmed local secondmate submit must exit delivered-unconfirmed"
|
|
717
|
+
rec=$(pending_record "$home")
|
|
718
|
+
[ -n "$rec" ] \
|
|
719
|
+
|| fail "the pending-reply expectation must survive an unconfirmed local secondmate send"
|
|
720
|
+
[ "$(fm_pending_reply_get "$rec" phase)" = awaiting_report ] \
|
|
721
|
+
|| fail "the surviving expectation must stay armed, got $(fm_pending_reply_get "$rec" phase)"
|
|
722
|
+
# Armed means resolvable: the mate's correlated report still closes it.
|
|
723
|
+
corr=$(fm_pending_reply_get "$rec" corr_id)
|
|
724
|
+
printf 'done [corr=%s]: ledger clean\n' "$corr" > "$home/state/lsm.status"
|
|
725
|
+
fm_pending_reply_try_resolve "$home/state" "$corr" \
|
|
726
|
+
|| fail "a correlated report must still resolve the preserved expectation"
|
|
727
|
+
pass "fm-send local: an unconfirmed secondmate send keeps its reply expectation armed"
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
test_local_pending_reports_delivered_unconfirmed() {
|
|
731
|
+
local dir fb log home rc err
|
|
732
|
+
dir="$TMP_ROOT/local-pending"; mkdir -p "$dir"
|
|
733
|
+
fb=$(make_stubs "$dir"); log="$dir/send.log"
|
|
734
|
+
home=$(setup_home local-pending)
|
|
735
|
+
|
|
736
|
+
# An explicit backend target is the typed plane, so the exit-3 ladder still
|
|
737
|
+
# governs it.
|
|
738
|
+
: > "$log"
|
|
739
|
+
rc=0
|
|
740
|
+
env PATH="$fb:$PATH" FM_FAKE_TMUX_PENDING=1 \
|
|
741
|
+
FM_ROOT_OVERRIDE="$home" FM_HOME="$home" FM_SEND_LOG="$log" FM_SEND_SETTLE=0 \
|
|
742
|
+
"$SEND" sess:win "steer text" >"$dir/out" 2>"$dir/err" || rc=$?
|
|
743
|
+
err=$(cat "$dir/err")
|
|
744
|
+
expect_code 3 "$rc" "an unconfirmed local submit must exit with the delivered-unconfirmed status"
|
|
745
|
+
assert_contains "$err" "submission is unconfirmed" \
|
|
746
|
+
"the unconfirmed local submit must be described honestly"
|
|
747
|
+
assert_not_contains "$err" "not submitted" \
|
|
748
|
+
"an unconfirmed local submit must not claim the text was not submitted"
|
|
749
|
+
assert_not_contains "$err" "error:" \
|
|
750
|
+
"an unconfirmed local submit must not carry an error-styled report"
|
|
751
|
+
pass "fm-send local: an unconfirmed submit exits 3 with an honest non-error report"
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
test_local_pending_does_not_close_resolve_key() {
|
|
755
|
+
local dir fb log home rc out
|
|
756
|
+
dir="$TMP_ROOT/local-pending-key"; mkdir -p "$dir"
|
|
757
|
+
fb=$(make_stubs "$dir"); log="$dir/send.log"
|
|
758
|
+
home=$(setup_home local-pending-key)
|
|
759
|
+
fm_write_meta "$home/state/t2.meta" "window=sess:fm-t2" "kind=ship"
|
|
760
|
+
printf 'blocked [key=creds]: need the deploy token\n' > "$home/state/t2.status"
|
|
761
|
+
|
|
762
|
+
# A harness-native slash answer keeps the typed plane, so the unconfirmed
|
|
763
|
+
# ladder still governs it; a plain-text answer would close at enqueue instead.
|
|
764
|
+
: > "$log"
|
|
765
|
+
rc=0
|
|
766
|
+
env PATH="$fb:$PATH" FM_FAKE_TMUX_PENDING=1 \
|
|
767
|
+
FM_ROOT_OVERRIDE="$home" FM_HOME="$home" FM_SEND_LOG="$log" FM_SEND_SETTLE=0 \
|
|
768
|
+
"$SEND" t2 --resolve-key creds "/vault fetch deploy-token" >/dev/null 2>&1 || rc=$?
|
|
769
|
+
expect_code 3 "$rc" "an unconfirmed local answer must exit with the delivered-unconfirmed status"
|
|
770
|
+
if grep -F 'resolved' "$home/state/t2.status" >/dev/null; then
|
|
771
|
+
fail "an unconfirmed local answer must not close the decision: $(cat "$home/state/t2.status")"
|
|
772
|
+
fi
|
|
773
|
+
out=$(drain_out "$home")
|
|
774
|
+
printf '%s' "$out" | grep -F '[key=creds]' >/dev/null \
|
|
775
|
+
|| fail "the blocker must stay open after an unconfirmed local answer: $out"
|
|
776
|
+
pass "fm-send local: an unconfirmed submit still never closes a --resolve-key decision"
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
test_remote_steer_lands_in_remote_inbox
|
|
780
|
+
test_remote_rerun_is_idempotent
|
|
781
|
+
test_remote_retry_failure_preserves_ambiguous_expectation
|
|
782
|
+
test_remote_fire_and_forget_never_arms_reply_recovery
|
|
783
|
+
test_remote_send_revalidates_after_retirement_lock
|
|
784
|
+
test_remote_send_revalidates_parent_route_after_retirement_lock
|
|
785
|
+
test_remote_expected_host_revalidates_final_route
|
|
786
|
+
test_remote_resolve_key_closes_at_enqueue
|
|
787
|
+
test_remote_slash_rides_inbox
|
|
788
|
+
test_remote_real_failure_still_fails
|
|
789
|
+
test_remote_exit3_no_longer_delivered
|
|
790
|
+
test_remote_transport_loss_preserves_expectation
|
|
791
|
+
test_remote_send_budget_bounds_busy_lane
|
|
792
|
+
test_local_pending_reports_delivered_unconfirmed
|
|
793
|
+
test_local_pending_does_not_close_resolve_key
|
|
794
|
+
test_local_secondmate_pending_keeps_expectation_armed
|
|
795
|
+
|
|
796
|
+
echo "all fm-send-remote-delivery tests passed"
|