@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,712 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tests/fm-startup-network.test.sh - behavior tests for bin/fm-startup-network.sh,
|
|
3
|
+
# the deferred network stage a session start launches instead of running its
|
|
4
|
+
# network work on the blocking path.
|
|
5
|
+
#
|
|
6
|
+
# The session-start suite proves the digest no longer waits and that the deferred
|
|
7
|
+
# sweeps still land. This suite pins the stage's own contract, whose whole job is
|
|
8
|
+
# to make deferral safe:
|
|
9
|
+
# - `start` returns immediately and does not hold the caller's stdout open,
|
|
10
|
+
# which is what would strand a session-open hook behind the worker
|
|
11
|
+
# - a durable acknowledgement after harvest prints a finished result suppresses
|
|
12
|
+
# the wake, while an unacknowledged result always produces one
|
|
13
|
+
# - mutating sweeps are refused when the fleet lock no longer names the session
|
|
14
|
+
# that requested them, and the refusal is reported rather than silent
|
|
15
|
+
# - the aggregate bound turns a wedged sweep into an actionable line
|
|
16
|
+
# - an abandoned `running` record is reported as needing a rerun rather than
|
|
17
|
+
# staying "in progress" forever
|
|
18
|
+
# - single-flight: a second `start` never launches a competing worker
|
|
19
|
+
set -u
|
|
20
|
+
|
|
21
|
+
# shellcheck source=tests/lib.sh
|
|
22
|
+
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
|
23
|
+
|
|
24
|
+
TMP_ROOT=$(fm_test_tmproot fm-startup-network-tests)
|
|
25
|
+
FM_TEST_CLEANUP_DIRS+=("$TMP_ROOT")
|
|
26
|
+
trap fm_test_cleanup EXIT
|
|
27
|
+
|
|
28
|
+
# new_world <name>: an FM_HOME plus a fake code root whose bin/ is a real
|
|
29
|
+
# firstmate bin/ except for fm-bootstrap.sh, which is replaced by a scriptable
|
|
30
|
+
# stand-in. The stage's contract is about WHEN and WHETHER the network half runs
|
|
31
|
+
# and how its result is published; bin/fm-bootstrap.sh's own behavior is owned by
|
|
32
|
+
# tests/fm-bootstrap.test.sh, so pinning it here would duplicate that owner and
|
|
33
|
+
# make these assertions depend on unrelated tool detection.
|
|
34
|
+
new_world() {
|
|
35
|
+
local name=$1 w home root
|
|
36
|
+
w="$TMP_ROOT/$name"
|
|
37
|
+
home="$w/home"
|
|
38
|
+
root="$w/root"
|
|
39
|
+
mkdir -p "$home/state" "$root/bin"
|
|
40
|
+
for f in "$ROOT"/bin/*.sh; do
|
|
41
|
+
ln -s "$f" "$root/bin/$(basename "$f")"
|
|
42
|
+
done
|
|
43
|
+
rm -f "$root/bin/fm-bootstrap.sh"
|
|
44
|
+
cat > "$root/bin/fm-bootstrap.sh" <<'SH'
|
|
45
|
+
#!/usr/bin/env bash
|
|
46
|
+
# Scriptable stand-in: records how it was invoked, then behaves as the test asks.
|
|
47
|
+
set -u
|
|
48
|
+
printf 'network=%s detect_only=%s\n' \
|
|
49
|
+
"${FM_BOOTSTRAP_NETWORK:-all}" "${FM_BOOTSTRAP_DETECT_ONLY:-0}" \
|
|
50
|
+
>> "${FM_FAKE_BOOTSTRAP_LOG:?}"
|
|
51
|
+
# The real sweeps record their elapsed times through fm-timing-lib.sh, which
|
|
52
|
+
# reaches them as an exported FM_TIMING_LOG. Recording the same way here proves
|
|
53
|
+
# the stage actually hands that channel to its child and publishes what the child
|
|
54
|
+
# wrote - the part of the contract this suite owns. What the real sweeps measure
|
|
55
|
+
# is owned by tests/fm-bootstrap.test.sh.
|
|
56
|
+
if [ -n "${FM_TIMING_LOG:-}" ]; then
|
|
57
|
+
. "$(dirname "$0")/fm-timing-lib.sh"
|
|
58
|
+
fm_timing_record phase "${FM_FAKE_TIMING_PHASE:-gh-auth}" \
|
|
59
|
+
"$(( $(fm_timing_now_ms) - 1500 ))" "${FM_FAKE_TIMING_DETAIL:-}"
|
|
60
|
+
fi
|
|
61
|
+
[ -z "${FM_FAKE_BOOTSTRAP_SLEEP:-}" ] || sleep "$FM_FAKE_BOOTSTRAP_SLEEP"
|
|
62
|
+
[ -z "${FM_FAKE_BOOTSTRAP_OUT:-}" ] || printf '%s\n' "$FM_FAKE_BOOTSTRAP_OUT"
|
|
63
|
+
exit "${FM_FAKE_BOOTSTRAP_RC:-0}"
|
|
64
|
+
SH
|
|
65
|
+
chmod +x "$root/bin/fm-bootstrap.sh"
|
|
66
|
+
cat > "$root/bin/ps" <<'SH'
|
|
67
|
+
#!/usr/bin/env bash
|
|
68
|
+
pid=
|
|
69
|
+
previous=
|
|
70
|
+
for argument in "$@"; do
|
|
71
|
+
[ "$previous" = -p ] && pid=$argument
|
|
72
|
+
previous=$argument
|
|
73
|
+
done
|
|
74
|
+
if [ "$pid" = "${FM_FAKE_HARNESS_PID:-}" ]; then
|
|
75
|
+
case "$*" in
|
|
76
|
+
*comm=*) printf '/usr/local/bin/claude\n' ;;
|
|
77
|
+
*args=*) printf 'claude\n' ;;
|
|
78
|
+
*ppid=*) /bin/ps -o ppid= -p "$pid" ;;
|
|
79
|
+
esac
|
|
80
|
+
else
|
|
81
|
+
/bin/ps "$@"
|
|
82
|
+
fi
|
|
83
|
+
SH
|
|
84
|
+
chmod +x "$root/bin/ps"
|
|
85
|
+
printf '%s|%s|%s\n' "$home" "$root" "$w/bootstrap.log"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# The detached worker records itself a moment after `start` returns - that gap is
|
|
89
|
+
# the whole point of not blocking - so a test that wants to observe the worker
|
|
90
|
+
# waits for its record rather than assuming instant publication.
|
|
91
|
+
await_worker_record() { # <home>
|
|
92
|
+
local home=$1 waited=0
|
|
93
|
+
while [ ! -s "$home/state/.startup-network.status" ] && [ "$waited" -lt 100 ]; do
|
|
94
|
+
sleep 0.1
|
|
95
|
+
waited=$((waited + 1))
|
|
96
|
+
done
|
|
97
|
+
[ -s "$home/state/.startup-network.status" ] || fail "the detached worker never recorded itself"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
test_wait_fails_without_a_published_stage() {
|
|
101
|
+
local rec home root log
|
|
102
|
+
rec=$(new_world wait-without-stage)
|
|
103
|
+
IFS='|' read -r home root log <<EOF
|
|
104
|
+
$rec
|
|
105
|
+
EOF
|
|
106
|
+
|
|
107
|
+
if run_stage "$home" "$root" wait 1 >/dev/null; then
|
|
108
|
+
fail "wait reported success even though no deferred stage had published"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
pass "fm-startup-network: wait fails when no deferred stage publishes before its deadline"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
run_stage() { # <home> <root> <args...>
|
|
115
|
+
local home=$1 root=$2
|
|
116
|
+
shift 2
|
|
117
|
+
PATH="$root/bin:$PATH" FM_FAKE_HARNESS_PID="${FM_FAKE_HARNESS_PID_OVERRIDE:-$$}" \
|
|
118
|
+
FM_HOME="$home" FM_ROOT_OVERRIDE="$root" "$root/bin/fm-startup-network.sh" "$@"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
wait_for_startup_network_wake() { # <home> [tenths]
|
|
122
|
+
local home=$1 limit=${2:-50} waited=0
|
|
123
|
+
while ! grep -Fq $'check\tstartup-network' "$home/state/.wake-queue" 2>/dev/null \
|
|
124
|
+
&& [ "$waited" -lt "$limit" ]; do
|
|
125
|
+
sleep 0.1
|
|
126
|
+
waited=$((waited + 1))
|
|
127
|
+
done
|
|
128
|
+
grep -Fq $'check\tstartup-network' "$home/state/.wake-queue" 2>/dev/null
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# --- tests -------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
# `start` is called from inside a session-open hook whose stdout the harness
|
|
134
|
+
# reads to EOF. A worker that inherited that pipe would hold the session open for
|
|
135
|
+
# exactly as long as the network work it was supposed to get off the critical
|
|
136
|
+
# path, so this asserts both halves: start returns fast, AND the pipe closes
|
|
137
|
+
# while the worker is still running.
|
|
138
|
+
test_start_returns_without_holding_the_callers_stdout() {
|
|
139
|
+
local rec home root log started elapsed pending
|
|
140
|
+
rec=$(new_world start-nonblocking)
|
|
141
|
+
IFS='|' read -r home root log <<EOF
|
|
142
|
+
$rec
|
|
143
|
+
EOF
|
|
144
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
145
|
+
|
|
146
|
+
started=$(date +%s)
|
|
147
|
+
# Command substitution reads to EOF, exactly like a hook harvesting hook output.
|
|
148
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=10 \
|
|
149
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$ >/dev/null
|
|
150
|
+
elapsed=$(( $(date +%s) - started ))
|
|
151
|
+
|
|
152
|
+
[ "$elapsed" -lt 4 ] || fail "start blocked for ${elapsed}s behind a 10s worker"
|
|
153
|
+
await_worker_record "$home"
|
|
154
|
+
pending=$(run_stage "$home" "$root" report)
|
|
155
|
+
[ "$(printf '%s\n' "$pending" | head -1)" = "IN PROGRESS - the deferred network checks have not finished yet." ] \
|
|
156
|
+
|| fail "the worker was not actually still running: $pending"
|
|
157
|
+
assert_contains "$pending" "Only a FAILED or otherwise actionable result arrives as a \`check: startup-network\` wake; a clean success stays silent." \
|
|
158
|
+
"the pending guidance still promised a wake for clean success"
|
|
159
|
+
assert_contains "$pending" "$root/bin/fm-startup-network.sh report" \
|
|
160
|
+
"the pending guidance omitted the durable on-demand report path"
|
|
161
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the worker never published"
|
|
162
|
+
assert_grep 'network=only' "$log" "the worker did not run bootstrap's network-only phase"
|
|
163
|
+
pass "fm-startup-network: start returns immediately and never holds the caller's stdout open"
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
test_harvest_acknowledgement_suppresses_the_wake_and_no_claim_produces_it() {
|
|
167
|
+
local rec home root log claimant output waited=0 worker_pid
|
|
168
|
+
rec=$(new_world claim-handshake)
|
|
169
|
+
IFS='|' read -r home root log <<EOF
|
|
170
|
+
$rec
|
|
171
|
+
EOF
|
|
172
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
173
|
+
|
|
174
|
+
sleep 30 &
|
|
175
|
+
claimant=$!
|
|
176
|
+
FM_SESSION_START_TIMEOUT=15 FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_OUT='acknowledged result' \
|
|
177
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid "$claimant"
|
|
178
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the claimed worker never published"
|
|
179
|
+
worker_pid=$(sed -n 's/^pid=//p' "$home/state/.startup-network.status")
|
|
180
|
+
output=$(run_stage "$home" "$root" harvest --pid "$claimant")
|
|
181
|
+
assert_contains "$output" "acknowledged result" \
|
|
182
|
+
"harvest did not print the finished result it acknowledged"
|
|
183
|
+
[ -s "$home/state/.startup-network.delivered" ] \
|
|
184
|
+
|| fail "harvest did not durably acknowledge the result it printed"
|
|
185
|
+
kill "$claimant" 2>/dev/null || true
|
|
186
|
+
wait "$claimant" 2>/dev/null || true
|
|
187
|
+
while kill -0 "$worker_pid" 2>/dev/null && [ "$waited" -lt 50 ]; do
|
|
188
|
+
sleep 0.1
|
|
189
|
+
waited=$((waited + 1))
|
|
190
|
+
done
|
|
191
|
+
! kill -0 "$worker_pid" 2>/dev/null \
|
|
192
|
+
|| fail "the worker did not settle after harvest acknowledged its result"
|
|
193
|
+
[ ! -s "$home/state/.wake-queue" ] \
|
|
194
|
+
|| fail "a result harvest acknowledged also queued a wake: $(cat "$home/state/.wake-queue")"
|
|
195
|
+
|
|
196
|
+
# Harvest releases that claim, so the NEXT publication has nobody to print it.
|
|
197
|
+
# An actionable result (not a clean success) is used here so the assertion
|
|
198
|
+
# stays about the claim mechanism; test_a_successful_result_never_queues_a_wake
|
|
199
|
+
# below owns the separate "a clean success never wakes" contract.
|
|
200
|
+
assert_absent "$home/state/.startup-network.claim" "harvest did not release its own claim"
|
|
201
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_OUT='MISSING: some-tool (install: brew install some-tool)' \
|
|
202
|
+
run_stage "$home" "$root" run --locked 0
|
|
203
|
+
assert_grep 'check startup-network' "$home/state/.wake-queue" \
|
|
204
|
+
"an unclaimed actionable result never reached the wake queue"
|
|
205
|
+
|
|
206
|
+
: > "$home/state/.wake-queue"
|
|
207
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_OUT='MISSING: some-tool (install: brew install some-tool)' \
|
|
208
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid 999999999
|
|
209
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the dead-claim worker never published"
|
|
210
|
+
wait_for_startup_network_wake "$home" || fail "the dead-claim worker never settled delivery"
|
|
211
|
+
assert_grep 'check startup-network' "$home/state/.wake-queue" \
|
|
212
|
+
"a dead session's stale claim swallowed the result"
|
|
213
|
+
assert_absent "$home/state/.startup-network.claim" "a dead claim was not reaped"
|
|
214
|
+
pass "fm-startup-network: exactly one of the digest and the wake reports each actionable result"
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
test_a_claimant_crash_after_publish_still_queues_the_wake() {
|
|
218
|
+
local rec home root log claimant
|
|
219
|
+
rec=$(new_world claimant-crash)
|
|
220
|
+
IFS='|' read -r home root log <<EOF
|
|
221
|
+
$rec
|
|
222
|
+
EOF
|
|
223
|
+
sleep 10 &
|
|
224
|
+
claimant=$!
|
|
225
|
+
# Actionable output: a clean success in this same crash window must stay
|
|
226
|
+
# silent (test_a_successful_result_never_queues_a_wake owns that case).
|
|
227
|
+
FM_SESSION_START_TIMEOUT=4 FM_FAKE_BOOTSTRAP_LOG="$log" \
|
|
228
|
+
FM_FAKE_BOOTSTRAP_OUT='MISSING: some-tool (install: brew install some-tool)' \
|
|
229
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid "$claimant"
|
|
230
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the crash-window worker never published"
|
|
231
|
+
kill -0 "$claimant" 2>/dev/null \
|
|
232
|
+
|| fail "the claimant died before the worker published"
|
|
233
|
+
kill "$claimant" 2>/dev/null || true
|
|
234
|
+
wait "$claimant" 2>/dev/null || true
|
|
235
|
+
wait_for_startup_network_wake "$home" || fail "the crash-window worker never settled delivery"
|
|
236
|
+
assert_grep 'check startup-network' "$home/state/.wake-queue" \
|
|
237
|
+
"a claimant crash after publication silently lost the result"
|
|
238
|
+
assert_absent "$home/state/.startup-network.delivered" \
|
|
239
|
+
"an unharvested result was recorded as delivered"
|
|
240
|
+
pass "fm-startup-network: a claimant crash after publication still surfaces the result"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
test_a_report_publication_failure_is_failed_and_still_wakes() {
|
|
244
|
+
local rec home root log claimant output state
|
|
245
|
+
rec=$(new_world report-publication-failure)
|
|
246
|
+
IFS='|' read -r home root log <<EOF
|
|
247
|
+
$rec
|
|
248
|
+
EOF
|
|
249
|
+
mkdir "$home/state/.startup-network.report"
|
|
250
|
+
chmod 500 "$home/state/.startup-network.report"
|
|
251
|
+
sleep 10 &
|
|
252
|
+
claimant=$!
|
|
253
|
+
|
|
254
|
+
FM_SESSION_START_TIMEOUT=4 FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_OUT='unpublishable result' \
|
|
255
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid "$claimant"
|
|
256
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the report-publication failure never settled"
|
|
257
|
+
state=$(sed -n 's/^state=//p' "$home/state/.startup-network.status")
|
|
258
|
+
[ "$state" = failed ] || fail "a report-publication failure was published as $state"
|
|
259
|
+
|
|
260
|
+
output=$(run_stage "$home" "$root" report)
|
|
261
|
+
assert_contains "$output" "NETWORK_CHECKS: could not publish the deferred check report" \
|
|
262
|
+
"report did not surface the report-publication failure: $output"
|
|
263
|
+
output=$(run_stage "$home" "$root" harvest --pid "$claimant")
|
|
264
|
+
assert_contains "$output" "NETWORK_CHECKS: could not publish the deferred check report" \
|
|
265
|
+
"harvest did not surface the report-publication failure: $output"
|
|
266
|
+
assert_absent "$home/state/.startup-network.delivered" \
|
|
267
|
+
"harvest acknowledged a result whose report was not published"
|
|
268
|
+
wait_for_startup_network_wake "$home" || fail "the report-publication failure suppressed the wake"
|
|
269
|
+
assert_grep 'check startup-network' "$home/state/.wake-queue" \
|
|
270
|
+
"the report-publication failure did not reach the wake queue"
|
|
271
|
+
|
|
272
|
+
kill "$claimant" 2>/dev/null || true
|
|
273
|
+
wait "$claimant" 2>/dev/null || true
|
|
274
|
+
chmod 700 "$home/state/.startup-network.report"
|
|
275
|
+
pass "fm-startup-network: a report-publication failure is failed, diagnosed, and still wakes"
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
# A clean success is not captain-facing progress (AGENTS.md section 8): it must
|
|
279
|
+
# never become a main-blocking wake row, whether or not a session was there to
|
|
280
|
+
# claim and harvest it inline. The result stays durable and readable through
|
|
281
|
+
# `report` either way.
|
|
282
|
+
test_a_successful_result_never_queues_a_wake() {
|
|
283
|
+
local rec home root log claimant report
|
|
284
|
+
rec=$(new_world successful-result-silent)
|
|
285
|
+
IFS='|' read -r home root log <<EOF
|
|
286
|
+
$rec
|
|
287
|
+
EOF
|
|
288
|
+
sleep 10 &
|
|
289
|
+
claimant=$!
|
|
290
|
+
FM_SESSION_START_TIMEOUT=4 FM_FAKE_BOOTSTRAP_LOG="$log" \
|
|
291
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid "$claimant"
|
|
292
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the unclaimed successful worker never published"
|
|
293
|
+
kill "$claimant" 2>/dev/null || true
|
|
294
|
+
wait "$claimant" 2>/dev/null || true
|
|
295
|
+
|
|
296
|
+
# Give the same settling window the crash-window test uses, then confirm no
|
|
297
|
+
# wake ever lands - not a race that just hasn't finished yet.
|
|
298
|
+
sleep 1
|
|
299
|
+
[ ! -s "$home/state/.wake-queue" ] \
|
|
300
|
+
|| fail "a clean successful network-checks result queued a main-blocking wake: $(cat "$home/state/.wake-queue")"
|
|
301
|
+
report=$(run_stage "$home" "$root" report)
|
|
302
|
+
assert_contains "$report" "(silent - no problems found)" \
|
|
303
|
+
"a successful result was not durably readable through report: $report"
|
|
304
|
+
|
|
305
|
+
# Bootstrap itself explicitly types completed benign work as BOOTSTRAP_INFO.
|
|
306
|
+
# That producer-owned no-action record is durable but must remain just as
|
|
307
|
+
# quiet as a fully silent success.
|
|
308
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" \
|
|
309
|
+
FM_FAKE_BOOTSTRAP_OUT='BOOTSTRAP_INFO: fixture completed benign work' \
|
|
310
|
+
run_stage "$home" "$root" run --locked 0
|
|
311
|
+
[ ! -s "$home/state/.wake-queue" ] \
|
|
312
|
+
|| fail "a BOOTSTRAP_INFO-only success queued a main-blocking wake: $(cat "$home/state/.wake-queue")"
|
|
313
|
+
report=$(run_stage "$home" "$root" report)
|
|
314
|
+
assert_contains "$report" "BOOTSTRAP_INFO: fixture completed benign work" \
|
|
315
|
+
"the completed no-action fact was not retained in the durable report"
|
|
316
|
+
|
|
317
|
+
pass "fm-startup-network: silent and explicitly informational successes never queue a main-blocking wake"
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
# The FAILED/actionable half of the same contract, paired with the success
|
|
321
|
+
# test above: an actionable report (here, a MISSING: line bootstrap-diagnostics
|
|
322
|
+
# would load a skill for) still reaches the wake queue even when unclaimed.
|
|
323
|
+
test_an_actionable_successful_result_still_queues_a_wake() {
|
|
324
|
+
local rec home root log claimant
|
|
325
|
+
rec=$(new_world actionable-result-wakes)
|
|
326
|
+
IFS='|' read -r home root log <<EOF
|
|
327
|
+
$rec
|
|
328
|
+
EOF
|
|
329
|
+
sleep 10 &
|
|
330
|
+
claimant=$!
|
|
331
|
+
FM_SESSION_START_TIMEOUT=4 FM_FAKE_BOOTSTRAP_LOG="$log" \
|
|
332
|
+
FM_FAKE_BOOTSTRAP_OUT='MISSING: some-tool (install: brew install some-tool)' \
|
|
333
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid "$claimant"
|
|
334
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the unclaimed actionable worker never published"
|
|
335
|
+
kill "$claimant" 2>/dev/null || true
|
|
336
|
+
wait "$claimant" 2>/dev/null || true
|
|
337
|
+
|
|
338
|
+
wait_for_startup_network_wake "$home" \
|
|
339
|
+
|| fail "an actionable successful (state=done) result never queued a wake"
|
|
340
|
+
assert_grep 'check startup-network' "$home/state/.wake-queue" \
|
|
341
|
+
"an actionable result did not reach the wake queue"
|
|
342
|
+
|
|
343
|
+
pass "fm-startup-network: an actionable state=done report still queues a wake"
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
# The worker outlives the command that launched it. If another session took the
|
|
347
|
+
# lock meanwhile, running the mutating sweeps would sweep underneath that
|
|
348
|
+
# session, so they are refused - and the refusal is reported, not silent.
|
|
349
|
+
test_mutating_sweeps_are_refused_when_the_lock_changed_hands() {
|
|
350
|
+
local rec home root log report
|
|
351
|
+
rec=$(new_world lock-changed)
|
|
352
|
+
IFS='|' read -r home root log <<EOF
|
|
353
|
+
$rec
|
|
354
|
+
EOF
|
|
355
|
+
printf '222222\n' > "$home/state/.lock"
|
|
356
|
+
|
|
357
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" run_stage "$home" "$root" run --locked 1 --lock-pid 111111
|
|
358
|
+
assert_grep 'network=only detect_only=1' "$log" \
|
|
359
|
+
"the worker ran mutating sweeps for a lock it no longer held"
|
|
360
|
+
report=$(run_stage "$home" "$root" report)
|
|
361
|
+
assert_contains "$report" "NETWORK_CHECKS: the fleet lock was no longer held" \
|
|
362
|
+
"the downgrade to a read-only probe was not reported"
|
|
363
|
+
|
|
364
|
+
# A detached start captures the lock itself and may run the mutating phase.
|
|
365
|
+
: > "$log"
|
|
366
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
367
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
368
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the lock-authorized worker never published"
|
|
369
|
+
assert_grep 'network=only detect_only=0' "$log" \
|
|
370
|
+
"the worker refused sweeps for the very session that still holds the lock"
|
|
371
|
+
pass "fm-startup-network: manual callers cannot forge mutation authority"
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
# The unbounded per-call network work is exactly what could wedge a startup. The
|
|
375
|
+
# stage carries one aggregate bound, and hitting it is an actionable line.
|
|
376
|
+
test_the_stage_bound_is_reported_not_swallowed() {
|
|
377
|
+
local rec home root log report
|
|
378
|
+
rec=$(new_world stage-bound)
|
|
379
|
+
IFS='|' read -r home root log <<EOF
|
|
380
|
+
$rec
|
|
381
|
+
EOF
|
|
382
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
383
|
+
|
|
384
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=20 FM_STARTUP_NETWORK_TIMEOUT=2 \
|
|
385
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
386
|
+
run_stage "$home" "$root" harvest --pid $$ >/dev/null
|
|
387
|
+
FM_STARTUP_NETWORK_TIMEOUT=2 run_stage "$home" "$root" wait 10 >/dev/null \
|
|
388
|
+
|| fail "the bounded worker never settled"
|
|
389
|
+
report=$(run_stage "$home" "$root" report)
|
|
390
|
+
assert_contains "$report" "NETWORK_CHECKS: hit the 2s bound before finishing" \
|
|
391
|
+
"a wedged deferred stage was not reported: $report"
|
|
392
|
+
assert_contains "$report" "fm-startup-network.sh run --locked 1" \
|
|
393
|
+
"the timeout line did not say how to rerun the stage"
|
|
394
|
+
wait_for_startup_network_wake "$home" || fail "the timed-out worker never settled delivery"
|
|
395
|
+
assert_grep 'check startup-network' "$home/state/.wake-queue" \
|
|
396
|
+
"a timed-out stage did not surface to the agent"
|
|
397
|
+
pass "fm-startup-network: an aggregate bound turns a wedged sweep into an actionable line"
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
# A worker killed before publication leaves a `running` record behind.
|
|
401
|
+
# That record must read as work to redo, not as work still in flight.
|
|
402
|
+
test_an_abandoned_run_reads_as_needing_a_rerun() {
|
|
403
|
+
local rec home root log report
|
|
404
|
+
rec=$(new_world abandoned)
|
|
405
|
+
IFS='|' read -r home root log <<EOF
|
|
406
|
+
$rec
|
|
407
|
+
EOF
|
|
408
|
+
cat > "$home/state/.startup-network.status" <<EOF
|
|
409
|
+
state=running
|
|
410
|
+
pid=999999999
|
|
411
|
+
started=$(date +%s)
|
|
412
|
+
locked=1
|
|
413
|
+
phases=probe,sweeps
|
|
414
|
+
EOF
|
|
415
|
+
|
|
416
|
+
report=$(run_stage "$home" "$root" report)
|
|
417
|
+
assert_contains "$report" "NETWORK_CHECKS: the deferred check worker stopped before publishing" \
|
|
418
|
+
"an abandoned run still read as in progress: $report"
|
|
419
|
+
assert_contains "$report" "dead-secondmate relaunch" \
|
|
420
|
+
"the abandoned run did not name the checks that never completed"
|
|
421
|
+
|
|
422
|
+
# A record older than the whole aggregate bound is abandoned even when its pid
|
|
423
|
+
# happens to be alive again, so "in progress" can never become permanent.
|
|
424
|
+
cat > "$home/state/.startup-network.status" <<EOF
|
|
425
|
+
state=running
|
|
426
|
+
pid=$$
|
|
427
|
+
started=$(( $(date +%s) - 400 ))
|
|
428
|
+
locked=1
|
|
429
|
+
phases=probe,sweeps
|
|
430
|
+
EOF
|
|
431
|
+
assert_contains "$(FM_STARTUP_NETWORK_TIMEOUT=10 run_stage "$home" "$root" report)" \
|
|
432
|
+
"NETWORK_CHECKS: the deferred check worker stopped before publishing" \
|
|
433
|
+
"a record that outlived the stage bound still read as in progress"
|
|
434
|
+
pass "fm-startup-network: an abandoned run reports as needing a rerun, never as in progress forever"
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
# Two session opens in quick succession must not run the same mutating sweeps
|
|
438
|
+
# concurrently against each other.
|
|
439
|
+
test_start_is_single_flight() {
|
|
440
|
+
local rec home root log runs
|
|
441
|
+
rec=$(new_world single-flight)
|
|
442
|
+
IFS='|' read -r home root log <<EOF
|
|
443
|
+
$rec
|
|
444
|
+
EOF
|
|
445
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
446
|
+
|
|
447
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=6 \
|
|
448
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
449
|
+
await_worker_record "$home"
|
|
450
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=6 \
|
|
451
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
452
|
+
run_stage "$home" "$root" wait 40 >/dev/null || fail "the worker never published"
|
|
453
|
+
|
|
454
|
+
runs=$(grep -c 'network=only' "$log" || true)
|
|
455
|
+
[ "$runs" -eq 1 ] || fail "a second start launched a competing worker ($runs runs): $(cat "$log")"
|
|
456
|
+
pass "fm-startup-network: a second start never launches a competing worker"
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
test_start_reserves_its_generation_before_returning() {
|
|
460
|
+
local rec home root log report
|
|
461
|
+
rec=$(new_world generation-reservation)
|
|
462
|
+
IFS='|' read -r home root log <<EOF
|
|
463
|
+
$rec
|
|
464
|
+
EOF
|
|
465
|
+
cat > "$home/state/.startup-network.status" <<EOF
|
|
466
|
+
state=done
|
|
467
|
+
pid=999999999
|
|
468
|
+
started=1
|
|
469
|
+
finished=2
|
|
470
|
+
rc=0
|
|
471
|
+
locked=0
|
|
472
|
+
phases=probe
|
|
473
|
+
generation=old
|
|
474
|
+
lock_pid=
|
|
475
|
+
EOF
|
|
476
|
+
printf 'old result\n' > "$home/state/.startup-network.report"
|
|
477
|
+
|
|
478
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=5 \
|
|
479
|
+
run_stage "$home" "$root" start --locked 0 --harvest-pid $$
|
|
480
|
+
report=$(run_stage "$home" "$root" harvest --pid $$)
|
|
481
|
+
assert_contains "$report" "IN PROGRESS" \
|
|
482
|
+
"harvest exposed the previous generation after a new start returned: $report"
|
|
483
|
+
assert_not_contains "$report" "old result" \
|
|
484
|
+
"harvest printed a stale generation's report"
|
|
485
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the reserved generation never published"
|
|
486
|
+
pass "fm-startup-network: start atomically reserves the generation harvest observes"
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
test_new_lock_owner_does_not_reuse_the_previous_owners_worker() {
|
|
490
|
+
local rec home root log generation_one generation_two next_owner
|
|
491
|
+
rec=$(new_world owner-handoff)
|
|
492
|
+
IFS='|' read -r home root log <<EOF
|
|
493
|
+
$rec
|
|
494
|
+
EOF
|
|
495
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
496
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=6 \
|
|
497
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
498
|
+
generation_one=$(sed -n 's/^generation=//p' "$home/state/.startup-network.status")
|
|
499
|
+
|
|
500
|
+
next_owner=$(/bin/ps -o ppid= -p $$ | tr -d ' ')
|
|
501
|
+
printf '%s\n' "$next_owner" > "$home/state/.lock"
|
|
502
|
+
FM_FAKE_HARNESS_PID_OVERRIDE="$next_owner" FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=1 \
|
|
503
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
504
|
+
generation_two=$(sed -n 's/^generation=//p' "$home/state/.startup-network.status")
|
|
505
|
+
[ "$generation_one" != "$generation_two" ] \
|
|
506
|
+
|| fail "the new lock owner reused the previous owner's generation"
|
|
507
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the new owner's generation never published"
|
|
508
|
+
pass "fm-startup-network: a new lock owner gets a distinct worker generation"
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
test_lock_takeover_stays_read_only_while_a_sweep_holds_the_lease() {
|
|
512
|
+
local rec home root log next_owner new_owner out rc started elapsed waited=0
|
|
513
|
+
rec=$(new_world sweep-lease)
|
|
514
|
+
IFS='|' read -r home root log <<EOF
|
|
515
|
+
$rec
|
|
516
|
+
EOF
|
|
517
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
518
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=6 \
|
|
519
|
+
run_stage "$home" "$root" start --locked 1 --harvest-pid $$
|
|
520
|
+
while [ ! -s "$log" ] && [ "$waited" -lt 50 ]; do
|
|
521
|
+
sleep 0.1
|
|
522
|
+
waited=$((waited + 1))
|
|
523
|
+
done
|
|
524
|
+
[ -s "$log" ] || fail "the mutating sweep never started"
|
|
525
|
+
|
|
526
|
+
next_owner=$(/bin/ps -o ppid= -p $$ | tr -d ' ')
|
|
527
|
+
started=$(date +%s)
|
|
528
|
+
rc=0
|
|
529
|
+
out=$(PATH="$root/bin:$PATH" FM_FAKE_HARNESS_PID="$next_owner" \
|
|
530
|
+
FM_HOME="$home" FM_ROOT_OVERRIDE="$root" "$root/bin/fm-lock.sh" 2>&1) || rc=$?
|
|
531
|
+
elapsed=$(( $(date +%s) - started ))
|
|
532
|
+
[ "$rc" -ne 0 ] || fail "lock takeover succeeded while the prior sweep was mutating"
|
|
533
|
+
[ "$elapsed" -lt 4 ] || fail "lock takeover blocked ${elapsed}s behind deferred network work"
|
|
534
|
+
assert_contains "$out" "operate read-only" \
|
|
535
|
+
"a lease-blocked takeover did not fail closed to read-only: $out"
|
|
536
|
+
[ "$(cat "$home/state/.lock")" = "$$" ] \
|
|
537
|
+
|| fail "the lease-blocked takeover replaced the prior owner"
|
|
538
|
+
|
|
539
|
+
run_stage "$home" "$root" wait 30 >/dev/null || fail "the leased sweep never settled"
|
|
540
|
+
out=$(PATH="$root/bin:$PATH" FM_FAKE_HARNESS_PID="$next_owner" \
|
|
541
|
+
FM_HOME="$home" FM_ROOT_OVERRIDE="$root" "$root/bin/fm-lock.sh" 2>&1) \
|
|
542
|
+
|| fail "lock takeover still failed after the sweep released its lease"
|
|
543
|
+
new_owner=$(cat "$home/state/.lock")
|
|
544
|
+
assert_contains "$out" "lock acquired: harness pid $new_owner" \
|
|
545
|
+
"the fleet lock did not record the harness owner reported by acquisition"
|
|
546
|
+
[ "$new_owner" != "$$" ] || fail "the prior harness still owned the lock after takeover"
|
|
547
|
+
pass "fm-startup-network: fleet-lock takeover cannot overlap a mutating sweep"
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
# Every record carries a start offset from ONE origin, so the artifact reads as a
|
|
551
|
+
# timeline and not just a bag of durations. The origin is normally exported by the
|
|
552
|
+
# stage, but a process that starts recording without one has to adopt an origin
|
|
553
|
+
# and KEEP it: recomputing it per record would silently flatten every offset to
|
|
554
|
+
# zero and lose the ordering the artifact exists to show. Driven with explicit
|
|
555
|
+
# start stamps so the assertion does not depend on the host clock's resolution.
|
|
556
|
+
test_records_share_one_origin_so_offsets_form_a_timeline() {
|
|
557
|
+
local dir log offsets count second third
|
|
558
|
+
dir="$TMP_ROOT/timing-origin"
|
|
559
|
+
mkdir -p "$dir"
|
|
560
|
+
log="$dir/timings.tsv"
|
|
561
|
+
|
|
562
|
+
(
|
|
563
|
+
# shellcheck source=bin/fm-timing-lib.sh
|
|
564
|
+
. "$ROOT/bin/fm-timing-lib.sh"
|
|
565
|
+
unset FM_TIMING_EPOCH_MS
|
|
566
|
+
FM_TIMING_LOG=$log
|
|
567
|
+
export FM_TIMING_LOG
|
|
568
|
+
base=$(fm_timing_now_ms)
|
|
569
|
+
fm_timing_record phase first "$base"
|
|
570
|
+
fm_timing_record phase second "$(( base + 5000 ))"
|
|
571
|
+
fm_timing_record phase third "$(( base + 9000 ))"
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
# The origin lands within the first record, so that record's own offset rounds
|
|
575
|
+
# to zero; what proves the origin was KEPT is that the later records are spaced
|
|
576
|
+
# by exactly the interval they were given. Recomputing the origin per record
|
|
577
|
+
# would report every one of them as zero.
|
|
578
|
+
offsets=$(awk -F'\t' '$1 == "v1" { print $4 }' "$log")
|
|
579
|
+
count=$(printf '%s\n' "$offsets" | grep -c .)
|
|
580
|
+
second=$(printf '%s\n' "$offsets" | sed -n 2p)
|
|
581
|
+
third=$(printf '%s\n' "$offsets" | sed -n 3p)
|
|
582
|
+
[ "$count" -eq 3 ] || fail "expected three records, got: $offsets"
|
|
583
|
+
[ "$second" -gt 0 ] && [ "$third" -gt "$second" ] \
|
|
584
|
+
|| fail "records did not share one origin - offsets were: $offsets"
|
|
585
|
+
[ "$(( third - second ))" -eq 4000 ] \
|
|
586
|
+
|| fail "offsets did not preserve the interval between records: $offsets"
|
|
587
|
+
pass "fm-startup-network: timing records share one origin so their offsets form a timeline"
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
# The whole point of the artifact is that it is FREE until someone asks for it.
|
|
591
|
+
# `harvest` is what composes a session start's NETWORK CHECKS section, so a
|
|
592
|
+
# timing line leaking into it would be a change to every startup's output; only
|
|
593
|
+
# the on-demand `report` may print them.
|
|
594
|
+
test_timings_are_published_and_only_the_on_demand_report_prints_them() {
|
|
595
|
+
local rec home root log report_out harvest_out
|
|
596
|
+
rec=$(new_world timings-published)
|
|
597
|
+
IFS='|' read -r home root log <<EOF
|
|
598
|
+
$rec
|
|
599
|
+
EOF
|
|
600
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
601
|
+
|
|
602
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_OUT='sweep finding' \
|
|
603
|
+
FM_FAKE_TIMING_PHASE=fleet-sync FM_FAKE_TIMING_DETAIL=dotfiles-private \
|
|
604
|
+
run_stage "$home" "$root" run --locked 1
|
|
605
|
+
|
|
606
|
+
assert_present "$home/state/.startup-network.timings" \
|
|
607
|
+
"a finished run published no timing record"
|
|
608
|
+
assert_grep 'fleet-sync' "$home/state/.startup-network.timings" \
|
|
609
|
+
"the stage did not publish what the sweep recorded"
|
|
610
|
+
assert_grep 'stage network-checks' "$home/state/.startup-network.timings" \
|
|
611
|
+
"the stage did not record its own bounded total"
|
|
612
|
+
|
|
613
|
+
report_out=$(run_stage "$home" "$root" report)
|
|
614
|
+
assert_contains "$report_out" "sweep finding" "report stopped printing the sweep result"
|
|
615
|
+
assert_contains "$report_out" "TIMINGS" "report did not print the per-step timings"
|
|
616
|
+
assert_contains "$report_out" "fleet-sync dotfiles-private" \
|
|
617
|
+
"report did not attribute the elapsed time to the clone that spent it"
|
|
618
|
+
assert_contains "$report_out" "slowest:" "report did not surface the slowest steps"
|
|
619
|
+
|
|
620
|
+
harvest_out=$(run_stage "$home" "$root" harvest --pid $$)
|
|
621
|
+
assert_contains "$harvest_out" "sweep finding" "harvest stopped printing the sweep result"
|
|
622
|
+
assert_not_contains "$harvest_out" "TIMINGS" \
|
|
623
|
+
"the timings leaked into the session-start digest section"
|
|
624
|
+
assert_not_contains "$harvest_out" "slowest:" \
|
|
625
|
+
"the timings leaked into the session-start digest section"
|
|
626
|
+
pass "fm-startup-network: timings are durable and printed only on demand"
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
# A run that hit the bound is exactly the run worth attributing, so whatever the
|
|
630
|
+
# killed sweeps managed to record must survive rather than being discarded with
|
|
631
|
+
# them.
|
|
632
|
+
test_a_bounded_run_still_publishes_the_timings_it_managed_to_record() {
|
|
633
|
+
local rec home root log report_out
|
|
634
|
+
rec=$(new_world timings-partial)
|
|
635
|
+
IFS='|' read -r home root log <<EOF
|
|
636
|
+
$rec
|
|
637
|
+
EOF
|
|
638
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
639
|
+
|
|
640
|
+
FM_STARTUP_NETWORK_TIMEOUT=1 FM_SESSION_START_TIMEOUT=2 \
|
|
641
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_BOOTSTRAP_SLEEP=20 \
|
|
642
|
+
FM_FAKE_TIMING_PHASE=secondmate-liveness FM_FAKE_TIMING_DETAIL='mate-a@host-one' \
|
|
643
|
+
run_stage "$home" "$root" run --locked 1
|
|
644
|
+
|
|
645
|
+
[ "$(sed -n 's/^state=//p' "$home/state/.startup-network.status")" = timeout ] \
|
|
646
|
+
|| fail "the bounded run did not record itself as timed out"
|
|
647
|
+
report_out=$(run_stage "$home" "$root" report)
|
|
648
|
+
assert_contains "$report_out" "hit the 1s bound" "the bound stopped being reported"
|
|
649
|
+
assert_contains "$report_out" "secondmate-liveness mate-a@host-one" \
|
|
650
|
+
"a timed-out run discarded the partial timings its sweeps had already recorded"
|
|
651
|
+
pass "fm-startup-network: a timed-out run still publishes the partial timings it recorded"
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
# The artifact is read by a human looking at a slow startup, so it must be
|
|
655
|
+
# incapable of carrying an argv or a credential out of a sweep, and incapable of
|
|
656
|
+
# being broken by one either: a detail with tabs or newlines would otherwise
|
|
657
|
+
# forge extra records.
|
|
658
|
+
test_the_timing_artifact_cannot_carry_a_command_line_or_forge_records() {
|
|
659
|
+
local rec home root log lines report_out
|
|
660
|
+
rec=$(new_world timings-sanitized)
|
|
661
|
+
IFS='|' read -r home root log <<EOF
|
|
662
|
+
$rec
|
|
663
|
+
EOF
|
|
664
|
+
printf '%s\n' $$ > "$home/state/.lock"
|
|
665
|
+
|
|
666
|
+
FM_FAKE_BOOTSTRAP_LOG="$log" FM_FAKE_TIMING_PHASE=secondmate-sync \
|
|
667
|
+
FM_FAKE_TIMING_DETAIL="ssh -i /key host v1 forged 0 9999
|
|
668
|
+
GITHUB_TOKEN=ghp_supersecretvalue" \
|
|
669
|
+
run_stage "$home" "$root" run --locked 1
|
|
670
|
+
|
|
671
|
+
assert_no_grep 'ghp_supersecretvalue' "$home/state/.startup-network.timings" \
|
|
672
|
+
"the timing artifact carried a credential-shaped value through"
|
|
673
|
+
assert_no_grep 'forged' "$home/state/.startup-network.timings" \
|
|
674
|
+
"a detail containing tabs forged an extra timing record"
|
|
675
|
+
assert_no_grep 'ssh' "$home/state/.startup-network.timings" \
|
|
676
|
+
"the timing artifact carried a command line through"
|
|
677
|
+
assert_grep 'unrecordable' "$home/state/.startup-network.timings" \
|
|
678
|
+
"free text was silently dropped instead of being marked unrecordable"
|
|
679
|
+
lines=$(grep -c . "$home/state/.startup-network.timings")
|
|
680
|
+
[ "$lines" -eq 2 ] \
|
|
681
|
+
|| fail "one sweep record plus the stage total should be 2 lines, got $lines"
|
|
682
|
+
|
|
683
|
+
# The step itself is still measured - only its untrustworthy label is refused,
|
|
684
|
+
# so a sweep that mislabels itself still shows up as time spent.
|
|
685
|
+
assert_grep 'secondmate-sync' "$home/state/.startup-network.timings" \
|
|
686
|
+
"refusing the label also discarded the measurement"
|
|
687
|
+
|
|
688
|
+
report_out=$(run_stage "$home" "$root" report)
|
|
689
|
+
assert_not_contains "$report_out" "ghp_supersecretvalue" \
|
|
690
|
+
"the rendered report printed a credential-shaped value"
|
|
691
|
+
pass "fm-startup-network: the timing artifact cannot carry a command line or forge records"
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
test_wait_fails_without_a_published_stage
|
|
695
|
+
test_start_returns_without_holding_the_callers_stdout
|
|
696
|
+
test_harvest_acknowledgement_suppresses_the_wake_and_no_claim_produces_it
|
|
697
|
+
test_a_claimant_crash_after_publish_still_queues_the_wake
|
|
698
|
+
test_a_report_publication_failure_is_failed_and_still_wakes
|
|
699
|
+
test_a_successful_result_never_queues_a_wake
|
|
700
|
+
test_an_actionable_successful_result_still_queues_a_wake
|
|
701
|
+
test_mutating_sweeps_are_refused_when_the_lock_changed_hands
|
|
702
|
+
test_the_stage_bound_is_reported_not_swallowed
|
|
703
|
+
test_an_abandoned_run_reads_as_needing_a_rerun
|
|
704
|
+
test_start_is_single_flight
|
|
705
|
+
test_start_reserves_its_generation_before_returning
|
|
706
|
+
test_new_lock_owner_does_not_reuse_the_previous_owners_worker
|
|
707
|
+
test_lock_takeover_stays_read_only_while_a_sweep_holds_the_lease
|
|
708
|
+
test_records_share_one_origin_so_offsets_form_a_timeline
|
|
709
|
+
test_timings_are_published_and_only_the_on_demand_report_prints_them
|
|
710
|
+
test_a_bounded_run_still_publishes_the_timings_it_managed_to_record
|
|
711
|
+
test_the_timing_artifact_cannot_carry_a_command_line_or_forge_records
|
|
712
|
+
echo "# fm-startup-network.test.sh: all assertions passed"
|