T-0AKS-an-issues-loop-joins-the-runner-roadmap-tasks-and-issues
State: closed/done · Impact: medium · Complexity: medium
Add an issues loop to sdlc orchestrate run, so issues advance up to their autonomy ceiling
alongside roadmap tasks. Design: D-0019-sdlc-chain-stages-and-labels.
Approach
Section titled “Approach”- Extend
LOOP_NAMESinsolutions/ontological/lib/services/orchestrator/ops/run.tsfrom['work', 'prs', 'merges']to include'issues', and thread arunIssuesTickdependency throughrunPasses()the same wayrunWorkTick/runPrsTick/runMergesTickare already threaded (default from the real module; injectable in tests, same pattern the existing three ticks use). - Add
solutions/ontological/lib/services/orchestrator/ticks/issues.ts(runIssuesTick(ctx)), modeled onticks/work.ts’s structure but for GitHub issues instead of task frontmatter:- List open issues carrying any
sdlc:stage/<x>label (viactx.gh.issueList(...), from T-3YQO’s new easy-gh verbs — an issue with nosdlc:stage/*label is not chain-managed and is skipped). - Per issue: parse its current stage from the
sdlc:stage/<x>label (first/only match — two stage labels on one issue is a data error, log and skip); parse its ceiling fromsdlc:auto/<x>(default when absent: the ceiling equals the current stage — D-0019’s “silence means wait for a human” default, i.e. no auto-advance until triage or a human sets a ceiling label). - If the current stage’s index in
CHAIN_STAGE_NAMES(lib/config/chain.ts, from T-8JJE) is<the ceiling’s index: resolve the next stage’s bound workflow viaresolveChain(). A checkpoint stage (workflow: null) advances the label immediately with no dispatch. A bound stage dispatches via the existing step-runner (../step-runner.ts— no new dispatch mechanism); on success, relabel the issue to the next stage (ctx.gh.setIssueLabel, from T-3YQO); on failure, leave the issue at its current label and log (a “park” for issues, mirroring the work tick’s park-and-move-on behavior — no in-tick retry). One stage advance per issue per tick, matching a label-driven board moving one column at a time. - The
definestage’s dispatch also calls T-3YQO’sensureLinkedTask()before running thedefineworkflow, so an issue reachingdefinefor the first time gets its task link. - If the current stage already equals the ceiling: fire
stage.ceiling_reachedthrough the existingdeps.notifyseam (lib/services/notify/dispatch.ts’snotify()— the same functionwork.ts’snotifyParkedalready calls fortask.parked). Add'stage.ceiling_reached'to theNotifyEventunion (its own doc comment says “extend freely as later ticks/phases need new event kinds” —task.parkedalready set the precedent of a tick firing a Phase-8-named event ahead of Phase 8’s fullnotify:channel config). Full channel delivery (desktop/ntfy config) stays Phase 8’s; this phase only needs the event to fire and be visible in the pass’slog-tickdigest, exactly liketask.parkedis today. Then move on to the next issue — “blocked is not stopped”. - Respect
ctx.dryRun: report what would be dispatched/relabeled without calling any mutatingghverb, mirroringwork.ts’sclaim: 'would-dispatch'convention.
- List open issues carrying any
- Add
solutions/ontological/lib/services/orchestrator/ticks/issues.test.tsand.../ops/run.test.tscoverage: inject a fakectx.ghreturning a fixture list of open issues with labels (no realghcall, per External-write safety). Cover: an issue below ceiling advances exactly one stage; an issue at ceiling is skipped and logged, not advanced; a checkpoint-stage advance needs no workflow dispatch; a--loop issues --once --dry-runrun reports the would-be move without mutating any fixture state;--loop work,issues --oncedispatches both loops in one pass (no cross-loop interference).
| Area | Note |
|---|---|
solutions/ontological/lib/services/orchestrator/ops/run.ts | Extend LOOP_NAMES, thread runIssuesTick |
solutions/ontological/lib/services/orchestrator/ticks/issues.ts | New: the issues tick |
solutions/ontological/lib/services/orchestrator/ticks/issues.test.ts | New: fixture-backed tick tests |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
runIssuesTickgiven a fixture issue at stageimplementwith ceilingcheckadvances it tocheck(one stage) and dispatches thecheckworkflow’s bound step(s) via the step-runner. - AC-2: The same fixture issue, once at stage
checkwith ceilingcheck, is left unchanged by a subsequent tick (ceiling reached, logged, not advanced). - AC-3:
sdlc orchestrate run --loop issues --once(against a fixturectx.gh) advances at least one fixture issue exactly one stage and reports it in the pass’s log-tick digest. - AC-4:
sdlc orchestrate run --loop work,issues --oncedispatches both ticks in one pass with no shared-state interference (task dispatch counts and issue dispatch counts are independent). - AC-5: No test in this task’s suite calls a real
ghbinary — everyctx.ghis a fixture double.
Out of scope
Section titled “Out of scope”- The label vocabulary’s existence/management (
apply, T-WPBJ) and the issue-task linking/sync primitives themselves (T-3YQO) — this task only calls them. - A dedicated Phase-8
notify:config section/event catalog forstage.ceiling_reached— this task fires it through the existingnotify()seam (lib/services/notify/dispatch.ts), which already delivers for real over the two channelsorchestrator.notifyconfig gates (desktop/ntfy), same aswork-park/task.parkedtoday; it does not add a new channel or config surface of its own. - Cross-host lease coordination for issue dispatch analogous to the work tick’s slot lease
(
_op_lease.ts) — a single-host, single-loop-iteration assumption is acceptable for this phase’s scope; revisit if concurrent multi-host issue dispatch becomes a real requirement.
Dependencies
Section titled “Dependencies”solutions/ontological/lib/config/chain.ts(T-8JJE) forCHAIN_STAGE_NAMES/resolveChain.packages/ts/easy-gh’s new issue verbs andlib/services/issues/{link,mapping}.ts(T-3YQO).packages/ts/easy-gh’s new label verbs (T-WPBJ) forsetIssueLabel’s underlyingissue edit --add-label/--remove-labelcalls (label values come from T-WPBJ; label mutation on an issue is agh issue editcall added alongside T-3YQO’s issue verbs — coordinate so the two tasks don’t both add a conflictingsetIssueLabel-shaped method).