Skip to the content

Capsid menu

src/jobs-mirror.ts

192 lines and 7 functions in DrDustinEdwards/capsid, at commit daa875b on 2026-10-24. This file on GitHub.

Functions

The functions of jobs-mirror.ts
FunctionLinesComplexityCoveredCRAPMutation
resumeNoteFields37 to 39133%OkCRAP 1.3No data: mutation testing has not run on this repo yet
noteFromRow49 to 78120%CriticalCRAP 156No data: mutation testing has not run on this repo yet
latestResumeNote80 to 9238%WatchCRAP 10.1No data: mutation testing has not run on this repo yet
resumeNotes112 to 133718%CriticalCRAP 33.8No data: mutation testing has not run on this repo yet
renderJobDoc137 to 1751885%WatchCRAP 19.2No data: mutation testing has not run on this repo yet
mirrorStatements179 to 2013100%OkCRAP 3No data: mutation testing has not run on this repo yet
jobAudit204 to 2061100%OkCRAP 1No data: mutation testing has not run on this repo yet

Imports

It imports src/doc-statements.ts, src/env.ts, src/job-signing.ts, src/jobs-schema.ts, src/store-guards.ts. Imported by src/jobs-begin.ts, src/jobs-claim.ts, src/jobs-edit.ts, src/jobs-holder.ts, src/jobs-park.ts, src/jobs-seat.ts, src/jobs-transition.ts, src/routine-fire.ts.

Source

import type { Env } from "./env";
import { docStatements, priorDoc } from "./doc-statements";
import { checkJobText, type SignatureCheck } from "./job-signing";
import { jobDocPath, isTerminalJobStatus, type JobRow } from "./jobs-schema";
import { auditStatement } from "./store-guards";

// The records a job transition writes beside its UPDATE: the mirror document, the
// audit row, and the latest resume note read back from that audit row.

// What the last resume approved, handed to whoever holds the job next.
//
// The reason a resume takes is written to the audit row, and no tool returns audit
// params to a driver, so without this a driver picking a resumed job back up could not
// read what the seat had approved and would have to ask again. The audit row stays the
// one record; this reads it back.
export interface ResumeNote {
  reason: string;
  // The seat's full note, when the resume carried one. `reason` is bounded at
  // MAX_TITLE and holds one line; the rulings or plan the seat approved go here and
  // are handed on whole, never truncated.
  note?: string;
  by: string;
  at: string;
  approved_by_policy?: string;
  policy_class?: string;
  correction?: true;
  // Whether the approval is the one the resume wrote (src/job-signing.ts). A note whose
  // signature does not match is withheld: its text is replaced and its full note
  // dropped, so nothing changed after the fact reaches a driver as an approval.
  signature: SignatureCheck;
}

// Who may read a note, and with what: the database and the signing secret.
type NoteEnv = Pick<Env, "DB" | "IMPROVE_SCORE_SECRET">;

/** The fields a resume note's signature covers, in one place for the writer and reader. */
export function resumeNoteFields(approved: string, note: string | null, by: string): Record<string, string | null> {
  return { approved, note, by };
}

const WITHHELD = "WITHHELD: this approval's signature does not match, so it was changed after the resume wrote it. Do not act on it; ask the seat.";

// Served by audit_log_doc (namespace, path, id DESC), the index every job audit row
// already falls under because it is written against the job's mirror path.
type NoteRow = { actor: string | null; params: string | null; at: string };

// One audit row as the note it recorded, its signature checked, or null when the row is
// not a readable resume (no params, not JSON, no approved text).
async function noteFromRow(env: NoteEnv, job: Pick<JobRow, "id">, row: NoteRow): Promise<ResumeNote | null> {
  if (!row.params) return null;
  let params: Record<string, unknown>;
  try {
    params = JSON.parse(row.params) as Record<string, unknown>;
  } catch {
    return null;
  }
  if (typeof params.approved !== "string") return null;
  const by = row.actor ?? "(unknown)";
  const note = typeof params.note === "string" ? params.note : null;
  const signature = await checkJobText(
    env.IMPROVE_SCORE_SECRET,
    "resume-note",
    job.id,
    resumeNoteFields(params.approved, note, by),
    typeof params.sig === "string" ? params.sig : null
  );
  if (signature === "mismatch") return { reason: WITHHELD, by, at: row.at, signature };
  return {
    reason: params.approved,
    ...(note !== null ? { note } : {}),
    by,
    at: row.at,
    signature,
    ...(typeof params.approved_by_policy === "string" ? { approved_by_policy: params.approved_by_policy } : {}),
    ...(typeof params.policy_class === "string" ? { policy_class: params.policy_class } : {}),
    ...(params.correction === true ? { correction: true as const } : {}),
  };
}

export async function latestResumeNote(
  env: NoteEnv,
  job: Pick<JobRow, "id" | "namespace" | "resumed_count">
): Promise<ResumeNote | null> {
  if (!job.resumed_count) return null;
  const row = await env.DB
    .prepare(
      "SELECT actor, params, at FROM audit_log WHERE namespace = ?1 AND path = ?2 AND action = 'job-resumed' ORDER BY id DESC LIMIT 1"
    )
    .bind(job.namespace, jobDocPath(job.id))
    .first<NoteRow>();
  return row ? noteFromRow(env, job, row) : null;
}

// Every resume note a driver is handed, together, and no more than this many bytes of
// them: a job resumed fifteen times (job_5765103c658f, 2026-09-26) carried its PR order
// and rulings in the early notes, which "the latest only" lost.
const RESUME_NOTES_MAX_BYTES = 64 * 1024;
// Rows read for it, so one job with a very long history is one bounded read.
const RESUME_NOTES_MAX_ROWS = 200;

export interface ResumeNotes {
  // Newest first. Each note's own signature is checked; one that does not match is
  // withheld, as the newest one is.
  notes: ResumeNote[];
  // Resumes the job recorded that this answer does not carry: older ones past the byte
  // cap or the row cap, or an audit row that cannot be read as a note.
  dropped: number;
}

/** Every resume note for a job, newest first, at most RESUME_NOTES_MAX_BYTES of them (the
 *  oldest dropped and counted). The newest is first and is what `latestResumeNote` returns. */
export async function resumeNotes(env: NoteEnv, job: Pick<JobRow, "id" | "namespace" | "resumed_count">): Promise<ResumeNotes> {
  if (!job.resumed_count) return { notes: [], dropped: 0 };
  const { results } = await env.DB
    .prepare(
      "SELECT actor, params, at FROM audit_log WHERE namespace = ?1 AND path = ?2 AND action = 'job-resumed' ORDER BY id DESC LIMIT ?3"
    )
    .bind(job.namespace, jobDocPath(job.id), RESUME_NOTES_MAX_ROWS)
    .all<NoteRow>();
  const notes: ResumeNote[] = [];
  let bytes = 0;
  for (const row of results ?? []) {
    const note = await noteFromRow(env, job, row);
    if (!note) continue;
    const size = new TextEncoder().encode(JSON.stringify(note)).length;
    // The newest note is always returned, whatever its size: it is the approval a driver
    // acts on, and a cap that hid it would be the loss this reads back to prevent.
    if (notes.length > 0 && bytes + size > RESUME_NOTES_MAX_BYTES) break;
    notes.push(note);
    bytes += size;
  }
  return { notes, dropped: Math.max(0, job.resumed_count - notes.length) };
}

// The document a job mirrors to. The prompt is the SIGNED body, byte for byte, so a
// driver that reads the document rather than the row still verifies the same bytes.
function renderJobDoc(job: JobRow, notes: ResumeNote[], dropped = 0): string {
  const note = notes[0] ?? null;
  const lines = [
    `# ${job.title}`,
    "",
    `Job \`${job.id}\` in \`${job.namespace}\`. This document is a PROJECTION of the jobs`,
    "table, which is the source of truth for status. Rewritten on every transition.",
    "",
    `- status: **${job.status}**`,
    `- priority: ${job.priority}`,
    `- gate required: ${job.gate_required ? "yes" : "no"}`,
    `- posted by: ${job.posted_by}`,
    `- claimed by: ${job.claimed_by ?? "(unclaimed)"}`,
  ];
  // The started label (src/jobs-begin.ts), once somebody began the job.
  if (job.started_by) lines.push(`- started by: ${job.started_by} at ${job.started_at ?? "(no time recorded)"}`);
  // Only once it has happened, so a job that never hit a gate carries no line of zeroes.
  if (job.blocked_count > 0) lines.push(`- gates hit: ${job.blocked_count}, resumed: ${job.resumed_count}`);
  // The brief carries open job documents, so this line is how brief hands the
  // approval to a driver.
  if (note) lines.push(`- last resume, by ${note.by} at ${note.at}${note.signature === "verified" ? "" : ` (${note.signature})`}: ${note.reason}`);
  if (job.result_summary) lines.push(`- result: ${job.result_summary}`);
  if (job.result_ref) lines.push(`- result ref: ${job.result_ref}`);
  // The full note as its own block after the status lines, untruncated: a driver
  // reading the brief needs every ruling, not the first line of them.
  if (note?.note) lines.push("", "## The last resume's note", "", note.note);
  // Every earlier resume, newest first: an approval given at one resume is still the
  // approval after the next (resumeNotes).
  if (notes.length > 1) {
    lines.push("", "## Earlier resumes", "");
    for (const earlier of notes.slice(1)) {
      lines.push(`- by ${earlier.by} at ${earlier.at}${earlier.signature === "verified" ? "" : ` (${earlier.signature})`}: ${earlier.reason}`);
      if (earlier.note) lines.push("", earlier.note, "");
    }
  }
  if (dropped > 0) lines.push("", `(${dropped} older resume${dropped === 1 ? "" : "s"} not shown.)`);
  lines.push("", "## The prompt", "", job.body);
  return lines.join("\n");
}

// `note` is passed by resume, whose audit row is written in the same batch as this
// mirror and so cannot be read back yet. Every other transition reads it.
export async function mirrorStatements(env: NoteEnv, job: JobRow, action: string, actor: string, note?: ResumeNote) {
  const path = jobDocPath(job.id);
  const prior = await priorDoc(env.DB, job.namespace, path);
  // The passed note is the resume being written in this batch, so it is not in the audit
  // log yet: it leads, and the notes read back are the earlier ones.
  const history = await resumeNotes(env, job);
  const notes = note ? [note, ...history.notes] : history.notes;
  return docStatements(env.DB, {
    namespace: job.namespace,
    path,
    title: `Job: ${job.title}`,
    body: renderJobDoc(job, notes, history.dropped),
    type: "task",
    // Closed on a finished row, and `failed` is as finished as `done`: a failed job's
    // mirror left active would keep brief carrying it as open work.
    // isTerminalJobStatus is the one list of finished statuses.
    status: isTerminalJobStatus(job.status) ? "closed" : "active",
    tags: "jobs",
    prior,
    action,
    actor,
  });
}

// A job's audit row is addressed to its mirror document and carries the job id.
export function jobAudit(db: D1Database, actor: string, action: string, job: JobRow, params: Record<string, unknown>) {
  return auditStatement(db, actor, action, job.namespace, jobDocPath(job.id), { job_id: job.id, ...params });
}