Files
msd-core/tests/fix-2603-kimi-code-host-matrix.test.cjs
sim 7dd9e59f6b test(#3090): stop exempting violations under categories that do not fit
An allow-test-rule annotation citing a category that does not apply is worse
than no annotation, because it reads as reviewed. Eight were confirmed by
reading the assertions each one covered, and auditing the rest found five more
plus one refutation — a converter test whose wording described the wrong
mechanism while the covered assertion genuinely was deployed-text.

The instructive one used the CANONICAL string for the same mistake: STATE.md
command output labelled as a deployed artifact. A canonical string is not
evidence the category fits, which is why normalising strings alone would have
laundered the problem rather than fixed it. Every mapping the audit had inferred
rather than code-verified was spot-checked before rewriting, and the ones that
turned out not to fit were re-annotated rather than relabelled.

Fourteen STATE.md assertions had a typed extractor available all along and now
use it; their annotations came out because nothing needs exempting. Eight
assertions genuinely need a production change first — CLI stdout and stderr with
no structured mode — and are tagged pending-migration-to-typed-ir citing #3090,
which is what that category is for. It had zero real uses before this, while one
file carried a real citation to migration issue #2974 under a non-canonical tag.

Six annotations covered assertions that do no text matching at all. An exemption
for a violation that does not exist is noise that makes the real ones harder to
audit; those are removed.

atomic-write-coverage gains the annotation it always warranted — its own
docstring describes a structural-regression-guard while the file carried none.

Fifty-nine non-canonical strings across roughly thirty files are normalised, and
the allow-test-rule allowlist is regenerated to match. 472 annotations became
463: every one now uses a canonical category, and the two remaining
non-canonical strings are ESLint RuleTester fixtures, not annotations.

Refs #3057

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 17:20:56 -04:00

225 lines
9.7 KiB
JavaScript

/**
* #2603 — `docs/reference/host-integration-capability-matrix.md` documented 18 of the
* 19 installed runtimes but had no `## kimi-code` section, so kimi-code's
* `runtime.hostIntegration` axes shipped with no cited source and no evidence quote.
*
* Sourcing each axis independently (the issue's explicit requirement — "Do not copy
* `kimi`'s section", they are distinct products) showed three axis values had been
* inherited from the Python `kimi` descriptor rather than sourced for Kimi Code CLI:
*
* - `embeddingMode: imperative` → `declarative`. Kimi Code plugins are a
* `kimi.plugin.json` manifest plus markdown Skills; "Plugins are configuration and
* markdown only" with no in-process programmatic API (docs/en/customization/plugins.md).
* Same shape as codex, which is `declarative`.
* - `dispatch.nested: false` → `true`. The `coder` built-in "can dispatch its own
* nested sub-agents when a task decomposes naturally" (docs/en/customization/agents.md).
* The Python `kimi` CLI genuinely prohibits nesting; Kimi Code does not.
* - `dispatch.maxDepth: 1` → `'undocumented'`. Nesting is documented but no depth
* bound is published, so the fail-closed sentinel applies rather than a guessed 1.
*
* `dispatch.namedDispatch` deliberately stays `false`: GSD's kimi-code artifact layout
* installs Agent Skills only (no `agents` kind), so no named GSD subagent is registered
* with the host and `resolveDispatchType` maps every role onto coder/explore/plan.
* Flipping it without also shipping agent files would reintroduce the dispatch failure
* recorded in docs/migration/kimi-to-kimi-code.md.
*
* This is the same defect class as #2598 (a descriptor axis asserting something the
* host docs contradict), and takes the same countermeasure: pin the corrected values
* AND require the matrix to agree with the descriptor, because a descriptor/matrix
* disagreement is how the gap survived.
*/
// allow-test-rule: source-text-is-the-product #2603 — the descriptor JSON and the
// host-integration matrix ARE the negotiated contract; asserting their values is behavioral.
'use strict';
process.env.GSD_TEST_MODE = '1';
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const ROOT = path.join(__dirname, '..');
const DESCRIPTOR = path.join(ROOT, 'capabilities', 'kimi-code', 'capability.json');
const MATRIX = path.join(ROOT, 'docs', 'reference', 'host-integration-capability-matrix.md');
const {
profileOf,
negotiateHostCapabilities,
} = require(path.join(ROOT, 'gsd-core/bin/lib/host-integration.cjs'));
function kimiCodeAxes() {
return JSON.parse(fs.readFileSync(DESCRIPTOR, 'utf8')).runtime.hostIntegration;
}
/** Extract the `## <host>` section body, stopping at the next top-level host heading. */
function matrixSection(host) {
const matrix = fs.readFileSync(MATRIX, 'utf8');
const start = matrix.indexOf(`\n## ${host}\n`);
if (start === -1) return null;
const rest = matrix.slice(start + 1);
const end = rest.indexOf('\n## ');
return end === -1 ? rest : rest.slice(0, end);
}
/** Read the `| <axis> | <value> | …` cell out of a matrix section. */
function matrixValue(section, axis) {
const row = section.split('\n').find((l) => l.startsWith(`| ${axis} |`));
return row ? row.split('|')[2].trim() : null;
}
describe('#2603: the host-integration matrix documents kimi-code', () => {
test('a `## kimi-code` section exists', () => {
assert.ok(
matrixSection('kimi-code'),
'the matrix is the deployment source-of-truth for every installed runtime; kimi-code must have a section',
);
});
test('every hostIntegration axis kimi-code declares is documented in the matrix', () => {
const section = matrixSection('kimi-code');
const axes = kimiCodeAxes();
const scalarAxes = Object.keys(axes).filter((k) => k !== 'dispatch');
for (const axis of scalarAxes) {
assert.ok(
matrixValue(section, axis),
`matrix must document the "${axis}" axis for kimi-code`,
);
}
// `builtInSubagents` is a GSD-side list, not a negotiated axis — the matrix
// documents it in prose, not as its own row.
const dispatchAxes = Object.keys(axes.dispatch).filter((k) => k !== 'builtInSubagents');
for (const axis of dispatchAxes) {
assert.ok(
matrixValue(section, `dispatch.${axis}`),
`matrix must document the "dispatch.${axis}" sub-axis for kimi-code`,
);
}
});
test('the matrix values agree with the shipped descriptor', () => {
const section = matrixSection('kimi-code');
const axes = kimiCodeAxes();
for (const axis of Object.keys(axes).filter((k) => k !== 'dispatch')) {
assert.equal(
matrixValue(section, axis),
String(axes[axis]),
`matrix "${axis}" must match the descriptor`,
);
}
for (const axis of Object.keys(axes.dispatch).filter((k) => k !== 'builtInSubagents')) {
assert.equal(
matrixValue(section, `dispatch.${axis}`),
String(axes.dispatch[axis]),
`matrix "dispatch.${axis}" must match the descriptor`,
);
}
});
test('the kimi-code section is sourced independently of the kimi section', () => {
// The two are distinct products (Python kimi-cli vs TypeScript Kimi Code CLI);
// the issue's central requirement is that kimi's section was NOT copied. The
// check is scoped to the axis ROWS — the section's prose intro deliberately
// names kimi's Python API to draw the contrast, which is the opposite of a copy.
const rows = matrixSection('kimi-code')
.split('\n')
.filter((l) => l.startsWith('| ') && !l.startsWith('| Axis |') && !l.startsWith('|---'));
assert.ok(rows.length >= 11, 'expected a row per hostIntegration axis');
for (const row of rows) {
assert.ok(
!row.includes('kimi_cli'),
`kimi-code axis row must not cite the Python kimi-cli: ${row.slice(0, 60)}`,
);
assert.ok(
!row.includes('moonshotai.github.io/kimi-cli'),
`kimi-code axis row must not cite kimi-cli docs: ${row.slice(0, 60)}`,
);
}
assert.ok(
rows.some((r) => r.includes('kimi-code/blob/main/docs')),
'kimi-code axes must cite the Kimi Code CLI docs',
);
});
});
describe('#2603: axis values inherited from the Python kimi descriptor are corrected', () => {
test('embeddingMode is declarative — plugins expose no in-process API', () => {
assert.equal(kimiCodeAxes().embeddingMode, 'declarative');
});
test('kimi-code therefore classifies as the declarative-cli profile', () => {
assert.equal(profileOf(kimiCodeAxes()), 'declarative-cli');
});
test('dispatch.nested is true — the coder built-in dispatches nested sub-agents', () => {
assert.equal(kimiCodeAxes().dispatch.nested, true);
});
test('dispatch.maxDepth is the undocumented sentinel, not a guessed integer', () => {
assert.equal(kimiCodeAxes().dispatch.maxDepth, 'undocumented');
});
test('namedDispatch stays false — GSD installs no agent files for this host', () => {
// Guard against a well-meaning "the docs say custom agents exist" edit: flipping
// this makes resolveDispatchType return `gsd-planner` unchanged, which kimi-code
// cannot dispatch (docs/migration/kimi-to-kimi-code.md).
assert.equal(kimiCodeAxes().dispatch.namedDispatch, false);
});
test('the undocumented maxDepth sentinel is reported as a sentinel, not as malformed', () => {
// Surfaced by this change: maxDepth was the ONE dispatch sub-axis with no
// sentinel-specific warning, so the documented fail-closed value was reported
// as "missing or not a number" — indistinguishable from a genuinely broken
// descriptor. kimi-code would have been the sixth runtime to hit that path.
const { warnings } = negotiateHostCapabilities(kimiCodeAxes());
assert.ok(
warnings.some((w) => w.includes('dispatch.maxDepth is undocumented')),
`expected a maxDepth sentinel warning, got: ${JSON.stringify(warnings)}`,
);
assert.ok(
!warnings.some((w) => w.includes('maxDepth is missing or not a number')),
'the documented sentinel must not be reported as a malformed value',
);
});
test('a genuinely malformed maxDepth is still reported as malformed', () => {
// Boundary: the sentinel carve-out must not swallow the real error case.
const axes = kimiCodeAxes();
const malformed = { ...axes, dispatch: { ...axes.dispatch, maxDepth: 'not-a-number' } };
const { warnings } = negotiateHostCapabilities(malformed);
assert.ok(
warnings.some((w) => w.includes('maxDepth is missing or not a number')),
`expected the malformed-value warning, got: ${JSON.stringify(warnings)}`,
);
});
test('both maxDepth paths still degrade the effective value closed to 0', () => {
const axes = kimiCodeAxes();
assert.equal(negotiateHostCapabilities(axes).effective.dispatch.maxDepth, 0);
const malformed = { ...axes, dispatch: { ...axes.dispatch, maxDepth: 'not-a-number' } };
assert.equal(negotiateHostCapabilities(malformed).effective.dispatch.maxDepth, 0);
});
test('the axes that were already correct are left intact', () => {
const axes = kimiCodeAxes();
assert.equal(axes.commandSurface, 'slash-file');
assert.equal(axes.modelMode, 'passive');
assert.equal(axes.hookBus, 'host');
assert.equal(axes.stateIO, 'filesystem');
assert.equal(axes.transport, 'mcp');
assert.equal(axes.runtime, 'node');
assert.equal(axes.dispatch.background, true);
assert.equal(axes.dispatch.backgroundDispatch, true);
assert.equal(axes.dispatch.subagentToolkit, 'built-in-only');
assert.equal(axes.dispatch.isolation, 'orchestrator-worktree');
});
});