docs: reorganize documentation into concepts, design, and examples
Move documentation files into a clearer structure: - concepts/: core ideas (convoy, identity, molecules, polecat-lifecycle, propulsion) - design/: architecture and protocols (architecture, escalation, federation, mail, etc.) - examples/: demos and tutorials (hanoi-demo) - overview.md: renamed from understanding-gas-town.md Remove outdated/superseded docs and update reference.md. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Steve Yegge
parent
8ed31e9634
commit
88f784a9aa
@@ -223,4 +223,4 @@ Use rig status for "what's everyone in this rig working on?"
|
|||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
- [Propulsion Principle](propulsion-principle.md) - Worker execution model
|
- [Propulsion Principle](propulsion-principle.md) - Worker execution model
|
||||||
- [Mail Protocol](mail-protocol.md) - Notification delivery
|
- [Mail Protocol](../design/mail-protocol.md) - Notification delivery
|
||||||
@@ -154,6 +154,50 @@ gt mol squash # Squash attached molecule
|
|||||||
gt mol step done <step> # Complete a molecule step
|
gt mol step done <step> # Complete a molecule step
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Polecat Workflow
|
||||||
|
|
||||||
|
Polecats receive work via their hook - a pinned molecule attached to an issue.
|
||||||
|
They execute molecule steps sequentially, closing each step as they complete it.
|
||||||
|
|
||||||
|
### Molecule Types for Polecats
|
||||||
|
|
||||||
|
| Type | Storage | Use Case |
|
||||||
|
|------|---------|----------|
|
||||||
|
| **Regular Molecule** | `.beads/` (synced) | Discrete deliverables, audit trail |
|
||||||
|
| **Wisp** | `.beads/` (ephemeral) | Patrol cycles, operational loops |
|
||||||
|
|
||||||
|
Polecats typically use **regular molecules** because each assignment has audit value.
|
||||||
|
Patrol agents (Witness, Refinery, Deacon) use **wisps** to prevent accumulation.
|
||||||
|
|
||||||
|
### Hook Management
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gt hook # What's on MY hook?
|
||||||
|
gt mol attach-from-mail <id> # Attach work from mail message
|
||||||
|
gt done # Signal completion (syncs, submits to MQ, notifies Witness)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Polecat Workflow Summary
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Spawn with work on hook
|
||||||
|
2. gt hook # What's hooked?
|
||||||
|
3. bd mol current # Where am I?
|
||||||
|
4. Execute current step
|
||||||
|
5. bd close <step> --continue
|
||||||
|
6. If more steps: GOTO 3
|
||||||
|
7. gt done # Signal completion
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wisp vs Molecule Decision
|
||||||
|
|
||||||
|
| Question | Molecule | Wisp |
|
||||||
|
|----------|----------|------|
|
||||||
|
| Does it need audit trail? | Yes | No |
|
||||||
|
| Will it repeat continuously? | No | Yes |
|
||||||
|
| Is it discrete deliverable? | Yes | No |
|
||||||
|
| Is it operational routine? | No | Yes |
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
1. **Use `--continue` for propulsion** - Keep momentum by auto-advancing
|
1. **Use `--continue` for propulsion** - Keep momentum by auto-advancing
|
||||||
@@ -278,6 +278,6 @@ This distinction matters for:
|
|||||||
|
|
||||||
## Related Documentation
|
## Related Documentation
|
||||||
|
|
||||||
- [Understanding Gas Town](understanding-gas-town.md) - Role taxonomy and architecture
|
- [Overview](../overview.md) - Role taxonomy and architecture
|
||||||
- [Polecat Wisp Architecture](polecat-wisp-architecture.md) - Molecule execution
|
- [Molecules](molecules.md) - Molecule execution and polecat workflow
|
||||||
- [Propulsion Principle](propulsion-principle.md) - Why work triggers immediate execution
|
- [Propulsion Principle](propulsion-principle.md) - Why work triggers immediate execution
|
||||||
@@ -125,6 +125,6 @@ bd show gt-xyz # Routes to gastown/mayor/rig/.beads
|
|||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
- [reference.md](reference.md) - Command reference
|
- [reference.md](../reference.md) - Command reference
|
||||||
- [molecules.md](molecules.md) - Workflow molecules
|
- [molecules.md](../concepts/molecules.md) - Workflow molecules
|
||||||
- [identity.md](identity.md) - Agent identity and BD_ACTOR
|
- [identity.md](../concepts/identity.md) - Agent identity and BD_ACTOR
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# Federation Architecture
|
# Federation Architecture
|
||||||
|
|
||||||
|
> **Status: Design spec - not yet implemented**
|
||||||
|
|
||||||
> Multi-workspace coordination for Gas Town and Beads
|
> Multi-workspace coordination for Gas Town and Beads
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@@ -100,7 +102,7 @@ Distribute work across workspaces:
|
|||||||
|
|
||||||
## Agent Provenance
|
## Agent Provenance
|
||||||
|
|
||||||
Every agent operation is attributed. See [identity.md](identity.md) for the
|
Every agent operation is attributed. See [identity.md](../concepts/identity.md) for the
|
||||||
complete BD_ACTOR format convention.
|
complete BD_ACTOR format convention.
|
||||||
|
|
||||||
### Git Commits
|
### Git Commits
|
||||||
136
docs/design/operational-state.md
Normal file
136
docs/design/operational-state.md
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# Operational State in Gas Town
|
||||||
|
|
||||||
|
> Managing runtime state through events and labels.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Gas Town tracks operational state changes as structured data. This document covers:
|
||||||
|
- **Events**: State transitions as beads (immutable audit trail)
|
||||||
|
- **Labels-as-state**: Fast queries via role bead labels (current state cache)
|
||||||
|
|
||||||
|
For Boot triage and degraded mode details, see [Watchdog Chain](watchdog-chain.md).
|
||||||
|
|
||||||
|
## Events: State Transitions as Data
|
||||||
|
|
||||||
|
Operational state changes are recorded as event beads. Each event captures:
|
||||||
|
- **What** changed (`event_type`)
|
||||||
|
- **Who** caused it (`actor`)
|
||||||
|
- **What** was affected (`target`)
|
||||||
|
- **Context** (`payload`)
|
||||||
|
- **When** (`created_at`)
|
||||||
|
|
||||||
|
### Event Types
|
||||||
|
|
||||||
|
| Event Type | Description | Payload |
|
||||||
|
|------------|-------------|---------|
|
||||||
|
| `patrol.muted` | Patrol cycle disabled | `{reason, until?}` |
|
||||||
|
| `patrol.unmuted` | Patrol cycle re-enabled | `{reason?}` |
|
||||||
|
| `agent.started` | Agent session began | `{session_id?}` |
|
||||||
|
| `agent.stopped` | Agent session ended | `{reason, outcome?}` |
|
||||||
|
| `mode.degraded` | System entered degraded mode | `{reason}` |
|
||||||
|
| `mode.normal` | System returned to normal | `{}` |
|
||||||
|
|
||||||
|
### Creating Events
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Mute deacon patrol
|
||||||
|
bd create --type=event --event-type=patrol.muted \
|
||||||
|
--actor=human:overseer --target=agent:deacon \
|
||||||
|
--payload='{"reason":"fixing convoy deadlock","until":"gt-abc1"}'
|
||||||
|
|
||||||
|
# System entered degraded mode
|
||||||
|
bd create --type=event --event-type=mode.degraded \
|
||||||
|
--actor=system:daemon --target=rig:greenplace \
|
||||||
|
--payload='{"reason":"tmux unavailable"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Querying Events
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Recent events for an agent
|
||||||
|
bd list --type=event --target=agent:deacon --limit=10
|
||||||
|
|
||||||
|
# All patrol state changes
|
||||||
|
bd list --type=event --event-type=patrol.muted
|
||||||
|
bd list --type=event --event-type=patrol.unmuted
|
||||||
|
|
||||||
|
# Events in the activity feed
|
||||||
|
bd activity --follow --type=event
|
||||||
|
```
|
||||||
|
|
||||||
|
## Labels-as-State Pattern
|
||||||
|
|
||||||
|
Events capture the full history. Labels cache the current state for fast queries.
|
||||||
|
|
||||||
|
### Convention
|
||||||
|
|
||||||
|
Labels use `<dimension>:<value>` format:
|
||||||
|
- `patrol:muted` / `patrol:active`
|
||||||
|
- `mode:degraded` / `mode:normal`
|
||||||
|
- `status:idle` / `status:working`
|
||||||
|
|
||||||
|
### State Change Flow
|
||||||
|
|
||||||
|
1. Create event bead (full context, immutable)
|
||||||
|
2. Update role bead labels (current state cache)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Mute patrol
|
||||||
|
bd create --type=event --event-type=patrol.muted ...
|
||||||
|
bd update role-deacon --add-label=patrol:muted --remove-label=patrol:active
|
||||||
|
|
||||||
|
# Unmute patrol
|
||||||
|
bd create --type=event --event-type=patrol.unmuted ...
|
||||||
|
bd update role-deacon --add-label=patrol:active --remove-label=patrol:muted
|
||||||
|
```
|
||||||
|
|
||||||
|
### Querying Current State
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Is deacon patrol muted?
|
||||||
|
bd show role-deacon | grep patrol:
|
||||||
|
|
||||||
|
# All agents with muted patrol
|
||||||
|
bd list --type=role --label=patrol:muted
|
||||||
|
|
||||||
|
# All agents in degraded mode
|
||||||
|
bd list --type=role --label=mode:degraded
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration vs State
|
||||||
|
|
||||||
|
| Type | Storage | Example |
|
||||||
|
|------|---------|---------|
|
||||||
|
| **Static config** | TOML files | Daemon tick interval |
|
||||||
|
| **Operational state** | Beads (events + labels) | Patrol muted |
|
||||||
|
| **Runtime flags** | Marker files | `.deacon-disabled` |
|
||||||
|
|
||||||
|
Static config rarely changes and doesn't need history.
|
||||||
|
Operational state changes at runtime and benefits from audit trail.
|
||||||
|
Marker files are fast checks that can trigger deeper beads queries.
|
||||||
|
|
||||||
|
## Commands Summary
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create operational event
|
||||||
|
bd create --type=event --event-type=<type> \
|
||||||
|
--actor=<entity> --target=<entity> --payload='<json>'
|
||||||
|
|
||||||
|
# Update state label
|
||||||
|
bd update <role-bead> --add-label=<dim>:<val> --remove-label=<dim>:<old>
|
||||||
|
|
||||||
|
# Query current state
|
||||||
|
bd list --type=role --label=<dim>:<val>
|
||||||
|
|
||||||
|
# Query state history
|
||||||
|
bd list --type=event --target=<entity>
|
||||||
|
|
||||||
|
# Boot management
|
||||||
|
gt dog status boot
|
||||||
|
gt dog call boot
|
||||||
|
gt dog prime boot
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Events are the source of truth. Labels are the cache.*
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
# Decision 009: Session Events Architecture
|
|
||||||
|
|
||||||
**Status:** Accepted
|
|
||||||
**Date:** 2025-12-31
|
|
||||||
**Context:** Where should session events live? Beads, separate repo, or events.jsonl?
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
|
|
||||||
Session events are **orchestration infrastructure**, not work items. They stay in
|
|
||||||
`events.jsonl` (outside beads). Work attribution happens by capturing `session_id`
|
|
||||||
on beads mutations (issue close, MR merge).
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
The seance feature needs to discover and resume Claude Code sessions. This requires:
|
|
||||||
1. **Pointer** to session (session_id) - for `claude --resume`
|
|
||||||
2. **Attribution** (which work happened in this session) - for entity CV
|
|
||||||
|
|
||||||
Claude Code already stores full session transcripts indefinitely. Gas Town doesn't
|
|
||||||
need to duplicate them - just point at them.
|
|
||||||
|
|
||||||
## The Separation
|
|
||||||
|
|
||||||
| Layer | Storage | Content | Retention |
|
|
||||||
|-------|---------|---------|-----------|
|
|
||||||
| **Orchestration** | `~/.events.jsonl` | session_start, nudges, mail routing | Ephemeral (auto-prune) |
|
|
||||||
| **Work** | Beads (rig-level) | Issues, MRs, convoys | Permanent (ledger) |
|
|
||||||
| **Entity activity** | Beads (entity chain) | Session digests | Permanent (CV) |
|
|
||||||
| **Transcript** | Claude Code | Full session content | Claude Code's retention |
|
|
||||||
|
|
||||||
## Why Not Beads for Events?
|
|
||||||
|
|
||||||
1. **Volume**: Orchestration events are high volume, would overwhelm work signal
|
|
||||||
2. **Ephemerality**: Most orchestration events don't need CV/ledger permanence
|
|
||||||
3. **Different audiences**: Work items are cross-agent; orchestration is internal
|
|
||||||
4. **Claude Code has it**: Transcripts already live there; we just need pointers
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
### Phase 1: Attribution (Now)
|
|
||||||
- `gt done` captures `CLAUDE_SESSION_ID` in issue close
|
|
||||||
- Beads supports `closed_by_session` field on issue mutations
|
|
||||||
- Events.jsonl continues to capture `session_start` for seance
|
|
||||||
|
|
||||||
### Phase 2: Session Digests (Future)
|
|
||||||
- Sessions as wisps: `session_start` creates ephemeral wisp
|
|
||||||
- Session work adds steps (issues closed, commits made)
|
|
||||||
- `session_end` squashes to digest
|
|
||||||
- Digest lives on entity chain (agent CV)
|
|
||||||
|
|
||||||
### Phase 3: Pruning (Future)
|
|
||||||
- Events.jsonl auto-prunes after N days
|
|
||||||
- Session digests provide permanent summary
|
|
||||||
- Full transcripts remain in Claude Code
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
|
|
||||||
**Positive:**
|
|
||||||
- Clean separation of concerns
|
|
||||||
- Work ledger stays focused on work
|
|
||||||
- CV attribution via session_id on beads mutations
|
|
||||||
- Seance works via events.jsonl discovery
|
|
||||||
|
|
||||||
**Negative:**
|
|
||||||
- Two systems to understand (events vs beads)
|
|
||||||
- Need to ensure session_id flows through commands
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- `gt seance` - Session discovery and resume
|
|
||||||
- `gt-3zsml` - SessionStart hook passes session_id to gt prime
|
|
||||||
- PRIMING.md - "The Feed Is the Signal" section
|
|
||||||
- CONTEXT.md - Entity chains and CV model
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
# Operational State in Gas Town
|
|
||||||
|
|
||||||
> Managing runtime state, degraded modes, and the Boot triage system.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Gas Town needs to track operational state: Is the Deacon's patrol muted? Is the
|
|
||||||
system in degraded mode? When did state change, and why?
|
|
||||||
|
|
||||||
This document covers:
|
|
||||||
- **Events**: State transitions as beads
|
|
||||||
- **Labels-as-state**: Fast queries via role bead labels
|
|
||||||
- **Boot**: The dog that triages the Deacon
|
|
||||||
- **Degraded mode**: Operating without tmux
|
|
||||||
|
|
||||||
## Events: State Transitions as Data
|
|
||||||
|
|
||||||
Operational state changes are recorded as event beads. Each event captures:
|
|
||||||
- **What** changed (`event_type`)
|
|
||||||
- **Who** caused it (`actor`)
|
|
||||||
- **What** was affected (`target`)
|
|
||||||
- **Context** (`payload`)
|
|
||||||
- **When** (`created_at`)
|
|
||||||
|
|
||||||
### Event Types
|
|
||||||
|
|
||||||
| Event Type | Description | Payload |
|
|
||||||
|------------|-------------|---------|
|
|
||||||
| `patrol.muted` | Patrol cycle disabled | `{reason, until?}` |
|
|
||||||
| `patrol.unmuted` | Patrol cycle re-enabled | `{reason?}` |
|
|
||||||
| `agent.started` | Agent session began | `{session_id?}` |
|
|
||||||
| `agent.stopped` | Agent session ended | `{reason, outcome?}` |
|
|
||||||
| `mode.degraded` | System entered degraded mode | `{reason}` |
|
|
||||||
| `mode.normal` | System returned to normal | `{}` |
|
|
||||||
|
|
||||||
### Creating Events
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Mute deacon patrol
|
|
||||||
bd create --type=event --event-type=patrol.muted \
|
|
||||||
--actor=human:overseer --target=agent:deacon \
|
|
||||||
--payload='{"reason":"fixing convoy deadlock","until":"gt-abc1"}'
|
|
||||||
|
|
||||||
# System entered degraded mode
|
|
||||||
bd create --type=event --event-type=mode.degraded \
|
|
||||||
--actor=system:daemon --target=rig:greenplace \
|
|
||||||
--payload='{"reason":"tmux unavailable"}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Querying Events
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Recent events for an agent
|
|
||||||
bd list --type=event --target=agent:deacon --limit=10
|
|
||||||
|
|
||||||
# All patrol state changes
|
|
||||||
bd list --type=event --event-type=patrol.muted
|
|
||||||
bd list --type=event --event-type=patrol.unmuted
|
|
||||||
|
|
||||||
# Events in the activity feed
|
|
||||||
bd activity --follow --type=event
|
|
||||||
```
|
|
||||||
|
|
||||||
## Labels-as-State Pattern
|
|
||||||
|
|
||||||
Events capture the full history. Labels cache the current state for fast queries.
|
|
||||||
|
|
||||||
### Convention
|
|
||||||
|
|
||||||
Labels use `<dimension>:<value>` format:
|
|
||||||
- `patrol:muted` / `patrol:active`
|
|
||||||
- `mode:degraded` / `mode:normal`
|
|
||||||
- `status:idle` / `status:working`
|
|
||||||
|
|
||||||
### State Change Flow
|
|
||||||
|
|
||||||
1. Create event bead (full context, immutable)
|
|
||||||
2. Update role bead labels (current state cache)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Mute patrol
|
|
||||||
bd create --type=event --event-type=patrol.muted ...
|
|
||||||
bd update role-deacon --add-label=patrol:muted --remove-label=patrol:active
|
|
||||||
|
|
||||||
# Unmute patrol
|
|
||||||
bd create --type=event --event-type=patrol.unmuted ...
|
|
||||||
bd update role-deacon --add-label=patrol:active --remove-label=patrol:muted
|
|
||||||
```
|
|
||||||
|
|
||||||
### Querying Current State
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Is deacon patrol muted?
|
|
||||||
bd show role-deacon | grep patrol:
|
|
||||||
|
|
||||||
# All agents with muted patrol
|
|
||||||
bd list --type=role --label=patrol:muted
|
|
||||||
|
|
||||||
# All agents in degraded mode
|
|
||||||
bd list --type=role --label=mode:degraded
|
|
||||||
```
|
|
||||||
|
|
||||||
## Boot: The Deacon's Watchdog
|
|
||||||
|
|
||||||
> See [Watchdog Chain](watchdog-chain.md) for the complete Daemon/Boot/Deacon
|
|
||||||
> architecture and design rationale.
|
|
||||||
|
|
||||||
Boot is a dog (Deacon helper) that triages the Deacon's health. The daemon pokes
|
|
||||||
Boot instead of the Deacon directly, centralizing the "when to wake" decision in
|
|
||||||
an agent that can reason about it.
|
|
||||||
|
|
||||||
### Why Boot?
|
|
||||||
|
|
||||||
The daemon is dumb transport (ZFC principle). It can't decide:
|
|
||||||
- Is the Deacon stuck or just thinking?
|
|
||||||
- Should we interrupt or let it continue?
|
|
||||||
- Is the system in a state where nudging would help?
|
|
||||||
|
|
||||||
Boot is an agent that can observe and decide.
|
|
||||||
|
|
||||||
### Boot's Lifecycle
|
|
||||||
|
|
||||||
```
|
|
||||||
Daemon tick
|
|
||||||
│
|
|
||||||
├── Check: Is Boot already running? (marker file)
|
|
||||||
│ └── Yes + recent: Skip this tick
|
|
||||||
│
|
|
||||||
└── Spawn Boot (fresh session each time)
|
|
||||||
│
|
|
||||||
└── Boot runs triage molecule
|
|
||||||
├── Observe (wisps, mail, git state, tmux panes)
|
|
||||||
├── Decide (start/wake/nudge/interrupt/nothing)
|
|
||||||
├── Act
|
|
||||||
├── Clean inbox (discard stale handoffs)
|
|
||||||
└── Handoff (or exit in degraded mode)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Boot is Always Fresh
|
|
||||||
|
|
||||||
Boot restarts on each daemon tick. This is intentional:
|
|
||||||
- Narrow scope makes restarts cheap
|
|
||||||
- Fresh context avoids accumulated confusion
|
|
||||||
- Handoff mail provides continuity without session persistence
|
|
||||||
- No keepalive needed
|
|
||||||
|
|
||||||
### Boot's Decision Guidance
|
|
||||||
|
|
||||||
Agents may take several minutes on legitimate work - composing artifacts, running
|
|
||||||
tools, deep analysis. Ten minutes or more in edge cases.
|
|
||||||
|
|
||||||
To assess whether an agent is stuck:
|
|
||||||
1. Check the agent's last reported activity (recent wisps, mail sent, git commits)
|
|
||||||
2. Observe the tmux pane output over a 30-second window
|
|
||||||
3. Look for signs of progress vs. signs of hanging (tool prompt, error loop, silence)
|
|
||||||
|
|
||||||
Agents work in small steps with feedback. Most tasks complete in 2-3 minutes, but
|
|
||||||
task nature matters.
|
|
||||||
|
|
||||||
**Boot's options (increasing disruption):**
|
|
||||||
- Let them continue (if progress is evident)
|
|
||||||
- `gt nudge <agent>` (gentle wake signal)
|
|
||||||
- Escape + chat (interrupt and ask what's happening)
|
|
||||||
- Request process restart (last resort, for true hangs)
|
|
||||||
|
|
||||||
**Common false positives:**
|
|
||||||
- Tool waiting for user confirmation
|
|
||||||
- Long-running test suite
|
|
||||||
- Large file read/write operations
|
|
||||||
|
|
||||||
### Boot's Location
|
|
||||||
|
|
||||||
```
|
|
||||||
~/gt/deacon/dogs/boot/
|
|
||||||
```
|
|
||||||
|
|
||||||
Session name: `gt-boot`
|
|
||||||
|
|
||||||
Created/maintained by `bd doctor`.
|
|
||||||
|
|
||||||
### Boot Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check Boot status
|
|
||||||
gt dog status boot
|
|
||||||
|
|
||||||
# Manual Boot run (debugging)
|
|
||||||
gt dog call boot
|
|
||||||
|
|
||||||
# Prime Boot with context
|
|
||||||
gt dog prime boot
|
|
||||||
```
|
|
||||||
|
|
||||||
## Degraded Mode
|
|
||||||
|
|
||||||
Gas Town can operate without tmux, with reduced capabilities.
|
|
||||||
|
|
||||||
### Detection
|
|
||||||
|
|
||||||
The daemon detects degraded mode mechanically and passes it to agents:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
GT_DEGRADED=true # Set by daemon when tmux unavailable
|
|
||||||
```
|
|
||||||
|
|
||||||
Boot and other agents check this environment variable.
|
|
||||||
|
|
||||||
### What Changes in Degraded Mode
|
|
||||||
|
|
||||||
| Capability | Normal | Degraded |
|
|
||||||
|------------|--------|----------|
|
|
||||||
| Observe tmux panes | Yes | No |
|
|
||||||
| Interactive interrupt | Yes | No |
|
|
||||||
| Session management | Full | Limited |
|
|
||||||
| Agent spawn | tmux sessions | Direct spawn |
|
|
||||||
| Boot lifecycle | Handoff | Exit |
|
|
||||||
|
|
||||||
### Agents in Degraded Mode
|
|
||||||
|
|
||||||
In degraded mode, agents:
|
|
||||||
- Cannot observe other agents' pane output
|
|
||||||
- Cannot interactively interrupt stuck agents
|
|
||||||
- Focus on beads/git state observation only
|
|
||||||
- Report anomalies but can't fix interactively
|
|
||||||
|
|
||||||
Boot specifically:
|
|
||||||
- Runs to completion and exits (no handoff)
|
|
||||||
- Limited to: start deacon, file beads, mail overseer
|
|
||||||
- Cannot: observe panes, nudge, interrupt
|
|
||||||
|
|
||||||
### Recording Degraded Mode
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# System entered degraded mode
|
|
||||||
bd create --type=event --event-type=mode.degraded \
|
|
||||||
--actor=system:daemon --target=rig:greenplace \
|
|
||||||
--payload='{"reason":"tmux unavailable"}'
|
|
||||||
|
|
||||||
bd update role-greenplace --add-label=mode:degraded --remove-label=mode:normal
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration vs State
|
|
||||||
|
|
||||||
| Type | Storage | Example |
|
|
||||||
|------|---------|---------|
|
|
||||||
| **Static config** | TOML files | Daemon tick interval |
|
|
||||||
| **Operational state** | Beads (events + labels) | Patrol muted |
|
|
||||||
| **Runtime flags** | Marker files | `.deacon-disabled` |
|
|
||||||
|
|
||||||
Static config rarely changes and doesn't need history.
|
|
||||||
Operational state changes at runtime and benefits from audit trail.
|
|
||||||
Marker files are fast checks that can trigger deeper beads queries.
|
|
||||||
|
|
||||||
## Commands Summary
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Create operational event
|
|
||||||
bd create --type=event --event-type=<type> \
|
|
||||||
--actor=<entity> --target=<entity> --payload='<json>'
|
|
||||||
|
|
||||||
# Update state label
|
|
||||||
bd update <role-bead> --add-label=<dim>:<val> --remove-label=<dim>:<old>
|
|
||||||
|
|
||||||
# Query current state
|
|
||||||
bd list --type=role --label=<dim>:<val>
|
|
||||||
|
|
||||||
# Query state history
|
|
||||||
bd list --type=event --target=<entity>
|
|
||||||
|
|
||||||
# Boot management
|
|
||||||
gt dog status boot
|
|
||||||
gt dog call boot
|
|
||||||
gt dog prime boot
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Events are the source of truth. Labels are the cache.*
|
|
||||||
@@ -27,7 +27,7 @@ These roles manage the Gas Town system itself:
|
|||||||
| Role | Description | Lifecycle |
|
| Role | Description | Lifecycle |
|
||||||
|------|-------------|-----------|
|
|------|-------------|-----------|
|
||||||
| **Mayor** | Global coordinator at mayor/ | Singleton, persistent |
|
| **Mayor** | Global coordinator at mayor/ | Singleton, persistent |
|
||||||
| **Deacon** | Background supervisor daemon ([watchdog chain](watchdog-chain.md)) | Singleton, persistent |
|
| **Deacon** | Background supervisor daemon ([watchdog chain](design/watchdog-chain.md)) | Singleton, persistent |
|
||||||
| **Witness** | Per-rig polecat lifecycle manager | One per rig, persistent |
|
| **Witness** | Per-rig polecat lifecycle manager | One per rig, persistent |
|
||||||
| **Refinery** | Per-rig merge queue processor | One per rig, persistent |
|
| **Refinery** | Per-rig merge queue processor | One per rig, persistent |
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ These roles do actual project work:
|
|||||||
|
|
||||||
| Role | Description | Lifecycle |
|
| Role | Description | Lifecycle |
|
||||||
|------|-------------|-----------|
|
|------|-------------|-----------|
|
||||||
| **Polecat** | Ephemeral worker with own worktree | Transient, Witness-managed ([details](polecat-lifecycle.md)) |
|
| **Polecat** | Ephemeral worker with own worktree | Transient, Witness-managed ([details](concepts/polecat-lifecycle.md)) |
|
||||||
| **Crew** | Persistent worker with own clone | Long-lived, user-managed |
|
| **Crew** | Persistent worker with own clone | Long-lived, user-managed |
|
||||||
| **Dog** | Deacon helper for infrastructure tasks | Ephemeral, Deacon-managed |
|
| **Dog** | Deacon helper for infrastructure tasks | Ephemeral, Deacon-managed |
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ gt convoy list
|
|||||||
- Historical record of completed work (`gt convoy list --all`)
|
- Historical record of completed work (`gt convoy list --all`)
|
||||||
|
|
||||||
The "swarm" is ephemeral - just the workers currently assigned to a convoy's issues.
|
The "swarm" is ephemeral - just the workers currently assigned to a convoy's issues.
|
||||||
When issues close, the convoy lands. See [Convoys](convoy.md) for details.
|
When issues close, the convoy lands. See [Convoys](concepts/convoy.md) for details.
|
||||||
|
|
||||||
## Crew vs Polecats
|
## Crew vs Polecats
|
||||||
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
# Polecat Wisp Architecture
|
|
||||||
|
|
||||||
How polecats use molecules and wisps to execute work in Gas Town.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Polecats receive work via their hook - a pinned molecule attached to an issue.
|
|
||||||
They execute molecule steps sequentially, closing each step as they complete it.
|
|
||||||
|
|
||||||
## Molecule Types for Polecats
|
|
||||||
|
|
||||||
| Type | Storage | Use Case |
|
|
||||||
|------|---------|----------|
|
|
||||||
| **Regular Molecule** | `.beads/` (synced) | Discrete deliverables, audit trail |
|
|
||||||
| **Wisp** | `.beads/` (ephemeral, type=wisp) | Patrol cycles, operational loops |
|
|
||||||
|
|
||||||
Polecats typically use **regular molecules** because each assignment has audit value.
|
|
||||||
Patrol agents (Witness, Refinery, Deacon) use **wisps** to prevent accumulation.
|
|
||||||
|
|
||||||
## Step Execution
|
|
||||||
|
|
||||||
### The Traditional Approach
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Check current status
|
|
||||||
gt hook
|
|
||||||
|
|
||||||
# 2. Find next step
|
|
||||||
bd ready --parent=gt-abc
|
|
||||||
|
|
||||||
# 3. Claim the step
|
|
||||||
bd update gt-abc.4 --status=in_progress
|
|
||||||
|
|
||||||
# 4. Do the work...
|
|
||||||
|
|
||||||
# 5. Close the step
|
|
||||||
bd close gt-abc.4
|
|
||||||
|
|
||||||
# 6. Repeat from step 2
|
|
||||||
```
|
|
||||||
|
|
||||||
### The Propulsion Approach
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Check where you are
|
|
||||||
bd mol current
|
|
||||||
|
|
||||||
# 2. Do the work on current step...
|
|
||||||
|
|
||||||
# 3. Close and advance in one command
|
|
||||||
bd close gt-abc.4 --continue
|
|
||||||
|
|
||||||
# 4. Repeat from step 1
|
|
||||||
```
|
|
||||||
|
|
||||||
The `--continue` flag:
|
|
||||||
- Closes the current step
|
|
||||||
- Finds the next ready step in the same molecule
|
|
||||||
- Auto-marks it `in_progress`
|
|
||||||
- Outputs the transition
|
|
||||||
|
|
||||||
### Example Session
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ bd mol current
|
|
||||||
You're working on molecule gt-abc (Implement user auth)
|
|
||||||
|
|
||||||
✓ gt-abc.1: Design schema
|
|
||||||
✓ gt-abc.2: Create models
|
|
||||||
→ gt-abc.3: Add endpoints [in_progress] <- YOU ARE HERE
|
|
||||||
○ gt-abc.4: Write tests
|
|
||||||
○ gt-abc.5: Update docs
|
|
||||||
|
|
||||||
Progress: 2/5 steps complete
|
|
||||||
|
|
||||||
$ # ... implement the endpoints ...
|
|
||||||
|
|
||||||
$ bd close gt-abc.3 --continue
|
|
||||||
✓ Closed gt-abc.3: Add endpoints
|
|
||||||
|
|
||||||
Next ready in molecule:
|
|
||||||
gt-abc.4: Write tests
|
|
||||||
|
|
||||||
→ Marked in_progress (use --no-auto to skip)
|
|
||||||
|
|
||||||
$ bd mol current
|
|
||||||
You're working on molecule gt-abc (Implement user auth)
|
|
||||||
|
|
||||||
✓ gt-abc.1: Design schema
|
|
||||||
✓ gt-abc.2: Create models
|
|
||||||
✓ gt-abc.3: Add endpoints
|
|
||||||
→ gt-abc.4: Write tests [in_progress] <- YOU ARE HERE
|
|
||||||
○ gt-abc.5: Update docs
|
|
||||||
|
|
||||||
Progress: 3/5 steps complete
|
|
||||||
```
|
|
||||||
|
|
||||||
## Molecule Completion
|
|
||||||
|
|
||||||
When closing the last step:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ bd close gt-abc.5 --continue
|
|
||||||
✓ Closed gt-abc.5: Update docs
|
|
||||||
|
|
||||||
Molecule gt-abc complete! All steps closed.
|
|
||||||
Consider: bd mol squash gt-abc --summary '...'
|
|
||||||
```
|
|
||||||
|
|
||||||
After all steps are closed:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Squash to digest for audit trail
|
|
||||||
bd mol squash gt-abc --summary "Implemented user authentication with JWT"
|
|
||||||
|
|
||||||
# Or if it's routine work
|
|
||||||
bd mol burn gt-abc
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hook Management
|
|
||||||
|
|
||||||
### Checking Your Hook
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gt hook
|
|
||||||
```
|
|
||||||
|
|
||||||
Shows what molecule is pinned to your current agent and the associated bead.
|
|
||||||
|
|
||||||
### Attaching Work from Mail
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gt mail inbox
|
|
||||||
gt mol attach-from-mail <mail-id>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Completing Work
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# After all molecule steps closed
|
|
||||||
gt done
|
|
||||||
|
|
||||||
# This:
|
|
||||||
# 1. Syncs beads
|
|
||||||
# 2. Submits to merge queue
|
|
||||||
# 3. Notifies Witness
|
|
||||||
```
|
|
||||||
|
|
||||||
## Polecat Workflow Summary
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Spawn with work on hook
|
|
||||||
2. gt hook # What's hooked?
|
|
||||||
3. bd mol current # Where am I?
|
|
||||||
4. Execute current step
|
|
||||||
5. bd close <step> --continue
|
|
||||||
6. If more steps: GOTO 3
|
|
||||||
7. gt done # Signal completion
|
|
||||||
8. Wait for Witness cleanup
|
|
||||||
```
|
|
||||||
|
|
||||||
## Wisp vs Molecule Decision
|
|
||||||
|
|
||||||
| Question | Molecule | Wisp |
|
|
||||||
|----------|----------|------|
|
|
||||||
| Does it need audit trail? | Yes | No |
|
|
||||||
| Will it repeat continuously? | No | Yes |
|
|
||||||
| Is it discrete deliverable? | Yes | No |
|
|
||||||
| Is it operational routine? | No | Yes |
|
|
||||||
|
|
||||||
Polecats: **Use molecules** (deliverables have audit value)
|
|
||||||
Patrol agents: **Use wisps** (routine loops don't accumulate)
|
|
||||||
@@ -471,7 +471,7 @@ gt convoy list --all # Include landed convoys
|
|||||||
gt convoy list --status=closed # Only landed convoys
|
gt convoy list --status=closed # Only landed convoys
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: "Swarm" is ephemeral (workers on a convoy's issues). See [Convoys](convoy.md).
|
Note: "Swarm" is ephemeral (workers on a convoy's issues). See [Convoys](concepts/convoy.md).
|
||||||
|
|
||||||
### Work Assignment
|
### Work Assignment
|
||||||
|
|
||||||
@@ -510,7 +510,7 @@ gt escalate -s HIGH "msg" # Important blocker
|
|||||||
gt escalate -s MEDIUM "msg" -m "Details..."
|
gt escalate -s MEDIUM "msg" -m "Details..."
|
||||||
```
|
```
|
||||||
|
|
||||||
See [escalation.md](escalation.md) for full protocol.
|
See [escalation.md](design/escalation.md) for full protocol.
|
||||||
|
|
||||||
### Sessions
|
### Sessions
|
||||||
|
|
||||||
@@ -611,4 +611,4 @@ bd mol bond mol-security-scan $PATROL_ID --var scope="$SCOPE"
|
|||||||
|
|
||||||
**Nondeterministic idempotence**: Any worker can continue any molecule. Steps are atomic checkpoints in beads.
|
**Nondeterministic idempotence**: Any worker can continue any molecule. Steps are atomic checkpoints in beads.
|
||||||
|
|
||||||
**Convoy tracking**: Convoys track batched work across rigs. A "swarm" is ephemeral - just the workers currently on a convoy's issues. See [Convoys](convoy.md) for details.
|
**Convoy tracking**: Convoys track batched work across rigs. A "swarm" is ephemeral - just the workers currently on a convoy's issues. See [Convoys](concepts/convoy.md) for details.
|
||||||
|
|||||||
@@ -1,220 +0,0 @@
|
|||||||
# Infrastructure & Utilities Code Review
|
|
||||||
|
|
||||||
**Review ID**: gt-a02fj.8
|
|
||||||
**Date**: 2026-01-04
|
|
||||||
**Reviewer**: gastown/polecats/interceptor (polecat gus)
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
Reviewed 14 infrastructure packages for dead code, missing abstractions, performance concerns, and error handling consistency. Found significant cleanup opportunities totaling ~44% dead code in constants package and an entire unused package (keepalive).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Dead Code Inventory
|
|
||||||
|
|
||||||
### Critical: Entire Package Unused
|
|
||||||
|
|
||||||
| Package | Status | Recommendation |
|
|
||||||
|---------|--------|----------------|
|
|
||||||
| `internal/keepalive/` | 100% unused | **DELETE ENTIRE PACKAGE** |
|
|
||||||
|
|
||||||
The keepalive package (5 functions) was removed from the codebase on Dec 30, 2025 as part of the shift to feed-based activation. No imports exist anywhere.
|
|
||||||
|
|
||||||
### High Priority: Functions to Remove
|
|
||||||
|
|
||||||
| Package | Function | Location | Notes |
|
|
||||||
|---------|----------|----------|-------|
|
|
||||||
| `config` | `NewExampleAgentRegistry()` | agents.go:361-381 | Zero usage in codebase |
|
|
||||||
| `constants` | `DirMayor`, `DirPolecats`, `DirCrew`, etc. | constants.go:32-59 | 9 unused directory constants |
|
|
||||||
| `constants` | `FileRigsJSON`, `FileTownJSON`, etc. | constants.go:62-74 | 4 unused file constants |
|
|
||||||
| `constants` | `BranchMain`, `BranchBeadsSync`, etc. | constants.go:77-89 | 4 unused branch constants |
|
|
||||||
| `constants` | `RigBeadsPath()`, `RigPolecatsPath()`, etc. | constants.go | 5 unused path helper functions |
|
|
||||||
| `doctor` | `itoa()` | daemon_check.go:93-111 | Duplicate of `strconv.Itoa()` |
|
|
||||||
| `lock` | `DetectCollisions()` | lock.go:367-402 | Superseded by doctor checks |
|
|
||||||
| `events` | `BootPayload()` | events.go:186-191 | Never called |
|
|
||||||
| `events` | `TypePatrolStarted`, `TypeSessionEnd` | events.go:50,54 | Never emitted |
|
|
||||||
| `events` | `VisibilityBoth` | events.go:32 | Never set |
|
|
||||||
| `boot` | `DeaconDir()` | boot.go:235-237 | Exported but never called |
|
|
||||||
| `dog` | `IdleCount()`, `WorkingCount()` | manager.go:532-562 | Inlined in callers |
|
|
||||||
|
|
||||||
### Medium Priority: Duplicate Definitions
|
|
||||||
|
|
||||||
| Package | Item | Duplicate Location | Action |
|
|
||||||
|---------|------|-------------------|--------|
|
|
||||||
| `constants` | `RigSettingsPath()` | Also in config/loader.go:673 | Remove from constants |
|
|
||||||
| `util` | Atomic write pattern | Also in mrqueue/, wisp/ | Consolidate to util |
|
|
||||||
| `doctor` | `findRigs()` | 3 identical implementations | Extract shared helper |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Utility Consolidation Plan
|
|
||||||
|
|
||||||
### Pattern: Atomic Write (Priority: HIGH)
|
|
||||||
|
|
||||||
**Current state**: Duplicated in 3+ locations
|
|
||||||
- `util/atomic.go` (canonical)
|
|
||||||
- `mrqueue/mrqueue.go` (duplicate)
|
|
||||||
- `wisp/io.go` (duplicate)
|
|
||||||
- `polecat/pending.go` (NON-ATOMIC - bug!)
|
|
||||||
|
|
||||||
**Action**:
|
|
||||||
1. Fix `polecat/pending.go:SavePending()` to use `util.AtomicWriteJSON`
|
|
||||||
2. Replace inline atomic writes in mrqueue and wisp with util calls
|
|
||||||
|
|
||||||
### Pattern: Rig Discovery (Priority: HIGH)
|
|
||||||
|
|
||||||
**Current state**: 7+ implementations scattered across doctor package
|
|
||||||
- `BranchCheck.findPersistentRoleDirs()`
|
|
||||||
- `OrphanSessionCheck.getValidRigs()`
|
|
||||||
- `PatrolMoleculesExistCheck.discoverRigs()`
|
|
||||||
- `config_check.go.findAllRigs()`
|
|
||||||
- Multiple `findCrewDirs()` implementations
|
|
||||||
|
|
||||||
**Action**: Create `internal/workspace/discovery.go`:
|
|
||||||
```go
|
|
||||||
type RigDiscovery struct { ... }
|
|
||||||
func (d *RigDiscovery) FindAllRigs() []string
|
|
||||||
func (d *RigDiscovery) FindCrewDirs(rig string) []string
|
|
||||||
func (d *RigDiscovery) FindPolecatDirs(rig string) []string
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pattern: Clone Validation (Priority: MEDIUM)
|
|
||||||
|
|
||||||
**Current state**: Duplicate logic in doctor checks
|
|
||||||
- `rig_check.go`: Validates .git, runs git status
|
|
||||||
- `branch_check.go`: Similar traversal logic
|
|
||||||
|
|
||||||
**Action**: Create `internal/workspace/clone.go`:
|
|
||||||
```go
|
|
||||||
type CloneValidator struct { ... }
|
|
||||||
func (v *CloneValidator) ValidateClone(path string) error
|
|
||||||
func (v *CloneValidator) GetCloneInfo(path string) (*CloneInfo, error)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pattern: Tmux Session Handling (Priority: MEDIUM)
|
|
||||||
|
|
||||||
**Current state**: Fragmented across lock, doctor, daemon
|
|
||||||
- `lock/lock.go`: `getActiveTmuxSessions()`
|
|
||||||
- `doctor/identity_check.go`: Similar logic
|
|
||||||
- `cmd/agents.go`: Uses `tmux.NewTmux()`
|
|
||||||
|
|
||||||
**Action**: Consolidate into `internal/tmux/sessions.go`
|
|
||||||
|
|
||||||
### Pattern: Load/Validate Config Files (Priority: LOW)
|
|
||||||
|
|
||||||
**Current state**: 8 near-identical Load* functions in config/loader.go
|
|
||||||
- `LoadTownConfig`, `LoadRigsConfig`, `LoadRigConfig`, etc.
|
|
||||||
|
|
||||||
**Action**: Create generic loader using Go generics:
|
|
||||||
```go
|
|
||||||
func loadConfigFile[T Validator](path string) (*T, error)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pattern: Math Utilities (Priority: LOW)
|
|
||||||
|
|
||||||
**Current state**: `min()`, `max()`, `min3()`, `abs()` in suggest/suggest.go
|
|
||||||
|
|
||||||
**Action**: If needed elsewhere, move to `internal/util/math.go`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Performance Concerns
|
|
||||||
|
|
||||||
### Critical: File I/O Per-Event
|
|
||||||
|
|
||||||
| Package | Issue | Impact | Recommendation |
|
|
||||||
|---------|-------|--------|----------------|
|
|
||||||
| `events` | Opens/closes file for every event | High on busy systems | Batch writes or buffered logger |
|
|
||||||
| `townlog` | Opens/closes file per log entry | Medium | Same as events |
|
|
||||||
| `events` | `workspace.FindFromCwd()` on every Log() | Low-medium | Cache town root |
|
|
||||||
|
|
||||||
### Critical: Process Tree Walking
|
|
||||||
|
|
||||||
| Package | Issue | Impact | Recommendation |
|
|
||||||
|---------|-------|--------|----------------|
|
|
||||||
| `doctor/orphan_check` | `hasCrewAncestor()` calls `ps` in loop | O(n) subprocess calls | Batch gather process info |
|
|
||||||
|
|
||||||
### High: Directory Traversal Inefficiencies
|
|
||||||
|
|
||||||
| Package | Issue | Impact | Recommendation |
|
|
||||||
|---------|-------|--------|----------------|
|
|
||||||
| `doctor/hook_check` | Uses `exec.Command("find")` | Subprocess overhead | Use `filepath.Walk` |
|
|
||||||
| `lock` | `FindAllLocks()` - unbounded Walk | Scales poorly | Add depth limits |
|
|
||||||
| `townlog` | `TailEvents()` reads entire file | Memory for large logs | Implement true tail |
|
|
||||||
|
|
||||||
### Medium: Redundant Operations
|
|
||||||
|
|
||||||
| Package | Issue | Recommendation |
|
|
||||||
|---------|-------|----------------|
|
|
||||||
| `dog` | `List()` + iterate = double work | Provide `CountByState()` |
|
|
||||||
| `dog` | Creates new git.Git per worktree | Cache or batch |
|
|
||||||
| `doctor/rig_check` | Runs git status twice per polecat | Combine operations |
|
|
||||||
| `checkpoint/Capture` | 3 separate git commands | Use combined flags |
|
|
||||||
|
|
||||||
### Low: JSON Formatting Overhead
|
|
||||||
|
|
||||||
| Package | Issue | Recommendation |
|
|
||||||
|---------|-------|----------------|
|
|
||||||
| `lock` | `MarshalIndent()` for lock files | Use `Marshal()` (no indentation needed) |
|
|
||||||
| `townlog` | No compression for old logs | Consider gzip rotation |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Error Handling Issues
|
|
||||||
|
|
||||||
### Pattern: Silent Failures
|
|
||||||
|
|
||||||
| Package | Location | Issue | Fix |
|
|
||||||
|---------|----------|-------|-----|
|
|
||||||
| `events` | All callers | 19 instances of `_ = events.LogFeed()` | Standardize: always ignore or always check |
|
|
||||||
| `townlog` | `ParseLogLines()` | Silently skips malformed lines | Log warnings |
|
|
||||||
| `lock` | Lines 91, 180, 194-195 | Silent `_ =` without comments | Document intent |
|
|
||||||
| `checkpoint` | `Capture()` | Returns nil error but git commands fail | Return actual errors |
|
|
||||||
| `deps` | `BeadsUnknown` case | Silently passes | Log warning or fail |
|
|
||||||
|
|
||||||
### Pattern: Inconsistent State Handling
|
|
||||||
|
|
||||||
| Package | Issue | Recommendation |
|
|
||||||
|---------|-------|----------------|
|
|
||||||
| `dog/Get()` | Returns minimal Dog if state missing | Document or error |
|
|
||||||
| `config/GetAccount()` | Returns pointer to loop variable (bug!) | Return by value |
|
|
||||||
| `boot` | `LoadStatus()` returns empty struct if missing | Document behavior |
|
|
||||||
|
|
||||||
### Bug: Missing Role Mapping
|
|
||||||
|
|
||||||
| Package | Issue | Impact |
|
|
||||||
|---------|-------|--------|
|
|
||||||
| `claude` | `RoleTypeFor()` missing `deacon`, `crew` | Wrong settings applied |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Testing Gaps
|
|
||||||
|
|
||||||
| Package | Gap | Priority |
|
|
||||||
|---------|-----|----------|
|
|
||||||
| `checkpoint` | No unit tests | HIGH (crash recovery) |
|
|
||||||
| `dog` | 4 tests, major paths untested | HIGH |
|
|
||||||
| `deps` | Minimal failure path testing | MEDIUM |
|
|
||||||
| `claude` | No tests | LOW |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary Statistics
|
|
||||||
|
|
||||||
| Category | Count | Packages Affected |
|
|
||||||
|----------|-------|-------------------|
|
|
||||||
| **Dead Code Items** | 25+ | config, constants, doctor, lock, events, boot, dog, keepalive |
|
|
||||||
| **Duplicate Patterns** | 6 | util, doctor, config, lock |
|
|
||||||
| **Performance Issues** | 12 | events, townlog, doctor, dog, lock, checkpoint |
|
|
||||||
| **Error Handling Issues** | 15 | events, townlog, lock, checkpoint, deps, claude |
|
|
||||||
| **Testing Gaps** | 4 packages | checkpoint, dog, deps, claude |
|
|
||||||
|
|
||||||
## Recommended Priority
|
|
||||||
|
|
||||||
1. **Delete keepalive package** (entire package unused)
|
|
||||||
2. **Fix claude/RoleTypeFor()** (incorrect behavior)
|
|
||||||
3. **Fix config/GetAccount()** (pointer to stack bug)
|
|
||||||
4. **Fix polecat/pending.go** (non-atomic writes)
|
|
||||||
5. **Delete 21 unused constants** (maintenance burden)
|
|
||||||
6. **Consolidate atomic write pattern** (DRY)
|
|
||||||
7. **Add checkpoint tests** (crash recovery critical)
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
# Swarm (Ephemeral Worker View)
|
|
||||||
|
|
||||||
> **Note**: "Swarm" is an ephemeral concept, not a persistent entity.
|
|
||||||
> For tracking work, see [Convoys](convoy.md).
|
|
||||||
|
|
||||||
## What is a Swarm?
|
|
||||||
|
|
||||||
A **swarm** is simply "the workers currently assigned to a convoy's issues."
|
|
||||||
It has no separate ID and no persistent state - it's just a view of active workers.
|
|
||||||
|
|
||||||
| Concept | Persistent? | ID | Description |
|
|
||||||
|---------|-------------|-----|-------------|
|
|
||||||
| **Convoy** | Yes | hq-* | The tracking unit. What you create and track. |
|
|
||||||
| **Swarm** | No | None | The workers. Ephemeral view of who's working. |
|
|
||||||
|
|
||||||
## The Relationship
|
|
||||||
|
|
||||||
```
|
|
||||||
Convoy hq-abc ─────────tracks───────────► Issues
|
|
||||||
│
|
|
||||||
│ assigned to
|
|
||||||
▼
|
|
||||||
Polecats
|
|
||||||
│
|
|
||||||
────────┴────────
|
|
||||||
"the swarm"
|
|
||||||
(ephemeral)
|
|
||||||
```
|
|
||||||
|
|
||||||
When you say "kick off a swarm," you're really:
|
|
||||||
1. Creating a convoy (persistent tracking)
|
|
||||||
2. Assigning polecats to the convoy's issues
|
|
||||||
3. The swarm = those polecats while they work
|
|
||||||
|
|
||||||
When the work completes, the convoy lands and the swarm dissolves.
|
|
||||||
|
|
||||||
## Viewing the Swarm
|
|
||||||
|
|
||||||
The swarm appears in convoy status:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
gt convoy status hq-abc
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
Convoy: hq-abc (Deploy v2.0)
|
|
||||||
════════════════════════════
|
|
||||||
|
|
||||||
Progress: 2/3 complete
|
|
||||||
|
|
||||||
Issues
|
|
||||||
✓ gt-xyz: Update API closed
|
|
||||||
→ bd-ghi: Update docs in_progress @beads/amber
|
|
||||||
○ gt-jkl: Final review open
|
|
||||||
|
|
||||||
Workers (the swarm) ← this is the swarm
|
|
||||||
beads/amber bd-ghi running 12m
|
|
||||||
```
|
|
||||||
|
|
||||||
## Historical Note
|
|
||||||
|
|
||||||
Earlier Gas Town development used "swarm" as if it were a persistent entity
|
|
||||||
with its own lifecycle. The `gt swarm` commands were built on this model.
|
|
||||||
|
|
||||||
The correct model is:
|
|
||||||
- **Convoy** = the persistent tracking unit (what `gt swarm` was trying to be)
|
|
||||||
- **Swarm** = ephemeral workers (no separate tracking needed)
|
|
||||||
|
|
||||||
The `gt swarm` command is being deprecated in favor of `gt convoy`.
|
|
||||||
|
|
||||||
## See Also
|
|
||||||
|
|
||||||
- [Convoys](convoy.md) - The persistent tracking unit
|
|
||||||
- [Propulsion Principle](propulsion-principle.md) - Worker execution model
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
# Test Coverage and Quality Review
|
|
||||||
|
|
||||||
**Reviewed by**: polecat/gus
|
|
||||||
**Date**: 2026-01-04
|
|
||||||
**Issue**: gt-a02fj.9
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
- **80 test files** covering **32 out of 42 packages** (76% package coverage)
|
|
||||||
- **631 test functions** with 192 subtests (30% use table-driven pattern)
|
|
||||||
- **10 packages** with **0 test coverage** (2,452 lines)
|
|
||||||
- **1 confirmed flaky test** candidate
|
|
||||||
- Test quality is generally good with moderate mocking
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Coverage Gap Inventory
|
|
||||||
|
|
||||||
### Packages Without Tests (Priority Order)
|
|
||||||
|
|
||||||
| Priority | Package | Lines | Risk | Notes |
|
|
||||||
|----------|---------|-------|------|-------|
|
|
||||||
| **P0** | `internal/lock` | 402 | **CRITICAL** | Multi-agent lock management. Bugs cause worker collisions. Already has `execCommand` mockable for testing. |
|
|
||||||
| **P1** | `internal/events` | 295 | HIGH | Event bus for audit trail. Mutex-protected writes. Core observability. |
|
|
||||||
| **P1** | `internal/boot` | 242 | HIGH | Boot watchdog lifecycle. Spawns tmux sessions. |
|
|
||||||
| **P1** | `internal/checkpoint` | 216 | HIGH | Session crash recovery. Critical for polecat continuity. |
|
|
||||||
| **P2** | `internal/tui/convoy` | 601 | MEDIUM | TUI component. Harder to test but user-facing. |
|
|
||||||
| **P2** | `internal/constants` | 221 | LOW | Mostly configuration constants. Low behavioral risk. |
|
|
||||||
| **P3** | `internal/style` | 331 | LOW | Output formatting. Visual only. |
|
|
||||||
| **P3** | `internal/claude` | 80 | LOW | Claude settings parsing. |
|
|
||||||
| **P3** | `internal/wisp` | 52 | LOW | Ephemeral molecule I/O. Small surface. |
|
|
||||||
| **P4** | `cmd/gt` | 12 | TRIVIAL | Main entry point. Minimal code. |
|
|
||||||
|
|
||||||
**Total untested lines**: 2,452
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Flaky Test Candidates
|
|
||||||
|
|
||||||
### Confirmed: `internal/feed/curator_test.go`
|
|
||||||
|
|
||||||
**Issue**: Uses `time.Sleep()` for synchronization (lines 59, 71, 119, 138)
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Give curator time to start
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
...
|
|
||||||
// Wait for processing
|
|
||||||
time.Sleep(300 * time.Millisecond)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Risk**: Flaky under load, CI delays, or slow machines.
|
|
||||||
|
|
||||||
**Fix**: Replace with channel-based synchronization or polling with timeout:
|
|
||||||
```go
|
|
||||||
// Wait for condition with timeout
|
|
||||||
deadline := time.Now().Add(time.Second)
|
|
||||||
for time.Now().Before(deadline) {
|
|
||||||
if conditionMet() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Test Quality Analysis
|
|
||||||
|
|
||||||
### Strengths
|
|
||||||
|
|
||||||
1. **Table-driven tests**: 30% of tests use `t.Run()` (192/631)
|
|
||||||
2. **Good isolation**: Only 2 package-level test variables
|
|
||||||
3. **Dedicated integration tests**: 15 files with explicit integration/e2e naming
|
|
||||||
4. **Error handling**: 316 uses of `if err != nil` in tests
|
|
||||||
5. **No random data**: No `rand.` usage in tests (deterministic)
|
|
||||||
6. **Environment safety**: Uses `t.Setenv()` for clean env var handling
|
|
||||||
|
|
||||||
### Areas for Improvement
|
|
||||||
|
|
||||||
1. **`testing.Short()`**: Only 1 usage. Long-running tests should check this.
|
|
||||||
2. **External dependencies**: 26 tests skip when `bd` or `tmux` unavailable - consider mocking more.
|
|
||||||
3. **time.Sleep usage**: Found in `curator_test.go` - should be eliminated.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Test Smells (Minor)
|
|
||||||
|
|
||||||
| Smell | Location | Severity | Notes |
|
|
||||||
|-------|----------|----------|-------|
|
|
||||||
| Sleep-based sync | `feed/curator_test.go` | HIGH | See flaky section |
|
|
||||||
| External dep skips | Multiple files | LOW | Reasonable for integration tests |
|
|
||||||
| Skip-heavy file | `tmux/tmux_test.go` | LOW | Acceptable - tmux not always available |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Priority List for New Tests
|
|
||||||
|
|
||||||
### Immediate (P0)
|
|
||||||
|
|
||||||
1. **`internal/lock`** - Critical path
|
|
||||||
- Test `Acquire()` with stale lock cleanup
|
|
||||||
- Test `Check()` with live/dead PIDs
|
|
||||||
- Test `CleanStaleLocks()` with mock tmux sessions
|
|
||||||
- Test `DetectCollisions()`
|
|
||||||
- Test concurrent lock acquisition (race detection)
|
|
||||||
|
|
||||||
### High Priority (P1)
|
|
||||||
|
|
||||||
2. **`internal/events`**
|
|
||||||
- Test `Log()` file creation and append
|
|
||||||
- Test `write()` mutex behavior
|
|
||||||
- Test payload helpers
|
|
||||||
- Test graceful handling when not in workspace
|
|
||||||
|
|
||||||
3. **`internal/boot`**
|
|
||||||
- Test `IsRunning()` with stale markers
|
|
||||||
- Test `AcquireLock()` / `ReleaseLock()` cycle
|
|
||||||
- Test `SaveStatus()` / `LoadStatus()` round-trip
|
|
||||||
- Test degraded mode path
|
|
||||||
|
|
||||||
4. **`internal/checkpoint`**
|
|
||||||
- Test `Read()` / `Write()` round-trip
|
|
||||||
- Test `Capture()` git state extraction
|
|
||||||
- Test `IsStale()` with various durations
|
|
||||||
- Test `Summary()` output
|
|
||||||
|
|
||||||
### Medium Priority (P2)
|
|
||||||
|
|
||||||
5. **`internal/tui/convoy`** - Consider golden file tests for view output
|
|
||||||
6. **`internal/constants`** - Test any validation logic
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Missing Test Types
|
|
||||||
|
|
||||||
| Type | Current State | Recommendation |
|
|
||||||
|------|--------------|----------------|
|
|
||||||
| Unit tests | Good coverage where present | Add for P0-P1 packages |
|
|
||||||
| Integration tests | 15 dedicated files | Adequate |
|
|
||||||
| E2E tests | `browser_e2e_test.go` | Consider more CLI E2E |
|
|
||||||
| Fuzz tests | None | Consider for parsers (`formula/parser.go`) |
|
|
||||||
| Benchmark tests | None visible | Add for hot paths (`lock`, `events`) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Actionable Next Steps
|
|
||||||
|
|
||||||
1. **Fix flaky test**: Refactor `feed/curator_test.go` to use channels/polling
|
|
||||||
2. **Add lock tests**: Highest priority - bugs here break multi-agent
|
|
||||||
3. **Add events tests**: Core observability must be tested
|
|
||||||
4. **Add checkpoint tests**: Session recovery is critical path
|
|
||||||
5. **Run with race detector**: `go test -race ./...` to catch data races
|
|
||||||
6. **Consider `-short` flag**: Add `testing.Short()` checks to slow tests
|
|
||||||
@@ -1,372 +0,0 @@
|
|||||||
# Wisp Squash Design: Cadences, Rules, Templates
|
|
||||||
|
|
||||||
Design specification for how wisps squash to digests in Gas Town.
|
|
||||||
|
|
||||||
## Problem Statement
|
|
||||||
|
|
||||||
Wisps are ephemeral molecules that need to be condensed into digests for:
|
|
||||||
- **Audit trail**: What happened, when, by whom
|
|
||||||
- **Activity feed**: Observable progress in the capability ledger
|
|
||||||
- **Space efficiency**: Ephemeral data doesn't accumulate indefinitely
|
|
||||||
|
|
||||||
Currently under-designed:
|
|
||||||
- **Cadences**: When should squash happen?
|
|
||||||
- **Templates**: What should digests contain?
|
|
||||||
- **Retention**: How long to keep, when to aggregate?
|
|
||||||
|
|
||||||
## Squash Cadences
|
|
||||||
|
|
||||||
### Patrol Wisps (Deacon, Witness, Refinery)
|
|
||||||
|
|
||||||
**Trigger**: End of each patrol cycle
|
|
||||||
|
|
||||||
```
|
|
||||||
patrol-start → steps → loop-or-exit step → squash → new wisp
|
|
||||||
```
|
|
||||||
|
|
||||||
| Decision Point | Action |
|
|
||||||
|----------------|--------|
|
|
||||||
| `loop-or-exit` with low context | Squash current wisp, create new wisp |
|
|
||||||
| `loop-or-exit` with high context | Squash current wisp, handoff |
|
|
||||||
| Extraordinary action | Squash immediately, handoff |
|
|
||||||
|
|
||||||
**Rationale**: Each patrol cycle is a logical unit. Squashing per-cycle keeps
|
|
||||||
digests meaningful and prevents context-filling sessions from losing history.
|
|
||||||
|
|
||||||
### Work Wisps (Polecats)
|
|
||||||
|
|
||||||
**Trigger**: Before `gt done` or molecule completion
|
|
||||||
|
|
||||||
```
|
|
||||||
work-assigned → steps → all-complete → squash → gt done → merge queue
|
|
||||||
```
|
|
||||||
|
|
||||||
Polecats typically use regular molecules (not wisps), but when wisps are used
|
|
||||||
for exploratory work:
|
|
||||||
|
|
||||||
| Scenario | Action |
|
|
||||||
|----------|--------|
|
|
||||||
| Molecule completes | Squash to digest |
|
|
||||||
| Molecule abandoned | Burn (no digest) |
|
|
||||||
| Molecule handed off | Squash, include handoff context |
|
|
||||||
|
|
||||||
### Time-Based Cadences (Future)
|
|
||||||
|
|
||||||
For long-running molecules that span multiple sessions:
|
|
||||||
|
|
||||||
| Duration | Action |
|
|
||||||
|----------|--------|
|
|
||||||
| Session ends | Auto-squash if molecule in progress |
|
|
||||||
| > 24 hours | Create checkpoint digest |
|
|
||||||
| > 7 days | Warning: stale molecule |
|
|
||||||
|
|
||||||
**Not implemented initially** - simplicity first.
|
|
||||||
|
|
||||||
## Summary Templates
|
|
||||||
|
|
||||||
### Template Structure
|
|
||||||
|
|
||||||
Digests have three sections:
|
|
||||||
1. **Header**: Standard metadata (who, what, when)
|
|
||||||
2. **Body**: Context-specific content (from template)
|
|
||||||
3. **Footer**: System metrics (steps, duration, commit refs)
|
|
||||||
|
|
||||||
### Patrol Digest Template
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Patrol Digest: {{.Agent}}
|
|
||||||
|
|
||||||
**Cycle**: {{.CycleNumber}} | **Duration**: {{.Duration}}
|
|
||||||
|
|
||||||
### Actions Taken
|
|
||||||
{{range .Actions}}
|
|
||||||
- {{.Icon}} {{.Description}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
### Issues Filed
|
|
||||||
{{range .IssuesFiled}}
|
|
||||||
- {{.ID}}: {{.Title}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
### Metrics
|
|
||||||
- Inbox: {{.InboxCount}} messages processed
|
|
||||||
- Health checks: {{.HealthChecks}}
|
|
||||||
- Alerts: {{.AlertCount}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Work Digest Template
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
## Work Digest: {{.IssueTitle}}
|
|
||||||
|
|
||||||
**Issue**: {{.IssueID}} | **Agent**: {{.Agent}} | **Duration**: {{.Duration}}
|
|
||||||
|
|
||||||
### Summary
|
|
||||||
{{.Summary}}
|
|
||||||
|
|
||||||
### Steps Completed
|
|
||||||
{{range .Steps}}
|
|
||||||
- [{{.Status}}] {{.Title}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
### Artifacts
|
|
||||||
- Commits: {{range .Commits}}{{.Short}}, {{end}}
|
|
||||||
- Files changed: {{.FilesChanged}}
|
|
||||||
- Lines: +{{.LinesAdded}} -{{.LinesRemoved}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Formula-Defined Templates
|
|
||||||
|
|
||||||
Formulas can define custom squash templates in `[squash]` section:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
formula = "mol-my-workflow"
|
|
||||||
version = 1
|
|
||||||
|
|
||||||
[squash]
|
|
||||||
template = """
|
|
||||||
## {{.Title}} Complete
|
|
||||||
|
|
||||||
Duration: {{.Duration}}
|
|
||||||
Key metrics:
|
|
||||||
{{range .Steps}}
|
|
||||||
- {{.ID}}: {{.CustomField}}
|
|
||||||
{{end}}
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Template variables from step outputs
|
|
||||||
[squash.vars]
|
|
||||||
include_metrics = true
|
|
||||||
summary_length = "short" # short | medium | detailed
|
|
||||||
```
|
|
||||||
|
|
||||||
**Resolution order**:
|
|
||||||
1. Formula-defined template (if present)
|
|
||||||
2. Type-specific default (patrol vs work)
|
|
||||||
3. Minimal fallback (current behavior)
|
|
||||||
|
|
||||||
## Retention Rules
|
|
||||||
|
|
||||||
### Digest Lifecycle
|
|
||||||
|
|
||||||
```
|
|
||||||
Wisp → Squash → Digest (active) → Digest (archived) → Rollup
|
|
||||||
```
|
|
||||||
|
|
||||||
| Phase | Duration | Storage |
|
|
||||||
|-------|----------|---------|
|
|
||||||
| Active | 30 days | `.beads/issues.jsonl` |
|
|
||||||
| Archived | 1 year | `.beads/archive/` (compressed) |
|
|
||||||
| Rollup | Permanent | Weekly/monthly summaries |
|
|
||||||
|
|
||||||
### Rollup Strategy
|
|
||||||
|
|
||||||
After retention period, digests aggregate into rollups:
|
|
||||||
|
|
||||||
**Weekly Patrol Rollup**:
|
|
||||||
```markdown
|
|
||||||
## Week of {{.WeekStart}}
|
|
||||||
|
|
||||||
| Agent | Cycles | Issues Filed | Merges | Incidents |
|
|
||||||
|-------|--------|--------------|--------|-----------|
|
|
||||||
| Deacon | 140 | 3 | - | 0 |
|
|
||||||
| Witness | 168 | 12 | - | 2 |
|
|
||||||
| Refinery | 84 | 0 | 47 | 1 |
|
|
||||||
```
|
|
||||||
|
|
||||||
**Monthly Work Rollup**:
|
|
||||||
```markdown
|
|
||||||
## {{.Month}} Work Summary
|
|
||||||
|
|
||||||
Issues completed: {{.TotalIssues}}
|
|
||||||
Total duration: {{.TotalDuration}}
|
|
||||||
Contributors: {{range .Contributors}}{{.Name}}, {{end}}
|
|
||||||
|
|
||||||
Top categories:
|
|
||||||
{{range .Categories}}
|
|
||||||
- {{.Name}}: {{.Count}} issues
|
|
||||||
{{end}}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Retention Configuration
|
|
||||||
|
|
||||||
Per-rig settings in `config.json`:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"retention": {
|
|
||||||
"digest_active_days": 30,
|
|
||||||
"digest_archive_days": 365,
|
|
||||||
"rollup_weekly": true,
|
|
||||||
"rollup_monthly": true,
|
|
||||||
"auto_archive": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Implementation Plan
|
|
||||||
|
|
||||||
### Phase 1: Template System (MVP)
|
|
||||||
|
|
||||||
1. Add `[squash]` section parsing to formula loader
|
|
||||||
2. Create default templates for patrol and work digests
|
|
||||||
3. Enhance `bd mol squash` to use templates
|
|
||||||
4. Add `--template` flag for override
|
|
||||||
|
|
||||||
### Phase 2: Cadence Automation
|
|
||||||
|
|
||||||
1. Hook squash into `gt done` flow
|
|
||||||
2. Add patrol cycle completion detection
|
|
||||||
3. Emit squash events for activity feed
|
|
||||||
|
|
||||||
### Phase 3: Retention & Archival
|
|
||||||
|
|
||||||
1. Implement digest aging (active → archived)
|
|
||||||
2. Add `bd archive` command for manual archival
|
|
||||||
3. Create rollup generator for weekly/monthly summaries
|
|
||||||
4. Background daemon task for auto-archival
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
### Squash with Template
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Use formula-defined template
|
|
||||||
bd mol squash <id>
|
|
||||||
|
|
||||||
# Use explicit template
|
|
||||||
bd mol squash <id> --template=detailed
|
|
||||||
|
|
||||||
# Add custom summary
|
|
||||||
bd mol squash <id> --summary="Patrol complete: 3 issues filed"
|
|
||||||
```
|
|
||||||
|
|
||||||
### View Digests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# List recent digests
|
|
||||||
bd list --label=digest
|
|
||||||
|
|
||||||
# View rollups
|
|
||||||
bd rollup list
|
|
||||||
bd rollup show weekly-2025-01
|
|
||||||
```
|
|
||||||
|
|
||||||
### Archive Management
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Archive old digests
|
|
||||||
bd archive --older-than=30d
|
|
||||||
|
|
||||||
# Generate rollup
|
|
||||||
bd rollup generate --week=2025-01
|
|
||||||
|
|
||||||
# Restore from archive
|
|
||||||
bd archive restore <digest-id>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Activity Feed Integration
|
|
||||||
|
|
||||||
Digests feed into the activity feed for observability:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "digest",
|
|
||||||
"agent": "greenplace/witness",
|
|
||||||
"timestamp": "2025-12-30T10:00:00Z",
|
|
||||||
"summary": "Patrol cycle 47 complete",
|
|
||||||
"metrics": {
|
|
||||||
"issues_filed": 2,
|
|
||||||
"polecats_nudged": 1,
|
|
||||||
"duration_minutes": 12
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The feed curator (daemon) can aggregate these for dashboards.
|
|
||||||
|
|
||||||
## Formula Example
|
|
||||||
|
|
||||||
Complete formula with squash configuration:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
formula = "mol-witness-patrol"
|
|
||||||
version = 1
|
|
||||||
type = "workflow"
|
|
||||||
description = "Witness patrol cycle"
|
|
||||||
|
|
||||||
[squash]
|
|
||||||
trigger = "on_complete"
|
|
||||||
template_type = "patrol"
|
|
||||||
include_metrics = true
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
id = "inbox-check"
|
|
||||||
title = "Check inbox"
|
|
||||||
description = "Process messages and escalations"
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
id = "health-scan"
|
|
||||||
title = "Scan polecat health"
|
|
||||||
description = "Check all polecats for stuck/idle"
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
id = "nudge-stuck"
|
|
||||||
title = "Nudge stuck workers"
|
|
||||||
description = "Send nudges to idle polecats"
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
id = "loop-or-exit"
|
|
||||||
title = "Loop or exit decision"
|
|
||||||
description = "Decide whether to continue or handoff"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration
|
|
||||||
|
|
||||||
### Existing Digests
|
|
||||||
|
|
||||||
Current minimal digests remain valid. New template system is additive:
|
|
||||||
- Old digests: Title, basic description
|
|
||||||
- New digests: Structured content, metrics
|
|
||||||
|
|
||||||
### Backward Compatibility
|
|
||||||
|
|
||||||
- `bd mol squash` without template uses current behavior
|
|
||||||
- Formulas without `[squash]` section use type defaults
|
|
||||||
- No breaking changes to existing workflows
|
|
||||||
|
|
||||||
## Design Decisions
|
|
||||||
|
|
||||||
### Why Squash Per-Cycle?
|
|
||||||
|
|
||||||
**Alternative**: Squash on session end only
|
|
||||||
|
|
||||||
**Rejected because**:
|
|
||||||
- Sessions can crash mid-cycle (lost audit trail)
|
|
||||||
- High-context sessions may span multiple cycles
|
|
||||||
- Per-cycle gives finer granularity
|
|
||||||
|
|
||||||
### Why Formula-Defined Templates?
|
|
||||||
|
|
||||||
**Alternative**: Hard-coded templates per role
|
|
||||||
|
|
||||||
**Rejected because**:
|
|
||||||
- Different workflows have different metrics
|
|
||||||
- Extensibility for custom formulas
|
|
||||||
- Separation of concerns (workflow defines its own output)
|
|
||||||
|
|
||||||
### Why Retain Forever (as Rollups)?
|
|
||||||
|
|
||||||
**Alternative**: Delete after N days
|
|
||||||
|
|
||||||
**Rejected because**:
|
|
||||||
- Capability ledger needs long-term history
|
|
||||||
- Rollups are small (aggregate stats)
|
|
||||||
- Audit requirements vary by use case
|
|
||||||
|
|
||||||
## Future Considerations
|
|
||||||
|
|
||||||
- **Search**: Full-text search over archived digests
|
|
||||||
- **Analytics**: Metrics aggregation dashboard
|
|
||||||
- **Export**: Export digests to external systems
|
|
||||||
- **Compliance**: Configurable retention for regulatory needs
|
|
||||||
Reference in New Issue
Block a user