mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-13 03:48:06 +01:00
Merge origin/main (v1.92.20.0) into the seed-ceiling splits (rule 19 grant 2, GSTA-36)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
commit
4de074cdc9
258 files changed
+15205
-1607
No files matched your search
@@ -10,6 +10,8 @@ export type CsoRuntimeBuildStack = typeof CSO_RUNTIME_STACKS[number];
|
||||
|
||||
const IMAGE = /^[a-z0-9.-]+(?::[0-9]+)?\/[a-z0-9][a-z0-9._/-]*@sha256:[a-f0-9]{64}$/;
|
||||
const TAGGED_IMAGE = /^[a-z0-9.-]+(?::[0-9]+)?\/[a-z0-9][a-z0-9._/-]*:[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
||||
const RELEASE_TAG = /:v?\d+\.\d+\.\d+(?:[._-][A-Za-z0-9._-]*)?$/;
|
||||
const TWO_PART_RELEASE_TAG = /:v?\d+\.\d+(?:\.\d+)?(?:[._-][A-Za-z0-9._-]*)?$/;
|
||||
const REVISION = /^[a-z0-9][a-z0-9._-]{0,100}$/;
|
||||
const REQUIRED_VERSIONS: Record<CsoRuntimeBuildStack, string[]> = {
|
||||
node: ['node', 'npm', 'cso-preparation'],
|
||||
@@ -56,8 +58,9 @@ function repositoryOfTag(image: string): string {
|
||||
return image.slice(0, colon);
|
||||
}
|
||||
|
||||
function assertPinnedFamily(source: unknown, indexImage: unknown, images: unknown, label: string): Record<CsoRuntimeBuildPlatform, string> {
|
||||
function assertPinnedFamily(source: unknown, indexImage: unknown, images: unknown, label: string, releaseTag = RELEASE_TAG): Record<CsoRuntimeBuildPlatform, string> {
|
||||
if (typeof source !== 'string' || !TAGGED_IMAGE.test(source)) throw new Error(`INVALID_${label}_SOURCE`);
|
||||
if (!releaseTag.test(source)) throw new Error(`FLOATING_${label}_SOURCE: ${source} must name an exact release version, not a moving major, minor or alias tag`);
|
||||
if (typeof indexImage !== 'string' || !IMAGE.test(indexImage)) throw new Error(`UNPINNED_${label}_INDEX`);
|
||||
if (!record(images)) throw new Error(`MISSING_${label}_IMAGES`);
|
||||
const repository = repositoryOfTag(source);
|
||||
@@ -101,7 +104,7 @@ export function imageBuildMatrix(input: unknown): { include: ImageBuildRow[] } {
|
||||
if (typeof stack !== 'string' || !CSO_RUNTIME_STACKS.includes(stack as CsoRuntimeBuildStack) || seenStacks.has(stack)) throw new Error('INVALID_STACK');
|
||||
seenStacks.add(stack);
|
||||
const typedStack = stack as CsoRuntimeBuildStack;
|
||||
const bases = assertPinnedFamily(source, indexImage, baseImages, 'BASE');
|
||||
const bases = assertPinnedFamily(source, indexImage, baseImages, 'BASE', typedStack === 'postgresql' ? TWO_PART_RELEASE_TAG : RELEASE_TAG);
|
||||
if (!record(versions)) throw new Error('MISSING_TOOL_VERSIONS');
|
||||
const exactVersion = (value: unknown) => typeof value === 'string' &&
|
||||
(typedStack === 'postgresql'
|
||||
|
||||
@@ -322,9 +322,16 @@ function flag(args: string[], name: string): string | undefined {
|
||||
return index >= 0 ? args[index + 1] : undefined;
|
||||
}
|
||||
|
||||
async function main(args: string[]): Promise<void> {
|
||||
/** The W2 per-judge table plus the arm benchmark's paired judge (run by --config only; the manifest prices the W2 table). */
|
||||
export async function loadCalibrationConfigs(): Promise<{ w2: CalibrationConfig[]; all: CalibrationConfig[] }> {
|
||||
// The per-judge table (builders, schemas, verdict rules) is committed separately from this harness.
|
||||
const { CALIBRATION_CONFIGS } = await import(path.join(import.meta.dir, 'judge-calibration-configs.ts')) as { CALIBRATION_CONFIGS: CalibrationConfig[] };
|
||||
const { ARM_PAIR_CALIBRATION } = await import(path.join(import.meta.dir, '..', 'test', 'helpers', 'arm-pair-judge.ts')) as { ARM_PAIR_CALIBRATION: CalibrationConfig };
|
||||
return { w2: CALIBRATION_CONFIGS, all: [...CALIBRATION_CONFIGS, ARM_PAIR_CALIBRATION] };
|
||||
}
|
||||
|
||||
async function main(args: string[]): Promise<void> {
|
||||
const { w2: CALIBRATION_CONFIGS, all: configs } = await loadCalibrationConfigs();
|
||||
const command = args[0];
|
||||
if (command === 'manifest') {
|
||||
const client = new Anthropic();
|
||||
@@ -338,8 +345,8 @@ async function main(args: string[]): Promise<void> {
|
||||
console.table(manifest.entries);
|
||||
return;
|
||||
}
|
||||
const config = CALIBRATION_CONFIGS.find(candidate => candidate.id === flag(args, 'config'));
|
||||
if (!config) throw new Error(`unknown --config; expected one of ${CALIBRATION_CONFIGS.map(candidate => candidate.id).join(', ')}`);
|
||||
const config = configs.find(candidate => candidate.id === flag(args, 'config'));
|
||||
if (!config) throw new Error(`unknown --config; expected one of ${configs.map(candidate => candidate.id).join(', ')}`);
|
||||
const items = loadCorpus(config.id);
|
||||
const runsDir = path.join(CORPUS_ROOT, config.id, 'runs');
|
||||
const samplesPath = path.join(runsDir, 'comparison-1.samples.jsonl');
|
||||
|
||||
@@ -364,6 +364,10 @@ export const KNOWN_WINDOWS_INCOMPATIBLE: Array<{ file: string; reason: string }>
|
||||
file: 'test/ship-queue-train-ops.test.ts',
|
||||
reason: 'drives bin/gstack-ship-queue (screen verdicts, scratch-merge screens, prune --stale, watch, forget, verify --post-merge, ready --dispatch-ci, --stack-tests) against the same #!/bin/sh gh shim in test/helpers/ship-queue-train-fixture.ts',
|
||||
},
|
||||
{
|
||||
file: 'test/ship-queue-train-generic.test.ts',
|
||||
reason: 'drives bin/gstack-ship-queue train build, verdict, land, watch, init and doctor against the same #!/bin/sh gh shim plus an extensionless node gh wrapper on a colon-joined PATH; on windows-latest spawnSync(\'gh\') resolves the runner\'s gh.exe instead (windows-free-shard 1, run 41218228855)',
|
||||
},
|
||||
{
|
||||
file: 'test/ship-policy-compat.test.ts',
|
||||
reason: 'spawns bin/gstack-ship-policy, bin/gstack-restamp and bin/gstack-tree-receipt (shebangs) through test/helpers/restamp-fixture.ts',
|
||||
@@ -380,6 +384,10 @@ export const KNOWN_WINDOWS_INCOMPATIBLE: Array<{ file: string; reason: string }>
|
||||
file: 'test/ship-release.test.ts',
|
||||
reason: 'spawns bin/gstack-ship-release (shebang) directly and writes #!/bin/sh gh stubs through test/helpers/ship-bin-fixture.ts; windows-latest exits before the bin runs (windows-free-shard 3, run 41073592483)',
|
||||
},
|
||||
{
|
||||
file: 'test/ship-rereview-triggers.test.ts',
|
||||
reason: 'drives bin/gstack-ship-release, gstack-docs-candidate and gstack-wtree (shebangs) through test/helpers/ship-bin-fixture.ts like test/ship-release.test.ts; windows-latest fails every bin case at the first spawn (windows-free-shard 6, run 41193336209)',
|
||||
},
|
||||
];
|
||||
|
||||
// Force-include overrides: files a WINDOWS_FRAGILE_PATTERNS regex excludes for
|
||||
|
||||
@@ -216,7 +216,11 @@
|
||||
"test/skill-e2e-triage.test.ts": 1000,
|
||||
"test/skill-e2e-workflow.test.ts": 121594,
|
||||
"test/skill-llm-eval.test.ts": 339704,
|
||||
"test/skill-routing-e2e.test.ts": 81360
|
||||
"test/skill-routing-e2e.test.ts": 81360,
|
||||
"test/skill-e2e-planning-wave.test.ts#planning-wave-planted-facts": 74000,
|
||||
"test/skill-e2e-planning-wave.test.ts#planning-wave-schema": 52000,
|
||||
"test/skill-e2e-planning-wave.test.ts#planning-wave-tasks-rerun": 37000,
|
||||
"test/skill-e2e-planning-wave.test.ts#planning-wave-closing-signals": 27000
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export const SELECTION_DATA_MODULES: readonly string[] = [
|
||||
// The build entry list: every compiled binary, which skills reach through their `--outfile` path instead.
|
||||
'scripts/build.sh',
|
||||
// The reason-code table: its `fix:` prose names the command a person reruns, not a file the module consumes.
|
||||
'lib/result-codes.ts', 'lib/result-codes-release.ts', 'lib/result-codes-capy.ts', 'lib/result-codes-budget.ts', 'lib/result-codes-eval.ts',
|
||||
'lib/result-codes.ts', 'lib/result-codes-release.ts', 'lib/result-codes-capy.ts', 'lib/result-codes-budget.ts', 'lib/result-codes-eval.ts', 'lib/result-codes-plan.ts',
|
||||
// The exercised-path map: observed commands per case, read only by exercisedConsumers() (shadow data; a change selects no paid case).
|
||||
'test/helpers/exercised-commands.json',
|
||||
];
|
||||
|
||||
@@ -593,11 +593,10 @@ Show the screenshot to the user. Ask: "Does this feel right? Want to iterate on
|
||||
If they want changes, regenerate the HTML with their feedback and re-render.
|
||||
If they approve or say "good enough," proceed.
|
||||
|
||||
**Step 5: Include in design doc**
|
||||
**Step 5: Save the sketch**
|
||||
|
||||
Reference the wireframe screenshot in the design doc's "Recommended Approach" section.
|
||||
The screenshot file at \`<sketch-dir>/sketch.png\` (name the full path in the doc) can be referenced by downstream skills
|
||||
(\`/plan-design-review\`, \`/design-review\`) to see what was originally envisioned.
|
||||
Copy the temporary \`sketch.png\` and \`sketch.html\` to \`<PROJECT_DIR>/{user}-{branch}-sketch-{datetime}.*\`.
|
||||
In "Recommended Approach" add \`Wireframe: projects/<slug>/<png name>\` (state-root relative), or \`Wireframe: none (<reason>)\`.
|
||||
|
||||
**Step 6: Outside design voices** (optional)
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ empty JSONL files array. Each task needs a concrete verification step.` : `Befor
|
||||
build-actionable tasks. Each task derives from a specific finding — no padding.`}
|
||||
${conditionalWrites ? `Always emit the markdown section. Write its JSONL artifact for \`/autoplan\` only when the ${storagePolicy} permits it; otherwise label the complete task output not persisted and do not claim an aggregation artifact exists.` : 'Emit the markdown section AND write a JSONL artifact that `/autoplan` can\naggregate across phases.'}
|
||||
|
||||
### Earlier lists on this branch
|
||||
|
||||
Before listing tasks, run \`~/.claude/skills/gstack/bin/gstack-tasks prior --phase ${phase}\` and reconcile what it prints, so a rerun never leaves two lists.
|
||||
|
||||
### Markdown section (always emit)
|
||||
|
||||
\`\`\`markdown
|
||||
@@ -54,49 +58,11 @@ Rules:
|
||||
|
||||
### JSONL artifact (${conditionalWrites ? 'write when permitted, including zero tasks' : 'always write, even if zero tasks'})
|
||||
|
||||
\`/autoplan\` reads this file to aggregate across phases. Build each line with
|
||||
\`jq -nc\` so titles and source findings containing quotes, newlines, or
|
||||
backslashes serialize cleanly — never use hand-rolled \`echo\` / \`printf\`.
|
||||
\`/autoplan\` aggregates this list. With your file-write tool, write one JSON object per line to \`.gstack/tmp/tasks-${phase}-rows.jsonl\` at the repo root (no free text in a command; no rows, no file): a task is \`{"id":"T1","priority":"P1","component":"","title":"","source_finding":"","effort_human":"~2h","effort_cc":"~15min","files":[]}\`, plus \`"carried_from":"<run_id>/<id>"\` when carried; a closed earlier task is \`{"prior":"<run_id>/<id>","disposition":"done|dropped","reason":""}\`. Then write the list (empty means "ran, no findings", distinct from "didn't run"):
|
||||
|
||||
\`\`\`bash
|
||||
GSTACK_STATE_ROOT=$(~/.claude/skills/gstack/bin/gstack-paths --get GSTACK_STATE_ROOT); : "\${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}"
|
||||
SLUG=$(~/.claude/skills/gstack/bin/gstack-slug --get SLUG 2>/dev/null)
|
||||
TASKS_DIR="$GSTACK_STATE_ROOT/projects/\${SLUG:-unknown}"
|
||||
mkdir -p "$TASKS_DIR"
|
||||
TASKS_FILE="$TASKS_DIR/tasks-${phase}-$(date +%Y%m%d-%H%M%S).jsonl"
|
||||
COMMIT=$(git rev-parse HEAD 2>/dev/null || echo unknown)
|
||||
# The task record keeps the raw git branch; artifact filenames keep gstack-slug's sanitized BRANCH.
|
||||
GIT_BRANCH=$(git branch --show-current 2>/dev/null || echo unknown)
|
||||
RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-$$"
|
||||
|
||||
# Repeat ONE jq invocation per task identified during this review.
|
||||
# Substitute the placeholders inline with shell variables you set per task:
|
||||
# TASK_ID (T1, T2, ...), PRIORITY (P1/P2/P3), COMPONENT, TITLE,
|
||||
# SOURCE_FINDING, EFFORT_HUMAN, EFFORT_CC, FILES_JSON (a JSON array literal
|
||||
# like '["browse/src/sanitize.ts","browse/src/server.ts"]').
|
||||
jq -nc \\
|
||||
--arg phase '${phase}' \\
|
||||
--arg run_id "$RUN_ID" \\
|
||||
--arg branch "$GIT_BRANCH" \\
|
||||
--arg commit "$COMMIT" \\
|
||||
--arg id "$TASK_ID" \\
|
||||
--arg priority "$PRIORITY" \\
|
||||
--arg component "$COMPONENT" \\
|
||||
--arg effort_human "$EFFORT_HUMAN" \\
|
||||
--arg effort_cc "$EFFORT_CC" \\
|
||||
--arg title "$TITLE" \\
|
||||
--arg source_finding "$SOURCE_FINDING" \\
|
||||
--argjson files "$FILES_JSON" \\
|
||||
'{phase:$phase, run_id:$run_id, branch:$branch, commit:$commit, id:$id, priority:$priority, component:$component, files:$files, effort_human:$effort_human, effort_cc:$effort_cc, title:$title, source_finding:$source_finding}' \\
|
||||
>> "$TASKS_FILE"
|
||||
~/.claude/skills/gstack/bin/gstack-tasks add --phase ${phase}
|
||||
\`\`\`
|
||||
|
||||
If \`jq\` is not installed, fall back to skipping the JSONL write and warn
|
||||
the user to install jq for autoplan aggregation. Never hand-roll JSONL.
|
||||
|
||||
${conditionalWrites ? 'When writes are permitted and zero tasks were identified, touch the JSONL file' : 'If zero tasks were identified in this review, still touch the JSONL file'}
|
||||
(\`: > "$TASKS_FILE"\`) so the aggregator sees that the phase produced output
|
||||
this run (an empty file means "ran, no findings" — distinct from "didn't run").
|
||||
`;
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user