fix(loop): parallel hand-off + serial scope filter + summary in-flight + .hew.toml config (hew-zt4z, hew-s9mb, hew-cn2y, hew-c0pa)#62
Merged
Conversation
…runs The parallel loop's atomic claim flipped each ready task to in_progress before any worker ran, which removed it from bd.ready(). The worker then re-polled bd.ready() for its initial task, saw an empty set, and exited iter 0 with `stop_reason: ready_empty` — stranding every claim and producing 0 iters per worker. Worker now carries `assigned_task: Option<ReadyTask>` populated from the dispatcher's `DispatchTick::assignments`. Iter 1 prepends the pre-claim to the worker's bd.ready() view so the existing task pick + signal eval paths stay unchanged; iter 2+ source from bd.ready() like the serial path. Closes hew-zt4z.
- discover_project_root walks cwd ancestors; .beads wins over .git per level - worktree gitlink resolves via git rev-parse --git-common-dir (--show-toplevel returns the worktree dir, not the main repo) - discover_project_config prefers .hew.toml, falls back to hew.toml, warns when both exist - 9 tests including a real-worktree e2e via tempdir Closes hew-ja44
- New load_layered(user, project) reads each file (missing = empty) and merges per documented rules: scalars project-wins, Option<T> uses Option::or, Vec<T> concats with order-preserving dedupe, nested structs recurse, BTreeMap extends with project-wins on collision. - Config::load() now resolves the XDG user path + walks cwd for a project root, then calls load_layered. HEW_CONFIG bypasses layering. - 7 new tests in hew-core/src/config.rs cover the merge axes plus the HEW_CONFIG bypass path.
…9mb) `run_worker_loop_with_scope` polled `bd.ready()` and grabbed the first task without consulting `cfg.scope`, so `hew loop run --scope=epics --epics=<id>` on the serial (`--jobs=1`) path would claim any unrelated ready bug. The parallel `Dispatcher::dispatch_tick` already filtered correctly; the surgical fix mirrors its `resolve_descendants` + `Scope::includes` call at the serial path's candidate boundary. - 3 new regression tests in hew/tests/loop_scope_serial.rs covering the reproducer, the empty-after-filter ReadyEmpty stop, and the no-regression `Scope::Ready` baseline. - Existing loop_scope_e2e 7/7 still green (argv-contract layer unchanged).
- New template hew/templates/hew.toml.starter (version=1 + commented loop/model/planner/end_of_run/compact sections + docs link). - emit_starter_dot_hew_toml helper in init.rs: Fresh/Refresh skip when .hew.toml or hew.toml already exists; Reconfigure prompts before overwriting (default no, only when interactive). Best-effort; never aborts init on write failure. - 10 unit tests cover template content + per-mode helper state via an injected regen picker. - 3 e2e tests cover fresh emit, dotfile preservation, and plain hew.toml blocking creation of .hew.toml.
- Add --global / --project flags on `hew config set` (clap conflicts_with).
- Resolve write target across 5 branches:
1. both flags → clap rejects upstream
2. --global → user-global (~/.config/hew/config.toml)
3. --project → existing project file or <root>/.hew.toml (created
with `# hew project config` + `version = 1` header on first write)
4. neither + project file present → refuse with dual-option error
listing both `--project <key> <value>` and `--global <key> <value>`
5. neither + no project file → user-global (back-compat)
- New `hew_core::config::save_project_to(path, cfg)` prepends starter
header on create; subsequent writes overwrite without re-adding it.
- 7 new e2e tests cover all 5 resolution branches + refusal message
shape + --help surface; 3 new core tests cover save_project_to.
- New `hew config show` subcommand renders a sources header in
precedence order (user-global → project → env) plus the effective
config with `(source)` attribution on every key.
- `hew_core::config::LoadedConfig` carries the merged Config plus a
BTreeMap<String, ConfigSource> and the contributing file paths.
- `ConfigSource` ∈ { UserGlobal, Project, Env, Default, Merged }.
`Merged` is reserved for keys whose values are unioned across both
files (compact.exempt, loop.model.by_priority, loop.model.by_type).
- Attribution walks the raw on-disk toml::Table for each side so a
user value that happens to equal the default still attributes to
user-global, not Default.
- New `HEW_USER_CONFIG` env var overrides the XDG user-global path
without bypassing layered project discovery. `HEW_CONFIG` keeps its
single-file bypass semantics; tests for the layered path use
`HEW_USER_CONFIG` to stay off the host's real config.
- 6 new e2e tests cover sources-in-precedence, scalar/array/default
attribution, the env single-source rendering, and the stable
--json shape. 5 new core tests cover the attribution primitives.
- New docs/CONFIG.md walks the layered config story for operators: two-file overview, discovery order, where-each-setting-belongs table, hew config set write-rules table, hew config show sample + --json shape, merge semantics with worked example, migration recipe, and explicit non-goals (.hew.local.toml, ancestor walk, schema migration). - CHANGELOG.md [Unreleased] entry summarizes the hew-c0pa epic. - CLAUDE.md "Where to look next" links docs/CONFIG.md. - 3 grep-based smoke tests pin the precedence table, merge-semantics section, and CHANGELOG entry against regression.
…bsent (hew-cn2y) `hew loop summary` against a freshly-started run surfaced `read run.json: No such file or directory` because run.json is only written after iter 1 completes. Classify the run-dir state up front (empty-start / parallel-in-flight / iter-logs-only / completed) and render a degraded "iter N in flight" view for every pre-completed case. The genuinely-missing run-id case still errors cleanly. - hew_core::loop_log::RunDirState + inspect_run_dir + run_dir_started_at - hew_core::loop_summary::InFlight + render_in_flight - 6 + 4 unit tests, 4 e2e tests (loop_summary_in_flight_e2e.rs)
…-fixes-and-config # Conflicts: # hew/src/commands/loop_cmd.rs
Merged
droidnoob
added a commit
that referenced
this pull request
May 30, 2026
- workspace Cargo.toml: 0.11.0 -> 0.12.0 - 23 skill body hew:version= markers bumped to match - .claude/ install snapshot refreshed via hew init --runtime=claude - CHANGELOG.md: [Unreleased] content moved to [0.12.0] — 2026-05-31 - CHANGELOG.md: added Fixed entries for hew-zt4z / hew-s9mb / hew-cn2y - hew/tests/config_e2e.rs: changelog_unreleased_has_project_local_config_entry retargeted at the [0.12.0] section (now that the entry has been released) Release contents since 0.11.0: - #62 parallel loop hand-off fix + serial scope filter fix + loop summary in-flight fix + .hew.toml project-local config (hew-zt4z, hew-s9mb, hew-cn2y, hew-c0pa) No code changes in this commit beyond version bumps + CHANGELOG promotion + test target update for the moved CHANGELOG entry. CI will verify. 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.
Combines four follow-up branches from the autonomous loop run that closed
hew-c0pa(project-local config epic) — three loop fixes plus the feature itself. Smoke-tested end-to-end before push.Closes
hew-zt4zP1 bug — parallel--jobs>=2stranded tasks (dispatcher claimed, workers re-polledbd.ready()and saw empty)hew-s9mbP2 bug — serial--jobs=1 --scope=epicsbypassed the scope filter at the worker'sbd.ready()pollhew-cn2yP3 chore —hew loop summaryerrored with rawNo such filewhen the run was in flighthew-c0paP2 epic — project-local.hew.tomlconfig file (+ 6 children)Commits
970f3ddfeat(config): discover_project_root + discover_project_config— pure fs walks for.beads/then.git/; resolves worktrees to real repo rootbe906adfeat(config): load_layered + per-struct merge (hew-36of)— scalars: project wins; arrays: cargo-style concat-dedupe; tables: recurse9f7b0c0feat(init): emit starter .hew.toml after install (hew-3r8v)— embedstemplates/hew.toml.starter; skips if a file already exists16ee6e9feat(config): config set --global/--project write-target (hew-k2gm)— refuses silent fallback when.hew.tomlexists397c5cdfeat(config): hew config show with per-key source provenance (hew-leh9)69cd50edocs(config): docs/CONFIG.md + CHANGELOG + CLAUDE cross-ref (hew-u181)f192e44fix(loop): render in-flight summary instead of ENOENT when run.json absent (hew-cn2y)eae322bfix(loop): apply Scope filter on serial path's bd.ready() poll (hew-s9mb)2221c27fix(loop): thread dispatcher pre-claim to worker so jobs>=2 actually runs (hew-zt4z)Plus three merge commits stitching the four branches together. One textual conflict at
hew/src/commands/loop_cmd.rs:1500-ishbetween the scope-filter and parallel-handoff branches — resolved by composing both (assign-then-filter, so the pre-claimed task still passes through the scope check for safety).Smoke proof — both fixes verified end-to-end
Set up 4 ready tasks:
hew-togn(smoke epic),hew-62c2(P2 in epic),hew-44ge+hew-ybq3(P1 standalones).Test 1 — serial scope filter (
hew-s9mb):✓ Picked
hew-62c2(in-epic P2). The two higher-priority P1 standalones were never considered. Pre-fix this would have grabbed a P1.Test 2 — parallel hand-off (
hew-zt4z), real end-to-end:Set up a 2-task epic with trivial "create a file, commit, close" tasks. Kicked the real loop (no
--dry-run, realclaude -pspawns, real worktrees at~/.hew/wt/<run-id>/{0,1}/, real merge-back).End-state verification:
hew-core/SMOKE_A.txtandhew-core/SMOKE_B.txtboth present in tree, each from a different worker's commit.manifest.jsonshowsiter_count: 2anditer_count: 1for the two workers (pre-fix this was 0/0 withready_empty).agent=0, runtime=2, fallback=0).hew loop summarymid-run rendered the in-flight view correctly (thehew-cn2yfix in action).(Smoke commits + files cleaned out of this branch; only the fix code is in the PR.)
What the smoke fixed for the next time
Previous smoke (
hew-mu5jin PR #58) tested only argv-parsing:--scope=bogusrejected, missing--scopeerrors withMissingFlag, etc. It never asserted "a scoped run claims only descendants" or "--jobs Nactually drives N workers." That's whyhew-zt4zandhew-s9mbshipped: those tests didn't exist.This PR adds real-bd-graph smoke as a discipline, and the bug bodies + the test additions called out in
hew-zt4z/hew-s9mbcarry that forward as required test additions for any future loop change.Gates
cargo fmt --all --check✓cargo clippy --all-targets -- -D warnings✓cargo test --workspace✓ (43 suites, 0 failed)loop_scope_e2e7/7Net change
Largest contributor is
hew-core/src/config.rs(+951) for the project-local config loader; otherwise it's well-scoped diffs across the loop + tests.🤖 Generated with Claude Code
Smoke proof —
.hew.tomlfeatureVerified after the loop-fix smoke (separate tempdir, fresh
hew init):All five concerns from the locked plan verified: starter emission,
--projectwrites, refusal-when-project-exists-without-flag, get round-trip, show-with-source-attribution.