<feed xmlns='http://www.w3.org/2005/Atom'>
<title>claudomator.git/internal/scheduler/story_orchestrator_test.go, branch main</title>
<subtitle>claudomator — task automation server
</subtitle>
<id>https://git.terst.org/claudomator.git/atom?h=main</id>
<link rel='self' href='https://git.terst.org/claudomator.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/'/>
<updated>2026-07-11T05:38:25+00:00</updated>
<entry>
<title>fix(scheduler): make arbitration fail-closed on a missing verdict, seed planner's system prompt</title>
<updated>2026-07-11T05:38:25+00:00</updated>
<author>
<name>Peter Stone</name>
<email>thepeterstone@gmail.com</email>
</author>
<published>2026-07-11T05:37:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=204fe6c536d5d3bca2cb712f66b1d63054807dac'/>
<id>urn:sha1:204fe6c536d5d3bca2cb712f66b1d63054807dac</id>
<content type='text'>
A live production run (2026-07-11) showed finalizeArbitration's 'no
verdict reported = approve' default silently shipping work an evaluator
had already flagged as factually wrong -- the arbitration agent never
called report_verdict because the planner role had no system prompt
telling it to. finalizeArbitration now treats a missing verdict the same
as an explicit rejection (fail-closed), and SeedRoleConfigs now also
seeds planner with a prompt that explicitly mandates calling
report_verdict before finishing.
</content>
</entry>
<entry>
<title>refactor(scheduler): migrate story fix loop off RootTaskID re-pointing onto CurrentAttempt resolution</title>
<updated>2026-07-10T20:06:20+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator.local</email>
</author>
<published>2026-07-10T20:06:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=34380da06b1b0f2088f83c1edcb0b506e3196cca'/>
<id>urn:sha1:34380da06b1b0f2088f83c1edcb0b506e3196cca</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor(scheduler): recurse processStory into a tree walk over every READY builder-role node</title>
<updated>2026-07-10T19:29:58+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator.local</email>
</author>
<published>2026-07-10T19:29:58+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=c812eeac49f5ebbcf8b9855a3f56ac4940e074d8'/>
<id>urn:sha1:c812eeac49f5ebbcf8b9855a3f56ac4940e074d8</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor(scheduler): generalize finalizeArbitration to any builder-role node, add nested fix-attempt spawning and acceptance-criteria fallback</title>
<updated>2026-07-10T05:49:36+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator.local</email>
</author>
<published>2026-07-10T05:49:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=063a6c1661a91370e2f70d7fab670acd09561619'/>
<id>urn:sha1:063a6c1661a91370e2f70d7fab670acd09561619</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor(scheduler): promote story root to COMPLETED only after arbitration approves it, not eagerly on READY</title>
<updated>2026-07-10T00:49:10+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator.local</email>
</author>
<published>2026-07-10T00:49:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=dba9c2e0293f7dd0a4c08d9516df1c7f473c6d8f'/>
<id>urn:sha1:dba9c2e0293f7dd0a4c08d9516df1c7f473c6d8f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor(scheduler): migrate story fix loop off RootTaskID re-pointing onto CurrentAttempt resolution</title>
<updated>2026-07-09T19:45:21+00:00</updated>
<author>
<name>Agent</name>
<email>agent@claudomator</email>
</author>
<published>2026-07-09T19:45:21+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=a90ac76f3ccf0bf1259b7ef45e5f331d2b4ec26f'/>
<id>urn:sha1:a90ac76f3ccf0bf1259b7ef45e5f331d2b4ec26f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(scheduler): automatically spawn and re-point a fix attempt when a story is rejected</title>
<updated>2026-07-09T01:51:47+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator</email>
</author>
<published>2026-07-09T01:51:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=ef22ba51d426690cb500aad6fdce0db92bba7f72'/>
<id>urn:sha1:ef22ba51d426690cb500aad6fdce0db92bba7f72</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(scheduler): finalizeArbitration consults a structured verdict instead of always routing to REVIEW_READY</title>
<updated>2026-07-08T09:43:25+00:00</updated>
<author>
<name>Claudomator Agent</name>
<email>agent@claudomator</email>
</author>
<published>2026-07-08T09:43:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=c82def744f23d09562f0bd980ee8333eeb1b90e4'/>
<id>urn:sha1:c82def744f23d09562f0bd980ee8333eeb1b90e4</id>
<content type='text'>
</content>
</entry>
<entry>
<title>feat(story,role): add retro ceremony -- closes the self-improvement loop (Phase 8)</title>
<updated>2026-07-04T05:05:36+00:00</updated>
<author>
<name>Claude Sonnet 5</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-07-04T05:05:36+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=8cb291ad7cdb317ff80947278ee055b1a4925b41'/>
<id>urn:sha1:8cb291ad7cdb317ff80947278ee055b1a4925b41</id>
<content type='text'>
The final mechanism the versioned role-config model (Phase 5) was built for:
when a story reaches DONE, StoryOrchestrator spawns a retro-role task that
reflects on the story's full history and proposes draft role_configs
versions for a human to review and activate via the existing (unchanged)
POST /api/roles/{role}/activate.

- AgentChannel gains a 6th method, ProposeRoleConfig(ctx, role.RoleConfig)
  (version, err), following ProposeEpic's precedent (Phase 7c): a structured
  tool call, not summary-parsing. storeChannel.ProposeRoleConfig calls the
  same Store.CreateRoleConfig the human-facing POST /api/roles/{role}/versions
  endpoint already uses (proposed_by: "retro"), landing a new draft row
  without touching whatever's currently active. Wired through both
  transports exactly like ProposeEpic: internal/agentloop/tools.go (native
  loop) and internal/executor/agentmcp.go (MCP).
- StoryOrchestrator.Tick now routes a story at status DONE to a new
  processRetro stage instead of processStory -- a sibling stage, not a
  continuation, since the Builder-&gt;Evaluators-&gt;Arbitration chain is long
  settled by then. processRetro only *reads* that settled pipeline
  (read-only findEvaluators/findArbitration counterparts to
  ensureEvaluators/ensureArbitration -- it never spawns/mutates
  Builder-pipeline tasks) to locate the Arbitration task the retro task
  depends on, then spawns (idempotently -- checks for an existing
  retro-role dependent first) one retro-role task with instructions
  assembled from the story's spec/acceptance-criteria, full task tree, per-
  task cost/escalation history, active role_configs per role encountered,
  and the story's own event stream (evaluator verdicts, arbitration
  decision).
- event.KindRetroCaptured (attached to the story's ID, matching
  KindEvalVerdict/KindArbitrationDecided's convention) fires once the retro
  task completes (auto-accepted like every other pipeline task), aggregating
  every event.KindRoleConfigProposed the retro task recorded (one per
  propose_role_config call) into {task_id, proposals: [{role, version}],
  summary} -- the summary is the "capturing lessons" half of this ceremony,
  the proposals are the versioned-config half.
- Human activation is completely untouched: drafts land through the
  identical CreateRoleConfig/config_json path Phase 5's endpoints already
  handle, confirmed via existing role-endpoint tests passing unmodified.

go build/vet/test -race -count=1 all pass, full suite (20 packages) -- one
run hit a known, pre-existing, intermittent flake under full-suite load
(unrelated to this phase's files) that did not reproduce on two immediate
reruns, both in isolation and full-suite.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01V1moSNCJRcP6kykA4tyUSs
</content>
</entry>
<entry>
<title>feat(story): add StoryOrchestrator -- Builder-&gt;Evaluators-&gt;Arbitration-&gt;accept (Phase 7b)</title>
<updated>2026-07-04T04:08:41+00:00</updated>
<author>
<name>Claude Sonnet 5</name>
<email>noreply@anthropic.com</email>
</author>
<published>2026-07-04T04:08:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.terst.org/claudomator.git/commit/?id=e4087a7dc133fe8c8523ca585b1841ff2b0be2d9'/>
<id>urn:sha1:e4087a7dc133fe8c8523ca585b1841ff2b0be2d9</id>
<content type='text'>
A deterministic, poll-based watcher (internal/scheduler.StoryOrchestrator,
sibling to the Phase 5 Scheduler) that drives a story.Story through its
execution pipeline, rather than relying on an LLM agent to correctly
orchestrate its own fan-out via tool calls.

Mechanism: polling, not a handleRunResult hook. Every task the orchestrator
watches (a story's root/Builder task, 4 Evaluators, Arbitration) is
top-level (no ParentTaskID), and executor.Pool.handleRunResult only ever
lands a top-level task at READY or BLOCKED -- never COMPLETED directly, since
that transition normally requires a human/chatbot POST /api/tasks/{id}/accept
in a different package. A handleRunResult hook would never observe it;
polling doesn't care how/whether a task reached a given state.

Stages: Builder COMPLETED -&gt; spawn 4 role-typed Evaluator tasks
(evaluator_quality/security/correctness/performance, DependsOn: [builder],
no ParentTaskID -- true DAG siblings, not delegated subtasks) + story -&gt;
VALIDATING. Each Evaluator COMPLETED -&gt; emit KindEvalVerdict (attached to
the story's ID, so one GET /api/stories/{id}/events call surfaces every
verdict). All 4 Evaluators COMPLETED -&gt; spawn 1 Arbitration task
(role: planner, DependsOn: all 4 evaluator IDs). Arbitration COMPLETED -&gt;
emit KindArbitrationDecided, story -&gt; REVIEW_READY. POST
/api/stories/{id}/accept (mirrors handleAcceptTask) -&gt; DONE, emits
KindHumanAccepted.

Fixes a gap caught before merging: since none of Builder/Evaluators/
Arbitration have a ParentTaskID, none of them auto-complete -- each would
otherwise need a separate manual /api/tasks/{id}/accept, meaning 6 human
clicks per story before ever reaching the intended single story-level gate.
StoryOrchestrator.autoAccept now transitions each of these specific tasks
READY-&gt;COMPLETED itself (via the same validated Store.UpdateTaskState path
acceptTask uses), scoped only to tasks already established as part of a
story's pipeline (root task, or role-matched dependents from
ensureEvaluators/ensureArbitration) -- never a blanket sweep of unrelated
READY tasks. This makes POST /api/stories/{id}/accept the system's only
required human touchpoint for the whole chain, matching the design goal
that story (not task/subtask) is the human-interaction atom.

Idempotency: structural for task-creation stages (ensureEvaluators/
ensureArbitration check ListDependents for already-existing role-matched
tasks before creating -- crash/restart-safe); story.Status=="VALIDATING"
gates the Arbitration-&gt;REVIEW_READY write (nothing further downstream to
check structurally there); an in-memory handledVerdicts set (mirrors
Scheduler.handled) dedupes per-evaluator KindEvalVerdict emission across
poll ticks, resetting harmlessly on restart.

Documented simplification: finalizeArbitration never parses the Arbitration
summary for approve/reject -- always routes to REVIEW_READY; NEEDS_FIX is
manually settable via PUT /api/stories/{id}. A later phase could close this
with a dedicated verdict-reporting AgentChannel method instead of parsing
free text.

go build/vet/test -race -count=1 all pass, full suite (20 packages).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01V1moSNCJRcP6kykA4tyUSs
</content>
</entry>
</feed>
