Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,13 @@ are closed (status: closed in frontmatter)._
- [ ] **[B-0864](backlog/P2/B-0864-streams-are-relationships-four-corner-ownership-push-pull-hot-cold-fsharp-ce-machinery-protocol-typing-multi-backend-execution-2026-05-27.md)** Streams-are-relationships — four-corner ownership across the push/pull × hot/cold matrix; F# CE surface syntax with kind-specific builders; protocol-typing for co-owned TInFeedback; multi-backend execution (CRDT/CAS/BFT/SQL/DBSP) — getting base primitives right (operator + Kestrel 2026-05-27)
- [ ] **[B-0865](backlog/P2/B-0865-zeta-instantiation-of-arc-agi-3-style-benchmark-usb-boot-starting-state-devops-objectives-as-levels-not-hand-crafted-video-game-levels-aaron-2026-05-27.md)** Zeta instantiation of ARC-AGI-3-style benchmark — USB-boot as starting state; DevOps objectives as the "levels" (NOT hand-crafted video-game-grid levels like canonical ARC); agents go through real operational substrate (operator 2026-05-27)
- [ ] **[B-0866](backlog/P2/B-0866-marketing-business-naming-ai-weigh-in-on-b-0865-public-positioning-servicetitan-primary-audience-24-months-ahead-mandate-context-aaron-2026-05-27.md)** Marketing + business + naming-AI weigh-in on B-0865 public-positioning — ServiceTitan SRE primary audience + C-level secondary + 24-months-ahead-in-AI mandate context (operator + Kestrel 2026-05-27)
- [ ] **[B-0867.16](backlog/P2/B-0867.16-two-level-state-machine-composition-agentstate-x-worklifecycle-kestrel-2026-05-28.md)** Two-level state machine composition — AgentState × WorkLifecycle (situation-scope × lifecycle-scope)
- [ ] **[B-0867.17](backlog/P2/B-0867.17-push-cycle-limit-as-structural-enforcement-not-discipline-kestrel-2026-05-28.md)** Push-cycle limit AS STRUCTURAL enforcement — chooseActionForLifecycle returns AbandonPr when revisionCount > N (tunable threshold)
- [ ] **[B-0867.2](backlog/P2/B-0867.2-git-append-only-state-persist-typescript-tool-event-sourcing-layer-kestrel-2026-05-28.md)** Git append-only state-persist TypeScript tool — event-sourcing layer for agent-loop substrate (per parent B-0867 allocation)
- [ ] **[B-0871](backlog/P2/B-0871-zetaid-v2-128-bit-structured-encoding-snowflake-ulid-family-kestrel-2026-05-28.md)** ZetaID v2 — 128-bit structured encoding (Snowflake/ULID family with timestamp + trajectory + persona + lifecycle-stage + random)
- [ ] **[B-0872](backlog/P2/B-0872-otel-trace-id-composition-with-zetaid-baggage-propagation-kestrel-2026-05-28.md)** OTel trace-ID composition with ZetaID — baggage propagation alongside W3C Trace Context for agent-loop events
- [ ] **[B-0873](backlog/P2/B-0873-trajectory-async-review-surface-operator-preferred-top-level-lens-aaron-2026-05-28.md)** Trajectory-async-review surface — operator's preferred top-level lens for own-Zeta deployment (not PR-per-deploy)
- [ ] **[B-0874](backlog/P2/B-0874-github-actions-recursion-as-infinite-runtime-platform-no-pr-swarm-mode-ani-kestrel-2026-05-28.md)** GitHub Actions recursion as infinite runtime platform — no-PR swarm-mode for agent-loop substrate (Microsoft-subsidizes-OSS hack)

## P3 — convenience / deferred

Expand Down Expand Up @@ -935,5 +942,7 @@ are closed (status: closed in frontmatter)._
- [ ] **[B-0788](backlog/P3/B-0788-agent-on-agent-claude-code-session-recovery-lift-operator-runs-gate-once-zeta-safety-substrate-stronger-than-classifier-2026-05-25.md)** Agent-on-agent Claude Code session recovery — lift operator-runs gate for `--apply` once Zeta safety substrate stronger than classifier
- [ ] **[B-0830](backlog/P3/B-0830-add-iso-release-attach-to-build-ai-cluster-iso-workflow-when-zeta-starts-tagging-releases-aaron-2026-05-26.md)** Add ISO release-attach to build-ai-cluster-iso.yml workflow when Zeta starts tagging releases
- [ ] **[B-0860](backlog/P3/B-0860-nemerle-dotnet-support-macro-metaprogramming-complement-fsharp-type-providers-relationship-type-inference-substrate-aaron-2026-05-27.md)** Nemerle support for dotnet substrate — compile-time macro metaprogramming complementing F# type providers; enables language-native relationship-type-inference substrate (Aaron 2026-05-27)
- [ ] **[B-0867.18](backlog/P3/B-0867.18-event-sourced-trajectory-phase-classification-derived-from-events-kestrel-2026-05-28.md)** Event-sourced trajectory phase classification — setup/execution/maturation/sunset derived from event log (no separate state tracking)
- [ ] **[B-0867.19](backlog/P3/B-0867.19-rest-file-create-auto-fast-forward-on-stale-base-empirical-verification-spike-aaron-2026-05-28.md)** REST file-create auto-fast-forward on stale base — empirical verification spike (operator hypothesis 2026-05-28)

<!-- END AUTO-GENERATED -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
id: B-0867.16
priority: P2
status: open
title: Two-level state machine composition — AgentState × WorkLifecycle (situation-scope × lifecycle-scope)
effort: S
ask: kestrel via aaron 2026-05-28
created: 2026-05-28
last_updated: 2026-05-28
depends_on:
- B-0867
composes_with:
- B-0867
tags:
- two-level-state-machine
- agentstate-situation-scope
- worklifecycle-lifecycle-scope
- high-informs-low-composition
- mainbroken-prioritizes-fix-lifecycles
- explorationopportunity-claims-setup-trajectories
- stableexecution-advances-toward-merge
- composes-pr-5666-state-machine-with-pr-5669-work-lifecycle
- potential-extension-not-committed
---

## What this row tracks

Compose the two state machines shipped today (AgentState DU in PR #5666 / `tools/agent-loop/state-machine.ts`; WorkLifecycle DU in PR #5669 / `tools/agent-loop/work-lifecycle-state-machine.ts`) so AgentState informs which WorkLifecycle items to advance and how aggressively.

Per Kestrel 2026-05-28: *"AgentState informs which WorkLifecycle items to advance and how aggressively. When MainBroken state fires, the agent prioritizes lifecycle items that fix main. When ExplorationOpportunity fires, the agent claims unclaimed items in setup-phase trajectories. When StableExecution fires, the agent advances in-progress lifecycles toward merge."*

## Composition pattern

```typescript
async function runFullLoop(): Promise<void> {
while (true) {
const agentState = computeAgentState(/* ... */);
const relevantLifecycles = filterLifecyclesByState(agentState);
for (const lifecycle of relevantLifecycles) {
const action = chooseActionForLifecycle(lifecycle);
await applyAction(lifecycle, action);
}
await sleep(cycleDelayForState(agentState));
}
}
```

## Acceptance criteria

- `tools/agent-loop/compose.ts` exposes `runFullLoop(deps)` implementing the two-level pattern
- `filterLifecyclesByState(agentState, allLifecycles)` returns a prioritized list per AgentState case
- `cycleDelayForState(agentState)` returns appropriate sleep duration (e.g., MainBroken = 0ms; StableExecution = 5s)
- Tests cover: each AgentState case routes to the correct subset of lifecycles; cycle delay matches state; full-loop completes one iteration deterministically

## Substrate-honest framing

POTENTIAL extension per operator standing direction. Small surface; mostly composition of existing pieces.

## Full reasoning

`memory/persona/kestrel/conversations/2026-05-28-kestrel-zetaid-128bit-structured-encoding-event-sourcing-without-pr-ceremony-otel-trace-composition-two-level-state-machine-aaron-forwarded.md` § "The composition with the earlier state machine"
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
id: B-0867.17
priority: P2
status: open
title: Push-cycle limit AS STRUCTURAL enforcement — chooseActionForLifecycle returns AbandonPr when revisionCount > N (tunable threshold)
effort: XS
ask: kestrel via aaron 2026-05-28
created: 2026-05-28
last_updated: 2026-05-28
depends_on:
- B-0867
composes_with:
- B-0867
- B-0867.16
tags:
- push-cycle-limit
- structural-enforcement-not-discipline
- revisioncount-already-tracked-by-work-lifecycle
- abandonment-as-normal-operation
- prevents-pr-cycle-loop-failure-mode
- threshold-tunable-default-5
- composes-with-pr-5669-work-lifecycle
- potential-extension-not-committed
---

## What this row tracks

Extend `tools/agent-loop/work-lifecycle-state-machine.ts` (PR #5669) with a `chooseActionForLifecycle` helper that:

- Examines current `WorkLifecycleState`
- Returns the next legal `WorkLifecycleTransition` based on state + thresholds
- When `state.tag === "RevisionPushed"` and `state.revisionCount > N` → returns `Abandon` with `reason: "review-concerns-too-many-to-address"`

The structural enforcement (chooseActionForLifecycle ALWAYS returns abandonment past threshold) prevents the failure mode where a PR cycle consumes arbitrary effort. Per Kestrel 2026-05-28: *"The push limit is enforced by the type system through the state machine — the loop literally cannot push more than the limit because the chooseActionForLifecycle function returns abandonment instead of another push once the threshold is reached. No discipline required; the structure prevents the failure mode."*

## Acceptance criteria

- `chooseActionForLifecycle(state, config)` function in work-lifecycle-state-machine.ts
- Config includes `maxRevisionCount: number` (default 5; tunable)
- Returns `{action: WorkLifecycleTransition, reason: string}` per state
- For `state.tag === "RevisionPushed"` with `revisionCount > maxRevisionCount`: returns `{action: "Abandon", reason: "review-concerns-too-many"}`
- For all other lifecycle states: returns the natural next-transition per existing transition table
- Tests cover: each state's natural-next-action; threshold-crossing produces Abandon; threshold-at-boundary produces normal action

## Composes with

- Existing `revisionCount` field on WorkLifecycleState (already shipped in PR #5669)
- B-0867.16 (two-level composition) — chooseActionForLifecycle is the work-lifecycle-level decision function called by runFullLoop

## Substrate-honest framing

POTENTIAL extension per operator standing direction. Smallest of the bundle; pure addition; backward-compatible (no existing API changes).

## Full reasoning

`memory/persona/kestrel/conversations/2026-05-28-kestrel-zetaid-128bit-structured-encoding-event-sourcing-without-pr-ceremony-otel-trace-composition-two-level-state-machine-aaron-forwarded.md` § "The push-cycle limit specifically as a feature"
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
id: B-0867.2
priority: P2
status: open
title: Git append-only state-persist TypeScript tool — event-sourcing layer for agent-loop substrate (per parent B-0867 allocation)
effort: M
ask: aaron 2026-05-27 (parent allocation) + kestrel 2026-05-28 (architectural detail)
created: 2026-05-28
last_updated: 2026-05-28
depends_on:
- B-0867
composes_with:
- B-0867
- B-0858
- B-0871
- B-0872
- B-0867.14
tags:
- event-sourcing
- append-only-git-persistence
- agent-state-branches
- no-pr-ceremony
- lifecycle-reconstruction-via-left-fold
- cqrs-pattern
- zetaid-named-files-no-conflict
- parent-allocated-subdecimal
- potential-extension-not-committed
---

## What this row tracks

The B-0867.2 slot allocated by the parent workflow-engine row. Kestrel 2026-05-28 ferry sketched the architectural detail.

Branch convention:

```text
main — PR required, full review
release/* — PR required
agent-state/{persona}/{trajectory}/... — direct push, no PR
agent-events/{date}/... — direct push, no PR
```

Event file path: `agent-state/{persona}/{trajectory}/events/YYYY/MM/DD/{zetaId}.json`

## Acceptance criteria

- `tools/agent-loop/events/append.ts` exposes `appendEvent(event)` that:
- Computes branch + path from event's persona + trajectory + ZetaID
- Direct-pushes new file to the agent-state branch (no PR)
- Returns the resulting commit SHA + push receipt
- `tools/agent-loop/events/read.ts` exposes:
- `readEventsForLifecycle(zetaId)` — walks the previous_zeta_id chain backward to reconstruct full history
- `readEventsForTrajectory(trajectoryId)` — reads all events under a trajectory's branch in time order
- `readEventsForPersona(persona, sinceIso)` — reads all events authored by a persona
- `tools/agent-loop/events/reconstruct.ts` exposes `reconstructLifecycle(events)` — left-fold over events producing current WorkLifecycle state
- Event schema validated in pre-receive hook (cheap defense per good-actor model)
- Tests cover: append-read round-trip, chain reconstruction, concurrent writes via ZetaID-named files, schema validation rejection of malformed events

## Composes with

- B-0867.14 (branch protection: path-scoped append-only carve-out) — required for direct-push semantics
- B-0871 (ZetaID v2) — events use ZetaIDs as primary keys + filenames
- B-0872 (OTel composition) — events carry trace_id + span_id
- B-0858 (heartbeat folder substrate) — heartbeat events are one event_type; this layer generalizes the pattern

## Substrate-honest framing

POTENTIAL extension per operator 2026-05-28 standing direction. Filed for prioritization; the parent B-0867 row pre-allocated this slot but the row file did not exist until this filing.

## Full reasoning

`memory/persona/kestrel/conversations/2026-05-28-kestrel-zetaid-128bit-structured-encoding-event-sourcing-without-pr-ceremony-otel-trace-composition-two-level-state-machine-aaron-forwarded.md` § "The state storage pattern" + § "Reconstructing lifecycle state from events"
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
id: B-0871
priority: P2
status: open
title: ZetaID v2 — 128-bit structured encoding (Snowflake/ULID family with timestamp + trajectory + persona + lifecycle-stage + random)
effort: M
ask: kestrel via aaron 2026-05-28
created: 2026-05-28
last_updated: 2026-05-28
depends_on:
- B-0867
composes_with:
- B-0867
- B-0858
- B-0869
- B-0871-prior-zetaid-v1-review
tags:
- zetaid-v2
- 128-bit-structured-encoding
- snowflake-ulid-uuidv7-family
- timestamp-trajectory-persona-lifecycle-stage-randomness
- cache-friendly-prefix-queries
- cheap-sort-by-time
- cheap-filter-by-trajectory
- composes-with-event-sourcing
- composes-with-otel-trace-id
- potential-extension-not-committed
---

## Operator framing 2026-05-28

> *"if you imagine we have good actors right now and even zetaids that are unique 128 bit where part of the bits can repersent anyting like trajectories are personas as long as there is enough for time and randomness to not collide"*

## What this row tracks

Implementation of a 128-bit structured ID generator for Zeta agent-loop substrate. Some bits encode meaningful structure (trajectory, persona, lifecycle-stage); remaining bits provide collision-resistant randomness; structured high bits enable cheap prefix queries (sort by time, filter by trajectory).

## Candidate bit allocations (per Kestrel ferry 2026-05-28)

**Option A** — microsecond timestamp, more random:

```text
Bits 0-63 (64 bits): Timestamp (microsecond Unix epoch)
Bits 64-79 (16 bits): Trajectory identifier (65k trajectories)
Bits 80-87 (8 bits): Persona identifier (256 agents)
Bits 88-95 (8 bits): Lifecycle stage (256 stages)
Bits 96-127 (32 bits): Random
```

**Option B** — millisecond timestamp, more random:

```text
Bits 0-47 (48 bits): Timestamp (millisecond Unix epoch — ~8900 years)
Bits 48-63 (16 bits): Trajectory
Bits 64-71 (8 bits): Persona
Bits 72-79 (8 bits): Lifecycle stage
Bits 80-127 (48 bits): Random
```

Choice depends on query patterns. Final allocation deferred to implementation; both candidates valid.

## Acceptance criteria

- `tools/agent-loop/zeta-id.ts` exports `generateZetaID({trajectory, persona, lifecycle_stage})` returning 128-bit value as 26-char Crockford base32 string (ULID-compatible) OR hex string
- Pure function; deterministic given (timestamp, structured-bits, random-source)
- Tests cover: time-ordering preservation under sort, no-collision under 1M generated in same microsecond, structured-bit extraction
- Composes with event-sourcing layer (B-0867.2) — events use ZetaID as primary key
- Composes with OTel trace-ID composition (B-0872) — baggage carries ZetaID alongside trace-ID
- Composes with prior ZetaID v1 review work preserved at `memory/persona/kestrel/conversations/2026-05-21-aaron-kestrel-claudeai-zeta-id-v1-review-...md` — this row is the v2 extension

## Scope

This row is the GENERATOR ONLY. The branch-protection rules, agent-state branch convention, and event-sourcing read/write layer are tracked in sibling rows (B-0867.2, B-0867.14 from parent B-0867).

## Substrate-honest framing

POTENTIAL extension per operator 2026-05-28: *"all extension should be backloged and looked at as potential."* Not committed; not yet picked up. Filed for prioritization.

## Full reasoning

`memory/persona/kestrel/conversations/2026-05-28-kestrel-zetaid-128bit-structured-encoding-event-sourcing-without-pr-ceremony-otel-trace-composition-two-level-state-machine-aaron-forwarded.md` (verbatim ferry; PR #5674)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
id: B-0872
priority: P2
status: open
title: OTel trace-ID composition with ZetaID — baggage propagation alongside W3C Trace Context for agent-loop events
effort: M
ask: kestrel via aaron 2026-05-28
created: 2026-05-28
last_updated: 2026-05-28
depends_on:
- B-0871
- B-0867
composes_with:
- B-0867
- B-0871
- B-0869
tags:
- opentelemetry
- otel-baggage-propagation
- w3c-trace-context
- trace-id-128-bit
- zetaid-otel-link
- observability-layer
- three-options-recommended-baggage
- composes-with-zetaid-v2
- composes-with-event-sourcing
- potential-extension-not-committed
---

## What this row tracks

Wire OpenTelemetry trace-IDs through the agent-loop substrate so every state-machine transition + every WorkLifecycle event carries observability context. Per Kestrel 2026-05-28 ferry, three options were sketched:

| Option | Description | Tradeoff |
|---|---|---|
| **A** | ZetaID == OTel trace-ID (use trace-ID as ZetaID directly) | Composes natively with OTel tooling; loses queryable-structured-bits property |
| **B** (recommended) | ZetaID separate; propagate via OTel baggage alongside trace-ID | ZetaIDs queryable by structure; traces queryable by trace-ID; linked via baggage |
| **C** | Encode structured bits into W3C Trace Context trace-ID itself | Composes most cleanly; requires care around W3C validity (no all-zero, no all-ones) |

## Acceptance criteria

- `tools/agent-loop/otel.ts` exposes `withTrace(zetaId, fn)` helper that:
- Creates/joins a W3C Trace Context for the current operation
- Sets baggage entries linking `zetaId` → current trace
- Runs `fn` within the trace scope
- Every event emitted via `appendEvent` (B-0867.2) carries both `zeta_id` AND `trace_id` + `span_id`
- `@opentelemetry/api` integrated as TS dependency; OTLP exporter configurable via env
- Tests cover: baggage propagation across async boundaries; trace-ID extraction from agent-loop events; round-trip ZetaID ↔ trace-ID linkage
- README documents the three options + why Option B was selected

## Scope

This row is the OTEL WIRING ONLY. ZetaID generation lives in B-0871; event-sourcing in B-0867.2; observability backend selection is operator-decision.

## Substrate-honest framing

POTENTIAL extension per operator 2026-05-28 standing direction. Not committed; filed for prioritization.

## Full reasoning

`memory/persona/kestrel/conversations/2026-05-28-kestrel-zetaid-128bit-structured-encoding-event-sourcing-without-pr-ceremony-otel-trace-composition-two-level-state-machine-aaron-forwarded.md` § "OTel trace IDs travelling along"
Loading
Loading