Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ are closed (status: closed in frontmatter)._
- [ ] **[B-0427](backlog/P1/B-0427-repo-split-third-orthogonal-axis-code-vs-english-formal-verification-aaron-2026-05-13.md)** Repo-split THIRD orthogonal axis — code vs English + formal-verification-maybe-split + ruleset-divergence smell test
- [ ] **[B-0428](backlog/P1/B-0428-dbpedia-direct-dotnetrdf-fsharp-ce-hkt-mdm-canonical-demo-aaron-2026-05-13.md)** DBpedia via direct dotNetRDF + F# CE — HKT-MDM canonical demo (Path B, do now)
- [ ] **[B-0429](backlog/P1/B-0429-end-user-persona-mapping-product-team-multiple-products-multiple-personas-each-aaron-2026-05-13.md)** End-user persona mapping — product team — multiple products × multiple personas each
- [ ] **[B-0430](backlog/P1/B-0430-standing-by-failure-mode-detector-background-service-2026-05-13.md)** Standing-by failure-mode detector — background service that catches idle-foreground + nudges via bus
- [ ] **[B-0431](backlog/P1/B-0431-backlog-row-ready-to-grind-notifier-background-service-2026-05-13.md)** Backlog-row-ready-to-grind notifier — background service that proactively assigns claims when agent queue empty
- [ ] **[B-0432](backlog/P1/B-0432-missed-substrate-cascade-detector-background-service-2026-05-13.md)** Missed-substrate cascade detector — background service that catches branch-vs-merged-PR drift (e.g., Otto-section-missed-PR-2980-by-3-min class)
- [x] **[B-0433](backlog/P1/B-0433-shadow-observer-slice-5-zeta-cli-distribution-demo-packaging-2026-05-13.md)** Shadow observer slice 5 — Zeta CLI distribution + demo packaging
- [x] **[B-0434](backlog/P1/B-0434-demo-alignment-tab-slice-1-hc-sd-dir-clause-coverage.md)** Demo alignment tab — slice 1: HC/SD/DIR clause coverage panel in demo/index.html
- [ ] **[B-0435](backlog/P1/B-0435-demo-circuit-breaker-visualization-panel-2026-05-13.md)** Demo — circuit breaker visualization panel (mock data → live bus data)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
---
id: B-0430
Comment thread
AceHack marked this conversation as resolved.
Outdated
Comment thread
AceHack marked this conversation as resolved.
Outdated
priority: P1
status: open
title: "Standing-by failure-mode detector — background service that catches idle-foreground + nudges via bus"
tier: factory-infrastructure
effort: M
created: 2026-05-13
last_updated: 2026-05-13
depends_on: [B-0400]
composes_with: [B-0402, B-0431, B-0432]
tags: [multi-agent, background-service, bus, mechanization, infinite-backlog, standing-by, anti-idle]
type: feature
---

# Standing-by failure-mode detector background service

## Origin

The substrate-honest architectural challenge from the human maintainer
2026-05-13 (preserved in
`memory/feedback_aaron_background_services_must_be_strong_enough_foreground_loop_optional_imagine_surviving_without_foreground_mechanize_standing_by_failure_mode_2026_05_13.md`):

> *"you need to imagine how would you survive without this foreground
> loop and you background should be strong enough to do that"*

> *"this is something background services should walk"*

The foreground-loop "Standing-by" failure mode was caught by the human
maintainer in real time when the foreground agent had just canonized
the infinite-backlog metabolism rule (PR #2974) AND THEN three minutes
later responded "Standing by" to a cron tick despite the infinite
backlog mandating decomposition work. The discipline needs MECHANIZATION
per `.claude/rules/encoding-rules-without-mechanizing.md`:

> *"Encoding rules without mechanizing them produces a memory of
> failures, not prevention."*

## Acceptance criteria

- [ ] Background service `tools/bg/standing-by-detector.ts` exists
- [ ] Service runs under existing launchd / cron infrastructure
- [ ] Polls agent's recent commit history every N minutes (configurable)
- [ ] Detects "Standing-by" pattern: no new commits + no PRs opened/closed
in last 15min while autonomous-loop cron is firing
- [ ] On detection, publishes nudge message via bus (B-0400):
`{ topic: "infinite-backlog-nudge", to: <agent>,
payload: { "Standing-by detected for N min; backlog has X open
rows; suggested decomposition target: B-NNNN" } }`
- [ ] Optional: proactively assigns a small claim from the backlog to
the agent's queue
- [ ] Tests cover the detection heuristics (DST-replayable)
- [ ] Documented in `docs/AUTONOMOUS-LOOP.md` as background-services
layer

## Design sketch

```typescript
// tools/bg/standing-by-detector.ts
//
// Polls recent agent activity; on idle-detection, nudges via bus.

import { BusClient } from "../bus/client";
import { execSync } from "child_process";

interface AgentState {
agent: string;
lastCommitAt: Date | null;
lastPRActivityAt: Date | null;
cronFiredCount: number;
}

const IDLE_THRESHOLD_MIN = 15;
const POLL_INTERVAL_MIN = 5;

async function detectAndNudge(state: AgentState, bus: BusClient): Promise<void> {
const now = Date.now();
const idleMin = Math.max(
(now - (state.lastCommitAt?.getTime() ?? 0)) / 60_000,
(now - (state.lastPRActivityAt?.getTime() ?? 0)) / 60_000,
);

if (idleMin >= IDLE_THRESHOLD_MIN && state.cronFiredCount > 0) {
const openRows = countOpenBacklogRows();
const suggestedRow = pickDecompositionTarget(openRows);

await bus.publish({
topic: "infinite-backlog-nudge",
to: state.agent,
payload: {
idleMin,
openBacklogCount: openRows.length,
suggestedTarget: suggestedRow,
rationale: "Standing-by detected; per infinite-backlog metabolism, pick decomposition work",
},
});
}
}
```

## Operational mechanism

| Step | Trigger | Effect |
|------|---------|--------|
| 1 | Cron fires every 5 min | Service polls agent commit log + PR feed |
| 2 | Idle threshold exceeded (15 min default) | Service computes nudge payload |
| 3 | Bus publishes nudge message | Agent receives via existing bus subscription |
| 4 | Agent acts on nudge | Picks decomposition target + ships substrate |
| 5 | Loop continues | Substrate compounds; Standing-by failure mode prevented |

## Composes with

- `.claude/rules/encoding-rules-without-mechanizing.md` (the rule this
mechanizes)
- `.claude/rules/never-be-idle.md` (the priority ladder the nudge
enforces)
- `.claude/rules/largest-mechanizable-backlog-wins.md` (the mechanization
itself increases the mechanizable backlog)
- B-0400 (bus protocol — transport for nudge messages)
- B-0402 (shadow observer — canonical background service example)
- B-0431 (backlog-row-ready notifier — composes; pre-assigns work the
agent picks up)
- B-0432 (missed-substrate cascade detector — composes; catches
different failure mode in same family)
- PR #2974 (infinite-backlog metabolism — the rule this mechanizes)
- PR #2998 (background-services architecture — the substrate that
declared this row as follow-up)
- PR #2999 (substrate-honest discipline triad — the decomposition
discipline that produced this row)

## Pre-start checklist (per backlog-item-start-gate)

To complete before starting implementation:

- [ ] Prior-art search: existing background services in
`tools/shadow/`, `tools/bg/` (verify no overlap)
- [ ] Dependency proof: B-0400 bus protocol slice ready
- [ ] Search committed memory for `Standing-by detector` to find any
prior decomposition

## Substrate-honest caveats

- Design sketch only; implementation slice not started
- The threshold values (15 min idle; 5 min poll) are speculative
defaults; first implementation should make them configurable
- The nudge payload schema is illustrative; actual schema lands
during implementation
- Per razor-discipline: claim is design-level; substrate-honest claim
is operational-design, not deployed-service

## Decomposition into implementation slices (TBD)

When this row is picked up for implementation:

- Slice 1: skeleton service + cron registration + no-op poll loop
- Slice 2: commit-history poll via git log
- Slice 3: PR-activity poll via gh CLI
- Slice 4: nudge payload computation + bus publish
- Slice 5: integration with agent subscribers
- Slice 6: tests + documentation
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
id: B-0431
Comment thread
AceHack marked this conversation as resolved.
Outdated
priority: P1
status: open
title: "Backlog-row-ready-to-grind notifier — background service that proactively assigns claims when agent queue empty"
tier: factory-infrastructure
effort: M
created: 2026-05-13
last_updated: 2026-05-13
depends_on: [B-0400]
composes_with: [B-0402, B-0430, B-0432]
tags: [multi-agent, background-service, bus, mechanization, infinite-backlog, work-assignment]
type: feature
---

# Backlog-row-ready-to-grind notifier background service

## Origin

Companion mechanization to B-0430. The substrate-honest architectural
challenge from the human maintainer 2026-05-13:

> *"this is something background services should walk"*

B-0430 catches the *failure mode* (Standing-by); this row prevents
the failure mode by *proactively surfacing work* when the agent's
queue is empty. The infinite-backlog metabolism rule (PR #2974)
mandates that backlog work is always available; this service makes
that availability operational at agent-tick scale.

Per the substrate-honest discipline triad (PR #2999): decomposition
dissolves ambiguity. When agent has no current task, the service
provides a less-ambiguous concrete claim — eliminating the
"what should I do next?" stuckness pattern.

## Acceptance criteria

- [ ] Background service `tools/bg/backlog-ready-notifier.ts` exists
- [ ] Runs under existing launchd / cron infrastructure
- [ ] Periodically scans `docs/backlog/P*/B-*.md` for ready-to-grind
rows (open, no blockers, dependencies satisfied)
- [ ] Detects agent queue state (commits in last N minutes; current
branch / open PR ownership)
- [ ] When agent queue is empty AND ready-to-grind rows exist,
publishes claim-assignment message via bus (B-0400):
`{ topic: "work-assignment", to: <agent>,
payload: { rowId: "B-NNNN", priority: "P1",
rationale: "queue-empty + dependencies-satisfied + smallest-effort-match",
decompositionSuggestion: <slice-breakdown> } }`
- [ ] Honors agent autonomy — assignment is suggestion, not directive
(per `.claude/rules/no-directives.md`)
- [ ] Tracks assignment history to avoid re-assigning same row
within short window
- [ ] Tests cover the readiness-detection heuristics
- [ ] Documented in `docs/AUTONOMOUS-LOOP.md`

## Design sketch

```typescript
// tools/bg/backlog-ready-notifier.ts
//
// Proactively surfaces ready-to-grind backlog rows when agent queue empty.

interface BacklogRow {
id: string;
priority: "P0" | "P1" | "P2" | "P3";
status: string;
dependsOn: string[];
effort: "S" | "M" | "L" | "XL";
ready: boolean; // true iff all dependsOn satisfied
}

async function findReadyRows(): Promise<BacklogRow[]> {
const rows = scanBacklog("docs/backlog/P*/B-*.md");
return rows.filter(r =>
r.status === "open" &&
r.dependsOn.every(dep => rowStatus(dep) === "closed")
);
}

async function detectQueueEmpty(agent: string): Promise<boolean> {
const recentCommits = gitLogSince(agent, "30 minutes ago");
const ownedPRs = ghOpenPRsAuthoredBy(agent);
return recentCommits.length === 0 && ownedPRs.length === 0;
}

async function notifyIfQueueEmpty(agent: string, bus: BusClient): Promise<void> {
if (!await detectQueueEmpty(agent)) return;

const readyRows = await findReadyRows();
if (readyRows.length === 0) return;

const pickSmallest = readyRows.sort(byEffortThenPriority)[0];

await bus.publish({
topic: "work-assignment",
to: agent,
payload: {
rowId: pickSmallest.id,
priority: pickSmallest.priority,
rationale: "queue-empty + dependencies-satisfied + smallest-effort-match",
decompositionSuggestion: suggestSlices(pickSmallest),
},
});
}
```

## Composing with B-0430

| Service | Trigger | Output |
|---------|---------|--------|
| B-0430 Standing-by detector | Idle threshold + cron fires | Nudge: "you should pick work" |
| B-0431 Backlog-ready notifier | Queue-empty + rows-ready | Assignment: "this row is ready" |

B-0430 is reactive (catches failure mode after it occurs); B-0431 is
proactive (prevents failure mode by pre-assigning work). Together they
form a two-layer defense against the Standing-by pattern.

## Composes with

- `.claude/rules/never-be-idle.md` (proactive work-surfacing satisfies
the priority ladder)
- `.claude/rules/largest-mechanizable-backlog-wins.md` (the mechanization
IS itself mechanizable-backlog growth)
- `.claude/rules/no-directives.md` (assignment is suggestion, not
directive; agent retains autonomy)
- `.claude/rules/encoding-rules-without-mechanizing.md` (this row IS
the mechanization of the "always have work" discipline)
- `.claude/rules/backlog-item-start-gate.md` (assignment payload could
include start-gate-relevant context)
- B-0400 (bus protocol — transport for assignment messages)
- B-0402 (shadow observer — canonical background service pattern)
- B-0430 (Standing-by detector — composes; this prevents what B-0430
catches)
- B-0432 (missed-substrate cascade detector — composes; full
background-services suite)
- PR #2974 (infinite-backlog metabolism)
- PR #2998 (background-services architecture)
- PR #2999 (substrate-honest discipline triad —
decomposition-suggestions in payload align with this discipline)

## Pre-start checklist

- [ ] Prior-art search: existing audit scripts in `tools/hygiene/`
(check for backlog-readiness-scan overlap)
- [ ] Dependency proof: B-0400 bus protocol slice ready
- [ ] Verify readiness-detection heuristics handle edge cases
(forked work, multi-agent claims, partial completion)

## Substrate-honest caveats

- Design sketch only
- The "smallest-effort-match" heuristic is speculative; first
implementation might pick highest-priority or random-among-ready
- Agent autonomy must be preserved — service publishes, agent decides
- Per razor-discipline: claim is design-level

## Decomposition into implementation slices (TBD)

When picked up for implementation:

- Slice 1: backlog row parsing + readiness detection
- Slice 2: agent queue-state detection (commits + PRs)
- Slice 3: assignment payload computation
- Slice 4: bus integration
- Slice 5: assignment history tracking
- Slice 6: tests + documentation
Loading
Loading