Skip to content

Can render an executable - #329

Merged
myobie merged 2 commits into
mainfrom
agent/deterministic-render-modes
Aug 24, 2026
Merged

Can render an executable#329
myobie merged 2 commits into
mainfrom
agent/deterministic-render-modes

Conversation

@myobie

@myobie myobie commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

What changed

  • Add executable=#true to copy, file, json-upsert, and ensure-line.
  • Support executable inline file content in positional and child content forms.
  • Apply exact mode 0755 when true and exact mode 0644 when false or absent.
  • Repair mode drift when the file bytes already match.
  • Omit unchanged targets from the materialization report.
  • Include the executable value in shared-workspace ownership claims and catalog semantic diffs.
  • Refuse a mode-only change to a Git-tracked target before any workspace mutation.
  • Reject unknown and non-boolean render properties.

Why

Render copied only bytes and used fs::write. A new destination used umask-dependent permissions. An existing destination retained its prior mode. The same declaration therefore produced different results from different local history.

A rendered command wrapper could silently remain non-executable. A PATH lookup could then run another command and leave an audit log quiet.

User impact

Catalog authors can declare an executable copy:

render {
  copy "_templates/gh" ".st2/bin/gh" executable=#true
}

They can also declare an executable inline file:

render {
  file ".st2/bin/probe" executable=#true {
    content #"""
#!/bin/sh
printf 'ready\n'

"""#
  }
}

The blank line before the raw-string delimiter encodes the script's final newline. The copy source mode does not affect the destination.

Proof

The red test commit is fea6ff2. Its exact inline-script regression fails before the implementation with mode 0664 instead of 0755.

The implementation proves exact bytes, the final newline, script execution, empty content, raw quote sequences, idempotency, and no unchanged-target report. It also proves the true -> false -> true mode sequence.

Focused checks pass:

  • cargo test --test materialize — 26 passed.
  • cargo test --test validate — 44 passed.
  • The executable catalog-diff regression passes.
  • Scoped strict Clippy passes for the changed library and test targets.
  • cargo fmt --all -- --check passes.
  • git diff --check origin/main...HEAD passes.
  • cargo build --release --locked passes.
  • Hosted nix flake check --print-build-logs passes at 229f55b.

A real st2 up --materialize-only --agent proof reports one operation, creates mode 0755, and runs the script. Its second run reports zero operations.

The full workspace run reaches a known current-main failure in incomplete_apply_marker_blocks_declarations_but_not_the_state_plane. The same exact test fails on origin/main. The existing catalog-diff classification test also fails on both states. Strict all-target Clippy has the same nine library failures on origin/main.

This PR stays draft under the st2 merge freeze.

@myobie
myobie force-pushed the agent/deterministic-render-modes branch 2 times, most recently from 1e03721 to 229f55b Compare August 23, 2026 20:46
@myobie
myobie marked this pull request as ready for review August 23, 2026 21:09
@myobie
myobie marked this pull request as draft August 23, 2026 21:11
@myobie myobie changed the title Make render file modes deterministic Can render an executable Aug 23, 2026
@myobie
myobie marked this pull request as ready for review August 23, 2026 22:01
@myobie
myobie force-pushed the agent/deterministic-render-modes branch from 229f55b to 856985e Compare August 24, 2026 21:34
@myobie
myobie merged commit 33c7505 into main Aug 24, 2026
1 check passed
@myobie
myobie deleted the agent/deterministic-render-modes branch August 24, 2026 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant