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
2 changes: 1 addition & 1 deletion docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ are closed (status: closed in frontmatter)._
- [ ] **[B-0496](backlog/P1/B-0496-hamiltonian-viz-slice-2-live-github-api-2026-05-14.md)** Hamiltonian viz — slice-2: live GitHub API commit fetch → trajectory
- [ ] **[B-0497](backlog/P1/B-0497-b0440-slice-6-standing-by-detector-launchd-registration-2026-05-14.md)** B-0440 slice 6 — standing-by-detector launchd plist + AUTONOMOUS-LOOP.md wiring update
- [x] **[B-0500](backlog/P1/B-0500-b0441-slice-3-queue-state-guard-poll-once-wiring-2026-05-14.md)** B-0441 slice 3 — wire isAgentQueueEmpty guard into pollOnce
- [ ] **[B-0501](backlog/P1/B-0501-b0441-slice-5-assignment-history-dedup-cooldown-2026-05-14.md)** B-0441 slice 5 — assignment history dedup cooldown (avoid re-assigning same row within short window)
- [x] **[B-0501](backlog/P1/B-0501-b0441-slice-5-assignment-history-dedup-cooldown-2026-05-14.md)** B-0441 slice 5 — assignment history dedup cooldown (avoid re-assigning same row within short window)
- [ ] **[B-0502](backlog/P1/B-0502-b0441-slice-6-launchd-plist-autonomous-loop-docs-2026-05-14.md)** B-0441 slice 6 — launchd plist for backlog-ready-notifier + AUTONOMOUS-LOOP.md update
- [x] **[B-0503](backlog/P1/B-0503-b0442-slice5a-open-recovery-pr-core-function-2026-05-14.md)** B-0442 slice 5a — openRecoveryPR core function + RecoveryAdapters + DST tests
- [x] **[B-0504](backlog/P1/B-0504-b0442-slice5b-wire-auto-recover-into-pollonce-2026-05-14.md)** B-0442 slice 5b — wire --auto-recover into pollOnce + real RecoveryAdapters + config flags
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ provides a less-ambiguous concrete claim — eliminating the
decompositionSuggestion: <slice-breakdown> } }` (Slice 4, shipped)
- [x] Honors agent autonomy — assignment is suggestion, not directive
(per `.claude/rules/no-directives.md`) — by design; envelope is advisory
- [ ] Tracks assignment history to avoid re-assigning same row
within short window (Slice 5a, B-0501 open — `historyFile`/cooldown logic not yet in `tools/bg/backlog-ready-notifier.ts`)
- [x] Tracks assignment history to avoid re-assigning same row
within short window (Slice 5a, B-0501 shipped — `historyFile`/`cooldownMin` config + read/write adapters + cooldown-gate logic in `tools/bg/backlog-ready-notifier.ts`; 8 new tests cover skip-within-window / re-assign-after-window / first-assignment / multi-row-mix / pruning)
- [x] Tests cover the readiness-detection heuristics
(`tools/bg/backlog-ready-notifier.test.ts`)
- [x] Documented in `docs/AUTONOMOUS-LOOP.md`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
id: B-0501
priority: P1
status: open
status: closed
title: "B-0441 slice 5 — assignment history dedup cooldown (avoid re-assigning same row within short window)"
tier: factory-infrastructure
effort: S
created: 2026-05-14
last_updated: 2026-05-14
last_updated: 2026-05-20
parent: B-0441
depends_on: []
composes_with: [B-0441, B-0500, B-0502]
Expand All @@ -28,34 +28,44 @@ busy. This produces noisy bus output and makes the assignment signal less meanin

## Acceptance criteria

- [ ] `NotifierConfig` gains a `historyFile` field (default
- [x] `NotifierConfig` gains a `historyFile` field (default
`"/tmp/zeta-bus/assignment-history.json"`; respects `ZETA_BUS_DIR` if set)
and a `cooldownMin` field (default `30`)
- [ ] Before publishing a work-assignment envelope for a given `rowId`, check the
- [x] Before publishing a work-assignment envelope for a given `rowId`, check the
history file:
- If `rowId` appears in the history with a timestamp within `cooldownMin` minutes
of `now()` → skip that row (do not publish)
- If absent or expired → publish and record `{ rowId, publishedAt: now().toISOString() }`
- [ ] After publishing, write the updated history back to `historyFile`:
- [x] After publishing, write the updated history back to `historyFile`:
- Prune entries older than `cooldownMin` before writing to bound file size
- Use atomic write (write to `<historyFile>.tmp` then rename) to survive concurrent
access from multiple notifier instances
- [ ] `PollResult` gains a `skippedDueToCooldown: string[]` field listing any `rowId`s
- [x] `PollResult` gains a `skippedDueToCooldown: string[]` field listing any `rowId`s
that were skipped because of cooldown
- [ ] Adapters interface gains:
- [x] Adapters interface gains:
- `readHistoryFile: (path: string) => AssignmentHistory | null`
(returns null when file absent or unreadable)
- `writeHistoryFile: (path: string, history: AssignmentHistory) => void`
- Tests inject fake implementations; production uses `REAL_ADAPTERS` with
`fs.readFileSync` / atomic-rename write
- [ ] Tests added (DST-replayable with injected adapters):
- [x] Tests added (DST-replayable with injected adapters):
- Row assigned at T=0; same row at T=15min (within 30min cooldown) → skipped
- Row assigned at T=0; same row at T=35min (after 30min cooldown) → re-assigned
- History file absent → treated as empty; first assignment proceeds normally
- Multiple rows in cooldown → only expired rows published; `skippedDueToCooldown`
lists skipped IDs
- History pruning: entries older than `cooldownMin` removed on write

## Resolution

Shipped in this PR. 8 new tests (45 total) cover all acceptance criteria + bonus
coverage of `defaultHistoryFile()` honoring `ZETA_BUS_DIR` + new `--history-file`
and `--cooldown-min` CLI flags. REAL_ADAPTERS uses atomic-rename via
`renameSync(tmp, path)` after `writeFileSync(tmp, ...)`. Default config resolves
the history-file path at module-load time via `defaultHistoryFile()` honoring
`process.env.ZETA_BUS_DIR`. B-0441 parent acceptance criterion "Tracks assignment
history to avoid re-assigning same row within short window" is now satisfied.

## Design sketch

```typescript
Expand Down
Loading
Loading