@tangle-network/agent-app 0.60.216 → 0.60.218

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/signoff/worker-defaults.ts","../src/signoff/config.ts","../src/signoff/app-defaults.ts","../src/signoff/run.ts","../src/signoff/cache.ts","../src/signoff/node-version.ts","../src/signoff/workflow-pin.ts","../src/signoff/exec.ts","../src/signoff/schedule.ts","../src/signoff/seeds.ts","../src/signoff/store.ts","../src/signoff/workspace.ts","../src/signoff/report.ts","../src/signoff/browser-budget.ts","../src/signoff/shell-alignment.ts","../src/signoff/shell-alignment-cli.ts","../src/signoff/surface-ladder.ts","../src/signoff/surface-ladder-cli.ts","../src/signoff/workspace-surface.ts","../src/signoff/workspace-surface-cli.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { basename, dirname, join } from 'node:path'\n\n/**\n * The Cloudflare defaults every agent-app Worker ships with, checked against\n * the Worker's own Wrangler config.\n *\n * Why these keys:\n * - `observability` with logs and traces at a 1.0 sampling rate. Workers Logs\n * and traces are what a production incident is read from; a 0.1 sample\n * dropped nine of ten failing chat turns in exactly the apps whose traffic is\n * small enough to afford 1.0. Traces are explicit because\n * `observability.enabled` turns on logs only while tracing is in beta.\n * - `upload_source_maps`, so exceptions in Workers Logs and on-demand CPU and\n * memory profiles name source functions instead of minified bundle offsets.\n * - `nodejs_compat` and a compatibility date no older than the one the\n * templates ship, so a Worker does not run years-old runtime semantics.\n *\n * Smart placement is deliberately absent: these Workers stream long model turns\n * from a sandbox and serve assets next to the user, and the measured comparison\n * is in docs/worker-defaults.md.\n *\n * The values are read through the app's own installed `wrangler`, so the check\n * resolves the source config as Wrangler does, including the keys each\n * `[env.*]` inherits or overrides. Vite-plugin apps deploy a config generated\n * at build time from this source; their Worker source maps also need the build\n * to emit them (docs/worker-defaults.md).\n */\n\n/** The name the built-in step reports under; a repo cannot declare a step with it. */\nexport const WORKER_DEFAULTS_STEP = 'worker defaults'\n\n/** Update together with the templates' `compatibility_date`. */\nexport const WORKER_COMPATIBILITY_DATE_FLOOR = '2026-09-01'\n\n/** `wrangler.toml` and named variants such as `wrangler.health.toml` or\n * `wrangler-demo.toml`: products deploy secondary Workers from those. */\nconst WRANGLER_CONFIG_NAME = /^wrangler[.-]?[\\w.-]*\\.(toml|json|jsonc)$/\n\ninterface SamplingSettings {\n readonly enabled?: boolean\n readonly head_sampling_rate?: number\n readonly invocation_logs?: boolean\n}\n\ninterface ResolvedWorkerConfig {\n readonly name?: string\n readonly compatibility_date?: string\n readonly compatibility_flags?: readonly string[]\n readonly upload_source_maps?: boolean\n readonly observability?: SamplingSettings & {\n readonly logs?: SamplingSettings\n readonly traces?: SamplingSettings\n }\n}\n\ninterface WranglerConfigApi {\n unstable_readConfig(args: { config: string; env?: string }): ResolvedWorkerConfig\n experimental_readRawConfig(args: { config: string }): { rawConfig: { env?: Record<string, unknown> } }\n}\n\nexport interface WorkerDefaultsFinding {\n /** Config path relative to the repo root. */\n readonly config: string\n /** `null` for the top-level Worker, otherwise the `[env.<name>]` it deploys. */\n readonly env: string | null\n readonly problem: string\n}\n\nexport interface WorkerDefaultsResult {\n readonly checked: readonly { readonly config: string; readonly envs: readonly (string | null)[] }[]\n readonly findings: readonly WorkerDefaultsFinding[]\n}\n\n/** Every file the repo tracks, repo-relative. Generated output is gitignored, so this is the complete source list without a hand-kept exclude list. */\nexport function trackedFiles(repoRoot: string): string[] {\n const listed = spawnSync('git', ['ls-files', '-z'], { cwd: repoRoot, encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 })\n if (listed.status !== 0) throw new Error(`signoff: git ls-files failed in ${repoRoot}: ${listed.stderr}`)\n return listed.stdout.split('\\0').filter((path) => path !== '')\n}\n\n/**\n * Wrangler configs the repo tracks. Generated output (`.wrangler/`, build\n * directories) is gitignored, so `git ls-files` is the complete source list\n * without a hand-kept exclude list.\n */\nexport function trackedWorkerConfigs(repoRoot: string): string[] {\n return trackedFiles(repoRoot).filter((path) => WRANGLER_CONFIG_NAME.test(basename(path))).sort()\n}\n\nfunction problemsFor(config: ResolvedWorkerConfig): string[] {\n const problems: string[] = []\n const observability = config.observability\n const isFullSample = (settings: SamplingSettings | undefined): boolean => (settings?.head_sampling_rate ?? 1) === 1\n\n if (observability?.enabled !== true) problems.push('observability.enabled must be true')\n if (!isFullSample(observability)) {\n problems.push(`observability.head_sampling_rate must be 1 (is ${observability?.head_sampling_rate})`)\n }\n if (observability?.logs?.enabled === false) problems.push('observability.logs.enabled must not be false')\n if (!isFullSample(observability?.logs)) {\n problems.push(`observability.logs.head_sampling_rate must be 1 (is ${observability?.logs?.head_sampling_rate})`)\n }\n if (observability?.logs?.invocation_logs === false) {\n problems.push('observability.logs.invocation_logs must not be false')\n }\n if (observability?.traces?.enabled !== true) problems.push('observability.traces.enabled must be true')\n if (!isFullSample(observability?.traces)) {\n problems.push(`observability.traces.head_sampling_rate must be 1 (is ${observability?.traces?.head_sampling_rate})`)\n }\n if (config.upload_source_maps !== true) problems.push('upload_source_maps must be true')\n if (!config.compatibility_flags?.includes('nodejs_compat')) {\n problems.push('compatibility_flags must include \"nodejs_compat\"')\n }\n const date = config.compatibility_date\n if (date === undefined || date < WORKER_COMPATIBILITY_DATE_FLOOR) {\n problems.push(`compatibility_date must be ${WORKER_COMPATIBILITY_DATE_FLOOR} or later (is ${date ?? 'unset'})`)\n }\n return problems\n}\n\n/**\n * Wrangler logs config warnings (unknown keys, missing secrets) to the console\n * while reading. They belong to the app's own `wrangler deploy`, not to this\n * verdict, so they are muted for the duration of the read. `CLOUDFLARE_ENV`\n * is cleared too: Wrangler reads it as the default environment, which would\n * make the \"top level\" row check some other environment.\n */\nfunction quietly<T>(read: () => T): T {\n const saved = { WRANGLER_LOG: process.env.WRANGLER_LOG, CLOUDFLARE_ENV: process.env.CLOUDFLARE_ENV }\n process.env.WRANGLER_LOG = 'error'\n delete process.env.CLOUDFLARE_ENV\n try {\n return read()\n } finally {\n for (const [key, value] of Object.entries(saved)) {\n if (value === undefined) delete process.env[key]\n else process.env[key] = value\n }\n }\n}\n\nfunction loadWrangler(configDir: string): WranglerConfigApi | null {\n try {\n return createRequire(join(configDir, 'package.json'))('wrangler') as WranglerConfigApi\n } catch {\n return null\n }\n}\n\n/**\n * Check each Worker config, and every environment it deploys, against the\n * defaults. `configs` are repo-relative paths; omit them to check every tracked\n * Wrangler config.\n */\nexport function checkWorkerDefaults(repoRoot: string, configs?: readonly string[]): WorkerDefaultsResult {\n const findings: WorkerDefaultsFinding[] = []\n const checked: { config: string; envs: (string | null)[] }[] = []\n\n for (const config of configs ?? trackedWorkerConfigs(repoRoot)) {\n const path = join(repoRoot, config)\n if (!existsSync(path)) {\n findings.push({ config, env: null, problem: 'declared Worker config does not exist' })\n continue\n }\n const wrangler = loadWrangler(dirname(path))\n if (!wrangler) {\n findings.push({ config, env: null, problem: 'wrangler is not installed where this config can resolve it' })\n continue\n }\n const envNames = Object.keys(quietly(() => wrangler.experimental_readRawConfig({ config: path })).rawConfig.env ?? {})\n const envs: (string | null)[] = [null, ...envNames]\n checked.push({ config, envs })\n for (const env of envs) {\n const resolved = quietly(() => wrangler.unstable_readConfig({ config: path, ...(env ? { env } : {}) }))\n for (const problem of problemsFor(resolved)) findings.push({ config, env, problem })\n }\n }\n return { checked, findings }\n}\n\nexport function formatWorkerDefaults(result: WorkerDefaultsResult): string {\n if (result.checked.length === 0 && result.findings.length === 0) return 'no Wrangler config tracked; nothing to check\\n'\n const lines = result.checked.map(\n ({ config, envs }) => `checked ${config} (${envs.map((env) => env ?? 'top level').join(', ')})`,\n )\n for (const finding of result.findings) {\n lines.push(`FAIL ${finding.config}${finding.env ? ` [env.${finding.env}]` : ''}: ${finding.problem}`)\n }\n if (result.findings.length > 0) lines.push('Required keys: https://github.com/tangle-network/agent-app/blob/main/docs/worker-defaults.md')\n return `${lines.join('\\n')}\\n`\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { z } from 'zod'\nimport { APP_DEFAULTS_STEP, EXEMPTIBLE_DEFAULTS } from './app-defaults'\nimport { WORKER_DEFAULTS_STEP } from './worker-defaults'\nimport type { LoadedSignoffConfig, SignoffConfig, SignoffStepSpec } from './types'\n\n/**\n * Where the step list comes from.\n *\n * It is declared by the repo, never hardcoded here, because the three workflows\n * this has to reproduce do not share a shape: tax-agent filters its install to\n * one workspace package and runs a Python toolkit suite; legal-agent runs a\n * react-router typegen and a Worker startup check; agent-app runs a named\n * incident-class gate, a generated-project test and knip. A checker that\n * hardcodes any one of those is wrong for the other two.\n *\n * Three sources, in order:\n * 1. `signoff.config.mjs` (or `.js`) — the full surface, including per-step\n * `env`, `needs` and shuffle specs.\n * 2. a `signoff` key in `package.json` — the same shape, JSON-only.\n * 3. derived from the repo's own `scripts`, so a repo gets a real gate before\n * anyone writes a config. The derivation is documented below and its origin\n * is stamped into the proof, because a derived run is a weaker claim than a\n * declared one.\n */\n\nconst SIGNOFF_CONFIG_FILES: readonly string[] = ['signoff.config.mjs', 'signoff.config.js']\n\nconst shuffleSchema = z.object({\n runs: z.number().int().positive().optional(),\n seeds: z.array(z.number().int()).optional(),\n args: z.array(z.string()).optional(),\n})\n\nconst stepSchema = z.object({\n name: z.string().min(1),\n run: z.string().min(1),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n needs: z.array(z.string()).optional(),\n timeoutMs: z.number().int().positive().optional(),\n shuffle: z.union([z.boolean(), shuffleSchema]).optional(),\n})\n\nconst configSchema = z.object({\n install: z\n .object({\n run: z.string().min(1).optional(),\n storeDirFlag: z.string().nullable().optional(),\n storeEnv: z.string().nullable().optional(),\n cwd: z.string().optional(),\n timeoutMs: z.number().int().positive().optional(),\n env: z.record(z.string(), z.string()).optional(),\n })\n .optional(),\n steps: z.array(stepSchema).min(1),\n maxParallel: z.number().int().positive().optional(),\n env: z.record(z.string(), z.string()).optional(),\n nodeVersion: z.string().min(1).optional(),\n carryFiles: z.array(z.string()).optional(),\n cacheDir: z.string().optional(),\n storeGenerations: z.number().int().positive().optional(),\n workerConfigs: z.array(z.string().min(1)).optional(),\n agentApp: z\n .object({\n exemptions: z\n .object(\n Object.fromEntries(EXEMPTIBLE_DEFAULTS.map((id) => [id, z.string().trim().min(8, 'say why in a sentence').optional()])) as Record<\n (typeof EXEMPTIBLE_DEFAULTS)[number],\n z.ZodOptional<z.ZodString>\n >,\n )\n .strict()\n .optional(),\n })\n .optional(),\n})\n\nfunction describeIssues(error: z.ZodError, where: string): string {\n const lines = error.issues.map((issue) => ` ${issue.path.join('.') || '(root)'}: ${issue.message}`)\n return `signoff: ${where} is not a valid config:\\n${lines.join('\\n')}`\n}\n\nexport function parseSignoffConfig(value: unknown, where: string): SignoffConfig {\n const result = configSchema.safeParse(value)\n if (!result.success) throw new Error(describeIssues(result.error, where))\n for (const reserved of [WORKER_DEFAULTS_STEP, APP_DEFAULTS_STEP]) {\n if (result.data.steps.some((step) => step.name === reserved)) {\n throw new Error(`signoff: ${where} declares a step named \"${reserved}\", which the gate runs itself`)\n }\n }\n return result.data as SignoffConfig\n}\n\n/**\n * The script → step derivation, and the dependency edges it asserts.\n *\n * The edges are the speed lever, so each one is a claim about the repo:\n * typecheck, the suite, the build and knip are ASSUMED to read source and not\n * each other's output, so they run concurrently. Only `test:generated`\n * genuinely consumes a build artifact, so only it declares a dependency.\n *\n * **That assumption is a guess, and it is wrong for at least one real repo.**\n * agent-app's own suite copies `dist/` into a generated project while `tsup`\n * (`clean: true`) is deleting it, which fails loudly as \"dist/ not built\" and\n * quietly as a half-copied package. A repo whose suite reads build output MUST\n * declare `needs: ['build']` on it in a `signoff.config.mjs`; the derivation\n * cannot see that from a script name, which is one more reason a derived run is\n * a weaker claim than a declared one.\n *\n * `build:check` supersedes `build` when both exist (legal-agent's `build:check`\n * is `pnpm build && …`, so running both builds twice for one verdict).\n */\nconst DERIVED_STEPS: readonly {\n readonly script: string\n readonly name: string\n readonly shuffle?: boolean\n readonly supersedes?: string\n readonly needsBuild?: boolean\n}[] = [\n { script: 'peer-check', name: 'peer floors' },\n { script: 'typecheck', name: 'typecheck' },\n { script: 'test:gates', name: 'incident-class gates' },\n { script: 'test', name: 'unit tests', shuffle: true },\n { script: 'build', name: 'build' },\n { script: 'build:check', name: 'build + worker checks', supersedes: 'build' },\n { script: 'test:generated', name: 'generated projects', needsBuild: true },\n { script: 'knip', name: 'dead-surface (knip)' },\n]\n\nexport function deriveSignoffConfig(scripts: Readonly<Record<string, string>>): {\n readonly config: SignoffConfig\n readonly used: readonly string[]\n} {\n const present = DERIVED_STEPS.filter((candidate) => scripts[candidate.script] !== undefined)\n const superseded = new Set(present.map((candidate) => candidate.supersedes).filter((name): name is string => !!name))\n const kept = present.filter((candidate) => !superseded.has(candidate.script))\n const buildStep = kept.find((candidate) => candidate.script === 'build' || candidate.script === 'build:check')\n\n const steps: SignoffStepSpec[] = kept.map((candidate) => ({\n name: candidate.name,\n run: `pnpm run ${candidate.script}`,\n ...(candidate.shuffle ? { shuffle: true as const } : {}),\n ...(candidate.needsBuild && buildStep ? { needs: [buildStep.name] } : {}),\n }))\n\n if (steps.length === 0) {\n throw new Error(\n 'signoff: no config and no recognizable scripts. Add a `signoff.config.mjs` naming the steps ' +\n `this repo's CI runs, or a package.json \"signoff\" key. Recognized script names: ` +\n `${DERIVED_STEPS.map((candidate) => candidate.script).join(', ')}.`,\n )\n }\n return { config: { steps }, used: kept.map((candidate) => candidate.script) }\n}\n\nexport interface LoadSignoffConfigOptions {\n readonly repoRoot: string\n /** Explicit config path. Missing file is an error, never a silent fallback. */\n readonly configPath?: string\n}\n\nexport async function loadSignoffConfig(options: LoadSignoffConfigOptions): Promise<LoadedSignoffConfig> {\n const { repoRoot, configPath } = options\n\n if (configPath !== undefined) {\n const abs = resolve(repoRoot, configPath)\n if (!existsSync(abs)) throw new Error(`signoff: no config at ${abs}`)\n return { config: await importConfig(abs), origin: { kind: 'file', path: abs } }\n }\n\n for (const candidate of SIGNOFF_CONFIG_FILES) {\n const abs = join(repoRoot, candidate)\n if (existsSync(abs)) return { config: await importConfig(abs), origin: { kind: 'file', path: abs } }\n }\n\n const pkgPath = join(repoRoot, 'package.json')\n if (!existsSync(pkgPath)) {\n throw new Error(`signoff: ${repoRoot} has no package.json, no signoff.config.mjs, and nothing to derive from.`)\n }\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) as {\n signoff?: unknown\n scripts?: Record<string, string>\n }\n if (pkg.signoff !== undefined) {\n return { config: parseSignoffConfig(pkg.signoff, `${pkgPath} \"signoff\"`), origin: { kind: 'package-json', path: pkgPath } }\n }\n\n const derived = deriveSignoffConfig(pkg.scripts ?? {})\n return { config: derived.config, origin: { kind: 'derived', path: pkgPath, scripts: derived.used } }\n}\n\nasync function importConfig(abs: string): Promise<SignoffConfig> {\n const mod: unknown = await import(pathToFileURL(abs).href)\n const value = (mod as { default?: unknown }).default\n if (value === undefined) throw new Error(`signoff: ${abs} must have a default export`)\n return parseSignoffConfig(value, abs)\n}\n","import { spawnSync } from 'node:child_process'\nimport { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join, posix } from 'node:path'\nimport { LAUNCH_BUDGETS } from '../launch-invariants/catalog'\nimport { trackedFiles, trackedWorkerConfigs } from './worker-defaults'\n\n/**\n * The defaults an agent app inherits from agent-app, and whether this app has them.\n *\n * Each proven improvement ships as a default inside agent-app, so an app gets it by construction. This report reads\n * an app's checkout and says which defaults it has, which it turned off, and which it replaced with a local copy.\n * It is a report: it fails only on an explicit opt-out that gives no reason, so a gap stays visible without\n * blocking a merge, and an exemption is a line in the app's `signoff.config.mjs` with the reason beside it.\n *\n * The rows are the outcomes Drew named on 2026-10-19: the turn trace on every turn with `first_text_ms`, the shared\n * prewarm route, Worker placement beside the D1 primary, limit alarms wired in the server entry, and the Worker\n * upload size against Cloudflare's limit. A row is read from the source, the Wrangler config and the lockfile; it\n * never runs the app.\n */\n\n/** The name the built-in step reports under; a repo cannot declare a step with it. */\nexport const APP_DEFAULTS_STEP = 'agent-app defaults'\n\n/** Defaults an app may turn off with a reason. */\nexport const EXEMPTIBLE_DEFAULTS = ['turn-trace', 'first-text', 'prewarm', 'placement', 'limit-alarms'] as const\ntype ExemptibleDefault = (typeof EXEMPTIBLE_DEFAULTS)[number]\n\n/** An app's declared opt-outs: the default and why. An empty reason is a configuration error. */\nexport type AppDefaultsExemptions = Readonly<Partial<Record<ExemptibleDefault, string>>>\n\n/**\n * The first agent-app release that carries each outcome. An app pinned below one cannot have it, whatever its source says.\n * Add a line when a new default ships.\n */\nconst AGENT_APP_OUTCOME_FLOORS = [\n { id: 'turn-trace', label: 'turn trace', since: '0.60.199' },\n { id: 'first-text', label: 'first text', since: '0.60.203' },\n] as const\n\ntype DefaultStatus = 'ok' | 'gap' | 'unknown' | 'exempt' | 'opted-out' | 'na'\n\ninterface DefaultRow {\n readonly id: 'pin' | 'turn-trace' | 'first-text' | 'prewarm' | 'placement' | 'tool-count' | 'limit-alarms' | 'worker-bundle'\n readonly label: string\n readonly status: DefaultStatus\n readonly detail: string\n}\n\ninterface AppDefaultsReport {\n /** The package name. */\n readonly app: string\n /** The package directory relative to the repo root. */\n readonly dir: string\n /** The `@tangle-network/agent-app` version the package pins, or null when it is not a plain version. */\n readonly pin: string | null\n readonly rows: readonly DefaultRow[]\n /** Opt-outs that give no reason. These alone fail the step. */\n readonly findings: readonly string[]\n}\n\nexport interface AppDefaultsResult {\n readonly apps: readonly AppDefaultsReport[]\n readonly findings: readonly string[]\n}\n\nexport interface AppDefaultsOptions {\n /** Declared opt-outs per package name. Applied to every app when keyed by `*`. */\n readonly exemptions?: AppDefaultsExemptions\n /** Measure the Worker upload with the app's own Wrangler (default true). Needs a built app. */\n readonly measureBundle?: boolean\n /** The last turn trace Intelligence accepted per Intelligence project; see {@link readLastTurnExport}. */\n readonly exports?: ReadonlyMap<string, LastTurnExport | null>\n}\n\n/** The newest `agent_app.turn` root span Intelligence holds for a project. */\ninterface LastTurnExport {\n readonly at: number\n readonly traceId: string\n readonly firstTextMs?: number\n}\n\nconst SOURCE_EXTENSIONS = /\\.(?:[cm]?[jt]sx?)$/\nconst NOT_SOURCE = /(?:^|\\/)(?:node_modules|dist|build|\\.wrangler|tests?|__tests__|e2e|scripts|proof|journeys?|evals?|docs|examples|stories|\\.storybook)\\/|\\.(?:test|spec|stories|e2e|bench)\\.[cm]?[jt]sx?$|\\.d\\.ts$/\nconst MAX_SOURCE_BYTES = 400 * 1024\n\ninterface SourceFile {\n readonly path: string\n readonly text: string\n}\n\ninterface AppPackage {\n readonly name: string\n /** Directory relative to the repo root, `.` for the root. */\n readonly dir: string\n readonly spec: string\n}\n\nfunction readJson(path: string): Record<string, unknown> | null {\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as Record<string, unknown>\n } catch {\n return null\n }\n}\n\n/** Packages in the repo that depend on `@tangle-network/agent-app`. agent-app itself is not one. */\nfunction findAppPackages(repoRoot: string, tracked: readonly string[]): AppPackage[] {\n const packages: AppPackage[] = []\n for (const path of tracked) {\n if (posix.basename(path) !== 'package.json' || /(?:^|\\/)node_modules\\//.test(path)) continue\n const pkg = readJson(join(repoRoot, path)) as {\n name?: string\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n peerDependencies?: Record<string, string>\n } | null\n if (!pkg || pkg.name === '@tangle-network/agent-app') continue\n const spec = pkg.dependencies?.['@tangle-network/agent-app'] ?? pkg.devDependencies?.['@tangle-network/agent-app'] ?? pkg.peerDependencies?.['@tangle-network/agent-app']\n if (spec === undefined) continue\n packages.push({ name: pkg.name ?? posix.dirname(path), dir: posix.dirname(path), spec })\n }\n return packages\n}\n\nfunction underDir(path: string, dir: string): boolean {\n return dir === '.' || path === dir || path.startsWith(`${dir}/`)\n}\n\n/** Source without comments, so a sentence that mentions `turnTrace: false` is not an opt-out. `://` stays: it is a URL. */\nfunction withoutComments(text: string): string {\n return text.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '').replace(/(?<!:)\\/\\/.*$/gm, '')\n}\n\nfunction readSources(repoRoot: string, tracked: readonly string[], dir: string, others: readonly string[]): SourceFile[] {\n const files: SourceFile[] = []\n for (const path of tracked) {\n if (!underDir(path, dir) || !SOURCE_EXTENSIONS.test(path) || NOT_SOURCE.test(path)) continue\n // A nested package (a monorepo's other app) is not this app's source.\n if (others.some((other) => other !== dir && other !== '.' && underDir(path, other) && underDir(other, dir))) continue\n const abs = join(repoRoot, path)\n try {\n if (statSync(abs).size > MAX_SOURCE_BYTES) continue\n files.push({ path, text: withoutComments(readFileSync(abs, 'utf8')) })\n } catch {\n /* a tracked file that is gone from the tree is not a source */\n }\n }\n return files\n}\n\nfunction versionTuple(spec: string): [number, number, number] | null {\n const match = /(\\d+)\\.(\\d+)\\.(\\d+)/.exec(spec)\n if (!match || /^(?:workspace|file|link|portal|git|github|http|catalog):/.test(spec)) return null\n return [Number(match[1]), Number(match[2]), Number(match[3])]\n}\n\nfunction atLeast(have: readonly number[], floor: string): boolean {\n const want = versionTuple(floor) as [number, number, number]\n for (let index = 0; index < 3; index += 1) {\n if ((have[index] as number) !== want[index]) return (have[index] as number) > (want[index] as number)\n }\n return true\n}\n\nfunction filesMatching(sources: readonly SourceFile[], pattern: RegExp): SourceFile[] {\n return sources.filter((file) => pattern.test(file.text))\n}\n\n/** The text of a call's argument list from its opening parenthesis, balanced and capped. */\nfunction callArguments(text: string, openIndex: number): string {\n let depth = 0\n for (let index = openIndex; index < Math.min(text.length, openIndex + 1200); index += 1) {\n const char = text[index]\n if (char === '(') depth += 1\n else if (char === ')' && --depth === 0) return text.slice(openIndex, index + 1)\n }\n return text.slice(openIndex, openIndex + 1200)\n}\n\ninterface SinkCall {\n readonly file: string\n readonly args: string\n readonly project: string | null\n}\n\nfunction sinkCalls(sources: readonly SourceFile[]): SinkCall[] {\n const calls: SinkCall[] = []\n for (const file of sources) {\n for (const match of file.text.matchAll(/createIntelligenceTurnTraceSink\\s*\\(/g)) {\n const args = callArguments(file.text, match.index + match[0].length - 1)\n const direct = /\\bproject\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(args)\n const named = /\\bproject\\s*:\\s*([A-Za-z_$][\\w$]*)\\s*[,}\\n]/.exec(args) ?? /\\bproject\\b\\s*[,}]/.exec(args)\n const identifier = named?.[1] ?? (named ? 'project' : undefined)\n const constant = identifier\n ? new RegExp(`(?:const|let)\\\\s+${identifier}\\\\s*(?::\\\\s*string\\\\s*)?=\\\\s*['\"\\`]([^'\"\\`]+)['\"\\`]`).exec(file.text)\n : null\n calls.push({ file: file.path, args, project: direct?.[1] ?? constant?.[1] ?? null })\n }\n }\n return calls\n}\n\nfunction pinRow(pin: string | null, spec: string): DefaultRow {\n const tuple = pin === null ? null : versionTuple(pin)\n if (pin === null || tuple === null) {\n return { id: 'pin', label: 'agent-app pin', status: 'unknown', detail: `\"${spec}\" is not a plain version; the floors cannot be compared` }\n }\n const below = AGENT_APP_OUTCOME_FLOORS.filter((floor) => !atLeast(tuple, floor.since))\n const floors = AGENT_APP_OUTCOME_FLOORS.map((floor) => `${floor.label} ${floor.since}`).join(', ')\n return below.length === 0\n ? { id: 'pin', label: 'agent-app pin', status: 'ok', detail: `${pin} (floors: ${floors})` }\n : { id: 'pin', label: 'agent-app pin', status: 'gap', detail: `${pin} is below the ${below.map((floor) => `${floor.label} floor ${floor.since}`).join(' and the ')}` }\n}\n\nfunction withExemption(\n row: DefaultRow,\n id: ExemptibleDefault,\n exemptions: AppDefaultsExemptions,\n optedOut: string | null,\n): { row: DefaultRow; finding: string | null } {\n const reason = exemptions[id]\n if (optedOut !== null) {\n return reason\n ? { row: { ...row, status: 'exempt', detail: `${optedOut}; exempt: ${reason}` }, finding: null }\n : { row: { ...row, status: 'opted-out', detail: optedOut }, finding: `${row.label}: ${optedOut}, with no reason in signoff.config.mjs agentApp.exemptions.${id}` }\n }\n if (row.status !== 'ok' && row.status !== 'na' && reason) {\n return { row: { ...row, status: 'exempt', detail: `${row.detail}; exempt: ${reason}` }, finding: null }\n }\n return { row, finding: null }\n}\n\nfunction turnTraceRow(sources: readonly SourceFile[], calls: readonly SinkCall[], exports: AppDefaultsOptions['exports']): { row: DefaultRow; optedOut: string | null; wired: boolean } {\n const optOut = filesMatching(sources, /\\bturnTrace\\s*:\\s*false\\b/)[0]\n if (optOut) return { row: { id: 'turn-trace', label: 'turn trace', status: 'gap', detail: '' }, optedOut: `turnTrace: false in ${optOut.path}`, wired: false }\n const customSink = filesMatching(sources, /\\bturnTrace\\s*:\\s*\\{/)\n if (calls.length === 0 && customSink.length === 0) {\n return { row: { id: 'turn-trace', label: 'turn trace', status: 'gap', detail: 'no turn trace sink; createChatTurnRoutes gets no turnTrace' }, optedOut: null, wired: false }\n }\n const project = calls.find((call) => call.project)?.project ?? null\n const last = project === null ? undefined : exports?.get(project)\n const where = calls[0]?.file ?? customSink[0]?.path ?? ''\n const wired = `sink wired in ${where}${project ? ` (${project})` : ''}`\n if (last) {\n return { row: { id: 'turn-trace', label: 'turn trace', status: 'ok', detail: `${wired}; last export accepted ${new Date(last.at).toISOString().slice(0, 16)}Z` }, optedOut: null, wired: true }\n }\n if (last === null) {\n return { row: { id: 'turn-trace', label: 'turn trace', status: 'gap', detail: `${wired}; Intelligence holds no turn from the last 30 days for this key` }, optedOut: null, wired: true }\n }\n const routerKey = calls.find((call) => /\\bapiKey\\s*:[^,}]*\\bTANGLE_API_KEY\\b/.test(call.args))\n if (routerKey) {\n // Legal's Worker TANGLE_API_KEY was refused with HTTP 401 (#468) and Hospitality's is accepted. Only the ingest knows.\n return { row: { id: 'turn-trace', label: 'turn trace', status: 'unknown', detail: `${wired} with TANGLE_API_KEY; the ingest refused it for Legal (#468): run with --probe, or drop apiKey so the sink reads the Sandbox product key` }, optedOut: null, wired: true }\n }\n return { row: { id: 'turn-trace', label: 'turn trace', status: 'ok', detail: `${wired}; last export not checked` }, optedOut: null, wired: true }\n}\n\nfunction firstTextRow(pin: string | null, sources: readonly SourceFile[], traceWired: boolean, calls: readonly SinkCall[], exports: AppDefaultsOptions['exports']): DefaultRow {\n const floor = AGENT_APP_OUTCOME_FLOORS.find((entry) => entry.id === 'first-text')?.since ?? ''\n const tuple = pin === null ? null : versionTuple(pin)\n const marks = filesMatching(sources, /\\.markFirstText\\s*\\(/).length > 0\n const routes = filesMatching(sources, /\\bcreateChatTurnRoutes\\s*[(<]/).length > 0\n if (!traceWired) return { id: 'first-text', label: 'first text', status: 'gap', detail: 'needs the turn trace' }\n if (tuple !== null && !atLeast(tuple, floor)) return { id: 'first-text', label: 'first text', status: 'gap', detail: `agent-app ${pin} does not mark first text; ${floor} does` }\n if (!routes && !marks) return { id: 'first-text', label: 'first text', status: 'gap', detail: 'the turn owner does not call trace.markFirstText() and the app does not use createChatTurnRoutes' }\n const project = calls.find((call) => call.project)?.project ?? null\n const last = project === null ? undefined : exports?.get(project)\n const observed = last?.firstTextMs === undefined ? '' : `; last turn first_text_ms ${Math.round(last.firstTextMs)}`\n if (last && last.firstTextMs === undefined) return { id: 'first-text', label: 'first text', status: 'gap', detail: 'the last exported turn has no tangle.turn.first_text_ms' }\n return { id: 'first-text', label: 'first text', status: 'ok', detail: `${routes ? 'createChatTurnRoutes marks it' : 'the turn owner marks it'}${observed}` }\n}\n\nfunction prewarmRow(sources: readonly SourceFile[]): DefaultRow {\n const usesBox = filesMatching(sources, /@tangle-network\\/agent-app\\/sandbox|\\bensureWorkspaceSandbox\\b/).length > 0\n if (!usesBox) return { id: 'prewarm', label: 'prewarm route', status: 'na', detail: 'the app opens no workspace box' }\n const shared = filesMatching(sources, /\\bcreateWorkspacePrewarmRoute\\b/)[0]\n if (shared) return { id: 'prewarm', label: 'prewarm route', status: 'ok', detail: `shared route in ${shared.path}` }\n const local = sources.find((file) => /prewarm/i.test(file.path) || /['\"`/]prewarm['\"`/]/.test(file.text))\n return local\n ? { id: 'prewarm', label: 'prewarm route', status: 'gap', detail: `local copy in ${local.path}; mount createWorkspacePrewarmRoute` }\n : { id: 'prewarm', label: 'prewarm route', status: 'gap', detail: 'no prewarm route; the first send waits for the box' }\n}\n\nfunction placementRow(configs: readonly SourceFile[]): DefaultRow {\n const pinned = configs.find((file) => /^\\s*\\[placement\\]\\s*$[\\s\\S]{0,300}?^\\s*(?:region|host|hostname)\\s*=/m.test(file.text) || /\"placement\"\\s*:\\s*\\{[^}]*\"(?:region|host|hostname)\"/.test(file.text))\n if (pinned) return { id: 'placement', label: 'placement', status: 'ok', detail: `pinned in ${pinned.path}` }\n if (configs.length === 0) return { id: 'placement', label: 'placement', status: 'na', detail: 'no Wrangler config' }\n const smart = configs.some((file) => /^\\s*\\[placement\\]/m.test(file.text) || /\"placement\"/.test(file.text))\n return {\n id: 'placement',\n label: 'placement',\n status: 'gap',\n detail: smart\n ? 'a [placement] without a region or host is smart placement, which does not pin; unmeasured against the D1 primary'\n : 'no [placement]; unmeasured against the D1 primary. Pin it beside D1 or declare an exemption with the reason',\n }\n}\n\nfunction limitAlarmsRow(sources: readonly SourceFile[]): DefaultRow {\n const wired = filesMatching(sources, /\\bwithD1LimitAlarms\\s*\\(/)\n const copies = filesMatching(sources, /\\bcreateLimitAlarms\\s*\\(/)\n const product = filesMatching(sources, /\\bcreateProductLimitAlarms\\s*\\(/)\n if (wired.length === 0) {\n return {\n id: 'limit-alarms',\n label: 'limit alarms',\n status: 'gap',\n detail: copies.length + product.length > 0\n ? `alarms are built in ${(copies[0] ?? product[0])?.path} but nothing wraps the D1 binding with withD1LimitAlarms in the server`\n : 'no limit alarms',\n }\n }\n if (copies.length > 0) {\n return { id: 'limit-alarms', label: 'limit alarms', status: 'gap', detail: `wired in ${wired[0]?.path}; ${copies[0]?.path} keeps a local copy of the budgets: use createProductLimitAlarms with overrides` }\n }\n return { id: 'limit-alarms', label: 'limit alarms', status: 'ok', detail: `wired in ${wired[0]?.path}` }\n}\n\n/** `Total Upload: 31059.18 KiB / gzip: 9659.00 KiB` from `wrangler deploy --dry-run`. */\nfunction parseWranglerUpload(output: string): { rawKiB: number; gzipKiB: number } | null {\n const clean = output.replace(/\\u001b\\[[0-9;]*m/g, '')\n const match = /Total Upload:\\s*([\\d.]+)\\s*KiB\\s*\\/\\s*gzip:\\s*([\\d.]+)\\s*KiB/.exec(clean)\n return match ? { rawKiB: Number(match[1]), gzipKiB: Number(match[2]) } : null\n}\n\nfunction wranglerBinary(repoRoot: string, dir: string): string | null {\n for (const base of [join(repoRoot, dir), repoRoot]) {\n const bin = join(base, 'node_modules', '.bin', 'wrangler')\n if (existsSync(bin)) return bin\n }\n return null\n}\n\nfunction bundleRow(repoRoot: string, dir: string, configs: readonly SourceFile[], measure: boolean): DefaultRow {\n const label = 'Worker upload'\n if (configs.length === 0) return { id: 'worker-bundle', label, status: 'na', detail: 'no Wrangler config' }\n if (!measure) return { id: 'worker-bundle', label, status: 'unknown', detail: 'not measured' }\n const bin = wranglerBinary(repoRoot, dir)\n if (!bin) return { id: 'worker-bundle', label, status: 'unknown', detail: 'wrangler is not installed; install, build, then measure' }\n const outDir = mkdtempSync(join(tmpdir(), 'agent-app-upload-'))\n try {\n const run = spawnSync(bin, ['deploy', '--dry-run', '--env=', '--outdir', outDir], {\n cwd: join(repoRoot, dir),\n encoding: 'utf8',\n timeout: 5 * 60_000,\n maxBuffer: 20 * 1024 * 1024,\n env: { ...process.env, CI: '1', WRANGLER_SEND_METRICS: 'false', NO_COLOR: '1' },\n })\n const upload = parseWranglerUpload(`${run.stdout}\\n${run.stderr}`)\n if (!upload) {\n const reason = `${run.stderr}${run.stdout}`.split('\\n').map((line) => line.trim()).find((line) => /error|not found|no such/i.test(line)) ?? `wrangler exited ${run.status}`\n return { id: 'worker-bundle', label, status: 'unknown', detail: `unmeasured (build first): ${reason.slice(0, 160)}` }\n }\n const limit = LAUNCH_BUDGETS.workerUploadGzipKiB\n const share = upload.gzipKiB / limit\n return {\n id: 'worker-bundle',\n label,\n status: share >= LAUNCH_BUDGETS.alarmRatio ? 'gap' : 'ok',\n detail: `${Math.round(upload.gzipKiB)} KiB gzip of ${limit} KiB (${Math.round(share * 100)}%); ${Math.round(upload.rawKiB)} KiB raw of ${LAUNCH_BUDGETS.workerUploadRawKiB} KiB`,\n }\n } finally {\n rmSync(outDir, { recursive: true, force: true })\n }\n}\n\nfunction toolCountRow(): DefaultRow {\n return { id: 'tool-count', label: 'tool_count p50', status: 'unknown', detail: 'unmeasured; no ceiling until a measured link to first text exists' }\n}\n\n/** Report each agent app in the checkout against the defaults. Reads only tracked files; measures the Worker upload with the app's own Wrangler. */\nexport function checkAppDefaults(repoRoot: string, options: AppDefaultsOptions = {}): AppDefaultsResult {\n const tracked = trackedFiles(repoRoot)\n const packages = findAppPackages(repoRoot, tracked)\n // A Wrangler config belongs to the deepest package that contains it, so a monorepo's web and server packages\n // each report their own Worker, and a package that deploys none (a workspace root, a client) is not an app.\n const owned = new Map<string, string[]>()\n for (const path of trackedWorkerConfigs(repoRoot)) {\n const owner = packages.filter((pkg) => underDir(path, pkg.dir)).sort((x, y) => y.dir.length - x.dir.length)[0]\n if (owner) owned.set(owner.dir, [...(owned.get(owner.dir) ?? []), path])\n }\n const deployed = packages.filter((pkg) => owned.has(pkg.dir))\n const apps: AppDefaultsReport[] = []\n const findings: string[] = []\n for (const pkg of deployed.length > 0 ? deployed : packages) {\n const sources = readSources(repoRoot, tracked, pkg.dir, packages.map((other) => other.dir))\n const configs = (owned.get(pkg.dir) ?? []).map((path) => ({ path, text: readFileSync(join(repoRoot, path), 'utf8') }))\n const exemptions = options.exemptions ?? {}\n const pin = versionTuple(pkg.spec) ? (/(\\d+\\.\\d+\\.\\d+)/.exec(pkg.spec)?.[1] ?? null) : null\n const calls = sinkCalls(sources)\n const trace = turnTraceRow(sources, calls, options.exports)\n const traceWired = trace.wired\n const reports: { row: DefaultRow; id: ExemptibleDefault | null; optedOut: string | null }[] = [\n { row: pinRow(pin, pkg.spec), id: null, optedOut: null },\n { row: trace.row, id: 'turn-trace', optedOut: trace.optedOut },\n { row: firstTextRow(pin, sources, traceWired, calls, options.exports), id: 'first-text', optedOut: null },\n { row: prewarmRow(sources), id: 'prewarm', optedOut: null },\n { row: placementRow(configs), id: 'placement', optedOut: null },\n { row: toolCountRow(), id: null, optedOut: null },\n { row: limitAlarmsRow(sources), id: 'limit-alarms', optedOut: null },\n { row: bundleRow(repoRoot, pkg.dir, configs, options.measureBundle ?? true), id: null, optedOut: null },\n ]\n const rows: DefaultRow[] = []\n const appFindings: string[] = []\n for (const entry of reports) {\n if (entry.id === null) {\n rows.push(entry.row)\n continue\n }\n const resolved = withExemption(entry.row, entry.id, exemptions, entry.optedOut)\n rows.push(resolved.row)\n if (resolved.finding) appFindings.push(resolved.finding)\n }\n // Turning the trace off turns first text off with it; the one reason, or the one finding, is the trace's.\n const traceResolved = rows.find((row) => row.id === 'turn-trace')\n if (trace.optedOut && traceResolved) {\n const at = rows.findIndex((row) => row.id === 'first-text')\n rows[at] = { id: 'first-text', label: 'first text', status: traceResolved.status, detail: 'the turn trace is turned off' }\n }\n apps.push({ app: pkg.name, dir: pkg.dir, pin, rows, findings: appFindings })\n findings.push(...appFindings.map((finding) => `${pkg.name}: ${finding}`))\n }\n return { apps, findings }\n}\n\nconst STATUS_MARK: Readonly<Record<DefaultStatus, string>> = {\n ok: 'ok ',\n gap: 'GAP ',\n unknown: '? ',\n exempt: 'exempt ',\n 'opted-out': 'FAIL ',\n na: 'n/a ',\n}\n\nexport function formatAppDefaults(result: AppDefaultsResult): string {\n if (result.apps.length === 0) return 'no agent app in this checkout; nothing to report\\n'\n const lines: string[] = []\n for (const app of result.apps) {\n lines.push(`${app.app}${app.dir === '.' ? '' : ` (${app.dir})`}`)\n for (const row of app.rows) lines.push(` ${STATUS_MARK[row.status]}${row.label.padEnd(15)} ${row.detail}`)\n }\n for (const finding of result.findings) lines.push(`FAIL ${finding}`)\n if (result.findings.length > 0) lines.push('Defaults and how to opt out with a reason: https://github.com/tangle-network/agent-app/blob/main/docs/app-defaults.md')\n return `${lines.join('\\n')}\\n`\n}\n\n/** Ask Intelligence for the newest `agent_app.turn` of a project. Needs a key whose tenant owns the project's spans. */\nasync function readLastTurnExport(\n project: string,\n options: { apiKey: string; baseUrl?: string; fetchImpl?: typeof fetch },\n): Promise<LastTurnExport | null> {\n const base = (options.baseUrl ?? 'https://intelligence.tangle.tools').replace(/\\/+$/, '')\n const get = async (path: string): Promise<unknown> => {\n const response = await (options.fetchImpl ?? fetch)(`${base}${path}`, {\n headers: { authorization: `Bearer ${options.apiKey}` },\n signal: AbortSignal.timeout(15_000),\n })\n if (!response.ok) throw new Error(`Intelligence answered HTTP ${response.status} for ${path.split('?')[0]}`)\n return response.json()\n }\n const listing = (await get(`/v1/traces?limit=1&q=agent_app.turn&attr=${encodeURIComponent(`tangle.project:${project}`)}`)) as {\n items?: { traceId: string; startUnixNano: string }[]\n }\n const newest = listing.items?.[0]\n if (!newest) return null\n const spans = (await get(`/v1/traces/${newest.traceId}/spans`)) as {\n items?: { name?: string; attributes?: Record<string, unknown> }[]\n }\n const firstTextMs = Number(spans.items?.find((span) => span.name === 'agent_app.turn')?.attributes?.['tangle.turn.first_text_ms'])\n return {\n at: Number(BigInt(newest.startUnixNano) / 1_000_000n),\n traceId: newest.traceId,\n ...(Number.isFinite(firstTextMs) ? { firstTextMs } : {}),\n }\n}\n\n/**\n * The newest turn Intelligence holds for each project the apps' sinks name, read with one platform key. A project the\n * key's tenant does not own, or one the ingest has never accepted, reads as null; a failed request leaves it out.\n */\nexport async function collectLastExports(repoRoot: string, apiKey: string): Promise<Map<string, LastTurnExport | null>> {\n const tracked = trackedFiles(repoRoot)\n const projects = new Set<string>()\n for (const pkg of findAppPackages(repoRoot, tracked)) {\n for (const call of sinkCalls(readSources(repoRoot, tracked, pkg.dir, []))) if (call.project) projects.add(call.project)\n }\n const exports = new Map<string, LastTurnExport | null>()\n for (const project of projects) {\n try {\n exports.set(project, await readLastTurnExport(project, { apiKey }))\n } catch {\n /* unreachable or refused: the row says the export was not checked */\n }\n }\n return exports\n}\n","import { spawnSync } from 'node:child_process'\nimport { randomUUID } from 'node:crypto'\nimport { existsSync } from 'node:fs'\nimport { availableParallelism, homedir } from 'node:os'\nimport { basename, join, resolve } from 'node:path'\nimport { loadSignoffConfig } from './config'\nimport { activeStoreKeys, openSignoffCacheSession, pruneSignoffCache, withCacheLock,\n type SignoffCacheSession } from './cache'\nimport {\n assertNodeTypesVersion,\n assertNodeVersion,\n resolveNodeRequirement,\n type NodeVersionRequirement,\n} from './node-version'\nimport { runCommand, type CommandResult } from './exec'\nimport { runGraph, validateGraph, type TaskOutcome } from './schedule'\nimport { assertShuffleArgsReachTheRunner, newSeedBase, planAttempts } from './seeds'\nimport { manifestCacheKey, manifestFiles, resolveStore } from './store'\nimport { APP_DEFAULTS_STEP, checkAppDefaults, formatAppDefaults } from './app-defaults'\nimport { checkWorkerDefaults, formatWorkerDefaults, WORKER_DEFAULTS_STEP } from './worker-defaults'\nimport { materializeCleanTree, removeCleanTree, repoRootOf, type CleanTree } from './workspace'\nimport type {\n SignoffAttempt,\n SignoffConfig,\n SignoffEvent,\n SignoffHostFacts,\n SignoffInstallResult,\n SignoffReport,\n SignoffSource,\n SignoffStepResult,\n SignoffStepSpec,\n} from './types'\n\n/**\n * The sign-off run: reproduce a clean CI environment, then go further.\n *\n * Order matters and each stage exists for a failure this fleet actually paid\n * for:\n * 1. a pristine checkout (`workspace.ts`) — no warm `node_modules`, no Vite\n * cache, because that is the entire mechanical difference between \"green\n * locally\" and \"red in CI\";\n * 2. `--frozen-lockfile` into a store keyed on the lockfile (`store.ts`) — the\n * clean install CI does, without paying the download twice;\n * 3. the repo's declared steps (`config.ts`), run as a graph rather than a line\n * (`schedule.ts`), with the suite re-run under randomized file order and\n * recorded seeds (`seeds.ts`) — the part CI does not do at all.\n *\n * Nothing about a failure is inferred. Every step reports its command, exit\n * code, duration, seed and captured output.\n */\n\nexport interface RunSignoffOptions {\n /** Any directory inside the repo. Defaults to the process cwd. */\n readonly repoDir?: string\n readonly configPath?: string\n /** Default `working-tree` — verify what you are about to commit. */\n readonly source?: SignoffSource\n /** Run every step even after one fails. Default false. */\n readonly keepGoing?: boolean\n /** Base seed. Pass a previous run's to reproduce it exactly. */\n readonly seed?: number\n readonly maxParallel?: number\n readonly cacheDir?: string\n /** Override every shuffled step's run count. */\n readonly shuffleRuns?: number\n /** Keep the clean tree for inspection instead of removing it. */\n readonly keepWorkspace?: boolean\n readonly onEvent?: (event: SignoffEvent) => void\n}\n\nconst DEFAULT_CACHE_DIR = join(homedir(), '.cache', 'agent-app-signoff')\n\nfunction hostFacts(treePath: string, requirement: NodeVersionRequirement | null): SignoffHostFacts {\n const pm = spawnSync('pnpm', ['--version'], { cwd: treePath, encoding: 'utf8' })\n return {\n node: process.version,\n nodePinned: requirement?.declared ?? null,\n nodePinSource: requirement?.source ?? null,\n packageManager: pm.status === 0 ? `pnpm ${pm.stdout.trim()}` : 'pnpm (not resolvable)',\n platform: process.platform,\n arch: process.arch,\n cpus: availableParallelism(),\n }\n}\n\n/** Successful steps keep only a tail; a passing 3,000-test run is not evidence. */\nconst SUCCESS_OUTPUT_TAIL = 4_000\n\nfunction toAttempt(result: CommandResult, seed: number | null, ok: boolean): SignoffAttempt {\n return {\n command: result.command,\n seed,\n exitCode: result.exitCode,\n signal: result.signal,\n durationMs: result.durationMs,\n timedOut: result.timedOut,\n output: ok ? result.output.slice(-SUCCESS_OUTPUT_TAIL) : result.output,\n outputTruncated: result.truncated || (ok && result.output.length > SUCCESS_OUTPUT_TAIL),\n }\n}\n\nfunction buildEnv(\n base: Readonly<Record<string, string | undefined>>,\n layers: readonly (Readonly<Record<string, string>> | undefined)[],\n): Record<string, string | undefined> {\n const env: Record<string, string | undefined> = { ...base }\n for (const layer of layers) {\n if (layer) Object.assign(env, layer)\n }\n return env\n}\n\n/** Where the store flag goes: after the subcommand, so `pnpm install X --store-dir Y` stays valid. */\nfunction withStoreDir(command: string, flag: string | null | undefined, storeDir: string): string {\n if (flag === null) return command\n return `${command} ${flag ?? '--store-dir'} ${JSON.stringify(storeDir)}`\n}\n\nexport async function runSignoff(options: RunSignoffOptions = {}): Promise<SignoffReport> {\n const startedAt = new Date()\n const wallStart = Date.now()\n const repoDir = resolve(options.repoDir ?? process.cwd())\n const repoRoot = repoRootOf(repoDir)\n const source = options.source ?? 'working-tree'\n // The config must come from the same selected bytes as the steps. The cache\n // option can be declared in that config, so bootstrap under the explicit\n // option or the default, then move the tree if the selected config says so.\n let cacheDir = resolve(options.cacheDir ?? DEFAULT_CACHE_DIR)\n // The tree lives under the same root as the stores on purpose: pnpm hardlinks\n // from the store into `node_modules`, and a store on another filesystem\n // silently degrades to a full copy.\n const treeName = `${basename(repoRoot)}-${process.pid}-${randomUUID()}`\n const treePath = (): string => join(cacheDir, 'trees', treeName)\n\n let tree: CleanTree | null = null\n const sessions: SignoffCacheSession[] = []\n let session = await openSignoffCacheSession(cacheDir, treePath())\n sessions.push(session)\n cacheDir = session.cacheDir\n const prune = async (root: string, keepPaths: readonly string[] = []): Promise<void> => {\n const result = await pruneSignoffCache(root, { keepPaths })\n if (result.removed.length || result.overBudgetBytes) {\n options.onEvent?.({ kind: 'cache-prune', ...result })\n }\n }\n try {\n await prune(cacheDir)\n tree = materializeCleanTree({ repoDir: repoRoot, dest: treePath(), source })\n let loaded = await loadSignoffConfig({ repoRoot: tree.path, configPath: options.configPath })\n\n cacheDir = resolve(options.cacheDir ?? loaded.config.cacheDir ?? DEFAULT_CACHE_DIR)\n if (tree.path !== treePath() || (loaded.config.carryFiles?.length ?? 0) > 0) {\n if (session.cacheDir !== cacheDir) {\n session = await openSignoffCacheSession(cacheDir, treePath())\n sessions.push(session)\n cacheDir = session.cacheDir\n await prune(cacheDir)\n }\n removeCleanTree(tree)\n tree = materializeCleanTree({ repoDir: repoRoot, dest: treePath(), source, carryFiles: loaded.config.carryFiles })\n // The second load gives the report an origin inside the final selected\n // tree, and keeps config-derived values tied to that same path.\n loaded = await loadSignoffConfig({ repoRoot: tree.path, configPath: options.configPath })\n }\n\n const { config, origin } = loaded\n // Validate after loading from the selected tree, before paying for install.\n validateGraph(config.steps.map((step) => ({ name: step.name, needs: step.needs })))\n assertShuffleArgsReachTheRunner(config.steps)\n const nodeRequirement = resolveNodeRequirement(tree.path, config.nodeVersion)\n assertNodeVersion(nodeRequirement)\n\n options.onEvent?.({ kind: 'tree', path: tree.path, head: tree.head, dirty: tree.dirty })\n\n // Publish the selected key before creating/pruning stores. A concurrent\n // signoff can then prune under the same lock without deleting this install.\n await session.protectStore(manifestCacheKey(tree.path, manifestFiles(tree.path)))\n const store = await withCacheLock(cacheDir, () => resolveStore({ treePath: tree!.path, cacheDir,\n generations: config.storeGenerations, protectedStoreKeys: activeStoreKeys(cacheDir) }))\n options.onEvent?.({ kind: 'store', storeDir: store.storeDir, cacheHit: store.hit, cacheKey: store.cacheKey })\n\n const installSpec = config.install ?? {}\n const installCwd = join(tree.path, installSpec.cwd ?? '.')\n const installCommand = withStoreDir(\n installSpec.run ?? 'pnpm install --frozen-lockfile',\n installSpec.storeDirFlag,\n store.storeDir,\n )\n const storeEnvName = installSpec.storeEnv === null ? null : installSpec.storeEnv ?? 'NPM_CONFIG_STORE_DIR'\n const sharedEnv = buildEnv(process.env, [\n // Parity with CI: a runner that behaves differently under `CI` (vitest's\n // reporter, wrangler's prompts) must behave that way here too.\n { CI: 'true' },\n // A step that reads history (agent-app-rollout-check's base) finds the\n // source checkout here; the clean tree has no .git.\n { SIGNOFF_SOURCE_REPO: repoRoot, SIGNOFF_TREE: tree.path },\n config.env,\n storeEnvName === null ? undefined : { [storeEnvName]: store.storeDir },\n ])\n\n options.onEvent?.({ kind: 'install-start', command: installCommand })\n const installResult = await runCommand({\n command: installCommand,\n cwd: installCwd,\n env: buildEnv(sharedEnv, [installSpec.env]),\n timeoutMs: installSpec.timeoutMs,\n })\n options.onEvent?.({ kind: 'install-end', exitCode: installResult.exitCode, durationMs: installResult.durationMs })\n\n const install: SignoffInstallResult = {\n command: installCommand,\n storeDir: store.storeDir,\n cacheKey: store.cacheKey,\n cacheHit: store.hit,\n keyedOn: store.keyedOn,\n exitCode: installResult.exitCode,\n durationMs: installResult.durationMs,\n output: installResult.exitCode === 0 ? installResult.output.slice(-SUCCESS_OUTPUT_TAIL) : installResult.output,\n outputTruncated: installResult.truncated,\n }\n\n const host = hostFacts(tree.path, nodeRequirement)\n const seedBase = options.seed ?? newSeedBase()\n\n if (installResult.exitCode !== 0) {\n // Every step is unrunnable, and saying so is the honest report. A gate\n // that reports \"0 failures\" because it never ran anything is the failure\n // mode this whole module exists to prevent.\n return finish({\n ok: false,\n startedAt,\n wallStart,\n tree,\n origin,\n host,\n install,\n steps: [...config.steps.map((step) => step.name), WORKER_DEFAULTS_STEP, APP_DEFAULTS_STEP].map(\n (name): SignoffStepResult => ({\n name,\n status: 'skipped',\n attempts: [],\n durationMs: 0,\n startedAtMs: null,\n finishedAtMs: null,\n }),\n ),\n seedBase,\n keepGoing: options.keepGoing ?? false,\n workspaceRetained: options.keepWorkspace ?? false,\n source,\n options,\n })\n }\n\n assertNodeTypesVersion(tree.path, nodeRequirement)\n\n const workerDefaults = runWorkerDefaults(tree.path, config.workerConfigs, options)\n\n const treeRoot = tree.path\n const outcomes = await runGraph<SignoffStepSpec, readonly SignoffAttempt[]>({\n nodes: config.steps,\n maxParallel: options.maxParallel ?? config.maxParallel ?? availableParallelism(),\n keepGoing: options.keepGoing ?? false,\n run: async (step, signal) => {\n const attempts: SignoffAttempt[] = []\n for (const plan of planAttempts(step, seedBase, options.shuffleRuns)) {\n options.onEvent?.({ kind: 'step-start', name: step.name, command: plan.command, seed: plan.seed })\n const result = await runCommand({\n command: plan.command,\n cwd: join(treeRoot, step.cwd ?? '.'),\n env: buildEnv(sharedEnv, [step.env]),\n timeoutMs: step.timeoutMs,\n signal,\n })\n const ok = result.exitCode === 0\n attempts.push(toAttempt(result, plan.seed, ok))\n // Stop at the first failing order: the remaining seeds would report\n // the same defect, and the seed that found it is already recorded.\n if (!ok) {\n emitStepEnd(options, step.name, 'failed', attempts)\n return { ok: false, value: attempts }\n }\n }\n emitStepEnd(options, step.name, 'passed', attempts)\n return { ok: true, value: attempts }\n },\n })\n\n // After the graph, so the build the app's steps made is there to measure the Worker upload from.\n const appDefaults = runAppDefaults(tree.path, config, options)\n const steps = [...outcomes.map(toStepResult), workerDefaults, appDefaults]\n return finish({\n ok: steps.every((step) => step.status === 'passed'),\n startedAt,\n wallStart,\n tree,\n origin,\n host,\n install,\n steps,\n seedBase,\n keepGoing: options.keepGoing ?? false,\n workspaceRetained: options.keepWorkspace ?? false,\n source,\n options,\n })\n } finally {\n try {\n if (tree && !options.keepWorkspace && existsSync(tree.path)) removeCleanTree(tree)\n } finally {\n for (const active of sessions) {\n await active.close()\n await prune(active.cacheDir, options.keepWorkspace && tree ? [tree.path] : [])\n }\n }\n }\n}\n\n/**\n * Built in rather than declared: every repo that deploys an agent-app Worker\n * must ship the shared Cloudflare defaults, and a step a repo can leave out of\n * its config would let exactly the drift it exists to catch through. It runs\n * after install because it reads each config through the repo's own Wrangler.\n */\nfunction runWorkerDefaults(\n treeRoot: string,\n workerConfigs: readonly string[] | undefined,\n options: RunSignoffOptions,\n): SignoffStepResult {\n const command = `agent-app-signoff ${WORKER_DEFAULTS_STEP}`\n options.onEvent?.({ kind: 'step-start', name: WORKER_DEFAULTS_STEP, command, seed: null })\n const started = Date.now()\n let output: string\n let ok: boolean\n try {\n const result = checkWorkerDefaults(treeRoot, workerConfigs)\n output = formatWorkerDefaults(result)\n ok = result.findings.length === 0\n } catch (error) {\n output = `${error instanceof Error ? error.stack ?? error.message : String(error)}\\n`\n ok = false\n }\n const durationMs = Date.now() - started\n const attempts: SignoffAttempt[] = [\n { command, seed: null, exitCode: ok ? 0 : 1, signal: null, durationMs, timedOut: false, output, outputTruncated: false },\n ]\n emitStepEnd(options, WORKER_DEFAULTS_STEP, ok ? 'passed' : 'failed', attempts)\n // It runs before the graph's clock starts, so it has no position on the\n // graph timeline; giving it one would count it as overlapping the roots.\n return { name: WORKER_DEFAULTS_STEP, status: ok ? 'passed' : 'failed', attempts, durationMs, startedAtMs: null, finishedAtMs: null }\n}\n\n/**\n * Built in beside `worker defaults`: a report of which agent-app defaults the app has (app-defaults.ts). It fails only\n * on an opt-out that gives no reason, so it can run in every app's gate without blocking one over a gap it can see.\n */\nfunction runAppDefaults(treeRoot: string, config: SignoffConfig, options: RunSignoffOptions): SignoffStepResult {\n const command = `agent-app-signoff ${APP_DEFAULTS_STEP}`\n options.onEvent?.({ kind: 'step-start', name: APP_DEFAULTS_STEP, command, seed: null })\n const started = Date.now()\n let output: string\n let ok: boolean\n try {\n const result = checkAppDefaults(treeRoot, { exemptions: config.agentApp?.exemptions })\n output = formatAppDefaults(result)\n ok = result.findings.length === 0\n } catch (error) {\n output = `${error instanceof Error ? error.stack ?? error.message : String(error)}\\n`\n ok = false\n }\n const durationMs = Date.now() - started\n const attempts: SignoffAttempt[] = [\n { command, seed: null, exitCode: ok ? 0 : 1, signal: null, durationMs, timedOut: false, output, outputTruncated: false },\n ]\n emitStepEnd(options, APP_DEFAULTS_STEP, ok ? 'passed' : 'failed', attempts)\n return { name: APP_DEFAULTS_STEP, status: ok ? 'passed' : 'failed', attempts, durationMs, startedAtMs: null, finishedAtMs: null }\n}\n\n/** Emitted from inside the step, so a watching CLI sees a completion when it\n * happens rather than every completion at the end of the run. */\nfunction emitStepEnd(\n options: RunSignoffOptions,\n name: string,\n status: SignoffStepResult['status'],\n attempts: readonly SignoffAttempt[],\n): void {\n options.onEvent?.({\n kind: 'step-end',\n name,\n status,\n durationMs: attempts.reduce((total, attempt) => total + attempt.durationMs, 0),\n })\n}\n\nfunction toStepResult(outcome: TaskOutcome<readonly SignoffAttempt[]>): SignoffStepResult {\n const attempts = outcome.value ?? []\n const durationMs = attempts.reduce((total, attempt) => total + attempt.durationMs, 0)\n return {\n name: outcome.name,\n status: outcome.status,\n attempts,\n durationMs,\n startedAtMs: outcome.startedAtMs,\n finishedAtMs: outcome.finishedAtMs,\n }\n}\n\ninterface FinishInput {\n readonly ok: boolean\n readonly startedAt: Date\n readonly wallStart: number\n readonly tree: CleanTree\n readonly origin: SignoffReport['configOrigin']\n readonly host: SignoffHostFacts\n readonly install: SignoffInstallResult\n readonly steps: readonly SignoffStepResult[]\n readonly seedBase: number\n readonly keepGoing: boolean\n readonly workspaceRetained: boolean\n readonly source: SignoffSource\n readonly options: RunSignoffOptions\n}\n\nfunction finish(input: FinishInput): SignoffReport {\n const serialMs = input.install.durationMs + input.steps.reduce((total, step) => total + step.durationMs, 0)\n const flags = [\n `--source ${input.source}`,\n `--seed ${input.seedBase}`,\n ...(input.keepGoing ? ['--keep-going'] : []),\n ]\n return {\n ok: input.ok,\n startedAt: input.startedAt.toISOString(),\n repo: {\n root: input.tree.root,\n head: input.tree.head,\n branch: input.tree.branch,\n source: input.source,\n dirty: input.tree.dirty,\n diffSha256: input.tree.diffSha256,\n untrackedFiles: input.tree.untrackedFiles,\n carriedFiles: input.tree.carriedFiles,\n },\n configOrigin: input.origin,\n workspace: input.tree.path,\n workspaceRetained: input.workspaceRetained,\n host: input.host,\n install: input.install,\n steps: input.steps,\n seedBase: input.seedBase,\n wallClockMs: Date.now() - input.wallStart,\n serialMs,\n keepGoing: input.keepGoing,\n reproduce: `agent-app-signoff ${input.tree.root} ${flags.join(' ')}`,\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport { spawnSync } from 'node:child_process'\nimport {\n existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync,\n readlinkSync, realpathSync, statSync, unlinkSync, writeFileSync,\n} from 'node:fs'\nimport type { Stats } from 'node:fs'\nimport { hostname } from 'node:os'\nimport { basename, join, relative, resolve, sep } from 'node:path'\nimport lockfile from 'proper-lockfile'\n\n/** Defaults owned by signoff; callers can override only when explicitly testing. */\nexport const SIGNOFF_CACHE_MAX_AGE_MS = 3 * 24 * 60 * 60 * 1_000\nexport const SIGNOFF_CACHE_MAX_BYTES = 4 * 1024 ** 3\n\ninterface ActiveRun {\n readonly pid: number\n readonly host: string\n readonly processStart: string | null\n readonly tree: string\n readonly storeKey: string | null\n}\n\nexport interface CachePruneResult {\n readonly beforeBytes: number\n readonly afterBytes: number\n readonly removed: readonly string[]\n /** Active or explicitly kept entries can temporarily hold the cache above its idle cap. */\n readonly overBudgetBytes: number\n}\n\nexport interface CachePruneOptions {\n readonly nowMs?: number\n readonly maxAgeMs?: number\n readonly maxBytes?: number\n readonly keepPaths?: readonly string[]\n}\n\ninterface CacheEntry {\n readonly path: string\n readonly kind: 'tree' | 'store'\n readonly mtimeMs: number\n readonly protected: boolean\n readonly inodes: Set<string>\n}\n\nfunction processStart(pid: number): string | null {\n try {\n // Linux field 22 is starttime; unlike a PID, it cannot be recycled while\n // this boot is running. Other hosts still use the conservative PID check.\n const stat = readFileSync(`/proc/${pid}/stat`, 'utf8')\n return stat.slice(stat.lastIndexOf(')') + 2).split(' ')[19] ?? null\n } catch { return null }\n}\n\n/** Detached install/check processes can outlive the signoff coordinator. */\nfunction hasRunProcesses(run: ActiveRun): boolean {\n if (process.platform !== 'linux') return true // cannot prove the run has stopped\n try {\n for (const entry of readdirSync('/proc')) {\n if (!/^\\d+$/.test(entry)) continue\n const proc = join('/proc', entry)\n try {\n // A pre-existing service cannot be a detached child of this run. Its\n // protected /proc files must not keep every crashed lease forever.\n const start = processStart(Number(entry))\n if (run.processStart && start && BigInt(start) < BigInt(run.processStart)) continue\n const cwd = readlinkSync(join(proc, 'cwd'))\n if (cwd === run.tree || cwd.startsWith(run.tree + sep)) return true\n const env = readFileSync(join(proc, 'environ'), 'utf8').split('\\0')\n if (env.includes(`SIGNOFF_TREE=${run.tree}`)) return true\n } catch (error) {\n if (['ENOENT', 'ESRCH'].includes((error as NodeJS.ErrnoException).code ?? '')) continue\n return true // unreadable process state is not evidence that it stopped\n }\n }\n return false\n } catch { return true }\n}\n\nfunction alive(run: ActiveRun): boolean {\n if (run.host !== hostname()) return true // a configured shared cache may have another host's run\n try { process.kill(run.pid, 0) } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ESRCH') return hasRunProcesses(run)\n return true // EPERM is not proof of a dead process\n }\n const currentStart = processStart(run.pid)\n return !run.processStart || !currentStart || currentStart === run.processStart || hasRunProcesses(run)\n}\n\nfunction cacheRoot(cacheDir: string): string {\n mkdirSync(cacheDir, { recursive: true })\n return realpathSync(cacheDir)\n}\n\n/** One short cross-process lock protects lease transitions and deletion decisions. */\nexport async function withCacheLock<T>(cacheDir: string, action: () => T | Promise<T>): Promise<T> {\n const release = await lockfile.lock(cacheRoot(cacheDir), {\n realpath: false,\n stale: 300_000,\n update: 30_000,\n retries: { retries: 100, factor: 1, minTimeout: 100, maxTimeout: 100 },\n })\n try { return await action() } finally { await release() }\n}\n\nfunction markerDir(cacheDir: string): string { return join(cacheDir, 'active') }\n\nfunction writeMarker(path: string, run: ActiveRun): void {\n const temp = `${path}.${randomUUID()}.tmp`\n writeFileSync(temp, `${JSON.stringify(run)}\\n`, { flag: 'wx' })\n renameSync(temp, path)\n}\n\n/** Called only while holding the cache lock. Invalid markers fail closed. */\nfunction protectedPaths(cacheDir: string): { paths: Set<string>; unknown: boolean } {\n const paths = new Set<string>()\n const root = markerDir(cacheDir)\n if (!existsSync(root)) return { paths, unknown: false }\n let unknown = false\n for (const entry of readdirSync(root)) {\n if (!entry.endsWith('.json')) continue\n const file = join(root, entry)\n let run: ActiveRun\n try {\n run = JSON.parse(readFileSync(file, 'utf8')) as ActiveRun\n if (!Number.isSafeInteger(run.pid) || run.pid <= 0 || typeof run.host !== 'string' ||\n typeof run.tree !== 'string' || !run.tree.startsWith(resolve(cacheDir) + sep) ||\n (run.processStart !== null && (typeof run.processStart !== 'string' || !/^\\d+$/.test(run.processStart))) ||\n (run.storeKey !== null && (typeof run.storeKey !== 'string' || !/^[a-f0-9]{64}$/.test(run.storeKey)))) {\n unknown = true\n continue\n }\n } catch { unknown = true; continue }\n if (!alive(run)) { unlinkSync(file); continue }\n const tree = resolve(run.tree)\n if (tree.startsWith(resolve(cacheDir) + sep)) paths.add(tree)\n if (run.storeKey && /^[a-f0-9]{64}$/.test(run.storeKey)) {\n paths.add(join(cacheDir, 'stores', run.storeKey))\n }\n }\n return { paths, unknown }\n}\n\n/** Old signoff processes have no lease marker. Their PID-named trees still\n * protect both themselves and stores until those processes exit. */\nfunction protectLegacyRuns(cacheDir: string, active: { paths: Set<string>; unknown: boolean }): void {\n const trees = join(cacheDir, 'trees')\n if (!existsSync(trees)) return\n for (const entry of readdirSync(trees, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue\n const tree = join(trees, entry.name)\n if (active.paths.has(tree) || !existsSync(join(tree, '.git'))) continue\n const match = /-(\\d+)$/.exec(entry.name)\n if (!match) continue\n const pid = Number(match[1])\n if (alive({ pid, host: hostname(), processStart: null, tree, storeKey: null })) {\n active.paths.add(tree)\n active.unknown = true // a pre-lease run did not record which store it uses\n }\n }\n}\n\nexport interface SignoffCacheSession {\n readonly cacheDir: string\n protectStore(cacheKey: string): Promise<void>\n close(): Promise<void>\n}\n\n/** Register before creating the tree, so a concurrent prune cannot select it. */\nexport async function openSignoffCacheSession(cacheDir: string, tree: string): Promise<SignoffCacheSession> {\n const root = cacheRoot(cacheDir)\n const treePath = resolve(root, relative(resolve(cacheDir), resolve(tree)))\n const file = join(markerDir(root), `${process.pid}-${randomUUID()}.json`)\n let run: ActiveRun = { pid: process.pid, host: hostname(), processStart: processStart(process.pid),\n tree: treePath, storeKey: null }\n await withCacheLock(root, () => {\n mkdirSync(markerDir(root), { recursive: true })\n writeMarker(file, run)\n })\n return {\n cacheDir: root,\n protectStore: async (cacheKey) => {\n if (!/^[a-f0-9]{64}$/.test(cacheKey)) throw new Error('signoff: invalid store cache key')\n await withCacheLock(root, () => {\n run = { ...run, storeKey: cacheKey }\n writeMarker(file, run)\n })\n },\n close: async () => {\n await withCacheLock(root, () => { if (existsSync(file)) unlinkSync(file) })\n },\n }\n}\n\n/** Active store keys for resolveStore's existing generation cap. Hold the lock. */\nexport function activeStoreKeys(cacheDir: string): Set<string> {\n cacheDir = cacheRoot(cacheDir)\n const active = protectedPaths(cacheDir)\n protectLegacyRuns(cacheDir, active)\n const { paths, unknown } = active\n if (unknown && existsSync(join(cacheDir, 'stores'))) return new Set(readdirSync(join(cacheDir, 'stores'), { withFileTypes: true })\n .filter((entry) => entry.isDirectory()).map((entry) => entry.name))\n return new Set([...paths].filter((path) => path.startsWith(join(cacheDir, 'stores') + sep)).map((path) => basename(path)))\n}\n\nfunction allocatedBytes(stat: Stats): number {\n return process.platform === 'win32' ? stat.size : stat.blocks * 512\n}\n\nfunction collectInodes(path: string, keys: Set<string>, sizes: Map<string, number>): void {\n let stat: Stats\n try { stat = lstatSync(path) } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n throw error\n }\n const key = `${stat.dev}:${stat.ino}`\n keys.add(key)\n sizes.set(key, allocatedBytes(stat))\n if (!stat.isDirectory() || stat.isSymbolicLink()) return\n let children: string[]\n try { children = readdirSync(path) } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n throw error\n }\n for (const child of children) collectInodes(join(path, child), keys, sizes)\n}\n\nfunction entries(cacheDir: string, protectedSet: Set<string>, unknown: boolean): CacheEntry[] {\n const found: CacheEntry[] = []\n for (const [kind, child] of [['tree', 'trees'], ['store', 'stores']] as const) {\n const root = join(cacheDir, child)\n if (!existsSync(root)) continue\n for (const entry of readdirSync(root, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue // never follow a symlink out of this cache\n const path = join(root, entry.name)\n const recognized = kind === 'store' ? /^[a-f0-9]{64}$/.test(entry.name)\n : existsSync(join(path, '.git'))\n let mtimeMs: number\n try { mtimeMs = statSync(path).mtimeMs } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue\n throw error\n }\n found.push({ path, kind, mtimeMs,\n protected: unknown || protectedSet.has(path) || !recognized, inodes: new Set() })\n }\n }\n return found\n}\n\nfunction removeEntry(entry: CacheEntry): void {\n if (entry.kind === 'store') { rmSync(entry.path, { recursive: true, force: true }); return }\n // Trees are registered Git worktrees, not ordinary scratch directories.\n const git = spawnSync('git', ['-C', entry.path, 'worktree', 'remove', '--force', entry.path], { encoding: 'utf8' })\n if (git.status !== 0) throw new Error(`signoff: cannot retire cached worktree ${entry.path}: ${git.stderr.trim()}`)\n}\n\n/** Bound idle trees and stores by age first, then allocated physical bytes. */\nexport async function pruneSignoffCache(cacheDir: string, options: CachePruneOptions = {}): Promise<CachePruneResult> {\n const root = cacheRoot(cacheDir)\n const nowMs = options.nowMs ?? Date.now()\n const maxAgeMs = options.maxAgeMs ?? SIGNOFF_CACHE_MAX_AGE_MS\n const maxBytes = options.maxBytes ?? SIGNOFF_CACHE_MAX_BYTES\n if (!Number.isFinite(maxAgeMs) || maxAgeMs < 0 || !Number.isFinite(maxBytes) || maxBytes < 0) {\n throw new Error('signoff: cache limits must be non-negative finite numbers')\n }\n return withCacheLock(root, () => {\n const active = protectedPaths(root)\n protectLegacyRuns(root, active)\n for (const path of options.keepPaths ?? []) active.paths.add(resolve(path))\n const candidates = entries(root, active.paths, active.unknown)\n const sizes = new Map<string, number>()\n const references = new Map<string, number>()\n for (const entry of candidates) {\n collectInodes(entry.path, entry.inodes, sizes)\n for (const key of entry.inodes) references.set(key, (references.get(key) ?? 0) + 1)\n }\n let bytes = [...sizes.values()].reduce((sum, size) => sum + size, 0)\n const beforeBytes = bytes\n const selected: CacheEntry[] = []\n const select = (entry: CacheEntry): void => {\n selected.push(entry)\n for (const key of entry.inodes) {\n const remaining = (references.get(key) ?? 1) - 1\n references.set(key, remaining)\n if (remaining === 0) bytes -= sizes.get(key) ?? 0\n }\n }\n const eligible = candidates.filter((entry) => !entry.protected).sort((a, b) => a.mtimeMs - b.mtimeMs)\n for (const entry of eligible) {\n if (nowMs - entry.mtimeMs >= maxAgeMs) select(entry)\n }\n for (const entry of eligible) {\n if (bytes <= maxBytes) break\n if (!selected.includes(entry)) select(entry)\n }\n for (const entry of selected) removeEntry(entry)\n return { beforeBytes, afterBytes: bytes, removed: selected.map((entry) => entry.path),\n overBudgetBytes: Math.max(0, bytes - maxBytes) }\n })\n}\n","import { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { resolveWorkflowNodePin } from './workflow-pin'\n\n/**\n * Refuse to sign off on a runtime the product does not ship.\n *\n * CI pins its Node version (`actions/setup-node` with `node-version: 22` in all\n * three fleet workflows). A developer's shell does not — this host runs 24. A\n * local gate that inherits whatever is on `PATH` therefore verifies a runtime\n * nobody deploys, and reports it as the runtime that ships. That is the same\n * failure shape as a number measured in a narrower context than it is\n * presented in, and it is not acceptable in the thing that replaces the merge\n * gate.\n *\n * So the pin is read from the repo and enforced, or it is absent and the report\n * says so. Three sources, in order:\n *\n * - `signoff.config.mjs`'s `nodeVersion` — the explicit declaration.\n * - `.nvmrc` — the pin a repo already keeps for humans.\n * - the `pull_request` workflows' `node-version` (`./workflow-pin`) — the pin\n * CI itself runs on.\n *\n * **The third source was added because the first two were empty on the entire\n * fleet, and that produced a false PASS.** legal-agent `4c0d688` failed CI on\n * `Cannot bundle Node.js built-in \"node:sqlite\"` and this gate signed it off.\n * Reproduced in one installed tree, same bytes: Node 22 fails both files, Node\n * 24 passes both, every time. No `.nvmrc` exists in tax-agent, legal-agent or\n * agent-app; all three pin `node-version: 22` in the workflow being replaced.\n * A gate that replaces a workflow has to read the runtime that workflow pins.\n *\n * A `.nvmrc` and a workflow that disagree is not resolved by preference — it is\n * a refusal, because it means the local gate and CI verify different runtimes,\n * which is the exact defect this module exists to prevent.\n *\n * **`engines.node` is deliberately NOT read.** It is a floor (`\">=18\"`), not a\n * pin, so treating it as one manufactures refusals on every version above the\n * floor — and an unsatisfiable gate does not stop bad work, it gets waived.\n */\n\nexport interface NodeVersionRequirement {\n /** The declared major, e.g. `22`. */\n readonly major: number\n readonly declared: string\n /** Where it came from, for the proof. */\n readonly source: string\n}\n\n/** Leading major from a pin like `22`, `v22.22.3`, `22.22`, `lts/iron` (none). */\nfunction majorOf(raw: string): number | null {\n const match = /^v?(\\d+)(?:\\.|$)/.exec(raw.trim())\n return match?.[1] === undefined ? null : Number.parseInt(match[1], 10)\n}\n\nexport function resolveNodeRequirement(\n repoRoot: string,\n configured?: string,\n): NodeVersionRequirement | null {\n if (configured !== undefined) {\n const major = majorOf(configured)\n if (major === null) {\n throw new Error(\n `signoff: nodeVersion \"${configured}\" does not start with a major version. ` +\n 'Declare a pin like \"22\" or \"22.22.3\".',\n )\n }\n return { major, declared: configured.trim(), source: 'signoff config `nodeVersion`' }\n }\n\n let fromNvmrc: NodeVersionRequirement | null = null\n const nvmrc = join(repoRoot, '.nvmrc')\n if (existsSync(nvmrc)) {\n const raw = readFileSync(nvmrc, 'utf8').trim()\n const major = majorOf(raw)\n // An alias (`lts/iron`) is a pin this module cannot resolve without a\n // network call, so it is reported as no requirement rather than guessed.\n if (major !== null) fromNvmrc = { major, declared: raw, source: '.nvmrc' }\n }\n\n const fromWorkflow = resolveWorkflowNodePin(repoRoot, majorOf)\n if (fromNvmrc && fromWorkflow && fromNvmrc.major !== fromWorkflow.major) {\n throw new Error(\n `signoff: .nvmrc pins Node ${fromNvmrc.declared} and ${fromWorkflow.source} pins ` +\n `${fromWorkflow.declared}. A sign-off that replaces CI cannot verify two runtimes, and picking ` +\n 'one silently would sign off a runtime the other half of the repo says is wrong. Make them agree, ' +\n 'or declare `nodeVersion` in the signoff config.',\n )\n }\n if (fromNvmrc) return fromNvmrc\n if (fromWorkflow) return { ...fromWorkflow, source: fromWorkflow.source }\n return null\n}\n\n/**\n * Throw when the running Node cannot stand in for the declared one.\n *\n * Major-only: a patch difference is not a different runtime, and demanding an\n * exact patch would refuse every host that has not just re-installed.\n */\nexport function assertNodeVersion(requirement: NodeVersionRequirement | null, running = process.version): void {\n if (!requirement) return\n const runningMajor = majorOf(running)\n if (runningMajor === requirement.major) return\n throw new Error(\n `signoff: this repo pins Node ${requirement.declared} (${requirement.source}) and you are running ${running}. ` +\n 'A sign-off that replaces CI has to verify the runtime the product ships, so this refuses rather than ' +\n `reporting a pass it did not earn. Switch with \\`nvm use ${requirement.major}\\`, or change the pin if the ` +\n 'product really has moved.',\n )\n}\n\n/** Refuse Node declaration files for a different runtime major. */\nexport function assertNodeTypesVersion(\n repoRoot: string,\n requirement: NodeVersionRequirement | null,\n): void {\n if (!requirement) return\n const packagePath = join(repoRoot, 'package.json')\n if (!existsSync(packagePath)) return\n const manifest = JSON.parse(readFileSync(packagePath, 'utf8')) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n optionalDependencies?: Record<string, string>\n }\n const declared = manifest.devDependencies?.['@types/node']\n ?? manifest.dependencies?.['@types/node']\n ?? manifest.optionalDependencies?.['@types/node']\n if (!declared) return\n\n const declaredMajor = /^[~^]?v?(\\d+)(?:\\.|$)/.exec(declared.trim())?.[1]\n if (declaredMajor !== undefined && Number.parseInt(declaredMajor, 10) !== requirement.major) {\n throw new Error(\n `signoff: this repo pins Node ${requirement.declared} but declares @types/node ${declared}. `\n + `Use the latest @types/node ${requirement.major}.x release.`,\n )\n }\n\n const installedPath = join(repoRoot, 'node_modules', '@types', 'node', 'package.json')\n if (!existsSync(installedPath)) {\n throw new Error(`signoff: @types/node is declared but missing after install in ${repoRoot}.`)\n }\n const installed = JSON.parse(readFileSync(installedPath, 'utf8')) as { version?: string }\n const installedMajor = majorOf(installed.version ?? '')\n if (installedMajor !== requirement.major) {\n throw new Error(\n `signoff: this repo pins Node ${requirement.declared} but installed @types/node@${installed.version ?? 'unknown'}. `\n + `Use the latest @types/node ${requirement.major}.x release.`,\n )\n }\n}\n","import { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\n/**\n * Read the Node pin out of the workflows that gate a merge.\n *\n * This exists because of a measured false PASS. legal-agent `4c0d688` was red\n * in CI on two test files — `Cannot bundle Node.js built-in \"node:sqlite\"` —\n * and the sign-off gate signed it off. Same bytes, same lockfile, same\n * hermetic tree: on Node 22 both files fail, on Node 24 both pass, 100% of the\n * time. The runtime was the whole difference, and the gate never saw it because\n * it looked for a pin in exactly two places the fleet does not keep one.\n *\n * At measurement time, none of tax-agent, legal-agent, or agent-app had an\n * `.nvmrc`.\n * All three pinned Node 22 in the merge workflow.\n * Agent App now pins Node 24.18.0 in `.nvmrc`.\n *\n * The workflow fallback reads only `pull_request` checks because those checks\n * can block a merge.\n * Agent App uses `.nvmrc` instead of this fallback.\n * Its publish workflow uses Node 24.18.0 for source checks and npm, with a\n * separate clean-runner Node 22 compatibility job.\n *\n * Nothing here guesses. An expression (`${{ matrix.node }}`) is not a version,\n * a `node-version-file` that does not exist is not a pin, and two merge-gate\n * workflows on different majors is a question this module cannot answer.\n * Each one refuses and names the config key that settles it.\n */\n\nexport interface WorkflowNodePin {\n /** Repo-relative workflow path, for the proof. */\n readonly file: string\n /** The version as written: `22`, `24.18.0`, `v20`. */\n readonly value: string\n /** `node-version`, or the `node-version-file` path it was read through. */\n readonly via: string\n}\n\nconst WORKFLOW_DIR = join('.github', 'workflows')\n\n/** Everything after an unquoted ` #`, plus surrounding quotes, is not the value. */\nfunction scalarValue(raw: string): string {\n const withoutComment = raw.replace(/\\s+#.*$/, '').trim()\n const quoted = /^(['\"])(.*)\\1$/.exec(withoutComment)\n return (quoted?.[2] ?? withoutComment).trim()\n}\n\nfunction indentOf(line: string): number {\n return line.length - line.trimStart().length\n}\n\nfunction isBlank(line: string): boolean {\n const trimmed = line.trim()\n return trimmed.length === 0 || trimmed.startsWith('#')\n}\n\n/**\n * Does this workflow run on `pull_request`?\n *\n * Both spellings the fleet uses are handled: the block form every workflow here\n * writes, and the inline form (`on: [push, pull_request]`). `on` is quoted in\n * some repos because YAML 1.1 reads a bare `on` as the boolean true, so the\n * quoted keys are matched too.\n */\nexport function triggersOnPullRequest(source: string): boolean {\n const lines = source.split('\\n')\n for (let index = 0; index < lines.length; index += 1) {\n const line = lines[index] as string\n const header = /^(?:on|\"on\"|'on')\\s*:(.*)$/.exec(line)\n if (!header) continue\n\n const inline = scalarValue(header[1] ?? '')\n if (inline.length > 0) {\n return inline\n .replace(/^\\[|\\]$/g, '')\n .split(',')\n .map((token) => token.trim())\n .includes('pull_request')\n }\n\n // Block form: the trigger names sit at the first nesting level under `on:`.\n // Anything deeper belongs to a trigger's own options (`branches`, `paths`).\n let nesting: number | null = null\n for (let cursor = index + 1; cursor < lines.length; cursor += 1) {\n const body = lines[cursor] as string\n if (isBlank(body)) continue\n const bodyIndent = indentOf(body)\n if (bodyIndent === 0) break\n if (nesting === null) nesting = bodyIndent\n if (bodyIndent !== nesting) continue\n const key = /^\\s*(?:-\\s*)?([A-Za-z_][\\w-]*)\\s*:?\\s*$/.exec(body)\n if (key?.[1] === 'pull_request') return true\n }\n return false\n }\n return false\n}\n\n/** Every Node pin an `actions/setup-node` step declares in one workflow. */\nfunction pinsInWorkflow(repoRoot: string, file: string, source: string): WorkflowNodePin[] {\n const pins: WorkflowNodePin[] = []\n for (const line of source.split('\\n')) {\n const match = /^\\s*(node-version|node-version-file)\\s*:\\s*(\\S.*)$/.exec(line)\n if (!match) continue\n const key = match[1] as string\n const value = scalarValue(match[2] as string)\n // A matrix expression is several runtimes, not one. Refusing to guess is\n // the point; `resolveWorkflowNodePin` turns an all-expression repo into a\n // named refusal rather than a silent \"unpinned\".\n if (value.includes('${{')) continue\n\n if (key === 'node-version') {\n pins.push({ file, value, via: 'node-version' })\n continue\n }\n\n const target = join(repoRoot, value)\n if (!existsSync(target)) {\n throw new Error(\n `signoff: ${file} reads its Node pin from \"${value}\" (node-version-file) and that file does not exist. ` +\n 'The workflow this gate replaces cannot itself run, so there is nothing to verify against.',\n )\n }\n const declared = readFileSync(target, 'utf8')\n .split('\\n')\n .map((entry) => entry.trim())\n .find((entry) => entry.length > 0 && !entry.startsWith('#'))\n if (declared !== undefined) pins.push({ file, value: declared, via: `node-version-file ${value}` })\n }\n return pins\n}\n\n/** Node pins declared by every workflow that gates a merge, in filename order. */\nexport function scanMergeGateNodePins(repoRoot: string): WorkflowNodePin[] {\n const dir = join(repoRoot, WORKFLOW_DIR)\n if (!existsSync(dir)) return []\n\n const pins: WorkflowNodePin[] = []\n const files = readdirSync(dir)\n .filter((name) => name.endsWith('.yml') || name.endsWith('.yaml'))\n .sort()\n for (const name of files) {\n const source = readFileSync(join(dir, name), 'utf8')\n if (!triggersOnPullRequest(source)) continue\n pins.push(...pinsInWorkflow(repoRoot, `${WORKFLOW_DIR}/${name}`, source))\n }\n return pins\n}\n\nexport interface ResolvedWorkflowPin {\n readonly major: number\n readonly declared: string\n readonly source: string\n}\n\n/**\n * One Node major for the whole merge gate, or a refusal that names why not.\n *\n * `majorOf` is injected rather than imported to keep the direction of the\n * dependency one-way: `node-version.ts` owns what a version string means, this\n * module owns where the string lives.\n */\nexport function resolveWorkflowNodePin(\n repoRoot: string,\n majorOf: (raw: string) => number | null,\n): ResolvedWorkflowPin | null {\n const pins = scanMergeGateNodePins(repoRoot)\n if (pins.length === 0) return null\n\n const byMajor = new Map<number, WorkflowNodePin[]>()\n for (const pin of pins) {\n const major = majorOf(pin.value)\n // An alias (`lts/*`) is a pin this module cannot resolve without a network\n // call — the same treatment `.nvmrc` gives one.\n if (major === null) continue\n const bucket = byMajor.get(major)\n if (bucket) bucket.push(pin)\n else byMajor.set(major, [pin])\n }\n\n if (byMajor.size === 0) return null\n if (byMajor.size > 1) {\n const detail = [...byMajor.values()]\n .flat()\n .map((pin) => ` ${pin.file} (${pin.via}): ${pin.value}`)\n .join('\\n')\n throw new Error(\n 'signoff: the workflows that gate a merge here pin different Node majors, so there is no single ' +\n `runtime to verify:\\n${detail}\\n` +\n 'Declare `nodeVersion` in the signoff config to say which one a sign-off means.',\n )\n }\n\n const [entry] = [...byMajor.entries()]\n if (entry === undefined) return null\n const [major, matched] = entry\n const first = matched[0] as WorkflowNodePin\n const files = [...new Set(matched.map((pin: WorkflowNodePin) => pin.file))].join(', ')\n return { major, declared: first.value, source: `${files} (${first.via})` }\n}\n","import { spawn } from 'node:child_process'\n\n/**\n * The subprocess primitive every sign-off step runs through.\n *\n * Three properties the gate depends on, none of which `execSync` gives:\n *\n * 1. **Cancellable.** Under fail-fast, a build still running when typecheck\n * fails is killed rather than waited out — otherwise the \"faster than CI\"\n * claim is spent waiting for work whose verdict no longer matters.\n * 2. **Process-group kill.** Steps run through `sh -c`, so killing the shell\n * leaves `vitest`'s forks and `tsup`'s dts worker orphaned and holding CPU.\n * The child is spawned as a group leader and the whole group is signalled.\n * 3. **Bounded, non-silent capture.** Output is capped, and when the cap is hit\n * the elision is stated in the captured text. A gate that quietly drops the\n * middle of a failure log is a gate that hides the failure.\n */\n\nexport interface CommandResult {\n readonly command: string\n readonly cwd: string\n readonly exitCode: number\n readonly signal: string | null\n readonly durationMs: number\n readonly output: string\n readonly truncated: boolean\n readonly timedOut: boolean\n}\n\nexport interface RunCommandOptions {\n readonly command: string\n readonly cwd: string\n readonly env?: Readonly<Record<string, string | undefined>>\n readonly timeoutMs?: number\n readonly signal?: AbortSignal\n /** Retained bytes before elision. Default 2 MiB. */\n readonly maxOutputBytes?: number\n /** Grace between SIGTERM and SIGKILL. Default 5 s. */\n readonly killGraceMs?: number\n readonly onData?: (chunk: string) => void\n}\n\nconst DEFAULT_MAX_OUTPUT_BYTES = 2 * 1024 * 1024\nconst DEFAULT_KILL_GRACE_MS = 5_000\n/** Fraction of the budget kept from the head; the rest is the tail. The head\n * carries the command echo and the first error, the tail carries the summary. */\nconst HEAD_SHARE = 0.25\n\n/**\n * Ring-ish buffer that keeps a head window and a tail window, so both the first\n * error and the final summary survive a very long log.\n */\nclass BoundedOutput {\n private head = ''\n private tail = ''\n private total = 0\n private readonly headBudget: number\n private readonly tailBudget: number\n\n constructor(private readonly budget: number) {\n this.headBudget = Math.floor(budget * HEAD_SHARE)\n this.tailBudget = budget - this.headBudget\n }\n\n push(chunk: string): void {\n this.total += chunk.length\n if (this.head.length < this.headBudget) {\n const room = this.headBudget - this.head.length\n this.head += chunk.slice(0, room)\n chunk = chunk.slice(room)\n if (chunk.length === 0) return\n }\n this.tail = (this.tail + chunk).slice(-this.tailBudget)\n }\n\n get truncated(): boolean {\n return this.total > this.budget\n }\n\n text(): string {\n if (!this.truncated) return this.head + this.tail\n const elided = this.total - this.head.length - this.tail.length\n return `${this.head}\\n\\n[signoff] ${elided} bytes elided (output exceeded ${this.budget} bytes)\\n\\n${this.tail}`\n }\n}\n\n/** Signal a whole process group, tolerating the race where it already exited. */\nfunction killGroup(pid: number, signal: NodeJS.Signals): void {\n try {\n process.kill(-pid, signal)\n } catch (err) {\n // ESRCH means the group is already gone, which is the outcome we wanted.\n // Anything else is a real failure to signal and must not be swallowed.\n if ((err as NodeJS.ErrnoException).code !== 'ESRCH') throw err\n }\n}\n\n/**\n * Run one shell command to completion and report what happened.\n *\n * Never throws on a non-zero exit — a failing step is data, not an exception.\n * It throws only when the process could not be started at all.\n */\nexport function runCommand(options: RunCommandOptions): Promise<CommandResult> {\n const {\n command,\n cwd,\n env,\n timeoutMs,\n signal,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n killGraceMs = DEFAULT_KILL_GRACE_MS,\n onData,\n } = options\n\n return new Promise<CommandResult>((resolve, reject) => {\n const startedAt = Date.now()\n const buffer = new BoundedOutput(maxOutputBytes)\n let timedOut = false\n let killTimer: NodeJS.Timeout | undefined\n let graceTimer: NodeJS.Timeout | undefined\n\n const child = spawn(command, {\n cwd,\n env: env as NodeJS.ProcessEnv | undefined,\n shell: true,\n // Group leader: lets one signal reach `sh` and everything it spawned.\n detached: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n })\n\n const pid = child.pid\n const terminate = (): void => {\n if (pid === undefined || child.exitCode !== null || child.signalCode !== null) return\n killGroup(pid, 'SIGTERM')\n graceTimer = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) killGroup(pid, 'SIGKILL')\n }, killGraceMs)\n graceTimer.unref()\n }\n\n const onAbort = (): void => terminate()\n signal?.addEventListener('abort', onAbort, { once: true })\n\n if (timeoutMs !== undefined) {\n killTimer = setTimeout(() => {\n timedOut = true\n terminate()\n }, timeoutMs)\n killTimer.unref()\n }\n\n const collect = (chunk: Buffer): void => {\n const text = chunk.toString('utf8')\n buffer.push(text)\n onData?.(text)\n }\n child.stdout.on('data', collect)\n child.stderr.on('data', collect)\n\n const cleanup = (): void => {\n if (killTimer) clearTimeout(killTimer)\n if (graceTimer) clearTimeout(graceTimer)\n signal?.removeEventListener('abort', onAbort)\n }\n\n child.on('error', (err) => {\n cleanup()\n reject(new Error(`signoff: could not start \\`${command}\\` in ${cwd}: ${err.message}`))\n })\n\n child.on('close', (code, sig) => {\n cleanup()\n resolve({\n command,\n cwd,\n // A signalled process reports code `null`; 128+n is the shell's own\n // convention and keeps the field a number a caller can compare.\n exitCode: code ?? (sig === 'SIGKILL' ? 137 : 143),\n signal: sig,\n durationMs: Date.now() - startedAt,\n output: buffer.text(),\n truncated: buffer.truncated,\n timedOut,\n })\n })\n })\n}\n","/**\n * The dependency graph, and running it as wide as the graph allows.\n *\n * CI runs these steps in a line because a YAML `steps:` list is a line. Nothing\n * about the work requires that: typecheck, the suite, the build and knip all\n * read source and none reads another's output. On a 32-core host, running them\n * concurrently is free wall-clock, and it is the only reason a strictly larger\n * verification can still finish faster than the CI it replaces.\n *\n * The graph is declared per step (`needs`), validated here, and the schedule is\n * derived from it — so an omitted edge is a correctness bug the repo owns, and\n * a cycle is named rather than deadlocking.\n */\n\nexport interface GraphNode {\n readonly name: string\n readonly needs?: readonly string[]\n}\n\n/** Throws on a duplicate name, a dangling `needs`, or a cycle. */\nexport function validateGraph(nodes: readonly GraphNode[]): void {\n const seen = new Set<string>()\n for (const node of nodes) {\n if (seen.has(node.name)) throw new Error(`signoff: two steps are both named \"${node.name}\"; names must be unique`)\n seen.add(node.name)\n }\n for (const node of nodes) {\n for (const need of node.needs ?? []) {\n if (!seen.has(need)) {\n throw new Error(`signoff: step \"${node.name}\" needs \"${need}\", which is not a step in this config`)\n }\n }\n }\n\n const byName = new Map(nodes.map((node) => [node.name, node]))\n const state = new Map<string, 'visiting' | 'done'>()\n const walk = (name: string, path: readonly string[]): void => {\n const status = state.get(name)\n if (status === 'done') return\n if (status === 'visiting') {\n const cycle = [...path.slice(path.indexOf(name)), name].join(' -> ')\n throw new Error(`signoff: dependency cycle among steps: ${cycle}`)\n }\n state.set(name, 'visiting')\n for (const need of byName.get(name)?.needs ?? []) walk(need, [...path, name])\n state.set(name, 'done')\n }\n for (const node of nodes) walk(node.name, [])\n}\n\ntype TaskStatus = 'passed' | 'failed' | 'skipped' | 'cancelled' | 'blocked'\n\nexport interface TaskOutcome<T> {\n readonly name: string\n readonly status: TaskStatus\n /** Present for anything that actually ran, including a cancelled task. */\n readonly value: T | null\n readonly startedAtMs: number | null\n readonly finishedAtMs: number | null\n}\n\nexport interface RunGraphOptions<TNode extends GraphNode, TValue> {\n readonly nodes: readonly TNode[]\n readonly maxParallel: number\n /** `false` stops scheduling after the first failure and kills what is running. */\n readonly keepGoing: boolean\n /** Runs one node. Resolves `{ ok }` for pass/fail; must not throw for a\n * failing command — a non-zero exit is data. */\n readonly run: (node: TNode, signal: AbortSignal) => Promise<{ readonly ok: boolean; readonly value: TValue }>\n /** Wall-clock origin, so outcomes are comparable across the whole run. */\n readonly now?: () => number\n}\n\n/**\n * Run the graph, honouring dependencies and the parallelism cap.\n *\n * Failure semantics, stated because they are the difference between a gate you\n * trust and one you argue with:\n * - fail-fast (default): nothing new is scheduled, everything in flight is\n * aborted and reported as `cancelled`, everything unstarted as `skipped`.\n * - `keepGoing`: independent work continues, but a step whose dependency\n * failed is reported `blocked`. It is never reported as passed, and never\n * silently omitted.\n */\nexport async function runGraph<TNode extends GraphNode, TValue>(\n options: RunGraphOptions<TNode, TValue>,\n): Promise<TaskOutcome<TValue>[]> {\n const { nodes, maxParallel, keepGoing, run, now = () => Date.now() } = options\n validateGraph(nodes)\n\n const origin = now()\n const outcomes = new Map<string, TaskOutcome<TValue>>()\n const pending = new Map(nodes.map((node) => [node.name, node]))\n const running = new Map<string, { readonly promise: Promise<void>; readonly controller: AbortController }>()\n let aborted = false\n\n const failedNames = new Set<string>()\n const passedNames = new Set<string>()\n\n const blockedBy = (node: TNode): boolean => (node.needs ?? []).some((need) => failedNames.has(need))\n const ready = (node: TNode): boolean => (node.needs ?? []).every((need) => passedNames.has(need))\n\n const settle = (name: string, outcome: TaskOutcome<TValue>): void => {\n outcomes.set(name, outcome)\n if (outcome.status === 'passed') passedNames.add(name)\n else failedNames.add(name)\n }\n\n const start = (node: TNode): void => {\n pending.delete(node.name)\n const controller = new AbortController()\n const startedAtMs = now() - origin\n const promise = run(node, controller.signal).then((result) => {\n const finishedAtMs = now() - origin\n const cancelled = controller.signal.aborted && !result.ok\n settle(node.name, {\n name: node.name,\n status: cancelled ? 'cancelled' : result.ok ? 'passed' : 'failed',\n value: result.value,\n startedAtMs,\n finishedAtMs,\n })\n running.delete(node.name)\n })\n running.set(node.name, { promise, controller })\n }\n\n for (;;) {\n if (!aborted) {\n // Drain everything the graph currently permits, up to the cap.\n for (const node of [...pending.values()]) {\n if (running.size >= maxParallel) break\n if (blockedBy(node)) {\n pending.delete(node.name)\n settle(node.name, { name: node.name, status: 'blocked', value: null, startedAtMs: null, finishedAtMs: null })\n continue\n }\n if (ready(node)) start(node)\n }\n }\n\n if (running.size === 0) {\n // Nothing running: either everything settled, or the rest is unreachable.\n if (pending.size === 0) break\n if (aborted) break\n // A pending node whose dependency neither passed nor failed cannot happen\n // after validateGraph, so anything left here is blocked or ready-next.\n const progressed = [...pending.values()].some((node) => ready(node) || blockedBy(node))\n if (!progressed) break\n continue\n }\n\n await Promise.race([...running.values()].map((entry) => entry.promise))\n\n if (!keepGoing && failedNames.size > 0 && !aborted) {\n aborted = true\n for (const entry of running.values()) entry.controller.abort()\n }\n }\n\n for (const node of pending.values()) {\n settle(node.name, {\n name: node.name,\n status: blockedBy(node) ? 'blocked' : 'skipped',\n value: null,\n startedAtMs: null,\n finishedAtMs: null,\n })\n }\n\n return nodes.map((node) => {\n const outcome = outcomes.get(node.name)\n if (!outcome) throw new Error(`signoff: step \"${node.name}\" produced no outcome — scheduler bug`)\n return outcome\n })\n}\n","import { createHash, randomInt } from 'node:crypto'\nimport type { SignoffShuffleSpec, SignoffStepSpec } from './types'\n\n/**\n * Suite-order randomization — the half of this gate that CI does not have.\n *\n * CI runs one arbitrary file order, so a scheduling-dependent failure is a coin\n * flip it happens to win or lose. The `node:sqlite` bundling failure that\n * started this was exactly that shape: it reproduced under CI's clean install\n * and worker sharding and not under a warm local run, and a single fixed order\n * could have missed it in either direction.\n *\n * Two rules make randomization useful rather than merely noisy:\n *\n * 1. **Every seed is recorded.** A shuffled failure that cannot be replayed is\n * a rumour. The report carries the base seed and every derived seed, and the\n * derivation is a pure function of `(base, step, index)` — so `--seed <base>`\n * reproduces the whole run, and a single seed replays one step.\n * 2. **Files are shuffled; tests inside a file are not.** File order is what\n * module-graph and worker-scheduling failures depend on. Shuffling the tests\n * within a file mostly finds intentional ordering in a `describe` block,\n * which is a false alarm, and a gate that cries wolf gets waived.\n */\n\n/**\n * Vitest file-order shuffle. `{seed}` is substituted per attempt.\n *\n * **No `--` separator, and that is measured, not assumed.** The habit is to\n * write `pnpm run test -- --flag`, and it silently breaks this: pnpm forwards\n * script arguments verbatim without needing the separator, so the `--` reaches\n * vitest, whose CLI treats it as end-of-options and drops everything after it.\n * Measured on this repo, four test files, `--reporter=verbose`:\n *\n * | invocation | seed 1 order | seed 2 order |\n * |---|---|---|\n * | `vitest run -- --sequence.shuffle.files=true --sequence.seed=N` | schedule, store, seeds, config | schedule, store, seeds, config |\n * | `vitest run --sequence.shuffle.files=true --sequence.seed=N` | schedule, config, store, seeds | seeds, schedule, config, store |\n *\n * The first row is the failure this gate exists to prevent, applied to itself:\n * a run that reports \"2 orders, seeds recorded\" while running one fixed order\n * twice. If a runner ever does need a separator, its config declares its own\n * `shuffle.args`.\n */\nconst DEFAULT_SHUFFLE_ARGS: readonly string[] = [\n '--sequence.shuffle.files=true',\n '--sequence.seed={seed}',\n]\n\nexport const DEFAULT_SHUFFLE_RUNS = 2\n\n/** A fresh base seed. Random, then recorded — never a fixed constant, or the\n * \"randomized\" order is one more fixed order. */\nexport function newSeedBase(): number {\n return randomInt(0, 2 ** 31 - 1)\n}\n\n/**\n * Derive a step's Nth seed from the base.\n *\n * A hash rather than `base + n`: adjacent seeds produce correlated orders in\n * some runners, and the point is independent samples of the order space.\n */\nexport function deriveSeed(base: number, stepName: string, index: number): number {\n const digest = createHash('sha256').update(`${base}:${stepName}:${index}`).digest()\n return digest.readUInt32BE(0) % 2 ** 31\n}\n\n/**\n * Refuse a shuffled step whose command cannot receive the appended flags.\n *\n * pnpm only forwards extra arguments to a script through `run`, `exec` or\n * `dlx`. The shorthand form puts pnpm's own option parser in front of them, and\n * what happens next is a version lottery. Measured on this host, appending\n * `--sequence.shuffle.files=true --sequence.seed=7` to a script that prints its\n * `process.argv`:\n *\n * | command | pnpm 9.15.9 | pnpm 10.22.0 |\n * |---|---|---|\n * | `pnpm run t <flags>` | forwarded, exit 0 | forwarded, exit 0 |\n * | `pnpm exec node probe.mjs <flags>` | forwarded, exit 0 | forwarded, exit 0 |\n * | `pnpm t <flags>` | `Unknown options`, exit 1 | exit 254, script never ran |\n * | `pnpm --filter web t <flags>` | `Unknown options`, exit 1 | **exit 0, script never ran** |\n *\n * That last cell is the reason this is a refusal and not a note. tax-agent's CI\n * runs `pnpm --filter web test`, and a config that copied the line verbatim\n * would, on pnpm 10, report a green \"unit tests\" step that executed zero tests.\n * A gate reporting safety it did not provide is the exact failure this module\n * exists to prevent, and the shorthand makes it silent.\n *\n * This is a static approximation — it checks the invocation SHAPE, not what the\n * runner received — so it is deliberately narrow: it fires only on commands\n * that invoke pnpm, and only on steps that get arguments appended.\n */\nexport function assertShuffleArgsReachTheRunner(steps: readonly SignoffStepSpec[]): void {\n for (const step of steps) {\n if (!normalizeShuffle(step.shuffle)) continue\n const tokens = step.run.split(/\\s+/).filter((token) => token.length > 0)\n const pnpmAt = tokens.findIndex((token) => token === 'pnpm' || token.endsWith('/pnpm'))\n if (pnpmAt === -1) continue\n if (tokens.slice(pnpmAt + 1).some((token) => token === 'run' || token === 'exec' || token === 'dlx')) continue\n throw new Error(\n `signoff: step \"${step.name}\" runs \\`${step.run}\\` and is shuffled, but pnpm only forwards appended ` +\n 'arguments to a script through `run`, `exec` or `dlx`. In the shorthand form pnpm 9 errors and pnpm 10 ' +\n 'exits 0 having run nothing, which would report a passing suite that never executed. ' +\n `Write it as \\`${step.run.replace(/\\s(\\S+)$/, ' run $1')}\\`.`,\n )\n }\n}\n\nexport interface StepAttemptPlan {\n readonly command: string\n readonly seed: number | null\n}\n\nfunction normalizeShuffle(shuffle: boolean | SignoffShuffleSpec | undefined): SignoffShuffleSpec | null {\n if (shuffle === undefined || shuffle === false) return null\n return shuffle === true ? {} : shuffle\n}\n\n/**\n * Expand one step into the commands that will actually run.\n *\n * An unshuffled step is one attempt with no seed. A shuffled step is one\n * attempt per seed, each with the seed substituted into the appended arguments.\n */\nexport function planAttempts(\n step: SignoffStepSpec,\n seedBase: number,\n overrideRuns?: number,\n): StepAttemptPlan[] {\n const spec = normalizeShuffle(step.shuffle)\n if (!spec) return [{ command: step.run, seed: null }]\n\n const args = spec.args ?? DEFAULT_SHUFFLE_ARGS\n const seeds =\n spec.seeds && spec.seeds.length > 0\n ? [...spec.seeds]\n : Array.from({ length: overrideRuns ?? spec.runs ?? DEFAULT_SHUFFLE_RUNS }, (_unused, index) =>\n deriveSeed(seedBase, step.name, index),\n )\n\n return seeds.map((seed) => ({\n command: `${step.run} ${args.map((arg) => arg.replaceAll('{seed}', String(seed))).join(' ')}`,\n seed,\n }))\n}\n","import { createHash } from 'node:crypto'\nimport { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, utimesSync, writeFileSync } from 'node:fs'\nimport { basename, join, relative, sep } from 'node:path'\n\n/**\n * The pristine package store, cached on the lockfile so speed is not paid for\n * with a stale module graph.\n *\n * The whole mechanical difference between \"green locally\" and \"red in CI\" is\n * that CI installs `--frozen-lockfile` into an isolated store with no\n * `node_modules` and no framework cache, and a local run reuses both. Only one\n * of those two is safe to keep:\n *\n * - `node_modules` and any build/framework cache are **never** reused. They are\n * what masked the failure this gate exists to catch, and they are recreated\n * for every run inside a fresh `git worktree`.\n * - The **store** is reused, keyed on the bytes that decide what gets installed.\n * A pnpm store is content-addressed: every entry is named by the hash of what\n * is in it, so a reused entry cannot be a different version of a package than\n * the lockfile asked for. Reusing it skips downloads, not resolution.\n *\n * The key covers every manifest in the tree — lockfile, workspace file, every\n * `package.json`, `.npmrc`. Change any of them and the key changes, so the next\n * run installs into an empty store and pays the honest cold cost. Generations\n * are kept (default 4) rather than one, so moving between a branch and `main`\n * finds both warm instead of thrashing.\n */\n\n/** Basenames whose bytes decide what an install resolves to. */\nconst MANIFEST_FILES: readonly string[] = [\n 'pnpm-lock.yaml',\n 'pnpm-workspace.yaml',\n 'package.json',\n '.npmrc',\n '.nvmrc',\n 'package-lock.json',\n 'npm-shrinkwrap.json',\n 'yarn.lock',\n]\n\n/** Never descended into when hunting manifests. */\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.wrangler', '.react-router'])\n\nexport interface StoreResolution {\n readonly storeDir: string\n readonly cacheKey: string\n /** True when a store for this key already had content. */\n readonly hit: boolean\n /** Repo-relative manifest paths, sorted — the inputs to `cacheKey`. */\n readonly keyedOn: readonly string[]\n /** Store directories removed by the generation cap. */\n readonly pruned: readonly string[]\n}\n\nexport interface ResolveStoreOptions {\n /** The clean tree whose manifests are hashed. */\n readonly treePath: string\n readonly cacheDir: string\n /** Generations to keep. Default 4. */\n readonly generations?: number\n /** Keys held by other active signoff runs; they cannot be evicted. */\n readonly protectedStoreKeys?: ReadonlySet<string>\n}\n\nfunction collectManifests(dir: string, root: string, out: string[]): void {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) continue\n collectManifests(join(dir, entry.name), root, out)\n } else if (MANIFEST_FILES.includes(entry.name)) {\n out.push(relative(root, join(dir, entry.name)).split(sep).join('/'))\n }\n }\n}\n\n/** Every manifest in the tree, repo-relative and sorted. */\nexport function manifestFiles(treePath: string): string[] {\n const found: string[] = []\n collectManifests(treePath, treePath, found)\n return found.sort()\n}\n\n/** sha256 over each manifest's path and content — order-independent by sorting. */\nexport function manifestCacheKey(treePath: string, files: readonly string[]): string {\n const hash = createHash('sha256')\n for (const rel of files) {\n hash.update(rel)\n hash.update('\\0')\n hash.update(createHash('sha256').update(readFileSync(join(treePath, rel))).digest('hex'))\n hash.update('\\n')\n }\n return hash.digest('hex')\n}\n\n/**\n * Prune all but the `keep` most recently used store generations.\n *\n * Recency is the directory's mtime, stamped on every use, so the store a run\n * just used is never the one evicted.\n */\nfunction pruneStores(storesRoot: string, keep: number, protectedKeys: ReadonlySet<string>): string[] {\n if (!existsSync(storesRoot)) return []\n const entries = readdirSync(storesRoot, { withFileTypes: true })\n .filter((entry) => entry.isDirectory() && /^[a-f0-9]{64}$/.test(entry.name))\n .map((entry) => {\n const full = join(storesRoot, entry.name)\n return { full, mtimeMs: statSync(full).mtimeMs }\n })\n .sort((a, b) => b.mtimeMs - a.mtimeMs)\n\n const pruned: string[] = []\n for (const stale of entries.slice(keep)) {\n if (protectedKeys.has(basename(stale.full))) continue\n rmSync(stale.full, { recursive: true, force: true })\n pruned.push(stale.full)\n }\n return pruned\n}\n\nexport function resolveStore(options: ResolveStoreOptions): StoreResolution {\n const { treePath, cacheDir, generations = 4, protectedStoreKeys = new Set<string>() } = options\n const files = manifestFiles(treePath)\n if (files.length === 0) {\n throw new Error(\n `signoff: no package manifest under ${treePath}. A sign-off run installs from a lockfile; ` +\n 'there is nothing here to install.',\n )\n }\n\n const cacheKey = manifestCacheKey(treePath, files)\n const storesRoot = join(cacheDir, 'stores')\n const storeDir = join(storesRoot, cacheKey)\n // A store directory that exists but holds only the marker is a previous run\n // that died before installing; treat it as a miss so the report does not\n // claim a warm store it does not have.\n const marker = join(storeDir, '.signoff-store.json')\n const hit = existsSync(storeDir) && readdirSync(storeDir).some((entry) => entry !== '.signoff-store.json')\n\n mkdirSync(storeDir, { recursive: true })\n writeFileSync(marker, `${JSON.stringify({ cacheKey, keyedOn: files, usedAt: new Date().toISOString() }, null, 2)}\\n`)\n const now = new Date()\n utimesSync(storeDir, now, now)\n\n return { storeDir, cacheKey, hit, keyedOn: files, pruned: pruneStores(storesRoot, generations, protectedStoreKeys) }\n}\n","import { spawnSync } from 'node:child_process'\nimport { createHash } from 'node:crypto'\nimport { copyFileSync, existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport type { SignoffRepoFacts, SignoffSource } from './types'\n\n/**\n * Materialize the pristine checkout every step runs against.\n *\n * **The decision, and the measurement behind it: a `git worktree` of HEAD, not\n * a filtered copy.** Both were timed on two real repos on this host:\n *\n * | repo | `git worktree add --detach` | `rsync -a --exclude node_modules --exclude .git` |\n * |---|---|---|\n * | agent-app (931 tracked files) | **0.04 s / 11 MB** | 0.12 s / 25 MB |\n * | legal-agent (753 tracked files) | **0.06 s / 24 MB** | **3.97 s / 2.7 GB** |\n *\n * The 2.7 GB is the argument. The copy carried `build/`, `.react-router/` and\n * `.wrangler/` — generated output and framework caches — because an exclude\n * list is a hand-maintained enumeration of things to leave behind, and it is\n * never complete. A warm Vite cache is precisely what made the `node:sqlite`\n * bundling failure invisible locally while CI saw it, so a materializer that\n * can leak one has defeated its own purpose. `git` already knows what is source\n * and what is generated, and `.gitignore` is that list, maintained by the repo.\n *\n * The overlay on top is what keeps the gate usable before you commit:\n * `source: 'working-tree'` applies `git diff HEAD` (staged and unstaged) as a\n * patch and copies untracked, non-ignored files in. `source: 'head'` verifies\n * exactly the commit that would merge.\n */\n\nexport interface MaterializeOptions {\n readonly repoDir: string\n readonly dest: string\n readonly source: SignoffSource\n /** Gitignored files the run genuinely needs. Missing ones abort. */\n readonly carryFiles?: readonly string[]\n}\n\nexport interface CleanTree extends SignoffRepoFacts {\n /** Absolute path of the materialized checkout. */\n readonly path: string\n}\n\nfunction git(args: readonly string[], cwd: string): string {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 })\n if (result.error) throw new Error(`signoff: git ${args.join(' ')} failed to start: ${result.error.message}`)\n if (result.status !== 0) {\n throw new Error(`signoff: git ${args.join(' ')} exited ${result.status}\\n${result.stderr.trim()}`)\n }\n return result.stdout\n}\n\n/** Split a `-z` separated git list into entries. */\nfunction zsplit(out: string): string[] {\n return out.split('\\0').filter((entry) => entry.length > 0)\n}\n\nexport function repoRootOf(dir: string): string {\n return git(['rev-parse', '--show-toplevel'], dir).trim()\n}\n\nexport function materializeCleanTree(options: MaterializeOptions): CleanTree {\n const { repoDir, dest, source, carryFiles = [] } = options\n const root = repoRootOf(repoDir)\n const head = git(['rev-parse', 'HEAD'], root).trim()\n const branch = git(['rev-parse', '--abbrev-ref', 'HEAD'], root).trim()\n\n // A crashed earlier run leaves a registered worktree whose directory is gone;\n // `add` then refuses on a name collision. Pruning first is what makes the gate\n // re-runnable after a kill.\n git(['worktree', 'prune'], root)\n mkdirSync(dirname(dest), { recursive: true })\n if (existsSync(dest)) rmSync(dest, { recursive: true, force: true })\n git(['worktree', 'add', '--detach', '--quiet', dest, head], root)\n\n let diffSha256: string | null = null\n let untrackedFiles: string[] = []\n\n if (source === 'working-tree') {\n // `git diff HEAD` covers staged and unstaged changes to tracked files in one\n // patch, including deletions and renames. `--binary` keeps a changed image\n // or lockfile-adjacent binary from silently dropping out of the patch.\n const patch = git(['diff', 'HEAD', '--binary', '--no-color', '--no-ext-diff'], root)\n if (patch.length > 0) {\n diffSha256 = createHash('sha256').update(patch).digest('hex')\n const patchFile = join(dirname(dest), `${dest.split('/').pop() ?? 'tree'}.patch`)\n writeFileSync(patchFile, patch)\n // Fail loud: a patch that does not apply means the tree we would verify is\n // not the tree the developer has, and verifying the wrong bytes is worse\n // than not verifying.\n git(['apply', '--binary', '--whitespace=nowarn', patchFile], dest)\n rmSync(patchFile, { force: true })\n }\n\n untrackedFiles = zsplit(git(['ls-files', '--others', '--exclude-standard', '-z'], root))\n for (const rel of untrackedFiles) {\n const target = join(dest, rel)\n mkdirSync(dirname(target), { recursive: true })\n copyFileSync(join(root, rel), target)\n }\n }\n\n const carried: string[] = []\n for (const rel of carryFiles) {\n if (isAbsolute(rel)) throw new Error(`signoff: carryFiles must be repo-relative; got \"${rel}\"`)\n const from = resolve(root, rel)\n if (!existsSync(from)) {\n throw new Error(\n `signoff: carryFiles names \"${rel}\", which does not exist at ${from}. ` +\n 'Remove it from the config or create the file — installing without it would resolve ' +\n 'against a different registry than the one you think you are verifying.',\n )\n }\n const target = join(dest, rel)\n mkdirSync(dirname(target), { recursive: true })\n copyFileSync(from, target)\n carried.push(rel)\n }\n\n return {\n path: dest,\n root,\n head,\n branch,\n source,\n dirty: diffSha256 !== null || untrackedFiles.length > 0,\n diffSha256,\n untrackedFiles,\n carriedFiles: carried,\n }\n}\n\n/** Unregister and delete a materialized tree. */\nexport function removeCleanTree(tree: CleanTree): void {\n git(['worktree', 'remove', '--force', tree.path], tree.root)\n}\n","import type { SignoffReport, SignoffStepResult } from './types'\n\n/**\n * The proof a human reads before merging.\n *\n * A sign-off gate is only worth the CI it replaces if its output answers the\n * question CI's green tick answers and the ones it does not: what bytes were\n * verified, in what environment, under which suite orders, and how to reproduce\n * it. So the report leads with the verdict, states the subject (commit + patch\n * digest) and the environment (clean tree, store cache state), lists every step\n * with its seeds, and ends with the exact command that runs it again.\n *\n * Failure output is printed in full, under the step's name. Naming the step is\n * the difference between \"CI is red\" and a fix.\n */\n\nconst BAR = '─'.repeat(72)\n\nfunction ms(value: number): string {\n return value >= 10_000 ? `${(value / 1000).toFixed(1)}s` : `${value}ms`\n}\n\nfunction statusMark(status: SignoffStepResult['status']): string {\n switch (status) {\n case 'passed': return 'ok '\n case 'failed': return 'FAIL'\n case 'cancelled': return 'kill'\n case 'blocked': return 'blkd'\n case 'skipped': return '-- '\n }\n}\n\nfunction seedList(step: SignoffStepResult): string {\n const seeds = step.attempts.map((attempt) => attempt.seed).filter((seed): seed is number => seed !== null)\n return seeds.length === 0 ? '' : ` seeds ${seeds.join(', ')}`\n}\n\n/** Concurrency actually achieved, measured from the step windows rather than\n * asserted from the config. A claimed speedup nobody measured is a wish. */\nexport function peakConcurrency(steps: readonly SignoffStepResult[]): number {\n const events: { at: number; delta: number }[] = []\n for (const step of steps) {\n if (step.startedAtMs === null || step.finishedAtMs === null) continue\n events.push({ at: step.startedAtMs, delta: 1 }, { at: step.finishedAtMs, delta: -1 })\n }\n events.sort((a, b) => a.at - b.at || a.delta - b.delta)\n let current = 0\n let peak = 0\n for (const event of events) {\n current += event.delta\n peak = Math.max(peak, current)\n }\n return peak\n}\n\nexport function formatSignoffReport(report: SignoffReport): string {\n const lines: string[] = []\n const verdict = report.ok ? 'SIGN-OFF PASSED' : 'SIGN-OFF FAILED'\n lines.push(BAR, `${verdict} — ${report.repo.branch} @ ${report.repo.head.slice(0, 12)}`, BAR, '')\n\n lines.push('subject')\n lines.push(` repo ${report.repo.root}`)\n lines.push(` source ${report.repo.source}${report.repo.dirty ? ' (working tree carries uncommitted work)' : ''}`)\n if (report.repo.diffSha256) lines.push(` patch sha256:${report.repo.diffSha256.slice(0, 16)}`)\n if (report.repo.untrackedFiles.length > 0) {\n lines.push(` untracked ${report.repo.untrackedFiles.length} file(s) copied in`)\n }\n if (report.repo.carriedFiles.length > 0) lines.push(` carried ${report.repo.carriedFiles.join(', ')}`)\n lines.push('')\n\n lines.push('environment')\n lines.push(` clean tree ${report.workspace}${report.workspaceRetained ? ' (retained)' : ' (removed)'}`)\n lines.push(` install ${report.install.command}`)\n lines.push(\n ` store ${report.install.cacheHit ? 'warm' : 'cold'} — ${report.install.cacheKey.slice(0, 16)} ` +\n `(keyed on ${report.install.keyedOn.length} manifest file(s))`,\n )\n lines.push(\n ` host ${report.host.node} · ${report.host.packageManager} · ${report.host.cpus} cpus` +\n (report.host.nodePinned === null\n ? ' · node UNPINNED by this repo'\n : ` · pinned ${report.host.nodePinned} (${report.host.nodePinSource})`),\n )\n lines.push(\n ` config ${report.configOrigin.kind === 'derived'\n ? `derived from scripts: ${report.configOrigin.scripts.join(', ')}`\n : report.configOrigin.path}`,\n )\n lines.push('')\n\n const width = Math.max(...report.steps.map((step) => step.name.length), 'install'.length)\n lines.push('steps')\n lines.push(\n ` ${report.install.exitCode === 0 ? 'ok ' : 'FAIL'} ${'install'.padEnd(width)} ${ms(report.install.durationMs).padStart(8)}`,\n )\n for (const step of report.steps) {\n const window =\n step.startedAtMs === null || step.finishedAtMs === null\n ? ''\n : ` [${ms(step.startedAtMs)} → ${ms(step.finishedAtMs)}]`\n lines.push(\n ` ${statusMark(step.status)} ${step.name.padEnd(width)} ${ms(step.durationMs).padStart(8)}` +\n ` ${step.attempts.length} run(s)${window}${seedList(step)}`,\n )\n }\n lines.push('')\n\n const peak = peakConcurrency(report.steps)\n const saved = report.serialMs - report.wallClockMs\n lines.push('timing')\n lines.push(` wall clock ${ms(report.wallClockMs)}`)\n lines.push(` serial sum ${ms(report.serialMs)} (install + every step, one after another)`)\n lines.push(\n ` parallel peak ${peak} step(s) at once — ` +\n (saved > 0 ? `${ms(saved)} saved, ${(report.serialMs / report.wallClockMs).toFixed(2)}x` : 'no overlap available'),\n )\n lines.push('')\n\n const failures = report.steps.filter((step) => step.status === 'failed' || step.status === 'cancelled')\n if (report.install.exitCode !== 0) {\n lines.push(BAR, 'install FAILED — no step could run', BAR, report.install.output.trimEnd(), '')\n }\n for (const step of failures) {\n const last = step.attempts[step.attempts.length - 1]\n lines.push(BAR)\n lines.push(`${step.status === 'cancelled' ? 'CANCELLED' : 'FAILED'}: ${step.name}`)\n if (last) {\n lines.push(` command ${last.command}`)\n lines.push(` exit ${last.exitCode}${last.signal ? ` (${last.signal})` : ''}${last.timedOut ? ' — TIMED OUT' : ''}`)\n if (last.seed !== null) {\n lines.push(` seed ${last.seed} — replay this order alone with the same seed`)\n }\n lines.push(BAR, last.output.trimEnd(), '')\n }\n }\n\n const blocked = report.steps.filter((step) => step.status === 'blocked' || step.status === 'skipped')\n if (blocked.length > 0) {\n lines.push(`not judged: ${blocked.map((step) => `${step.name} (${step.status})`).join(', ')}`)\n lines.push('')\n }\n\n lines.push(`reproduce: ${report.reproduce}`)\n return lines.join('\\n')\n}\n\n/** One line for a commit message, a PR comment, or a chat handoff. */\nexport function formatSignoffLine(report: SignoffReport): string {\n const passed = report.steps.filter((step) => step.status === 'passed').length\n return (\n `${report.ok ? 'signoff PASS' : 'signoff FAIL'} ${report.repo.head.slice(0, 12)} — ` +\n `${passed}/${report.steps.length} steps, ${ms(report.wallClockMs)} wall ` +\n `(${ms(report.serialMs)} serial), seed ${report.seedBase}, ` +\n `${report.install.cacheHit ? 'warm' : 'cold'} store, clean install`\n )\n}\n","/**\n * Network budget for the browser checks (`shell-alignment`, `surface-ladder`,\n * `workspace-surface`) when they run against a live site.\n *\n * Every Tangle app sits behind one Cloudflare zone that allows 1000 requests per\n * 10 s per IP, and the fleet's Beelinks and workstation share one egress IP. On\n * 2026-10-12 a production sweep of these checks sent 1533-1782 requests a minute:\n * each page load pulled every asset, and Cloudflare's speculation rules made\n * Chromium prerender every rail link as a hidden full page. It blocked a\n * production canary on another app. So the checks:\n *\n * - launch Chromium with prerender and speculative prefetch off, which also\n * ignores the zone's `/cdn-cgi/speculation` rules;\n * - keep the HTTP cache: they never call `context.route`, because Playwright\n * turns the cache off for a context with any route. In 0.60.141 a route that\n * aborted the speculation rules did that, and every page reload re-downloaded\n * every asset (creative production smoke: 1900 requests, busiest 10 s 373);\n * - count only requests that reach the network: Playwright's `request` event\n * also fires for responses served from the browser's own cache, so 0.60.148\n * counted a cached bundle as an edge request and its totals never moved when\n * the cache worked (creative smoke: ~1900 before and after immutable assets).\n * `meterPage` reads Chromium's `Network.responseReceived` and skips\n * disk-cache, prefetch-cache and service-worker responses; a 304 still counts,\n * because a revalidation does reach the edge;\n * - wait before a navigation whenever the last 10 s already holds\n * `REQUEST_BUDGET_PER_10S`;\n * - report the total and the busiest 10 s, and exit `NETWORK_OVER_BUDGET_EXIT`\n * when the busiest 10 s went over the budget, so an over-budget run fails\n * instead of passing with a note. One page load can't be paced from outside\n * the page, so the exit code is the enforcement.\n */\nimport type { Page } from 'playwright'\n\n/** Chromium flags that stop prerender and speculative prefetch of linked pages. */\nexport const QUIET_CHROMIUM_ARGS: readonly string[] = [\n '--disable-features=Prerender2,SpeculationRules,SpeculationRulesPrefetchProxy,NoStatePrefetch',\n '--disable-background-networking',\n]\n\n/** Requests per 10 s a check may send; a quarter of the shared zone limit. */\nexport const REQUEST_BUDGET_PER_10S = 250\nconst WINDOW_MS = 10_000\n\nexport interface NetworkCount {\n /** Requests the browser sent during the run. */\n readonly requests: number\n /** The most requests inside any 10 s window. */\n readonly peak10s: number\n}\n\nexport interface RequestMeter {\n /** Count one request. */\n record(now?: number): void\n /** Resolve once the last 10 s holds fewer than the budget. */\n pace(): Promise<void>\n count(): NetworkCount\n}\n\nexport function createRequestMeter(budget = REQUEST_BUDGET_PER_10S, sleep = (ms: number) => new Promise<void>((done) => setTimeout(done, ms))): RequestMeter {\n const stamps: number[] = []\n let requests = 0\n let peak10s = 0\n const trim = (now: number) => {\n while (stamps.length && now - stamps[0]! > WINDOW_MS) stamps.shift()\n }\n return {\n record(now = Date.now()) {\n requests += 1\n stamps.push(now)\n trim(now)\n peak10s = Math.max(peak10s, stamps.length)\n },\n async pace() {\n for (;;) {\n const now = Date.now()\n trim(now)\n if (stamps.length < budget) return\n await sleep(WINDOW_MS - (now - stamps[0]!) + 50)\n }\n },\n count: () => ({ requests, peak10s }),\n }\n}\n\n/** The fields of Chromium's `Network.responseReceived` that say where a response came from. */\nexport interface CdpResponseSource {\n readonly fromDiskCache?: boolean\n readonly fromPrefetchCache?: boolean\n readonly fromServiceWorker?: boolean\n}\n\n/** True when a response was fetched over the network, so the edge saw the request. */\nexport function reachedNetwork(response: CdpResponseSource): boolean {\n return !response.fromDiskCache && !response.fromPrefetchCache && !response.fromServiceWorker\n}\n\n/**\n * Count the requests a page sends to the network (Chromium only). Call it before\n * the page's first navigation. Never add a route instead: Playwright turns the\n * HTTP cache off for any context with a route.\n */\nexport async function meterPage(page: Page, meter: RequestMeter): Promise<void> {\n const cdp = await page.context().newCDPSession(page)\n // A memory-cache hit says so in its own event, before its response event.\n const fromMemory = new Set<string>()\n cdp.on('Network.requestServedFromCache', (event: { requestId: string }) => {\n fromMemory.add(event.requestId)\n })\n cdp.on('Network.responseReceived', (event: { requestId: string; response: CdpResponseSource }) => {\n if (fromMemory.delete(event.requestId)) return\n if (reachedNetwork(event.response)) meter.record()\n })\n await cdp.send('Network.enable')\n}\n\n/** Exit code of a check whose pages passed but whose busiest 10 s went over the budget. */\nexport const NETWORK_OVER_BUDGET_EXIT = 3\n\nexport function isOverBudget(count: NetworkCount, budget = REQUEST_BUDGET_PER_10S): boolean {\n return count.peak10s > budget\n}\n\n/** 0, or `NETWORK_OVER_BUDGET_EXIT` when the run went over the budget. */\nexport function networkExitCode(count: NetworkCount | undefined): number {\n return count && isOverBudget(count) ? NETWORK_OVER_BUDGET_EXIT : 0\n}\n\nexport function formatNetworkCount(count: NetworkCount): string {\n const line = `network: ${count.requests} requests, busiest 10 s ${count.peak10s} (budget ${REQUEST_BUDGET_PER_10S})`\n return isOverBudget(count) ? `FAIL ${line}: over the shared edge budget` : line\n}\n","/**\n * Shell alignment: on each route, at desktop and phone widths, the main pane's\n * header divider must continue the sidebar rail's first divider.\n *\n * Every shell header row is a sandbox-ui `ShellHeader` at brand's\n * `--shell-header-height`, so their bottom borders share one y. A product that\n * gives a header its own height (Hospitality's 66px inbox head beside a 56px\n * rail) moves its divider off that line; this check measures the rendered page,\n * so it catches the drift whatever CSS caused it.\n *\n * The browser half (`collectShellDividers`) only reads geometry; the decision\n * (`judgeShellAlignment`) is a pure function so it is unit-tested without a browser.\n */\n\nimport { createRequestMeter, meterPage, QUIET_CHROMIUM_ARGS, type NetworkCount } from './browser-budget'\n\n/** A horizontal divider: the bottom border of a top-anchored row. Coordinates in CSS px. */\nexport interface ShellDivider {\n readonly label: string\n readonly left: number\n readonly right: number\n readonly top: number\n readonly bottom: number\n}\n\nexport interface ShellDividerSample {\n readonly route: string\n readonly width: number\n readonly theme: string\n /** `--shell-header-height` resolved to px on this page. */\n readonly shellHeaderPx: number\n /** The rail's first divider (desktop), or null when the rail is hidden. */\n readonly rail: ShellDivider | null\n /** The phone bar standing in for the rail below its breakpoint, or null. */\n readonly phoneBar: ShellDivider | null\n /** Every top-anchored row divider in the main pane and its side panels. */\n readonly headers: readonly ShellDivider[]\n}\n\nexport interface ShellAlignmentFinding {\n readonly route: string\n readonly width: number\n readonly theme: string\n readonly header: string\n /** Signed px: positive when the header divider sits below the expected line. */\n readonly offsetPx: number\n readonly expectedY: number\n readonly actualY: number\n readonly reason: string\n}\n\nexport const SHELL_ALIGNMENT_TOLERANCE_PX = 0.5\n\n/**\n * Desktop: every header divider lands on the rail's first divider.\n * Phone: the rail is hidden; the phone bar is one shell row, and a header row\n * that starts under it is exactly one shell row tall.\n */\nexport function judgeShellAlignment(\n sample: ShellDividerSample,\n tolerancePx = SHELL_ALIGNMENT_TOLERANCE_PX,\n): ShellAlignmentFinding[] {\n const where = { route: sample.route, width: sample.width, theme: sample.theme }\n const anchor = sample.rail ?? sample.phoneBar\n if (!anchor) {\n return [{ ...where, header: '(shell)', offsetPx: Number.NaN, expectedY: Number.NaN, actualY: Number.NaN,\n reason: 'no rail divider or phone bar found: the route does not render the shared shell' }]\n }\n const findings: ShellAlignmentFinding[] = []\n if (sample.rail) {\n const expectedY = sample.rail.bottom\n for (const header of sample.headers) {\n const offsetPx = header.bottom - expectedY\n if (Math.abs(offsetPx) > tolerancePx) {\n findings.push({ ...where, header: header.label, offsetPx, expectedY, actualY: header.bottom,\n reason: `header divider is ${formatPx(offsetPx)} from the rail's first divider` })\n }\n }\n return findings\n }\n const bar = sample.phoneBar as ShellDivider\n const barOffset = bar.bottom - bar.top - sample.shellHeaderPx\n if (Math.abs(barOffset) > tolerancePx) {\n findings.push({ ...where, header: bar.label, offsetPx: barOffset, expectedY: bar.top + sample.shellHeaderPx,\n actualY: bar.bottom, reason: `phone bar is ${formatPx(barOffset)} off one shell row` })\n }\n const expectedY = bar.bottom + sample.shellHeaderPx\n for (const header of sample.headers) {\n const offsetPx = header.bottom - expectedY\n if (Math.abs(offsetPx) > tolerancePx) {\n findings.push({ ...where, header: header.label, offsetPx, expectedY, actualY: header.bottom,\n reason: `header under the phone bar is ${formatPx(offsetPx)} off one shell row` })\n }\n }\n return findings\n}\n\nfunction formatPx(value: number): string {\n return `${value > 0 ? '+' : ''}${Math.round(value * 100) / 100}px`\n}\n\n/**\n * Runs in the page (Playwright serializes it). A divider is the visible bottom\n * border of a wide, top-anchored element with no top border: header rows have\n * only a bottom divider, while inputs, cards and the inset surface draw a full\n * box and are skipped. Returns raw geometry; `judgeShellAlignment` decides.\n */\nexport function collectShellDividers(): Omit<ShellDividerSample, 'route' | 'width' | 'theme'> {\n const probe = document.createElement('div')\n probe.style.cssText = 'position:absolute;visibility:hidden;height:var(--shell-header-height, 3.5rem)'\n document.body.appendChild(probe)\n const shellHeaderPx = probe.getBoundingClientRect().height || 56\n probe.remove()\n\n const viewport = document.documentElement.clientWidth\n const describe = (el: Element): string => {\n const id = el.id ? `#${el.id}` : ''\n const classes = typeof el.className === 'string' ? el.className.trim().split(/\\s+/).filter((c) => !c.includes(':') && !c.includes('[')).slice(0, 3).map((c) => `.${c}`).join('') : ''\n const shell = el.hasAttribute('data-shell-header') ? '[data-shell-header]' : ''\n return `${el.tagName.toLowerCase()}${id}${classes}${shell}`\n }\n const controls = new Set(['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON', 'HR', 'TABLE', 'TR', 'TD', 'TH'])\n const visibleColor = (color: string) => !/^(transparent|rgba\\([^)]*,\\s*0\\))$/.test(color.trim())\n const rows: ShellDivider[] = []\n for (const el of Array.from(document.body.querySelectorAll('*'))) {\n if (controls.has(el.tagName) || el.closest('[role=\"dialog\"],[role=\"menu\"],[role=\"listbox\"],[data-radix-popper-content-wrapper]')) continue\n const rect = el.getBoundingClientRect()\n if (rect.width < 160 || rect.height < 20 || rect.top > 140 || rect.bottom > 240) continue\n const style = getComputedStyle(el)\n if (style.visibility === 'hidden' || style.display === 'none' || Number(style.opacity) === 0) continue\n const bottomWidth = Number.parseFloat(style.borderBottomWidth)\n if (!(bottomWidth > 0) || style.borderBottomStyle === 'none' || !visibleColor(style.borderBottomColor)) continue\n if (Number.parseFloat(style.borderTopWidth) > 0 && style.borderTopStyle !== 'none') continue\n rows.push({ label: describe(el), left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom })\n }\n\n // The rail sits at the left edge, narrower than the page; its first divider is its top row.\n const rail = rows\n .filter((r) => r.left < 2 && r.right < Math.min(480, viewport * 0.5) && r.top < 16)\n .sort((a, b) => a.bottom - b.bottom)[0] ?? null\n const phoneBar = rail ? null : rows\n .filter((r) => r.left < 2 && r.right > viewport - 2 && r.top < 2)\n .sort((a, b) => a.bottom - b.bottom)[0] ?? null\n const paneTop = phoneBar ? phoneBar.bottom : 0\n const headers = rows.filter((r) => r !== rail && r !== phoneBar\n && (!rail || r.left >= rail.right - 1)\n // A header row starts at or near the pane top: Hospitality's history header\n // started 28px down (and ended 28px low), so \"near\" is 48px, not a gutter.\n && r.top >= paneTop - 1 && r.top < paneTop + 48\n && r.bottom > paneTop + 20 && r.bottom < paneTop + 160)\n // Nested rows that share one divider line are one divider; keep the outermost.\n const unique = headers.filter((r, i) => !headers.some((o, j) => j !== i\n && Math.abs(o.bottom - r.bottom) < 0.01 && o.left <= r.left && o.right >= r.right && (o.right - o.left > r.right - r.left || j < i)))\n return { shellHeaderPx, rail, phoneBar, headers: unique }\n}\n\nexport interface ShellAlignmentOptions {\n readonly baseUrl: string\n readonly routes: readonly string[]\n readonly widths?: readonly number[]\n readonly themes?: readonly ('light' | 'dark')[]\n /** Playwright storage state (cookies, localStorage) for an authenticated app. */\n readonly storageState?: string\n /** Run in each page before the app loads, with `theme` in scope, to apply the app's own theme switch. */\n readonly themeScript?: string\n /** Write a screenshot per failing route and width here. */\n readonly screenshotDir?: string\n readonly tolerancePx?: number\n /** Wait for this selector after navigation (default `[data-shell-header]`). */\n readonly readySelector?: string\n}\n\nexport interface ShellAlignmentReport {\n /** Requests the run sent and its busiest 10 s (see browser-budget.ts). */\n readonly network?: NetworkCount\n readonly samples: readonly ShellDividerSample[]\n readonly findings: readonly ShellAlignmentFinding[]\n readonly maxOffsetPx: number\n}\n\nconst PHONE_HEIGHT = 844\nconst DESKTOP_HEIGHT = 900\n\n/** Drive Chromium over every route × width × theme and judge each page. Needs the optional `playwright` peer. */\nexport async function checkShellAlignment(options: ShellAlignmentOptions): Promise<ShellAlignmentReport> {\n const { chromium } = await import('playwright')\n const widths = options.widths ?? [1440, 390]\n const themes = options.themes ?? ['light', 'dark']\n const browser = await chromium.launch({ args: [...QUIET_CHROMIUM_ARGS] })\n const meter = createRequestMeter()\n const samples: ShellDividerSample[] = []\n const findings: ShellAlignmentFinding[] = []\n try {\n for (const width of widths) {\n for (const theme of themes) {\n const context = await browser.newContext({\n viewport: { width, height: width < 768 ? PHONE_HEIGHT : DESKTOP_HEIGHT },\n colorScheme: theme,\n ...(options.storageState ? { storageState: options.storageState } : {}),\n })\n if (options.themeScript) {\n await context.addInitScript({ content: `(() => { const theme = ${JSON.stringify(theme)}; ${options.themeScript} })()` })\n }\n const page = await context.newPage()\n await meterPage(page, meter)\n for (const route of options.routes) {\n // An app that polls never reaches network idle, so wait for the shell to\n // render and give in-flight data a short, capped settle.\n await meter.pace()\n await page.goto(new URL(route, options.baseUrl).toString(), { waitUntil: 'domcontentloaded' })\n await page.waitForSelector(options.readySelector ?? '[data-shell-header]', { state: 'visible', timeout: 15_000 }).catch(() => undefined)\n await page.waitForLoadState('networkidle', { timeout: 3_000 }).catch(() => undefined)\n await page.evaluate(() => document.fonts?.ready)\n const geometry = await page.evaluate(collectShellDividers)\n const sample: ShellDividerSample = { route, width, theme, ...geometry }\n samples.push(sample)\n const found = judgeShellAlignment(sample, options.tolerancePx)\n findings.push(...found)\n if (found.length && options.screenshotDir) {\n const name = `${route.replace(/[^a-z0-9]+/gi, '_').replace(/^_|_$/g, '') || 'root'}-${width}-${theme}.png`\n // Evidence only: a screenshot that stalls must not lose the measurement.\n await page.screenshot({ path: `${options.screenshotDir}/${name}`, timeout: 10_000, animations: 'disabled' }).catch(() => undefined)\n }\n }\n await context.close()\n }\n }\n } finally {\n await browser.close()\n }\n const maxOffsetPx = findings.reduce((max, f) => (Number.isFinite(f.offsetPx) ? Math.max(max, Math.abs(f.offsetPx)) : max), 0)\n return { samples, findings, maxOffsetPx, network: meter.count() }\n}\n\nexport function formatShellAlignmentReport(report: ShellAlignmentReport): string {\n const lines = [`shell alignment: ${report.samples.length} pages, ${report.findings.length} misaligned, max offset ${Math.round(report.maxOffsetPx * 100) / 100}px`]\n for (const f of report.findings) lines.push(` FAIL ${f.route} @${f.width} ${f.theme}: ${f.header} ${f.reason} (y ${round(f.actualY)} vs ${round(f.expectedY)})`)\n if (!report.findings.length) lines.push(' ok: every main header divider continues the rail\\'s first divider')\n return lines.join('\\n')\n}\n\nfunction round(value: number): string {\n return Number.isFinite(value) ? String(Math.round(value * 100) / 100) : '?'\n}\n","/**\n * `agent-app-signoff shell-alignment` — measure, in Chromium, that each route's\n * main header divider continues the sidebar rail's first divider.\n *\n * agent-app-signoff shell-alignment --base-url http://127.0.0.1:8787 \\\n * --route /app/w1/chat --route /app/w1/inbox --storage-state auth.json\n *\n * Exit 0 when every route, width and theme is within tolerance; 1 on any\n * misaligned divider; 2 on a usage error; 3 when every page passed but the\n * run's busiest 10 s went over the shared edge budget (browser-budget.ts).\n */\nimport { formatNetworkCount, networkExitCode } from './browser-budget'\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { checkShellAlignment, formatShellAlignmentReport, type ShellAlignmentOptions } from './shell-alignment'\n\nfunction shellAlignmentUsage(): string {\n return [\n 'Usage: agent-app-signoff shell-alignment --base-url <url> --route <path> [--route <path> ...] [options]',\n '',\n ' --widths <w,w> viewport widths (default 1440,390)',\n ' --themes <t,t> light,dark (default both)',\n ' --storage-state <file> Playwright storage state for an authenticated app',\n ' --theme-script <file> JS run before each page loads with `theme` in scope',\n ' --ready <selector> wait for this after navigation (default [data-shell-header])',\n ' --tolerance <px> allowed divider offset (default 0.5)',\n ' --screenshots <dir> screenshot each failing page here',\n ' --json <path> write every sample and finding',\n ].join('\\n')\n}\n\nexport class ShellAlignmentUsageError extends Error {}\n\nexport function parseShellAlignmentArgs(argv: readonly string[]): ShellAlignmentOptions & { readonly jsonPath?: string } {\n const routes: string[] = []\n let baseUrl: string | undefined\n const out: { -readonly [K in keyof ShellAlignmentOptions]?: ShellAlignmentOptions[K] } & { jsonPath?: string } = {}\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] as string\n const take = (): string => {\n const value = argv[index + 1]\n if (value === undefined) throw new ShellAlignmentUsageError(`${flag} needs a value`)\n index += 1\n return value\n }\n switch (flag) {\n case '--base-url': baseUrl = take(); break\n case '--route': routes.push(take()); break\n case '--widths': out.widths = take().split(',').map((w) => {\n const n = Number(w)\n if (!Number.isInteger(n) || n < 200) throw new ShellAlignmentUsageError(`--widths needs integers of at least 200, got \"${w}\"`)\n return n\n }); break\n case '--themes': out.themes = take().split(',').map((t) => {\n if (t !== 'light' && t !== 'dark') throw new ShellAlignmentUsageError(`--themes takes light and dark, got \"${t}\"`)\n return t\n }); break\n case '--storage-state': out.storageState = resolve(take()); break\n case '--theme-script': out.themeScript = readFileSync(resolve(take()), 'utf8'); break\n case '--ready': out.readySelector = take(); break\n case '--tolerance': {\n const n = Number(take())\n if (!(n >= 0)) throw new ShellAlignmentUsageError('--tolerance needs a non-negative number')\n out.tolerancePx = n\n break\n }\n case '--screenshots': out.screenshotDir = resolve(take()); break\n case '--json': out.jsonPath = take(); break\n default: throw new ShellAlignmentUsageError(`unknown option: ${flag}`)\n }\n }\n if (!baseUrl) throw new ShellAlignmentUsageError('--base-url is required')\n if (!routes.length) throw new ShellAlignmentUsageError('at least one --route is required')\n return { ...out, baseUrl, routes }\n}\n\nexport async function runShellAlignmentCli(argv: readonly string[]): Promise<number> {\n if (argv.includes('--help') || argv.includes('-h')) {\n process.stdout.write(`${shellAlignmentUsage()}\\n`)\n return 0\n }\n let options: ReturnType<typeof parseShellAlignmentArgs>\n try {\n options = parseShellAlignmentArgs(argv)\n } catch (error) {\n if (!(error instanceof ShellAlignmentUsageError)) throw error\n process.stderr.write(`agent-app-signoff shell-alignment: ${error.message}\\n\\n${shellAlignmentUsage()}\\n`)\n return 2\n }\n if (options.screenshotDir) mkdirSync(options.screenshotDir, { recursive: true })\n const report = await checkShellAlignment(options)\n if (options.jsonPath) {\n const abs = resolve(options.jsonPath)\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, `${JSON.stringify(report, null, 2)}\\n`)\n }\n process.stdout.write(`${formatShellAlignmentReport(report)}\\n`)\n if (report.network) process.stdout.write(`${formatNetworkCount(report.network)}\\n`)\n return report.findings.length ? 1 : networkExitCode(report.network)\n}\n","/**\n * Surface ladder: every card and field must step off the surface it sits on,\n * every field border must be visible against that surface, and a card's body\n * copy must stay one short line.\n *\n * Hospitality shipped cards painted the color of their parent, a search field\n * the color of the page, and cards carrying 20–40 words of body copy. Drew\n * rated it 0/10 for exactly that. This check measures the rendered page, so it\n * catches the flat step whatever token, class or override produced it.\n *\n * Rules (OKLCH lightness ×100, the same unit the brand ladder is specified in):\n * - card: a painted box with a radius of at least 6px, taller than 80px. Fails\n * when |ΔL| against its nearest painted ancestor is under 3.\n * - field: input, textarea, [role=combobox], [role=searchbox] and\n * .focus-field-within. Fails when |ΔL| is under 3. A transparent field inside\n * a .focus-field-within wrapper is skipped: the wrapper is the field.\n * - field border: fails when its contrast against the field's parent is under 3:1.\n * - card copy: each body-copy element inside a card (CardDescription, a header\n * or section paragraph: any <p>, since CardDescription carries no data-slot)\n * fails over 12 words. The element's own text is counted, not the card's\n * innerText, and clamped text counts in full. Chat transcript text is exempt.\n *\n * The browser half (`collectSurfaceLadder`) only reads computed colors and text;\n * the decision (`judgeSurfaceLadder`) and the color math are pure functions, so\n * they are unit-tested without a browser.\n */\n\nimport { createRequestMeter, meterPage, QUIET_CHROMIUM_ARGS, type NetworkCount } from './browser-budget'\n\n/** sRGB channels 0–255. */\nexport type Rgb = readonly [number, number, number]\n/** sRGB channels 0–255 plus alpha 0–1. */\nexport type Rgba = readonly [number, number, number, number]\n\nexport interface SurfaceBox {\n readonly kind: 'card' | 'field'\n readonly label: string\n readonly top: number\n readonly left: number\n readonly width: number\n readonly height: number\n /** The box's own computed background (alpha may be below 1). */\n readonly fill: Rgba\n /** The nearest painted ancestor's effective (composited, opaque) color. */\n readonly parent: Rgb\n readonly parentLabel: string\n /** The field's visible border color, or null when it draws none. Cards leave it null. */\n readonly border: Rgba | null\n /** Words in the card's whole innerText, for reporting only. */\n readonly words?: number\n}\n\nexport interface CopyBlock {\n readonly label: string\n /** The card the copy sits in. */\n readonly card: string\n readonly words: number\n readonly text: string\n}\n\nexport interface SurfaceSample {\n readonly route: string\n readonly width: number\n readonly theme: string\n readonly boxes: readonly SurfaceBox[]\n readonly copy: readonly CopyBlock[]\n}\n\nexport type SurfaceRule = 'card-step' | 'field-step' | 'field-border' | 'card-copy'\n\nexport interface SurfaceFinding {\n readonly route: string\n readonly width: number\n readonly theme: string\n readonly rule: SurfaceRule\n readonly target: string\n /** |ΔL|, contrast ratio, or word count, depending on the rule. */\n readonly value: number\n readonly limit: number\n readonly reason: string\n}\n\nexport interface SurfaceLadderLimits {\n /** Minimum |ΔL| (OKLCH L ×100) for a card or field against its parent. */\n readonly minDeltaL?: number\n /** Minimum contrast ratio of a field border against the field's parent. */\n readonly minBorderContrast?: number\n /** Maximum words in one body-copy element of a card. */\n readonly maxWords?: number\n}\n\nexport const SURFACE_LADDER_MIN_DELTA_L = 3\nexport const SURFACE_LADDER_MIN_BORDER_CONTRAST = 3\nexport const SURFACE_LADDER_MAX_WORDS = 12\n\n/** Alpha-composite `top` over an opaque `bottom`. */\nexport function composite(top: Rgba, bottom: Rgb): Rgb {\n const a = Math.min(1, Math.max(0, top[3]))\n return [0, 1, 2].map((i) => (top[i] as number) * a + (bottom[i] as number) * (1 - a)) as unknown as Rgb\n}\n\nfunction linear(channel: number): number {\n const c = channel / 255\n return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4\n}\n\n/** OKLab lightness of an sRGB color, ×100 (0 black … 100 white). */\nexport function oklchL(rgb: Rgb): number {\n const [r, g, b] = rgb.map(linear) as [number, number, number]\n const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b\n const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b\n const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b\n return 100 * (0.2104542553 * Math.cbrt(l) + 0.793617785 * Math.cbrt(m) - 0.0040720468 * Math.cbrt(s))\n}\n\n/** WCAG 2 contrast ratio between two opaque sRGB colors. */\nexport function contrastRatio(a: Rgb, b: Rgb): number {\n const luminance = (c: Rgb) => {\n const [r, g, bl] = c.map(linear) as [number, number, number]\n return 0.2126 * r + 0.7152 * g + 0.0722 * bl\n }\n const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x) as [number, number]\n return (hi + 0.05) / (lo + 0.05)\n}\n\n/** Signed ΔL of a box against its parent: positive when the box is lighter. */\nexport function surfaceDeltaL(box: Pick<SurfaceBox, 'fill' | 'parent'>): number {\n return oklchL(composite(box.fill, box.parent)) - oklchL(box.parent)\n}\n\nexport function judgeSurfaceLadder(sample: SurfaceSample, limits: SurfaceLadderLimits = {}): SurfaceFinding[] {\n const minDeltaL = limits.minDeltaL ?? SURFACE_LADDER_MIN_DELTA_L\n const minBorder = limits.minBorderContrast ?? SURFACE_LADDER_MIN_BORDER_CONTRAST\n const maxWords = limits.maxWords ?? SURFACE_LADDER_MAX_WORDS\n const where = { route: sample.route, width: sample.width, theme: sample.theme }\n const findings: SurfaceFinding[] = []\n for (const box of sample.boxes) {\n const delta = surfaceDeltaL(box)\n if (Math.abs(delta) < minDeltaL) {\n findings.push({ ...where, rule: box.kind === 'card' ? 'card-step' : 'field-step', target: box.label, value: round1(Math.abs(delta)), limit: minDeltaL,\n reason: `${box.kind} is ΔL ${signed(delta)} against ${box.parentLabel} (needs |ΔL| ≥ ${minDeltaL})` })\n }\n if (box.kind === 'field' && box.border) {\n const ratio = contrastRatio(composite(box.border, box.parent), box.parent)\n if (ratio < minBorder) {\n findings.push({ ...where, rule: 'field-border', target: box.label, value: round2(ratio), limit: minBorder,\n reason: `field border is ${round2(ratio)}:1 against ${box.parentLabel} (needs ${minBorder}:1)` })\n }\n }\n }\n for (const block of sample.copy) {\n if (block.words > maxWords) {\n findings.push({ ...where, rule: 'card-copy', target: `${block.card} › ${block.label}`, value: block.words, limit: maxWords,\n reason: `card body copy is ${block.words} words (max ${maxWords}): \"${block.text}\"` })\n }\n }\n return findings\n}\n\nfunction round1(value: number): number {\n return Math.round(value * 10) / 10\n}\nfunction round2(value: number): number {\n return Math.round(value * 100) / 100\n}\nfunction signed(value: number): string {\n return `${value >= 0 ? '+' : ''}${round1(value)}`\n}\n\n/**\n * Runs in the page (Playwright serializes it, so every helper lives inside).\n * Returns raw colors and text for the boxes the rules cover; `judgeSurfaceLadder` decides.\n */\nexport function collectSurfaceLadder(): Pick<SurfaceSample, 'boxes' | 'copy'> {\n type C4 = [number, number, number, number]\n type C3 = [number, number, number]\n const canvas = document.createElement('canvas')\n canvas.width = 1\n canvas.height = 1\n const ctx = canvas.getContext('2d', { willReadFrequently: true })\n const parseCache = new Map<string, C4 | null>()\n // Chromium serializes most colors as rgb()/rgba(); oklch(), lab() and color()\n // go through a canvas, which converts any CSS color to sRGB bytes.\n const parse = (css: string): C4 | null => {\n const hit = parseCache.get(css)\n if (hit !== undefined) return hit\n let out: C4 | null = null\n const m = css.match(/^rgba?\\(([^)]+)\\)$/)\n if (m) {\n const parts = (m[1] as string).split(/[\\s,/]+/).filter(Boolean).map((p) => (p.endsWith('%') ? Number.parseFloat(p) / 100 : Number(p)))\n out = [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0, parts[3] ?? 1]\n } else if (ctx && css && css !== 'none') {\n ctx.clearRect(0, 0, 1, 1)\n ctx.fillStyle = '#000'\n ctx.fillStyle = css\n ctx.fillRect(0, 0, 1, 1)\n const d = ctx.getImageData(0, 0, 1, 1).data\n out = [d[0] as number, d[1] as number, d[2] as number, (d[3] as number) / 255]\n }\n parseCache.set(css, out)\n return out\n }\n const PAINT_ALPHA = 0.1\n const blend = (top: C4, bottom: C3): C3 => [0, 1, 2].map((i) => (top[i] as number) * top[3] + (bottom[i] as number) * (1 - top[3])) as C3\n const describe = (el: Element): string => {\n const id = el.id ? `#${el.id}` : ''\n const slot = el.getAttribute('data-slot') ? `[data-slot=${el.getAttribute('data-slot')}]` : ''\n const role = el.getAttribute('role') ? `[role=${el.getAttribute('role')}]` : ''\n const classes = typeof el.className === 'string'\n ? el.className.trim().split(/\\s+/).filter((c) => c && !c.includes(':') && !c.includes('[') && !c.includes('/')).slice(0, 3).map((c) => `.${c}`).join('')\n : ''\n return `${el.tagName.toLowerCase()}${id}${slot}${role}${classes}`\n }\n const visible = (el: Element, style: CSSStyleDeclaration, rect: DOMRect) =>\n rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.display !== 'none' && Number(style.opacity) !== 0\n\n // Effective opaque color behind each element: its own fill composited over its parent's.\n const effective = new Map<Element, { color: C3; painter: Element | null }>()\n const canvasColor = (): C3 => {\n for (const el of [document.body, document.documentElement]) {\n const fill = parse(getComputedStyle(el).backgroundColor)\n if (fill && fill[3] >= PAINT_ALPHA) return [fill[0], fill[1], fill[2]]\n }\n return matchMedia('(prefers-color-scheme: dark)').matches ? [18, 18, 18] : [255, 255, 255]\n }\n const root = canvasColor()\n const effectiveOf = (el: Element | null): { color: C3; painter: Element | null } => {\n if (!el) return { color: root, painter: null }\n const known = effective.get(el)\n if (known) return known\n const below = effectiveOf(el.parentElement)\n const fill = parse(getComputedStyle(el).backgroundColor)\n const result = fill && fill[3] >= PAINT_ALPHA ? { color: blend(fill, below.color), painter: el } : below\n effective.set(el, result)\n return result\n }\n\n const fieldSelector = 'input:not([type=hidden]):not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]):not([type=submit]):not([type=button]):not([type=reset]):not([type=image]), textarea, [role=\"combobox\"], [role=\"searchbox\"], .focus-field-within'\n const overlay = '[role=\"dialog\"],[role=\"menu\"],[role=\"listbox\"],[role=\"tooltip\"],[data-radix-popper-content-wrapper]'\n const media = new Set(['IMG', 'VIDEO', 'CANVAS', 'SVG', 'svg', 'IFRAME', 'PICTURE'])\n const scope = Array.from(document.querySelectorAll('main, [role=\"main\"]'))\n const roots = scope.length ? scope.filter((el) => !scope.some((o) => o !== el && o.contains(el))) : [document.body]\n\n const boxes: SurfaceBox[] = []\n const cards: { el: Element; label: string }[] = []\n for (const el of roots.flatMap((r) => Array.from(r.querySelectorAll('*')))) {\n if (media.has(el.tagName) || el.closest(overlay)) continue\n const style = getComputedStyle(el)\n const rect = el.getBoundingClientRect()\n if (!visible(el, style, rect)) continue\n const isField = el.matches(fieldSelector)\n const fill = parse(style.backgroundColor) ?? [0, 0, 0, 0]\n const painted = fill[3] >= PAINT_ALPHA\n const base = { label: describe(el), top: rect.top + window.scrollY, left: rect.left, width: rect.width, height: rect.height, fill: fill as Rgba }\n if (isField) {\n if (rect.width < 40 || rect.height < 20) continue\n if (!painted && el.parentElement?.closest('.focus-field-within')) continue\n const parent = effectiveOf(el.parentElement)\n const sides = ['Top', 'Bottom', 'Left', 'Right'] as const\n const side = sides.find((s) => Number.parseFloat(style.getPropertyValue(`border-${s.toLowerCase()}-width`)) > 0\n && style.getPropertyValue(`border-${s.toLowerCase()}-style`) !== 'none')\n const borderFill = side ? parse(style.getPropertyValue(`border-${side.toLowerCase()}-color`)) : null\n const border = borderFill && borderFill[3] > 0 ? (borderFill as Rgba) : null\n boxes.push({ kind: 'field', ...base, parent: parent.color, parentLabel: parent.painter ? describe(parent.painter) : '(canvas)', border })\n continue\n }\n if (!painted || rect.height <= 80 || rect.width < 120) continue\n const radius = Math.max(...['border-top-left-radius', 'border-top-right-radius', 'border-bottom-left-radius', 'border-bottom-right-radius']\n .map((p) => Number.parseFloat(style.getPropertyValue(p)) || 0))\n if (radius < 6) continue\n const parent = effectiveOf(el.parentElement)\n const words = ((el as HTMLElement).innerText || '').split(/\\s+/).filter(Boolean).length\n boxes.push({ kind: 'card', ...base, parent: parent.color, parentLabel: parent.painter ? describe(parent.painter) : '(canvas)', border: null, words })\n cards.push({ el, label: base.label })\n }\n\n // Body copy: CardDescription, card header paragraphs and section paragraphs,\n // attributed to the innermost card that holds them. CardDescription renders a\n // bare <p> with no data-slot, so every paragraph inside a card counts; chat\n // transcript content is message text, not card copy.\n const copySelector = '[data-slot=\"card-description\"], p'\n const transcript = '[data-timeline-step], .prose, [role=\"log\"], pre, code'\n const copy: CopyBlock[] = []\n const seen = new Set<Element>()\n for (const el of roots.flatMap((r) => Array.from(r.querySelectorAll(copySelector)))) {\n if (seen.has(el) || el.closest(overlay) || el.closest(transcript) || el.closest(fieldSelector) || el.parentElement?.closest('[data-slot=\"card-description\"]')) continue\n seen.add(el)\n const style = getComputedStyle(el)\n if (!visible(el, style, el.getBoundingClientRect())) continue\n let card: { el: Element; label: string } | undefined\n for (let p = el.parentElement; p && !card; p = p.parentElement) card = cards.find((c) => c.el === p)\n if (!card) continue\n // textContent, not innerText: a line clamp hides words without removing them.\n const text = (el.textContent ?? '').replace(/\\s+/g, ' ').trim()\n const words = text ? text.split(' ').length : 0\n copy.push({ label: describe(el), card: card.label, words, text: text.length > 90 ? `${text.slice(0, 87)}…` : text })\n }\n return { boxes, copy }\n}\n\nexport interface SurfaceLadderOptions extends SurfaceLadderLimits {\n readonly baseUrl: string\n readonly routes: readonly string[]\n readonly widths?: readonly number[]\n readonly themes?: readonly ('light' | 'dark')[]\n /** Playwright storage state (cookies, localStorage) for an authenticated app. */\n readonly storageState?: string\n /** Run in each page before the app loads, with `theme` in scope, to apply the app's own theme switch. */\n readonly themeScript?: string\n /** Write a screenshot per failing route, width and theme here. */\n readonly screenshotDir?: string\n /** Wait for this selector after navigation (default `[data-shell-header]`). */\n readonly readySelector?: string\n /** Calibration only: CSS file contents added to each page before measuring, to test a proposed override. */\n readonly injectCss?: string\n}\n\nexport interface SurfacePageSummary {\n readonly route: string\n readonly width: number\n readonly theme: string\n readonly cards: number\n readonly flatCards: number\n readonly minCardDeltaL: number | null\n readonly fields: number\n readonly flatFields: number\n readonly minFieldDeltaL: number | null\n readonly weakBorders: number\n readonly copyBlocks: number\n readonly longCopy: number\n readonly maxCopyWords: number | null\n /** Median of each card's whole innerText word count (context, not a rule). */\n readonly medianCardWords: number | null\n}\n\nexport interface SurfaceLadderReport {\n /** Requests the run sent and its busiest 10 s (see browser-budget.ts). */\n readonly network?: NetworkCount\n readonly samples: readonly SurfaceSample[]\n readonly pages: readonly SurfacePageSummary[]\n readonly findings: readonly SurfaceFinding[]\n readonly countsByRule: Readonly<Record<SurfaceRule, number>>\n}\n\nexport function summarizeSurfacePage(sample: SurfaceSample, findings: readonly SurfaceFinding[]): SurfacePageSummary {\n const mine = findings.filter((f) => f.route === sample.route && f.width === sample.width && f.theme === sample.theme)\n const count = (rule: SurfaceRule) => mine.filter((f) => f.rule === rule).length\n const deltas = (kind: SurfaceBox['kind']) => sample.boxes.filter((b) => b.kind === kind).map((b) => Math.abs(surfaceDeltaL(b)))\n const min = (values: number[]) => (values.length ? round1(Math.min(...values)) : null)\n const cardWords = sample.boxes.filter((b) => b.kind === 'card').map((b) => b.words ?? 0).sort((a, b) => a - b)\n return {\n route: sample.route, width: sample.width, theme: sample.theme,\n cards: deltas('card').length, flatCards: count('card-step'), minCardDeltaL: min(deltas('card')),\n fields: deltas('field').length, flatFields: count('field-step'), minFieldDeltaL: min(deltas('field')),\n weakBorders: count('field-border'),\n copyBlocks: sample.copy.length, longCopy: count('card-copy'),\n maxCopyWords: sample.copy.length ? Math.max(...sample.copy.map((c) => c.words)) : null,\n medianCardWords: cardWords.length ? (cardWords[Math.floor(cardWords.length / 2)] as number) : null,\n }\n}\n\nconst PHONE_HEIGHT = 844\nconst DESKTOP_HEIGHT = 900\n\n/** Drive Chromium over every route × width × theme and judge each page. Needs the optional `playwright` peer. */\nexport async function checkSurfaceLadder(options: SurfaceLadderOptions): Promise<SurfaceLadderReport> {\n const { chromium } = await import('playwright')\n const widths = options.widths ?? [1440, 390]\n const themes = options.themes ?? ['light', 'dark']\n const browser = await chromium.launch({ args: [...QUIET_CHROMIUM_ARGS] })\n const meter = createRequestMeter()\n const samples: SurfaceSample[] = []\n const findings: SurfaceFinding[] = []\n try {\n for (const width of widths) {\n for (const theme of themes) {\n const context = await browser.newContext({\n viewport: { width, height: width < 768 ? PHONE_HEIGHT : DESKTOP_HEIGHT },\n colorScheme: theme,\n reducedMotion: 'reduce',\n ...(options.storageState ? { storageState: options.storageState } : {}),\n })\n if (options.themeScript) {\n await context.addInitScript({ content: `(() => { const theme = ${JSON.stringify(theme)}; ${options.themeScript} })()` })\n }\n const page = await context.newPage()\n await meterPage(page, meter)\n for (const route of options.routes) {\n await meter.pace()\n await page.goto(new URL(route, options.baseUrl).toString(), { waitUntil: 'domcontentloaded' })\n await page.waitForSelector(options.readySelector ?? '[data-shell-header]', { state: 'visible', timeout: 15_000 }).catch(() => undefined)\n await page.waitForLoadState('networkidle', { timeout: 3_000 }).catch(() => undefined)\n if (options.injectCss) await page.addStyleTag({ content: options.injectCss })\n await page.evaluate(() => document.fonts?.ready)\n // Let color transitions finish (reduced motion does not stop every one).\n await page.waitForTimeout(600)\n const collected = await page.evaluate(collectSurfaceLadder)\n const sample: SurfaceSample = { route, width, theme, ...collected }\n samples.push(sample)\n const found = judgeSurfaceLadder(sample, options)\n findings.push(...found)\n if (found.length && options.screenshotDir) {\n const name = `${route.replace(/[^a-z0-9]+/gi, '_').replace(/^_|_$/g, '') || 'root'}-${width}-${theme}.png`\n // Evidence only: a screenshot that stalls must not lose the measurement.\n await page.screenshot({ path: `${options.screenshotDir}/${name}`, timeout: 10_000, animations: 'disabled' }).catch(() => undefined)\n }\n }\n await context.close()\n }\n }\n } finally {\n await browser.close()\n }\n const countsByRule: Record<SurfaceRule, number> = { 'card-step': 0, 'field-step': 0, 'field-border': 0, 'card-copy': 0 }\n for (const f of findings) countsByRule[f.rule] += 1\n return { samples, pages: samples.map((s) => summarizeSurfacePage(s, findings)), findings, countsByRule, network: meter.count() }\n}\n\nexport function formatSurfaceLadderReport(report: SurfaceLadderReport): string {\n const c = report.countsByRule\n const lines = [\n `surface ladder: ${report.pages.length} pages, ${report.findings.length} failures (card-step ${c['card-step']}, field-step ${c['field-step']}, field-border ${c['field-border']}, card-copy ${c['card-copy']})`,\n ' route | width | theme | cards flat/total (min |ΔL|) | fields flat/total (min |ΔL|) | weak borders | long copy/blocks (max words) | median card words',\n ]\n for (const p of report.pages) {\n lines.push(` ${p.route} | ${p.width} | ${p.theme} | ${p.flatCards}/${p.cards} (${p.minCardDeltaL ?? '–'}) | ${p.flatFields}/${p.fields} (${p.minFieldDeltaL ?? '–'}) | ${p.weakBorders} | ${p.longCopy}/${p.copyBlocks} (${p.maxCopyWords ?? '–'}) | ${p.medianCardWords ?? '–'}`)\n }\n for (const f of report.findings) lines.push(` FAIL ${f.rule} ${f.route} @${f.width} ${f.theme}: ${f.target} ${f.reason}`)\n if (!report.findings.length) lines.push(' ok: every card and field steps off its parent, field borders read, and card copy is one short line')\n return lines.join('\\n')\n}\n","/**\n * `agent-app-signoff surface-ladder` — measure, in Chromium, that each route's\n * cards and fields step off the surface they sit on, field borders read, and\n * card body copy stays one short line.\n *\n * agent-app-signoff surface-ladder --base-url http://127.0.0.1:8787 \\\n * --route /workspaces/w1/connections --route /workspaces/w1/overview --storage-state auth.json\n *\n * Exit 0 when every route, width and theme passes; 1 on any failure; 2 on a usage error;\n * 3 when the pages passed but the run went over the shared edge budget.\n */\nimport { formatNetworkCount, networkExitCode } from './browser-budget'\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { checkSurfaceLadder, formatSurfaceLadderReport, type SurfaceLadderOptions } from './surface-ladder'\n\nfunction surfaceLadderUsage(): string {\n return [\n 'Usage: agent-app-signoff surface-ladder --base-url <url> --route <path> [--route <path> ...] [options]',\n '',\n ' --widths <w,w> viewport widths (default 1440,390)',\n ' --themes <t,t> light,dark (default both)',\n ' --storage-state <file> Playwright storage state for an authenticated app',\n ' --theme-script <file> JS run before each page loads with `theme` in scope',\n ' --ready <selector> wait for this after navigation (default [data-shell-header])',\n ' --tolerance <L> minimum |ΔL| (OKLCH L x100) for a card or field (default 3)',\n ' --min-border-contrast <r> minimum field border contrast against its parent (default 3)',\n ' --max-words <n> maximum words in one card body-copy element (default 12)',\n ' --inject-css <file> calibration only: add this stylesheet to each page before measuring',\n ' --screenshots <dir> screenshot each failing page here',\n ' --json <path> write every sample and finding',\n ].join('\\n')\n}\n\nexport class SurfaceLadderUsageError extends Error {}\n\nexport function parseSurfaceLadderArgs(argv: readonly string[]): SurfaceLadderOptions & { readonly jsonPath?: string } {\n const routes: string[] = []\n let baseUrl: string | undefined\n const out: { -readonly [K in keyof SurfaceLadderOptions]?: SurfaceLadderOptions[K] } & { jsonPath?: string } = {}\n for (let index = 0; index < argv.length; index += 1) {\n const flag = argv[index] as string\n const take = (): string => {\n const value = argv[index + 1]\n if (value === undefined) throw new SurfaceLadderUsageError(`${flag} needs a value`)\n index += 1\n return value\n }\n const nonNegative = (): number => {\n const n = Number(take())\n if (!(n >= 0)) throw new SurfaceLadderUsageError(`${flag} needs a non-negative number`)\n return n\n }\n switch (flag) {\n case '--base-url': baseUrl = take(); break\n case '--route': routes.push(take()); break\n case '--widths': out.widths = take().split(',').map((w) => {\n const n = Number(w)\n if (!Number.isInteger(n) || n < 200) throw new SurfaceLadderUsageError(`--widths needs integers of at least 200, got \"${w}\"`)\n return n\n }); break\n case '--themes': out.themes = take().split(',').map((t) => {\n if (t !== 'light' && t !== 'dark') throw new SurfaceLadderUsageError(`--themes takes light and dark, got \"${t}\"`)\n return t\n }); break\n case '--storage-state': out.storageState = resolve(take()); break\n case '--theme-script': out.themeScript = readFileSync(resolve(take()), 'utf8'); break\n case '--ready': out.readySelector = take(); break\n case '--tolerance': out.minDeltaL = nonNegative(); break\n case '--min-border-contrast': out.minBorderContrast = nonNegative(); break\n case '--max-words': {\n const n = Number(take())\n if (!Number.isInteger(n) || n < 1) throw new SurfaceLadderUsageError('--max-words needs a positive integer')\n out.maxWords = n\n break\n }\n case '--inject-css': out.injectCss = readFileSync(resolve(take()), 'utf8'); break\n case '--screenshots': out.screenshotDir = resolve(take()); break\n case '--json': out.jsonPath = take(); break\n default: throw new SurfaceLadderUsageError(`unknown option: ${flag}`)\n }\n }\n if (!baseUrl) throw new SurfaceLadderUsageError('--base-url is required')\n if (!routes.length) throw new SurfaceLadderUsageError('at least one --route is required')\n return { ...out, baseUrl, routes }\n}\n\nexport async function runSurfaceLadderCli(argv: readonly string[]): Promise<number> {\n if (argv.includes('--help') || argv.includes('-h')) {\n process.stdout.write(`${surfaceLadderUsage()}\\n`)\n return 0\n }\n let options: ReturnType<typeof parseSurfaceLadderArgs>\n try {\n options = parseSurfaceLadderArgs(argv)\n } catch (error) {\n if (!(error instanceof SurfaceLadderUsageError)) throw error\n process.stderr.write(`agent-app-signoff surface-ladder: ${error.message}\\n\\n${surfaceLadderUsage()}\\n`)\n return 2\n }\n if (options.screenshotDir) mkdirSync(options.screenshotDir, { recursive: true })\n const report = await checkSurfaceLadder(options)\n if (options.jsonPath) {\n const abs = resolve(options.jsonPath)\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, `${JSON.stringify(report, null, 2)}\\n`)\n }\n process.stdout.write(`${formatSurfaceLadderReport(report)}\\n`)\n if (report.network) process.stdout.write(`${formatNetworkCount(report.network)}\\n`)\n return report.findings.length ? 1 : networkExitCode(report.network)\n}\n","/**\n * Workspace surface: every route of a workspace renders exactly one shared\n * floating panel (sandbox-ui `WorkspaceSurface`, or `WorkspaceLayout` with\n * `surface=\"inset\"`), and that panel's first row is an inset `ShellHeader`.\n *\n * Drew's review of Creative asked for \"ONE skeleton\": the chat's rounded panel\n * as the layout of Studio, Assets, Tasks, Activity, Vault, the terminal and\n * Integrations. A page with its own skeleton has no `[data-workspace-surface]`,\n * or a header that is not the shell row, and this check names it. It measures\n * the rendered page, so a wrapper that only looks right in the source cannot\n * pass it.\n */\n\nimport { createRequestMeter, meterPage, QUIET_CHROMIUM_ARGS, type NetworkCount } from './browser-budget'\n\nexport interface WorkspaceSurfaceSample {\n readonly route: string\n readonly width: number\n readonly theme: string\n /** Visible `[data-workspace-surface]` elements on the page. */\n readonly surfaces: number\n /** The first surface's first header row: `inset`, `flat`, or null when it has none. */\n readonly header: 'inset' | 'flat' | null\n /** px between the surface's top edge and its header's top edge. */\n readonly headerOffsetPx: number | null\n}\n\nexport interface WorkspaceSurfaceFinding {\n readonly route: string\n readonly width: number\n readonly theme: string\n readonly reason: string\n}\n\n/** A header within this distance of the panel top is its first row (a 1px border). */\nexport const HEADER_TOP_TOLERANCE_PX = 2\n\nexport function judgeWorkspaceSurface(sample: WorkspaceSurfaceSample): WorkspaceSurfaceFinding[] {\n const where = { route: sample.route, width: sample.width, theme: sample.theme }\n if (sample.surfaces === 0) {\n return [{ ...where, reason: 'not on the shared panel: no [data-workspace-surface] (use WorkspaceSurface or WorkspaceLayout surface=\"inset\")' }]\n }\n if (sample.surfaces > 1) return [{ ...where, reason: `${sample.surfaces} workspace surfaces on one page; a page has exactly one panel` }]\n if (sample.header !== 'inset') {\n return [{ ...where, reason: sample.header === 'flat'\n ? 'the panel header is a flat ShellHeader; inside the panel it must be inset so its divider meets the rail'\n : 'the panel has no ShellHeader row' }]\n }\n if (sample.headerOffsetPx === null || sample.headerOffsetPx > HEADER_TOP_TOLERANCE_PX) {\n return [{ ...where, reason: `the ShellHeader is ${sample.headerOffsetPx ?? '?'}px below the panel top; it must be the panel's first row` }]\n }\n return []\n}\n\n/** Runs in the page. Reads geometry only; `judgeWorkspaceSurface` decides. */\nexport function collectWorkspaceSurface(): Omit<WorkspaceSurfaceSample, 'route' | 'width' | 'theme'> {\n const visible = (el: Element) => {\n const r = el.getBoundingClientRect()\n const cs = getComputedStyle(el)\n return r.width > 0 && r.height > 0 && cs.visibility !== 'hidden' && cs.display !== 'none'\n }\n const surfaces = Array.from(document.querySelectorAll('[data-workspace-surface]')).filter(visible)\n const first = surfaces[0]\n if (!first) return { surfaces: 0, header: null, headerOffsetPx: null }\n const header = Array.from(first.querySelectorAll('[data-shell-header]')).find(visible)\n if (!header) return { surfaces: surfaces.length, header: null, headerOffsetPx: null }\n const offset = header.getBoundingClientRect().top - first.getBoundingClientRect().top\n return {\n surfaces: surfaces.length,\n header: header.getAttribute('data-shell-header') === 'inset' ? 'inset' : 'flat',\n headerOffsetPx: Math.round(offset * 100) / 100,\n }\n}\n\nexport interface WorkspaceSurfaceOptions {\n readonly baseUrl: string\n readonly routes: readonly string[]\n readonly widths?: readonly number[]\n readonly themes?: readonly ('light' | 'dark')[]\n readonly storageState?: string\n readonly themeScript?: string\n readonly screenshotDir?: string\n readonly readySelector?: string\n}\n\nexport interface WorkspaceSurfaceReport {\n /** Requests the run sent and its busiest 10 s (see browser-budget.ts). */\n readonly network?: NetworkCount\n readonly samples: readonly WorkspaceSurfaceSample[]\n readonly findings: readonly WorkspaceSurfaceFinding[]\n}\n\n/** Drive Chromium over every route × width × theme. Needs the optional `playwright` peer. */\nexport async function checkWorkspaceSurface(options: WorkspaceSurfaceOptions): Promise<WorkspaceSurfaceReport> {\n const { chromium } = await import('playwright')\n const browser = await chromium.launch({ args: [...QUIET_CHROMIUM_ARGS] })\n const meter = createRequestMeter()\n const samples: WorkspaceSurfaceSample[] = []\n const findings: WorkspaceSurfaceFinding[] = []\n try {\n for (const width of options.widths ?? [1440, 390]) {\n for (const theme of options.themes ?? ['light', 'dark']) {\n const context = await browser.newContext({\n viewport: { width, height: width < 768 ? 844 : 900 },\n colorScheme: theme,\n ...(options.storageState ? { storageState: options.storageState } : {}),\n })\n if (options.themeScript) {\n await context.addInitScript({ content: `(() => { const theme = ${JSON.stringify(theme)}; ${options.themeScript} })()` })\n }\n const page = await context.newPage()\n await meterPage(page, meter)\n for (const route of options.routes) {\n await meter.pace()\n await page.goto(new URL(route, options.baseUrl).toString(), { waitUntil: 'domcontentloaded' })\n await page.waitForSelector(options.readySelector ?? '[data-shell-header]', { state: 'visible', timeout: 15_000 }).catch(() => undefined)\n await page.waitForLoadState('networkidle', { timeout: 3_000 }).catch(() => undefined)\n const sample: WorkspaceSurfaceSample = { route, width, theme, ...(await page.evaluate(collectWorkspaceSurface)) }\n samples.push(sample)\n const found = judgeWorkspaceSurface(sample)\n findings.push(...found)\n if (found.length && options.screenshotDir) {\n const name = `${route.replace(/[^a-z0-9]+/gi, '_').replace(/^_|_$/g, '') || 'root'}-${width}-${theme}.png`\n await page.screenshot({ path: `${options.screenshotDir}/${name}`, timeout: 10_000 }).catch(() => undefined)\n }\n }\n await context.close()\n }\n }\n } finally {\n await browser.close()\n }\n return { samples, findings, network: meter.count() }\n}\n\nexport function formatWorkspaceSurfaceReport(report: WorkspaceSurfaceReport): string {\n const lines = [`workspace surface: ${report.samples.length} pages, ${report.findings.length} off the shared panel`]\n for (const f of report.findings) lines.push(` FAIL ${f.route} @${f.width} ${f.theme}: ${f.reason}`)\n if (!report.findings.length) lines.push(' ok: every page sits on one shared panel under an inset shell header')\n return lines.join('\\n')\n}\n","/**\n * `agent-app-signoff workspace-surface` — every route renders one shared\n * floating panel whose first row is an inset ShellHeader.\n *\n * agent-app-signoff workspace-surface --base-url http://127.0.0.1:8787 \\\n * --route /app/w1/assets --route /app/w1/tasks --storage-state auth.json\n *\n * Same options as `shell-alignment` (it ignores --tolerance). Exit 0 when every\n * page is on the panel, 1 on any page that is not, 2 on a usage error, 3 when\n * the pages passed but the run went over the shared edge budget.\n */\nimport { formatNetworkCount, networkExitCode } from './browser-budget'\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { parseShellAlignmentArgs, ShellAlignmentUsageError } from './shell-alignment-cli'\nimport { checkWorkspaceSurface, formatWorkspaceSurfaceReport } from './workspace-surface'\n\nconst USAGE = [\n 'Usage: agent-app-signoff workspace-surface --base-url <url> --route <path> [--route <path> ...] [options]',\n '',\n ' --widths <w,w> viewport widths (default 1440,390)',\n ' --themes <t,t> light,dark (default both)',\n ' --storage-state <file> Playwright storage state for an authenticated app',\n ' --theme-script <file> JS run before each page loads with `theme` in scope',\n ' --ready <selector> wait for this after navigation (default [data-shell-header])',\n ' --screenshots <dir> screenshot each failing page here',\n ' --json <path> write every sample and finding',\n].join('\\n')\n\nexport async function runWorkspaceSurfaceCli(argv: readonly string[]): Promise<number> {\n if (argv.includes('--help') || argv.includes('-h')) {\n process.stdout.write(`${USAGE}\\n`)\n return 0\n }\n let options: ReturnType<typeof parseShellAlignmentArgs>\n try {\n options = parseShellAlignmentArgs(argv)\n } catch (error) {\n if (!(error instanceof ShellAlignmentUsageError)) throw error\n process.stderr.write(`agent-app-signoff workspace-surface: ${error.message}\\n\\n${USAGE}\\n`)\n return 2\n }\n if (options.screenshotDir) mkdirSync(options.screenshotDir, { recursive: true })\n const report = await checkWorkspaceSurface(options)\n if (options.jsonPath) {\n const abs = resolve(options.jsonPath)\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, `${JSON.stringify(report, null, 2)}\\n`)\n }\n process.stdout.write(`${formatWorkspaceSurfaceReport(report)}\\n`)\n if (report.network) process.stdout.write(`${formatNetworkCount(report.network)}\\n`)\n return report.findings.length ? 1 : networkExitCode(report.network)\n}\n"],"mappings":"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","names":["existsSync","readFileSync","join","spawnSync","existsSync","join","join","existsSync","spawnSync","existsSync","join","readFileSync","spawnSync","randomUUID","existsSync","basename","join","resolve","spawnSync","existsSync","readFileSync","rmSync","statSync","basename","join","resolve","git","existsSync","readFileSync","join","existsSync","readdirSync","readFileSync","join","majorOf","major","join","existsSync","readFileSync","resolve","createHash","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","basename","join","relative","sep","entries","spawnSync","createHash","existsSync","mkdirSync","rmSync","writeFileSync","dirname","join","resolve","join","spawnSync","resolve","basename","randomUUID","existsSync","window","ms","expectedY","mkdirSync","readFileSync","writeFileSync","dirname","resolve","resolve","readFileSync","mkdirSync","dirname","writeFileSync","parent","PHONE_HEIGHT","DESKTOP_HEIGHT","mkdirSync","readFileSync","writeFileSync","dirname","resolve","resolve","readFileSync","mkdirSync","dirname","writeFileSync","mkdirSync","writeFileSync","dirname","resolve","mkdirSync","resolve","dirname","writeFileSync"]}