From: Jérôme Benoit Date: Thu, 7 May 2026 06:49:45 +0000 (+0200) Subject: refactor(sandcastle): organize constants by domain with coherent naming X-Git-Tag: cli@v4.7.0~28 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=51b8731824b8a911f4910f02ad735cd4da76a93f;p=e-mobility-charging-stations-simulator.git refactor(sandcastle): organize constants by domain with coherent naming --- diff --git a/.sandcastle/constants.ts b/.sandcastle/constants.ts index bd6a9635..eb647597 100644 --- a/.sandcastle/constants.ts +++ b/.sandcastle/constants.ts @@ -1,17 +1,31 @@ import { execFileSync } from 'node:child_process' import { existsSync } from 'node:fs' -export const AGENT_IDLE_TIMEOUT_S = 300 +// ── Agent ──────────────────────────────────────────────────────────────────── export const AGENT_ACTOR_MODEL = 'github-copilot/claude-sonnet-4.6' export const AGENT_CRITIC_MODEL = 'github-copilot/gpt-5.4' -export const BRANCH_PREFIX = 'agent/issue' +export const AGENT_IDLE_TIMEOUT_S = 300 -export const COMPLETION_SIGNAL = 'COMPLETE' +export const AGENT_ITERATION_BUDGET = 50 -export const CONTEXT_HASH_RADIUS = 3 +export const AGENT_MAX_CRITIC_ROUNDS = 10 + +export const AGENT_PLANNER_MODEL = 'github-copilot/claude-opus-4.6' + +export const AGENT_TASK_TIMEOUT_MS = 6_000_000 + +// ── Git ────────────────────────────────────────────────────────────────────── + +export const GIT_BRANCH_PREFIX = 'agent/issue' + +export const GIT_PUSH_TIMEOUT_MS = 60_000 + +export const GIT_TIMEOUT_MS = 30_000 + +// ── Docker ─────────────────────────────────────────────────────────────────── export const DOCKER_IMAGE = 'sandcastle-sandbox' @@ -41,35 +55,33 @@ function resolvePnpmStorePath (): string | undefined { } } -export const GIT_TIMEOUT_MS = 30_000 - -export const GRACE_TIMEOUT_MS = 30_000 +// ── GitHub ─────────────────────────────────────────────────────────────────── -export const HASH_PREFIX_LENGTH = 16 +export const GITHUB_ISSUE_LABEL = 'sandcastle' -export const ITERATION_BUDGET_PER_ROUND = 50 +export const GITHUB_MAX_ISSUES_FETCH = 50 -export const ISSUE_LABEL = 'sandcastle' +export const GITHUB_MAX_PRS_FETCH = 200 -export const MAX_ISSUES_FETCH = 50 +// ── Validation ─────────────────────────────────────────────────────────────── -export const MAX_PRS_FETCH = 200 +export const VALIDATION_COMMAND = + 'pnpm format && pnpm typecheck && pnpm lint && pnpm build && pnpm test' -export const MAX_PARALLEL = 5 +export const VALIDATION_TIMEOUT_MS = 300_000 -export const MAX_STDERR_CHARS = 500 +// ── Limits & Protocol ──────────────────────────────────────────────────────── -export const MAX_CRITIC_ROUNDS = 10 +export const COMPLETION_SIGNAL = 'COMPLETE' -export const MAX_TITLE_LENGTH = 200 +export const CONTEXT_HASH_RADIUS = 3 -export const AGENT_PLANNER_MODEL = 'github-copilot/claude-opus-4.6' +export const GRACE_TIMEOUT_MS = 30_000 -export const PUSH_TIMEOUT_MS = 60_000 +export const HASH_PREFIX_LENGTH = 16 -export const TASK_TIMEOUT_MS = 100 * 60 * 1000 +export const MAX_PARALLEL = 5 -export const VALIDATION_COMMAND = - 'pnpm format && pnpm typecheck && pnpm lint && pnpm build && pnpm test' +export const MAX_STDERR_CHARS = 500 -export const VALIDATION_TIMEOUT_MS = 300_000 +export const MAX_TITLE_CHARS = 200 diff --git a/.sandcastle/finalizer.ts b/.sandcastle/finalizer.ts index a5831107..7ff3f89d 100644 --- a/.sandcastle/finalizer.ts +++ b/.sandcastle/finalizer.ts @@ -3,9 +3,9 @@ import crypto from 'node:crypto' import type { LoopResult, TaskSpec } from './types.js' import { + GIT_PUSH_TIMEOUT_MS, GIT_TIMEOUT_MS, MAX_STDERR_CHARS, - PUSH_TIMEOUT_MS, VALIDATION_COMMAND, VALIDATION_TIMEOUT_MS, } from './constants.js' @@ -124,7 +124,7 @@ export async function pushBranch ( try { await execFileAsync('git', ['push', '--force-with-lease', 'origin', 'HEAD'], { cwd, - timeout: PUSH_TIMEOUT_MS, + timeout: GIT_PUSH_TIMEOUT_MS, }) return true } catch (pushErr: unknown) { @@ -136,7 +136,7 @@ export async function pushBranch ( ['push', 'origin', `HEAD:refs/heads/rescue/${spec.branch}-${suffix}`], { cwd, - timeout: PUSH_TIMEOUT_MS, + timeout: GIT_PUSH_TIMEOUT_MS, } ) console.warn( @@ -153,7 +153,7 @@ export async function pushBranch ( try { await execFileAsync('git', ['push', '-u', 'origin', 'HEAD'], { cwd, - timeout: PUSH_TIMEOUT_MS, + timeout: GIT_PUSH_TIMEOUT_MS, }) return true } catch (pushErr: unknown) { diff --git a/.sandcastle/main.ts b/.sandcastle/main.ts index e42ea879..0e76bb22 100644 --- a/.sandcastle/main.ts +++ b/.sandcastle/main.ts @@ -5,23 +5,23 @@ import type { TaskSpec } from './types.js' import { ConcurrencyPool } from './concurrency-pool.js' import { - BRANCH_PREFIX, + AGENT_ITERATION_BUDGET, + AGENT_MAX_CRITIC_ROUNDS, + AGENT_TASK_TIMEOUT_MS, DOCKER_IMAGE, DOCKER_MOUNTS, - ISSUE_LABEL, - ITERATION_BUDGET_PER_ROUND, - MAX_CRITIC_ROUNDS, + GIT_BRANCH_PREFIX, + GITHUB_ISSUE_LABEL, MAX_PARALLEL, - TASK_TIMEOUT_MS, } from './constants.js' import { runRefinementLoop } from './refinement-loop.js' import { implementStrategy } from './strategies/implement/strategy.js' import { GithubIssueSource } from './task-source.js' const source = new GithubIssueSource({ - branchPrefix: BRANCH_PREFIX, + branchPrefix: GIT_BRANCH_PREFIX, dockerImage: DOCKER_IMAGE, - label: ISSUE_LABEL, + label: GITHUB_ISSUE_LABEL, }) let tasks: TaskSpec[] @@ -43,8 +43,8 @@ if (tasks.length === 0) { pool.run(async () => { const ac = new AbortController() const timer = setTimeout(() => { - ac.abort(new Error(`Task #${spec.id} timed out after ${String(TASK_TIMEOUT_MS)}ms`)) - }, TASK_TIMEOUT_MS) + ac.abort(new Error(`Task #${spec.id} timed out after ${String(AGENT_TASK_TIMEOUT_MS)}ms`)) + }, AGENT_TASK_TIMEOUT_MS) timer.unref() try { @@ -58,8 +58,8 @@ if (tasks.length === 0) { }) const loopResult = await runRefinementLoop(spec, sandbox, implementStrategy, { - iterationBudget: ITERATION_BUDGET_PER_ROUND, - maxRounds: MAX_CRITIC_ROUNDS, + iterationBudget: AGENT_ITERATION_BUDGET, + maxRounds: AGENT_MAX_CRITIC_ROUNDS, postLoopValidationRetry: true, signal: ac.signal, }) diff --git a/.sandcastle/refinement-loop.ts b/.sandcastle/refinement-loop.ts index 9983e518..32456337 100644 --- a/.sandcastle/refinement-loop.ts +++ b/.sandcastle/refinement-loop.ts @@ -16,11 +16,11 @@ import { AGENT_ACTOR_MODEL, AGENT_CRITIC_MODEL, AGENT_IDLE_TIMEOUT_S, + AGENT_ITERATION_BUDGET, + AGENT_MAX_CRITIC_ROUNDS, COMPLETION_SIGNAL, CONTEXT_HASH_RADIUS, HASH_PREFIX_LENGTH, - ITERATION_BUDGET_PER_ROUND, - MAX_CRITIC_ROUNDS, } from './constants.js' import { runValidation } from './finalizer.js' import { parseFindingsSafe } from './types.js' @@ -568,8 +568,8 @@ async function resetToBestState ( */ function resolveLoopOptions (opts: RefinementLoopOptions | undefined): ResolvedLoopOptions { return { - budget: opts?.iterationBudget ?? ITERATION_BUDGET_PER_ROUND, - maxRounds: opts?.maxRounds ?? MAX_CRITIC_ROUNDS, + budget: opts?.iterationBudget ?? AGENT_ITERATION_BUDGET, + maxRounds: opts?.maxRounds ?? AGENT_MAX_CRITIC_ROUNDS, onRoundComplete: opts?.onRoundComplete ?? (() => undefined), } } diff --git a/.sandcastle/task-source.ts b/.sandcastle/task-source.ts index 7e71897c..7bf6e812 100644 --- a/.sandcastle/task-source.ts +++ b/.sandcastle/task-source.ts @@ -10,10 +10,10 @@ import { COMPLETION_SIGNAL, DOCKER_MOUNTS, GIT_TIMEOUT_MS, - MAX_ISSUES_FETCH, - MAX_PRS_FETCH, - MAX_TITLE_LENGTH, - TASK_TIMEOUT_MS, + GITHUB_MAX_ISSUES_FETCH, + GITHUB_MAX_PRS_FETCH, + AGENT_TASK_TIMEOUT_MS, + MAX_TITLE_CHARS, } from './constants.js' import { execFileAsync, toErrorMessage } from './utils.js' @@ -107,7 +107,7 @@ export class GithubIssueSource implements TaskSource { }, promptFile: './.sandcastle/plan-prompt.md', sandbox: docker({ imageName: this.dockerImage, mounts: [...DOCKER_MOUNTS] }), - signal: AbortSignal.timeout(TASK_TIMEOUT_MS), + signal: AbortSignal.timeout(AGENT_TASK_TIMEOUT_MS), }) } catch (err: unknown) { console.error(`Planner timed out or failed: ${toErrorMessage(err)}`) @@ -166,7 +166,7 @@ export class GithubIssueSource implements TaskSource { '--json', 'number,title,labels,body', '--limit', - String(MAX_ISSUES_FETCH), + String(GITHUB_MAX_ISSUES_FETCH), '--label', this.label, ], @@ -210,7 +210,7 @@ export class GithubIssueSource implements TaskSource { '--json', 'headRefName', '--limit', - String(MAX_PRS_FETCH), + String(GITHUB_MAX_PRS_FETCH), ], { encoding: 'utf-8', maxBuffer: 8 * 1024 * 1024, timeout: GIT_TIMEOUT_MS } ) @@ -249,7 +249,7 @@ export class GithubIssueSource implements TaskSource { if (typeof item.id !== 'string' || !/^\d+$/.test(item.id)) return false if (typeof item.branch !== 'string' || !this.branchPattern.test(item.branch)) return false if (typeof item.title !== 'string') return false - if (item.title.length > MAX_TITLE_LENGTH) return false + if (item.title.length > MAX_TITLE_CHARS) return false // eslint-disable-next-line no-control-regex if (/[\x00-\x1f]/.test(item.title)) return false return true