moadim 3.3.1

Loop engine for AI agents — routines over REST, MCP, and a built-in web UI
import { Link } from "react-router-dom";
import { abstime } from "../../lib/cronUtils";
import { exitCodeMeaning, type FailureCauseReport } from "./exitCodeMath";

/** Routines listed inline per cause before collapsing the rest into "+N more". */
const MAX_ROUTINES = 3;

/**
 * Failure causes: failed runs grouped by exit code, so a fleet-wide pattern (timeouts, OOM kills,
 * missing binaries) stands out from a single routine's own bug.
 */
export function FailureCauses({ report }: { report: FailureCauseReport }) {
  const { causes, totalFailed } = report;
  if (causes.length === 0) return null;
  return (
    <details className="table-wrap adherence" open>
      <summary className="adherence-hd">
        <span className="filter-label">FAILURE CAUSES</span>
        <span className="cell-meta">
          {totalFailed} failed runs · {causes.length} distinct exit {causes.length === 1 ? "code" : "codes"}
        </span>
      </summary>
      <p className="adherence-note">
        Failed runs in the fetched sample grouped by exit code. The same code across many routines usually means a
        host-level cause.
      </p>
      <table>
        <thead>
          <tr>
            <th>EXIT CODE</th>
            <th>MEANING</th>
            <th>FAILURES</th>
            <th>ROUTINES</th>
            <th>LAST SEEN</th>
          </tr>
        </thead>
        <tbody>
          {causes.map((c) => {
            const extra = c.routines.length - MAX_ROUTINES;
            return (
              <tr key={c.code ?? "none"}>
                <td>
                  <span className="run-status failed">{c.code ?? "?"}</span>
                </td>
                <td className="cell-meta">{exitCodeMeaning(c.code)}</td>
                <td className="cell-meta">
                  {c.count} ({Math.round((c.count / totalFailed) * 100)}%)
                </td>
                <td>
                  {c.routines.slice(0, MAX_ROUTINES).map((r, i) => (
                    <span key={r.id}>
                      {i > 0 ? ", " : null}
                      <Link to={`/routines?history=${encodeURIComponent(r.id)}`}>{r.title}</Link>
                      {r.count > 1 ? <span className="cell-meta"> ×{r.count}</span> : null}
                    </span>
                  ))}
                  {extra > 0 ? <span className="cell-meta"> +{extra} more</span> : null}
                </td>
                <td className="cell-meta">
                  <Link
                    to={`/runs/${encodeURIComponent(c.last.routineId)}/${encodeURIComponent(c.last.workbench)}`}
                    title="Open the newest failed run with this exit code"
                  >
                    {abstime(c.last.at)}
                  </Link>
                </td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </details>
  );
}