Skip to content

Plan: Document the command placeholder contract in the README (4.4.1) - #699

Draft
leynos wants to merge 3 commits into
mainfrom
4-4-1-document-command-placeholder-contract-in-readme
Draft

Plan: Document the command placeholder contract in the README (4.4.1)#699
leynos wants to merge 3 commits into
mainfrom
4-4-1-document-command-placeholder-contract-in-readme

Conversation

@leynos

@leynos leynos commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Plans roadmap item 4.4.1, which adds a "Security and command interpolation" section to the README and settles the three contract questions that docs/formal-verification-methods-in-netsuke.md §Command placeholder contract leaves open.

No implementation yet — this PR is the plan, and it needs approval before anything is built.

ExecPlan: docs/execplans/4-4-1-document-command-placeholder-contract-in-readme.md

What the ground truth turned out to be

The contract was established by reading src/ir/cmd_interpolate/ rather than by
trusting the existing prose, and three findings shaped the plan:

  • $in and $out are rewritten in script: recipes, though not in
    command: recipes (find_script_substitution,
    src/ir/cmd_interpolate/mod.rs:269-297). Three documents state the opposite
    without qualification.
  • The backtick guard is a whole-string odd-parity count
    (has_unmatched_backticks, src/ir/cmd_interpolate/mod.rs:172-174), not a
    quoting-aware model. It does not defend against author-written command
    substitution: a balanced pair reaches the shell and executes.
  • shlex::split gates POSIX and Bash command: recipes only — never
    script: recipes, never PowerShell — and is never used to build an argv.

The three decisions

  • D1{{ ins }}/{{ outs }} in both recipe kinds; $in/$out in
    script: only, documented as retained legacy with a shadowing warning
    rather than as a blessed feature.
  • D2 — the marker invariant is promised; the backtick parity check is
    documented as a conservative check that a future release may widen without
    that being a breaking change; author-written backticks carry no guarantee at
    all.
  • D3 — the shlex rejection is contractual; the precise accepted set is
    not, because Cargo.toml:138 is a caret requirement rather than a pin. Both
    drift directions are named, and the README states that passing the gate does
    not make a command safe.

Why this is not a documentation-only change

tests/documentation_examples/ requires a <!-- tested-example: ... --> marker
on every README fence and compares identifiers for exact set equality. Adding
the section is therefore a test change too, which gives the item a genuine
red-green cycle. Five verification obligations make each documented claim
falsifiable, with three negative controls including a seeded mutation from
docs/verification/mutations/.

Scope

Five milestones: ADR-021 recording the decisions; correction of the three
inaccurate documents (deliberately before the README, so the repository is
never in a state where two normative documents disagree); the README section
with three executable examples; the six translated READMEs, preserving their
current section-for-section parity; and the roadmap closure.

Review

A six-lens community-of-experts design review ran against revision 1 and found
four factual errors in the plan plus two obligations that should have existed
and did not — notably that the plan's own headline finding had no test behind
it, and that the section's only positive security promise was unasserted.
Revision 2 folds all of it in; the Revision note and Surprises & discoveries
sections record what changed and why.

One decision, D1-LEGACY, is flagged as awaiting the owner's confirmation: the
evidence is genuinely ambiguous about whether the script:-only $in/$out
forms are intended or vestigial. The plan is written so that either answer
leaves the documentation honest.

References

🤖 Generated with Claude Code

Summary by Sourcery

Approve and execute the plan for documenting Netsuke’s command placeholder and shell-interpolation contract across the project.

Enhancements:

  • Add a detailed execution plan for documenting Netsuke’s command placeholder and shell-interpolation contract.
  • Record decisions covering recipe-specific placeholders, backtick handling, and the scope and stability of the shlex::split rejection guard.
  • Plan corrections to existing documentation, a new ADR, executable README examples and security tests, translated README updates, and roadmap closure.

Documentation:

  • Plan a new README security section and align the developers', users', formal-verification, design, and translated README documentation with the implementation.

Tests:

  • Plan executable documentation tests and negative controls that verify placeholder rewriting, path quoting, backtick rejection boundaries, and shlex coverage.

Chores:

  • Capture review findings, risks, constraints, milestones, and verification requirements for roadmap item 4.4.1.

leynos and others added 2 commits September 9, 2026 15:10
Add the ExecPlan for roadmap item 4.4.1, which adds a "Security and
command interpolation" section to the README and settles the three
contract questions that
docs/formal-verification-methods-in-netsuke.md leaves open.

Ground truth was established by reading src/ir/cmd_interpolate/ rather
than by trusting existing prose, and three findings shaped the plan:

- `$in` and `$out` ARE substituted in `script:` recipes though not in
  `command:` recipes, contradicting docs/developers-guide.md and
  docs/formal-verification-methods-in-netsuke.md;
- the backtick guard is a whole-string odd-parity count, not a
  quoting-aware model, and does not defend against author-written
  command substitution;
- `shlex::split` gates POSIX and Bash `command:` recipes only, never
  `script:` recipes and never PowerShell.

The plan therefore spans five milestones: a new ADR recording the three
decisions, the README section with two executable examples, correction
of the two inaccurate internal documents, the six translated READMEs,
and the roadmap closure.

Because tests/documentation_examples/ requires a `tested-example`
marker on every README fence and compares identifiers for exact set
equality, adding the section is a test change as well as a prose
change. That gives the item a genuine red-green cycle, which the
verification plan uses to make each documented claim falsifiable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fold a six-lens design review into revision 2 of the ExecPlan. The
review found four factual errors in revision 1 and two obligations
that should have existed and did not.

Blocking corrections:

- EP-M2 (document corrections) now precedes the README milestone and
  covers docs/users-guide.md:1697,1713, which also contradict the
  script-recipe placeholder behaviour. Revision 1 would have shipped a
  README that contradicted the very page it links to.
- The negative controls now run after the README is committed and
  restore by file copy. Revision 1 ran them first and restored with
  `git checkout -- README.md`, which would have deleted the section it
  had just written.
- OBL-PLACEHOLDERS' negative control was non-discriminating:
  UndefinedBehavior::Strict makes an undefined `{{ inputs }}` fail
  during rendering, before marker recognition is reached.
- Two obligations added. OBL-RECIPE-KIND covers the plan's own headline
  finding, and OBL-QUOTING covers the section's only positive security
  promise. Neither had any test in revision 1.

Factual corrections: assert_shell_command is in src/ninja_gen/mod.rs,
not src/ninja_gen_recipe_shell.rs; `shlex = "2.0.1"` is a caret
requirement, not a pin; the registry test is
every_documented_fence_has_a_known_unique_identifier; and
docs/netsuke-design.md already states the contract correctly and must
not be touched.

Rewording: D2 now promises the marker invariant and the backtick parity
check at different strengths, so a future quoting-aware fix is not a
breaking change. D3 names both shlex drift directions and states that
passing the gate does not make a command safe. D1 frames the
script-only $in/$out forms as retained legacy with a shadowing warning
and raises D1-LEGACY for the owner.

The README section order was inverted to put the live hazards before
the placeholder table, and the templated-value injection vector was
promoted out of a bullet list into its own labelled part. Scope
tolerance was raised to 18 files / 1200 lines, because the review
showed the original would fire on the plan's own expected path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This planning-only PR introduces a revision-2 ExecPlan for roadmap item 4.4.1, specifying how the command interpolation contract will be documented, tested through executable README examples and negative controls, propagated across documentation and translations, and recorded in ADR-021; no implementation changes are included.

Flow diagram for planned command placeholder handling

flowchart TD
    Recipe{Recipe kind}
    Recipe -->|command| Command[Rewrite ins and outs]
    Recipe -->|script| Script[Rewrite ins outs and legacy dollar aliases]
    Command --> Guard[POSIX or Bash validation gates]
    Script --> ScriptResult[Generate script text]
    Guard -->|accepted| CommandResult[Generate command text]
    Guard -->|rejected| Invalid[Invalid command interpolation]
    CommandResult --> Quoted[Own path substitutions are shell-quoted]
    ScriptResult --> Quoted
Loading

Flow diagram for planned documentation and verification milestones

flowchart LR
    Decisions[ADR-021 decisions D1 D2 D3] --> Corrections[Correct internal documentation]
    Corrections --> README[README contract and examples]
    README --> Tests[Executable examples and negative controls]
    README --> Translations[Six translated READMEs]
    Tests --> Gates[Validation gates]
    Translations --> Parity[README structural parity]
    Gates --> Closure[Close roadmap item 4.4.1]
    Parity --> Closure
Loading

File-Level Changes

Change Details Files
Adds a detailed execution plan for documenting and formalising the command placeholder contract without changing production behaviour.
  • Defines decisions for placeholder rewriting, backtick handling, and the shlex rejection gate.
  • Records implementation facts, constraints, risks, milestones, recovery procedures, and review history.
  • Requires an ADR, corrections to conflicting documentation, README content, translations, and roadmap closure.
docs/execplans/4-4-1-document-command-placeholder-contract-in-readme.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-access[bot]

This comment was marked as outdated.

The `spelling` gate rejects "hand-written". The plan already used
"handwritten" in the other of its two occurrences, so this also makes
the document internally consistent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No quality gates enabled for this code.

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