Skip to main content

Module backlog

Module backlog 

Source
Expand description

The backlog CLI: kranz ticket …, kranz draft, kranz queue, and the kranz work dispatcher (design: docs/backlog-and-slack.md).

Tickets are missions-in-waiting authored as .kranz/tickets/<slug>.md. The pipeline is: ticket new scaffolds one; draft runs the planning conversation non-interactively (orchestrator only, budget-capped) and parks a committed plan.md for review (or bounces the ticket back with the orchestrator’s questions); ticket approve enqueues the parked mission; work drains the per-repo queue, one mission at a time.

The rendering and decision logic here are pure functions (data → String, or state → next-action) so they are unit-tested without a backend; the two handlers that spawn claude (draft, work) are thin async wrappers over the shared engine + run_mission_loop.

Structs§

TicketRow
One row of the kranz ticket list table: the ticket plus its resolved terminal label (already split into DELIVERED/LANDED for a Done ticket).

Enums§

DraftDecision
What a draft turn resolved to, given the PlanRequest and whether --yes (auto-approve+enqueue) was passed. Separating the decision from the I/O keeps the state-machine unit-testable without a backend.
WorkAction
The dispatcher’s next action given the queue front and repo-busy state.

Functions§

cmd_decompose
kranz decompose <goal> [--yes]: one planner turn decomposes a complex goal into a blocked-by ticket DAG (design: .kranz/tickets/ ticket-dag-decomposition.md). The proposed DAG is always printed; tickets are written only with --yes (dry-run preview otherwise), all-or-none — any validation refusal (slug rules, unknown blocker, missing root, cycle) writes nothing.
cmd_draft
kranz draft <slug> [--yes] [--from-mission m-xxxx]: non-interactive plan drafting.
cmd_queue
kranz queue.
cmd_queue_remove
kranz queue --remove <mission-id>: retire only the runnable queue entry. The mission record remains append-only/auditable and may be abandoned or re-enqueued by the caller’s own lifecycle policy.
cmd_ticket_approve
Deprecated alias for cmd_ticket_queue. kranz ticket approve used to be the only spelling for ticket-queueing; D-A renamed it to queue and reserved “approve” for plan approval. Kept one release for compatibility.
cmd_ticket_list
kranz ticket list.
cmd_ticket_migrate_state
kranz ticket migrate-state [--yes]: the one-time fold of terminal .status sidecars into committed frontmatter state: keys (design ticket-state-frontmatter, rule 4). Dry-run by default — the report lists every fold it WOULD make plus the loud per-name skips — --yes applies. The fold logic and its skip rules live in kranz_engine::migrate_state; this wrapper only renders.
cmd_ticket_new
Scaffold .kranz/tickets/<slug>.md. Refuses (error) if a ticket with that slug already exists. Thin wrapper over Ticket::scaffold. Returns the written path.
cmd_ticket_queue
kranz ticket queue <slug> [--mission <id>]: enqueue the parked (Review) mission for the ticket and set the ticket Queued.
cmd_ticket_ready
kranz ticket ready [--include-deferred]: the pick-up-now listing (D-BW-3). Ready = an actionable pipeline state (not in flight, not terminal) AND no defer-until still in the future — a deferred ticket simply becomes listable on its day; the clock at listing time is the only arbiter, there is no scheduler. --include-deferred appends the parked deferred tickets with their defer times for operator visibility.
cmd_ticket_show
kranz ticket show <slug>.
cmd_work
kranz work [--once]: the dispatcher. Drains the per-repo queue one mission at a time; --once processes exactly one front entry (or exits if the repo is busy). Per-repo serialization is enforced by is_repo_busy.
draft_decision
Map a completed plan request + the --yes flag to the next action. Pure: the caller performs the git/state side effects the decision names.
next_work_action
Decide the dispatcher’s next step from the queue front + busy state. Pure: front is queue::peek, busy_with is queue::is_repo_busy.
render_migration_report
Render the fold report: one line per fold (or would-fold), one loud line per dirty skip, a line per ticket with a NON-terminal sidecar (pipeline state is left sidecar-owned by design), and a summary. No-sidecar tickets are summary-counted only — a line each would drown the signal.
render_queue
Render the kranz queue table: position, priority, mission id, ticket slug, plus a header noting whether the repo is currently busy.
render_ticket_list
Render the kranz ticket list table: slug, priority, state, title.
render_ticket_ready
Render the kranz ticket ready table: the ready rows in the same shape as render_ticket_list, then — only when include_deferred asked for it — a second table of the not-yet-ready deferred tickets with their defer times (D-BW-3: operator visibility without polluting the default listing).
render_ticket_show
Render kranz ticket show <slug>: the parsed ticket, its resolved terminal label, and any “needs context” / “wrong plan” block appended to the ticket body.
split_questions
Split the orchestrator’s “not ready” prose into individual questions: each non-empty line, with any leading bullet/number marker stripped. A reply with no line breaks becomes a single one-item list.
ticket_state_for_mission
Map a terminal (or blocked) mission status to the ticket state recorded after a run. Only called by reconcile_ticket_for_mission for terminal/blocked statuses — live statuses are gated out before this runs.
ticket_state_label
UPPERCASE label for a ticket pipeline state (mirrors mission status labels).
ticket_template
Back-compat wrapper (no context) over Ticket::ticket_template, which now lives in kranz-engine so the REST POST /api/tickets handler shares it instead of duplicating.
ticket_terminal_label
A ticket’s terminal-state label, splitting Done into DELIVERED (mission complete but its branch is not yet merged into base) vs LANDED (mission branch merged, or no mission-merge information to distinguish otherwise) — reusing the engine’s merged-ancestor probe (kranz_engine::merged::ticket_merged) so this can never drift from the REST /api/tickets projection. Non-Done states render exactly as ticket_state_label.
work_skip_for_failed_blocker
Work-time re-check for a claimed queue entry with a ticket: Some(blocker) when one of the ticket’s unsatisfied blocked-by entries is unsatisfied because that blocker’s own ticket ended up Failed (its mission reached a terminal non-Complete state — Failed/Abandoned/Blocked — after batch-approval queued this entry alongside it). The dispatcher must skip such an entry rather than run it: re-driving a mission whose dependency failed can never succeed, and retrying forever would hot-loop.