refactor: drop 12 runtimes, keep Claude, Codex, OpenCode, Cursor, ZCode, Antigravity
Removes kilo, kimi, kimi-code, copilot, windsurf, augment, trae, qwen, hermes, cline, codebuddy and pi end to end: capability descriptors, installer branches and converters (bin/install.js 14.9k -> 11.2k lines), TypeScript converters, hook surfaces and runtime homes, review lanes qwen/kimi-code, the two pi migrations, Kimi payload normalization in the hook guards, dead hostBehaviors vocabulary, launcher home probes, fixtures, runtime-specific tests and the prose that presented them as supported. Installer output for the six kept runtimes is byte-identical to before the prune. The Kimi tool-vocabulary tests in workflow-guard, read-guard and read-injection-scanner are left in place pending a decision.
This commit is contained in:
@@ -194,7 +194,7 @@ test('a moved hash whose source changed is attributed', () => {
|
||||
});
|
||||
|
||||
test('a trailing-slash source entry matches by prefix, segment-aware', () => {
|
||||
// Kimi's root agent aggregates all of agents/ — a Phase 2 prefix source.
|
||||
// A prefix source aggregates a whole directory (e.g. all of agents/).
|
||||
assert.equal(sourceSatisfiedBy('agents/', new Set(['agents/msd-planner.md'])), 'agents/msd-planner.md');
|
||||
// Hostile: a bare startsWith would over-attribute here. It must NOT match.
|
||||
assert.equal(sourceSatisfiedBy('agents/', new Set(['agentsfoo/x.md'])), null);
|
||||
@@ -202,11 +202,32 @@ test('a trailing-slash source entry matches by prefix, segment-aware', () => {
|
||||
assert.equal(sourceSatisfiedBy('a/b.md', new Set(['a/b.md'])), 'a/b.md');
|
||||
assert.equal(sourceSatisfiedBy('a/b.md', new Set(['a/b.md.bak'])), null);
|
||||
|
||||
const r = diffEmitted({
|
||||
baseline: { kimi: { 'agents/msd.yaml': 'aaa' } },
|
||||
current: { kimi: { 'agents/msd.yaml': 'bbb' } },
|
||||
changedPaths: ['agents/msd-planner.md'],
|
||||
});
|
||||
// No shipped provenance rule declares a prefix source any more (the Kimi root agent
|
||||
// that did was removed with its runtime), so drive the REAL diffEmitted against a
|
||||
// synthetic rule by swapping attributeEmittedPath in a freshly loaded emitted-diff.
|
||||
const provPath = require.resolve('./helpers/emitted-provenance.cjs');
|
||||
const diffPath = require.resolve('./helpers/emitted-diff.cjs');
|
||||
const realProv = require(provPath);
|
||||
const savedProv = require.cache[provPath].exports;
|
||||
const savedDiff = require.cache[diffPath];
|
||||
let r;
|
||||
try {
|
||||
require.cache[provPath].exports = {
|
||||
...realProv,
|
||||
attributeEmittedPath: (rel, runtime) => (rel === 'agents/msd.yaml'
|
||||
? { ruleId: 'synthetic-prefix', kind: 'derived', sources: ['agents/'], transforms: [] }
|
||||
: realProv.attributeEmittedPath(rel, runtime)),
|
||||
};
|
||||
delete require.cache[diffPath];
|
||||
r = require(diffPath).diffEmitted({
|
||||
baseline: { synthetic: { 'agents/msd.yaml': 'aaa' } },
|
||||
current: { synthetic: { 'agents/msd.yaml': 'bbb' } },
|
||||
changedPaths: ['agents/msd-planner.md'],
|
||||
});
|
||||
} finally {
|
||||
require.cache[provPath].exports = savedProv;
|
||||
if (savedDiff) require.cache[diffPath] = savedDiff; else delete require.cache[diffPath];
|
||||
}
|
||||
assert.equal(r.unattributable.length, 0, 'prefix source should attribute');
|
||||
assert.equal(r.attributed[0].via, 'agents/msd-planner.md');
|
||||
});
|
||||
@@ -246,16 +267,16 @@ test('synthesized paths are exempt from attribution', () => {
|
||||
test('code-derived paths attribute to their emitting source file', () => {
|
||||
// Phase 2 deliberately refused to mark these exempt; this is why.
|
||||
const r = diffEmitted({
|
||||
baseline: { cline: { '.clinerules/msd.md': 'aaa' } },
|
||||
current: { cline: { '.clinerules/msd.md': 'bbb' } },
|
||||
changedPaths: ['src/runtime-hooks-surface.cts'],
|
||||
baseline: { claude: { 'hooks/package.json': 'aaa' } },
|
||||
current: { claude: { 'hooks/package.json': 'bbb' } },
|
||||
changedPaths: ['src/commonjs-marker.cts'],
|
||||
});
|
||||
assert.equal(r.unattributable.length, 0);
|
||||
assert.equal(r.attributed[0].via, 'src/runtime-hooks-surface.cts');
|
||||
assert.equal(r.attributed[0].via, 'src/commonjs-marker.cts');
|
||||
|
||||
const blind = diffEmitted({
|
||||
baseline: { cline: { '.clinerules/msd.md': 'aaa' } },
|
||||
current: { cline: { '.clinerules/msd.md': 'bbb' } },
|
||||
baseline: { claude: { 'hooks/package.json': 'aaa' } },
|
||||
current: { claude: { 'hooks/package.json': 'bbb' } },
|
||||
changedPaths: ['README.md'],
|
||||
});
|
||||
assert.equal(blind.unattributable.length, 1, 'had these been exempt, this ripple would be invisible forever');
|
||||
@@ -1681,6 +1702,20 @@ test('property: every moved key lands in exactly one bucket', () => {
|
||||
// prove RED.
|
||||
|
||||
const ALL_FAMILIES = MANIFEST_FAMILIES.map((f) => f.name);
|
||||
// Synthetic family sets are sized from the floor, never from hardcoded counts or the
|
||||
// names of runtimes that once existed. `familiesOfSize(n)` keeps claude-local (pinned by
|
||||
// name) and the real families first, padding with synthetic names when n exceeds them.
|
||||
const FLOOR = MINIMUM_MANIFEST_FAMILIES;
|
||||
const DROPPABLE = 'synthetic-droppable';
|
||||
const WITH_DROPPABLE = [...ALL_FAMILIES, DROPPABLE];
|
||||
function familiesOfSize(n) {
|
||||
const pool = [
|
||||
...ALL_FAMILIES.filter((f) => f !== 'claude-local'),
|
||||
...Array.from({ length: n }, (_, i) => `synthetic-pad-${i}`),
|
||||
];
|
||||
return ['claude-local', ...pool.slice(0, n - 1)];
|
||||
}
|
||||
|
||||
const REGISTRY_CHANGE = ['tests/helpers/install-shared.cjs'];
|
||||
// The shape a shipping caller passes: repo-relative POSIX paths from `git diff --name-only`.
|
||||
const CONTENT_ONLY_CHANGE = ['msd-core/workflows/plan-phase.md'];
|
||||
@@ -1748,43 +1783,41 @@ test('rejects an added family with no runtime-registry change, naming it', () =>
|
||||
});
|
||||
|
||||
test('permits a dropped family attributed to a runtime-registry change', () => {
|
||||
const without = ALL_FAMILIES.filter((n) => n !== 'trae');
|
||||
const without = ALL_FAMILIES;
|
||||
const r = reconcileWith({
|
||||
derivedNames: without,
|
||||
baselineNames: ALL_FAMILIES,
|
||||
baselineNames: WITH_DROPPABLE,
|
||||
currentNames: without,
|
||||
changedPaths: REGISTRY_CHANGE,
|
||||
minimum: 18,
|
||||
});
|
||||
assert.deepEqual(r, { ok: true, errors: [] });
|
||||
});
|
||||
|
||||
test('rejects a silently dropped family, naming it', () => {
|
||||
const without = ALL_FAMILIES.filter((n) => n !== 'trae');
|
||||
const without = ALL_FAMILIES;
|
||||
const r = reconcileWith({
|
||||
derivedNames: without,
|
||||
baselineNames: ALL_FAMILIES,
|
||||
baselineNames: WITH_DROPPABLE,
|
||||
currentNames: without,
|
||||
changedPaths: CONTENT_ONLY_CHANGE,
|
||||
minimum: 18,
|
||||
});
|
||||
assert.equal(r.ok, false);
|
||||
assert.deepEqual(r.errors, [{ code: FAMILY_REASON.DROPPED_UNATTRIBUTED, family: 'trae' }]);
|
||||
assert.deepEqual(r.errors, [{ code: FAMILY_REASON.DROPPED_UNATTRIBUTED, family: DROPPABLE }]);
|
||||
});
|
||||
|
||||
test('attribution is the ONLY permission path, symmetrically', () => {
|
||||
// No ack-style bypass on either side: a one-sided escape hatch would make removals
|
||||
// easier to wave through than additions, and the drift-ack file covers unattributable
|
||||
// emitted-PATH deltas, not family churn.
|
||||
const without = ALL_FAMILIES.filter((n) => n !== 'trae');
|
||||
const without = ALL_FAMILIES;
|
||||
const added = [...ALL_FAMILIES, 'qoder'];
|
||||
for (const [names, baselineNames, code, family] of [
|
||||
[without, ALL_FAMILIES, FAMILY_REASON.DROPPED_UNATTRIBUTED, 'trae'],
|
||||
[without, WITH_DROPPABLE, FAMILY_REASON.DROPPED_UNATTRIBUTED, DROPPABLE],
|
||||
[added, ALL_FAMILIES, FAMILY_REASON.ADDED_UNATTRIBUTED, 'qoder'],
|
||||
]) {
|
||||
const r = reconcileWith({
|
||||
derivedNames: names, baselineNames, currentNames: names,
|
||||
changedPaths: CONTENT_ONLY_CHANGE, minimum: 18,
|
||||
changedPaths: CONTENT_ONLY_CHANGE,
|
||||
});
|
||||
assert.equal(r.ok, false);
|
||||
assert.deepEqual(r.errors, [{ code, family }]);
|
||||
@@ -1792,10 +1825,10 @@ test('attribution is the ONLY permission path, symmetrically', () => {
|
||||
});
|
||||
|
||||
test('an add and a drop together are permitted when attributed', () => {
|
||||
const swapped = [...ALL_FAMILIES.filter((n) => n !== 'trae'), 'qoder'];
|
||||
const swapped = [...WITH_DROPPABLE.filter((n) => n !== DROPPABLE), 'qoder'];
|
||||
const r = reconcileWith({
|
||||
derivedNames: swapped,
|
||||
baselineNames: ALL_FAMILIES,
|
||||
baselineNames: WITH_DROPPABLE,
|
||||
currentNames: swapped,
|
||||
changedPaths: REGISTRY_CHANGE,
|
||||
});
|
||||
@@ -1803,20 +1836,20 @@ test('an add and a drop together are permitted when attributed', () => {
|
||||
});
|
||||
|
||||
test('an EQUAL-COUNT membership swap is caught in both directions', () => {
|
||||
// 19 in, 19 out — invisible to any count-based check. This is why the contract is
|
||||
// N in, N out — invisible to any count-based check. This is why the contract is
|
||||
// set-based rather than numeric.
|
||||
const swapped = [...ALL_FAMILIES.filter((n) => n !== 'trae'), 'qoder'];
|
||||
const swapped = [...WITH_DROPPABLE.filter((n) => n !== DROPPABLE), 'qoder'];
|
||||
const r = reconcileWith({
|
||||
derivedNames: swapped,
|
||||
baselineNames: ALL_FAMILIES,
|
||||
baselineNames: WITH_DROPPABLE,
|
||||
currentNames: swapped,
|
||||
changedPaths: CONTENT_ONLY_CHANGE,
|
||||
});
|
||||
assert.equal(swapped.length, ALL_FAMILIES.length, 'the swap must leave the totals equal');
|
||||
assert.equal(swapped.length, WITH_DROPPABLE.length, 'the swap must leave the totals equal');
|
||||
assert.equal(r.ok, false);
|
||||
assert.deepEqual(r.errors.slice().sort((a, b) => a.code.localeCompare(b.code)), [
|
||||
{ code: FAMILY_REASON.ADDED_UNATTRIBUTED, family: 'qoder' },
|
||||
{ code: FAMILY_REASON.DROPPED_UNATTRIBUTED, family: 'trae' },
|
||||
{ code: FAMILY_REASON.DROPPED_UNATTRIBUTED, family: DROPPABLE },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -1843,30 +1876,32 @@ test('rejects a registered runtime with no fixture, naming it', () => {
|
||||
// ── The absolute floor: limit-1 / limit / limit+1 ────────────────────────────
|
||||
|
||||
test('floor is enforced at limit-1 / limit / limit+1', () => {
|
||||
const eighteen = ALL_FAMILIES.filter((n) => n !== 'trae'); // limit-1
|
||||
const twenty = [...ALL_FAMILIES, 'qoder']; // limit+1
|
||||
const below = familiesOfSize(FLOOR - 1); // limit-1
|
||||
const atLimit = familiesOfSize(FLOOR); // limit
|
||||
const above = familiesOfSize(FLOOR + 1); // limit+1
|
||||
|
||||
const below = reconcileWith({
|
||||
derivedNames: eighteen, baselineNames: eighteen, currentNames: eighteen,
|
||||
const rBelow = reconcileWith({
|
||||
derivedNames: below, baselineNames: below, currentNames: below,
|
||||
});
|
||||
assert.equal(below.ok, false);
|
||||
assert.ok(codesOf(below).includes(FAMILY_REASON.BELOW_FLOOR));
|
||||
assert.equal(rBelow.ok, false);
|
||||
assert.ok(codesOf(rBelow).includes(FAMILY_REASON.BELOW_FLOOR));
|
||||
|
||||
assert.deepEqual(reconcileWith({}), { ok: true, errors: [] }); // limit == 19
|
||||
assert.deepEqual(reconcileWith({
|
||||
derivedNames: atLimit, baselineNames: atLimit, currentNames: atLimit,
|
||||
}), { ok: true, errors: [] });
|
||||
|
||||
const above = reconcileWith({
|
||||
derivedNames: twenty, baselineNames: twenty, currentNames: twenty,
|
||||
});
|
||||
assert.deepEqual(above, { ok: true, errors: [] });
|
||||
assert.deepEqual(reconcileWith({
|
||||
derivedNames: above, baselineNames: above, currentNames: above,
|
||||
}), { ok: true, errors: [] });
|
||||
});
|
||||
|
||||
test('a uniformly shrunken universe fails on the floor', () => {
|
||||
// The Goodhart move the old literal permitted: drop a runtime AND its fixture together
|
||||
// and lower the constant, and 18 === 18 passes over a smaller world.
|
||||
const eighteen = ALL_FAMILIES.filter((n) => n !== 'trae');
|
||||
// and lower the constant, and N-1 === N-1 passes over a smaller world.
|
||||
const shrunk = familiesOfSize(FLOOR - 1);
|
||||
const r = reconcileWith({
|
||||
derivedNames: eighteen, fixtureNames: eighteen,
|
||||
baselineNames: eighteen, currentNames: eighteen,
|
||||
derivedNames: shrunk, fixtureNames: shrunk,
|
||||
baselineNames: shrunk, currentNames: shrunk,
|
||||
changedPaths: REGISTRY_CHANGE,
|
||||
});
|
||||
assert.equal(r.ok, false);
|
||||
|
||||
Reference in New Issue
Block a user