feat(07-02): wire sweepStaleReviews into heartbeat timer

- Import sweepStaleReviews, resolveApprovalDecision, dispatchAgentMessage
- Insert stale review sweep into per-company heartbeat loop after budget reset
- Sweep runs on every 15-second heartbeat cycle for each active company
- Local callback stubs for handleTaskStatusChange and handleApprovalResolved
- Error handling prevents sweep failures from crashing the heartbeat loop
- Fix test type casts to use as-unknown-as for vi.fn mock compatibility
- TypeScript compiles cleanly, 249/249 tests pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-27 00:43:08 -04:00
1 parent 0bfbdec09b
commit c4eb4423db
2 files changed
+38 -7

No files matched your search

+7 -7
View File
@@ -237,7 +237,7 @@ describe("sweepStaleReviews", () => {
it("escalates to manager's manager when task in_review for 35 minutes", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
// Task in review for 35 min
dbMock.queryAll.mockReturnValueOnce([
@@ -265,7 +265,7 @@ describe("sweepStaleReviews", () => {
it("does not escalate when task in_review for only 25 minutes (under threshold)", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn> };
dbMock.queryAll.mockReturnValueOnce([
{ id: "task-1", assigneeAgentId: "agent-1", updatedAt: TWENTY_FIVE_MIN_AGO, title: "Build login" },
@@ -279,7 +279,7 @@ describe("sweepStaleReviews", () => {
it("notifies human when no higher manager (reviewer is CEO)", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
dbMock.queryAll
.mockReturnValueOnce([
@@ -305,7 +305,7 @@ describe("sweepStaleReviews", () => {
it("auto-approves pending approval linked to stale review task", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
// First queryAll: stale task
dbMock.queryAll.mockReturnValueOnce([
@@ -332,7 +332,7 @@ describe("sweepStaleReviews", () => {
it("catches resolveApprovalDecision error gracefully (race condition)", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn> };
dbMock.queryAll.mockReturnValueOnce([
{ id: "task-1", assigneeAgentId: "agent-1", updatedAt: THIRTY_FIVE_MIN_AGO, title: "Build login" },
@@ -352,7 +352,7 @@ describe("sweepStaleReviews", () => {
it("advances task status to done after escalation", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn>; advanceTaskStatus: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn>; getManagerForAgent: ReturnType<typeof vi.fn>; getChainOfCommand: ReturnType<typeof vi.fn>; advanceTaskStatus: ReturnType<typeof vi.fn> };
dbMock.queryAll.mockReturnValueOnce([
{ id: "task-1", assigneeAgentId: "agent-1", updatedAt: THIRTY_FIVE_MIN_AGO, title: "Build login" },
@@ -373,7 +373,7 @@ describe("sweepStaleReviews", () => {
it("skips task with no assigneeAgentId", () => {
const deps = makeSweepDeps();
const dbMock = deps.db as { queryAll: ReturnType<typeof vi.fn> };
const dbMock = deps.db as unknown as { queryAll: ReturnType<typeof vi.fn> };
dbMock.queryAll.mockReturnValueOnce([
{ id: "task-1", assigneeAgentId: null, updatedAt: THIRTY_FIVE_MIN_AGO, title: "Orphan task" },