fix(workflows): keep caller-input details in workflow input errors (#1089)

* fix(managed): keep caller-input details in managed workflow errors

The managed workflows wrapped every rejected input as
`new AnalysisInputError(op, { cause })` with no issues. The projected
result said "Correct the listed arguments and retry" and listed nothing:

- `rea import-managed-reconstruction`,
  `rea project-managed-application-graph` and
  `rea verify-managed-native-boundaries` lost every schema issue for
  malformed JSON;
- domain checks such as a reconstruction text hash mismatch, or Evidence
  from the wrong operation, lost their message on CLI and MCP;
- `rea compare-managed-members` with a missing file did not say which
  path failed.

Add managedInputError, which projects Zod issues with their paths and
keeps a domain TypeError's message, as the JavaScript workflows already
do. Return the BinaryTargetError from an unopenable comparison path
unchanged, with details.path, as every other path-based command does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(managed): keep nested Evidence schema issues off request paths

A ZodError raised after the request parsed comes from a nested
Evidence result, so its issue paths are relative to that result.
Projecting it against the whole request reported, for example,
artifact.sha256 as a missing request field. Keep request-relative
projection for the raw request's schema failures. Report nested schema
failures as root issues whose message names the nested location.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(managed): type the malformed nested Evidence fixture

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(workflows): keep input details in the remaining workflow services

Inventory projection (project_android_application_graph and
project_apple_application_graph), build_reconstruction_obligation_ledger
and evaluate_reconstruction_coverage had the same issue-less
`AnalysisInputError({ cause })` as the managed services. For example,
evaluating coverage for an unknown boundary returned "Correct the listed
arguments" with no issues, dropping "Unknown reconstruction boundary: X"
on CLI and MCP.

Move the helpers to src/application/workflowInputError.ts and use them
for these services: requestInputError for raw request schema failures,
workflowInputError for nested schema and domain constraint failures.
Classification is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kaoru0822andClaude Opus 5.5 authored and GitHub committed 2026-10-08 23:56:19 +08:00
1 parent a1ed4232de
commit 289aef6838
11 files changed
+198 -49

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
import { z } from "zod";
import { AnalysisInputError } from "../domain/analysisErrorCore.js";
import { projectInputIssues } from "../domain/inputIssueProjection.js";
/** Project schema issues of the raw request onto their request paths. */
export const requestInputError = (
operation: string,
cause: z.ZodError,
input: unknown,
): AnalysisInputError =>
new AnalysisInputError(
operation,
{ cause },
projectInputIssues(cause.issues, input),
);
/**
* Keep the failed constraint when a parsed request is rejected later. Nested
* values such as Evidence results are parsed on their own, so their issue
* paths are relative to that value and are reported in the message, not as
* request paths.
*/
export const workflowInputError = (
operation: string,
cause: z.ZodError | TypeError,
): AnalysisInputError =>
new AnalysisInputError(
operation,
{ cause },
cause instanceof z.ZodError
? cause.issues.map((issue) => ({
path: [],
reason: "invalid_value" as const,
message: `A nested value failed validation at ${issue.path.length === 0 ? "its root" : issue.path.map(String).join(".")}: ${issue.message}`,
}))
: [{ path: [], reason: "invalid_value", message: cause.message }],
);