feat(loop): hew loop run --scope={ready|epics} flag (hew-b3yl)#58
Merged
Conversation
…d-compat
- New `hew_core::scope` module exporting `Scope { Ready, Epics { epic_ids } }`
with `#[serde(tag = "kind", rename_all = "snake_case")]` mirroring the
external_gate::GateKind tagged-union pattern.
- `Default` is `Ready` so legacy RunConfig payloads without a scope key
deserialize unchanged (covered by scope_serde_backward_compat_missing_field).
- `Scope::includes(task_id, &epic_descendant_set)` filters via a pre-resolved
HashSet so the hot path is a set lookup, not a graph walk per task.
- `resolve_descendants(bd, &[epic_ids])` BFS-walks `tasks::children` with a
visited set — handles shared descendants and accidental cycles.
- 9 unit tests: default, includes (Ready/Epics), serde roundtrip both
variants, missing-field compat, transitive resolution, multi-epic
union/dedupe, empty input. Per-parent fake BdClient added inline since
the shared MockBd in tasks::tests keys on argv[0] alone.
Closes hew-55ne (parent epic hew-b3yl).
Dispatcher::new now takes a Scope. dispatch_tick resolves the descendant set on every tick for Scope::Epics (so mid-run-added children are picked up) and filters the bd ready list before slot assignment. ready_seen counts the filtered set so callers detect "queue drained" per scope. Loop_cmd hands Scope::Ready for now; hew-ry5r threads the real value from RunConfig. - 4 new dispatcher unit tests cover Ready (unfiltered), Epics (descendant filter), Epics (no match → empty), Epics (recompute picks up newly-added child between ticks). - MockBd extended to answer 'children <id> --json'. Closes hew-7ind.
- Add Option<Scope> field with serde(default, skip_serializing_if = "Option::is_none") so legacy run.json (missing scope) parses to None and Some(Ready) serializes verbatim - from_run sets scope = None; hew loop populates after RunConfig.scope lands (hew-ry5r) - Add tests/fixtures/run-log-pre-scope.json + 5 tests covering Ready/Epics persistence, backward-compat fixture load, two-id epics round-trip, and default-None invariant - Mirrors IterLog.model defensive serde pattern from hew-2cq Closes hew-6nxs.
- RunConfig gains pub scope: Scope (default Ready) - RunLog::from_run propagates run.config.scope verbatim, replacing the hew-6nxs placeholder-None — Some(Scope::Ready) on default cfg keeps the "defaulted vs explicit Ready" distinction intact - loop_cmd grows resolve_scope(args) as the single source of truth; Dispatcher::new in run_loop_parallel and the RunConfig builder in run_worker_loop both read through it (returns Ready until hew-xhhw wires the --scope CLI flag) Closes hew-ry5r.
Wires the run-scope CLI surface for hew loop run. argv > interactive picker > non-interactive MissingFlag error. - New ScopeArg ValueEnum + --scope, --epics (CSV), --epic (singular alias merged into --epics). - resolve_scope(args, ctx, bd): validates --scope=ready against --epics conflict; validates each epic id via tasks::show (exists, is epic, open); interactive paths use inquire Select then MultiSelect; ResolvedScope::Cancelled exits 0 with a note. - Scope is resolved once at run_loop top and threaded through new run_loop_with_scope / run_worker_loop_with_scope. Legacy run_loop_with / run_worker_loop kept as Scope::Ready back-compat wrappers so loop_backpressure / loop_dynamic_model / loop_parallel_e2e don't need new args. - 8 unit tests on a FakeBd stub cover every resolve_scope branch. - 7 e2e tests cover the CLI surface: clap rejection, no-picker argv paths, MissingFlag enforcement, conflict rejection, --help. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Summary gains `scope: Option<Scope>`; render() prints `scope: <label>` between outcomes and tokens. - Live print path passes `Some(run.config.scope.clone())`; the re-render path (`hew loop summary`) reads `RunLog.scope`, so pre-scope `run.json` files surface as `scope: ready (legacy)`. - Parallel summary reads scope from worker 0's `run.json` (dispatcher- level scope is identical across workers). - `Scope::label` + `scope::label_optional` keep the label format in one place: "ready", "epics [hew-6az, hew-1tq]", "ready (legacy)". - Tests: scope_label_ready_and_epics, label_optional_distinguishes_none_from_explicit_ready, summary_renders_scope_ready, summary_renders_scope_epics_with_ids, summary_renders_legacy_no_scope_field_as_ready_legacy, summary_scope_line_appears_between_outcomes_and_tokens. - docs/LOOP.md gets a `## Scope` section above Stop signals; CHANGELOG Unreleased Added entry; commands/loop.md examples now lead with the required `--scope=ready` (or `--scope=epics --epics=…`) flag. Closes hew-cjhj. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI lacked `bd` on PATH, which made `hew loop run` exit with `bd: not found` before ever reaching the scope MissingFlag check. The three contract tests in loop_scope_e2e.rs that assert on the exact `MissingFlag(scope|epics)` string therefore failed in CI even though they passed locally where `bd` was installed. Argv-level validation shouldn't depend on external binaries. Adds a `precheck_scope_argv(args, ctx)` that runs ahead of `bd discover` and fires the three errors that don't need bd: 1. `--scope=ready` + `--epics` (contradiction) 2. `--scope=epics` + no epics + non-interactive (MissingFlag epics) 3. no `--scope` + non-interactive (MissingFlag scope) The rest of resolution (id validation, interactive pickers) still lives in `resolve_scope` and runs after bd is on hand. Verified by running the suite with bd scrubbed from PATH — loop_scope_e2e 7/7 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 30, 2026
Merged
Merged
droidnoob
added a commit
that referenced
this pull request
May 30, 2026
* chore(release): 0.11.0 - workspace Cargo.toml: 0.10.0 -> 0.11.0 - 23 skill body `hew:version=` markers bumped to match - .claude/ install snapshot refreshed via `hew init --runtime=claude` - CHANGELOG.md: move [Unreleased] content into [0.11.0] — 2026-05-30 Release contents since 0.10.0: #53 parallel hew loop via per-worker git worktrees (hew-6az) #54 per-task model selection + per-model token spend (hew-1tq) #55 init re-run UX — refresh/reconfigure/cancel (hew-0wa) #56 split /hew:auto from /hew:loop semantics (hew-6n0v) #57 cut local cargo test from ~2 min to ~22s (hew-v2ib) #58 hew loop run --scope={ready|epics} (hew-b3yl) #59 batch planner + end-of-run verify + loop graph (hew-lf40) #60 retry_etxtbsy stub flake fix (hew-0rky) Breaking surface: hew loop run in non-interactive mode now requires --scope. Justifies the minor bump. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(readme): reflect 0.11.0 surface changes - /hew:auto description updated to in-conversation epic walk (was the legacy plan→decompose→execute→verify; rewritten in hew-6n0v / #56) - slash count 40 → 41 (new /hew:auto + various) - loop snippets show --scope (required in non-interactive mode per hew-b3yl / #58), --jobs N, --verify-tests, hew loop summary, hew loop graph - autonomous-loop bullets gain parallel-workers, scoped-runs + per-task-model, end-of-run-verification entries - Selected knobs table adds loop.model.*, loop.planner.*, loop.end_of_run.verify_tests, loop.fallback_runtime No changes to brand, hero copy, or repo description. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the
hew-b3ylepic —hew loop run --scope={ready|epics}flag.Lets the operator (or a calling agent) tell
hew loop runwhich set of tasks counts as the queue for this run. Agents calling agents MUST pass--scopeexplicitly; interactive humans get a picker.v1 scopes
--scope=ready— current behavior. Everybd readytask is fair game.--scope=epics --epics=<csv>— restricted to children of selected epics (transitive descendants, including the epic itself).Resolution policy
argv > interactive picker > non-interactive error.--scope=ready--scope=epics --epics=hew-X,hew-Y--scope=epics(no--epics)MissingFlag { flag: "epics" }--scope)MissingFlag { flag: "scope" }--scope=ready --epics=XWhat lands
6 atomic commits, one per task in the decomposed graph:
2fe599bhew_core::scopemodule —Scopeenum + serde (#[serde(tag = "kind")]) +resolve_descendantsagainstBdCliente94c9b6Scope;dispatch_tickrecomputes descendant set per tick so mid-run epic-child additions get picked up35c905cRunLog.scope: Option<Scope>with#[serde(default, skip_serializing_if)]for backward-compat parsing of pre-scoperun.jsonfixturescae3827RunConfig.scope(defaultReady); threaded intoDispatcher::new7d8d988--scope(clap enum),--epics(CSV),--epic(singular alias);resolve_scope()implements the resolution policy withinquirepickers2ce2ca7loop_summaryrendersscope:line;docs/LOOP.mdgains a## Scopesection;CHANGELOG.mdentrySummary surface
Smoke (hew-mu5j — closed)
Full surface smoke report at
/tmp/scope-smoke-report.md. Highlights:scope::*(11),dispatcher::dispatch_tick_*(4),loop_log::run_log_*(7),runner::run_config*(1),loop_scope_e2e(7),loop_summary::summary_renders_scope/legacy/line(4).--scoperesolution covered byhew/tests/loop_scope_e2e.rs.cargo nextest run --workspace: 1060 passed / 2 skipped (slow-marked) / 0 failed.Scopeenum athew-core/src/scope.rs:33; verified no duplicate definitions across modules.Honest caveat: the 6 children landed on this single stacked branch (one commit per task, in dependency order) rather than 6 sibling branches. Per-branch isolation therefore wasn't proven separately — the smoke chore explicitly flagged the deviation rather than fabricating results, and ran every per-child test selector against the stacked branch instead.
Non-goals (v1)
loop.scope.defaultconfig knob./hew:autochanges (already epic-scoped per hew-6n0v).🤖 Generated with Claude Code