Skip to content

feat(tickets): groundwork for a parent initiative chain (DW-574, 1/3) - #1011

Merged
pbean merged 7 commits into
dw-ledger-1028/03-adapter-session-fixesfrom
dw-ledger-1028/04-chain-foundations
Oct 30, 2026
Merged

pbean merged 7 commits into
dw-ledger-1028/03-adapter-session-fixesfrom
dw-ledger-1028/04-chain-foundations

Conversation

@pbean

@pbean pbean commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Part 4 of 8 of the deferred-work ledger stack. Parts 4-6 are DW-574: tickets mode builds a parent initiative's children instead of refusing it.

What

The groundwork for a parent initiative chain. Nothing in this PR runs a chain yet.

Why

run on a v7 parent initiative exits 1. A chain needs: the parent's next parsed, a tree routed through a child folder, a run that records its parent, a drained child closed, and every recorded-run site reopened on the child's own paths and pin.

How

  • ticketmodel parses tickets.py next on a parent (ParentView / ChildInitiative / InitiativeEdge). TicketTree takes an optional child folder and keeps the pin on the parent.
  • RunState.parent_initiative is new. An older state.json loads unchanged. ProjectPaths.with_initiative re-roots a v7 snapshot on a child initiative.
  • A drained child initiative is marked status: done. set_frontmatter_field gains an opt-in keep_bom.
  • A chained child's trees are pinned, and its initiative is written into the unit mount's config.
  • The tickets preflight accepts a parent initiative under worktree isolation.
  • runs.paths_for_state reopens a chained run on its child's paths. If the live active_initiative no longer names its parent, it raises BmadConfigError naming the value to restore.

Testing

  • uv run pytest -q -n logical at this PR's tip: 17535 passed, 124 skipped.
  • uv run pyright (1.1.411): 0 errors.
  • CI.

Changelog

n/a here. The DW-574 entry lands in part 6, once the chain is complete.

@coderabbitai

coderabbitai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 04860855-b164-4923-a88d-93ecc770e32d
Commits

Reviewing files that changed from the base of the PR and between a156a6b and 247f577.

Files selected for processing: 43
  • AGENTS.md
  • docs/FEATURES.md
  • docs/reference/cli.md
  • docs/reference/run-state.md
  • docs/tickets-guide.md
  • pyproject.toml
  • src/bmad_loop/bmadconfig.py
  • src/bmad_loop/cli.py
  • src/bmad_loop/diagnostics.py
  • src/bmad_loop/documents.py
  • src/bmad_loop/initiativechain.py
  • src/bmad_loop/install.py
  • src/bmad_loop/model.py
  • src/bmad_loop/runs.py
  • src/bmad_loop/statemachine.py
  • src/bmad_loop/ticketmodel.py
  • src/bmad_loop/tickets_engine.py
  • src/bmad_loop/ticketstore.py
  • src/bmad_loop/tickettree.py
  • src/bmad_loop/tui/app.py
  • src/bmad_loop/tui/data.py
  • src/bmad_loop/verify.py
  • src/bmad_loop/worktree_flow.py
  • tests/test_bmadconfig.py
  • tests/test_cli.py
  • tests/test_diagnostics.py
  • tests/test_engine_worktree.py
  • tests/test_initiativechain.py
  • tests/test_install.py
  • tests/test_model.py
  • tests/test_portability_guard.py
  • tests/test_resolve.py
  • tests/test_runs.py
  • tests/test_statemachine.py
  • tests/test_ticketmodel.py
  • tests/test_tickets_e2e.py
  • tests/test_tickets_engine.py
  • tests/test_ticketstore.py
  • tests/test_ticketstore_probe.py
  • tests/test_tickettree.py
  • tests/test_tui_app.py
  • tests/test_tui_data.py
  • tests/test_worktree_flow.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@pbean
pbean added this pull request to stack #1016 October 29, 2026 17:19
@pbean pbean changed the title dw ledger 1028/04 chain foundations feat(tickets): groundwork for a parent initiative chain (DW-574, 1/3) Oct 29, 2026
@pbean
pbean force-pushed the dw-ledger-1028/04-chain-foundations branch 2 times, most recently from 2b6617d to 9bd94e9 Compare October 29, 2026 19:16
t added 7 commits October 29, 2026 14:40
…ugh a child folder (DW-574)

ticketmodel gains ParentView/ChildInitiative/InitiativeEdge and
parse_parent_next for tickets.py next on a parent (folder-less children
are data). TicketTree takes an optional child folder, passed as the
<dir> positional to next/status/find/mark (argv unchanged without one),
keeps the pin on the parent, and adds parent_next(). default_ticket_tree
takes an optional folder keyword. Call sites are unchanged.
…ild (DW-574)

RunState gains parent_initiative (str | None, None by default): the
parent initiative whose child the run builds. to_dict always writes it,
as RunState writes every key; from_dict reads an absent or empty key as
None, so an older state.json loads unchanged. ProjectPaths.with_initiative
re-roots a v7 snapshot on a child initiative: the parent folder's sibling,
with both artifact dirs, the ledger and the sprint path on it. It is pure
and refuses anything that is not a single folder name.

New pure module initiativechain: next_child walks a ParentView's ready
children in build order. It passes over a folder-less child (no-folder)
or one the caller's probe passes over, and reports both, along with the
waiting children. When it takes none, the chain-end reason is waiting,
passed-over or all-done.

status --json: the run-level tickets object gains parent_initiative
(string or null). The key is additive, so STATUS_SCHEMA_VERSION stays 1
(machine.py: additive-only evolution).

The engine's TicketTreeFactory becomes a Protocol with a folder keyword.
The run-pinned tree seams take a folder keyword too: the engine's
ticket_tree and _workspace_ticket_tree, cli._status_ticket_tree,
runs._rearm_ticket_tree, tui.data._board_ticket_tree and
tui.app._replan_ticket_tree. Every caller passes folder=None, so
behaviour is unchanged.
… and pin (DW-574)

Add runs.paths_for_state: a chained run (parent_initiative set) reopens on its
child initiative's paths (ProjectPaths.with_initiative), any other run on the
loaded paths unchanged. A chained run whose live [core] active_initiative no
longer names its parent, or whose child cannot be located, raises
BmadConfigError naming the value to restore rather than returning the loaded
paths: the engine would otherwise read and write the other initiative's ledger
and sprint path before its tree pin could pause it. Every site that reopens a
recorded run applies it: resume (the engine is built on the child's paths while
the launch-parity gates and tickets preflight still judge the loaded parent's,
and a moved parent refuses ahead of every side effect), the resolve
restore-patch/sweep-pin/trust/code-root/abandon/reverify loads, the status
sprint footer, the runs held-closes/sweep-ledger/reverify loaders, and the TUI
replan and re-arm guards. tree_pin moves to runs (re-exported from
tickets_engine) and now raises ValueError on a chained state whose paths are
not re-rooted on its child; TicketsEngine checks this at construction, before
the base engine touches the paths. New runs.recorded_tree_pin pins a recorded
run's tree as the engine does: tree_pin over the child's paths in the main
checkout, the child with no folder in a worktree mount. The status board, the
re-arm (pinned before its first write; a config fault refuses as RearmError
with the escalation still armed) and the TUI replan (pinned from the state
re-read under the lock; the modal no longer passes an initiative) route
through it. cli._status_ticket_tree now takes (project, pinned_initiative,
folder) like the other tree factories.
…d8bbb scope (DW-574)

The bom shape of test_mark_initiative_done_closes_a_drained_child_for_the_script
spelled U+FEFF as a literal, invisible character; an editor or formatter
stripping it would turn the [bom] row into a silent copy of [lf]. It is now the
escape \ufeff, and the row asserts its pre-image starts with codecs.BOM_UTF8
exactly when the shape is bom. The file holds no other literal U+FEFF.

Records what fea88791 changed beyond its subject:
- verify.set_frontmatter_field gained an opt-in keep_bom keyword: a leading
  UTF-8 BOM is set aside before the frontmatter split and written back ahead of
  the edit.
- tests/test_portability_guard.py::test_journal_routing_tables_are_read_from_diagnostics
  was relaxed: a journal schema field may now be accounted for by a
  JOURNAL_KIND_BENIGN_FIELDS row for that kind.
- diagnostics.py routes the new initiative-mark journal kind: parent and slug
  are aliased in the initiative namespace, and file is left off the kind's
  schema, so it reduces to file_present.
- The initiative-mark row's parent field is the parent folder's name, not its
  path.

Records what 96dd8bbb changed beyond its subject:
- ticketstore.classify_store and assess_store gained chained=, and the T1 branch
  no longer returns early, so a chained run under worktree isolation gets the
  user-config-tracked / user-config-not-ignored refusals on T1.
- That refusal's text changed for unchained shared layouts too; it now reads
  "the shared ticket store or a chained run's child initiative".
- store_conflict gained initiative= and re-roots the paths on that child.
- ticketstore.redirect_mount_store was renamed redirect_mount_config, with
  keyword-only main_store= and initiative=; a blank initiative passed to it
  raises TicketStoreError.
@pbean
pbean force-pushed the dw-ledger-1028/04-chain-foundations branch from 9bd94e9 to 247f577 Compare October 29, 2026 21:44
@pbean

pbean commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T22:08:30.459416Z 247f577 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 247f577f10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@pbean
pbean merged commit a0463f9 into main Oct 30, 2026
17 of 33 checks passed
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