feat(mosaic): WI-2 mutator-class guard for directive-freshness (#837)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/publish Pipeline was successful

WI-2: mutator-class guard for the compaction directive-freshness mechanism — command-position parser (prefix x var-indirection unified) + primitive-anchored invariant backstop + all-tools-hook fail-close. Parser-complete on principle: realistic evasion matrix RED-regression-covered, residual exotic evasions proven backstop-caught (B-tests), lens-convergence reached.

closes #829
This commit was merged in pull request #837.
This commit is contained in:
2026-07-18 05:51:58 +00:00
parent 8ec67a1126
commit abd2791f59
27 changed files with 2579 additions and 46 deletions

View File

@@ -179,32 +179,41 @@ function buildContinuationPrompt(params: {
`3. Read \`${mission.scratchpadFile}\` for session history and decisions`,
`4. Read \`${mission.tasksFile}\` for current task state`,
'5. `git pull --rebase` to sync latest changes',
`6. Launch runtime with \`${runtime} -p\``,
`6. Launch runtime with \`mosaic ${runtime} -p\``,
`7. Continue execution from task **${taskId}**`,
'8. Follow Two-Phase Completion Protocol',
`9. You are the SOLE writer of \`${mission.tasksFile}\``,
].join('\n');
}
function resolveLaunchCommand(
export function resolveLaunchCommand(
runtime: 'claude' | 'codex',
prompt: string,
configuredCommand: string[] | undefined,
): string[] {
if (configuredCommand === undefined || configuredCommand.length === 0) {
return [runtime, '-p', prompt];
return runtime === 'claude' ? ['mosaic', 'claude', '-p', prompt] : [runtime, '-p', prompt];
}
const hasPromptPlaceholder = configuredCommand.some((value) => value === '{prompt}');
const withInterpolation = configuredCommand.map((value) =>
value === '{prompt}' ? prompt : value,
);
const command = hasPromptPlaceholder ? withInterpolation : [...withInterpolation, prompt];
if (hasPromptPlaceholder) {
return withInterpolation;
if (runtime !== 'claude') return command;
if (
command[0] === 'mosaic' &&
(command[1] === 'claude' || (command[1] === 'yolo' && command[2] === 'claude'))
) {
return command;
}
return [...withInterpolation, prompt];
if (command[0] === 'claude') {
return ['mosaic', 'claude', ...command.slice(1)];
}
throw new Error(
'Custom Claude task commands must use `mosaic claude` so lease registration cannot be bypassed.',
);
}
async function writeAtomicJson(filePath: string, payload: unknown): Promise<void> {