refactor(coverage): evaluate inline without workspaces

This commit is contained in:
morluto committed 2026-09-29 08:45:00 +08:00
1 parent b3529aa327
commit 9e7605482a
33 files changed
+195 -1269

No files matched your search

+1 -1
View File
@@ -366,7 +366,7 @@ REA handles the app analysis in steps 1–5. The agent performs step 6 with its
| Browser observation | 9 | exact-origin passive CDP capture, bundle and source-map analysis, WebMCP discovery, session timelines, capture diff, visual evidence, and bounded Playwright scenarios |
| Electron analysis | 5 | passive root-confined observation, static application mapping, evidence-backed static/runtime reconciliation, and provider-owned click/wait scenarios |
| JavaScript runtime | 2 | approved attach-only Node/Electron Inspector target discovery plus bounded script and execution-context observation without evaluation or instrumentation |
| Application workflows | 12 | bounded cross-layer traces, unique-only version matching, historical-source to bundle mapping, static export return-shape comparison, approved Linux-isolated extracted-module replay, managed-runtime characterization, reconstruction coverage closure, deterministic obligation ledgers, and end-to-end readiness conformance |
| Application workflows | 11 | bounded cross-layer traces, unique-only version matching, historical-source to bundle mapping, static export return-shape comparison, approved Linux-isolated extracted-module replay, managed-runtime characterization, reconstruction coverage closure, deterministic obligation ledgers, and end-to-end readiness conformance |
| Workspace and observation | 22 | target lifecycle, inline Evidence bundle retrieval, aggregate navigation/address context, direct finite replay-machine evaluation, process/artifact/function comparison, evidence-linked residual-unknown lifecycle |
The public interface describes what the agent is trying to learn. Providers decide how to answer. macOS utilities handle common semantic inspection without launching Hopper; Hopper handles deeper native analysis; the process harness implements controlled behavioral capture.
+1 -1
View File
@@ -169,7 +169,7 @@ rea uninstall --purge-data
| مراقبة المتصفح | 9 | التقاط CDP محدود الأصل وتحليل الحزم وخرائط المصدر واكتشاف WebMCP والفروق والأدلة المرئية |
| تحليل Electron | 5 | مراقبة سلبية ضمن جذور canonical، ورسم ثابت ومحدود للتطبيق، ومطابقة ثابتة/وقت تشغيل قائمة على Evidence |
| وقت تشغيل JavaScript | 2 | اكتشاف أهداف Node/Electron Inspector المعتمدة للاتصال فقط، ومراقبة محدودة للبرامج النصية وسياقات التنفيذ دون تقييم أو تجهيز |
| سير عمل التطبيقات | 12 | تتبع محدود ومقارنة إصدارات فريدة ومقارنة ثابتة لأشكال قيم إرجاع الصادرات وإعادة تشغيل وحدات معزولة ومعتمدة على Linux وتوصيف وقت التشغيل المُدار وإغلاق تغطية إعادة البناء ودفاتر التزامات حتمية والتحقق الشامل من جاهزية إعادة البناء |
| سير عمل التطبيقات | 11 | تتبع محدود ومقارنة إصدارات فريدة ومقارنة ثابتة لأشكال قيم إرجاع الصادرات وإعادة تشغيل وحدات معزولة ومعتمدة على Linux وتوصيف وقت التشغيل المُدار وإغلاق تغطية إعادة البناء ودفاتر التزامات حتمية والتحقق الشامل من جاهزية إعادة البناء |
| جلسة الملف التنفيذي | 22 | فتح الأهداف وحزم الأدلة وتشغيل آلة إعادة محدودة ومقارنة العمليات والقطع والدوال وسجل المجهولات المتبقية |
## استخدام REA مع وكلاء برمجة آخرين
+1 -1
View File
@@ -159,7 +159,7 @@ REA は手順 1〜5 のバイナリ解析を処理し、手順 6 はエージェ
| ブラウザ観察 | 9 | origin 限定 CDP 取得、bundle/source map 解析、WebMCP 検出、セッション、capture diff、視覚証拠 |
| Electron 解析 | 5 | canonical ファイルルート内の受動観察、有界な静的アプリマッピング、Evidence に基づく静的/実行時の照合 |
| JavaScript ランタイム | 2 | 承認済みのアタッチ専用 Node/Electron Inspector ターゲット検出と、評価や計装を行わない有界なスクリプト/実行コンテキスト観察 |
| アプリケーション | 12 | 有界なクロスレイヤー追跡、一意限定のバージョン比較、静的なエクスポート戻り値形状比較、承認済み Linux 隔離 extracted-module replay、マネージドランタイム特性評価、再構築カバレッジ閉包、決定論的な義務台帳、エンドツーエンドの準備適合性検証 |
| アプリケーション | 11 | 有界なクロスレイヤー追跡、一意限定のバージョン比較、静的なエクスポート戻り値形状比較、承認済み Linux 隔離 extracted-module replay、マネージドランタイム特性評価、再構築カバレッジ閉包、決定論的な義務台帳、エンドツーエンドの準備適合性検証 |
| バイナリセッション | 22 | `open_binary`、`binary_session`、証拠バンドル、有限リプレイ状態機械、プロセス/成果物/関数比較、残余未知レジストリ |
## 他のコーディングエージェントで使う
+1 -1
View File
@@ -159,7 +159,7 @@ REA는 1–5단계의 바이너리 분석을 처리합니다. 6단계는 에이
| 브라우저 관찰 | 9 | origin 제한 CDP 캡처, bundle/source map 분석, WebMCP 검색, 세션 타임라인, capture diff 및 시각 증거 |
| Electron 분석 | 5 | canonical 파일 루트 내 수동 관찰, 제한된 정적 앱 매핑, Evidence 기반 정적/런타임 조정 |
| JavaScript 런타임 | 2 | 승인된 연결 전용 Node/Electron Inspector 대상 탐색과 평가·계측 없는 제한된 스크립트 및 실행 컨텍스트 관찰 |
| 애플리케이션 | 12 | 제한된 교차 계층 추적, 고유 일치 버전 비교, 정적 export 반환 형태 비교, 승인된 Linux 격리 extracted-module replay, 관리형 런타임 특성화, 재구성 커버리지 폐쇄, 결정론적 의무 원장, 엔드투엔드 준비 적합성 검증 |
| 애플리케이션 | 11 | 제한된 교차 계층 추적, 고유 일치 버전 비교, 정적 export 반환 형태 비교, 승인된 Linux 격리 extracted-module replay, 관리형 런타임 특성화, 재구성 커버리지 폐쇄, 결정론적 의무 원장, 엔드투엔드 준비 적합성 검증 |
| 바이너리 세션 | 22 | `open_binary`, `binary_session`, 증거 번들, 유한 replay 상태 머신, 프로세스·아티팩트·함수 비교, 잔여 미지수 레지스트리 |
## 다른 코딩 에이전트에서 사용하기
+1 -1
View File
@@ -159,7 +159,7 @@ REA 负责第 1–5 步中的二进制分析。第 6 步由智能体使用其常
| 浏览器观察 | 9 | 精确来源 CDP 抓取、bundle/source map 分析、WebMCP 发现、会话时间线、capture diff 与视觉证据 |
| Electron 分析 | 5 | 限定 canonical 文件根的被动观察、有界静态应用映射,以及基于 Evidence 的静态/运行时对账 |
| JavaScript 运行时 | 2 | 经批准的只附加 Node/Electron Inspector 目标发现,以及不执行求值或插桩的有界脚本和执行上下文观察 |
| 应用工作流 | 12 | 有界跨层追踪、唯一匹配跨版本图比较、静态导出返回形状比较、经批准的 Linux 隔离 extracted-module replay、托管运行时表征、重建覆盖闭合、确定性义务账本和端到端就绪性一致性验证 |
| 应用工作流 | 11 | 有界跨层追踪、唯一匹配跨版本图比较、静态导出返回形状比较、经批准的 Linux 隔离 extracted-module replay、托管运行时表征、重建覆盖闭合、确定性义务账本和端到端就绪性一致性验证 |
| 二进制会话 | 22 | `open_binary`、`binary_session`、证据包、有限重放状态机、进程、制品与函数比较、残余未知项注册表 |
## 与其他编程智能体一起使用
+11 -14
View File
@@ -10,7 +10,7 @@
"skill_version": "23"
},
"tools": {
"total": 115,
"total": 114,
"families": [
{
"id": "direct",
@@ -148,17 +148,16 @@
{
"id": "application",
"surface": "application-workflow",
"count": 12,
"count": 11,
"tools": [
"build_reconstruction_obligation_ledger",
"commit_reconstruction_coverage",
"compare_application_versions",
"compare_javascript_export_shapes",
"compare_source_to_bundle",
"evaluate_reconstruction_coverage",
"evaluate_reconstruction_readiness",
"execute_node_characterization",
"prepare_node_characterization",
"query_reconstruction_coverage",
"run_controlled_replay",
"trace_application_feature",
"trace_javascript_semantics"
@@ -343,14 +342,13 @@
"version": "1",
"capabilities": [
"build_reconstruction_obligation_ledger",
"commit_reconstruction_coverage",
"compare_application_versions",
"compare_javascript_export_shapes",
"compare_source_to_bundle",
"evaluate_reconstruction_coverage",
"evaluate_reconstruction_readiness",
"execute_node_characterization",
"prepare_node_characterization",
"query_reconstruction_coverage",
"run_controlled_replay",
"trace_application_feature",
"trace_javascript_semantics"
@@ -429,7 +427,7 @@
}
],
"cli": {
"primary_count": 67,
"primary_count": 66,
"commands": [
"analyze",
"analyze-javascript-application",
@@ -440,7 +438,6 @@
"capture-electron-scenario",
"capture-process",
"capture-web-screenshot",
"commit-reconstruction-coverage",
"compare",
"compare-application-versions",
"compare-javascript-export-shapes",
@@ -453,6 +450,7 @@
"demangle-swift",
"discover-webmcp-tools",
"doctor",
"evaluate-reconstruction-coverage",
"evaluate-reconstruction-readiness",
"evidence-export",
"evidence-import",
@@ -485,7 +483,6 @@
"prepare-node-characterization",
"project-managed-application-graph",
"providers",
"query-reconstruction-coverage",
"reconcile-javascript-runtime",
"run-controlled-replay",
"run-replay-machine",
@@ -508,15 +505,15 @@
},
"runtime_catalog": {
"counts": {
"cli_commands": 67,
"mcp_tools": 115,
"cli_commands": 66,
"mcp_tools": 114,
"mcp_prompts": 6
},
"digests": {
"tools_sha256": "c0b0319310502e55dd3279361c5a65615a12f25c0e97fb0779b79b7950cecfe0",
"tools_sha256": "6b56b65d4d0b16365617dd2fcd08d8254ddd309b000fa0d173512f544441d17f",
"prompts_sha256": "77c76df62f92484a43cebf5ca110bdf562c38fbee2531d293eeb51d6e712d459",
"combined_sha256": "85d3e5545b3e01eb22b67a1794fdcb737654a1abbea803e1f2445815ee4f17ff",
"providers_sha256": "7446b51788734ebf6f4f702e3a5a8c9f0b61967490c245f30bd37b2060827e6b"
"combined_sha256": "e9e72f81202fc2c0e19fef2b66ec015db90c208005cac9afff90410ce7efd531",
"providers_sha256": "919047a899143c606e521b3b0437c3cd494368504672e4f7423521ab3651f843"
}
}
}
-9
View File
@@ -18,7 +18,6 @@ import type {
UnknownStatus,
UpdateUnknownInput,
} from "../domain/residualUnknown.js";
import type { ReconstructionCoverageWorkspace } from "../domain/reconstructionCoverage.js";
import type {
AnalysisOperation,
AnalysisOperationPort,
@@ -57,14 +56,6 @@ export interface BinarySessionPort extends AnalysisOperationPort {
importAnalysisSnapshot(
snapshot: AnalysisSnapshot,
): Result<number, AnalysisError>;
retainReconstructionCoverageWorkspace(
workspace: ReconstructionCoverageWorkspace,
): "added" | "duplicate";
reconstructionCoverageWorkspace(
workspaceId: string,
revision: number,
): ReconstructionCoverageWorkspace | undefined;
reconstructionCoverageWorkspaces(): readonly ReconstructionCoverageWorkspace[];
recordUnknown(
input: RecordUnknownInput,
): Result<ResidualUnknown, AnalysisError>;
-48
View File
@@ -10,10 +10,6 @@ import {
type AnalysisError,
type UnknownRegistryError,
} from "../domain/errors.js";
import {
parseReconstructionCoverageWorkspace,
type ReconstructionCoverageWorkspace,
} from "../domain/reconstructionCoverage.js";
import type {
RecordUnknownInput,
ResidualUnknown,
@@ -45,10 +41,6 @@ export abstract class BinarySessionRecords {
maxBytes: 64 * 1024 * 1024,
});
readonly #snapshot = new AnalysisSnapshotCache();
readonly #coverageWorkspaces = new Map<
string,
ReconstructionCoverageWorkspace
>();
#snapshotInvalidated = false;
readonly #snapshotListeners = new Set<() => void | Promise<void>>();
@@ -211,30 +203,6 @@ export abstract class BinarySessionRecords {
}
}
retainReconstructionCoverageWorkspace(
workspace: ReconstructionCoverageWorkspace,
): "added" | "duplicate" {
const parsed = parseReconstructionCoverageWorkspace(workspace);
const key = workspaceKey(parsed.workspace_id, parsed.revision);
if (this.#coverageWorkspaces.has(key)) return "duplicate";
this.#coverageWorkspaces.set(key, parsed);
return "added";
}
reconstructionCoverageWorkspace(
workspaceId: string,
revision: number,
): ReconstructionCoverageWorkspace | undefined {
const workspace = this.#coverageWorkspaces.get(
workspaceKey(workspaceId, revision),
);
return workspace === undefined ? undefined : structuredClone(workspace);
}
reconstructionCoverageWorkspaces(): readonly ReconstructionCoverageWorkspace[] {
return sortedWorkspaces(this.#coverageWorkspaces.values());
}
recordUnknown(
input: RecordUnknownInput,
): Result<ResidualUnknown, AnalysisError> {
@@ -305,19 +273,3 @@ export abstract class BinarySessionRecords {
return this.#evidence.verifyUnknownResolution(unknownId);
}
}
const workspaceKey = (workspaceId: string, revision: number): string =>
`${workspaceId}:${String(revision)}`;
const sortedWorkspaces = <
T extends { readonly workspace_id: string; readonly revision: number },
>(
workspaces: Iterable<T>,
): readonly T[] =>
[...workspaces]
.sort(
(left, right) =>
left.workspace_id.localeCompare(right.workspace_id) ||
left.revision - right.revision,
)
.map((workspace) => structuredClone(workspace));
@@ -1,121 +1,44 @@
import { z } from "zod";
import {
AnalysisCancelledError,
AnalysisInputError,
type AnalysisError,
} from "../domain/errors.js";
import type { EvidenceFilePolicy } from "../domain/evidenceBundle.js";
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
import { AnalysisInputError, type AnalysisError } from "../domain/errors.js";
import {
evaluateReconstructionClosure,
reconstructionCoverageWorkspaceSchema,
reconstructionCoverageDataSchema,
} from "../domain/reconstructionCoverage.js";
import { jsonValueSchema, type JsonValue } from "../domain/jsonValue.js";
import { err, ok, type Result } from "../domain/result.js";
import type { ExecutionOptions } from "./AnalysisProvider.js";
import {
readReconstructionCoverageWorkspace,
writeReconstructionCoverageWorkspace,
} from "./ReconstructionCoverageWorkspaceStore.js";
const COMMIT_OPERATION = "commit_reconstruction_coverage" as const;
const QUERY_OPERATION = "query_reconstruction_coverage" as const;
const isAborted = (signal: AbortSignal | undefined): boolean =>
signal?.aborted === true;
export const reconstructionCoverageCommitInputSchema = z.strictObject({
approved: z.literal(true),
workspace_path: z.string().min(1).max(4_096),
expected_revision: z.number().int().min(1).nullable(),
workspace: reconstructionCoverageWorkspaceSchema,
});
export const reconstructionCoverageQueryInputSchema = z.strictObject({
workspace_path: z.string().min(1).max(4_096),
export const reconstructionCoverageEvaluationInputSchema = z.strictObject({
coverage: reconstructionCoverageDataSchema,
boundary_id: z.string().min(1).max(200),
});
export const reconstructionCoverageCommitOutputSchema = z.strictObject({
workspace_path: z.string(),
bytes: z.number().int().min(0),
workspace_id: z.string().regex(/^rcw_[a-f0-9]{64}$/u),
revision: z.number().int().min(1),
revision_sha256: z.string().regex(/^[a-f0-9]{64}$/u),
evidence_records: z.number().int().min(0),
});
/** Commit one caller-approved canonical reconstruction coverage CAS revision. */
export const commitReconstructionCoverage = async (
/** Evaluate inline reconstruction coverage against a named boundary. */
export const evaluateReconstructionCoverage = (
rawInput: unknown,
policy: EvidenceFilePolicy,
options: ExecutionOptions = {},
): Promise<Result<JsonValue, AnalysisError>> => {
const parsed = reconstructionCoverageCommitInputSchema.safeParse(rawInput);
nowEpochMs = Date.now(),
): Result<JsonValue, AnalysisError> => {
const parsed =
reconstructionCoverageEvaluationInputSchema.safeParse(rawInput);
if (!parsed.success)
return err(
new AnalysisInputError(COMMIT_OPERATION, { cause: parsed.error }),
);
if (isAborted(options.signal))
return err(new AnalysisCancelledError(COMMIT_OPERATION));
const written = await writeReconstructionCoverageWorkspace(
parsed.data.workspace,
parsed.data.workspace_path,
parsed.data.expected_revision,
policy,
);
if (!written.ok) return written;
return ok(
jsonValueSchema.parse({
workspace_path: written.value.path,
bytes: written.value.bytes,
workspace_id: parsed.data.workspace.workspace_id,
revision: parsed.data.workspace.revision,
revision_sha256: parsed.data.workspace.revision_sha256,
evidence_records: parsed.data.workspace.evidence_bundle.records.length,
}),
);
};
/** Read one coverage revision and evaluate a named fail-closed boundary. */
export const queryReconstructionCoverage = async (
rawInput: unknown,
policy: EvidenceFilePolicy,
nowEpochMs: number,
options: ExecutionOptions = {},
): Promise<Result<JsonValue, AnalysisError>> => {
const parsed = reconstructionCoverageQueryInputSchema.safeParse(rawInput);
if (!parsed.success)
return err(
new AnalysisInputError(QUERY_OPERATION, { cause: parsed.error }),
);
if (isAborted(options.signal))
return err(new AnalysisCancelledError(QUERY_OPERATION));
const loaded = await readReconstructionCoverageWorkspace(
parsed.data.workspace_path,
policy,
);
if (!loaded.ok) return loaded;
if (loaded.value === null)
return err(
new AnalysisInputError(QUERY_OPERATION, {
cause: new TypeError(
"Reconstruction coverage workspace does not exist",
),
new AnalysisInputError("evaluate_reconstruction_coverage", {
cause: parsed.error,
}),
);
if (isAborted(options.signal))
return err(new AnalysisCancelledError(QUERY_OPERATION));
try {
return ok(
jsonValueSchema.parse(
evaluateReconstructionClosure(
loaded.value,
parsed.data.coverage,
parsed.data.boundary_id,
nowEpochMs,
),
),
);
} catch (cause: unknown) {
return err(new AnalysisInputError(QUERY_OPERATION, { cause }));
return err(
new AnalysisInputError("evaluate_reconstruction_coverage", { cause }),
);
}
};
@@ -1,61 +0,0 @@
import { WorkspaceStorageError } from "../domain/errors.js";
import type { EvidenceFilePolicy } from "../domain/evidenceBundle.js";
import {
parseReconstructionCoverageWorkspace,
serializeReconstructionCoverageWorkspace,
type ReconstructionCoverageWorkspace,
} from "../domain/reconstructionCoverage.js";
import { err, ok, type Result } from "../domain/result.js";
import {
readRevisionedWorkspace,
writeRevisionedWorkspace,
type RevisionedWorkspaceCodec,
} from "./RevisionedWorkspaceStore.js";
const codec: RevisionedWorkspaceCodec<ReconstructionCoverageWorkspace> = {
parse: parseReconstructionCoverageWorkspace,
serialize: serializeReconstructionCoverageWorkspace,
validateNext: (current, next, expectedRevision) => {
if ((current?.revision ?? null) !== expectedRevision)
return err(new WorkspaceStorageError("update", "revision-conflict"));
if (current === null)
return next.revision === 1 && next.previous_revision_sha256 === null
? ok(null)
: err(new WorkspaceStorageError("update", "revision-conflict"));
if (
current.name !== next.name ||
current.workspace_id !== next.workspace_id
)
return err(new WorkspaceStorageError("update", "name-conflict"));
return next.revision === current.revision + 1 &&
next.previous_revision_sha256 === current.revision_sha256
? ok(null)
: err(new WorkspaceStorageError("update", "revision-conflict"));
},
};
/** Read a validated reconstruction coverage workspace revision. */
export const readReconstructionCoverageWorkspace = (
path: string,
policy: EvidenceFilePolicy,
): Promise<
Result<ReconstructionCoverageWorkspace | null, WorkspaceStorageError>
> => readRevisionedWorkspace(path, policy, codec);
/** Atomically append one reconstruction coverage workspace CAS revision. */
export const writeReconstructionCoverageWorkspace = (
workspace: ReconstructionCoverageWorkspace,
path: string,
expectedRevision: number | null,
policy: EvidenceFilePolicy,
): Promise<
Result<
{ readonly path: string; readonly bytes: number },
WorkspaceStorageError
>
> =>
writeRevisionedWorkspace(path, policy, {
document: workspace,
expectedRevision,
codec,
});
-190
View File
@@ -1,190 +0,0 @@
import {
createStoreFileLock,
removeStaleStoreFileLock,
type StoreFileLock,
} from "./StoreFileLock.js";
import { lstat, readFile, realpath } from "node:fs/promises";
import { basename, dirname, resolve } from "node:path";
import { isPathWithinRoot } from "../domain/localPath.js";
import writeFileAtomic from "write-file-atomic";
import type { EvidenceFilePolicy } from "../domain/evidenceBundle.js";
import { isJsonWithinLimits } from "../domain/jsonLimits.js";
import { WorkspaceStorageError } from "../domain/errors.js";
import { err, ok, type Result } from "../domain/result.js";
import { canonicalizeConfiguredRoots } from "./ConfiguredRoots.js";
type WorkspaceResult<Value> = Result<Value, WorkspaceStorageError>;
/** Parser, serializer, and CAS transition owned by one revisioned workspace. */
export interface RevisionedWorkspaceCodec<Document> {
readonly parse: (input: unknown) => Document;
readonly serialize: (document: Document) => string;
readonly validateNext: (
current: Document | null,
next: Document,
expectedRevision: number | null,
) => WorkspaceResult<null>;
}
/** Read one root-confined, owner-only revisioned workspace document. */
export const readRevisionedWorkspace = async <Document>(
path: string,
policy: EvidenceFilePolicy,
codec: RevisionedWorkspaceCodec<Document>,
): Promise<WorkspaceResult<Document | null>> => {
if (policy.roots.length === 0)
return err(new WorkspaceStorageError("read", "disabled"));
try {
const destination = await resolveDestination(path, policy.roots);
if (destination === null)
return err(new WorkspaceStorageError("read", "outside-root"));
return await readWorkspaceFile(destination, policy, codec);
} catch (cause: unknown) {
return err(new WorkspaceStorageError("read", "io", { cause }));
}
};
export interface RevisionedWorkspaceWriteInput<Document> {
readonly document: Document;
readonly expectedRevision: number | null;
readonly codec: RevisionedWorkspaceCodec<Document>;
}
/** Atomically append one validated CAS-linked revision under an exclusive lock. */
export const writeRevisionedWorkspace = async <Document>(
path: string,
policy: EvidenceFilePolicy,
input: RevisionedWorkspaceWriteInput<Document>,
): Promise<
WorkspaceResult<{ readonly path: string; readonly bytes: number }>
> => {
const { document, expectedRevision, codec } = input;
if (policy.roots.length === 0)
return err(new WorkspaceStorageError("update", "disabled"));
let encoded: string;
try {
encoded = codec.serialize(document);
} catch (cause: unknown) {
return err(new WorkspaceStorageError("update", "integrity", { cause }));
}
const bytes = Buffer.byteLength(encoded, "utf8");
if (bytes > policy.maxBytes)
return err(new WorkspaceStorageError("update", "too-large"));
let lock: StoreFileLock | undefined;
try {
const destination = await resolveDestination(path, policy.roots);
if (destination === null)
return err(new WorkspaceStorageError("update", "outside-root"));
const acquired = await acquireLock(destination);
if (!acquired.ok) return acquired;
lock = acquired.value;
const current = await readWorkspaceFile(destination, policy, codec);
if (!current.ok) return current;
const checked = codec.validateNext(
current.value,
document,
expectedRevision,
);
if (!checked.ok) return checked;
await writeFileAtomic(destination, encoded, {
encoding: "utf8",
mode: 0o600,
fsync: true,
});
return ok({ path: resolve(path), bytes });
} catch (cause: unknown) {
return err(new WorkspaceStorageError("update", "io", { cause }));
} finally {
if (lock !== undefined) await lock.release();
}
};
const resolveDestination = async (
path: string,
roots: readonly string[],
): Promise<string | null> => {
const requested = resolve(path);
const canonicalParent = await realpath(dirname(requested));
const destination = resolve(canonicalParent, basename(requested));
for (const root of await canonicalizeConfiguredRoots(
roots.map((configuredRoot) => resolve(configuredRoot)),
)) {
if (isPathWithinRoot(root, destination)) return destination;
}
return null;
};
const readWorkspaceFile = async <Document>(
destination: string,
policy: EvidenceFilePolicy,
codec: RevisionedWorkspaceCodec<Document>,
): Promise<WorkspaceResult<Document | null>> => {
const stats = await lstat(destination).catch((cause: unknown) => {
if (isFileNotFound(cause)) return undefined;
throw cause;
});
if (stats === undefined) return ok(null);
if (!stats.isFile() || stats.isSymbolicLink())
return err(new WorkspaceStorageError("read", "not-file"));
if (stats.size > policy.maxBytes)
return err(new WorkspaceStorageError("read", "too-large"));
const encoded = await readFile(destination);
if (encoded.byteLength > policy.maxBytes)
return err(new WorkspaceStorageError("read", "too-large"));
let decoded: unknown;
try {
decoded = JSON.parse(encoded.toString("utf8"));
} catch (cause: unknown) {
return err(new WorkspaceStorageError("read", "invalid-json", { cause }));
}
if (!isJsonWithinLimits(decoded, policy))
return err(new WorkspaceStorageError("read", "too-large"));
try {
return ok(codec.parse(decoded));
} catch (cause: unknown) {
return err(new WorkspaceStorageError("read", "integrity", { cause }));
}
};
const acquireLock = async (
destination: string,
): Promise<WorkspaceResult<StoreFileLock>> => {
const path = `${destination}.lock`;
try {
return ok(await createStoreFileLock(path));
} catch (cause: unknown) {
if (isAlreadyExists(cause) && (await removeStaleStoreFileLock(path))) {
try {
return ok(await createStoreFileLock(path));
} catch (retryCause: unknown) {
return err(
new WorkspaceStorageError(
"update",
isAlreadyExists(retryCause) ? "locked" : "io",
{ cause: retryCause },
),
);
}
}
return err(
new WorkspaceStorageError(
"update",
isAlreadyExists(cause) ? "locked" : "io",
{ cause },
),
);
}
};
const isFileNotFound = (cause: unknown): boolean =>
errorCode(cause) === "ENOENT";
const isAlreadyExists = (cause: unknown): boolean =>
errorCode(cause) === "EEXIST";
const errorCode = (cause: unknown): unknown =>
typeof cause === "object" && cause !== null && "code" in cause
? cause.code
: undefined;
+21 -73
View File
@@ -22,10 +22,8 @@ import {
prepareNodeCharacterization,
} from "./application/NodeRuntimeCharacterizationService.js";
import {
commitReconstructionCoverage,
queryReconstructionCoverage,
reconstructionCoverageCommitInputSchema,
reconstructionCoverageQueryInputSchema,
evaluateReconstructionCoverage,
reconstructionCoverageEvaluationInputSchema,
} from "./application/ReconstructionCoverageService.js";
import {
buildReconstructionObligationLedgerEvidenceValidated,
@@ -35,10 +33,7 @@ import {
evaluateReconstructionReadinessValidated,
resolveReconstructionReadinessRequest,
} from "./application/ReconstructionReadinessService.js";
import {
authorizeFileReadWithDeferredWrite,
authorizeRootPermission,
} from "./application/DeferredFileAuthorization.js";
import { authorizeRootPermission } from "./application/DeferredFileAuthorization.js";
import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
import { CLI_COMMANDS } from "./cliCommandNames.js";
import { parseCliJsonInput } from "./cliJsonInput.js";
@@ -157,7 +152,7 @@ export const registerApplicationCommands = (
});
registerObligationLedgerCommand(cli, logger);
registerReadinessCommand(cli, logger);
registerCoverageCommands(cli, logger);
registerCoverageCommand(cli, logger);
};
const registerObligationLedgerCommand = (
@@ -228,74 +223,27 @@ const registerAuthorizedJsonCommand = ({
});
};
const registerCoverageCommands = (
cli: ReturnType<typeof Cli.create>,
logger: Logger,
): void => {
registerAuthorizedJsonCommand({
const registerCoverageCommand = (cli: CliInstance, logger: Logger): void =>
registerJsonCommand({
cli,
logger,
name: CLI_COMMANDS.commitReconstructionCoverage,
description:
"Commit one canonical reconstruction coverage workspace revision",
workflow: async (config, authority, input) => {
const parsed = reconstructionCoverageCommitInputSchema.safeParse(input);
if (!parsed.success)
return {
ok: false,
error: new AnalysisInputError(
CLI_COMMANDS.commitReconstructionCoverage,
{ cause: parsed.error },
),
};
const authorization = await authorizeFileReadWithDeferredWrite(
authority,
{
path: parsed.data.workspace_path,
readCapability: "reconstruction_coverage_read",
writeCapability: "reconstruction_coverage_write",
operation: CLI_COMMANDS.commitReconstructionCoverage,
},
);
if (!authorization.ok) return authorization;
const write = await authorization.value.authorizeWrite();
if (!write.ok) return write;
return commitReconstructionCoverage(
parsed.data,
config.evidenceFilePolicy,
);
name: CLI_COMMANDS.evaluateReconstructionCoverage,
description: "Evaluate inline fail-closed reconstruction coverage",
resolveInput: (input) => {
const parsed =
reconstructionCoverageEvaluationInputSchema.safeParse(input);
return parsed.success
? { ok: true, value: parsed.data }
: {
ok: false,
error: new AnalysisInputError(
CLI_COMMANDS.evaluateReconstructionCoverage,
{ cause: parsed.error },
),
};
},
workflow: (input) => evaluateReconstructionCoverage(input),
});
registerAuthorizedJsonCommand({
cli,
logger,
name: CLI_COMMANDS.queryReconstructionCoverage,
description: "Evaluate one fail-closed reconstruction coverage boundary",
workflow: async (config, authority, input) => {
const parsed = reconstructionCoverageQueryInputSchema.safeParse(input);
if (!parsed.success)
return {
ok: false,
error: new AnalysisInputError(
CLI_COMMANDS.queryReconstructionCoverage,
{ cause: parsed.error },
),
};
const authorized = await authorizeRootPermission(authority, {
capability: "reconstruction_coverage_read",
roots: [parsed.data.workspace_path],
access: "read",
operation: CLI_COMMANDS.queryReconstructionCoverage,
});
if (!authorized.ok) return authorized;
return queryReconstructionCoverage(
parsed.data,
config.evidenceFilePolicy,
Date.now(),
);
},
});
};
const configuredAuthority = async (): Promise<
| {
+1 -2
View File
@@ -65,8 +65,7 @@ export const CLI_COMMANDS = Object.freeze({
executeNodeCharacterization: "execute-node-characterization",
buildReconstructionObligationLedger: "build-reconstruction-obligation-ledger",
evaluateReconstructionReadiness: "evaluate-reconstruction-readiness",
commitReconstructionCoverage: "commit-reconstruction-coverage",
queryReconstructionCoverage: "query-reconstruction-coverage",
evaluateReconstructionCoverage: "evaluate-reconstruction-coverage",
});
/** Ordered primary CLI inventory; aliases are intentionally excluded. */
-2
View File
@@ -125,8 +125,6 @@ const buildPermissionCeilings = (
const ceilings: PermissionCeiling[] = [
permissionScope("evidence_read", arrays.evidenceRoots),
permissionScope("evidence_write", arrays.evidenceRoots),
permissionScope("reconstruction_coverage_read", arrays.evidenceRoots),
permissionScope("reconstruction_coverage_write", arrays.evidenceRoots),
permissionScope("snapshot_read", arrays.analysisSnapshotRoots),
permissionScope("snapshot_write", arrays.analysisSnapshotRoots),
permissionScope("artifact_extract", ["/"]),
+42 -63
View File
@@ -20,11 +20,7 @@ import {
nodeCharacterizationPreparationInputSchema,
nodeCharacterizationPreparationOutputSchema,
} from "../domain/nodeRuntimeCharacterization.js";
import {
reconstructionCoverageCommitInputSchema,
reconstructionCoverageCommitOutputSchema,
reconstructionCoverageQueryInputSchema,
} from "../application/ReconstructionCoverageService.js";
import { reconstructionCoverageEvaluationInputSchema } from "../application/ReconstructionCoverageService.js";
import { reconstructionClosureResultSchema } from "../domain/reconstructionCoverage.js";
import {
reconstructionObligationLedgerInputSchema,
@@ -99,33 +95,6 @@ const NODE_PREPARATION_EXAMPLE = jsonObjectSchema.parse({
},
});
const COVERAGE_WORKSPACE_EXAMPLE = jsonObjectSchema.parse({
workspace_id: `rcw_${HASH}`,
name: "replacement",
revision: 1,
previous_revision_sha256: null,
revision_sha256: HASH,
evidence_bundle: {
artifacts: [],
providers: [],
environments: [],
scenarios: [],
captures: [],
unknowns: [],
records: [],
},
artifacts: [],
surfaces: [],
owners: [],
claims: [],
verifier_contracts: [],
verifier_results: [],
residual_unknown_ids: [],
contradictions: [],
package_proofs: [],
boundaries: [],
});
/** Provider-neutral graph workflow contracts shared by MCP and CLI adapters. */
export const APPLICATION_TOOL_CONTRACTS = [
{
@@ -184,7 +153,7 @@ export const APPLICATION_TOOL_CONTRACTS = [
name: "compare_source_to_bundle",
...toolContractMetadata("compare_source_to_bundle"),
description:
"Compare a cryptographically committed HistoricalSourceGraph/v1 with authenticated JavaScript Application Graph Evidence supplied directly or by session Evidence ID. Uses explicit exact-digest, source-map path, current-path, suffix, and basename signals with stable weights. Classifies unchanged, modified, removed, split, merged, duplicated, and unknown; incomplete coverage and ambiguous weak signals never become absence or forced matches.",
"Compare a cryptographically committed HistoricalSourceGraph with authenticated JavaScript Application Graph Evidence supplied directly or by session Evidence ID. Uses explicit exact-digest, source-map path, current-path, suffix, and basename signals with stable weights. Classifies unchanged, modified, removed, split, merged, duplicated, and unknown; incomplete coverage and ambiguous weak signals never become absence or forced matches.",
kind: "application",
inputSchema: compareSourceToBundleRequestSchema,
outputSchema: sourceToBundleOutputSchema,
@@ -331,7 +300,7 @@ export const APPLICATION_TOOL_CONTRACTS = [
name: "evaluate_reconstruction_readiness",
...toolContractMetadata("evaluate_reconstruction_readiness"),
description:
"Evaluate the fixed nine-stage public reconstruction journey into a deterministic ReconstructionReadinessReport/v1. Exact capability limits, provider routing, CLI/MCP status parity, bounded authority, partial-order comparison, contradictions, obligation closure, cleanup, and replay digests fail closed. Aggregate pass is emitted only when every required stage and check passes with attributable Evidence.",
"Evaluate the fixed nine-stage public reconstruction journey into a deterministic ReconstructionReadinessReport. Exact capability limits, provider routing, CLI/MCP status parity, bounded authority, partial-order comparison, contradictions, obligation closure, cleanup, and replay digests fail closed. Aggregate pass is emitted only when every required stage and check passes with attributable Evidence.",
kind: "application",
inputSchema: reconstructionReadinessInputSchema,
outputSchema: reconstructionReadinessOutputSchema,
@@ -343,38 +312,51 @@ export const APPLICATION_TOOL_CONTRACTS = [
],
},
{
name: "commit_reconstruction_coverage",
...toolContractMetadata("commit_reconstruction_coverage"),
name: "evaluate_reconstruction_coverage",
...toolContractMetadata("evaluate_reconstruction_coverage"),
description:
"Atomically commit one canonical evidence-backed reconstruction coverage workspace revision under an approved root. CAS revisions reject lost updates; every Evidence and residual-unknown reference must resolve in the embedded canonical bundle.",
"Evaluate inline evidence-backed reconstruction coverage against one named boundary. Missing ownership or inventory is partial; stale, weak, truncated, skipped, or unresolved proof is unknown; contradictions, failed proof, missing owners, and authority routing fail closed.",
kind: "application",
inputSchema: reconstructionCoverageCommitInputSchema,
outputSchema: reconstructionCoverageCommitOutputSchema,
examples: [
{
title: "Commit the first canonical coverage revision",
input: {
approved: true,
workspace_path: "/approved/coverage.json",
expected_revision: null,
workspace: COVERAGE_WORKSPACE_EXAMPLE,
},
},
],
},
{
name: "query_reconstruction_coverage",
...toolContractMetadata("query_reconstruction_coverage"),
description:
"Evaluate one named reconstruction boundary from a canonical coverage workspace. Missing ownership or inventory is partial; stale, weak, truncated, skipped, or unresolved proof is unknown; contradictions, failed proof, missing owners, and authority routing fail closed.",
kind: "application",
inputSchema: reconstructionCoverageQueryInputSchema,
inputSchema: reconstructionCoverageEvaluationInputSchema,
outputSchema: reconstructionClosureResultSchema,
examples: [
{
title: "Evaluate one replacement boundary",
input: {
workspace_path: "/approved/coverage.json",
coverage: {
evidence_bundle: {
artifacts: [],
providers: [],
environments: [],
scenarios: [],
captures: [],
unknowns: [],
records: [],
},
artifacts: [],
surfaces: [],
owners: [],
claims: [],
verifier_contracts: [],
verifier_results: [],
residual_unknown_ids: [],
contradictions: [],
package_proofs: [],
boundaries: [
{
boundary_id: "replacement.cli",
title: "CLI replacement",
required_surface_ids: ["cli.help"],
required_claim_ids: ["claim.cli.help"],
required_package_proof_kinds: [
"clean-install",
"authority-independence",
],
allowed_dispositions: [],
allowed_unknown_ids: [],
},
],
},
boundary_id: "replacement.cli",
},
},
@@ -414,11 +396,8 @@ export function applicationToolContract(
name: "evaluate_reconstruction_readiness",
): (typeof APPLICATION_TOOL_CONTRACTS)[9];
export function applicationToolContract(
name: "commit_reconstruction_coverage",
name: "evaluate_reconstruction_coverage",
): (typeof APPLICATION_TOOL_CONTRACTS)[10];
export function applicationToolContract(
name: "query_reconstruction_coverage",
): (typeof APPLICATION_TOOL_CONTRACTS)[11];
export function applicationToolContract(
name: (typeof APPLICATION_TOOL_CONTRACTS)[number]["name"],
): (typeof APPLICATION_TOOL_CONTRACTS)[number] {
+1 -2
View File
@@ -63,8 +63,7 @@ describe("tool contract inventory", () => {
"execute_node_characterization",
"build_reconstruction_obligation_ledger",
"evaluate_reconstruction_readiness",
"commit_reconstruction_coverage",
"query_reconstruction_coverage",
"evaluate_reconstruction_coverage",
]);
expect(new Set(TOOL_CONTRACTS.map(({ name }) => name)).size).toBe(
TOOL_CONTRACTS.length,
+1 -5
View File
@@ -165,11 +165,7 @@ export const TOOL_EFFECTS: Readonly<Record<string, ToolEffects>> = {
writesFilesystem: true,
launchesProcess: true,
}),
commit_reconstruction_coverage: effects({
writesFilesystem: true,
mutatesSession: true,
}),
query_reconstruction_coverage: effects({ mutatesSession: true }),
evaluate_reconstruction_coverage: effects(),
open_binary: effects({ mutatesSession: true, launchesProcess: true }),
close_binary: effects({
mutatesSession: true,
-2
View File
@@ -46,8 +46,6 @@ const PROPERTY_DESCRIPTIONS: Readonly<Record<string, string>> = {
unknown_id: "Exact residual-unknown identifier.",
unknown_registry_approved:
"Explicit approval to record bounded residual uncertainty in the session registry.",
workspace_path:
"Approved local path of the persistent investigation workspace.",
};
/** Attach caller guidance to a canonical schema for the SDK wire projection. */
-2
View File
@@ -12,8 +12,6 @@ export const PERMISSION_CAPABILITIES = [
"v8_inspector_observe",
"evidence_read",
"evidence_write",
"reconstruction_coverage_read",
"reconstruction_coverage_write",
"snapshot_read",
"snapshot_write",
"artifact_extract",
+3 -6
View File
@@ -1,7 +1,7 @@
import { createEvidence } from "./evidence.js";
import { createEvidenceBundle } from "./evidenceBundle.js";
import {
createReconstructionCoverageWorkspace,
createReconstructionCoverageData,
createReconstructionVerifierContract,
} from "./reconstructionCoverage.js";
@@ -35,7 +35,7 @@ export const reconstructionCoverageEvidenceId = (character: string): string => {
};
/** Build one fully closed reconstruction-coverage workspace. */
export const completeReconstructionCoverageWorkspace = () => {
export const completeReconstructionCoverageData = () => {
const contract = createReconstructionVerifierContract({
verifier_id: "verify.cli.help",
claim_ids: ["claim.cli.help"],
@@ -46,10 +46,7 @@ export const completeReconstructionCoverageWorkspace = () => {
normalization_sha256: digest("4"),
normalization_removes_dimensions: false,
});
return createReconstructionCoverageWorkspace({
name: "fixture",
revision: 1,
previous_revision_sha256: null,
return createReconstructionCoverageData({
evidence_bundle: createEvidenceBundle(EVIDENCE_RECORDS),
artifacts: [
{
+22 -59
View File
@@ -1,21 +1,20 @@
import { describe, expect, it } from "vitest";
import {
completeReconstructionCoverageWorkspace,
completeReconstructionCoverageData,
RECONSTRUCTION_COVERAGE_NOW,
reconstructionCoverageEvidenceId,
} from "./reconstructionCoverage.fixture.js";
import {
createReconstructionCoverageWorkspace,
createReconstructionCoverageData,
evaluateReconstructionClosure,
parseReconstructionCoverageWorkspace,
} from "./reconstructionCoverage.js";
const digest = (character: string): string => character.repeat(64);
describe("reconstruction coverage closure", () => {
it("returns ready only when ownership, verification, package, and authority closure pass", () => {
const workspace = completeReconstructionCoverageWorkspace();
const workspace = completeReconstructionCoverageData();
expect(
evaluateReconstructionClosure(
@@ -33,22 +32,16 @@ describe("reconstruction coverage closure", () => {
reconstructionCoverageEvidenceId("5"),
].sort(),
});
expect(parseReconstructionCoverageWorkspace(workspace)).toEqual(workspace);
expect(createReconstructionCoverageData(workspace)).toEqual(workspace);
});
it("keeps an incomplete inventory partial despite every registered verifier passing", () => {
const workspace = completeReconstructionCoverageWorkspace();
const {
revision_sha256: _revisionSha256,
workspace_id: _workspaceId,
...semantic
} = workspace;
const workspace = completeReconstructionCoverageData();
const semantic = workspace;
const boundary = workspace.boundaries[0];
if (boundary === undefined) throw new Error("Expected fixture boundary");
const incomplete = createReconstructionCoverageWorkspace({
const incomplete = createReconstructionCoverageData({
...semantic,
revision: 2,
previous_revision_sha256: workspace.revision_sha256,
boundaries: [
{
...boundary,
@@ -83,19 +76,13 @@ describe("reconstruction coverage closure", () => {
});
it("invalidates stale verifier contracts and detected authority routing", () => {
const workspace = completeReconstructionCoverageWorkspace();
const workspace = completeReconstructionCoverageData();
const owner = workspace.owners[0];
if (owner === undefined || owner.ownership.disposition !== "implemented")
throw new Error("Expected implemented fixture owner");
const {
revision_sha256: _revisionSha256,
workspace_id: _workspaceId,
...semantic
} = workspace;
const changed = createReconstructionCoverageWorkspace({
const semantic = workspace;
const changed = createReconstructionCoverageData({
...semantic,
revision: 2,
previous_revision_sha256: workspace.revision_sha256,
owners: [
{
...owner,
@@ -125,16 +112,10 @@ describe("reconstruction coverage closure", () => {
});
it("never lets mock-strength or stale results satisfy stronger current claims", () => {
const workspace = completeReconstructionCoverageWorkspace();
const {
revision_sha256: _revisionSha256,
workspace_id: _workspaceId,
...semantic
} = workspace;
const stale = createReconstructionCoverageWorkspace({
const workspace = completeReconstructionCoverageData();
const semantic = workspace;
const stale = createReconstructionCoverageData({
...semantic,
revision: 2,
previous_revision_sha256: workspace.revision_sha256,
verifier_results: workspace.verifier_results.map((result) => ({
...result,
observed_at: "2026-07-01T00:00:00.000Z",
@@ -156,19 +137,13 @@ describe("reconstruction coverage closure", () => {
describe("reconstruction coverage verifier observations", () => {
it("orders offset-bearing verifier timestamps chronologically", () => {
const workspace = completeReconstructionCoverageWorkspace();
const workspace = completeReconstructionCoverageData();
const result = workspace.verifier_results[0];
if (result === undefined)
throw new Error("Expected fixture verifier result");
const {
revision_sha256: _revisionSha256,
workspace_id: _workspaceId,
...semantic
} = workspace;
const changed = createReconstructionCoverageWorkspace({
const semantic = workspace;
const changed = createReconstructionCoverageData({
...semantic,
revision: 2,
previous_revision_sha256: workspace.revision_sha256,
verifier_results: [
{ ...result, observed_at: "2026-07-16T08:00:00.000Z" },
{
@@ -192,19 +167,13 @@ describe("reconstruction coverage verifier observations", () => {
});
it("rejects verifier observations from the future", () => {
const workspace = completeReconstructionCoverageWorkspace();
const workspace = completeReconstructionCoverageData();
const result = workspace.verifier_results[0];
if (result === undefined)
throw new Error("Expected fixture verifier result");
const {
revision_sha256: _revisionSha256,
workspace_id: _workspaceId,
...semantic
} = workspace;
const changed = createReconstructionCoverageWorkspace({
const semantic = workspace;
const changed = createReconstructionCoverageData({
...semantic,
revision: 2,
previous_revision_sha256: workspace.revision_sha256,
verifier_results: [
{ ...result, observed_at: "2026-07-17T12:00:00.000Z" },
],
@@ -223,16 +192,10 @@ describe("reconstruction coverage verifier observations", () => {
});
it("rejects green results and package proofs that omit current commitments", () => {
const workspace = completeReconstructionCoverageWorkspace();
const {
revision_sha256: _revisionSha256,
workspace_id: _workspaceId,
...semantic
} = workspace;
const incomplete = createReconstructionCoverageWorkspace({
const workspace = completeReconstructionCoverageData();
const semantic = workspace;
const incomplete = createReconstructionCoverageData({
...semantic,
revision: 2,
previous_revision_sha256: workspace.revision_sha256,
verifier_results: workspace.verifier_results.map((result) => ({
...result,
owner_sha256s: [],
+21 -109
View File
@@ -8,7 +8,7 @@ import {
evaluateReconstructionClaims,
evaluateReconstructionPackageProofs,
evaluateReconstructionSurfaces,
evaluateReconstructionWorkspaceRisks,
evaluateReconstructionCoverageRisks,
recommendedReconstructionProbes,
type ReconstructionEvaluationContext,
} from "./reconstructionCoverageEvaluation.js";
@@ -158,11 +158,7 @@ const boundarySchema = z.strictObject({
allowed_unknown_ids: z.array(stableIdSchema).max(1_000),
});
const workspaceSemanticSchema = z.strictObject({
workspace_id: z.string().regex(/^rcw_[a-f0-9]{64}$/u),
name: z.string().trim().min(1).max(200),
revision: z.number().int().min(1),
previous_revision_sha256: digestSchema.nullable(),
export const reconstructionCoverageDataSchema = z.strictObject({
evidence_bundle: evidenceBundleSchema,
artifacts: z.array(artifactSchema).max(1_000),
surfaces: z.array(surfaceSchema).max(10_000),
@@ -176,16 +172,22 @@ const workspaceSemanticSchema = z.strictObject({
boundaries: z.array(boundarySchema).max(1_000),
});
export const reconstructionCoverageWorkspaceSchema =
workspaceSemanticSchema.extend({ revision_sha256: digestSchema });
export type ReconstructionCoverageWorkspace = z.infer<
typeof reconstructionCoverageWorkspaceSchema
export type ReconstructionCoverageData = z.infer<
typeof reconstructionCoverageDataSchema
>;
export type ReconstructionVerifierContract = z.infer<
typeof verifierContractSchema
>;
/** Parse inline coverage data and validate every evidence and authority link. */
export const createReconstructionCoverageData = (
input: unknown,
): ReconstructionCoverageData => {
const coverage = reconstructionCoverageDataSchema.parse(input);
validateCoverageReferences(coverage);
return coverage;
};
const closureReasonSchema = z.strictObject({
code: z.enum([
"surface-missing",
@@ -220,7 +222,6 @@ const closureReasonSchema = z.strictObject({
export const reconstructionClosureResultSchema = z.strictObject({
boundary_id: stableIdSchema,
status: z.enum(["partial", "failed", "unknown", "ready"]),
workspace_revision_sha256: digestSchema,
summary: z.strictObject({
required_surfaces: z.number().int().min(0),
required_claims: z.number().int().min(0),
@@ -243,7 +244,7 @@ export type ReconstructionClosureResult = z.infer<
typeof reconstructionClosureResultSchema
>;
type WorkspaceSemantic = z.infer<typeof workspaceSemanticSchema>;
type CoverageData = z.infer<typeof reconstructionCoverageDataSchema>;
type ClosureReason = z.infer<typeof closureReasonSchema>;
/** Build a verifier contract whose digest prevents retrospective coverage edits. */
@@ -257,80 +258,20 @@ export const createReconstructionVerifierContract = (
});
};
/** Build one canonical immutable coverage-workspace revision. */
export const createReconstructionCoverageWorkspace = (
input: Omit<z.input<typeof workspaceSemanticSchema>, "workspace_id">,
): ReconstructionCoverageWorkspace => {
const semanticInput = {
workspace_id: `rcw_${digest({ name: input.name })}`,
...input,
};
const semantic = canonicalWorkspace(
workspaceSemanticSchema.parse(semanticInput),
);
validateWorkspaceReferences(semantic);
return reconstructionCoverageWorkspaceSchema.parse({
...semantic,
revision_sha256: digest(semantic),
});
};
/** Parse persisted coverage state and verify canonical order, references, and digests. */
export const parseReconstructionCoverageWorkspace = (
input: unknown,
): ReconstructionCoverageWorkspace => {
const parsed = reconstructionCoverageWorkspaceSchema.parse(input);
const rebuilt = createReconstructionCoverageWorkspace({
name: parsed.name,
revision: parsed.revision,
previous_revision_sha256: parsed.previous_revision_sha256,
evidence_bundle: parsed.evidence_bundle,
artifacts: parsed.artifacts,
surfaces: parsed.surfaces,
owners: parsed.owners,
claims: parsed.claims,
verifier_contracts: parsed.verifier_contracts,
verifier_results: parsed.verifier_results,
residual_unknown_ids: parsed.residual_unknown_ids,
contradictions: parsed.contradictions,
package_proofs: parsed.package_proofs,
boundaries: parsed.boundaries,
});
if (
parsed.workspace_id !== rebuilt.workspace_id ||
parsed.revision_sha256 !== rebuilt.revision_sha256 ||
JSON.stringify(parsed) !== JSON.stringify(rebuilt)
)
throw new TypeError("Reconstruction coverage workspace is not canonical");
return rebuilt;
};
/** Serialize one validated coverage revision as byte-stable canonical JSON. */
export const serializeReconstructionCoverageWorkspace = (
workspace: ReconstructionCoverageWorkspace,
): string => {
const encoded = canonicalize(parseReconstructionCoverageWorkspace(workspace));
if (encoded === undefined)
throw new TypeError(
"Reconstruction coverage workspace is not canonical JSON",
);
return encoded;
};
/** Evaluate one named completion boundary without inferring undiscovered coverage. */
/** Evaluate inline coverage data against one named fail-closed boundary. */
export const evaluateReconstructionClosure = (
workspaceInput: unknown,
coverageInput: unknown,
boundaryId: string,
nowEpochMs: number,
): ReconstructionClosureResult => {
const workspace = parseReconstructionCoverageWorkspace(workspaceInput);
const boundary = workspace.boundaries.find(
const coverage = createReconstructionCoverageData(coverageInput);
const boundary = coverage.boundaries.find(
({ boundary_id: id }) => id === boundaryId,
);
if (boundary === undefined)
throw new TypeError(`Unknown reconstruction boundary: ${boundaryId}`);
const context: ReconstructionEvaluationContext = {
workspace,
coverage,
boundary,
nowEpochMs,
reasons: [],
@@ -338,13 +279,12 @@ export const evaluateReconstructionClosure = (
};
evaluateReconstructionSurfaces(context);
evaluateReconstructionClaims(context);
evaluateReconstructionWorkspaceRisks(context);
evaluateReconstructionCoverageRisks(context);
evaluateReconstructionPackageProofs(context);
const reasons = [...context.reasons].sort(reasonOrder);
return reconstructionClosureResultSchema.parse({
boundary_id: boundary.boundary_id,
status: closureStatus(reasons),
workspace_revision_sha256: workspace.revision_sha256,
summary: {
required_surfaces: boundary.required_surface_ids.length,
required_claims: boundary.required_claim_ids.length,
@@ -356,7 +296,7 @@ export const evaluateReconstructionClosure = (
});
};
const validateWorkspaceReferences = (workspace: WorkspaceSemantic): void => {
const validateCoverageReferences = (workspace: CoverageData): void => {
const evidenceBundle = parseEvidenceBundle(workspace.evidence_bundle);
const evidenceIds = new Set(
evidenceBundle.records.map(({ evidence_id: id }) => id),
@@ -418,34 +358,6 @@ const validateWorkspaceReferences = (workspace: WorkspaceSemantic): void => {
);
};
const canonicalWorkspace = (
workspace: WorkspaceSemantic,
): WorkspaceSemantic => ({
...workspace,
artifacts: sorted(workspace.artifacts, "artifact_id"),
surfaces: sorted(workspace.surfaces, "surface_id"),
owners: [...workspace.owners].sort((left, right) =>
left.surface_id.localeCompare(right.surface_id),
),
claims: sorted(workspace.claims, "claim_id"),
verifier_contracts: sorted(workspace.verifier_contracts, "verifier_id"),
verifier_results: [...workspace.verifier_results].sort((left, right) =>
`${left.verifier_id}:${left.observed_at}`.localeCompare(
`${right.verifier_id}:${right.observed_at}`,
),
),
residual_unknown_ids: [...new Set(workspace.residual_unknown_ids)].sort(),
contradictions: sorted(workspace.contradictions, "contradiction_id"),
package_proofs: sorted(workspace.package_proofs, "proof_id"),
boundaries: sorted(workspace.boundaries, "boundary_id"),
});
const sorted = <Item extends Record<Key, string>, Key extends keyof Item>(
items: readonly Item[],
key: Key,
): Item[] =>
[...items].sort((left, right) => left[key].localeCompare(right[key]));
const assertUnique = <Item extends Record<Key, string>, Key extends keyof Item>(
items: readonly Item[],
key: Key,
+22 -22
View File
@@ -1,6 +1,6 @@
import type {
ReconstructionClosureResult,
ReconstructionCoverageWorkspace,
ReconstructionCoverageData,
ReconstructionVerifierContract,
} from "./reconstructionCoverage.js";
@@ -23,10 +23,10 @@ const probeOperation = (code: ClosureReason["code"]): string => {
return "update_authoritative_inventory";
};
type Boundary = ReconstructionCoverageWorkspace["boundaries"][number];
type Boundary = ReconstructionCoverageData["boundaries"][number];
type ClosureReason = ReconstructionClosureResult["reasons"][number];
export interface ReconstructionEvaluationContext {
readonly workspace: ReconstructionCoverageWorkspace;
readonly coverage: ReconstructionCoverageData;
readonly boundary: Boundary;
readonly nowEpochMs: number;
readonly reasons: ClosureReason[];
@@ -36,7 +36,7 @@ export interface ReconstructionEvaluationContext {
export const evaluateReconstructionSurfaces = (
context: ReconstructionEvaluationContext,
): void => {
const surfaces = indexUnique(context.workspace.surfaces, "surface_id");
const surfaces = indexUnique(context.coverage.surfaces, "surface_id");
for (const surfaceId of context.boundary.required_surface_ids) {
const surface = surfaces.get(surfaceId);
if (surface === undefined) {
@@ -65,7 +65,7 @@ const evaluateOwner = (
context: ReconstructionEvaluationContext,
surfaceId: string,
): void => {
const owners = context.workspace.owners.filter(
const owners = context.coverage.owners.filter(
({ surface_id: id }) => id === surfaceId,
);
if (owners.length === 0) {
@@ -139,7 +139,7 @@ const evaluateOwner = (
export const evaluateReconstructionClaims = (
context: ReconstructionEvaluationContext,
): void => {
const claims = indexUnique(context.workspace.claims, "claim_id");
const claims = indexUnique(context.coverage.claims, "claim_id");
for (const claimId of context.boundary.required_claim_ids) {
const claim = claims.get(claimId);
if (claim === undefined) {
@@ -151,7 +151,7 @@ export const evaluateReconstructionClaims = (
);
continue;
}
const contracts = context.workspace.verifier_contracts.filter(
const contracts = context.coverage.verifier_contracts.filter(
({ claim_ids: ids }) => ids.includes(claimId),
);
if (contracts.length === 0) {
@@ -180,10 +180,10 @@ export const evaluateReconstructionClaims = (
const evaluateVerifierResult = (
context: ReconstructionEvaluationContext,
claim: ReconstructionCoverageWorkspace["claims"][number],
claim: ReconstructionCoverageData["claims"][number],
contract: ReconstructionVerifierContract,
): void => {
const results = context.workspace.verifier_results
const results = context.coverage.verifier_results
.filter(({ verifier_id: id }) => id === contract.verifier_id)
.sort(
(left, right) =>
@@ -240,23 +240,23 @@ const evaluateVerifierResult = (
const verifierResultIsCompatible = (
context: ReconstructionEvaluationContext,
claim: ReconstructionCoverageWorkspace["claims"][number],
claim: ReconstructionCoverageData["claims"][number],
contract: ReconstructionVerifierContract,
result: ReconstructionCoverageWorkspace["verifier_results"][number],
result: ReconstructionCoverageData["verifier_results"][number],
): boolean => {
const artifactDigests = new Set(
context.workspace.artifacts.map(({ artifact_sha256: value }) => value),
context.coverage.artifacts.map(({ artifact_sha256: value }) => value),
);
const ownerDigests = new Set(
context.workspace.owners.flatMap(({ ownership }) =>
context.coverage.owners.flatMap(({ ownership }) =>
ownership.disposition === "implemented" ? [ownership.owner_sha256] : [],
),
);
const surfaces = new Map(
context.workspace.surfaces.map((surface) => [surface.surface_id, surface]),
context.coverage.surfaces.map((surface) => [surface.surface_id, surface]),
);
const artifacts = new Map(
context.workspace.artifacts.map((artifact) => [
context.coverage.artifacts.map((artifact) => [
artifact.artifact_id,
artifact,
]),
@@ -267,7 +267,7 @@ const verifierResultIsCompatible = (
surface === undefined ? undefined : artifacts.get(surface.artifact_id);
return artifact === undefined ? [] : [artifact.artifact_sha256];
});
const expectedOwnerDigests = context.workspace.owners.flatMap(
const expectedOwnerDigests = context.coverage.owners.flatMap(
({ surface_id: surfaceId, ownership }) =>
claim.surface_ids.includes(surfaceId) &&
ownership.disposition === "implemented"
@@ -301,10 +301,10 @@ const verifierResultIsCompatible = (
);
};
export const evaluateReconstructionWorkspaceRisks = (
export const evaluateReconstructionCoverageRisks = (
context: ReconstructionEvaluationContext,
): void => {
for (const unknownId of context.workspace.residual_unknown_ids)
for (const unknownId of context.coverage.residual_unknown_ids)
if (!context.boundary.allowed_unknown_ids.includes(unknownId))
addReason(
context,
@@ -312,7 +312,7 @@ export const evaluateReconstructionWorkspaceRisks = (
unknownId,
"Active residual unknown is not permitted by the completion boundary.",
);
for (const contradiction of context.workspace.contradictions)
for (const contradiction of context.coverage.contradictions)
if (
contradiction.status === "active" &&
(contradiction.surface_ids.some((id) =>
@@ -336,10 +336,10 @@ export const evaluateReconstructionPackageProofs = (
context: ReconstructionEvaluationContext,
): void => {
const surfaces = new Map(
context.workspace.surfaces.map((surface) => [surface.surface_id, surface]),
context.coverage.surfaces.map((surface) => [surface.surface_id, surface]),
);
const artifacts = new Map(
context.workspace.artifacts.map((artifact) => [
context.coverage.artifacts.map((artifact) => [
artifact.artifact_id,
artifact,
]),
@@ -353,7 +353,7 @@ export const evaluateReconstructionPackageProofs = (
},
);
for (const kind of context.boundary.required_package_proof_kinds) {
const proofs = context.workspace.package_proofs.filter(
const proofs = context.coverage.package_proofs.filter(
(proof) => proof.kind === kind,
);
const passing = proofs.find(
@@ -77,14 +77,6 @@ export const reconstructionSpecificationSchema = z
/** Bounded reconstruction-verification input. */
export const reconstructionVerificationInputSchema = z.strictObject({
specification: reconstructionSpecificationSchema,
coverage: z
.strictObject({
workspace_id: z.string().regex(/^rcw_[a-f0-9]{64}$/u),
revision: z.number().int().min(1),
revision_sha256: digestSchema,
boundary_id: z.string().min(1).max(200),
})
.optional(),
unknown_registry_approved: z.literal(true).optional(),
});
-5
View File
@@ -351,11 +351,6 @@ const registerObservationTools = ({
: (evidenceId) => session.evidenceById(evidenceId),
evidenceFilePolicy: options.evidenceFilePolicy ?? DENY_EVIDENCE_FILE_POLICY,
permissionAuthority,
retainCoverageWorkspace:
session === undefined
? undefined
: (workspace) =>
session.retainReconstructionCoverageWorkspace(workspace),
replay: {
policy:
options.javascriptReplayPolicy ?? (() => ({ status: "disabled" })),
+9 -131
View File
@@ -1,149 +1,27 @@
import type { McpServer } from "@modelcontextprotocol/server";
import {
authorizeFileReadWithDeferredWrite,
authorizeRootPermission,
} from "../../application/DeferredFileAuthorization.js";
import {
commitReconstructionCoverage,
queryReconstructionCoverage,
} from "../../application/ReconstructionCoverageService.js";
import { readReconstructionCoverageWorkspace } from "../../application/ReconstructionCoverageWorkspaceStore.js";
import { evaluateReconstructionCoverage } from "../../application/ReconstructionCoverageService.js";
import { applicationToolContract } from "../../contracts/applicationToolContracts.js";
import {
AnalysisCapabilityUnavailableError,
EvidenceIntegrityError,
} from "../../domain/errors.js";
import { reconstructionClosureResultSchema } from "../../domain/reconstructionCoverage.js";
import { err } from "../../domain/result.js";
import { logToolExecution } from "../toolLogging.js";
import { toolRegistrationOptions } from "../toolRegistrationOptions.js";
import { toCallToolResult } from "../toolResult.js";
import type { ApplicationToolRegistration } from "./types.js";
const commitContract = applicationToolContract(
"commit_reconstruction_coverage",
);
const queryContract = applicationToolContract("query_reconstruction_coverage");
const contract = applicationToolContract("evaluate_reconstruction_coverage");
/** Register reconstruction coverage commit and query tools. */
/** Register the inline fail-closed reconstruction coverage evaluator. */
export const registerCoverageTools = (
server: McpServer,
options: ApplicationToolRegistration,
): void => {
registerCommitTool(server, options);
registerQueryTool(server, options);
};
const registerCommitTool = (
server: McpServer,
options: ApplicationToolRegistration,
): void => {
server.registerTool(
commitContract.name,
toolRegistrationOptions(commitContract),
async (input, context) => {
if (options.permissionAuthority === undefined)
return toCallToolResult(
err(
new AnalysisCapabilityUnavailableError(
"rea-reconstruction-coverage",
commitContract.name,
"workspace permission policy is not configured",
),
),
commitContract,
);
const authorization = await authorizeFileReadWithDeferredWrite(
options.permissionAuthority,
{
path: input.workspace_path,
readCapability: "reconstruction_coverage_read",
writeCapability: "reconstruction_coverage_write",
operation: commitContract.name,
},
contract.name,
toolRegistrationOptions(contract),
async (input) => {
const result = await logToolExecution(options.logger, contract.name, () =>
Promise.resolve(evaluateReconstructionCoverage(input)),
);
if (!authorization.ok)
return toCallToolResult(authorization, commitContract);
const write = await authorization.value.authorizeWrite();
if (!write.ok) return toCallToolResult(write, commitContract);
const result = await logToolExecution(
options.logger,
commitContract.name,
() =>
commitReconstructionCoverage(input, options.evidenceFilePolicy, {
signal: context.mcpReq.signal,
}),
);
if (!result.ok) return toCallToolResult(result, commitContract);
options.retainCoverageWorkspace?.(input.workspace);
return toCallToolResult(result, commitContract);
},
);
};
const registerQueryTool = (
server: McpServer,
options: ApplicationToolRegistration,
): void => {
server.registerTool(
queryContract.name,
toolRegistrationOptions(queryContract),
async (input, context) => {
if (options.permissionAuthority === undefined)
return toCallToolResult(
err(
new AnalysisCapabilityUnavailableError(
"rea-reconstruction-coverage",
queryContract.name,
"workspace permission policy is not configured",
),
),
queryContract,
);
const authorized = await authorizeRootPermission(
options.permissionAuthority,
{
capability: "reconstruction_coverage_read",
roots: [input.workspace_path],
access: "read",
operation: queryContract.name,
},
);
if (!authorized.ok) return toCallToolResult(authorized, queryContract);
const result = await logToolExecution(
options.logger,
queryContract.name,
() =>
queryReconstructionCoverage(
input,
options.evidenceFilePolicy,
Date.now(),
{ signal: context.mcpReq.signal },
),
);
if (result.ok && options.retainCoverageWorkspace !== undefined) {
const closure = reconstructionClosureResultSchema.parse(result.value);
const loaded = await readReconstructionCoverageWorkspace(
input.workspace_path,
options.evidenceFilePolicy,
);
if (!loaded.ok) return toCallToolResult(loaded, queryContract);
if (
loaded.value === null ||
loaded.value.revision_sha256 !== closure.workspace_revision_sha256
)
return toCallToolResult(
err(
new EvidenceIntegrityError(
"workspace changed while its closure was being retained",
),
),
queryContract,
);
options.retainCoverageWorkspace(loaded.value);
}
return toCallToolResult(result, queryContract);
return toCallToolResult(result, contract);
},
);
};
@@ -16,7 +16,4 @@ export interface ApplicationToolRegistration {
readonly replay: JavaScriptReplayDependencies;
readonly evidenceFilePolicy: EvidenceFilePolicy;
readonly permissionAuthority: PermissionAuthority | undefined;
readonly retainCoverageWorkspace:
| BinarySessionPort["retainReconstructionCoverageWorkspace"]
| undefined;
}
-3
View File
@@ -14,7 +14,6 @@ import {
functionEvidenceIds,
isIncomplete,
recordWorkflowEvidence,
verifyCoverageReadiness,
} from "./registerInvestigationTools/helpers.js";
import { runDerivedOperation } from "./runDerivedOperation.js";
import {
@@ -231,8 +230,6 @@ const registerReconstruction = (
contract.name,
contractOptions(contract),
async (input, context) => {
const coverage = verifyCoverageReadiness(session, input.coverage);
if (!coverage.ok) return toCallToolResult(coverage, contract);
const owned = session.exportEvidenceBundle();
const computed = await runDerivedOperation(context, contract.name, () =>
verifyReconstruction(input.specification, owned),
@@ -7,10 +7,6 @@ import {
import { err, ok, type Result } from "../../domain/result.js";
import { recordDerivedEvidence } from "../recordDerivedEvidence.js";
import type { WorkflowUnknownInput } from "./types.js";
import { evaluateReconstructionClosure } from "../../domain/reconstructionCoverage.js";
import type { z } from "zod";
import type { reconstructionVerificationInputSchema } from "../../domain/reconstructionVerification.js";
import { AnalysisInputError } from "../../domain/errors.js";
export const isIncomplete = (status: string): boolean =>
status === "unknown" || status === "truncated";
@@ -56,43 +52,6 @@ export const evidenceClosure = (
return ok(uniqueIds([...visited]));
};
/** Verify a retained coverage boundary before reconstruction evidence is derived. */
export const verifyCoverageReadiness = (
session: BinarySessionPort,
coverage: z.output<typeof reconstructionVerificationInputSchema>["coverage"],
): Result<null, AnalysisError> => {
if (coverage === undefined) return ok(null);
const workspace = session.reconstructionCoverageWorkspace(
coverage.workspace_id,
coverage.revision,
);
if (
workspace === undefined ||
workspace.revision_sha256 !== coverage.revision_sha256
)
return err(
new EvidenceIntegrityError(
"The requested reconstruction coverage revision is not retained by this session",
),
);
try {
const result = evaluateReconstructionClosure(
workspace,
coverage.boundary_id,
Date.now(),
);
return result.status === "ready"
? ok(null)
: err(
new EvidenceIntegrityError(
`Reconstruction coverage boundary is ${result.status}; readiness requires ready`,
),
);
} catch (cause: unknown) {
return err(new AnalysisInputError("verify_reconstruction", { cause }));
}
};
export const recordWorkflowEvidence = (
...[session, evidence, approved, unresolved, input]: readonly [
session: BinarySessionPort,
+1 -2
View File
@@ -122,14 +122,13 @@ describe("canonical product catalog", () => {
)?.capabilities,
).toEqual([
"build_reconstruction_obligation_ledger",
"commit_reconstruction_coverage",
"compare_application_versions",
"compare_javascript_export_shapes",
"compare_source_to_bundle",
"evaluate_reconstruction_coverage",
"evaluate_reconstruction_readiness",
"execute_node_characterization",
"prepare_node_characterization",
"query_reconstruction_coverage",
"run_controlled_replay",
"trace_application_feature",
"trace_javascript_semantics",
@@ -79,7 +79,6 @@ describe("direct analysis snapshot filesystem permissions", () => {
analysisProfile: workflowProfile,
});
const snapshot: AnalysisSnapshot = {
snapshot_version: 2,
target: snapshotTarget(target.value),
binding: snapshotBinding(profile),
entries: [],
@@ -1,99 +0,0 @@
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import {
commitReconstructionCoverage,
queryReconstructionCoverage,
} from "../../../src/application/ReconstructionCoverageService.js";
import {
readReconstructionCoverageWorkspace,
writeReconstructionCoverageWorkspace,
} from "../../../src/application/ReconstructionCoverageWorkspaceStore.js";
import type { EvidenceFilePolicy } from "../../../src/domain/evidenceBundle.js";
import {
completeReconstructionCoverageWorkspace,
RECONSTRUCTION_COVERAGE_NOW,
} from "../../../src/domain/reconstructionCoverage.fixture.js";
const filePolicy = (root: string): EvidenceFilePolicy => ({
roots: [root],
maxBytes: 64 * 1024 * 1024,
maxDepth: 64,
maxStringLength: 1024 * 1024,
maxNodes: 1_000_000,
});
describe("reconstruction coverage persistence", () => {
it("persists owner-only revisions with CAS and digest-chain enforcement", async () => {
const root = await createTestTempDirectory("rea-coverage-workspace-");
const path = join(root, "coverage.json");
const workspace = completeReconstructionCoverageWorkspace();
const policy = filePolicy(root);
const written = await writeReconstructionCoverageWorkspace(
workspace,
path,
null,
policy,
);
expect(written.ok).toBe(true);
expect(await readReconstructionCoverageWorkspace(path, policy)).toEqual({
ok: true,
value: workspace,
});
expect(
await writeReconstructionCoverageWorkspace(workspace, path, null, policy),
).toMatchObject({
ok: false,
error: {
_tag: "WorkspaceStorageError",
reason: "revision-conflict",
},
});
});
it("shares commit and fail-closed query behavior across adapters", async () => {
const root = await createTestTempDirectory("rea-coverage-service-");
const path = join(root, "coverage.json");
const workspace = completeReconstructionCoverageWorkspace();
const policy = filePolicy(root);
const committed = await commitReconstructionCoverage(
{
approved: true,
workspace_path: path,
expected_revision: null,
workspace,
},
policy,
);
expect(committed.ok && committed.value).toMatchObject({
revision: 1,
revision_sha256: workspace.revision_sha256,
evidence_records: 5,
});
const queried = await queryReconstructionCoverage(
{ workspace_path: path, boundary_id: "replacement.cli" },
policy,
RECONSTRUCTION_COVERAGE_NOW,
);
expect(queried.ok && queried.value).toMatchObject({ status: "ready" });
const controller = new AbortController();
controller.abort();
expect(
await queryReconstructionCoverage(
{ workspace_path: path, boundary_id: "replacement.cli" },
policy,
RECONSTRUCTION_COVERAGE_NOW,
{ signal: controller.signal },
),
).toMatchObject({
ok: false,
error: { _tag: "AnalysisCancelledError" },
});
});
});
@@ -1,242 +1,52 @@
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
import { rm } from "node:fs/promises";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { completeReconstructionCoverageData } from "../../../src/domain/reconstructionCoverage.fixture.js";
import { createReconstructionCoverageData } from "../../../src/domain/reconstructionCoverage.js";
import { createTestBinarySession } from "../../fixtures/binarySession.js";
import { INVESTIGATION_EXAMPLES } from "../../../src/contracts/investigationExamples.js";
import { createEvidence } from "../../../src/domain/evidence.js";
import { createEvidenceBundle } from "../../../src/domain/evidenceBundle.js";
import {
createReconstructionCoverageWorkspace,
createReconstructionVerifierContract,
} from "../../../src/domain/reconstructionCoverage.js";
import { createServer } from "../../../src/server/createServer.js";
import { observed } from "../../fixtures/analysisExecution.js";
import { permissionAuthorityForRoot } from "../../fixtures/permissionAuthority.js";
const digest = (character: string): string => character.repeat(64);
describe("reconstruction coverage MCP parity", () => {
it("commits and queries the same evidence-backed fail-closed workspace", async () => {
const root = await createTestTempDirectory("rea-coverage-mcp-");
const path = join(root, "coverage.json");
const policy = {
roots: [root],
maxBytes: 64 * 1024 * 1024,
maxDepth: 64,
maxStringLength: 1024 * 1024,
maxNodes: 1_000_000,
};
const authority = await permissionAuthorityForRoot(
root,
["reconstruction_coverage_read", "reconstruction_coverage_write"],
["reconstruction_coverage_read", "reconstruction_coverage_write"],
);
describe("reconstruction coverage MCP", () => {
it("evaluates inline fail-closed coverage without session retention", async () => {
const session = createTestBinarySession(() => ({
execute: () => Promise.resolve(observed(null)),
close: () => Promise.resolve(),
}));
const server = createServer(session, session, {
evidenceFilePolicy: policy,
permissionAuthority: authority,
});
const server = createServer(session, session);
const client = new Client({ name: "coverage-mcp-test", version: "1" });
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
try {
await server.connect(serverTransport);
await client.connect(clientTransport);
const workspace = fixtureWorkspace();
const committed = await client.callTool({
name: "commit_reconstruction_coverage",
const result = await client.callTool({
name: "evaluate_reconstruction_coverage",
arguments: {
approved: true,
workspace_path: path,
expected_revision: null,
workspace,
},
});
expect(committed.isError).not.toBe(true);
expect(committed.structuredContent).toMatchObject({
revision: 1,
revision_sha256: workspace.revision_sha256,
});
expect(committed.structuredContent).toMatchObject({
workspace_id: workspace.workspace_id,
revision_sha256: workspace.revision_sha256,
});
const queried = await client.callTool({
name: "query_reconstruction_coverage",
arguments: {
workspace_path: path,
coverage: currentFixtureCoverage(),
boundary_id: "replacement.cli",
},
});
expect(queried.isError).not.toBe(true);
expect(queried.structuredContent).toMatchObject({
expect(result.isError).not.toBe(true);
expect(result.structuredContent).toMatchObject({
status: "ready",
summary: { reasons: 0 },
});
const staleVerification = await client.callTool({
name: "verify_reconstruction",
arguments: {
...INVESTIGATION_EXAMPLES.verify_reconstruction,
coverage: {
workspace_id: workspace.workspace_id,
revision: workspace.revision,
revision_sha256: digest("9"),
boundary_id: "replacement.cli",
},
},
});
expect(staleVerification.isError).toBe(true);
expect(staleVerification.structuredContent).toMatchObject({
error: { code: "evidence_integrity_mismatch" },
});
const unknownBoundary = await client.callTool({
name: "verify_reconstruction",
arguments: {
...INVESTIGATION_EXAMPLES.verify_reconstruction,
coverage: {
workspace_id: workspace.workspace_id,
revision: workspace.revision,
revision_sha256: workspace.revision_sha256,
boundary_id: "replacement.unknown",
},
},
});
expect(unknownBoundary.isError).toBe(true);
expect(unknownBoundary.structuredContent).toMatchObject({
error: { code: "invalid_request" },
});
} finally {
await client.close();
await server.close();
await session.close();
await rm(root, { recursive: true, force: true });
}
});
});
const fixtureWorkspace = () => {
const record = createEvidence(
undefined,
{ id: "fixture", name: "Fixture", version: "1" },
{
predicateType: "rea.coverage-fixture/v1",
operation: "verify-cli",
parameters: {},
result: { status: "pass" },
authority: "controlled-replay",
environment: {
id: "fixture",
platform: "linux",
architecture: "x86_64",
isolation: "container",
},
},
);
const contract = createReconstructionVerifierContract({
verifier_id: "verify.cli",
claim_ids: ["claim.cli"],
dimensions: ["output"],
authority: "controlled-replay",
max_age_ms: Number.MAX_SAFE_INTEGER,
minimum_repeats: 1,
normalization_sha256: digest("4"),
normalization_removes_dimensions: false,
});
return createReconstructionCoverageWorkspace({
name: "mcp-fixture",
revision: 1,
previous_revision_sha256: null,
evidence_bundle: createEvidenceBundle([record]),
artifacts: [
{
artifact_id: "authority",
artifact_sha256: digest("1"),
version: "1",
environment_sha256: digest("2"),
evidence_ids: [record.evidence_id],
},
],
surfaces: [
{
surface_id: "cli.help",
family: "cli-command",
artifact_id: "authority",
occurrence_id: null,
location: "app --help",
authority: "observed",
dependency_surface_ids: [],
evidence_ids: [record.evidence_id],
},
],
owners: [
{
surface_id: "cli.help",
ownership: {
disposition: "implemented",
owner_path: "src/cli.ts",
owner_export: null,
owner_sha256: digest("3"),
path_state: "present",
package_state: "distributed",
authority_route: "none",
},
},
],
claims: [
{
claim_id: "claim.cli",
title: "CLI help matches",
kind: "behavioral",
surface_ids: ["cli.help"],
required_dimensions: ["output"],
required_authority: "controlled-replay",
},
],
verifier_contracts: [contract],
verifier_results: [
{
verifier_id: contract.verifier_id,
contract_sha256: contract.contract_sha256,
observed_at: "2026-07-16T00:00:00.000Z",
status: "pass",
covered_claim_ids: ["claim.cli"],
covered_dimensions: ["output"],
artifact_sha256s: [digest("1")],
owner_sha256s: [digest("3")],
normalization_sha256: digest("4"),
repeats: 1,
evidence_ids: [record.evidence_id],
},
],
residual_unknown_ids: [],
contradictions: [],
package_proofs: [
{
proof_id: "proof.install",
kind: "clean-install",
status: "pass",
artifact_sha256s: [digest("1")],
evidence_ids: [record.evidence_id],
},
],
boundaries: [
{
boundary_id: "replacement.cli",
title: "CLI replacement",
required_surface_ids: ["cli.help"],
required_claim_ids: ["claim.cli"],
required_package_proof_kinds: ["clean-install"],
allowed_dispositions: [],
allowed_unknown_ids: [],
},
],
const currentFixtureCoverage = () => {
const coverage = completeReconstructionCoverageData();
return createReconstructionCoverageData({
...coverage,
verifier_results: coverage.verifier_results.map((result) => ({
...result,
observed_at: new Date().toISOString(),
})),
});
};