MAJOR
- 9e97cd5 40-validate-standalone.sh: route a target's sc2_gate to its dedicated
gate (config-audit → 50-config-audit-sc2.sh), mirroring 99-dryrun.sh, so --all
no longer falsely FAILs config-audit on the machine-locked v5.0.0 tests.
- 1708e90 99-dryrun.sh: assert EXACTLY one tag survives (F5); a partial tag-strip
no longer silently reports the wrong tag via head -1.
- 4e494c8 99-dryrun.sh: capture the SC2 standalone failing set from the dry-run's
own prepped extract ($dest), not the 40-validate side-effect clean room.
- aeb6292 00-preflight.sh: assert every map path is whitespace/glob-free, making
the word-split path handling in 99-dryrun.sh sound.
- 5d112cb extract the SC6 DROP + SC2 regression detectors into sc6-check.sh /
sc2-regression.sh and add sc-checks.test.mjs — a negative test proving each
detector FIRES (force-fresh re-extraction would undo a planted file-drop).
- 9e588ca 10-extract.sh re-asserts git filter-repo before use (self-heal runs
preflight only on a missing mirror); RUNBOOK lists git-filter-repo + python3>=3.6.
MINOR
- bc0f8a7 plugin-map.json: reset ms-ai-architect blob_strip_safe to null
(00-preflight.sh populates it per run).
- 8d649e9 99-dryrun.sh: gate SC6 behind extract success; a failed extract is
labelled (extract failed), not a content DROP.
- 4044c49 99-dryrun.sh: guard mktemp — an empty capture is an error, not a
false zero-regression PASS.
Also: 00-preflight.test.mjs asserted all 3 'renamed' plugins carry >=2 paths, but
llm-security became single-path in 836b8e9 (copilot was a coexisting plugin, not a
rename) — a stale pre-existing failure. Aligned the test to the ratified map and
added a positive single-path lock against re-introducing the 87-file-drop defect.
Verified: full dry-run 11/11, 0 pushes; sc-checks/99-dryrun/40-validate/00-preflight/
60-rewrite suites green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
93 lines
4.6 KiB
JavaScript
93 lines
4.6 KiB
JavaScript
// Step 11 test — the full local dry-run report ($WORK/dryrun-report.md) + previews.
|
|
// Verifies the GENERATED artifact (does not re-derive it):
|
|
// - the report lists all 11 targets
|
|
// - voyage shows >=250 commits (F1 — pre-rename history retained)
|
|
// - config-audit shows PASS under its dedicated SC2 gate (50-config-audit-sc2.sh)
|
|
// - llm-security shows complete content retention (SC6 — no file DROP; the dual-rename defect is fixed)
|
|
// - no SC6 DROP and no SC2 regression on ANY target
|
|
// - no target shows a tracked state-file leak (SC7)
|
|
// - the previewed all-external marketplace.json has zero ./plugins/ and zero ssh:// (F2)
|
|
// Pattern: plugins/voyage/tests/integration/*.test.mjs (heavy integration — long timeout, artifact reuse).
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { existsSync, readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const SCRIPT = path.join(here, '99-dryrun.sh');
|
|
const WORK = process.env.WORK || '/tmp/polyrepo-migration';
|
|
const REPORT = path.join(WORK, 'dryrun-report.md');
|
|
const MP_PREVIEW = path.join(WORK, 'marketplace.all-external.json');
|
|
const LONG = 1000 * 60 * 25; // cold path force-fresh re-extracts 11 repos + runs their suites
|
|
|
|
const TARGETS = [
|
|
'ai-psychosis', 'claude-design', 'config-audit', 'graceful-handoff',
|
|
'human-friendly-style', 'linkedin-studio', 'llm-security', 'ms-ai-architect',
|
|
'okr', 'playground-design-system', 'voyage',
|
|
];
|
|
|
|
let _report = null;
|
|
function report() {
|
|
if (_report !== null) return _report;
|
|
if (!existsSync(REPORT)) {
|
|
const r = spawnSync('bash', [SCRIPT], { encoding: 'utf8', timeout: 1000 * 60 * 24, env: { ...process.env, WORK } });
|
|
if (!existsSync(REPORT)) {
|
|
throw new Error(`dry-run did not produce ${REPORT}\nstdout:\n${r.stdout}\nstderr:\n${r.stderr}`);
|
|
}
|
|
}
|
|
_report = readFileSync(REPORT, 'utf8');
|
|
return _report;
|
|
}
|
|
function row(key) {
|
|
return report().split('\n').find((l) => new RegExp(`^\\|\\s*${key}\\s*\\|`).test(l)) || '';
|
|
}
|
|
|
|
test('report lists all 11 targets', { timeout: LONG }, () => {
|
|
const r = report();
|
|
for (const t of TARGETS) assert.ok(r.includes(t), `report must list target ${t}`);
|
|
const rows = r.split('\n').filter((l) => /^\|\s*[a-z0-9-]+\s*\|\s*\d+\s*\|/.test(l));
|
|
assert.equal(rows.length, 11, `expected 11 target rows, found ${rows.length}`);
|
|
});
|
|
|
|
test('voyage shows >=250 commits (F1 pre-rename history retained)', { timeout: LONG }, () => {
|
|
const m = report().match(/\|\s*voyage\s*\|\s*(\d+)\s*\|/);
|
|
assert.ok(m, 'voyage row with a commit count must be present');
|
|
assert.ok(Number(m[1]) >= 250, `voyage commits ${m && m[1]} must be >= 250`);
|
|
});
|
|
|
|
test('config-audit PASSes its dedicated SC2 gate', { timeout: LONG }, () => {
|
|
const line = row('config-audit');
|
|
assert.ok(line, 'config-audit row must be present');
|
|
assert.ok(/\bPASS\b/.test(line) && !/FAIL/.test(line), `config-audit must PASS: ${line}`);
|
|
});
|
|
|
|
test('llm-security retains all content (SC6 — dual-rename file-drop defect is fixed)', { timeout: LONG }, () => {
|
|
const line = row('llm-security');
|
|
assert.ok(line, 'llm-security row must be present');
|
|
assert.ok(!/DROP/.test(line), `llm-security must not drop files (SC6): ${line}`);
|
|
assert.ok(/\bPASS\b/.test(line) && !/FAIL/.test(line), `llm-security must PASS standalone: ${line}`);
|
|
});
|
|
|
|
// This asserts the HAPPY path (the live report shows no DROP / no regression). The NEGATIVE coverage —
|
|
// proving the SC6 DROP and SC2 regression-FAIL detectors actually FIRE — lives in sc-checks.test.mjs,
|
|
// which drives sc6-check.sh / sc2-regression.sh (the extracted detectors this dry-run calls) directly,
|
|
// because force-fresh re-extraction would undo any file-drop planted into $WORK/<key> here (5d112cb).
|
|
test('no SC6 file-drop and no SC2 regression on any target', { timeout: LONG }, () => {
|
|
const r = report();
|
|
assert.ok(!/\bDROP\b/.test(r), 'no target may drop content (SC6)');
|
|
assert.ok(!/regression:/.test(r), 'no target may show an SC2 regression');
|
|
});
|
|
|
|
test('no target shows a tracked state-file leak (SC7)', { timeout: LONG }, () => {
|
|
assert.ok(!/LEAK/.test(report()), 'no SC7 state-file leak may appear in the report');
|
|
});
|
|
|
|
test('all-external marketplace.json preview has zero ./plugins/ and zero ssh:// (F2)', { timeout: LONG }, () => {
|
|
report();
|
|
assert.ok(existsSync(MP_PREVIEW), `${MP_PREVIEW} must exist`);
|
|
const mp = readFileSync(MP_PREVIEW, 'utf8');
|
|
assert.ok(!mp.includes('./plugins/'), 'no local ./plugins/ source may remain');
|
|
assert.ok(!mp.includes('ssh://'), 'no ssh:// url may remain');
|
|
});
|