Skip to content

fix: honor node-level mode: read on mode-overridable exec nodes (#165)#168

Merged
pawellisowski merged 3 commits into
mainfrom
fix/165-exec-mode-overridable
May 27, 2026
Merged

fix: honor node-level mode: read on mode-overridable exec nodes (#165)#168
pawellisowski merged 3 commits into
mainfrom
fix/165-exec-mode-overridable

Conversation

@pawellisowski
Copy link
Copy Markdown
Contributor

Summary

Fixes #165. A read-only tekla/exec node declaring mode: read was refused at install with E_APP_WRITE_WITHOUT_SAFETY (and, if it compiled, the lock recorded mode: write with no signal the declaration was dropped). The earlier #166 fix only handled the branch where a command is absent from the agent manifest — but the tekla manifest now declares exec with a conservative mode: write, so every consumer hit the "command found" path that resolved mode solely from the manifest and ignored the author's node-level mode:.

The fix (issue's preferred option 1)

  • New per-command manifest flag mode-overridable: true for commands whose read/write behavior is caller-determined — they run caller-supplied logic the agent can't inspect (e.g. exec runs an arbitrary C# script). The manifest mode: becomes a conservative default; an explicit node-level mode: wins.
  • Agent::effective_mode — a single shared resolver, now the one source of truth used by validate, lock-compile, dry-run/simulate, and explain. These had drifted apart, which is what let the bug hide.
  • E_APP_NODE_MODE_NOT_OVERRIDABLE — a node-level mode: that conflicts with a non-overridable command is now rejected loudly (on every agent-aware path: install, compile, inspect, validate, run, dry-run; recurses into for-each/sweep bodies) instead of being silently dropped. Closes the footgun in both directions.
  • tekla exec marked mode-overridable (keeps mode: write default, so un-annotated exec nodes still fall under the safety contract).
  • app-spec.md documents the semantics; version bumped 0.46.0 → 0.47.0.

Behavior after the fix

Node on exec (mode-overridable) Effective mode Safety block?
mode: read read not required
mode: write write required
(no mode:) write (conservative default) required

A mode: read on a genuinely-writing, non-overridable command (e.g. uda-set) → hard validation error.

Review

  • Codex reviewed across 3 rounds (codex exec review --base main); it caught two real consistency gaps (dry-run/explain consumers, and the conflict check being skipped by compile/inspect/dry-run) — both fixed in follow-up commits. Final round: clean, no findings.

Test plan

  • cargo test — 502 passed, 0 failed (incl. new unit tests for compile, validate-conflict + nested body, dry-run override, write default)
  • End-to-end: read-only exec app installs without a safety: block and compiles to mode: read with note "command exec is mode-overridable; using author-declared mode: read"
  • End-to-end: aware app compile refuses a mode: read declared on uda-set (non-overridable write) with E_APP_NODE_MODE_NOT_OVERRIDABLE

Closes #165.

)

The #166 fix only covered the branch where a command is absent from the
agent manifest. But the tekla manifest now declares `exec` with a
conservative `mode: write`, so both `validate_app_safety` and
`compile_node` hit the "command found" path — which resolved mode solely
from the manifest via `mode_of` and ignored the author's node-level
`mode:` entirely. Result on aware 0.46.0: a read-only `tekla/exec` node
declaring `mode: read` was refused at install with
E_APP_WRITE_WITHOUT_SAFETY, and (if it compiled) the lock recorded
`mode: write` with no signal that the declaration was dropped — exactly
the footgun the issue flags, now escalated to a hard install failure.

Fix (issue's preferred option 1): introduce a per-command manifest flag
`mode-overridable: true` for commands whose read/write behavior is
caller-determined (they run caller-supplied logic the agent can't
inspect — `exec`). For such a command the manifest `mode:` is a
conservative default, but an explicit node-level `mode:` wins. A new
`Agent::effective_mode` resolver is the single source of truth shared by
validate + compile (they previously drifted, which is what let the bug
hide). For every other command the manifest mode stays authoritative,
and a *conflicting* node-level `mode:` is now rejected loudly
(E_APP_NODE_MODE_NOT_OVERRIDABLE) instead of being silently dropped — so
the authoring field is never quietly ignored in either direction.

- agent.rs: Command.mode_overridable, Agent::effective_mode, Mode::as_str
- validate.rs: effective-mode gate + conflict rejection
- app_lock.rs: effective-mode resolution + accurate override note
  (no more "defaulting to write-mode for safety" on a declared read)
- tekla manifest: exec marked mode-overridable (keeps mode: write default)
- app-spec.md: document node-level mode + mode-overridable semantics
- bump 0.46.0 -> 0.47.0

Verified end-to-end: read-only exec app installs without a safety: block
and compiles to `mode: read`. 6 new tests; full suite green.
)

Codex review caught that the effective-mode resolution was applied in
validate + compile but two other mode consumers still called `mode_of`
directly, so a read-only `tekla/exec` node declaring `mode: read` was
inconsistent across surfaces:

- runtime::orchestrator::lookup_command_mode (--dry-run / --simulate)
  treated the manifest-declared `exec` as write and short-circuited it as
  `would-write` instead of running the read-only probe.
- `aware app explain` / glass-box listed the same node under writes.

Both now route through `Agent::effective_mode(cmd, node.mode)`, so an
explicit node-level `mode:` wins on mode-overridable commands everywhere
the lock + validator already honor it. Adds a dry-run test for the
command-present mode-overridable path.
Codex review (round 2): the E_APP_NODE_MODE_NOT_OVERRIDABLE conflict check
lived only in `validate_app_safety`, which `aware app compile`/`inspect`
and `app run --dry-run` skip — so those paths still silently ignored a
`mode: read` declared on a non-overridable write command, preserving the
exact footgun for the issue's own repro command (`app compile`).

Move the check into `validate_app_agents`, the agent-aware validator that
runs on every lock-producing + run path (install, compile, inspect,
validate, run, dry-run) and recurses into for-each/sweep `do:` bodies.
`validate_app_safety` now only resolves the effective mode for the
write-without-safety gate. Tests repointed + added (nested-body coverage);
verified end-to-end that `aware app compile` refuses the conflict.
@pawellisowski pawellisowski merged commit 1019fab into main May 27, 2026
@pawellisowski pawellisowski deleted the fix/165-exec-mode-overridable branch May 27, 2026 15:15
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.

Node-level mode: read on an exec node is silently overridden to write-mode at compile (no warning)

1 participant