Skip to content

Commit 6663755

Browse files
creaymaQoder-AI
andcommitted
test(scripts): add platform support-declaration consistency tests
The supported platform set (qoder, codex, claude, cursor, qwen) is declared independently in CLI help, the agent-customize provider registry, the session-analysis platform loader, the Harness report platform gate, the asset-baseline provider gate, and the host adapter matrix. Nothing kept those declarations in agreement, so adding or dropping a host in one owner silently left the others stale. Add test/support-declarations.test.mjs, which derives the declared list from each surface (help output, registry keys, fail-closed error messages, and documented module paths) through public routes only and asserts set equality against one canonical list. This closes roadmap P0 item A-06. Story: roadmap.md TODO A-06 Spec: docs/specs/2026-07-28-a06-support-declaration-consistency.md Test: node --test test/support-declarations.test.mjs (6 pass) Co-authored-by: QoderAI (Qwen 3.8 Max) <qoder_ai@qoder.com>
1 parent 1ad9642 commit 6663755

3 files changed

Lines changed: 192 additions & 1 deletion

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Support-declaration Consistency Tests
2+
3+
Add a contract test that keeps the platform support declarations named by
4+
the roadmap Definition of Done in agreement: CLI help, the agent-customize
5+
provider registry, session-analysis platform loading, Harness report
6+
platform gating, and the host adapter matrix. This is roadmap P0 item A-06.
7+
8+
## Traceability
9+
10+
- Spec ID: 2026-07-28-a06-support-declaration-consistency
11+
- Story: roadmap.md TODO A-06
12+
- Status: Implemented
13+
14+
## Intent
15+
16+
The supported platform set (`qoder`, `codex`, `claude`, `cursor`, `qwen`) is
17+
declared
18+
independently in at least five places:
19+
20+
- `scripts/session-analysis.mjs` and `scripts/session-analysis/analyzer.mjs`
21+
help text and `loadPlatform` gates;
22+
- `scripts/agent-customize/providers/index.mjs` `PROVIDER_COLLECTORS`;
23+
- `scripts/harness-analysis/report-run.mjs` `ANALYZE_HELP` and the
24+
`reportPlatform` whitelist;
25+
- `scripts/coding-agent-practices/asset-baseline.mjs` provider gate;
26+
- `docs/adapters/README.md` host adapter matrix rows.
27+
28+
Nothing asserts these declarations agree. Adding or dropping a host in one
29+
owner silently leaves the others stale, so CLI help, error messages, and docs
30+
can advertise different platform sets. The roadmap Definition of Done requires
31+
that "CLI help, provider registry, session platforms, report platforms, and
32+
docs agree".
33+
34+
## Acceptance
35+
36+
- AC-1: A test derives the platform list each surface declares — help output,
37+
registry keys, loader and gate error messages, and adapter matrix module
38+
paths — and asserts every list equals the canonical supported set.
39+
- AC-2: The test exercises public routes only: the root facade CLI, the
40+
`scripts/session-analysis/index.mjs` and
41+
`scripts/agent-customize/providers/index.mjs` import surfaces, and the
42+
shipped docs file. No private helper is imported.
43+
- AC-3: Unsupported platform input keeps failing closed on each gated route,
44+
and the failure message names the full supported set.
45+
- AC-4: `npm test` picks the test up automatically (default `node --test`
46+
discovery under `test/`).
47+
48+
## Non-goals
49+
50+
- No change to which platforms are supported.
51+
- No new shared runtime constant; each capability keeps owning its
52+
declaration, and the test only proves the declarations agree.
53+
- No assertions on prose wording beyond the declared platform lists.
54+
- Other commands that declare their own platform or provider lists
55+
(coding-agent-practices `inventory` and `asset-integrity`,
56+
`agent-customize`, `agent-lint`, `evidence-bundle`, `task-loop-source`,
57+
`selection-profile`) stay out of scope; the roadmap Definition of Done
58+
names only the surfaces above.
59+
60+
## Plan
61+
62+
1. Add `test/support-declarations.test.mjs` with one canonical
63+
`SUPPORTED_PLATFORMS` list and set-equality helpers.
64+
2. Cover the five surfaces: session-analysis CLI help plus its platform
65+
gate, the exported `SESSION_ANALYSIS_HELP`, `harness analyze` help plus
66+
its platform gate, `PROVIDER_COLLECTORS`, `createAnalyzer` rejection,
67+
the asset-baseline provider gate, and the adapter matrix module
68+
references.
69+
3. Mark roadmap A-06 done.
70+
71+
## Test Evidence
72+
73+
- `node --test test/support-declarations.test.mjs`
74+
- `node --test test/doc-link-graph.test.mjs`

roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ platform depth.
4646
| [ ] | P0 | A-03 | Bind source references and provider-home paths to an explicit provider. | A patch cannot resolve into another host's configuration root. |
4747
| [x] | P0 | A-04 | Add a help-only path to `agent-customize`. | `--help` returns before reading HOME, workspace, SQLite, or plugin caches. |
4848
| [ ] | P0 | A-05 | Fix stale adapter documentation and smoke commands. | The matrix uses current `harness analyze` / `harness render` commands and does not overstate Cursor output support. |
49-
| [ ] | P0 | A-06 | Add support-declaration consistency tests. | CLI help, provider registry, session platforms, report platforms, and docs agree. |
49+
| [x] | P0 | A-06 | Add support-declaration consistency tests. | CLI help, provider registry, session platforms, report platforms, and docs agree. |
5050
| [ ] | P1 | C-01 | Add Codex-specific configuration source precedence. | Checkup distinguishes editable sources from cache, audit, and session data. |
5151
| [ ] | P1 | C-02 | Normalize Codex model, usage, and hook evidence when present. | Missing data stays unavailable; no model, token, or hook values are invented. |
5252
| [ ] | P1 | C-03 | Add a real Codex installation smoke. | Build, install, discover Skills, analyze, render HTML, validate, and reinstall all pass. |

test/support-declarations.test.mjs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import assert from "node:assert/strict";
2+
import { spawnSync } from "node:child_process";
3+
import { existsSync, readFileSync } from "node:fs";
4+
import path from "node:path";
5+
import test from "node:test";
6+
7+
import { PROVIDER_COLLECTORS } from "../scripts/agent-customize/providers/index.mjs";
8+
import { createAnalyzer, SESSION_ANALYSIS_HELP } from "../scripts/session-analysis/index.mjs";
9+
10+
// Canonical support declaration (roadmap A-06): CLI help, provider registry,
11+
// session platforms, report platforms, and docs must all agree on this set.
12+
const SUPPORTED_PLATFORMS = ["qoder", "codex", "claude", "cursor", "qwen"];
13+
14+
const cliPath = path.join(process.cwd(), "scripts", "better-harness.mjs");
15+
const adapterMatrixPath = path.join(process.cwd(), "docs", "adapters", "README.md");
16+
17+
function runBetterHarness(args) {
18+
return spawnSync(process.execPath, [cliPath, ...args], {
19+
cwd: process.cwd(),
20+
encoding: "utf8",
21+
});
22+
}
23+
24+
function sortedSet(values) {
25+
return [...new Set(values)].sort();
26+
}
27+
28+
function assertSameSet(actual, label) {
29+
assert.deepEqual(sortedSet(actual), sortedSet(SUPPORTED_PLATFORMS), `${label} disagrees with the supported platform set`);
30+
}
31+
32+
test("agent-customize provider registry declares exactly the supported platforms", () => {
33+
assertSameSet([...PROVIDER_COLLECTORS.keys()], "PROVIDER_COLLECTORS");
34+
35+
for (const platform of SUPPORTED_PLATFORMS) {
36+
const providerModule = path.join(process.cwd(), "scripts", "agent-customize", "providers", `${platform}.mjs`);
37+
assert.ok(existsSync(providerModule), `missing configured-asset provider module: ${providerModule}`);
38+
}
39+
});
40+
41+
test("session-analysis platform loader declares exactly the supported platforms", async () => {
42+
for (const platform of SUPPORTED_PLATFORMS) {
43+
const platformModule = path.join(process.cwd(), "scripts", "session-analysis", "platforms", `${platform}.mjs`);
44+
assert.ok(existsSync(platformModule), `missing session platform module: ${platformModule}`);
45+
}
46+
47+
let message = "";
48+
try {
49+
await createAnalyzer("__unsupported__");
50+
} catch (error) {
51+
message = error.message;
52+
}
53+
const declared = message.match(/Supported platforms: ([a-z, ]+)\./u)?.[1];
54+
assert.ok(declared, `platform loader did not fail closed with a supported list: ${message}`);
55+
assertSameSet(declared.split(", "), "session-analysis loadPlatform error");
56+
57+
const declaredHelp = SESSION_ANALYSIS_HELP.match(/--platform <([a-z|]+)>/u)?.[1];
58+
assert.ok(declaredHelp, `exported session-analysis help does not declare a platform list:\n${SESSION_ANALYSIS_HELP}`);
59+
assertSameSet(declaredHelp.split("|"), "SESSION_ANALYSIS_HELP platform list");
60+
});
61+
62+
test("session-analysis CLI help and platform gate agree with the supported platforms", () => {
63+
const result = runBetterHarness(["session-analysis", "--help"]);
64+
assert.equal(result.status, 0, result.stderr);
65+
66+
const declared = result.stdout.match(/--platform <([a-z|]+)>/u)?.[1];
67+
assert.ok(declared, `session-analysis help does not declare a platform list:\n${result.stdout}`);
68+
assertSameSet(declared.split("|"), "session-analysis --help platform list");
69+
70+
const gated = runBetterHarness(["session-analysis", "sources", "--platform", "__unsupported__", "--workspace", "."]);
71+
assert.notEqual(gated.status, 0, "session-analysis CLI accepted an unsupported platform");
72+
const gateDeclared = `${gated.stderr}${gated.stdout}`.match(/Supported platforms: ([a-z, ]+)\./u)?.[1];
73+
assert.ok(gateDeclared, `session-analysis CLI did not fail closed with a supported list:\n${gated.stderr}`);
74+
assertSameSet(gateDeclared.split(", "), "session-analysis CLI platform gate");
75+
});
76+
77+
test("harness analyze help and platform gate agree with the supported platforms", () => {
78+
const help = runBetterHarness(["harness", "analyze", "--help"]);
79+
assert.equal(help.status, 0, help.stderr);
80+
81+
const declared = help.stdout.match(/--platform <name>\s+([a-z, ]+or [a-z]+)/u)?.[1];
82+
assert.ok(declared, `harness analyze help does not declare a platform list:\n${help.stdout}`);
83+
assertSameSet(declared.match(/[a-z]+/gu).filter((word) => word !== "or"), "harness analyze --help platform list");
84+
85+
const gated = runBetterHarness(["harness", "analyze", "--platform", "__unsupported__", "--workspace", ".", "--format", "json"]);
86+
assert.notEqual(gated.status, 0, "harness analyze accepted an unsupported platform");
87+
assert.match(`${gated.stderr}${gated.stdout}`, /unsupported Harness report platform/u);
88+
});
89+
90+
test("asset-baseline provider gate lists exactly the supported platforms", () => {
91+
const result = runBetterHarness(["coding-agent-practices", "asset-baseline", "__unsupported__", "--workspace", "."]);
92+
assert.notEqual(result.status, 0, "asset-baseline accepted an unsupported provider");
93+
94+
const declared = `${result.stderr}${result.stdout}`.match(/Supported providers: ([a-z, ]+)\./u)?.[1];
95+
assert.ok(declared, `asset-baseline did not fail closed with a supported list:\n${result.stderr}`);
96+
assertSameSet(declared.split(", "), "asset-baseline provider gate");
97+
});
98+
99+
test("host adapter matrix documents exactly the supported platforms", () => {
100+
const matrix = readFileSync(adapterMatrixPath, "utf8");
101+
102+
for (const platform of SUPPORTED_PLATFORMS) {
103+
assert.ok(
104+
matrix.includes(`scripts/agent-customize/providers/${platform}.mjs`),
105+
`adapter matrix is missing the configured-asset provider for ${platform}`,
106+
);
107+
assert.ok(
108+
matrix.includes(`scripts/session-analysis/platforms/${platform}.mjs`),
109+
`adapter matrix is missing the session platform for ${platform}`,
110+
);
111+
}
112+
113+
const documentedProviders = [...matrix.matchAll(/agent-customize\/providers\/([a-z-]+)\.mjs/gu)].map((match) => match[1]);
114+
const documentedPlatforms = [...matrix.matchAll(/session-analysis\/platforms\/([a-z-]+)\.mjs/gu)].map((match) => match[1]);
115+
assertSameSet(documentedProviders, "adapter matrix configured-asset providers");
116+
assertSameSet(documentedPlatforms, "adapter matrix session platforms");
117+
});

0 commit comments

Comments
 (0)