Skip to content

Tasks: the work item's record owns its pull requests

Phase 4 of 4. Derived from the locked design.md and testing-plan.md — each task's _Test:_ names a row of the matrix. Revised with the design after owner review on PR #173; T1–T8 below are the rebuild's tasks (the link-record version's tasks are in this file's git history).

Task list

mermaid
flowchart LR
  T1["T1 registry: pullRequests[] endpoints"] --> T2["T2 router: pr_work_item"]
  T1 --> T3["T3 dispatcher: match by record,<br/>deliver to endpoint, lazy spawn"]
  T2 --> T3
  T3 --> T4["T4 close: endpoint ends,<br/>record survives"]
  T1 --> T5["T5 config: sessionPerPr<br/>schema + docs"]
  T3 --> T6["T6 regression scenarios"]
  T4 --> T6
  T5 --> T7["T7 spec/decision/capability docs"]
  T3 --> T9["T9 the two loops:<br/>pdlc-work-item-loop + pdlc-pr-loop"]
  T6 --> T8["T8 verification + evidence"]
  T7 --> T8
  T9 --> T8
  • [x] T1 — the registry learns endpointscli/the_loop/sessions/registry.py: Session.pull_requests (+ endpoint_for/owns, one-level nesting and per-entry degradation in from_dict, absent-key round-trip in to_dict), and the verbs record_owning, session_for(ref, session_per_pr), link_pull_request, save_endpoint, close_endpoint, per-endpoint touch. Events session.pr_linked / session.pr_spawned / session.pr_closed / session.link_failed in eventlog.EVENT_TYPES. Requirements: R1.1–R1.6, R2.3, R2.4, R4.3Test: T1 (unit), T8 (abuse cases)

  • [x] T2 — the router names a PR's own refcli/the_loop/webhook/router.py: pr_work_item(event, payload), composed from the same helpers extract_work_items uses so the recorded ref cannot drift from the routed one. Requirements: R1.1, R1.5Test: T1 (unit)

  • [x] T3 — the dispatcher matches by record and delivers to the endpointcli/the_loop/webhook/dispatcher.py: handle() matches via record_owning; _record_pr_binding records the PR on each matched record (never on close); _endpoint_for picks the conversation per sessionPerPr; _spawn_endpoint gives a recorded PR its session lazily (no graph entry — R2.9) with fallback to the record; _dispatch_one delivers per endpoint with per-endpoint dedup and touch; respawn goes through save_endpoint. Poll path: delivery_status and has_session resolve through the record. Requirements: R1.1, R1.2, R2.1–R2.9Test: T2 (integration), T2b (poll path), T1 (resolver ordering)

  • [x] T4 — a PR closing ends its endpoint, not the record The close branch: a closed object that is a recorded PR of a still-open record → close_endpoint + tmux teardown for that endpoint (session.pr_closed), record kept (session.kept_open). A PR with its own record still auto-closes. Requirements: R3.1, R3.2Test: T2

  • [x] T5 — routing.tmux.sessionPerPr, declared and documented.the-loop/cli-config.schema.json (+ TmuxConfig.session_per_pr, default true) and docs/config/cli/routing-options.md. Sensitive path (**/*schema*): flagged for the owner's sign-off on the PR. Requirements: R2.1, R2.2Test: T10 (docs parity P3/P4, validate_config.py)

  • [x] T6 — the ticket's reproduction, as tests that fail without T3 Seven Gherkin-documented scenarios across test_webhook_routing_integration.py/test_poller.py: the linkage-removed sequence, both recording paths, the re-link both-records case, control-command resolution, both close cases, and the poll-path pair. All seven fail against a pre-fix resolver. Requirements: R5.1, R5.2Test: T2, T2b

  • [x] T7 — the paper trail, and the two-loop definitiondecision-064 rewritten (the reversal recorded, not erased); spec chain revised; docs/capabilities/webhook-triggers.md clause + history row; docs/cli/state.md session-record section; decision-065, the process-graph capability doc's two-loops behaviour, and the --pr section of the graph command page. (T7 originally scoped the loops as follow-up; the owner's second review round pulled them into this PR — they are T9.) Requirements: R4.1, R4.2, and the loop's same-PR capability-docs ruleTest: T11

  • [x] T9 — the two loops (decision-065) pdlc.yamlpdlc-work-item-loop.yaml (+ name:, + await-inner-loops on implementation); new pdlc-pr-loop.yaml; Graph.name + load_graph(name=…); the await-inner-loops hook (graph/hooks/loops.py) over pr-loops/*/graph-state.json; Runtime.state_subpath; graphlink on_pr_spawn/on_pr_event/pr_context/on_pr_close (merge → audited force to complete); dispatcher wiring (endpoint spawn enters the loop, endpoint events advance it, outer loop never advanced by PR events); --pr through CLI → core → API → the authored OpenAPI contract; P5 parity over both graphs. Requirements: R6.1–R6.6, R2.9Test: T12 (tests/test_graph_loops.py), T2 (wiring), parity P5

  • [x] T10 — the graph assigns: deliver-assignment (decision-065 D8) graph/hooks/assignment.py (render + push through a daemon-injected channel; skip without one; a failure never gates); on every non-terminal agent node's entry in both loops; GraphLink.assignment_sink binding the channel per loop; Dispatcher._deliver_assignment resolving the record or the PR's endpoint and pasting via tmux; graph.assignment_delivered/graph.assignment_failed in EVENT_TYPES. Requirements: R6.7Test: T12

  • [x] T8 — execute the testing plan and commit the evidence Every activity in testing-plan.md § Verification activities, including the seven-test negative run and the re-captured reproduction. Requirements: R5.1Test: T1, T2, T2b, T8, T10, T11

Released under the MIT License.