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

@@ -28,6 +28,7 @@ import { execSync, spawnSync } from 'node:child_process';
// ---------------------------------------------------------------------------
const MOSAIC_HOME = process.env['MOSAIC_HOME'] ?? join(homedir(), '.config', 'mosaic');
const MUTATOR_GATE = join(MOSAIC_HOME, 'tools', 'lease-broker', 'mutator-gate.py');
// ---------------------------------------------------------------------------
// Helpers
@@ -106,6 +107,23 @@ function nowIso(): string {
return new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
}
function checkPiMutatorGate(toolName: string): { block: true; reason: string } | undefined {
const result = spawnSync('python3', [MUTATOR_GATE, '--runtime', 'pi'], {
input: `${JSON.stringify({ tool_name: toolName })}\n`,
encoding: 'utf8',
timeout: 2_000,
env: process.env,
});
if (result.status === 0) return undefined;
const detail = String(result.stderr ?? '')
.trim()
.split('\n')[0];
return {
block: true,
reason: detail || 'BLOCKED: Mosaic mutator gate is unavailable or the lease is UNVERIFIED.',
};
}
// ---------------------------------------------------------------------------
// Mission detection
// ---------------------------------------------------------------------------
@@ -250,6 +268,11 @@ export default function register(pi: ExtensionAPI) {
let hbModel: string | null = null;
let hbTimer: ReturnType<typeof setInterval> | null = null;
// ── Whole mutator-class authorization gate ────────────────────────────
// Every Pi tool, including unknown/custom tools, reaches the broker-backed
// class gate before execution. Broker/script failure blocks fail-closed.
pi.on('tool_call', async (event) => checkPiMutatorGate(event.toolName));
// ── Session Start ─────────────────────────────────────────────────────
pi.on('session_start', async (_event, ctx) => {
sessionCwd = process.cwd();