import { JudgeAdvice, JudgePickBadge } from "./judge.tsx";
import { ArchivedBadge } from "./archive.tsx";
import { RaceCompare } from "./race-usage.tsx";
import { BudgetUsage, UsageFigures } from "./usage.tsx";
import { LaneRunner, laneSilkStyle, LaneMarker, LaneConnector } from "./lane.tsx";
import { Badge, Button, Tooltip } from "@cloudflare/kumo";
import { useEffect, useRef, useState, type CSSProperties } from "react";
import type { Brand, ProjectState, Race, RaceEntrant } from "./contracts.ts";
import type { ViewModel } from "./model.ts";
import type { ViewActions } from "./view.tsx";
import { duration, receiptWord } from "./receipts.tsx";
import { oldestLoadedActivity, packetPushes } from "./fork-graph-model.ts";
import { milestoneDescription, raceAnnouncementChanges, raceAnnouncementSnapshot } from "./race-announcements.ts";
import {
entrantResult,
entrantChecks,
entrantReviews,
ordinal,
photoFinish,
raceEntrants,
raceMilestones,
raceSplit,
raceStart,
rejectionDelta,
timestamp,
} from "./race-model.ts";
function Place({ entrant }: { entrant: RaceEntrant }) {
return (
entrant.place !== null && (
{ordinal(entrant.place)}
)
);
}
function Lane({
entrant,
race,
state,
brand,
owner,
ledger,
}: {
entrant: RaceEntrant;
race: Race;
state: ProjectState;
brand: Brand;
owner: boolean;
ledger?: ProjectState["ledger"][number];
}) {
const start = raceStart(race);
const reviews = entrantReviews(state, race, entrant);
const receipt = reviews.at(-1)?.receipt;
const failed =
receipt && ["failed", "timed-out", "infrastructure-error"].includes(receipt.status);
const failureAt = failed ? receipt.finishedAt : null;
const priorFailures = reviews.flatMap((review) =>
review.receipt && review.receipt.status !== "passed" && review.receipt.status !== "running"
? [review.receipt]
: [],
);
const tooltip = [
...priorFailures.flatMap((r) =>
r.checks
.filter((check) => check.outcome !== "passed")
.map(
(check) =>
`${check.name} · ${receiptWord(check.outcome).label.toLowerCase()}${duration(check.durationMs) ? ` · ${duration(check.durationMs)}` : ""}`,
),
),
...(receipt?.status === "passed" && priorFailures.length && entrant.receiptPassedAt
? [`retried, passed at +${raceSplit(entrant.receiptPassedAt, start)}`]
: []),
].join("; ");
let previous = -1;
return (
|
|
{raceMilestones.map((milestone, index) => {
const at = entrant[milestone.key];
const reached = timestamp(at) !== undefined;
const gap = reached && previous >= 0 ? index - previous : 0;
if (reached) previous = index;
const hurdle = milestone.key === "receiptPassedAt";
const failure = hurdle && failed;
const promoted = milestone.key === "promotedAt" && reached;
const label = failure ? receiptWord(receipt!.status).label : milestone.label;
const eventAt = failure ? failureAt : at;
const split = raceSplit(eventAt, start);
const { description } = milestoneDescription(state, race, entrant, milestone);
const marker = (
);
return (
{milestone.label}
{description}
0} />
{hurdle && tooltip ? (
}
>
{marker}
) : (
marker
)}
{split && }
{failure && {label}}
|
);
})}
Tokens
|
{entrantResult(entrant, owner)}
{entrant.promotedAt && (
{raceSplit(entrant.promotedAt, start)}
{ledger && (
<>
{" "}
· {ledger.sha.slice(0, 7)}
>
)}
)}
{entrant.closedAt && !entrant.promotedAt && (
Closed +{raceSplit(entrant.closedAt, start)}
)}
{entrant.promotedAt && ledger?.before && (
Promoted to main{" "}
{ledger.before.slice(0, 7)} → {ledger.sha.slice(0, 7)}
)}
|
);
}
export function RaceView({
packet,
view,
actions,
}: {
packet: string;
view: ViewModel;
actions: ViewActions;
}) {
const state = view.state;
const observedRace = state?.races?.find((entry) => entry.packet === packet);
const previous = useRef<{ scope: string; snapshot: ReturnType } | null>(null);
const [announcement, setAnnouncement] = useState("");
useEffect(() => {
if (!state || !observedRace || view.error) {
previous.current = null;
setAnnouncement("");
return;
}
const scope = `${view.project}:${packet}`;
const snapshot = raceAnnouncementSnapshot(state, observedRace);
if (previous.current?.scope === scope) {
const message = raceAnnouncementChanges(previous.current.snapshot, snapshot);
if (message) setAnnouncement(message);
} else {
// Establish a baseline on load or switch; don't narrate historical milestones.
setAnnouncement("");
}
previous.current = { scope, snapshot };
}, [packet, view.project, state, observedRace, view.error]);
const title = useRef(null);
useEffect(() => {
// Focus after the triggering click completes, including tooltip focus restoration.
const frame = requestAnimationFrame(() => title.current?.focus());
return () => cancelAnimationFrame(frame);
}, [packet, !!state]);
const back = (
);
if (view.error && !view.stale)
return (
{back}
Couldn't load this race.
);
if (!state)
return (
);
const work = state.packets.find((entry) => entry.id === packet);
const race = state.races?.find((entry) => entry.packet === packet);
if (!race)
return (
{back}
{work && work.mode !== "race"
? "This packet isn't a race."
: "This race doesn't exist anymore."}
);
const entrants = raceEntrants(race),
start = raceStart(race),
photo = photoFinish(race);
// Match only an explicit ledger reference; never use response array position.
const ledger =
race.ledgerEntryId === undefined || race.ledgerEntryId === null
? undefined
: state.ledger.find((entry) => entry.id === race.ledgerEntryId);
const placed = entrants
.filter((entry) => entry.place !== null)
.toSorted((a, b) => a.place! - b.place!);
const oldestLoaded = oldestLoadedActivity(view.activity);
const pushesAvailable = oldestLoaded !== Infinity && entrants.every((entrant) => {
const claimed = timestamp(entrant.claimedAt);
return claimed !== undefined && oldestLoaded <= claimed;
});
const now = Date.now();
return (
{announcement}
{back}
{work && actions.showPacket && }
{work?.title ?? packet}{" "}
{work?.archived && }
⚑ {race.status === "finished" ? "Finished" : "Racing"}
{photo >= 2 && " · photo finish"}
{packet} · Race · {entrants.length}{" "}
{entrants.length === 1 ? "entrant" : "entrants"}
{race.judge && <> · Judge {race.judge}>}
{start !== undefined && (
<>
{" "}
· Started{" "}
{new Date(start).toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
hour12: false,
})}
>
)}
{race.finishedAt && start !== undefined && (
<> · Finished {duration(timestamp(race.finishedAt)! - start)} later>
)}
{placed.map((entrant) => (
{" "}
· {ordinal(entrant.place!)} {entrant.agent}
))}
{start !== undefined && (
Post time
{new Date(start).toLocaleTimeString(undefined, {
hour: "2-digit",
minute: "2-digit",
hour12: false,
})}
{race.finishedAt && race.winner && (
<>
Won in
{raceSplit(race.finishedAt, start)}
>
)}
)}
{photo >= 2 && (
Photo finish {photo} entrants were approved; the first
promote to main won. The others' reviews closed when the race finished.
)}
Race progress for {packet}
| Runner |
{raceMilestones.map((step) => (
{step.label}
|
))}
Tokens |
Result |
{entrants.map((entrant) => (
))}
{(!!entrants.length || !!race.judge) && } />}
{!entrants.length && (
No entrants yet. Agents join by claiming {packet}.
)}
{!!entrants.length && (
Results
Recorded results for {packet}
| Pos |
Runner |
Time to promote |
{pushesAvailable && Pushes | }
Checks passed |
Tokens |
Result |
{[...placed, ...entrants.filter((entry) => entry.place === null)].map((entrant) => {
const pushes = packetPushes(
view.activity, entrant.repoName, state.project.defaultBranch,
timestamp(entrant.claimedAt) ?? Infinity,
timestamp(entrant.closedAt) ?? timestamp(race.finishedAt) ?? now,
).length;
return (
|
{entrant.place !== null ? ordinal(entrant.place) : "—"}
|
|
{entrant.promotedAt ? raceSplit(entrant.promotedAt, start) : "—"}
|
{pushesAvailable && {pushes} | }
{entrantChecks(state, race, entrant)}
|
|
{entrantResult(entrant, actions.owner)} |
);
})}
{pushesAvailable && Pushes from loaded activity.
}
)}
{photo >= 2 && (
Photo finish
Promote is compare-and-swap, so exactly one can move main.
The others' reviews closed when the race finished.
{entrants
.filter((entrant) => entrant.promotedAt)
.map((entrant) => (
{entrant.agent} promoted
{ledger?.before && (
<>
{" "}
· main{" "}
{ledger.before.slice(0, 7)} → {ledger.sha.slice(0, 7)}
>
)}{" "}
· {raceSplit(entrant.promotedAt, start)}
))}
{entrants
.filter((entrant) => entrant.promoteRejected)
.map((entrant) => (
{entrant.agent} tried to promote · expected{" "}
{entrant.promoteRejected!.expected.slice(0, 7)}, found{" "}
{entrant.promoteRejected!.found.slice(0, 7)}
{rejectionDelta(entrant.promoteRejected!.at, race.finishedAt) && (
<> · {rejectionDelta(entrant.promoteRejected!.at, race.finishedAt)}>
)}
Main moved
))}
)}
);
}