Skip to content

epic-reconcile

The coxswain dispatches epic-reconcile on a schedule, not on a ticket event: it compares an epic's board state against what its tickets' records actually show and proposes a correction where the two disagree. What lands is a reconciliation proposal, not a silent rewrite of the board.

epic-reconcile

lifecycle-propose scopes work into an epic. Nothing until now looked at whether the epic still describes reality afterwards, and epics drift: tickets get closed on the board and not in the epic, phases finish out of order, work gets added that nobody attached. An epic model that is only ever written and never checked degrades into a diagram of what someone once intended.

flowchart LR
    n0["compare<br/>step · 1"]
    n1["emit<br/>step · 2"]
    n0 --> n1
    style n0 fill:#f96,stroke:#333,stroke-width:2px
Node Step
compare 1
emit 2

epic-reconcile — specification

The feedback half of epics. lifecycle-propose scopes work into an epic; this checks whether the epic still describes reality afterwards. Strictly propose-only.

Epics drift in ordinary ways: a ticket gets closed on the board and not in the epic, a phase finishes out of order, work gets added that nobody attached. An epic model that is only ever written and never checked degrades into a diagram of what someone once intended.

Node Role Tier Notes
compare deterministic set arithmetic over declared vs observed
reconcile reconcile standard which differences are drift, and what corrects each
emit item_update / state_move proposals

Args: run_id, date, cartridge (resolved, required, no fallback), epic (the declared state), observed (the board's actual state).

Returns: {run_id, date, epic, divergences, reconcile, proposals[], totals}

Both sides arrive as arguments. A reconcile that fetches its own "actual" cannot be replayed, and a drift report you cannot replay is one you cannot argue with.

Why the comparison is not a model call

compare is set arithmetic, and it runs before the model sees anything. A node asked "what drifted?" will produce a plausible answer whether or not anything did; a set difference will not. The reconcile node then reasons only about differences that are already established fact, and a correction naming a ticket the comparison never flagged is refused rather than proposed — the node does not get to invent drift.

When nothing has drifted, no model call happens at all. Asking a model to confirm that nothing happened is a good way to be told that something did.

correction: none is a first-class answer. Not every difference is drift; some are legitimate, and a reconcile pass that cannot say so trains people to ignore it.

Requires the optional reconcile role. A team that has not bound it is told so, rather than silently getting a graph that does nothing.

Status: implemented in epic_reconcile.py.