merge: main (7a skills workshop, 9 rettepakke, 7b researching-sources, 8 release runbook) into wave2-kobling
Union lines resolved: CLAUDE.md command table keeps main's /trekresearch and /trekplan rows and this branch's /trekexecute row. README's architecture block now counts the three skills main ships (it said 2 after 7b added researching-sources). Contracts run against the real ones on the merged tree: K10/K11 (plan validator refuses a piped Regression:, warns on an unknown On failure:; regression-check passes/fails/absent/unrunnable), S2 (skills/test-first and skills/debugging exist, voyage:<name> form as 7a chose), K7 (real review_version 1.1 WARN -> 0, a BLOCK copy -> 1, a 1.0 review with no verdict -> 2). npm test: 2102 / 2100 pass / 0 fail / 2 skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
3c18fdb5f7
83 changed files with 4293 additions and 71 deletions
|
|
@ -22,6 +22,14 @@
|
|||
// criteria runner's allowlist, and each `End-to-end:` command also stands
|
||||
// under `## Verification`, where Phase 7 runs it.
|
||||
// Strict mode reports these as errors; --soft downgrades them to warnings.
|
||||
//
|
||||
// Every plan version (the fields are new; a plan without them is unchanged):
|
||||
// - K10: the optional step field `Regression:` holds ONE command the
|
||||
// criteria runner's allowlist runs (first backticked span, no pipe, no
|
||||
// `&&`); the executor runs it green before the step's checkpoint. One that
|
||||
// can never run is an error (a warning under --soft).
|
||||
// - K11: `On failure:` opens with revert | retry | skip | escalate, the words
|
||||
// /trekexecute reads; any other opening is a warning.
|
||||
|
||||
import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
|
@ -29,6 +37,7 @@ import {
|
|||
sliceSteps, validatePlanHeadings, extractPlanVersion, extractPlanCeremony,
|
||||
parseStepFields, findSection, splitSections, findModuleCycle, parseMermaid, fencedBlocks,
|
||||
versionAtLeast, PLAN_VERSION_CURRENT, PLAN_VERSIONS_SUPPORTED, CEREMONY_VALUES,
|
||||
ON_FAILURE_ACTIONS, onFailureAction,
|
||||
} from '../parsers/plan-schema.mjs';
|
||||
import { validateAllManifests } from '../parsers/manifest-yaml.mjs';
|
||||
import { parseDocument } from '../util/frontmatter.mjs';
|
||||
|
|
@ -125,6 +134,36 @@ function checkRunnable(text, sections, opts) {
|
|||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* K10 and K11. `Verify:` is both the step's one test command and its proof of
|
||||
* red, so a step whose red test is a shell script could not also run the frozen
|
||||
* suite before its checkpoint; the plan wrote "run npm test before the
|
||||
* checkpoint" in prose that nothing enforced (voyage-lekerepo trial 2,
|
||||
* 2026-10-08). `Regression:` is that command, checked like `Verify:`.
|
||||
*/
|
||||
function checkRecovery(sections, opts) {
|
||||
const errors = [];
|
||||
const warnings = [];
|
||||
for (const s of sections) {
|
||||
const f = parseStepFields(s.body);
|
||||
if (f.has('Regression')) {
|
||||
const r = runnableCheck(firstCommand(f.get('Regression').text), opts);
|
||||
if (!r.runnable) {
|
||||
errors.push(issue('PLAN_STEP_REGRESSION_NOT_RUNNABLE',
|
||||
`Step ${s.n}: \`Regression:\` is not one runnable command (${r.reason})`,
|
||||
'Backtick ONE command the criteria runner allows, unpiped and without `&&` (`npm test`); ' +
|
||||
`the executor runs it green before the checkpoint. ${WAY_IN}`));
|
||||
}
|
||||
}
|
||||
if (f.has('On failure') && onFailureAction(f.get('On failure').text) === null) {
|
||||
warnings.push(issue('PLAN_STEP_ON_FAILURE_UNKNOWN',
|
||||
`Step ${s.n}: \`On failure:\` does not open with a recovery word the executor reads`,
|
||||
`Open with one of ${ON_FAILURE_ACTIONS.join(' | ')}, then the specifics (\`retry once, then escalate\`).`));
|
||||
}
|
||||
}
|
||||
return { errors, warnings };
|
||||
}
|
||||
|
||||
/** Table body rows (skips the header and the |---| separator). */
|
||||
function tableRows(text) {
|
||||
const rows = text.split('\n').filter(l => l.trim().startsWith('|'));
|
||||
|
|
@ -230,6 +269,11 @@ export function validatePlanContent(rawText, opts = {}) {
|
|||
warnings.push(issue('PLAN_VERSION_MISMATCH', `plan_version=${planVersion}, current target is ${PLAN_VERSION_CURRENT}`));
|
||||
}
|
||||
|
||||
const recovery = checkRecovery(sections, { cwd: opts.cwd });
|
||||
if (strict) errors.push(...recovery.errors);
|
||||
else warnings.push(...recovery.errors);
|
||||
warnings.push(...recovery.warnings);
|
||||
|
||||
const ceremony = extractPlanCeremony(text);
|
||||
if (versionAtLeast(planVersion, '1.8')) {
|
||||
const v18 = [...checkSteps(sections), ...checkRunnable(text, sections, { cwd: opts.cwd })];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue