Skip to content

stamp_installed is unreachable when a project defines its own up: — provisioning commands need spawn-and-wait, not exec #85

Description

@JPDuchesne

Runner#run sequences the installed stamp after the command:

cmd.execute(args:, context:)                          # runner.rb:78
stamp_installed(cmd_name, context.project_root)       # runner.rb:79

But project run: commands exec-replace the dev process (CommandRunner#run_in_container at command_runner.rb:101, #run_replace_process at :240, #run_exec_with_status at :248), so line 79 only ever runs for fully in-process builtins. In a repo whose dev.yml defines its own up:, dev up execs into the project command and never stamps — the staleness gate then reports "never installed" forever, which is fatal under CI=true. Hit live in the dev#73 build pass; captured on dev#84 as the command-runner-exec learning.

The wrong fix

Stamping before cmd.execute (what the initial capture recommended) breaks the stamp's semantics: stamp_installed's contract is "record the stamp after a fully-successful provisioning command" (runner.rb:117–120). A failed dev up would look installed and the staleness guard would go quiet exactly when it should be loud.

The fix

When the resolved command needs post-execute work (the stamping commands: up, install-deps) and it is an exec-style project command, run it spawn-and-wait instead of exec-replace:

  • CommandRunner gains a wait mode — Kernel.system(child_env, "shadowenv", "exec", "--", "sh", "-c", shell_command) (and the docker equivalent for containerized commands) with the child's exit status propagated — selected by the caller when post-steps exist.
  • Runner#run stamps only on success, then exits with the child's status, preserving today's exit-code behavior.
  • Generic run: commands keep the exec tail-call: it's the right shape for a leaf command (TTY/signal passthrough, no double process tree), and nothing sequences after them.

The command-runner-exec skill on dev#84 states the underlying invariant (must-happen work can't be sequenced after a maybe-exec point) and points here for the fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions