Commit Graph

16 Commits

Author SHA1 Message Date
dave 13f7dab5f0 huskies: merge 1088 2026-05-15 02:03:30 +00:00
dave 72d79deec9 huskies: merge 1026 2026-05-14 13:00:51 +00:00
dave 604fb55bd8 huskies: merge 959 2026-05-13 12:28:30 +00:00
dave 8b53e20ca9 huskies: merge 961 2026-05-13 11:27:21 +00:00
dave a7840ea4b0 huskies: merge 946 2026-05-13 08:00:49 +00:00
dave 9ce5a8df0c huskies: merge 945 2026-05-13 06:09:34 +00:00
dave 7ca5339450 huskies: merge 944 2026-05-13 05:07:28 +00:00
Timmy d78dd9e8f9 feat(934): typed Stage enum replaces directory-string state model
The state machine's `Stage` enum becomes the source of truth for pipeline
state. Six stages of work land together:

  1. Clean wire vocabulary (`coding`, `merge`, `merge_failure`, ...) replaces
     legacy directory-style strings (`2_current`, `4_merge`, ...) on the wire.
     `Stage::from_dir` accepted both during deployment; new writes always
     emit the clean form via `stage_dir_name`. Lexicographic `dir >= "5_done"`
     checks in lifecycle.rs become typed `matches!` checks since the new
     vocabulary doesn't sort in pipeline order.
  2. `crdt_state::write_item` takes typed `&Stage`, serialising via
     `stage_dir_name` at the CRDT boundary. `#[cfg(test)] write_item_str`
     parses legacy strings for test fixtures.
  3. `WorkItem::stage()` returns typed `crdt_state::Stage`; `stage_str()`
     is gone from the public API. Projection dispatches on the typed enum.
  4. `frozen` becomes an orthogonal CRDT register. `Stage::Frozen` and
     `PipelineEvent::Freeze`/`Unfreeze` are removed; `transition_to_frozen`/
     `unfrozen` set the flag directly without touching the stage register.
  5. Watcher sweep and `tool_update_story`'s `blocked` setter route through
     `apply_transition` so the typed transition table validates every
     stage change. `update_story` gains a `frozen` field for symmetry.
  6. One-shot startup migration rewrites pre-934 directory-style stage
     registers (and sets `frozen=true` on items previously at `7_frozen`).
     `Stage::from_dir` drops legacy aliases. The db boundary keeps a small
     normaliser so callers with legacy strings (MCP, tests) still work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:31:59 +01:00
Timmy 7d7ab85994 feat(933): add item_type + epic CRDT registers + migrate epic mechanism
Replaces the YAML-only `type: epic` / `epic: <id>` front-matter fields with
typed CRDT registers on PipelineItemCrdt. The epic-mechanism MCP tools
(`tool_list_epics`, `tool_show_epic`), the epic-context injection in agent
spawn, and the type-classifier helpers (`item_type_from_id`, `is_bug_item`,
`is_refactor_item`) now all read from the CRDT.

Schema:
- PipelineItemCrdt: `item_type: LwwRegisterCrdt<String>` and
  `epic: LwwRegisterCrdt<String>` registers.
- WorkItem: typed `item_type()` and `epic()` accessors returning `Option<&str>`.
- crdt_state::set_item_type(story_id, Option<&str>) and
  crdt_state::set_epic(story_id, Option<&str>) typed setters.

Write paths populate the new registers:
- create_story_file / create_bug_file / create_spike_file /
  create_refactor_file / create_epic_file — each calls set_item_type after
  write_story_content.
- tool_update_story intercepts `epic` and `type` fields and routes them to
  the typed setters (same pattern as qa / depends_on).

Read paths migrated off yaml_legacy:
- http/mcp/story_tools/epic.rs: tool_list_epics + tool_show_epic.
- agents/lifecycle.rs::item_type_from_id (numeric-only IDs).
- agents/pool/start/spawn.rs epic-context injection.
- http/workflow/bug_ops/bug.rs::is_bug_item, refactor.rs::is_refactor_item.
- http/workflow/pipeline.rs::load_pipeline_state — review_hold/qa/epic_id
  all come from the CRDT now; only merge_failure is still YAML (sweep in
  929 stage 10).

All `yaml_residue(...)` wraps for item_type / epic are removed; the
remaining residue marker doc no longer references 933.

cargo fmt --check, clippy --all-targets -- -D warnings, and the 2857-test
suite all pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 19:58:43 +01:00
Timmy b8945654bf wip(929): stage 3 — migrate http/mcp/* off yaml_legacy + introduce yaml_residue marker
Three MCP files touched:

- status_tools.rs (story-status JSON dump): every field with a CRDT
  equivalent now reads from WorkItem (name, agent, blocked, qa_mode,
  retry_count, depends_on, claimed_by, claimed_at) or MergeJob.error
  (merge_failure detail). One field — review_hold — has no CRDT register
  yet (sub-story 932) and is wrapped in `yaml_residue(parse_front_matter(...))`
  so the gap is visible at every code-search.

- qa_tools.rs:
  • tool_approve_qa wraps the legacy `clear_front_matter_field("review_hold")`
    write in `yaml_residue(...)` pending sub-story 932.
  • tool_reject_qa now reads the agent name from the CRDT WorkItem instead
    of parsing front matter on disk.

- story_tools/epic.rs: the entire epic feature (item_type, epic link)
  has no CRDT analog — sub-story 933. Every parse_front_matter call here
  is wrapped in `yaml_residue(...)`.

Also: new identity wrapper `db::yaml_legacy::yaml_residue<T>(v: T) -> T`
that marks a yaml_legacy callsite blocked on a CRDT-register gap. Pure
identity at runtime; the distinctive name makes the residue grep-findable
(`grep -rn yaml_residue`). Sub-stories 932 and 933 enumerate the gaps.

Filed:
- 932: Add CRDT register for review_hold
- 933: Add CRDT registers for the epic mechanism

All 2854 tests pass; fmt + clippy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:54:32 +01:00
dave 9be438e6d3 huskies: merge 865 2026-05-08 14:29:06 +00:00
dave 61cf7684de huskies: merge 864 2026-04-30 22:27:51 +00:00
dave 1d86202abb huskies: merge 868 2026-04-29 23:34:24 +00:00
dave 9a3f60d5d3 huskies: merge 866 2026-04-29 22:47:53 +00:00
dave a49f668b5a huskies: merge 867 2026-04-29 22:17:08 +00:00
dave 7e2f122d36 huskies: merge 880 2026-04-29 21:46:12 +00:00