Record manifest-time condition semantics (3.14.1)#298
Conversation
Add the pre-implementation ExecPlan for roadmap item 3.14.1. The plan records the manifest-time `foreach` and `when` contract for actions and targets, names the manifest-to-IR boundaries, and defines the documentation and test gates required before implementation.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
OverviewThis PR implements roadmap task 3.14.1 by recording and enforcing manifest-time condition semantics for top-level Design & DocumentationA new ExecPlan document— The design boundary was clarified across multiple documents:
American spelling conventions were applied consistently across documentation (e.g., "deserialize" rather than "deserialise"). Core Implementation
TestingUnit Tests
Integration & BDD Tests
Observability & Security
Documentation CorrectionsVarious files updated for consistency (e.g., NoteA follow-up GitHub issue was created to add insta snapshot coverage for conditional-manifest Ninja output, marked as out-of-scope for this PR. WalkthroughRecord and validate that top-level ChangesManifest-Time Condition Semantics for Actions and Targets
Sequence DiagramsequenceDiagram
participant Loader
participant expand_foreach
participant TypedAST
participant IR
participant Ninja
Loader->>expand_foreach: Provide raw manifest with `foreach`/`when`
expand_foreach->>TypedAST: Emit typed AST with filtered entries removed
TypedAST->>IR: Generate IR from typed AST (no when/foreach)
IR->>Ninja: Synthesize build.ninja (kept entries only)
Ninja->>Runner: Execute built rules (runner sees only emitted builds)
Possibly related issues
Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 18✅ Passed checks (18 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Document that top-level action and target foreach/when clauses are manifest-time decisions before typed AST deserialisation, IR generation, and Ninja execution. Add unit and BDD coverage that skipped entries are absent from downstream output.
Reviewer's GuideDocuments and hardens manifest-time semantics for foreach/when on top-level actions and targets, adds structured debug logging for filtered entries, and extends tests and BDD scenarios to prove skipped manifest entries are removed before AST deserialization and never reach IR or generated Ninja output, while also normalizing serialization/deserialization spelling and ticking roadmap item 3.14.1 as complete. Class diagram for manifest expansion and condition decision typesclassDiagram
class ManifestExpander {
+expand_foreach(doc: ManifestValue, env: Environment) Result~()~
+expand_section(doc: ManifestValue, key: &str, env: Environment) Result~usize~
+expand_target(map: ManifestMap, env: Environment) Result~Expansion~
+when_allows(map: ManifestMap, env: Environment, iteration_item: Value, iteration_index: usize) Result~WhenDecision~
+log_filtered_entry(map: ManifestMap, expression: &str, iteration_index: usize) void
+entry_name(map: ManifestMap) &str
}
class Expansion {
+entries: Vec~ManifestValue~
+filtered: usize
}
class WhenDecision {
+allowed: bool
+expression: Option~String~
}
class ManifestValue {
}
class ManifestMap {
}
class Environment {
}
ManifestExpander "1" o-- "many" Expansion : creates
ManifestExpander "1" o-- "many" WhenDecision : computes
ManifestExpander --> ManifestValue : reads_writes
ManifestExpander --> ManifestMap : manipulates
ManifestExpander --> Environment : uses
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/manifest/expand_tests.rs" line_range="87-81" />
<code_context>
+fn expand_foreach_when_injects_iteration_vars_only_for_kept_entries(
</code_context>
<issue_to_address>
**suggestion (testing):** Strengthen the foreach + when test by asserting control fields (`foreach`/`when`) are fully stripped from kept entries
The current test already checks that only `keep`/`also-keep` iterations survive the `when` filter and that indices are preserved. Adding assertions that `foreach` and `when` keys are absent on all kept entries would better lock in the manifest-time semantics and match the earlier static `when` test, helping ensure loader-only control fields never leak into the typed AST/IR boundary.
Suggested implementation:
```rust
fn expand_foreach_when_injects_iteration_vars_only_for_kept_entries(
#[case] section: &str,
) -> Result<()> {
let env = Environment::new();
let yaml = format!(
"{section}:
- foreach:
- skip
- keep
- also-keep
when: item != 'skip'
```
```rust
);
// Existing setup / expansion & assertions (kept as–is above this point)
// Strengthen the test: ensure loader-only control fields never reach
// the typed AST / IR for any of the kept entries.
//
// `items` is expected to be the collection of expanded entries for the
// given `section` (e.g. `targets` / `actions`) after `foreach`+`when`
// have been processed.
for item in &items {
// `item` is expected to be a map-like structure (e.g. serde_json::Map /
// serde_yaml::Mapping / IndexMap<String, Value>) representing the kept
// entry. We defensively assert that none of the loader-only control
// fields are present anymore.
assert!(
!item.contains_key("foreach"),
"loader-only control field `foreach` must be stripped from kept entries"
);
assert!(
!item.contains_key("when"),
"loader-only control field `when` must be stripped from kept entries"
);
}
```
The strengthening of the test assumes that:
1. There is a variable named `items` in this test that holds the expanded, kept entries (for the selected `section`) *after* `foreach` and `when` have been applied.
2. Each element of `items` exposes a `contains_key(&str) -> bool` method, as map-like values (e.g. `serde_yaml::Mapping`, `serde_json::Map<String, Value>`, or `IndexMap<String, Value>`).
To integrate this in your actual codebase, you will likely need to:
1. Replace `items` in the loop with the real variable that holds the expanded entries in this test (for example, `expanded_targets`, `expanded_actions`, or similar).
2. If each entry is wrapped in a newtype or struct, adjust the loop body to reach the underlying map (e.g. `for item in &items { let map = &item.0; ... }` or `let map = item.as_mapping().unwrap();`).
3. If the underlying type does not have `contains_key(&str)`, replace the assertions with the appropriate accessors, for example:
- For `serde_yaml::Mapping`: `assert!(!map.contains_key(&Value::String("when".into())))`
- For a struct: `assert!(item.foreach.is_none()); assert!(item.when.is_none());`
4. Place this loop after the existing assertions that verify that only the `keep` / `also-keep` iterations survived and that their indices are preserved, but before the final `Ok(())`.
These adjustments will ensure the test explicitly asserts that `foreach` and `when` control fields are fully stripped from all kept entries, locking in the intended manifest-time semantics.
</issue_to_address>
### Comment 2
<location path="docs/execplans/3-14-1-manifest-time-condition-semantics-for-actions-and-targets.md" line_range="16" />
<code_context>
+unambiguous for both top-level `targets` and top-level `actions`. A Netsuke
+manifest can use `foreach` to generate entries and `when` to include or skip
+entries. The important rule is that these are manifest-time decisions: Netsuke
+evaluates them while loading the manifest, before typed AST deserialisation,
+before IR generation, and before the Ninja backend executes anything.
+
</code_context>
<issue_to_address>
**issue (review_instructions):** AST/IR are introduced here without being expanded, and “deserialisation” uses -isation rather than the requested -ization spelling.
In this new document, `AST` (Abstract Syntax Tree) and `IR` (Intermediate Representation) are first introduced here but not defined, which conflicts with the requirement to define uncommon acronyms on first use. Additionally, the project style asks for Oxford -ize/-ization spellings; “deserialisation” should be updated to “deserialization” (and similar forms elsewhere in this file, such as “deserialised”).
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*.md`
**Instructions:**
- Define uncommon acronyms on first use.
- Use en-GB-oxendic (-ize / -yse / -our) spelling and grammar.
</details>
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@docs/execplans/3-14-1-manifest-time-condition-semantics-for-actions-and-targets.md`:
- Around line 16-17: Replace all British-form instances of
"deserialisation"/"deserialises" (and their capitalized variants) with the
project-preferred "-ize" spellings "deserialization"/"deserializes" throughout
this document
(docs/execplans/3-14-1-manifest-time-condition-semantics-for-actions-and-targets.md)
and the other listed files (occurrences at the noted locations), using a
case-preserving search-and-replace so plurals/capitalization remain correct;
ensure no other words are changed and run a quick grep to confirm all instances
were updated.
- Around line 373-380: The shell pipelines that run validation (the lines
invoking make fmt, make check-fmt, make lint, make test, make markdownlint, make
nixie piped into tee) can hide failing exit codes; add a directive to enable
pipefail (e.g., run set -o pipefail once at the top of the shell snippet/block)
so any failed make command will propagate its non-zero exit status even when
piped to tee, ensuring the captured logs reflect actual failures.
- Around line 40-41: Remove the obsolete pre-implementation gate sentence "This
plan is pre-implementation. Do not implement it until the plan is explicitly
approved." from the document
(docs/execplans/3-14-1-manifest-time-condition-semantics-for-actions-and-targets.md)
so it no longer contradicts the existing "Status: COMPLETE" and implemented
retrospective; simply delete that instruction block and any surrounding gating
text that repeats the same pre-implementation restriction.
In `@docs/netsuke-design.md`:
- Around line 417-420: The document uses British "-ise" spellings; replace every
occurrence of "deserialised" with "deserialized" and "deserialisation" with
"deserialization" (e.g., the instance "deserialised" in the sentence containing
`foreach` and `when` and the occurrences around lines referenced in the review)
so the docs use the Oxford "-ize" form consistently; update both instances
mentioned ("deserialised" -> "deserialized" and "deserialisation" ->
"deserialization") and scan the surrounding paragraphs (including the block
around the earlier 889-891 note) to ensure no other occurrences remain.
In `@docs/roadmap.md`:
- Around line 332-334: Replace the British-spelled word "deserialisation" with
the Oxford -ize form "deserialization" in the roadmap text (the list item
containing "State that `foreach` and `when` are evaluated before typed AST
deserialisation, IR generation, and Ninja execution."); update that single
occurrence so the sentence reads "...before typed AST deserialization, IR
generation, and Ninja execution." to comply with the en-GB-oxendict -ize
spelling rule.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 7a984884-7933-439c-abfc-e13e77b1b483
📒 Files selected for processing (10)
docs/developers-guide.mddocs/execplans/3-14-1-manifest-time-condition-semantics-for-actions-and-targets.mddocs/netsuke-design.mddocs/roadmap.mddocs/users-guide.mdsrc/manifest/expand_tests.rstests/bdd/steps/conditional_manifest.rstests/bdd/steps/mod.rstests/features/manifest_subcommand.featuretests/ir_from_manifest_tests.rs
Add debug tracing around manifest-time condition filtering so skipped entries expose their name, when expression, result, iteration index, and filtered summary counts. Clean up the completed ExecPlan validation and requested spelling.
Define AST and IR on first use in the ExecPlan and make the validation snippet enable `pipefail` once for the whole shell block. Strengthen the `foreach` plus `when` expansion test so kept entries prove that loader-only control fields are stripped before the typed manifest boundary.
Normalize the remaining `deserialization` spellings reported by the documentation check and keep nearby touched serialization wording in the same style. Make the manifest filtering summary log expose an explicit `filtered_entry_count` field so observability checks can see the aggregate filter count alongside target and action counts.
Remove the `Expansion` and `WhenDecision` helper structs from manifest condition expansion. Keep filtered counts in `expand_section` and centralize filtered-entry debug tracing in `when_allows` so expression text remains borrowed until it is logged. Include the source manifest section in filtered-entry logs and clarify the ExecPlan spelling and Behaviour-Driven Development acronym guidance.
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already.
|
This comment was marked as resolved.
This comment was marked as resolved.
Return `FilteringStats` from manifest condition expansion so callers and tests can inspect filtered target and action counts explicitly. Introduce an injected logger boundary with a tracing-backed production adapter, and cover both the recorded filtering counts and emitted debug fields in unit tests.
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. ❌ Failed checks (1 error, 2 warnings, 1 inconclusive)
|
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Snapshot the generated Ninja manifest for a foreach/when conditional target so kept entries and skipped entries are covered at the output boundary. Assert the kept build edge is present and the skipped target name is absent before comparing the output against the accepted insta snapshot.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/manifest/expand.rs (1)
194-198:⚠️ Potential issue | 🟠 Major | ⚡ Quick winLayer entry
varsinto thewhenevaluation context.Build
ctxfrom the entry’s existingvarsand then overlayitem/index. Right nowwhencan only see iteration locals, so conditions cannot depend on values declared on the same target/action and those manifests will be filtered incorrectly or fail during expansion.Based on learnings: "Implement foreach and when keys for target generation, exposing item and optional index variables, layering per-iteration locals over target.vars and manifest globals."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/manifest/expand.rs` around lines 194 - 198, The current when-evaluation context only includes iteration locals; update the ctx construction used by eval_when so it starts from the entry’s existing vars and manifest/global context and then overlays the iteration item and optional index; specifically, build ctx from the entry.vars (and existing context.env if needed) before applying the match branch that inserts item and index (the code around ctx, iteration, context! and the call to eval_when(context.env, expr, ctx)?), so that per-target/action vars are visible to the when expression while still allowing item/index to override or augment them.src/manifest/expand_tests.rs (1)
109-541: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy liftSplit this test module now.
Move the tracing capture utilities and the new conditional-expansion cases into smaller modules/fixtures. The file now exceeds the repository’s 400-line limit, which makes the changed surface harder to navigate and maintain.
As per coding guidelines: "Files must not exceed 400 lines in length".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/manifest/expand_tests.rs` around lines 109 - 541, The test file exceeds the 400-line limit; split it by extracting the tracing capture helper and the conditional-expansion tests into smaller test modules/files: move installed_test_subscriber (and its OnceLock/CapturedEvents setup) plus the tests that rely on tracing (expand_foreach_emits_debug_event_for_filtered_entry) into a new test module/fixture, and move the many expand_static_* and foreach-related cases (e.g. expand_static_when_false_removes_entry_before_typed_ast, expand_foreach_when_injects_iteration_vars_only_for_kept_entries, expand_foreach_expands_sequence_values, expand_foreach_applies_when_expression, expand_foreach_expands_actions_sequence_values, expand_foreach_applies_action_when_expression, expand_static_action_when_false_drops_action, expand_foreach_preserves_object_key_order, expand_static_target_when_evaluation, expand_static_target_when_invalid_errors, expand_foreach_invalid_expression_errors_during_template_expansion) into one or more smaller test modules/files; update module declarations (mod ...) and any use/imports so functions like expand_foreach, targets, actions, section_entries, indexes, entry_name_hash and Environment remain in scope and preserve test behavior and visibility. Ensure each new file compiles as part of the test suite and keep test names and assertions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/manifest/expand_tests.rs`:
- Around line 207-217: The installed_test_subscriber function currently installs
a global subscriber (set_global_default) and reuses a static CAPTURED
CapturedEvents across tests which causes cross-test interference; remove the
global set_global_default call and instead create and return a fresh
CapturedEvents per test (or wrap the created layer with
tracing_subscriber::layer::Scope to limit its scope to the current test),
updating callers to initialise the subscriber inside each test so start_index
snapshots are isolated; also split large src/manifest/expand_tests.rs by moving
test utilities and helpers (e.g., installed_test_subscriber,
CapturedEvents-related helpers) into a new test_utils module to keep the test
file under 400 lines.
In `@src/manifest/expand.rs`:
- Around line 211-214: Remove the unbounded/PII field `entry_name` from the
tracing call in expand.rs: locate the trace! invocation that passes `section =
context.section, entry_name, iteration_index, "filtered manifest entry raw
name"` and delete the `entry_name` argument so the trace only emits
bounded/approved fields (e.g. `section = context.section` and `iteration_index`)
and the static message; keep the rest of the trace invocation and formatting
intact so compilation and correlation via the existing bounded hash debug event
continue to work.
---
Outside diff comments:
In `@src/manifest/expand_tests.rs`:
- Around line 109-541: The test file exceeds the 400-line limit; split it by
extracting the tracing capture helper and the conditional-expansion tests into
smaller test modules/files: move installed_test_subscriber (and its
OnceLock/CapturedEvents setup) plus the tests that rely on tracing
(expand_foreach_emits_debug_event_for_filtered_entry) into a new test
module/fixture, and move the many expand_static_* and foreach-related cases
(e.g. expand_static_when_false_removes_entry_before_typed_ast,
expand_foreach_when_injects_iteration_vars_only_for_kept_entries,
expand_foreach_expands_sequence_values, expand_foreach_applies_when_expression,
expand_foreach_expands_actions_sequence_values,
expand_foreach_applies_action_when_expression,
expand_static_action_when_false_drops_action,
expand_foreach_preserves_object_key_order, expand_static_target_when_evaluation,
expand_static_target_when_invalid_errors,
expand_foreach_invalid_expression_errors_during_template_expansion) into one or
more smaller test modules/files; update module declarations (mod ...) and any
use/imports so functions like expand_foreach, targets, actions, section_entries,
indexes, entry_name_hash and Environment remain in scope and preserve test
behavior and visibility. Ensure each new file compiles as part of the test suite
and keep test names and assertions unchanged.
In `@src/manifest/expand.rs`:
- Around line 194-198: The current when-evaluation context only includes
iteration locals; update the ctx construction used by eval_when so it starts
from the entry’s existing vars and manifest/global context and then overlays the
iteration item and optional index; specifically, build ctx from the entry.vars
(and existing context.env if needed) before applying the match branch that
inserts item and index (the code around ctx, iteration, context! and the call to
eval_when(context.env, expr, ctx)?), so that per-target/action vars are visible
to the when expression while still allowing item/index to override or augment
them.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d64be625-dd8a-40e7-a3c1-495269320818
📒 Files selected for processing (2)
src/manifest/expand.rssrc/manifest/expand_tests.rs
Remove the raw entry name from manifest condition trace events and make when conditions evaluate against entry vars before overlaying foreach item and index locals. Split the large manifest expansion test file into smaller modules and use thread-local tracing captures so filtering debug assertions do not share state across parallel tests.
|
@coderabbitai Please suggest a fix for the following concern and provide an AI coding agent prompt for the fix: Observability
|
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai Have the following now been resolved? src/manifest/expand.rs (1)
🤖 Prompt for AI Agentssrc/manifest/expand_tests.rs (1)
🤖 Prompt for AI Agents |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 3754
|
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. ❌ Failed checks (2 errors, 5 warnings, 2 inconclusive)
|
Update the filtered-entry trace message so it says the raw manifest entry name is withheld and operators should correlate with the hashed debug field. Assert that captured filtering log events never include a raw entry_name structured field.
This comment was marked as resolved.
This comment was marked as resolved.
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 8364 🏁 Script executed: Length of output: 1921
Annulled requirements (stand from previous round)Comments 3–26 (all requests to use Comment-by-comment verdict
Failed checks — updated assessmentOne concrete item remains in-PR ❌The trace!(
section = context.section,
iteration_index, "filtered manifest entry raw name"
);The raw trace!(
section = context.section,
iteration_index,
"filtered manifest entry (raw name withheld; hashed form in accompanying debug event)"
);The global Out-of-scope items — GitHub issuesNo open issues exist for either of the following. Confirm and I will open them immediately. 1 — Ninja snapshot coverage (Testing/UI 2 — Observability: log cardinality and expression redaction (Observability The |
|
@coderabbitai please create a new GitHub issue for the following: Out-of-scope items — GitHub issuesNo open issues exist for either of the following. Confirm and I will open them immediately. 1 — Ninja snapshot coverage (Testing/UI |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 45
|
Remove the redundant filtered-entry trace event so only the bounded debug event reports manifest filtering decisions. Replace the manifest expansion tracing test helper with a per-test scoped subscriber and avoid registering the debug callsite when no subscriber is active, keeping the scoped capture stable under parallel tests.
Record why manifest condition filtering logs hash entry names and omit raw when expressions, preserving useful correlation without leaking manifest contents. Strengthen the tracing capture test so it rejects both raw entry_name and raw when_expression structured fields.
Summary
This branch implements roadmap task (3.14.1) by recording the manifest-time condition contract for top-level actions and targets.
foreachandwhenare documented as loader-time semantics that run before typed AST deserialization, IR generation, Ninja generation, and Ninja execution. Build-time branching remains in recipe commands or scripts unless a future runtime-condition feature is designed.Review follow-up also adds structured debug tracing for manifest-time condition filtering. Skipped entries now expose entry name,
whenexpression text, false result, iteration index where present, and filtered action/target summary counts.Execplan: docs/execplans/3-14-1-manifest-time-condition-semantics-for-actions-and-targets.md
Review walkthrough
Validation
cargo test --workspace expand_ -- --nocapture: passedcargo test --workspace skipped_manifest_conditions_do_not_contribute_to_ir -- --nocapture: passedcargo test --test bdd_tests manifest_time_conditions -- --nocapture: passedmake check-fmt: passedmake lint: passedmake test: passedmake markdownlint: passedmake nixie: passedReview follow-up validation:
cargo test --workspace expand_ -- --nocapture: passedmake check-fmt: passedmake lint: passedmake test: passedmake markdownlint: passedmake nixie: passedNotes
make fmtwas attempted first and logged to/tmp/fmt-netsuke-3-14-1-review-followups.out. It appliedcargo fmt, then failed on pre-existing repository-wide Markdown line-length and table findings outside this branch's changes. Unrelated formatter churn was restored;make markdownlintpasses on the final tree.Summary by Sourcery
Clarify and lock in manifest-time condition semantics for actions and targets, ensuring conditional entries are filtered during manifest loading and never reach the typed AST, IR, or generated Ninja output.
New Features:
whenconditions duringforeachexpansion.manifestsubcommand emits only conditionally selected actions and targets.Enhancements:
expand_foreachboundary as the sole owner of manifest-time conditional planning semantics.Documentation:
foreachandwhenare evaluated before AST deserialization, IR generation, and Ninja execution, and that build-time branching belongs in recipes.Tests:
when: falseentries are removed before AST deserialization, iteration variables are injected only for keptforeachentries, and invalidforeachexpressions fail during template expansion.