feat(evidence): discover missing Evidence links without transferring records (#8633)

* feat(evidence): discover missing Evidence links without transferring records

An agent could only learn that a retained record's source was absent by reading
complete records or by having a downstream analysis refuse. The summary said
nothing about links, and complete-record retention was easy to mistake for
source closure.

- Add detail: links to get_evidence_bundle and CLI inspect-evidence-bundle:
  paged link rows with retained or missing status and no record payloads, for
  selected records against the whole session or file.
- Add retained-closure traversal, the walk composed workflows require, reporting
  complete or incomplete. Direct reads make no closure claim.
- Count direct and missing direct links in the summary.

Fixes #8454

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

* fix(evidence): count a repeated Evidence link once in every delivery

The Evidence schema does not deduplicate evidence_links, so the summary counted
a repeated link twice while link rows and counts reported it once. Both now read
one helper for a record's distinct direct links.

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

* test(evidence): validate link delivery against the advertised schemas

The test never called tools/list, so neither the shared validator nor the MCP
client checked its replies against what each profile advertises. A schema that
rejected the links result could have passed. Fetch the advertised definition and
validate every request and reply against it.

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-11-02 05:14:34 -08:00
1 parent 93b8b82db7
commit 710fad8acf
17 files changed
+736 -44

No files matched your search

+2 -2
View File
@@ -26,12 +26,12 @@ export const registerAnalysisViewCommands = (
): void => {
cli.command(CLI_COMMANDS.inspectEvidenceBundle, {
description:
"Inspect a local Evidence bundle completely, as discovery metadata, or as a page of selected complete records",
"Inspect a local Evidence bundle completely, as discovery metadata, as a page of selected complete records, or as direct-link and retained-closure membership.",
args: z.object({
inputJson: z
.string()
.describe(
"JSON or JSON file with absolute path, detail, optional record filters, and records offset/limit",
"JSON or JSON file with absolute path, detail, optional record filters, records or links offset/limit, and links traversal/link_status",
),
}),
run: ({ args }) =>