@zerwiz/ymir 0.1.3 → 0.1.5
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/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 +290 -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 +50 -0
- package/.agents/config/agents.yaml.example +72 -0
- package/.agents/config/crew-dispatch.json +22 -0
- package/.agents/config/cron.yaml +9 -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/config/tailscale-sync.yaml +27 -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/kaia.engram +0 -0
- package/.agents/memory/kaia.engram-shm +0 -0
- package/.agents/memory/kaia.engram-wal +0 -0
- package/.agents/memory/runes_audit.md +5 -0
- package/.agents/memory/well/episodes.jsonl +367 -0
- package/.agents/memory/well/workspace.jsonl +27 -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 +111 -0
- package/.agents/migrations/0004-hoard-and-realms.sh +104 -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 +158 -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 +673 -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 +496 -0
- package/.agents/skills/galdr-ymirsystem/assets/installation.md +571 -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 +161 -0
- package/.agents/skills/galdr-ymirsystem/assets/nornir-jobs.md +377 -0
- package/.agents/skills/galdr-ymirsystem/assets/norse-naming.md +325 -0
- package/.agents/skills/galdr-ymirsystem/assets/odrerir-hall.md +129 -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 +96 -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 +175 -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 +360 -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 +70 -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 +52 -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 +34 -0
- package/.agents/skills/ymir-host/assets/desktop.md +36 -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 +454 -0
- package/CHANGELOG.md +881 -0
- package/LICENSE +1 -1
- package/NOTICE +63 -0
- package/README.md +113 -39
- 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 +65 -0
- package/RULES/05-platforms.md +67 -0
- package/RULES/06-append-only.md +58 -0
- package/RULES/07-config.md +45 -0
- package/RULES/08-delivery-gate.md +75 -0
- package/RULES/README.md +20 -0
- package/bin/README.md +107 -0
- package/bin/a2a-mcp.sh +98 -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 +233 -0
- package/bin/apodex-smoke-test.sh +92 -0
- package/bin/bifrost-bridge.sh +112 -0
- package/bin/bifrost-ingress.sh +77 -0
- package/bin/bootstrap-macos.sh +107 -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 +38 -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-guard.sh +165 -0
- package/bin/crash-sense.sh +160 -0
- package/bin/desktop-place.sh +224 -0
- package/bin/docs-guard.sh +39 -0
- package/bin/editor-place.sh +207 -0
- package/bin/eindri-acclaim.sh +34 -0
- package/bin/eindri-control.sh +28 -0
- package/bin/eindri-role.sh +83 -0
- package/bin/eindri-seen.sh +41 -0
- package/bin/eindri-send.sh +15 -0
- package/bin/eindri-start.sh +85 -0
- package/bin/eindri-watch.sh +57 -0
- package/bin/einherjar-spawn.sh +576 -0
- package/bin/eir-doctor.sh +112 -0
- package/bin/erindi-brief.sh +271 -0
- package/bin/fleet-apply.sh +68 -0
- package/bin/github-deploy.sh +81 -0
- package/bin/gjallarhorn-expose.sh +102 -0
- package/bin/gjallarhorn-notify.sh +58 -0
- package/bin/gjallarhorn-purge.sh +54 -0
- package/bin/gjallarhorn-tunnel.sh +72 -0
- package/bin/gleipnir-lock-lib.sh +284 -0
- package/bin/groa-update.sh +122 -0
- package/bin/hall-snapshot.sh +92 -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 +431 -0
- package/bin/hermes-ensure.sh +88 -0
- package/bin/hoard-lib.sh +25 -0
- package/bin/hodd.sh +78 -0
- package/bin/host-sense.sh +199 -0
- package/bin/huginn-research-worker.sh +108 -0
- package/bin/local-model-lock.sh +51 -0
- package/bin/mimir-bridge.py +226 -0
- package/bin/mimir-bridge.sh +87 -0
- package/bin/mimir-ingest.sh +131 -0
- package/bin/mimir.sh +113 -0
- package/bin/mjollnir-webhook.sh +59 -0
- package/bin/mjollnir.sh +85 -0
- package/bin/model-hardware.sh +82 -0
- package/bin/model-resolve.sh +147 -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-memory-housekeeping.sh +114 -0
- package/bin/nornir-job-observer.sh +166 -0
- package/bin/nornir-job-skillopt-sleep.sh +76 -0
- package/bin/omarchy-hook-install.sh +60 -0
- package/bin/omarchy-install.sh +148 -0
- package/bin/omarchy-plugins.sh +174 -0
- package/bin/omarchy-sense.sh +149 -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-seat.sh +63 -0
- package/bin/prereq-ensure.sh +166 -0
- package/bin/private-guard.sh +38 -0
- package/bin/project-git.sh +55 -0
- package/bin/public-guard.sh +70 -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 +91 -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 +90 -0
- package/bin/smidja-observe.sh +86 -0
- package/bin/syn-arm-pretool-check.sh +57 -0
- package/bin/syn-asset-pretool-check.sh +76 -0
- package/bin/syn-cd-pretool-check.sh +28 -0
- package/bin/syn-guard-pretool-check.sh +83 -0
- package/bin/syn-turnend-guard.sh +36 -0
- package/bin/syn-watch-arm.sh +99 -0
- package/bin/tailscale-sync.sh +190 -0
- package/bin/telegram-bot.sh +69 -0
- package/bin/toolchain.sh +74 -0
- package/bin/utgard.sh +111 -0
- package/bin/valhalla.sh +115 -0
- package/bin/valknut-load.sh +260 -0
- package/bin/vor-crew-state.sh +124 -0
- package/bin/wedge-notify.sh +47 -0
- package/bin/workspace-provision.sh +80 -0
- package/bin/workspace-rag.sh +150 -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 +641 -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-platform.sh +348 -0
- package/bin/ymir-say.sh +97 -0
- package/bin/ymir-setup-auth.sh +108 -0
- package/bin/ymir-validate.sh +173 -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 +1056 -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 +44 -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 +210 -0
- package/scripts/start.sh +167 -0
- package/scripts/stop.sh +113 -0
- package/install.sh +0 -35
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tests/fm-task-inbox.test.sh - the per-task steering inbox
|
|
3
|
+
# (bin/fm-task-inbox-lib.sh) and the watcher's re-ring ladder.
|
|
4
|
+
#
|
|
5
|
+
# The inbox+doorbell design replaces typed steer payloads with durable
|
|
6
|
+
# sequenced records acknowledged by an atomic mv into handled/; the terminal
|
|
7
|
+
# carries only a constant doorbell line, and the watcher re-rings an
|
|
8
|
+
# unacknowledged message before escalating once as an ordinary stale wake.
|
|
9
|
+
# These tests pin the semantics with real processes:
|
|
10
|
+
# 1. A message is written durably and appears in the inbox, byte-exact
|
|
11
|
+
# including newlines, with a doorbell naming the inbox glob, numeric order,
|
|
12
|
+
# and handled/.
|
|
13
|
+
# 2. Sequencing dedups per worker lifetime: the handled mv retires a record,
|
|
14
|
+
# re-acking it is a no-op, and an acknowledged sequence is never reissued.
|
|
15
|
+
# The idempotent enqueue (the remote steer leg's primitive) additionally
|
|
16
|
+
# dedups an exact-body re-run onto the existing record, handled or not.
|
|
17
|
+
# 3. Concurrent writers serialize on the sequence lock: no clobbered records.
|
|
18
|
+
# 4. The re-ring ladder: within grace is quiet, past grace rings, ring
|
|
19
|
+
# spacing holds, a spent budget escalates exactly once, and an
|
|
20
|
+
# acknowledgement resets the ladder for the next message.
|
|
21
|
+
# 5. A real fm-watch.sh subprocess re-rings the doorbell for an unhandled
|
|
22
|
+
# aged message on an idle pane WITHOUT waking firstmate, waits on a busy
|
|
23
|
+
# pane, stays silent on a healthy/empty inbox, surfaces unwritable ladder
|
|
24
|
+
# bookkeeping only while its record remains unhandled, and emits exactly
|
|
25
|
+
# one stale wake once the ring budget is spent.
|
|
26
|
+
set -u
|
|
27
|
+
|
|
28
|
+
# shellcheck source=tests/wake-helpers.sh
|
|
29
|
+
. "$(dirname "${BASH_SOURCE[0]}")/wake-helpers.sh"
|
|
30
|
+
|
|
31
|
+
WATCH="$ROOT/bin/fm-watch.sh"
|
|
32
|
+
TMP_ROOT=$(fm_test_tmproot fm-task-inbox)
|
|
33
|
+
# The doorbell line canonicalizes its paths, so keep the fixture root
|
|
34
|
+
# canonical too (a trailing-slash TMPDIR otherwise yields a double slash).
|
|
35
|
+
TMP_ROOT=$(cd "$TMP_ROOT" && pwd)
|
|
36
|
+
|
|
37
|
+
# Run one library function against a state dir through a subshell that sources
|
|
38
|
+
# the production library, so the tests exercise the executable surface rather
|
|
39
|
+
# than re-implementing any format knowledge here.
|
|
40
|
+
inbox_lib() { # <state> <function> [args...]
|
|
41
|
+
local state=$1
|
|
42
|
+
shift
|
|
43
|
+
FM_STATE_OVERRIDE="$state" bash -c '
|
|
44
|
+
. "$1"
|
|
45
|
+
fn=$2
|
|
46
|
+
shift 2
|
|
47
|
+
"$fn" "$@"
|
|
48
|
+
' _ "$ROOT/bin/fm-task-inbox-lib.sh" "$@"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# A fake tmux for the watcher cases: capture-pane replays FM_FAKE_TMUX_CAPTURE,
|
|
52
|
+
# display-message yields a numeric cursor row, and every literal send-keys is
|
|
53
|
+
# logged to FM_SEND_LOG so a doorbell ring is observable.
|
|
54
|
+
make_watch_stubs() { # <dir> -> echoes fakebin dir
|
|
55
|
+
local dir=$1 fb="$1/fakebin"
|
|
56
|
+
mkdir -p "$fb"
|
|
57
|
+
cat > "$fb/tmux" <<'SH'
|
|
58
|
+
#!/usr/bin/env bash
|
|
59
|
+
set -u
|
|
60
|
+
case "${1:-}" in
|
|
61
|
+
send-keys)
|
|
62
|
+
shift
|
|
63
|
+
literal=0
|
|
64
|
+
while [ $# -gt 0 ]; do
|
|
65
|
+
case "$1" in
|
|
66
|
+
-t) shift 2 ;;
|
|
67
|
+
-l) literal=1; shift ;;
|
|
68
|
+
*) break ;;
|
|
69
|
+
esac
|
|
70
|
+
done
|
|
71
|
+
if [ "$literal" = 1 ]; then
|
|
72
|
+
printf '%s\n' "${1:-}" >> "${FM_SEND_LOG:-/dev/null}"
|
|
73
|
+
if [ -n "${FM_ACK_RECORD:-}" ] && [ -f "$FM_ACK_RECORD" ]; then
|
|
74
|
+
mv "$FM_ACK_RECORD" "${FM_ACK_RECORD%/*}/handled/"
|
|
75
|
+
fi
|
|
76
|
+
fi
|
|
77
|
+
exit 0 ;;
|
|
78
|
+
display-message)
|
|
79
|
+
for a in "$@"; do case "$a" in *cursor_y*) printf '1\n'; exit 0 ;; esac; done
|
|
80
|
+
printf 'fakepane\n'; exit 0 ;;
|
|
81
|
+
capture-pane)
|
|
82
|
+
if [ -n "${FM_FAKE_TMUX_CAPTURE:-}" ] && [ -f "$FM_FAKE_TMUX_CAPTURE" ]; then
|
|
83
|
+
cat "$FM_FAKE_TMUX_CAPTURE"
|
|
84
|
+
else
|
|
85
|
+
printf '╭────╮\n│ │\n╰────╯\n'
|
|
86
|
+
fi
|
|
87
|
+
exit 0 ;;
|
|
88
|
+
list-windows) exit 0 ;;
|
|
89
|
+
esac
|
|
90
|
+
exit 0
|
|
91
|
+
SH
|
|
92
|
+
chmod +x "$fb/tmux"
|
|
93
|
+
make_fake_crew_state "$fb" >/dev/null
|
|
94
|
+
printf '%s\n' "$fb"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
watch_bg() { # <state> <fakebin> <out> [extra env assignments...]
|
|
98
|
+
local state=$1 fakebin=$2 out=$3
|
|
99
|
+
shift 3
|
|
100
|
+
PATH="$fakebin:$PATH" FM_STATE_OVERRIDE="$state" \
|
|
101
|
+
FM_CREW_STATE_BIN="$fakebin/fm-crew-state.sh" \
|
|
102
|
+
FM_FAKE_CREW_STATE='state: working · source: run-step · validating (running)' \
|
|
103
|
+
FM_POLL=1 FM_SIGNAL_GRACE=1 FM_CHECK_INTERVAL=999999 FM_HEARTBEAT=999999 \
|
|
104
|
+
FM_TASK_INBOX_GRACE_SECS=1 \
|
|
105
|
+
env "$@" "$WATCH" > "$out" 2>/dev/null &
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
wait_watcher_gone() { # <pid> [limit-ticks]
|
|
109
|
+
local pid=$1 limit=${2:-120} i=0
|
|
110
|
+
while [ "$i" -lt "$limit" ]; do
|
|
111
|
+
kill -0 "$pid" 2>/dev/null || return 0
|
|
112
|
+
sleep 0.1
|
|
113
|
+
i=$((i + 1))
|
|
114
|
+
done
|
|
115
|
+
return 1
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
age_path() { # <path> (set mtime well past any grace under test)
|
|
119
|
+
touch -t 202001010000 "$1"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
test_write_is_durable_and_exact() {
|
|
123
|
+
local state rec rec2 doorbell doorbell2 expected actual expected2 actual2 text
|
|
124
|
+
state="$TMP_ROOT/write/state"; mkdir -p "$state"
|
|
125
|
+
text=$'line one\nline two with spaces\n/slash body\n\n'
|
|
126
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "$text") \
|
|
127
|
+
|| fail "inbox write failed"
|
|
128
|
+
[ -f "$rec" ] || fail "inbox write printed a path that does not exist: $rec"
|
|
129
|
+
case "$rec" in
|
|
130
|
+
"$state/t1.inbox/001.msg") : ;;
|
|
131
|
+
*) fail "first record should be 001.msg under the task inbox, got $rec" ;;
|
|
132
|
+
esac
|
|
133
|
+
expected="$state/expected.body"
|
|
134
|
+
actual="$state/actual.body"
|
|
135
|
+
printf '%s' "$text" > "$expected"
|
|
136
|
+
inbox_lib "$state" fm_task_inbox_body "$rec" > "$actual" \
|
|
137
|
+
|| fail "record body could not be read"
|
|
138
|
+
cmp -s "$expected" "$actual" \
|
|
139
|
+
|| fail "record body did not preserve trailing and blank-line bytes"
|
|
140
|
+
rec2=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "no trailing newline") \
|
|
141
|
+
|| fail "second inbox write failed"
|
|
142
|
+
expected2="$state/expected-no-newline.body"
|
|
143
|
+
actual2="$state/actual-no-newline.body"
|
|
144
|
+
printf '%s' "no trailing newline" > "$expected2"
|
|
145
|
+
inbox_lib "$state" fm_task_inbox_body "$rec2" > "$actual2" \
|
|
146
|
+
|| fail "second record body could not be read"
|
|
147
|
+
cmp -s "$expected2" "$actual2" \
|
|
148
|
+
|| fail "record body added a trailing newline"
|
|
149
|
+
doorbell=$(inbox_lib "$state" fm_task_inbox_doorbell_line "$rec")
|
|
150
|
+
doorbell2=$(inbox_lib "$state" fm_task_inbox_doorbell_line "$rec2")
|
|
151
|
+
[ "$doorbell" = "$doorbell2" ] \
|
|
152
|
+
|| fail "every record in one inbox should ring the same drain-all doorbell"
|
|
153
|
+
assert_contains "$doorbell" "$state/t1.inbox/*.msg" "doorbell should name all unhandled records"
|
|
154
|
+
assert_contains "$doorbell" "numeric order" "doorbell should require ordered processing"
|
|
155
|
+
assert_contains "$doorbell" "$state/t1.inbox/handled/" "doorbell should name the handled dir"
|
|
156
|
+
assert_contains "$doorbell" "Firstmate instruction waiting" "doorbell should be self-describing"
|
|
157
|
+
case "$doorbell" in
|
|
158
|
+
*$'\n'*) fail "the doorbell must be a single line" ;;
|
|
159
|
+
esac
|
|
160
|
+
pass "inbox: a steer is written durably and round-trips byte-exact with a self-describing doorbell"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
test_idempotent_write_dedups_exact_body() {
|
|
164
|
+
local state r1 r2 r3 r4 count text
|
|
165
|
+
state="$TMP_ROOT/idem/state"; mkdir -p "$state"
|
|
166
|
+
text=$'re-runnable steer\nsecond line'
|
|
167
|
+
r1=$(inbox_lib "$state" fm_task_inbox_write_idempotent "$state" t1 "$text") \
|
|
168
|
+
|| fail "idempotent write failed"
|
|
169
|
+
[ "$r1" = "$state/t1.inbox/001.msg" ] || fail "first idempotent write should create 001.msg, got $r1"
|
|
170
|
+
# Re-running the same enqueue (the safe recovery after an ambiguous remote
|
|
171
|
+
# transport failure) lands on the SAME record, never a duplicate.
|
|
172
|
+
r2=$(inbox_lib "$state" fm_task_inbox_write_idempotent "$state" t1 "$text") \
|
|
173
|
+
|| fail "idempotent re-run failed"
|
|
174
|
+
[ "$r2" = "$r1" ] || fail "an identical re-run should return the existing record, got $r2"
|
|
175
|
+
count=$(find "$state/t1.inbox" -maxdepth 1 -name '*.msg' | wc -l | tr -d ' ')
|
|
176
|
+
[ "$count" = 1 ] || fail "an identical re-run must not enqueue a duplicate, found $count records"
|
|
177
|
+
# A different body - two logical requests differ at least by their embedded
|
|
178
|
+
# correlation token - still enqueues normally.
|
|
179
|
+
r3=$(inbox_lib "$state" fm_task_inbox_write_idempotent "$state" t1 $'re-runnable steer\nsecond line changed') \
|
|
180
|
+
|| fail "idempotent write of a different body failed"
|
|
181
|
+
[ "$r3" = "$state/t1.inbox/002.msg" ] || fail "a different body should enqueue a new record, got $r3"
|
|
182
|
+
# A body the worker already acknowledged still dedups: the re-run reports
|
|
183
|
+
# the handled record rather than re-delivering an instruction that was
|
|
184
|
+
# already acted on.
|
|
185
|
+
mv "$r1" "$state/t1.inbox/handled/"
|
|
186
|
+
r4=$(inbox_lib "$state" fm_task_inbox_write_idempotent "$state" t1 "$text") \
|
|
187
|
+
|| fail "idempotent re-run after the ack failed"
|
|
188
|
+
[ "$r4" = "$state/t1.inbox/handled/001.msg" ] \
|
|
189
|
+
|| fail "a re-run of an acknowledged steer should land on the handled record, got $r4"
|
|
190
|
+
count=$(find "$state/t1.inbox" -maxdepth 1 -name '*.msg' | wc -l | tr -d ' ')
|
|
191
|
+
[ "$count" = 1 ] || fail "a re-run of an acknowledged steer must not re-enqueue it, found $count unhandled records"
|
|
192
|
+
pass "inbox: the idempotent enqueue dedups an exact re-run onto the same record, handled or not"
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
test_idempotent_write_follows_concurrent_ack() {
|
|
196
|
+
local state rec result count text
|
|
197
|
+
state="$TMP_ROOT/idem-ack-race/state"; mkdir -p "$state"
|
|
198
|
+
text="acknowledge while dedup scans"
|
|
199
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write_idempotent "$state" t1 "$text") \
|
|
200
|
+
|| fail "race fixture write failed"
|
|
201
|
+
result=$(FM_STATE_OVERRIDE="$state" bash -c '
|
|
202
|
+
. "$1"
|
|
203
|
+
eval "$(declare -f fm_task_inbox_body | sed "1s/fm_task_inbox_body/_original_fm_task_inbox_body/")"
|
|
204
|
+
fm_task_inbox_body() {
|
|
205
|
+
candidate=$1
|
|
206
|
+
case "$candidate" in
|
|
207
|
+
*/handled/*) ;;
|
|
208
|
+
*) mv "$candidate" "${candidate%/*}/handled/" || return 1
|
|
209
|
+
candidate="${candidate%/*}/handled/${candidate##*/}" ;;
|
|
210
|
+
esac
|
|
211
|
+
_original_fm_task_inbox_body "$candidate"
|
|
212
|
+
}
|
|
213
|
+
fm_task_inbox_write_idempotent "$2" t1 "$3"
|
|
214
|
+
' _ "$ROOT/bin/fm-task-inbox-lib.sh" "$state" "$text") \
|
|
215
|
+
|| fail "idempotent enqueue failed while acknowledgement moved its candidate"
|
|
216
|
+
[ "$result" = "$state/t1.inbox/handled/${rec##*/}" ] \
|
|
217
|
+
|| fail "dedup did not follow the concurrently acknowledged record: $result"
|
|
218
|
+
count=$(find "$state/t1.inbox" -name '*.msg' | wc -l | tr -d ' ')
|
|
219
|
+
[ "$count" = 1 ] || fail "acknowledgement racing dedup created a duplicate record"
|
|
220
|
+
pass "inbox: idempotent enqueue follows a record concurrently moved to handled"
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
test_handled_mv_dedups_by_sequence() {
|
|
224
|
+
local state r1 r2 oldest r3
|
|
225
|
+
state="$TMP_ROOT/dedup/state"; mkdir -p "$state"
|
|
226
|
+
r1=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "first")
|
|
227
|
+
r2=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "second")
|
|
228
|
+
[ "$r2" = "$state/t1.inbox/002.msg" ] || fail "second record should be 002.msg, got $r2"
|
|
229
|
+
oldest=$(inbox_lib "$state" fm_task_inbox_oldest_unhandled "$state" t1)
|
|
230
|
+
[ "$oldest" = "$r1" ] || fail "oldest unhandled should be 001, got $oldest"
|
|
231
|
+
mv "$r1" "$state/t1.inbox/handled/"
|
|
232
|
+
oldest=$(inbox_lib "$state" fm_task_inbox_oldest_unhandled "$state" t1)
|
|
233
|
+
[ "$oldest" = "$r2" ] || fail "after the ack mv the oldest should advance to 002, got $oldest"
|
|
234
|
+
# Re-acking the same message is a no-op: the record is already retired and
|
|
235
|
+
# nothing re-lists it as unhandled.
|
|
236
|
+
mv "$state/t1.inbox/001.msg" "$state/t1.inbox/handled/" 2>/dev/null \
|
|
237
|
+
&& fail "a second mv of an acked record should find nothing to move"
|
|
238
|
+
mv "$r2" "$state/t1.inbox/handled/"
|
|
239
|
+
if inbox_lib "$state" fm_task_inbox_oldest_unhandled "$state" t1 >/dev/null; then
|
|
240
|
+
fail "a fully handled inbox should report no unhandled record"
|
|
241
|
+
fi
|
|
242
|
+
# An acknowledged sequence is never reissued, so a message is processed at
|
|
243
|
+
# most once per worker lifetime even if every doorbell is duplicated.
|
|
244
|
+
r3=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "third")
|
|
245
|
+
[ "$r3" = "$state/t1.inbox/003.msg" ] || fail "a handled sequence was reissued: $r3"
|
|
246
|
+
pass "inbox: the handled mv is the idempotent ack and sequences are never reissued"
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
test_concurrent_writers_never_clobber() {
|
|
250
|
+
local state i pids=() count
|
|
251
|
+
state="$TMP_ROOT/race/state"; mkdir -p "$state"
|
|
252
|
+
for i in 1 2 3 4 5 6; do
|
|
253
|
+
inbox_lib "$state" fm_task_inbox_write "$state" t1 "steer number $i" >/dev/null &
|
|
254
|
+
pids+=($!)
|
|
255
|
+
done
|
|
256
|
+
for i in "${pids[@]}"; do
|
|
257
|
+
wait "$i" || fail "a concurrent inbox write failed"
|
|
258
|
+
done
|
|
259
|
+
count=$(find "$state/t1.inbox" -maxdepth 1 -name '*.msg' | wc -l | tr -d ' ')
|
|
260
|
+
[ "$count" = 6 ] || fail "6 concurrent writes should yield 6 records, got $count:"$'\n'"$(ls "$state/t1.inbox")"
|
|
261
|
+
for i in 1 2 3 4 5 6; do
|
|
262
|
+
grep -rqF "steer number $i" "$state/t1.inbox" \
|
|
263
|
+
|| fail "steer number $i was lost in the concurrent write race"
|
|
264
|
+
done
|
|
265
|
+
pass "inbox: concurrent writers serialize on the sequence lock and lose nothing"
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
test_ladder_writes_ignore_vanished_inbox() {
|
|
269
|
+
local state rec
|
|
270
|
+
state="$TMP_ROOT/vanished/state"; mkdir -p "$state"
|
|
271
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "retired task")
|
|
272
|
+
rm -rf "$state/t1.inbox"
|
|
273
|
+
inbox_lib "$state" fm_task_inbox_record_ring "$state" t1 "$rec" \
|
|
274
|
+
|| fail "ring bookkeeping should ignore a concurrently removed inbox"
|
|
275
|
+
inbox_lib "$state" fm_task_inbox_record_escalated "$state" t1 "$rec" \
|
|
276
|
+
|| fail "escalation bookkeeping should ignore a concurrently removed inbox"
|
|
277
|
+
[ ! -e "$state/t1.inbox" ] || fail "bookkeeping recreated a retired task inbox"
|
|
278
|
+
pass "inbox: ladder bookkeeping ignores a concurrently removed inbox"
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
test_fire_and_forget_records_never_enter_the_ladder() {
|
|
282
|
+
local state fire tracked action
|
|
283
|
+
state="$TMP_ROOT/fire-and-forget/state"; mkdir -p "$state"
|
|
284
|
+
fire=$(inbox_lib "$state" fm_task_inbox_write_idempotent "$state" t1 "one-shot steer" fire-and-forget)
|
|
285
|
+
age_path "$fire"
|
|
286
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=0 FM_TASK_INBOX_RING_MAX=0 \
|
|
287
|
+
inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
288
|
+
[ "$action" = quiet ] || fail "a fire-and-forget record entered the re-ring ladder: $action"
|
|
289
|
+
tracked=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "tracked steer")
|
|
290
|
+
age_path "$tracked"
|
|
291
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=0 FM_TASK_INBOX_RING_MAX=0 \
|
|
292
|
+
inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
293
|
+
[ "$action" = "escalate $tracked 0" ] \
|
|
294
|
+
|| fail "a fire-and-forget record hid the later tracked steer: $action"
|
|
295
|
+
[ -f "$fire" ] || fail "excluding fire-and-forget from escalation removed its durable record"
|
|
296
|
+
pass "inbox: fire-and-forget records stay durable and outside the ladder"
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
test_ring_ladder_policy() {
|
|
300
|
+
local state rec action
|
|
301
|
+
state="$TMP_ROOT/ladder/state"; mkdir -p "$state"
|
|
302
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "do the thing")
|
|
303
|
+
# Within grace: quiet.
|
|
304
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=3600 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
305
|
+
[ "$action" = quiet ] || fail "a fresh unhandled message inside grace should be quiet, got: $action"
|
|
306
|
+
# Past grace: one ring is due.
|
|
307
|
+
age_path "$rec"
|
|
308
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
309
|
+
[ "$action" = "ring $rec" ] || fail "an aged unhandled message should be due a ring, got: $action"
|
|
310
|
+
# A just-recorded ring holds the spacing: quiet until another grace elapses.
|
|
311
|
+
inbox_lib "$state" fm_task_inbox_record_ring "$state" t1 "$rec"
|
|
312
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
313
|
+
[ "$action" = quiet ] || fail "a ring within the spacing window should be quiet, got: $action"
|
|
314
|
+
# Backdate the ladder: the next ring becomes due, and at the budget the
|
|
315
|
+
# action turns into a single escalation.
|
|
316
|
+
printf '001.msg\t1\t100\n' > "$state/t1.inbox/.ring-state"
|
|
317
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 FM_TASK_INBOX_RING_MAX=3 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
318
|
+
[ "$action" = "ring $rec" ] || fail "an aged ladder should ring again, got: $action"
|
|
319
|
+
printf '001.msg\t3\t100\n' > "$state/t1.inbox/.ring-state"
|
|
320
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 FM_TASK_INBOX_RING_MAX=3 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
321
|
+
[ "$action" = "escalate $rec 3" ] || fail "a spent ring budget should escalate, got: $action"
|
|
322
|
+
# Escalation fires at most once per message.
|
|
323
|
+
inbox_lib "$state" fm_task_inbox_record_escalated "$state" t1 "$rec"
|
|
324
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 FM_TASK_INBOX_RING_MAX=3 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
325
|
+
[ "$action" = quiet ] || fail "an escalated message should stay quiet for recovery, got: $action"
|
|
326
|
+
# The acknowledgement resets the ladder: the next message starts fresh.
|
|
327
|
+
mv "$rec" "$state/t1.inbox/handled/"
|
|
328
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
329
|
+
[ "$action" = quiet ] || fail "a handled inbox should be quiet, got: $action"
|
|
330
|
+
[ ! -e "$state/t1.inbox/.escalated" ] || fail "the ack should clear the escalation marker"
|
|
331
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "next thing")
|
|
332
|
+
age_path "$rec"
|
|
333
|
+
action=$(FM_TASK_INBOX_GRACE_SECS=60 FM_TASK_INBOX_RING_MAX=3 inbox_lib "$state" fm_task_inbox_due_action "$state" t1)
|
|
334
|
+
[ "$action" = "ring $rec" ] || fail "the next message should start a fresh ladder, got: $action"
|
|
335
|
+
pass "inbox: the re-ring ladder paces by grace, escalates once, and resets on ack"
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
setup_watch_case() { # <name> -> echoes case dir; state in <dir>/state
|
|
339
|
+
local name=$1 dir
|
|
340
|
+
dir="$TMP_ROOT/$name"
|
|
341
|
+
mkdir -p "$dir/state"
|
|
342
|
+
make_watch_stubs "$dir" >/dev/null
|
|
343
|
+
fm_write_meta "$dir/state/t1.meta" "window=sess:fm-t1" "kind=ship" "harness=grok"
|
|
344
|
+
printf '%s\n' "$dir"
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
idle_capture() { # <dir>
|
|
348
|
+
printf '╭────╮\n│ │\n╰────╯\n' > "$1/idle.capture"
|
|
349
|
+
printf '%s\n' "$1/idle.capture"
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
test_watcher_rerings_idle_pane_quietly() {
|
|
353
|
+
local dir state out log pid rec
|
|
354
|
+
dir=$(setup_watch_case rering)
|
|
355
|
+
state="$dir/state"; out="$dir/watch.out"; log="$dir/send.log"; : > "$log"
|
|
356
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "please continue")
|
|
357
|
+
age_path "$rec"
|
|
358
|
+
watch_bg "$state" "$dir/fakebin" "$out" \
|
|
359
|
+
FM_SEND_LOG="$log" FM_FAKE_TMUX_CAPTURE="$(idle_capture "$dir")" \
|
|
360
|
+
FM_TASK_INBOX_RING_MAX=99
|
|
361
|
+
pid=$!
|
|
362
|
+
local i=0
|
|
363
|
+
while [ "$i" -lt 100 ]; do
|
|
364
|
+
grep -qF 'Firstmate instruction waiting' "$log" 2>/dev/null && break
|
|
365
|
+
kill -0 "$pid" 2>/dev/null || break
|
|
366
|
+
sleep 0.1
|
|
367
|
+
i=$((i + 1))
|
|
368
|
+
done
|
|
369
|
+
grep -qF "Firstmate instruction waiting: list $state/t1.inbox/*.msg" "$log" \
|
|
370
|
+
|| { kill "$pid" 2>/dev/null; fail "the watcher never re-rang the doorbell:"$'\n'"$(cat "$log")"; }
|
|
371
|
+
kill -0 "$pid" 2>/dev/null \
|
|
372
|
+
|| fail "a healthy re-ring must not wake firstmate (watcher exited):"$'\n'"$(cat "$out")"
|
|
373
|
+
[ ! -s "$state/.wake-queue" ] \
|
|
374
|
+
|| { kill "$pid" 2>/dev/null; fail "a healthy re-ring queued a wake:"$'\n'"$(cat "$state/.wake-queue")"; }
|
|
375
|
+
# The acknowledgement silences the ladder: no further doorbells after the mv.
|
|
376
|
+
mv "$rec" "$state/t1.inbox/handled/"
|
|
377
|
+
sleep 2.5
|
|
378
|
+
: > "$log"
|
|
379
|
+
sleep 2.5
|
|
380
|
+
kill "$pid" 2>/dev/null; wait "$pid" 2>/dev/null
|
|
381
|
+
[ ! -s "$log" ] || fail "the watcher kept ringing after the ack:"$'\n'"$(cat "$log")"
|
|
382
|
+
pass "watcher: an unhandled aged message on an idle pane re-rings without waking firstmate, and the ack silences it"
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
test_watcher_waits_on_busy_pane() {
|
|
386
|
+
local dir state out log pid rec
|
|
387
|
+
dir=$(setup_watch_case busywait)
|
|
388
|
+
state="$dir/state"; out="$dir/watch.out"; log="$dir/send.log"; : > "$log"
|
|
389
|
+
printf 'some output\nBUSYTOKEN active\n' > "$dir/busy.capture"
|
|
390
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "please continue")
|
|
391
|
+
age_path "$rec"
|
|
392
|
+
watch_bg "$state" "$dir/fakebin" "$out" \
|
|
393
|
+
FM_SEND_LOG="$log" FM_FAKE_TMUX_CAPTURE="$dir/busy.capture" \
|
|
394
|
+
FM_BUSY_REGEX=BUSYTOKEN FM_TASK_INBOX_RING_MAX=99
|
|
395
|
+
pid=$!
|
|
396
|
+
sleep 4
|
|
397
|
+
kill "$pid" 2>/dev/null; wait "$pid" 2>/dev/null
|
|
398
|
+
[ ! -s "$log" ] || fail "a busy pane should wait, not ring:"$'\n'"$(cat "$log")"
|
|
399
|
+
[ ! -s "$state/.wake-queue" ] || fail "a busy wait queued a wake:"$'\n'"$(cat "$state/.wake-queue")"
|
|
400
|
+
pass "watcher: a busy pane just waits - the record is durable and no doorbell is typed"
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
test_watcher_quiet_on_healthy_inbox() {
|
|
404
|
+
local dir state out log pid
|
|
405
|
+
dir=$(setup_watch_case healthy)
|
|
406
|
+
state="$dir/state"; out="$dir/watch.out"; log="$dir/send.log"; : > "$log"
|
|
407
|
+
mkdir -p "$state/t1.inbox/handled"
|
|
408
|
+
watch_bg "$state" "$dir/fakebin" "$out" \
|
|
409
|
+
FM_SEND_LOG="$log" FM_FAKE_TMUX_CAPTURE="$(idle_capture "$dir")" \
|
|
410
|
+
FM_TASK_INBOX_RING_MAX=99
|
|
411
|
+
pid=$!
|
|
412
|
+
sleep 4
|
|
413
|
+
kill -0 "$pid" 2>/dev/null || fail "the watcher exited on a healthy empty inbox:"$'\n'"$(cat "$out")"
|
|
414
|
+
kill "$pid" 2>/dev/null; wait "$pid" 2>/dev/null
|
|
415
|
+
[ ! -s "$log" ] || fail "an empty inbox rang a doorbell:"$'\n'"$(cat "$log")"
|
|
416
|
+
[ ! -s "$state/.wake-queue" ] || fail "an empty inbox queued a wake:"$'\n'"$(cat "$state/.wake-queue")"
|
|
417
|
+
pass "watcher: a healthy or empty inbox stays completely silent"
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
test_watcher_ack_silences_unwritable_ladder() {
|
|
421
|
+
local dir state out log pid rec rings i=0
|
|
422
|
+
dir=$(setup_watch_case ack-unwritable-ladder)
|
|
423
|
+
state="$dir/state"; out="$dir/watch.out"; log="$dir/send.log"; : > "$log"
|
|
424
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "please continue")
|
|
425
|
+
age_path "$rec"
|
|
426
|
+
mkdir "$state/t1.inbox/.ring-state"
|
|
427
|
+
watch_bg "$state" "$dir/fakebin" "$out" \
|
|
428
|
+
FM_SEND_LOG="$log" FM_FAKE_TMUX_CAPTURE="$(idle_capture "$dir")" \
|
|
429
|
+
FM_ACK_RECORD="$rec" FM_TASK_INBOX_RING_MAX=99
|
|
430
|
+
pid=$!
|
|
431
|
+
while [ "$i" -lt 100 ]; do
|
|
432
|
+
[ -f "$state/t1.inbox/handled/001.msg" ] && break
|
|
433
|
+
kill -0 "$pid" 2>/dev/null || break
|
|
434
|
+
sleep 0.1
|
|
435
|
+
i=$((i + 1))
|
|
436
|
+
done
|
|
437
|
+
[ -f "$state/t1.inbox/handled/001.msg" ] \
|
|
438
|
+
|| { kill "$pid" 2>/dev/null; fail "the doorbell stub did not acknowledge the record"; }
|
|
439
|
+
sleep 2
|
|
440
|
+
kill -0 "$pid" 2>/dev/null \
|
|
441
|
+
|| fail "the watcher escalated ladder failure after the record was acknowledged:"$'\n'"$(cat "$out")"
|
|
442
|
+
kill "$pid" 2>/dev/null; wait "$pid" 2>/dev/null
|
|
443
|
+
rings=$(grep -cF 'Firstmate instruction waiting' "$log" || true)
|
|
444
|
+
[ "$rings" = 1 ] || fail "acknowledgement should silence retries, got $rings doorbells:"$'\n'"$(cat "$log")"
|
|
445
|
+
[ ! -s "$state/.wake-queue" ] \
|
|
446
|
+
|| fail "an acknowledged record queued a bookkeeping wake:"$'\n'"$(cat "$state/.wake-queue")"
|
|
447
|
+
pass "watcher: acknowledgement silences an unwritable ladder without a stale wake"
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
test_watcher_surfaces_unwritable_ladder() {
|
|
451
|
+
local dir state out log pid rec rings wakes
|
|
452
|
+
dir=$(setup_watch_case unwritable-ladder)
|
|
453
|
+
state="$dir/state"; out="$dir/watch.out"; log="$dir/send.log"; : > "$log"
|
|
454
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "please continue")
|
|
455
|
+
age_path "$rec"
|
|
456
|
+
mkdir "$state/t1.inbox/.ring-state"
|
|
457
|
+
watch_bg "$state" "$dir/fakebin" "$out" \
|
|
458
|
+
FM_SEND_LOG="$log" FM_FAKE_TMUX_CAPTURE="$(idle_capture "$dir")" \
|
|
459
|
+
FM_TASK_INBOX_RING_MAX=99
|
|
460
|
+
pid=$!
|
|
461
|
+
wait_watcher_gone "$pid" \
|
|
462
|
+
|| { kill "$pid" 2>/dev/null; fail "the watcher silently retried with unwritable ladder bookkeeping"; }
|
|
463
|
+
rings=$(grep -cF 'Firstmate instruction waiting' "$log" || true)
|
|
464
|
+
[ "$rings" = 1 ] || fail "expected one doorbell before the bookkeeping wake, got $rings:"$'\n'"$(cat "$log")"
|
|
465
|
+
wakes=$(grep -cF 'steering-inbox ladder bookkeeping unwritable' "$state/.wake-queue" || true)
|
|
466
|
+
[ "$wakes" = 1 ] \
|
|
467
|
+
|| fail "expected exactly one bookkeeping-unwritable stale wake, got $wakes:"$'\n'"$(cat "$state/.wake-queue" 2>/dev/null)"
|
|
468
|
+
grep -qF "$state/t1.inbox/.ring-state cannot be written" "$state/.wake-queue" \
|
|
469
|
+
|| fail "the stale wake did not identify the unwritable ladder:"$'\n'"$(cat "$state/.wake-queue")"
|
|
470
|
+
[ -f "$rec" ] || fail "the unhandled record disappeared during bookkeeping failure"
|
|
471
|
+
grep -qF 'stale:' "$out" \
|
|
472
|
+
|| fail "the watcher should exit through the ordinary stale wake:"$'\n'"$(cat "$out")"
|
|
473
|
+
pass "watcher: unwritable ladder bookkeeping surfaces a stale wake after the doorbell"
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
test_watcher_escalates_once_after_budget() {
|
|
477
|
+
local dir state out log pid rec rings
|
|
478
|
+
dir=$(setup_watch_case escalate)
|
|
479
|
+
state="$dir/state"; out="$dir/watch.out"; log="$dir/send.log"; : > "$log"
|
|
480
|
+
rec=$(inbox_lib "$state" fm_task_inbox_write "$state" t1 "please continue")
|
|
481
|
+
age_path "$rec"
|
|
482
|
+
watch_bg "$state" "$dir/fakebin" "$out" \
|
|
483
|
+
FM_SEND_LOG="$log" FM_FAKE_TMUX_CAPTURE="$(idle_capture "$dir")" \
|
|
484
|
+
FM_TASK_INBOX_RING_MAX=1
|
|
485
|
+
pid=$!
|
|
486
|
+
wait_watcher_gone "$pid" \
|
|
487
|
+
|| { kill "$pid" 2>/dev/null; fail "the watcher never escalated a spent ring budget"; }
|
|
488
|
+
rings=$(grep -cF 'Firstmate instruction waiting' "$log" || true)
|
|
489
|
+
[ "$rings" = 1 ] || fail "expected exactly 1 doorbell before escalation, got $rings:"$'\n'"$(cat "$log")"
|
|
490
|
+
grep -qF 'unread firstmate instruction' "$state/.wake-queue" \
|
|
491
|
+
|| fail "the escalation should queue a stale wake naming the unread instruction:"$'\n'"$(cat "$state/.wake-queue" 2>/dev/null)"
|
|
492
|
+
grep -qF "$rec" "$state/.wake-queue" \
|
|
493
|
+
|| fail "the stale wake should name the record path:"$'\n'"$(cat "$state/.wake-queue")"
|
|
494
|
+
[ "$(grep -cF 'unread firstmate instruction' "$state/.wake-queue")" = 1 ] \
|
|
495
|
+
|| fail "the escalation must fire exactly once:"$'\n'"$(cat "$state/.wake-queue")"
|
|
496
|
+
grep -qF 'stale:' "$out" || fail "the watcher should exit through the ordinary stale wake:"$'\n'"$(cat "$out")"
|
|
497
|
+
pass "watcher: a spent ring budget emits exactly one ordinary stale wake for recovery"
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
test_write_is_durable_and_exact
|
|
501
|
+
test_idempotent_write_dedups_exact_body
|
|
502
|
+
test_idempotent_write_follows_concurrent_ack
|
|
503
|
+
test_handled_mv_dedups_by_sequence
|
|
504
|
+
test_concurrent_writers_never_clobber
|
|
505
|
+
test_ladder_writes_ignore_vanished_inbox
|
|
506
|
+
test_fire_and_forget_records_never_enter_the_ladder
|
|
507
|
+
test_ring_ladder_policy
|
|
508
|
+
test_watcher_rerings_idle_pane_quietly
|
|
509
|
+
test_watcher_waits_on_busy_pane
|
|
510
|
+
test_watcher_quiet_on_healthy_inbox
|
|
511
|
+
test_watcher_ack_silences_unwritable_ladder
|
|
512
|
+
test_watcher_surfaces_unwritable_ladder
|
|
513
|
+
test_watcher_escalates_once_after_budget
|