AkurAI Build
Menu

popagent

public

Latest change 2fb6f198c4c71ef37dffc8ac5dca8482068a7bfc - Add governed AkurAI Build maintenance by AkurAI Build

import { describe, expect, test } from "bun:test";
import { renderToStaticMarkup } from "react-dom/server";
import type { AgentWorkflowDetail, AgentWorkflowSummary, EvolutionRevision, EvolutionSignal } from "../api-types";
import {
  AutonomyRevisionList,
  AutonomySignalList,
  AutonomyWorkflowPhaseDetail,
  AutonomyWorkflowRail,
  countAutonomySignalHealth,
  startAutonomyHistoryPolling,
} from "./AutonomySettingsPanel";

const timestamp = "2026-08-14T12:00:00.000Z";

describe("autonomy history", () => {
  test("shows processing, retry, and dead-letter evidence without hiding errors", () => {
    const signal: EvolutionSignal = {
      id: "signal-1",
      sessionId: "session-1",
      turnId: "turn-1",
      traceId: "trace-1",
      agentId: "orchistrator",
      workspaceId: "default",
      kind: "turn-failure",
      summary: "Provider timed out while reflecting.",
      status: "dead-letter",
      attempts: 3,
      nextAttemptAt: null,
      processedAt: timestamp,
      error: "Provider timeout",
      createdAt: timestamp,
      updatedAt: timestamp,
    };
    const processing: EvolutionSignal = {
      ...signal,
      id: "signal-processing",
      status: "processing",
      attempts: 1,
      error: null,
    };
    const retry: EvolutionSignal = {
      ...signal,
      id: "signal-retry",
      status: "pending",
      attempts: 2,
      nextAttemptAt: timestamp,
      error: null,
    };
    const signals = [processing, retry, signal];
    const html = renderToStaticMarkup(<AutonomySignalList signals={signals} />);

    expect(html).toContain("processing");
    expect(html).toContain("pending");
    expect(html).toContain("retry");
    expect(html).toContain("dead-letter");
    expect(html).toContain("3 attempts");
    expect(html).toContain("Provider timeout");
    expect(html).toContain("trace trace-1");
    expect(countAutonomySignalHealth(signals)).toEqual({
      pending: 1,
      processing: 1,
      applied: 0,
      ignored: 0,
      retried: 2,
      deadLetters: 1,
    });
  });

  test("refreshes while mounted, then aborts the active request on unmount", async () => {
    const secondStarted = Promise.withResolvers<void>();
    const releaseSecond = Promise.withResolvers<void>();
    let calls = 0;
    let requestSignal: AbortSignal | undefined;
    const poll = startAutonomyHistoryPolling(async (signal) => {
      calls++;
      requestSignal = signal;
      if (calls === 2) {
        secondStarted.resolve();
        await releaseSecond.promise;
      }
    }, 0);

    await secondStarted.promise;
    expect(calls).toBe(2);
    poll.stop();
    expect(requestSignal?.aborted).toBe(true);
    releaseSecond.resolve();
    await releaseSecond.promise;
    await Promise.resolve();
    expect(calls).toBe(2);
  });

  test("offers revert only for an applied learned revision", () => {
    const revision = (status: EvolutionRevision["status"]): EvolutionRevision => ({
      id: `revision-${status}`,
      agentId: "orchistrator",
      targetType: "overlay",
      targetKey: "reflection",
      beforeContent: "Before",
      afterContent: "After",
      rationale: "Repeated operator corrections",
      evidenceIds: ["signal-1"],
      revertsRevisionId: null,
      status,
      createdAt: timestamp,
      appliedAt: timestamp,
    });

    const original = revision("applied");
    const compensation = {
      ...revision("reverted"),
      revertsRevisionId: original.id,
    };
    const applied = renderToStaticMarkup(<AutonomyRevisionList revisions={[original]} onRevert={() => undefined} />);
    const reverted = renderToStaticMarkup(<AutonomyRevisionList revisions={[compensation]} onRevert={() => undefined} />);
    const superseded = renderToStaticMarkup(<AutonomyRevisionList revisions={[compensation, original]} onRevert={() => undefined} />);
    const fact = renderToStaticMarkup(<AutonomyRevisionList
      revisions={[{ ...original, id: "revision-fact", targetType: "fact", targetKey: "verified-command" }]}
      onRevert={() => undefined}
    />);

    expect(applied).toContain("Inspect learned change");
    expect(applied).toContain("Revert change");
    expect(reverted).toContain("reverted");
    expect(reverted).toContain(`reverts ${original.id}`);
    expect(reverted).not.toContain("Revert change");
    expect(superseded).not.toContain("Revert change");
    expect(fact).toContain("Learned durable fact");
  });
  test("renders the ordered workflow rail, every phase state, and outcome guidance accessibly", () => {
    const phaseIds = ["prepare", "research", "decide", "implement", "inspect-change", "verify", "review", "commit"] as const;
    const states = ["waiting", "active", "complete", "failed", "cancelled", "skipped", "complete", "complete"] as const;
    const workflow: AgentWorkflowSummary = {
      runId: "run-1",
      correlationId: "corr-1",
      state: "failed",
      currentPhase: "verify",
      phases: phaseIds.map((id, index) => ({
        id,
        label: id,
        state: states[index]!,
        evidence: [`Evidence for ${id}`],
      })),
    };
    const detail: AgentWorkflowDetail = {
      ...workflow,
      phases: workflow.phases.map((phase) => ({
        ...phase,
        startedAt: timestamp,
        completedAt: timestamp,
        error: phase.id === "verify" ? "Focused check failed" : null,
      })),
    };
    const rail = renderToStaticMarkup(<AutonomyWorkflowRail workflow={workflow} selectedPhase="verify" onSelect={() => undefined} />);
    expect(rail).toContain('aria-label="Autonomous workflow phases"');
    expect(rail).toContain('aria-current="step"');
    for (const label of ["Prepare", "Research", "Decide", "Implement", "Inspect change", "Verify", "Review", "Commit"]) expect(rail).toContain(label);
    for (const state of ["Waiting", "Active", "Complete", "Failed", "Cancelled", "Skipped"]) expect(rail).toContain(state);

    const failed = renderToStaticMarkup(<AutonomyWorkflowPhaseDetail workflow={detail} selectedPhase="verify" />);
    const noOp = renderToStaticMarkup(<AutonomyWorkflowPhaseDetail workflow={detail} selectedPhase="decide" />);
    const commit = renderToStaticMarkup(<AutonomyWorkflowPhaseDetail workflow={detail} selectedPhase="commit" />);
    expect(failed).toContain("Focused check failed");
    expect(failed).toContain("This phase failed");
    expect(noOp).toContain("No-op");
    expect(commit).toContain("local to the prepared branch");
  });
});