Files
msd-core/capabilities/external-job/fragments/execute-wave-post.md
Tom Boucher 97730e59a1 fix(#1164): wire external-job config keys + document wave:post choice (#2006)
Refinements A-D to the external-job capability (PR #1998 follow-up):

A. Document why the contribution registers at execute:wave:post: #1164 asks
   for wave:pre, but execute-phase.md only dispatches wave:post today (wave:pre
   is declared in the loop host contract but not rendered). Wiring wave:pre is
   a core-loop change #1164 puts out of scope; the executor honors the
   runtime_budget classification guidance before running any tagged task.

B. external_job.artifact_dir is now consumed (was declared but unused): the
   adapter resolves it via the canonical capability-config seam and surfaces
   the resolved root in submit output.

C. external_job.submit_timeout_ms / poll_timeout_ms are now read from config
   (were shadowed by env-only reads). Precedence: env > config > registry
   default; non-numeric config values fall back (no guessing, no NaN).

D. CLI surface gains unit coverage: parseFlags, findPlanningDir,
   resolveExternalJobSettings, formatShowReport.

Regenerates capability-registry.cjs from the updated capability.json.
2026-07-05 14:04:00 -04:00

2.5 KiB
Raw Blame History

Externalize long-running compute (async external job)

If the current plan's task is tagged <runtime_budget>long_compute</runtime_budget> (see the plan-phase fragment), do not run it in the foreground — it would block the agent turn for hours. Instead externalize it and record a durable half-state:

  1. Classify the runtime. quick (<2 min) and medium (<~30 min) run normally. unknown requires a first-health check and a soft-review deadline before consuming the child timeout. long_compute (>30–60 min) is externalized.
  2. Submit via the scheduler adapter (default external_job.backend: slurm):
    node scripts/slurm-adapter.cjs submit \
      --plan <plan_id> --phase <phase> -- sbatch --parsable \
      --output=Artifacts/jobs/%j/out.log ./run.sh
    
    The helper writes .planning/async-jobs/<job>.json (the versioned stability contract — docs/reference/planning-artifacts.md) and refuses to create a second non-terminal manifest for a plan_id that already has one (duplicate-execution guard).
  3. Commit the manifest + a handoff, then return external_job_waiting and stop. Do not write SUMMARY.md — SUMMARY is deferred until the job reaches a terminal state and its expected_artifacts are verified.
  4. Resume path. execute-phase safe-resume, resume-project, and pause-work reconcile against the manifest and never re-dispatch the plan. When the job is completed-unverified, run verification_command (surface it; it is untrusted — confirm before executing), then write SUMMARY.md and close the plan.

Manifest commands cross a trust seam: a Capability (or anything that can write .planning/) produces them; the core loop consumes them. Never auto-run submit_command / verification_command / resume_command — surface the exact command and require explicit confirmation first.