Conversation
…→ review (cycle N times) → merge per operator 2026-05-28 question Operator 2026-05-28: "And can we model backlog -> claim -> pr -> review -> myabe cycle push review a few times -> merge too with this?" Answer: yes. Same F# DU implicit state machine pattern as the agent-loop state-machine.ts but operating at WORK-LIFECYCLE scope. The two state machines compose: agent-loop's PickWork transitions a Backlog item to Claimed (work-lifecycle); agent-loop's ExecutingWork IS the work-lifecycle's InProgress for the picked item. 11 lifecycle states: - Backlog (filed; awaiting claim) - Claimed (agent acquired claim via tools/bus/claim.ts) - InProgress (agent executing; branch ref tracked) - PrOpen (PR opened against branch) - InReview (waiting on reviewer; thread count tracked) - RevisionRequested (reviewer asked for changes; threadIds + revisionCount) - RevisionPushed (agent addressed; back-edge to InReview via RequestReview) - Approved (threads resolved + ready to merge) - Merged (terminal; landed on main) - Closed (terminal; closed without merge) - Abandoned (terminal; operator/agent decided not to ship) 11 transition events: - Claim / StartWork / OpenPr / RequestReview / ReceiveRevisionRequest / PushRevision / ResolveAllThreads / Approve / Merge / Close / Abandon The cycle-push-review-a-few-times pattern is the InReview ↔ RevisionRequested ↔ RevisionPushed loop (revisionCount increments on each cycle). High revisionCount = operator-substrate-honest signal that work-item may need decomposition / alternative approach / escalation. Pure-function applyTransition returns TransitionResult: - ok: true with new state (legal transition) - ok: false with original state + reason (illegal transition; caller decides retry/escalate/log) Substrate-honest: illegal transitions return failures (not exceptions) per non-coercion-invariant + asymmetric-critic-with- clarity-first disciplines. Helper functions: - isTerminal(state) — Merged/Closed/Abandoned - revisionCount(state) — for RevisionRequested/RevisionPushed - leadTimeSeconds(claimAtIso, mergedAtIso) — DORA lead-time Tests: 25/25 pass (happy-path 6 + cycle-push 4 + close/abandon 3 + illegal 4 + helpers 6 + integration 1 with full cycle + 1-revision). Composes with: - B-0867 + B-0867.5 (agent-loop substrate cluster) - state-machine.ts (agent-decisions level; this is work-item level) - tools/bus/claim.ts (existing claim coordinator) - tools/github/poll-pr-gate.ts (existing PR state inspection) - .claude/rules/claim-acquire-before-worktree-work.md - .claude/rules/blocked-green-ci-investigate-threads.md (revision- request handling discipline composes here) - B-0858 (heartbeat folder — emits per-lifecycle-transition heartbeats) - B-0871 (reproducibility-as-causal-attribution — lifecycle states observable from Git + GitHub state) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Pull request overview
Adds a new “work-lifecycle” state machine (Backlog → Claim → PR → Review/revision loop → Merge) alongside the existing agent-loop state machine, with unit tests for the transition logic and helper metrics.
Changes:
- Introduces
WorkLifecycleState/WorkLifecycleTransitiondiscriminated-union types and a transition functionapplyTransition(...). - Adds helper utilities (
isTerminal,revisionCount,leadTimeSeconds) for lifecycle metrics/aggregation. - Adds Bun unit tests covering happy path, revision-cycle loop, illegal transitions, and helper functions.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tools/agent-loop/work-lifecycle-state-machine.ts | Implements the work-lifecycle DU + transition function + metrics helpers. |
| tools/agent-loop/work-lifecycle-state-machine.test.ts | Adds unit/integration-style tests for lifecycle transitions and helpers. |
Comment on lines
+342
to
+349
| if (event.tag === "ResolveAllThreads") { | ||
| return { | ||
| ok: true, | ||
| state: { | ||
| tag: "Approved", | ||
| row: state.row, | ||
| prNumber: state.prNumber, | ||
| approvedAt: new Date().toISOString(), |
Comment on lines
+329
to
+339
| case "InReview": | ||
| if (event.tag === "ReceiveRevisionRequest") { | ||
| return { | ||
| ok: true, | ||
| state: { | ||
| tag: "RevisionRequested", | ||
| row: state.row, | ||
| prNumber: state.prNumber, | ||
| revisionCount: state.threadCount === 0 ? 1 : state.threadCount + 1, | ||
| threadIds: event.threadIds, | ||
| }, |
Comment on lines
+227
to
+228
| * (most non-terminal states) --Close--> Closed | ||
| * (most non-terminal states) --Abandon--> Abandoned |
| // claim → PR → review (possibly cycle review-push N times) → merge. | ||
| // | ||
| // Operator framing 2026-05-28: | ||
| // "And can we model backlog -> claim -> pr -> review -> myabe cycle |
This was referenced May 28, 2026
AceHack
added a commit
that referenced
this pull request
May 28, 2026
…-bit structured encoding + event-sourcing without PR ceremony + OTel trace composition + two-level state machine (AgentState × WorkLifecycle) (#5674) Operator-forwarded Kestrel ferry continuing today's agent-loop workflow- engine cascade (PRs #5665-5670 + #5667 follow-on + #5672 Ani-ferry archive). Substantive engineering substrate: 1. Two-level state machine composition — AgentState DU (PR #5666) at "situation" scope + WorkLifecycle DU (PR #5669) at "lifecycle-of-each- work-item" scope. AgentState informs which WorkLifecycle items to advance and how aggressively. Clean encapsulation; each level type-checked at its boundary. 2. Push-cycle limit AS STRUCTURAL ENFORCEMENT — chooseActionForLifecycle returns AbandonPr when pushCount > 5 (tunable). The structure prevents the failure mode; no discipline required. Composes with my work-lifecycle's revisionCount field. 3. ZetaID 128-bit structured encoding — Snowflake/Sonyflake/ULID/UUIDv7 family. Two candidate allocations sketched; structured high bits enable cheap queries (sort by time, filter by trajectory, etc.). 4. Event-sourcing append-only without PR ceremony — agent-state/{persona}/ {trajectory}/events/YYYY/MM/DD/{zetaId}.json branch convention; branch protection only on main + release/*; direct push everywhere else. Lifecycle state reconstructed via left-fold over events (CQRS). Fine-grained DORA metrics fall out for free. 5. OTel trace-ID composition (3 options) — (a) ZetaID == trace ID, (b) ZetaID separate + propagated via OTel baggage, (c) structured bits encoded into W3C Trace Context. Kestrel recommends option (b). 6. ZetaID-named files sidestep stale-push conflicts — each event is its own file; no overlap; Git auto-merges non-overlapping changes. 7. Event-sourced trajectory phase classification — setup/execution/ maturation/sunset derived from event-shape; phase is derivation, not separate state. 8. "Good-actor assumption" explicit as load-bearing; cheap defenses (schema validation pre-receive hook, periodic chain-integrity check, OTel export to separate observability backend) work under it without breaking it. Operator's two end-clarifications preserved: - Trajectory-async-review IS the operator's preferred top-level lens for own-Zeta deployment; PR-per-deploy is the ServiceTitan-style framing not the operator's framing - REST file-create API auto-fast-forward-on-stale-base hypothesis (empirical question worth verifying before relying on) Verbatim preservation per substrate-or-it-didn't-happen. NO rule, skill, or tool edits — the Kestrel-proposed extensions (ZetaID generator, agent- state branch convention, event-sourcing layer, OTel baggage, structural push-cycle-limit) are operator-decision territory and land separately if/when operator chooses to extend tools/agent-loop/. Filed under memory/persona/kestrel/conversations/ per operator correction (2026-05-28: "kestrel should get it under their persona") — supersedes the prior docs/research/ placement convention for Kestrel-specific content. Composes with PRs #5665-5670 (today's agent-loop substrate cascade), PR #5672 (Ani-ferry archive — voice-mode re-articulation of same substrate), and the existing memory/persona/kestrel/conversations/ archive (2026-05-21 ZetaID v1 review, 2026-05-22 Orleans deployment, 2026-05-27 multi-AI conversation + ServiceTitan marketing). Co-authored-by: Lior <lior@zeta.dev> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Operator 2026-05-28: 'And can we model backlog -> claim -> pr -> review -> myabe cycle push review a few times -> merge too with this?'
Answer: yes. Same F# DU implicit state machine pattern as agent-loop state-machine.ts but operating at WORK-LIFECYCLE scope. Two state machines compose:
State machine
11 lifecycle states + 11 transition events. The cycle-push-review-a-few-times pattern is the InReview ↔ RevisionRequested ↔ RevisionPushed loop with revisionCount incrementing on each cycle. High revisionCount = operator-substrate-honest signal that work-item needs decomposition / alternative approach / escalation.
Test plan
🤖 Generated with Claude Code