From d0eb9535f5827c233c7ea9dd33ab721c0576df2a Mon Sep 17 00:00:00 2001 From: Antonio Viggiano Date: Tue, 29 Sep 2026 06:06:08 +0000 Subject: [PATCH 1/4] refactor: delete duplicate export aliases knip reports four exports that are a second name for another export of the same module. Keep the declared name and point every caller at it: - cleanGenerated = cleanRun and materializeRun = materializeSelection: the CLI clean/materialize commands and the dashboard call the declared functions, which are also the operation names their audit records already store ("cleanRun", "materializeSelection"). - findingNoteSchema = findingReportBoundTextSchema: finding notes use the schema directly. It is the same object, so the generated JSON Schemas are unchanged. - MODAL_MAX_SANDBOX_TIMEOUT_MS, MODAL_RECOVERY_SANDBOX_TIMEOUT_MS and MODAL_SANDBOX_TIMEOUT_MS were one 24-hour value under three names. MODAL_SANDBOX_TIMEOUT_MS remains, and recovery workers use it. The layout test loses the two assertions that compared the aliases with each other. No value or behaviour changes. Co-Authored-By: Claude Opus 5.5 --- packages/artifacts/src/findings-schema.ts | 3 +-- packages/artifacts/src/workflow-contracts.ts | 9 ++++----- packages/cli/src/commands/clean.ts | 4 ++-- packages/cli/src/commands/materialize.ts | 4 ++-- packages/dashboard/src/index.ts | 8 ++++---- packages/modal/src/defaults.ts | 4 +--- packages/modal/src/runner.ts | 4 ++-- packages/modal/test/layout.test.ts | 8 ++------ packages/runtime/src/clean.ts | 2 -- packages/runtime/src/materialize.ts | 2 -- 10 files changed, 18 insertions(+), 30 deletions(-) diff --git a/packages/artifacts/src/findings-schema.ts b/packages/artifacts/src/findings-schema.ts index e4f45991a..177283331 100644 --- a/packages/artifacts/src/findings-schema.ts +++ b/packages/artifacts/src/findings-schema.ts @@ -732,8 +732,7 @@ export const findingReportBoundTextSchema = nonEmptyString if (issue !== undefined) context.addIssue({ code: "custom", message: issue.message }); }) .meta({ id: "findingReportBoundText", allOf: findingNoteJsonSchemaConstraints }); -export const findingNoteSchema = findingReportBoundTextSchema; -const findingNotesSchema = z.array(findingNoteSchema).max(MAX_FINDING_NESTED_ITEMS); +const findingNotesSchema = z.array(findingReportBoundTextSchema).max(MAX_FINDING_NESTED_ITEMS); const uniqueNonEmptyStrings = z .array(nonEmptyString) .max(MAX_FINDING_NESTED_ITEMS) diff --git a/packages/artifacts/src/workflow-contracts.ts b/packages/artifacts/src/workflow-contracts.ts index b103ba3c6..0fb8c4766 100644 --- a/packages/artifacts/src/workflow-contracts.ts +++ b/packages/artifacts/src/workflow-contracts.ts @@ -8,7 +8,6 @@ import { MAX_FINDING_NESTED_ITEMS, findingLifecycleSchema, findingLifecycleStageSchema, - findingNoteSchema, findingReportBoundTextSchema, findingSchema, findingStrategyHitSchema, @@ -170,7 +169,7 @@ export const strategyDetectionsSchema = withDocumentMetadata( const triagedFindingSchema = findingSchema .safeExtend({ triage_classification: z.enum(TRIAGE_CLASSIFICATIONS), - notes: z.array(findingNoteSchema).min(1).max(MAX_FINDING_NESTED_ITEMS) + notes: z.array(findingReportBoundTextSchema).min(1).max(MAX_FINDING_NESTED_ITEMS) }) .meta({ allOf: [ @@ -243,7 +242,7 @@ const severityClassifiedFindingSchema = findingSchema // Severity review must preserve the already-validated triage notes byte for // byte, but the copied values remain inside the report-vocabulary trust // boundary and are therefore validated again at this contract boundary. - notes: z.array(findingNoteSchema).max(MAX_FINDING_NESTED_ITEMS).optional(), + notes: z.array(findingReportBoundTextSchema).max(MAX_FINDING_NESTED_ITEMS).optional(), severity: z.enum(FINDING_SEVERITIES).optional(), impact: z.enum(FINDING_SEVERITIES).optional(), likelihood: z.enum(FINDING_SEVERITIES).optional(), @@ -1613,7 +1612,7 @@ const reportCoverageUnavailableSchema = z.strictObject({ }); const reportIssueSchema = findingSchema.safeExtend({ - notes: z.array(findingNoteSchema).max(MAX_FINDING_NESTED_ITEMS).optional(), + notes: z.array(findingReportBoundTextSchema).max(MAX_FINDING_NESTED_ITEMS).optional(), description: nonEmptyString, severity: z.enum(FINDING_SEVERITIES), likelihood: z.enum(FINDING_SEVERITIES), @@ -1630,7 +1629,7 @@ const reportIssueSchema = findingSchema.safeExtend({ }); const reportNonProductionOutcomeSchema = findingSchema.safeExtend({ - notes: z.array(findingNoteSchema).max(MAX_FINDING_NESTED_ITEMS).optional(), + notes: z.array(findingReportBoundTextSchema).max(MAX_FINDING_NESTED_ITEMS).optional(), triage_classification: z.enum(TRIAGE_CLASSIFICATIONS), recommended_next_action: nonEmptyString, lifecycle: findingLifecycleSchema diff --git a/packages/cli/src/commands/clean.ts b/packages/cli/src/commands/clean.ts index 66963fdb4..46bf7bf73 100644 --- a/packages/cli/src/commands/clean.ts +++ b/packages/cli/src/commands/clean.ts @@ -1,5 +1,5 @@ import { Args, Command, Flags } from "@oclif/core"; -import { cleanGenerated } from "@ultrafuzz/runtime"; +import { cleanRun } from "@ultrafuzz/runtime"; import { commandFromRuntime, emitCommandResult, globalFlags, projectRoot } from "../command-shared.js"; @@ -17,7 +17,7 @@ export default class Clean extends Command { async run(): Promise { const { args, flags } = await this.parse(Clean); const selections = flags.select && flags.select.length > 0 ? flags.select : [`runs/${args.runId}`]; - const result = await cleanGenerated({ + const result = await cleanRun({ projectRoot: projectRoot(flags), selections, confirmed: flags.yes === true || flags.confirm === true, diff --git a/packages/cli/src/commands/materialize.ts b/packages/cli/src/commands/materialize.ts index fdbd0eeb8..6bbde04f3 100644 --- a/packages/cli/src/commands/materialize.ts +++ b/packages/cli/src/commands/materialize.ts @@ -1,5 +1,5 @@ import { Args, Command, Flags } from "@oclif/core"; -import { materializeRun } from "@ultrafuzz/runtime"; +import { materializeSelection } from "@ultrafuzz/runtime"; import { commandFromRuntime, emitCommandResult, globalFlags, projectRoot } from "../command-shared.js"; @@ -24,7 +24,7 @@ export default class Materialize extends Command { destination: separator === -1 ? entry : entry.slice(separator + 1) }; }); - const result = await materializeRun({ + const result = await materializeSelection({ projectRoot: projectRoot(flags), runId: args.runId, copies, diff --git a/packages/dashboard/src/index.ts b/packages/dashboard/src/index.ts index d71b47b61..c046e5873 100644 --- a/packages/dashboard/src/index.ts +++ b/packages/dashboard/src/index.ts @@ -43,12 +43,12 @@ import { SUPPORTED_TEMPLATE_VARIABLES } from "@ultrafuzz/prompts"; import { - cleanGenerated, + cleanRun, assertVerifiedRunOutputAuthorityRemainedCurrent, forkRun, getRunStatus, listRuns, - materializeRun, + materializeSelection, referencesStatus, referencesSync, referencesUpdate, @@ -1545,7 +1545,7 @@ class DashboardApp { result = referencesUpdate({ projectRoot: this.projectRoot, latest: body.latest !== false }); break; case "materialize": - result = await materializeRun({ + result = await materializeSelection({ projectRoot: this.projectRoot, runId: runId!, copies: copySelections(body), @@ -1555,7 +1555,7 @@ class DashboardApp { }); break; case "clean": - result = await cleanGenerated({ + result = await cleanRun({ projectRoot: this.projectRoot, selections: stringArrayField(body, "select").length > 0 ? stringArrayField(body, "select") : [`runs/${runId}`], diff --git a/packages/modal/src/defaults.ts b/packages/modal/src/defaults.ts index 183820094..adee2b14e 100644 --- a/packages/modal/src/defaults.ts +++ b/packages/modal/src/defaults.ts @@ -2,14 +2,13 @@ export const MODAL_BENCHMARK_SCHEMA_VERSION = "ultrafuzz.modal.benchmark.v3" as export const MODAL_LAUNCH_STATE_SCHEMA_VERSION = "ultrafuzz.modal.launch-state.v3" as const; export const MODAL_RECOVERY_STATE_SCHEMA_VERSION = "ultrafuzz.modal.recovery-state.v1" as const; export const MODAL_WORKER_LINEAGE_SCHEMA_VERSION = "ultrafuzz.modal.worker-lineage.v1" as const; -export const MODAL_MAX_SANDBOX_TIMEOUT_MS = 24 * 60 * 60 * 1000; +export const MODAL_SANDBOX_TIMEOUT_MS = 24 * 60 * 60 * 1000; export const MODAL_PUBLIC_SANDBOX_TIMEOUT_MS = 6 * 60 * 60 * 1000; // A full public EVMBench pair's derived control envelope is roughly 10.5 hours: // two bounded eval waves plus preparation, scoring, cleanup, reporting, and // polling grace. Keep that lane below the historical 24-hour default without // expiring a worker inside its own accepted command envelope. export const MODAL_PUBLIC_FULL_SANDBOX_TIMEOUT_MS = 16 * 60 * 60 * 1000; -export const MODAL_RECOVERY_SANDBOX_TIMEOUT_MS = MODAL_MAX_SANDBOX_TIMEOUT_MS; export const MODAL_OVERSEER_POLL_MS = 60 * 1000; // Consecutive poll ticks in which EVERY supervised job threw before the overseer gives up loudly. // A single tick failure is transient (a control-plane blip, a sandbox shutting down mid-read) and must @@ -22,7 +21,6 @@ export const MODAL_RECOVERY_BACKOFF_BASE_MS = 5 * 60 * 1000; export const MODAL_RECOVERY_BACKOFF_MAX_MS = 15 * 60 * 1000; export const MODAL_RECOVERY_LEASE_TIMEOUT_MS = 10 * 60 * 1000; export const EVAL_POST_WATCH_MARGIN_MS = 2 * 60 * 60 * 1000; -export const MODAL_SANDBOX_TIMEOUT_MS = MODAL_MAX_SANDBOX_TIMEOUT_MS; export const EVAL_WATCH_TIMEOUT_SECONDS = (MODAL_SANDBOX_TIMEOUT_MS - EVAL_POST_WATCH_MARGIN_MS) / 1000; export const MODAL_PRE_MODEL_RETRY_LIMIT = 3; export const MODAL_PRE_MODEL_RETRY_BASE_DELAY_MS = 1_000; diff --git a/packages/modal/src/runner.ts b/packages/modal/src/runner.ts index 254e39877..53767a0b2 100644 --- a/packages/modal/src/runner.ts +++ b/packages/modal/src/runner.ts @@ -55,7 +55,7 @@ import { MODAL_OVERSEER_POLL_MS, MODAL_PRE_MODEL_RETRY_LIMIT, MODAL_RECOVERY_LEASE_TIMEOUT_MS, - MODAL_RECOVERY_SANDBOX_TIMEOUT_MS, + MODAL_SANDBOX_TIMEOUT_MS, type ModalLaunchMode, type ModalModelSpec, type ModelProvider @@ -2049,7 +2049,7 @@ async function launchModalRecoveryWorker(input: { sandbox = await createModalBenchmarkSandbox(input.modal.sandboxes, input.app, input.image, { name, command: ["bash", "-lc", modalWorkerEntrypointCommand(auth === undefined ? undefined : input.model.provider)], - timeoutMs: MODAL_RECOVERY_SANDBOX_TIMEOUT_MS, + timeoutMs: MODAL_SANDBOX_TIMEOUT_MS, workdir: "/opt/ultrafuzz", env: { ULTRAFUZZ_MODAL_RUN_ID: input.launchState.logical_run_id, diff --git a/packages/modal/test/layout.test.ts b/packages/modal/test/layout.test.ts index c1ba0fe10..f0a213551 100644 --- a/packages/modal/test/layout.test.ts +++ b/packages/modal/test/layout.test.ts @@ -3,10 +3,8 @@ import { describe, expect, it } from "vitest"; import { EVAL_POST_WATCH_MARGIN_MS, EVAL_WATCH_TIMEOUT_SECONDS, - MODAL_MAX_SANDBOX_TIMEOUT_MS, MODAL_PUBLIC_FULL_SANDBOX_TIMEOUT_MS, MODAL_PUBLIC_SANDBOX_TIMEOUT_MS, - MODAL_RECOVERY_SANDBOX_TIMEOUT_MS, MODAL_SANDBOX_TIMEOUT_MS } from "../src/defaults.js"; import { @@ -42,12 +40,10 @@ describe("Modal storage layout", () => { }); it("keeps the bounded eval watch below the sandbox maximum with a fixed completion margin", () => { - expect(MODAL_SANDBOX_TIMEOUT_MS).toBe(MODAL_MAX_SANDBOX_TIMEOUT_MS); - expect(MODAL_MAX_SANDBOX_TIMEOUT_MS).toBe(24 * 60 * 60 * 1000); + expect(MODAL_SANDBOX_TIMEOUT_MS).toBe(24 * 60 * 60 * 1000); expect(MODAL_PUBLIC_SANDBOX_TIMEOUT_MS).toBe(6 * 60 * 60 * 1000); expect(MODAL_PUBLIC_FULL_SANDBOX_TIMEOUT_MS).toBe(16 * 60 * 60 * 1000); - expect(MODAL_PUBLIC_FULL_SANDBOX_TIMEOUT_MS).toBeLessThan(MODAL_MAX_SANDBOX_TIMEOUT_MS); - expect(MODAL_RECOVERY_SANDBOX_TIMEOUT_MS).toBe(MODAL_MAX_SANDBOX_TIMEOUT_MS); + expect(MODAL_PUBLIC_FULL_SANDBOX_TIMEOUT_MS).toBeLessThan(MODAL_SANDBOX_TIMEOUT_MS); expect(EVAL_POST_WATCH_MARGIN_MS).toBe(2 * 60 * 60 * 1000); expect(EVAL_WATCH_TIMEOUT_SECONDS * 1000).toBe(MODAL_SANDBOX_TIMEOUT_MS - EVAL_POST_WATCH_MARGIN_MS); expect(EVAL_WATCH_TIMEOUT_SECONDS * 1000).toBeLessThan(MODAL_SANDBOX_TIMEOUT_MS); diff --git a/packages/runtime/src/clean.ts b/packages/runtime/src/clean.ts index da3ca8f18..99256fec8 100644 --- a/packages/runtime/src/clean.ts +++ b/packages/runtime/src/clean.ts @@ -244,8 +244,6 @@ function readPersistedModalExecution(runRoot: string): ModalExecutionProviderCon return modal; } -export const cleanGenerated = cleanRun; - function planRemoval( generatedRoot: string, selection: string, diff --git a/packages/runtime/src/materialize.ts b/packages/runtime/src/materialize.ts index f1164f236..187e721af 100644 --- a/packages/runtime/src/materialize.ts +++ b/packages/runtime/src/materialize.ts @@ -172,8 +172,6 @@ export async function materializeSelection(input: MaterializeInput): Promise Date: Tue, 29 Sep 2026 06:16:43 +0000 Subject: [PATCH 2/4] refactor(cli): split the pairwise chart into panel helpers The next commit removes the export keyword from buildPairwiseChart. The diff-limited strict lint (`pnpm -w lint:strict:ci`) applies its budgets to any function whose declaration line changes. buildPairwiseChart is 142 lines long and the budget is 80, so un-exporting it would fail the "Lint changed code strictly" CI step. Move the panel definitions into pairwisePanels() and the drawing of one panel into pairwisePanelParts(). The moved code is unchanged apart from indentation, and the panels still render in the same order. For the same three-pair fixture (including an NA row), paired_row_comparison.svg and .png are byte-identical before and after the split. Co-Authored-By: Claude Opus 5.5 --- .../cli/src/benchmark-analysis/lib/charts.ts | 129 +++++++++++------- 1 file changed, 76 insertions(+), 53 deletions(-) diff --git a/packages/cli/src/benchmark-analysis/lib/charts.ts b/packages/cli/src/benchmark-analysis/lib/charts.ts index f34b0d1b5..176b8b1ee 100644 --- a/packages/cli/src/benchmark-analysis/lib/charts.ts +++ b/packages/cli/src/benchmark-analysis/lib/charts.ts @@ -341,10 +341,7 @@ export async function buildScoreChart(result: AnalysisResult, outputDir: string) return writeSvgAndPng(svgDocument(width, height, parts.join("\n")), svgPath); } -export async function buildPairwiseChart(result: AnalysisResult, outputDir: string): Promise { - const pairs = result.pairComparison; - if (pairs.length === 0) throw new Error("No Ultrafuzz/no-fuzz row pairs are available for pairwise analysis"); - +function pairwisePanels(pairs: PairComparison[]): PairwisePanel[] { const creditMaximum = niceAxisMaximum( Math.max( 1, @@ -359,7 +356,7 @@ export async function buildPairwiseChart(result: AnalysisResult, outputDir: stri Math.max(1, ...pairs.flatMap((pair) => [pair.ultrafuzz.totalTokensMillions, pair.noFuzz.totalTokensMillions])), 4 ); - const panels: PairwisePanel[] = [ + return [ { title: "Ground-truth TP credits", note: "Higher is better", @@ -390,7 +387,79 @@ export async function buildPairwiseChart(result: AnalysisResult, outputDir: stri formatTick: (value) => value.toFixed(0) } ]; +} + +interface PairwiseLayout { + panelWidth: number; + rowTop: number; + rowStep: number; + axisTop: number; + axisBottom: number; +} + +function pairwisePanelParts( + panel: PairwisePanel, + left: number, + pairs: PairComparison[], + layout: PairwiseLayout +): string[] { + const { panelWidth, rowTop, rowStep, axisTop, axisBottom } = layout; + const parts: string[] = []; + const right = left + panelWidth; + const xAt = (value: number) => left + (value / panel.maximum) * panelWidth; + parts.push(text(left, 172, panel.title, { "font-size": 17, "font-weight": 650 })); + parts.push(text(right, 195, panel.note, { "font-size": 12, fill: "#666", "text-anchor": "end" })); + + for (let tick = 0; tick <= panel.divisions; tick += 1) { + const value = (panel.maximum * tick) / panel.divisions; + const x = xAt(value); + parts.push(line(x, axisTop, x, axisBottom, { stroke: tick === 0 ? "#999" : "#e1e1e1" })); + parts.push( + text(x, axisBottom + 28, panel.formatTick(value), { + "font-size": 11, + "text-anchor": "middle", + fill: "#666" + }) + ); + } + + pairs.forEach((pair, pairIndex) => { + const y = rowTop + pairIndex * rowStep; + const ultrafuzz = panel.value(pair, "ultrafuzz"); + const noFuzz = panel.value(pair, "no-fuzz"); + if (ultrafuzz === null || noFuzz === null) { + parts.push(text((left + right) / 2, y + 5, "NA", { "font-size": 12, "text-anchor": "middle", fill: "#777" })); + return; + } + const ultrafuzzX = xAt(ultrafuzz); + const noFuzzX = xAt(noFuzz); + parts.push(line(ultrafuzzX, y, noFuzzX, y, { stroke: "#777", "stroke-width": 2 })); + parts.push(circle(ultrafuzzX, y, 8, CONDITION_STYLES[0])); + parts.push(markerSquare(noFuzzX, y, 8, CONDITION_STYLES[1])); + parts.push( + text(ultrafuzzX, y - 15, panel.format(ultrafuzz), { + "font-size": 11, + "font-weight": 600, + "text-anchor": "middle" + }) + ); + parts.push( + text(noFuzzX, y + 25, panel.format(noFuzz), { + "font-size": 11, + "font-weight": 600, + "text-anchor": "middle", + fill: "#555" + }) + ); + }); + return parts; +} + +export async function buildPairwiseChart(result: AnalysisResult, outputDir: string): Promise { + const pairs = result.pairComparison; + if (pairs.length === 0) throw new Error("No Ultrafuzz/no-fuzz row pairs are available for pairwise analysis"); + const panels = pairwisePanels(pairs); const width = 1600; const panelLeft = [145, 655, 1165]; const panelWidth = 375; @@ -426,54 +495,8 @@ export async function buildPairwiseChart(result: AnalysisResult, outputDir: stri }); panels.forEach((panel, panelIndex) => { - const left = panelLeft[panelIndex] ?? 145; - const right = left + panelWidth; - const xAt = (value: number) => left + (value / panel.maximum) * panelWidth; - parts.push(text(left, 172, panel.title, { "font-size": 17, "font-weight": 650 })); - parts.push(text(right, 195, panel.note, { "font-size": 12, fill: "#666", "text-anchor": "end" })); - - for (let tick = 0; tick <= panel.divisions; tick += 1) { - const value = (panel.maximum * tick) / panel.divisions; - const x = xAt(value); - parts.push(line(x, axisTop, x, axisBottom, { stroke: tick === 0 ? "#999" : "#e1e1e1" })); - parts.push( - text(x, axisBottom + 28, panel.formatTick(value), { - "font-size": 11, - "text-anchor": "middle", - fill: "#666" - }) - ); - } - - pairs.forEach((pair, pairIndex) => { - const y = rowTop + pairIndex * rowStep; - const ultrafuzz = panel.value(pair, "ultrafuzz"); - const noFuzz = panel.value(pair, "no-fuzz"); - if (ultrafuzz === null || noFuzz === null) { - parts.push(text((left + right) / 2, y + 5, "NA", { "font-size": 12, "text-anchor": "middle", fill: "#777" })); - return; - } - const ultrafuzzX = xAt(ultrafuzz); - const noFuzzX = xAt(noFuzz); - parts.push(line(ultrafuzzX, y, noFuzzX, y, { stroke: "#777", "stroke-width": 2 })); - parts.push(circle(ultrafuzzX, y, 8, CONDITION_STYLES[0])); - parts.push(markerSquare(noFuzzX, y, 8, CONDITION_STYLES[1])); - parts.push( - text(ultrafuzzX, y - 15, panel.format(ultrafuzz), { - "font-size": 11, - "font-weight": 600, - "text-anchor": "middle" - }) - ); - parts.push( - text(noFuzzX, y + 25, panel.format(noFuzz), { - "font-size": 11, - "font-weight": 600, - "text-anchor": "middle", - fill: "#555" - }) - ); - }); + const layout = { panelWidth, rowTop, rowStep, axisTop, axisBottom }; + parts.push(...pairwisePanelParts(panel, panelLeft[panelIndex] ?? 145, pairs, layout)); }); parts.push( From a18d6cc8dee52db8cc68a8abc0f3317081a0b1a4 Mon Sep 17 00:00:00 2001 From: Antonio Viggiano Date: Tue, 29 Sep 2026 06:17:04 +0000 Subject: [PATCH 3/4] refactor: stop exporting symbols that only their own module uses knip reports 40 unused exports and 38 unused exported types. Each one is used inside the module that declares it and imported nowhere else: no other module, test, script or package refers to it, and no package entry point re-exports it. Remove the export keyword and keep the declaration. - 69 are in production modules of cli, dashboard, modal, runtime, security and topology; 25 of them are cli-contracts and run-statistics payload types. - 8 are in test helpers of evals, modal and runtime. - 1 is in scripts/ci/verify-cohort-reachability.mjs. assertCurrentPersistentWorkerLineage was async without awaiting anything, which the changed-line strict lint rejects once its declaration line changes. It is now synchronous, and its one caller no longer awaits it. It still throws inside the caller's try/finally while the lineage lock is held, so the lock is still released and the error still rejects the guarded write. The CLI schema registry still looks up its schemas by name in CLI_SCHEMA_EXPORTS, which is now module-private. The temporary-root helper no longer claims that removeRegisteredRoots is exposed. Co-Authored-By: Claude Opus 5.5 --- .../cli/src/benchmark-analysis/lib/archive.ts | 2 +- .../cli/src/benchmark-analysis/lib/charts.ts | 2 +- .../cli/src/benchmark-analysis/lib/format.ts | 2 +- .../cli/src/benchmark-analysis/lib/stats.ts | 2 +- .../cli/src/benchmark-analysis/lib/svg.ts | 6 +-- packages/cli/src/benchmark-analysis/types.ts | 2 +- packages/cli/src/cli-contracts.ts | 44 +++++++++---------- packages/cli/src/cli-schema-registry.ts | 8 ++-- packages/cli/src/run-statistics.ts | 10 ++--- packages/dashboard/frontend/src/display.ts | 2 +- .../frontend/src/edgeEndpointEditing.ts | 2 +- .../dashboard/frontend/src/graphLayout.ts | 12 ++--- .../dashboard/frontend/src/nodeEvidence.ts | 4 +- packages/dashboard/frontend/src/theme.ts | 8 ++-- .../frontend/src/useManagedConfigEditor.ts | 2 +- .../frontend/src/useManagedPromptEditor.ts | 2 +- packages/evals/test/helpers.ts | 4 +- packages/modal/src/ground-truth.ts | 2 +- packages/modal/src/worker-lineage.ts | 7 +-- .../modal/test/current-artifact-fixtures.ts | 2 +- packages/runtime/src/required-commands.ts | 2 +- packages/runtime/src/trusted-cli-closure.ts | 6 +-- .../runtime/src/unverified-report-inputs.ts | 2 +- .../workflow-execution-snapshot-capability.ts | 6 +-- packages/runtime/src/workflow-run-link.ts | 2 +- packages/runtime/test/cloud-worker-harness.ts | 2 +- packages/runtime/test/reference-fixtures.ts | 6 +-- packages/runtime/test/temporary-root.ts | 4 +- .../security/src/secretlint-scan-channel.ts | 4 +- packages/topology/src/path-utils.ts | 2 +- scripts/ci/verify-cohort-reachability.mjs | 2 +- 31 files changed, 80 insertions(+), 83 deletions(-) diff --git a/packages/cli/src/benchmark-analysis/lib/archive.ts b/packages/cli/src/benchmark-analysis/lib/archive.ts index e63c207c4..4c98646e7 100644 --- a/packages/cli/src/benchmark-analysis/lib/archive.ts +++ b/packages/cli/src/benchmark-analysis/lib/archive.ts @@ -107,7 +107,7 @@ function validateZipEntryNames(entries: readonly AdmZip.IZipEntry[]): ReadonlyMa return byName; } -export function assertCanonicalRelativePath(value: string): void { +function assertCanonicalRelativePath(value: string): void { if ( !/^[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*$/u.test(value) || value.split("/").some((segment) => segment === "." || segment === "..") diff --git a/packages/cli/src/benchmark-analysis/lib/charts.ts b/packages/cli/src/benchmark-analysis/lib/charts.ts index 176b8b1ee..e8bda1cae 100644 --- a/packages/cli/src/benchmark-analysis/lib/charts.ts +++ b/packages/cli/src/benchmark-analysis/lib/charts.ts @@ -455,7 +455,7 @@ function pairwisePanelParts( return parts; } -export async function buildPairwiseChart(result: AnalysisResult, outputDir: string): Promise { +async function buildPairwiseChart(result: AnalysisResult, outputDir: string): Promise { const pairs = result.pairComparison; if (pairs.length === 0) throw new Error("No Ultrafuzz/no-fuzz row pairs are available for pairwise analysis"); diff --git a/packages/cli/src/benchmark-analysis/lib/format.ts b/packages/cli/src/benchmark-analysis/lib/format.ts index be4ef0cb3..a3804bc3b 100644 --- a/packages/cli/src/benchmark-analysis/lib/format.ts +++ b/packages/cli/src/benchmark-analysis/lib/format.ts @@ -1,4 +1,4 @@ -export function csvEscape(value: unknown): string { +function csvEscape(value: unknown): string { if (value === null || value === undefined || (typeof value === "number" && !Number.isFinite(value))) return ""; const raw = Array.isArray(value) ? value.join("; ") diff --git a/packages/cli/src/benchmark-analysis/lib/stats.ts b/packages/cli/src/benchmark-analysis/lib/stats.ts index 8307c6e7f..cd89a25e4 100644 --- a/packages/cli/src/benchmark-analysis/lib/stats.ts +++ b/packages/cli/src/benchmark-analysis/lib/stats.ts @@ -8,7 +8,7 @@ export function mean(values: number[]): number | null { return values.length ? sum(values) / values.length : null; } -export function median(values: number[]): number | null { +function median(values: number[]): number | null { if (!values.length) return null; const ordered = [...values].sort((a, b) => a - b); const middle = Math.floor(ordered.length / 2); diff --git a/packages/cli/src/benchmark-analysis/lib/svg.ts b/packages/cli/src/benchmark-analysis/lib/svg.ts index a6d6913c0..03ea8ad54 100644 --- a/packages/cli/src/benchmark-analysis/lib/svg.ts +++ b/packages/cli/src/benchmark-analysis/lib/svg.ts @@ -4,9 +4,9 @@ import { Resvg } from "@resvg/resvg-js"; import { escapeXml } from "./format.js"; -export const FONT = "Inter, Arial, Helvetica, sans-serif"; +const FONT = "Inter, Arial, Helvetica, sans-serif"; -export function attrs(values: Record): string { +function attrs(values: Record): string { return Object.entries(values) .filter(([, value]) => value !== null && value !== undefined && value !== false) .map(([key, value]) => `${key.replaceAll("_", "-")}="${escapeXml(value === true ? key : value)}"`) @@ -66,7 +66,7 @@ export function svgDocument(width: number, height: number, content: string): str return `\n\n\n${content}\n\n`; } -export async function writeSvg(svg: string, svgPath: string): Promise { +async function writeSvg(svg: string, svgPath: string): Promise { await writeFile(svgPath, svg, "utf8"); } diff --git a/packages/cli/src/benchmark-analysis/types.ts b/packages/cli/src/benchmark-analysis/types.ts index b2814005f..4b8488b35 100644 --- a/packages/cli/src/benchmark-analysis/types.ts +++ b/packages/cli/src/benchmark-analysis/types.ts @@ -1,7 +1,7 @@ export const SEVERITY_ORDER = ["H", "M", "L"] as const; export type Severity = (typeof SEVERITY_ORDER)[number]; -export type Classification = "true-positive" | "false-positive" | "needs-human-review"; +type Classification = "true-positive" | "false-positive" | "needs-human-review"; export type AnalysisCommandName = "upset" | "scores" | "provenance" | "table" | "cost" | "pairwise" | "all"; export interface BenchmarkRow { diff --git a/packages/cli/src/cli-contracts.ts b/packages/cli/src/cli-contracts.ts index 4af481569..55d1f779b 100644 --- a/packages/cli/src/cli-contracts.ts +++ b/packages/cli/src/cli-contracts.ts @@ -53,7 +53,7 @@ import type { ReportArtifacts } from "./report-artifacts.js"; import type { RunStatisticsValue } from "./run-statistics.js"; export const CLI_SCHEMA_VERSION = "ultrafuzz.cli.result.v2" as const; -export const CLI_PUBLIC_RUN_STATE_SCHEMA_VERSION = "ultrafuzz.cli.public-run-state.v1" as const; +const CLI_PUBLIC_RUN_STATE_SCHEMA_VERSION = "ultrafuzz.cli.public-run-state.v1" as const; export const CLI_KNOWN_COMMANDS = [ "init", @@ -137,11 +137,11 @@ export interface CliValidateProjectData { prompts?: NonNullable; } -export type CliPublicNodeState = Omit; +type CliPublicNodeState = Omit; -export type CliPublicWorkflowProvenance = PublicRunWorkflowProvenance; +type CliPublicWorkflowProvenance = PublicRunWorkflowProvenance; -export interface CliPublicRunState { +interface CliPublicRunState { schema_version: typeof CLI_PUBLIC_RUN_STATE_SCHEMA_VERSION; run_id: string; status: RunState["status"]; @@ -159,7 +159,7 @@ export interface CliPublicRunState { provenance?: { workflow: CliPublicWorkflowProvenance }; } -export interface CliPublicRunMetadata { +interface CliPublicRunMetadata { schema_version: "ultrafuzz.run-metadata.v2"; run_id: string; created_at: string; @@ -185,14 +185,14 @@ export interface CliInspectData extends Omit { +interface CliWorkflowNodeToolCall extends Omit { /** Redacted third-party tool payload; the tool defines its inner shape. */ input?: CliJsonValue; /** Redacted third-party tool payload; the tool defines its inner shape. */ output?: CliJsonValue; } -export interface CliWorkflowNodeAttempt extends Omit { +interface CliWorkflowNodeAttempt extends Omit { tool_calls: CliWorkflowNodeToolCall[]; } @@ -202,14 +202,14 @@ export interface CliWorkflowNodeData extends Omit type DoctorPostureKey = keyof ValidateProjectResult["policy_posture"]; -export interface CliDoctorData extends Omit { +interface CliDoctorData extends Omit { validation: { status: DoctorCheckStatus; policy_posture: Partial>; }; } -export interface CliReportBundleData { +interface CliReportBundleData { scope?: "report-only"; verification?: "verified" | "not-checked"; zip_path: string; @@ -233,7 +233,7 @@ type CliResolvedEvalVariant = Omit & workflow_input?: CliJsonValue; }; -export type CliEvalMatrixRow = Omit & { +type CliEvalMatrixRow = Omit & { variant: CliResolvedEvalVariant; /** Explicit operator-controlled workflow input; Ultrafuzz does not infer its domain shape. */ workflow_input?: CliJsonValue; @@ -249,14 +249,14 @@ export interface CliEvalRunData { incomplete: number; } -export interface CliEvalHistoryAppendData { +interface CliEvalHistoryAppendData { history_path: string; observations: number; appended: number; charts: string[]; } -export interface CliEvalHistoryViewData { +interface CliEvalHistoryViewData { history_path: string; observations: number; charts_directory: string; @@ -264,7 +264,7 @@ export interface CliEvalHistoryViewData { } /** Payloads for the packaged audit-profile and topology commands. */ -export interface CliAuditProfileData { +interface CliAuditProfileData { id: string; description: string; intended_use: string; @@ -281,7 +281,7 @@ export interface CliAuditProfileData { overridden_settings: string[]; } -export interface CliAuditProfileSummary { +interface CliAuditProfileSummary { id: string; description: string; intended_use: string; @@ -290,14 +290,14 @@ export interface CliAuditProfileSummary { topology_digest?: string; } -export interface CliAuditProfilesData { +interface CliAuditProfilesData { schema_version: number; catalog_digest: string; default_profile: string; profiles: CliAuditProfileSummary[]; } -export interface CliTopologySummary { +interface CliTopologySummary { id: string; description: string; topology_path: string; @@ -305,15 +305,15 @@ export interface CliTopologySummary { digest: string; } -export interface CliTopologyListData { +interface CliTopologyListData { topologies: CliTopologySummary[]; } -export interface CliTopologyShowData extends CliTopologySummary { +interface CliTopologyShowData extends CliTopologySummary { source: string; } -export interface CliTopologyCopyData { +interface CliTopologyCopyData { id: string; source_path: string; destination_path: string; @@ -321,7 +321,7 @@ export interface CliTopologyCopyData { overwritten: boolean; } -export interface CliArtifactValidateData { +interface CliArtifactValidateData { contract: string; path: string; } @@ -385,7 +385,7 @@ export interface CliCommandDataMap { export type CliCommandData = CliCommandDataMap[CliKnownCommand]; -export type CliKnownResultEnvelope = { +type CliKnownResultEnvelope = { [Command in CliKnownCommand]: { schema_version: typeof CLI_SCHEMA_VERSION; command: Command; @@ -395,7 +395,7 @@ export type CliKnownResultEnvelope = { }; }[CliKnownCommand]; -export interface CliInvocationFailureEnvelope { +interface CliInvocationFailureEnvelope { schema_version: typeof CLI_SCHEMA_VERSION; command: string; ok: false; diff --git a/packages/cli/src/cli-schema-registry.ts b/packages/cli/src/cli-schema-registry.ts index dfb875e7f..99ffa2064 100644 --- a/packages/cli/src/cli-schema-registry.ts +++ b/packages/cli/src/cli-schema-registry.ts @@ -69,10 +69,10 @@ function loadSchemaDocument(filename: string): Readonly> } export const cliResultJsonSchema = loadSchemaDocument(CLI_RESULT_SCHEMA_FILENAME); -export const operatorInputJsonSchema = loadSchemaDocument(OPERATOR_INPUT_SCHEMA_FILENAME); -export const reportBundleManifestJsonSchema = loadSchemaDocument(REPORT_BUNDLE_MANIFEST_SCHEMA_FILENAME); +const operatorInputJsonSchema = loadSchemaDocument(OPERATOR_INPUT_SCHEMA_FILENAME); +const reportBundleManifestJsonSchema = loadSchemaDocument(REPORT_BUNDLE_MANIFEST_SCHEMA_FILENAME); -export const CLI_SCHEMA_EXPORTS = Object.freeze({ +const CLI_SCHEMA_EXPORTS = Object.freeze({ cliResultJsonSchema, operatorInputJsonSchema, reportBundleManifestJsonSchema @@ -152,7 +152,7 @@ export function cliOwnedSchemaRegistry(): readonly SchemaRegistryEntry[] { return cachedOwnedRegistry; } -export function cliSchemaBundleDigest(): string { +function cliSchemaBundleDigest(): string { return schemaRegistryBundleDigest(cliOwnedSchemaRegistry()); } diff --git a/packages/cli/src/run-statistics.ts b/packages/cli/src/run-statistics.ts index 4787b6066..7349efe8d 100644 --- a/packages/cli/src/run-statistics.ts +++ b/packages/cli/src/run-statistics.ts @@ -22,9 +22,9 @@ import { } from "@ultrafuzz/runtime"; import { sameStrings } from "@ultrafuzz/artifacts"; -export const RUN_STATISTICS_SCHEMA_VERSION = "ultrafuzz.stats.v1" as const; +const RUN_STATISTICS_SCHEMA_VERSION = "ultrafuzz.stats.v1" as const; -export interface StatisticsSource { +interface StatisticsSource { kind: "local-run" | "report-bundle"; path: string; } @@ -58,9 +58,9 @@ export interface TokenStatistics { models: string[]; } -export type NodeStatisticsStatus = NodeStatus | "canceled" | "unknown"; +type NodeStatisticsStatus = NodeStatus | "canceled" | "unknown"; -export interface NodeStatistics { +interface NodeStatistics { node_id: string; logical_node_id: string | null; kind: PlannedGraphNodeDocument["kind"] | null; @@ -78,7 +78,7 @@ export interface NodeStatistics { usage: TokenStatistics | null; } -export interface AccountingCumulativeStatistics { +interface AccountingCumulativeStatistics { input_tokens: number; cache_read_tokens: number; cache_write_tokens: number; diff --git a/packages/dashboard/frontend/src/display.ts b/packages/dashboard/frontend/src/display.ts index 1d9958313..fee4703d9 100644 --- a/packages/dashboard/frontend/src/display.ts +++ b/packages/dashboard/frontend/src/display.ts @@ -36,7 +36,7 @@ const reviewKindLabels: Record = { "aggregate-test-files": "Test aggregation" }; -export function nodeCardEyebrow(data: NodeCardDisplayData): string | null { +function nodeCardEyebrow(data: NodeCardDisplayData): string | null { const eyebrow = nodeCardEyebrowLabel(data); return displayValueKey(eyebrow) === displayValueKey(data.label) ? null : eyebrow; } diff --git a/packages/dashboard/frontend/src/edgeEndpointEditing.ts b/packages/dashboard/frontend/src/edgeEndpointEditing.ts index 955f3e120..42b3072b9 100644 --- a/packages/dashboard/frontend/src/edgeEndpointEditing.ts +++ b/packages/dashboard/frontend/src/edgeEndpointEditing.ts @@ -20,7 +20,7 @@ export type EdgeEndpointValidationResult = { valid: boolean; }; -export type TopologyEdgeMutationNode = { +type TopologyEdgeMutationNode = { depends_on?: string[]; id: string; }; diff --git a/packages/dashboard/frontend/src/graphLayout.ts b/packages/dashboard/frontend/src/graphLayout.ts index 8128a05c7..1abebfbce 100644 --- a/packages/dashboard/frontend/src/graphLayout.ts +++ b/packages/dashboard/frontend/src/graphLayout.ts @@ -28,15 +28,15 @@ export type PhaseDimensions = { width: number; }; -export const dashboardNodeWidth = 268; -export const dashboardNodeHeight = 132; +const dashboardNodeWidth = 268; +const dashboardNodeHeight = 132; export const metaNodeWidth = 138; export const metaNodeHeight = 56; export const metaNodeGap = 76; -export const phaseNodeGap = 52; -export const phaseGroupGap = 108; -export const phaseBranchGap = 72; -export const phasePadding = { +const phaseNodeGap = 52; +const phaseGroupGap = 108; +const phaseBranchGap = 72; +const phasePadding = { left: 36, right: 36, top: 62, diff --git a/packages/dashboard/frontend/src/nodeEvidence.ts b/packages/dashboard/frontend/src/nodeEvidence.ts index a3e231f7b..5516e4e2f 100644 --- a/packages/dashboard/frontend/src/nodeEvidence.ts +++ b/packages/dashboard/frontend/src/nodeEvidence.ts @@ -1,6 +1,6 @@ export type NodeEvidenceSectionId = "artifacts" | "logs" | "findings"; -export type NodeEvidenceAvailability = { +type NodeEvidenceAvailability = { logs: boolean; findings: boolean; patch: boolean; @@ -8,7 +8,7 @@ export type NodeEvidenceAvailability = { metadata: boolean; }; -export type NodeEvidenceDetail = { +type NodeEvidenceDetail = { stdout?: string; stderr?: string; findings: unknown[]; diff --git a/packages/dashboard/frontend/src/theme.ts b/packages/dashboard/frontend/src/theme.ts index fb6850292..9229ad26a 100644 --- a/packages/dashboard/frontend/src/theme.ts +++ b/packages/dashboard/frontend/src/theme.ts @@ -1,14 +1,14 @@ export type ThemePreference = "system" | "light" | "dark"; export type ResolvedTheme = "light" | "dark"; -export const THEME_STORAGE_KEY = "mds-theme"; -export const DEFAULT_THEME_PREFERENCE: ThemePreference = "system"; +const THEME_STORAGE_KEY = "mds-theme"; +const DEFAULT_THEME_PREFERENCE: ThemePreference = "system"; -export function isThemePreference(value: string | null): value is ThemePreference { +function isThemePreference(value: string | null): value is ThemePreference { return value === "system" || value === "light" || value === "dark"; } -export function getSystemTheme(): ResolvedTheme { +function getSystemTheme(): ResolvedTheme { if (typeof window === "undefined" || typeof window.matchMedia !== "function") { return "light"; } diff --git a/packages/dashboard/frontend/src/useManagedConfigEditor.ts b/packages/dashboard/frontend/src/useManagedConfigEditor.ts index a5c5a7fc7..4d5cc58a6 100644 --- a/packages/dashboard/frontend/src/useManagedConfigEditor.ts +++ b/packages/dashboard/frontend/src/useManagedConfigEditor.ts @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from "react"; -export type ManagedConfigDetail = { +type ManagedConfigDetail = { path: string; source: string; editable: boolean; diff --git a/packages/dashboard/frontend/src/useManagedPromptEditor.ts b/packages/dashboard/frontend/src/useManagedPromptEditor.ts index b58cdaf30..fd8f9cbe8 100644 --- a/packages/dashboard/frontend/src/useManagedPromptEditor.ts +++ b/packages/dashboard/frontend/src/useManagedPromptEditor.ts @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { validatePromptTemplateVariables } from "./templateValidation"; import { dashboardRequest, parseDashboardHttpResponse, throwDashboardHttpError } from "./wireContracts"; -export const promptAutosaveDelayMs = 1500; +const promptAutosaveDelayMs = 1500; type PromptSummary = { strategyId?: string; diff --git a/packages/evals/test/helpers.ts b/packages/evals/test/helpers.ts index 6a638e90a..7ddfb0944 100644 --- a/packages/evals/test/helpers.ts +++ b/packages/evals/test/helpers.ts @@ -92,7 +92,7 @@ export function cleanRecoveryEquivalence(overrides: Partial = {}): EvalRunProvenance { +function testRunProvenance(overrides: Partial = {}): EvalRunProvenance { return { candidate: { label: "test-candidate", commit: TEST_SHA40, dirty: false }, benchmark: { @@ -120,7 +120,7 @@ export function testRunProvenance(overrides: Partial = {}): E }; } -export function testSummaryProvenance(overrides: Partial = {}): EvalSummaryProvenance { +function testSummaryProvenance(overrides: Partial = {}): EvalSummaryProvenance { const run = testRunProvenance(); return { availability: "available", diff --git a/packages/modal/src/ground-truth.ts b/packages/modal/src/ground-truth.ts index 7bf16afc9..5c8e2c61c 100644 --- a/packages/modal/src/ground-truth.ts +++ b/packages/modal/src/ground-truth.ts @@ -1,6 +1,6 @@ import type { GroundTruthSubject } from "@ultrafuzz/evals"; -export interface ModalGroundTruthBug { +interface ModalGroundTruthBug { id: string; title: string; severity?: string; diff --git a/packages/modal/src/worker-lineage.ts b/packages/modal/src/worker-lineage.ts index 1666e2366..28c4b587e 100644 --- a/packages/modal/src/worker-lineage.ts +++ b/packages/modal/src/worker-lineage.ts @@ -151,10 +151,7 @@ async function ensurePersistentWorkerLineageLocked(input: { await writeLineageAtomic(input.lineagePath, input.lineage); } -export async function assertCurrentPersistentWorkerLineage( - lineagePath: string, - expected: ModalWorkerLineage -): Promise { +function assertCurrentPersistentWorkerLineage(lineagePath: string, expected: ModalWorkerLineage): void { let persisted: ModalWorkerLineage; try { persisted = readModalWorkerLineage(lineagePath); @@ -173,7 +170,7 @@ export function guardCurrentPersistentWorkerLineage( return async (write: () => Promise): Promise => { const release = await acquireLineageLock(lineagePath); try { - await assertCurrentPersistentWorkerLineage(lineagePath, expected); + assertCurrentPersistentWorkerLineage(lineagePath, expected); return await write(); } finally { await release(); diff --git a/packages/modal/test/current-artifact-fixtures.ts b/packages/modal/test/current-artifact-fixtures.ts index f11dbe405..1ded9f7f8 100644 --- a/packages/modal/test/current-artifact-fixtures.ts +++ b/packages/modal/test/current-artifact-fixtures.ts @@ -20,7 +20,7 @@ import { projectCanonicalFinalReport, WORKFLOW_CONTROL_INTEGRITY_SCHEMA_VERSION const FIXTURE_TIMESTAMP = "2026-01-01T00:00:00.000Z"; -export function currentFinding(overrides: Record = {}): Record { +function currentFinding(overrides: Record = {}): Record { return { schema_version: "ultrafuzz.finding.v2", id: "fixture-finding-1", diff --git a/packages/runtime/src/required-commands.ts b/packages/runtime/src/required-commands.ts index c390f37fc..5105ca3e1 100644 --- a/packages/runtime/src/required-commands.ts +++ b/packages/runtime/src/required-commands.ts @@ -80,7 +80,7 @@ export async function probeCommandsForExecution( ); } -export function resolveExecutable( +function resolveExecutable( name: string, env: Record ): { available: boolean; path: string | null } { diff --git a/packages/runtime/src/trusted-cli-closure.ts b/packages/runtime/src/trusted-cli-closure.ts index e011e9da1..deb234f06 100644 --- a/packages/runtime/src/trusted-cli-closure.ts +++ b/packages/runtime/src/trusted-cli-closure.ts @@ -33,13 +33,13 @@ interface SourcePackage { dependencies: Record; } -export interface TrustedCliClosureFile { +interface TrustedCliClosureFile { path: string; sha256: string; executable: boolean; } -export interface TrustedCliClosurePackage { +interface TrustedCliClosurePackage { id: string; name: string; version: string; @@ -48,7 +48,7 @@ export interface TrustedCliClosurePackage { files: readonly TrustedCliClosureFile[]; } -export interface TrustedCliClosureManifest { +interface TrustedCliClosureManifest { schema_version: typeof CLOSURE_SCHEMA_VERSION; cli_entrypoint: string; module_confinement: TrustedCliClosureFile; diff --git a/packages/runtime/src/unverified-report-inputs.ts b/packages/runtime/src/unverified-report-inputs.ts index 4e45ebaac..05ded6dec 100644 --- a/packages/runtime/src/unverified-report-inputs.ts +++ b/packages/runtime/src/unverified-report-inputs.ts @@ -358,6 +358,6 @@ function safeReportPath(relative: string): boolean { ); } -export function asRecord(value: unknown): JsonRecord | undefined { +function asRecord(value: unknown): JsonRecord | undefined { return typeof value === "object" && value !== null && !Array.isArray(value) ? (value as JsonRecord) : undefined; } diff --git a/packages/runtime/src/workflow-execution-snapshot-capability.ts b/packages/runtime/src/workflow-execution-snapshot-capability.ts index 1359d27a5..2227bb34f 100644 --- a/packages/runtime/src/workflow-execution-snapshot-capability.ts +++ b/packages/runtime/src/workflow-execution-snapshot-capability.ts @@ -7,7 +7,7 @@ const WORKFLOW_EXECUTION_SNAPSHOT_CAPABILITY: unique symbol = Symbol( "ultrafuzz.workflow-execution-snapshot-capability" ); -export interface WorkflowExecutionSnapshotProtectedDirectory { +interface WorkflowExecutionSnapshotProtectedDirectory { kind: "directory"; relativePath: string; device: number; @@ -16,7 +16,7 @@ export interface WorkflowExecutionSnapshotProtectedDirectory { links: number; } -export interface WorkflowExecutionSnapshotProtectedFile { +interface WorkflowExecutionSnapshotProtectedFile { kind: "file"; relativePath: string; device: number; @@ -27,7 +27,7 @@ export interface WorkflowExecutionSnapshotProtectedFile { sha256: string; } -export interface WorkflowExecutionSnapshotProtectedLink { +interface WorkflowExecutionSnapshotProtectedLink { kind: "link"; relativePath: string; device: number; diff --git a/packages/runtime/src/workflow-run-link.ts b/packages/runtime/src/workflow-run-link.ts index 38ec07010..35c04b6a1 100644 --- a/packages/runtime/src/workflow-run-link.ts +++ b/packages/runtime/src/workflow-run-link.ts @@ -257,7 +257,7 @@ export function verifyWorkflowRunLinkAuthorization(layout: RunLayout, entry: Wor } } -export function workflowRunLinkEvent(layout: RunLayout, linkId: string): EventRecord | undefined { +function workflowRunLinkEvent(layout: RunLayout, linkId: string): EventRecord | undefined { const matches = replayAllEvents(layout).filter( (event) => event.event_type === "workflow-link-recorded" && eventPayload(event).workflow_link_id === linkId ); diff --git a/packages/runtime/test/cloud-worker-harness.ts b/packages/runtime/test/cloud-worker-harness.ts index 06bc54dd4..efcd35911 100644 --- a/packages/runtime/test/cloud-worker-harness.ts +++ b/packages/runtime/test/cloud-worker-harness.ts @@ -7,7 +7,7 @@ import * as ts from "typescript"; import type { CompiledSmithersWorkflow } from "../src/smithers.js"; -export interface RenderedElement { +interface RenderedElement { type: unknown; props: Record; } diff --git a/packages/runtime/test/reference-fixtures.ts b/packages/runtime/test/reference-fixtures.ts index bbc786e77..db3272f87 100644 --- a/packages/runtime/test/reference-fixtures.ts +++ b/packages/runtime/test/reference-fixtures.ts @@ -16,13 +16,13 @@ import { * declares it. Tests bind their local cache representation to this entry rather than appending a * fixture entry, so a catalog edit can never make the "clean scaffold" assertions vacuous. */ -export const SHIPPED_VULNERABILITY_DATABASE = shippedReference("vulnerability-database.owasp-scs"); +const SHIPPED_VULNERABILITY_DATABASE = shippedReference("vulnerability-database.owasp-scs"); export function shippedReferenceCatalog(): ReferenceCatalog { return parseReferenceCatalog(defaultReferenceCatalogYaml()); } -export function shippedReference(id: string): { repo: string; commit: string; paths: readonly string[] } { +function shippedReference(id: string): { repo: string; commit: string; paths: readonly string[] } { const entry = shippedReferenceCatalog().references[id]; assert.ok(entry, `shipped references.yml must define ${id}`); return { repo: entry.repo, commit: entry.commit, paths: entry.paths }; @@ -142,6 +142,6 @@ export function fixtureFileDigest( return { path: filePath, size_bytes: contents.byteLength, sha256: digestFixtureBytes(contents) }; } -export function digestFixtureBytes(contents: Buffer): string { +function digestFixtureBytes(contents: Buffer): string { return crypto.createHash("sha256").update(contents).digest("hex"); } diff --git a/packages/runtime/test/temporary-root.ts b/packages/runtime/test/temporary-root.ts index 061fe7c79..d5a9ef8b9 100644 --- a/packages/runtime/test/temporary-root.ts +++ b/packages/runtime/test/temporary-root.ts @@ -47,8 +47,8 @@ export function registerTemporaryPath(directory: string): string { return directory; } -/** Remove every registered root. Exposed for fixtures that clean up eagerly. */ -export function removeRegisteredRoots(): void { +/** Remove every registered root. */ +function removeRegisteredRoots(): void { for (let root = registered.pop(); root !== undefined; root = registered.pop()) removeTemporaryRoot(root); } diff --git a/packages/security/src/secretlint-scan-channel.ts b/packages/security/src/secretlint-scan-channel.ts index 532c12b6f..a194fdc90 100644 --- a/packages/security/src/secretlint-scan-channel.ts +++ b/packages/security/src/secretlint-scan-channel.ts @@ -16,13 +16,13 @@ const PAYLOAD_LENGTH_BYTES = 4; * Initial payload capacity. The buffer grows on demand up to the maximum, and * growth only reserves virtual address space until pages are touched. */ -export const SCAN_CHANNEL_INITIAL_BYTES = 1 << 16; +const SCAN_CHANNEL_INITIAL_BYTES = 1 << 16; /** * Publication-gate artifacts are capped at 16MB of bytes, which decode to at * most 16M UTF-16 code units and re-encode to at most 3 bytes each; 256MB * covers any text a caller can realistically hand the redaction API. */ -export const SCAN_CHANNEL_MAX_BYTES = 1 << 28; +const SCAN_CHANNEL_MAX_BYTES = 1 << 28; const utf8Decoder = new TextDecoder(); const utf8Encoder = new TextEncoder(); diff --git a/packages/topology/src/path-utils.ts b/packages/topology/src/path-utils.ts index b713dd4f2..84cd2ea21 100644 --- a/packages/topology/src/path-utils.ts +++ b/packages/topology/src/path-utils.ts @@ -7,7 +7,7 @@ export function isSafeId(value: string): boolean { return value.length > 0 && /^[a-z0-9_-]+$/.test(value) && value !== "." && value !== ".."; } -export function isSafeRelativePath(value: string): boolean { +function isSafeRelativePath(value: string): boolean { if (value.length === 0 || value.includes("\\")) { return false; } diff --git a/scripts/ci/verify-cohort-reachability.mjs b/scripts/ci/verify-cohort-reachability.mjs index 47e2cb0dd..418e2abaf 100644 --- a/scripts/ci/verify-cohort-reachability.mjs +++ b/scripts/ci/verify-cohort-reachability.mjs @@ -41,7 +41,7 @@ const COHORT_DIRECTORIES = Object.freeze({ "ultrafuzz-bench": "ultrafuzzbench", * Selectors: a benchmark lane name probes exactly the targets that lane runs, a * cohort name probes every target that cohort pins. */ -export const COHORT_REACHABILITY_LANES = Object.freeze([...BENCHMARK_LANE_NAMES, ...Object.keys(COHORT_DIRECTORIES)]); +const COHORT_REACHABILITY_LANES = Object.freeze([...BENCHMARK_LANE_NAMES, ...Object.keys(COHORT_DIRECTORIES)]); const GITHUB_REPOSITORY = /^https:\/\/github\.com\/([A-Za-z0-9._-]+)\/([A-Za-z0-9._-]+)$/u; const SCP_LIKE_URL = /^[A-Za-z0-9._-]+@[A-Za-z0-9._-]+:[A-Za-z0-9._~\-/]+$/u; const REMOTE_HELPER_URL = /^[A-Za-z0-9+.-]+::/u; From 155d5f20ce4fe478874981099c0b089d0c55251e Mon Sep 17 00:00:00 2001 From: Antonio Viggiano Date: Tue, 29 Sep 2026 06:17:04 +0000 Subject: [PATCH 4/4] ci: fail on unused exports, types and duplicates The previous commits clear every unused export, unused exported type and duplicate export that knip reported. Add those three categories to the --include list of the root knip script, so `pnpm -w knip` (the blocking "Find dead code and dependencies" CI step, and `pnpm -w ci`) now fails on them. Delete the separate continue-on-error "Report unused exports" step, which only printed them. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 7 ------- package.json | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97fde79a0..c928e4aae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,13 +67,6 @@ jobs: - name: Find dead code and dependencies run: pnpm -w knip - # Informational until the pending dead-code removals land; then these - # categories move into the blocking `pnpm -w knip` step above. Findings - # exit 0, so they do not add a failure annotation to every run. - - name: Report unused exports - continue-on-error: true - run: pnpm -w knip --include exports,types,duplicates --no-exit-code - - name: Build run: pnpm -w build diff --git a/package.json b/package.json index fba00c0ea..d672c858f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "docs:check": "node scripts/audit-profile-docs.mjs --check && node scripts/prompt-catalog-docs.mjs --check && node scripts/docs-check.mjs", "format": "prettier --write .", "format:check": "prettier --check .", - "knip": "pnpm dlx knip@6.33.0 --include files,dependencies,unlisted,unresolved --treat-config-hints-as-errors", + "knip": "pnpm dlx knip@6.33.0 --include files,dependencies,unlisted,unresolved,exports,types,duplicates --treat-config-hints-as-errors", "lint": "eslint \"packages/**/*.{ts,tsx,js,mjs,cjs}\" \"scripts/**/*.{ts,tsx,js,mjs,cjs}\" \"*.{js,mjs,cjs}\"", "lint:fix": "eslint \"packages/**/*.{ts,tsx,js,mjs,cjs}\" \"scripts/**/*.{ts,tsx,js,mjs,cjs}\" \"*.{js,mjs,cjs}\" --fix", "lint:strict": "ULTRAFUZZ_STRICT_LINT=1 eslint \"packages/**/*.{ts,tsx,js,mjs,cjs}\" \"scripts/**/*.{ts,tsx,js,mjs,cjs}\" \"*.{js,mjs,cjs}\" --max-warnings 0",