fix(cli)!: retain repeated WASM input paths (#9624)

BREAKING CHANGE: caller_input_paths values may now be ordered arrays of strings as well as strings. Clients must accept both forms.
This commit is contained in:
morluto authored and GitHub committed 2026-11-09 19:43:01 +08:00
1 parent 8dc2d7bec4
commit 400a91b5f9
7 files changed
+79 -12

No files matched your search

+2 -1
View File
@@ -10,6 +10,7 @@ import {
parseEvidence,
withEvidenceCallerInputPath,
type Evidence,
type CallerInputPaths,
} from "../domain/evidence.js";
import type { JsonValue } from "../domain/jsonValue.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
@@ -60,7 +61,7 @@ interface CliEvidenceDelivery {
/** Exact one-shot CLI target spelling, when this invocation selects a file. */
readonly callerInputPath?: string;
/** Verbatim named auxiliary path choices for the same direct invocation. */
readonly callerInputPaths?: Readonly<Record<string, string>>;
readonly callerInputPaths?: CallerInputPaths;
/** Derived workflows publish their selected source closure with the result. */
readonly sourceEvidence?: readonly Evidence[];
/** Invocation exclusions cover final cleanup and publication paths/diagnostics. */
+4 -2
View File
@@ -2,6 +2,7 @@ import {
parseEvidence,
withEvidenceCallerInputPath,
type Evidence,
type CallerInputPaths,
} from "../domain/evidence.js";
import type { AnalysisError } from "../domain/analysisErrorBase.js";
import type { Result } from "../domain/result.js";
@@ -13,7 +14,7 @@ export const bindCliEvidenceCallerPath =
(
callerPath: string,
run: () => Promise<Result<Evidence, AnalysisError>>,
additionalPaths?: Readonly<Record<string, string>>,
additionalPaths?: CallerInputPaths,
): (() => Promise<Result<Evidence, AnalysisError>>) =>
async () => {
const result = await run();
@@ -49,9 +50,10 @@ export const finishCliEvidenceCommand = (
providerId: string,
operation: string,
signal: AbortSignal,
additionalPaths?: CallerInputPaths,
) =>
finishAnalysisCommand(
bindCliEvidenceCallerPath(callerPath, run),
bindCliEvidenceCallerPath(callerPath, run, additionalPaths),
service,
providerId,
operation,
+11
View File
@@ -107,6 +107,17 @@ export const registerWasmCommands = (
"wabt-artifact",
"inspect_wasm_artifact",
signal,
options.glue_paths === undefined &&
options.candidate_paths === undefined
? undefined
: {
...(options.glue_paths === undefined
? {}
: { glue_paths: options.glue_paths }),
...(options.candidate_paths === undefined
? {}
: { candidate_paths: options.candidate_paths }),
},
).then(projectCliAnalysisResult),
),
),
+10 -1
View File
@@ -331,16 +331,24 @@ it("retains named auxiliary path choices without changing identity, history or s
result: { rows: ["source facts"] },
}),
);
const paths = { operations_path: "./queries 雪.graphql" };
const paths = {
operations_path: "./queries 雪.graphql",
candidate_paths: ["./a", "./a", "./b"],
};
const rebound = withEvidenceCallerInputPath(
original,
"./schema.graphql",
paths,
);
paths.operations_path = "later unrelated choice";
paths.candidate_paths.push("./later");
expect(rebound.caller_input_paths).toEqual({
operations_path: "./queries 雪.graphql",
candidate_paths: ["./a", "./a", "./b"],
});
expect(Object.isFrozen(rebound.caller_input_paths?.candidate_paths)).toBe(
true,
);
expect(original.caller_input_paths).toBeUndefined();
expect(rebound.evidence_id).toBe(original.evidence_id);
expect(rebound.normalized_result).toBe(original.normalized_result);
@@ -349,6 +357,7 @@ it("retains named auxiliary path choices without changing identity, history or s
expect(
withEvidenceCallerInputPath(rebound, "./schema.graphql", {
operations_path: "./queries 雪.graphql",
candidate_paths: ["./a", "./a", "./b"],
}),
).toBe(rebound);
expect(
+7 -3
View File
@@ -88,8 +88,12 @@ const executionEnvironmentSchema = z.strictObject({
});
const callerInputPathsSchema = z.record(
nulFreeStringSchema,
nulFreeStringSchema,
z.union([nulFreeStringSchema, z.array(nulFreeStringSchema)]),
);
/** Caller-selected auxiliary paths, retaining ordered repeated options. */
export type CallerInputPaths = Readonly<
Record<string, string | readonly string[]>
>;
const evidenceBaseSchema = z
.object({
@@ -107,7 +111,7 @@ const evidenceBaseSchema = z
caller_input_paths: callerInputPathsSchema
.exactOptional()
.describe(
"Verbatim auxiliary input paths keyed by argument name; caller assertions outside semantic identity.",
"Verbatim auxiliary input paths keyed by argument name; repeated selections retain their order. Caller assertions are outside semantic identity.",
),
raw_result: jsonValueSchema.nullable(),
normalized_result: jsonValueSchema,
@@ -375,7 +379,7 @@ export const rebindEvidenceToTargetPath = (
export const withEvidenceCallerInputPath = (
evidence: Evidence,
rawPath: string,
additionalPaths?: Readonly<Record<string, string>>,
additionalPaths?: CallerInputPaths,
): Evidence => {
const callerInputPath = nulFreeStringSchema.parse(rawPath);
const owned = immutableEvidence(evidence);