fix(inspector): accept channel factory seams

This commit is contained in:
Vincent Koc 2026-04-29 06:32:59 -07:00
parent 862d8c9fb8
commit 7b5f706398
No known key found for this signature in database
3 changed files with 52 additions and 1 deletions

View File

@ -5,6 +5,7 @@
### Fixed
- Classify `createChatChannelPlugin` as channel factory metadata in synthetic probe plans so channel-core plugins do not fail as unknown registrars.
- Treat `createChatChannelPlugin` and `defineChannelPluginEntry` as channel registration equivalents when validating fixture expectations.
## 0.3.4 - 2026-04-29

View File

@ -11,6 +11,9 @@ import { readOpenClawTargetSurface } from "./openclaw-target.js";
import { buildCompatibilityReport, buildReport } from "./report.js";
const execFileAsync = promisify(execFile);
const registrationEquivalents = new Map([
["registerChannel", new Set(["createChatChannelPlugin", "defineChannelPluginEntry", "registerChannel"])],
]);
export async function inspectFixtureSet(config, options = {}) {
const { inspections, failures } = await inspectConfiguredFixtures(config, options);
@ -58,7 +61,7 @@ async function inspectConfiguredFixtures(config, options = {}) {
["manifestContracts", inspection.manifestContracts],
]) {
const expected = fixture.expect?.[key] ?? [];
const missing = expected.filter((value) => !observed.includes(value));
const missing = expected.filter((value) => !satisfiesExpectedSeam(key, value, observed));
if (missing.length > 0) {
failures.push(`${fixture.id}: missing ${key}: ${missing.join(", ")}`);
}
@ -68,6 +71,17 @@ async function inspectConfiguredFixtures(config, options = {}) {
return { inspections, failures };
}
function satisfiesExpectedSeam(key, expected, observed) {
if (observed.includes(expected)) {
return true;
}
if (key !== "registrations") {
return false;
}
const equivalents = registrationEquivalents.get(expected);
return Boolean(equivalents && observed.some((value) => equivalents.has(value)));
}
export async function inspectPlugin(fixture, options = {}) {
const config = options.config ?? { rootDir: options.rootDir ?? process.cwd() };
const checkoutPath = fixtureCheckoutPath(config, fixture);

View File

@ -65,6 +65,42 @@ test("fixture set inspection reports missing expected seams", async () => {
assert.match(report.breakages[0].message, /llm_output/);
});
test("fixture set inspection treats channel factories as channel registration coverage", async () => {
const dir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-channel-factory-"));
await mkdir(path.join(dir, "fixture"), { recursive: true });
await writeFile(
path.join(dir, "fixture", "index.js"),
[
'import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";',
"",
"export const channel = createChatChannelPlugin({ id: 'fixture-channel' });",
].join("\n"),
"utf8",
);
const report = await inspectFixtureSet({
version: 1,
submoduleRoot: ".",
rootDir: dir,
fixtures: [
{
id: "fixture",
path: "fixture",
repo: "https://github.com/openclaw/fixture.git",
priority: "high",
seams: ["channel"],
expect: {
registrations: ["registerChannel"],
},
},
],
});
assert.equal(report.status, "pass");
assert.deepEqual(report.breakages, []);
assert.deepEqual(report.fixtures[0].registrations, ["createChatChannelPlugin"]);
});
test("capture entrypoint imports a local fixture and records registrations", async () => {
const dir = await mkdtemp(path.join(os.tmpdir(), "plugin-inspector-capture-"));
const entrypoint = path.join(dir, "fixture.mjs");