@momentiq/dark-factory-cli 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,168 @@
1
+ // `df publish` — Cycle 331.1 verifiable-objectives Phase 2
2
+ // (momentiq-ai/dark-factory#207). Persist the `df verify` evidence bundle.
3
+ //
4
+ // In CI, after `df verify` (re)produces the diffHash-bound gate JSON +
5
+ // screenshots, `df publish` uploads them to Cerebe object storage and emits a
6
+ // `PublishedEvidence` pointer manifest (`{routeId → upload_id, diffHash}`,
7
+ // provenance `consumer-attested`) for the hosted worker (Phase 3) to join
8
+ // against `.darkfactory/objectives.yaml`.
9
+ //
10
+ // Degrade-and-pass (spec §5): when Cerebe is unconfigured (the air-gap / OSS
11
+ // baseline path — `CEREBE_API_URL`/`CEREBE_API_KEY` unset) or an upload fails,
12
+ // `df publish` emits a `status: "degraded"` manifest and still EXITS 0, so the
13
+ // merge verdict is never blocked by a storage outage. Exit non-zero only for a
14
+ // usage error (2) or a config/git error (1).
15
+ import { writeFileSync } from "node:fs";
16
+ import { loadAgentReviewConfig } from "../policy/config.js";
17
+ import { resolveCommit } from "../git.js";
18
+ import { CerebeStorage, resolveCerebeConfig, } from "../evidence/cerebe.js";
19
+ import { buildPublishManifest, collectPublishArtifacts, } from "../evidence/publish.js";
20
+ const HELP = [
21
+ "df publish — upload the `df verify` evidence bundle to Cerebe + emit pointers.",
22
+ "",
23
+ "Usage:",
24
+ " df publish [--commit <ref>] [--cwd <path>] [--out <file>]",
25
+ "",
26
+ "Reads the per-SHA quality-gate evidence `df verify` wrote (the diffHash-bound",
27
+ "gate JSON + any UI screenshots), uploads each artifact to Cerebe object",
28
+ "storage, and writes a `PublishedEvidence` pointer manifest (schemaVersion 1,",
29
+ "provenance consumer-attested) the hosted worker joins against the objectives",
30
+ "manifest.",
31
+ "",
32
+ "Cerebe is configured via the environment:",
33
+ " CEREBE_API_URL Base URL of the Cerebe storage API (required to publish).",
34
+ " CEREBE_API_KEY API key sent as the `X-API-Key` header (required).",
35
+ " CEREBE_PROJECT Optional project scope (`X-Cerebe-Project` header).",
36
+ " CEREBE_USER_ID Optional upload identity (multipart `user_id`; default",
37
+ " `dark-factory`). Set it to your CI service identity.",
38
+ "",
39
+ "When Cerebe is not configured, or an upload fails, publish emits a",
40
+ '`status: "degraded"` manifest and still exits 0 (degrade-and-pass) — the',
41
+ "merge verdict is never blocked by a storage outage.",
42
+ "",
43
+ "Flags:",
44
+ " --commit <ref> Commit ref (anything `git rev-parse` accepts; default HEAD).",
45
+ " --cwd <path> Repository root to operate in (default: process cwd).",
46
+ " --out <file> Write the manifest to <file> (default: stdout).",
47
+ " --help, -h Show this message.",
48
+ "",
49
+ "Exit codes:",
50
+ " 0 manifest emitted (complete OR degraded), or nothing to publish",
51
+ " 1 config load failure or bad commit ref",
52
+ " 2 usage / flag error",
53
+ "",
54
+ ].join("\n");
55
+ function parsePublishArgs(rest) {
56
+ let commit = "HEAD";
57
+ let cwd = process.cwd();
58
+ let out = null;
59
+ for (let i = 0; i < rest.length; i++) {
60
+ const a = rest[i] ?? "";
61
+ if (a === "--commit" || a === "--cwd" || a === "--out") {
62
+ const next = rest[i + 1];
63
+ if (next === undefined || next.startsWith("--")) {
64
+ return { error: `${a} requires a value.` };
65
+ }
66
+ if (a === "--commit")
67
+ commit = next;
68
+ else if (a === "--cwd")
69
+ cwd = next;
70
+ else
71
+ out = next;
72
+ i++;
73
+ continue;
74
+ }
75
+ if (a.startsWith("--commit=")) {
76
+ commit = a.slice("--commit=".length);
77
+ continue;
78
+ }
79
+ if (a.startsWith("--cwd=")) {
80
+ cwd = a.slice("--cwd=".length);
81
+ continue;
82
+ }
83
+ if (a.startsWith("--out=")) {
84
+ out = a.slice("--out=".length);
85
+ continue;
86
+ }
87
+ return { error: `unknown flag or positional arg: ${a}` };
88
+ }
89
+ return { commit, cwd, out };
90
+ }
91
+ export async function cmdPublish(rest, io, deps = {}) {
92
+ if (rest.includes("--help") || rest.includes("-h")) {
93
+ io.stdout(`${HELP}`);
94
+ return 0;
95
+ }
96
+ const parsed = parsePublishArgs(rest);
97
+ if ("error" in parsed) {
98
+ io.stderr(`df publish: ${parsed.error}\nRun \`df publish --help\` for usage.\n`);
99
+ return 2;
100
+ }
101
+ let loaded;
102
+ try {
103
+ loaded = await loadAgentReviewConfig({ cwd: parsed.cwd });
104
+ }
105
+ catch (err) {
106
+ io.stderr(`df publish: ${err.message}\n`);
107
+ return 1;
108
+ }
109
+ let sha;
110
+ try {
111
+ sha = await resolveCommit(parsed.commit, parsed.cwd);
112
+ }
113
+ catch (err) {
114
+ io.stderr(`df publish: ${err.message}\n`);
115
+ return 1;
116
+ }
117
+ const short = sha.slice(0, 12);
118
+ let collected;
119
+ try {
120
+ collected = await collectPublishArtifacts(loaded, sha, parsed.cwd);
121
+ }
122
+ catch (err) {
123
+ io.stderr(`df publish: failed to read evidence for ${short}: ${err.message}\n`);
124
+ return 1;
125
+ }
126
+ if (collected === null) {
127
+ io.stdout(`df publish: no quality-gate evidence found for ${short} — run \`df verify\` first; nothing to publish.\n`);
128
+ return 0;
129
+ }
130
+ const env = deps.env ?? process.env;
131
+ const resolveCerebe = deps.resolveCerebe ?? resolveCerebeConfig;
132
+ const makeUploader = deps.makeUploader ?? ((config) => new CerebeStorage(config));
133
+ const cerebe = resolveCerebe(env);
134
+ const uploader = cerebe ? makeUploader(cerebe) : null;
135
+ const manifest = await buildPublishManifest({
136
+ commit: sha,
137
+ ...(collected.diffHash !== undefined ? { diffHash: collected.diffHash } : {}),
138
+ ...(collected.gate !== undefined ? { gate: collected.gate } : {}),
139
+ routes: collected.routes,
140
+ uploader,
141
+ sessionId: `df-publish:${short}`,
142
+ userId: (env["CEREBE_USER_ID"] ?? "dark-factory").trim() || "dark-factory",
143
+ });
144
+ const serialized = `${JSON.stringify(manifest, null, 2)}\n`;
145
+ if (parsed.out !== null) {
146
+ try {
147
+ writeFileSync(parsed.out, serialized, "utf8");
148
+ }
149
+ catch (err) {
150
+ io.stderr(`df publish: failed to write ${parsed.out}: ${err.message}\n`);
151
+ return 1;
152
+ }
153
+ io.stdout(`df publish: wrote manifest to ${parsed.out}\n`);
154
+ }
155
+ else {
156
+ io.stdout(serialized);
157
+ }
158
+ const uploaded = (manifest.gateEvidence ? 1 : 0) +
159
+ Object.values(manifest.routes).reduce((n, r) => n + r.artifacts.length, 0);
160
+ if (manifest.status === "degraded") {
161
+ io.stderr(`df publish: status=degraded (${short}) — ${manifest.degradedReason ?? "unknown reason"}\n`);
162
+ }
163
+ else {
164
+ io.stderr(`df publish: status=complete (${short}) — ${uploaded} artifact(s) uploaded.\n`);
165
+ }
166
+ return 0;
167
+ }
168
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ export interface CerebeConfig {
2
+ baseUrl: string;
3
+ apiKey: string;
4
+ project?: string;
5
+ }
6
+ export interface CerebeUploadInput {
7
+ bytes: Uint8Array;
8
+ filename: string;
9
+ contentType: string;
10
+ sessionId: string;
11
+ userId: string;
12
+ purpose?: string;
13
+ tenantId?: string;
14
+ }
15
+ export interface CerebeUploadResult {
16
+ uploadId: string;
17
+ sha256: string;
18
+ sizeBytes: number;
19
+ contentType: string;
20
+ cdnUrl?: string;
21
+ status?: string;
22
+ }
23
+ export declare class CerebeAuthError extends Error {
24
+ constructor(message: string);
25
+ }
26
+ export declare class CerebeUploadError extends Error {
27
+ readonly status?: number | undefined;
28
+ constructor(message: string, status?: number | undefined);
29
+ }
30
+ type FetchFn = (input: string, init?: RequestInit) => Promise<Response>;
31
+ export interface CerebeStorageOptions {
32
+ fetch?: FetchFn;
33
+ maxRetries?: number;
34
+ retryBaseMs?: number;
35
+ sleep?: (ms: number) => Promise<void>;
36
+ }
37
+ export declare function resolveCerebeConfig(env?: Record<string, string | undefined>): CerebeConfig | null;
38
+ export declare function sha256Hex(bytes: Uint8Array): string;
39
+ export declare class CerebeStorage {
40
+ private readonly config;
41
+ private readonly options;
42
+ constructor(config: CerebeConfig, options?: CerebeStorageOptions);
43
+ uploadFile(input: CerebeUploadInput): Promise<CerebeUploadResult>;
44
+ private headers;
45
+ private buildForm;
46
+ }
47
+ export {};
48
+ //# sourceMappingURL=cerebe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cerebe.d.ts","sourceRoot":"","sources":["../../src/evidence/cerebe.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IAGpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IAGjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAID,qBAAa,iBAAkB,SAAQ,KAAK;IAGxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM;gBADxB,OAAO,EAAE,MAAM,EACN,MAAM,CAAC,EAAE,MAAM,YAAA;CAK3B;AAED,KAAK,OAAO,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAExE,MAAM,WAAW,oBAAoB;IAEnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAKD,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,YAAY,GAAG,IAAI,CAUrB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEnD;AAKD,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,oBAAyB;IAG/C,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAkFvE,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,SAAS;CAkBlB"}
@@ -0,0 +1,163 @@
1
+ // Cycle 331.1 verifiable-objectives Phase 2 (momentiq-ai/dark-factory#207) —
2
+ // the Cerebe object-storage facade. A thin, typed wrapper over the Cerebe
3
+ // storage REST API, used by `df publish` to persist `df verify` evidence
4
+ // durably in CI.
5
+ //
6
+ // Why raw `fetch` instead of the `cerebe` SDK: the taxpilot2a facade
7
+ // (`backend/shared/services/storage.py`, the contract reference) wraps the
8
+ // Python SDK, but this CLI ships Apache-2.0 + air-gap-capable, so the publish
9
+ // path must (a) add no network-SDK dependency and (b) FAIL SOFT when Cerebe is
10
+ // not configured. The wire contract is pinned from cerebe-platform's server
11
+ // route + SDK: `POST /storage/upload` (multipart: file/session_id/user_id/
12
+ // purpose/tenant_id) authenticated by the `X-API-Key` header, → 201
13
+ // `{ upload_id, cdn_url, status, … }`.
14
+ //
15
+ // `resolveCerebeConfig` returns `null` when the env is absent — the caller
16
+ // degrades-and-passes rather than erroring (spec §5). `uploadFile` retries
17
+ // transient failures (5xx/429/network) and distinguishes an auth failure
18
+ // (`CerebeAuthError`, never retried) from an exhausted/unrecoverable upload
19
+ // (`CerebeUploadError`).
20
+ import { createHash } from "node:crypto";
21
+ // An authentication failure (401/403). Distinct from a transient error so the
22
+ // caller surfaces "check CEREBE_API_KEY" instead of retrying a doomed request.
23
+ export class CerebeAuthError extends Error {
24
+ constructor(message) {
25
+ super(message);
26
+ this.name = "CerebeAuthError";
27
+ }
28
+ }
29
+ // A non-auth upload failure: a request-level 4xx, an exhausted transient retry
30
+ // budget, or a malformed success response.
31
+ export class CerebeUploadError extends Error {
32
+ status;
33
+ constructor(message, status) {
34
+ super(message);
35
+ this.status = status;
36
+ this.name = "CerebeUploadError";
37
+ }
38
+ }
39
+ // Resolve Cerebe config from the environment. Returns `null` when either
40
+ // CEREBE_API_URL or CEREBE_API_KEY is missing/blank — the fail-soft signal
41
+ // that publish should degrade rather than error (air-gap / OSS baseline).
42
+ export function resolveCerebeConfig(env = process.env) {
43
+ const baseUrl = (env["CEREBE_API_URL"] ?? "").trim();
44
+ const apiKey = (env["CEREBE_API_KEY"] ?? "").trim();
45
+ if (baseUrl === "" || apiKey === "")
46
+ return null;
47
+ const project = (env["CEREBE_PROJECT"] ?? "").trim();
48
+ return {
49
+ baseUrl: baseUrl.replace(/\/+$/, ""),
50
+ apiKey,
51
+ ...(project !== "" ? { project } : {}),
52
+ };
53
+ }
54
+ export function sha256Hex(bytes) {
55
+ return createHash("sha256").update(bytes).digest("hex");
56
+ }
57
+ const DEFAULT_MAX_RETRIES = 3;
58
+ const DEFAULT_RETRY_BASE_MS = 500;
59
+ export class CerebeStorage {
60
+ config;
61
+ options;
62
+ constructor(config, options = {}) {
63
+ this.config = config;
64
+ this.options = options;
65
+ }
66
+ async uploadFile(input) {
67
+ const fetchFn = this.options.fetch ?? globalThis.fetch;
68
+ const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;
69
+ const retryBaseMs = this.options.retryBaseMs ?? DEFAULT_RETRY_BASE_MS;
70
+ const sleep = this.options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
71
+ const sha256 = sha256Hex(input.bytes);
72
+ const sizeBytes = input.bytes.byteLength;
73
+ const url = `${this.config.baseUrl}/storage/upload`;
74
+ let lastError;
75
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
76
+ let res;
77
+ try {
78
+ res = await fetchFn(url, {
79
+ method: "POST",
80
+ headers: this.headers(),
81
+ body: this.buildForm(input),
82
+ });
83
+ }
84
+ catch (err) {
85
+ // Network/transport error — retryable.
86
+ lastError = new CerebeUploadError(`network error uploading ${input.filename}: ${err.message}`);
87
+ if (attempt < maxRetries) {
88
+ await sleep(retryBaseMs * 2 ** attempt);
89
+ continue;
90
+ }
91
+ break;
92
+ }
93
+ if (res.status === 401 || res.status === 403) {
94
+ throw new CerebeAuthError(`Cerebe rejected the API key (HTTP ${res.status}) — check CEREBE_API_KEY.`);
95
+ }
96
+ if (res.status === 429 || res.status >= 500) {
97
+ // Transient — back off and retry, honoring Retry-After when present.
98
+ lastError = new CerebeUploadError(`Cerebe upload failed (HTTP ${res.status})`, res.status);
99
+ if (attempt < maxRetries) {
100
+ await sleep(retryAfterMs(res) ?? retryBaseMs * 2 ** attempt);
101
+ continue;
102
+ }
103
+ break;
104
+ }
105
+ if (!res.ok) {
106
+ // A non-auth 4xx — a request-level problem; retrying won't help.
107
+ throw new CerebeUploadError(`Cerebe upload failed (HTTP ${res.status}): ${await safeText(res)}`, res.status);
108
+ }
109
+ const data = (await res.json().catch(() => ({})));
110
+ if (!data.upload_id) {
111
+ throw new CerebeUploadError(`Cerebe upload of ${input.filename} returned no upload_id`);
112
+ }
113
+ return {
114
+ uploadId: data.upload_id,
115
+ sha256,
116
+ sizeBytes,
117
+ contentType: input.contentType,
118
+ ...(data.cdn_url ? { cdnUrl: data.cdn_url } : {}),
119
+ ...(data.status ? { status: data.status } : {}),
120
+ };
121
+ }
122
+ throw (lastError ??
123
+ new CerebeUploadError(`Cerebe upload of ${input.filename} failed after ${maxRetries} retries`));
124
+ }
125
+ headers() {
126
+ return {
127
+ "X-API-Key": this.config.apiKey,
128
+ ...(this.config.project ? { "X-Cerebe-Project": this.config.project } : {}),
129
+ };
130
+ }
131
+ buildForm(input) {
132
+ const form = new FormData();
133
+ // Native Blob/FormData (Node 18+ / undici): `fetch` sets the multipart
134
+ // Content-Type + boundary itself, so `headers()` must NOT set it.
135
+ // `as BlobPart`: a Uint8Array is a valid Blob part at runtime, but TS 5.7's
136
+ // stricter `Uint8Array<ArrayBufferLike>` doesn't structurally match the
137
+ // lib's `BlobPart` (which excludes SharedArrayBuffer-backed views).
138
+ form.append("file", new Blob([input.bytes], { type: input.contentType }), input.filename);
139
+ form.append("session_id", input.sessionId);
140
+ form.append("user_id", input.userId);
141
+ form.append("purpose", input.purpose ?? "general");
142
+ form.append("tenant_id", input.tenantId ?? "cerebe");
143
+ return form;
144
+ }
145
+ }
146
+ function retryAfterMs(res) {
147
+ const raw = res.headers.get("retry-after");
148
+ if (!raw)
149
+ return undefined;
150
+ const seconds = Number(raw);
151
+ if (Number.isFinite(seconds) && seconds >= 0)
152
+ return seconds * 1000;
153
+ return undefined;
154
+ }
155
+ async function safeText(res) {
156
+ try {
157
+ return (await res.text()).slice(0, 200);
158
+ }
159
+ catch {
160
+ return "<no body>";
161
+ }
162
+ }
163
+ //# sourceMappingURL=cerebe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cerebe.js","sourceRoot":"","sources":["../../src/evidence/cerebe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { type BoundProofRecord, type CriticStatus, type Objective, type ReviewVerdict } from "@momentiq/dark-factory-schemas";
2
+ export interface RouteEvidenceInput {
3
+ exitCode: number;
4
+ }
5
+ export interface CriticEvidenceInput {
6
+ status: CriticStatus;
7
+ verdict?: ReviewVerdict;
8
+ }
9
+ export interface ProofInputs {
10
+ commit: string;
11
+ headDiffHash?: string;
12
+ objectives: Objective[];
13
+ gateResults: Record<string, RouteEvidenceInput>;
14
+ evidenceDiffHash?: string;
15
+ criticResults: Record<string, CriticEvidenceInput>;
16
+ uploadIds?: Record<string, string>;
17
+ }
18
+ export declare function buildProofRecord(inputs: ProofInputs, generatedAt: string): BoundProofRecord;
19
+ export interface CollectedProofInputs {
20
+ inputs: ProofInputs;
21
+ resolvedSha: string;
22
+ }
23
+ export declare function collectProofInputs(cwd: string, commit: string): Promise<CollectedProofInputs | null>;
24
+ //# sourceMappingURL=prove.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prove.d.ts","sourceRoot":"","sources":["../../src/evidence/prove.ts"],"names":[],"mappings":"AAsBA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAEjB,KAAK,SAAS,EAId,KAAK,aAAa,EACnB,MAAM,gCAAgC,CAAC;AASxC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IAEf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,SAAS,EAAE,CAAC;IAExB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAEhD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAEnD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAqED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAsB3F;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAiEtC"}
@@ -0,0 +1,170 @@
1
+ // Cycle 331.1 verifiable-objectives — the closeout proof readout behind
2
+ // `df prove` (momentiq-ai/dark-factory#207). Joins each declared objective
3
+ // (`.darkfactory/objectives.yaml`) against the local evidence that attests it —
4
+ // route exit codes (`df verify`), critic verdicts (`df review`) — resolving every
5
+ // binding to proven / pending / failed and assembling a `BoundProofRecord`.
6
+ //
7
+ // Two layers, split for testability:
8
+ // - `buildProofRecord` — the pure join (no disk, no git); takes already-loaded
9
+ // inputs, returns the record. The trichotomy + worst-of rollup live here.
10
+ // - `collectProofInputs` — reads the manifest + gate evidence + review artifact
11
+ // from disk for a commit.
12
+ //
13
+ // Trust boundary: this readout is agent-attested, evidence-backed — the agent
14
+ // authored both the code and the objectives. It is stronger than free-text "done"
15
+ // (every status is DERIVED from diffHash-bound artifacts, not asserted) but is NOT
16
+ // independent verification. See the design spec (§2).
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ import { resolve } from "node:path";
19
+ import { parse as parseYaml } from "yaml";
20
+ import { parseObjectivesManifest, } from "@momentiq/dark-factory-schemas";
21
+ import { loadAgentReviewConfig } from "../policy/config.js";
22
+ import { commitDiff, diffHash, repoRoot, resolveCommit, safeParentOrThrow } from "../git.js";
23
+ import { readQualityGateEvidence } from "./quality-gates.js";
24
+ import { loadForCommit } from "../lib/show-status-core.js";
25
+ const STATUS_RANK = { proven: 0, pending: 1, failed: 2 };
26
+ function worstOf(statuses) {
27
+ let worst = "proven";
28
+ for (const s of statuses) {
29
+ if (STATUS_RANK[s] > STATUS_RANK[worst])
30
+ worst = s;
31
+ }
32
+ return worst;
33
+ }
34
+ function resolveRouteLike(kind, ref, inputs) {
35
+ const uploadId = inputs.uploadIds?.[ref];
36
+ const base = { kind, ref, ...(uploadId ? { uploadId } : {}) };
37
+ const r = inputs.gateResults[ref];
38
+ if (!r) {
39
+ return { ...base, status: "pending", detail: "no route evidence — run `df verify`" };
40
+ }
41
+ if (r.exitCode !== 0) {
42
+ return { ...base, status: "failed", detail: `route exited ${r.exitCode}` };
43
+ }
44
+ const bound = inputs.evidenceDiffHash !== undefined &&
45
+ inputs.headDiffHash !== undefined &&
46
+ inputs.evidenceDiffHash === inputs.headDiffHash;
47
+ if (bound) {
48
+ return { ...base, status: "proven", detail: "exit 0, diffHash-bound" };
49
+ }
50
+ return {
51
+ ...base,
52
+ status: "pending",
53
+ detail: "exit 0 but evidence not bound to HEAD's diff (stale or SHA-only)",
54
+ };
55
+ }
56
+ function resolveCritic(criticId, inputs) {
57
+ const uploadId = inputs.uploadIds?.[criticId];
58
+ const base = { kind: "critic", ref: criticId, ...(uploadId ? { uploadId } : {}) };
59
+ const c = inputs.criticResults[criticId];
60
+ if (!c) {
61
+ return { ...base, status: "pending", detail: "awaiting critic verdict — fleet has not run on HEAD" };
62
+ }
63
+ if (c.verdict === "APPROVED") {
64
+ return { ...base, status: "proven", detail: "critic APPROVED" };
65
+ }
66
+ if (c.verdict === "CHANGES_REQUESTED") {
67
+ return { ...base, status: "failed", detail: "critic CHANGES_REQUESTED" };
68
+ }
69
+ return { ...base, status: "pending", detail: `critic ${c.status}, no verdict yet` };
70
+ }
71
+ function resolveBinding(b, inputs) {
72
+ switch (b.kind) {
73
+ case "route":
74
+ return resolveRouteLike("route", b.routeId, inputs);
75
+ case "test":
76
+ return resolveRouteLike("test", b.ref, inputs);
77
+ case "critic":
78
+ return resolveCritic(b.criticId, inputs);
79
+ }
80
+ }
81
+ // Pure join: objectives × evidence → BoundProofRecord. `generatedAt` is supplied
82
+ // by the caller (keeps this deterministic + testable).
83
+ export function buildProofRecord(inputs, generatedAt) {
84
+ const objectives = inputs.objectives.map((o) => {
85
+ const bindings = o.attestedBy.map((b) => resolveBinding(b, inputs));
86
+ // An objective with no bindings is declared-but-unbound → pending, never
87
+ // silently proven. Otherwise it's the worst of its bindings.
88
+ const status = bindings.length === 0 ? "pending" : worstOf(bindings.map((b) => b.status));
89
+ return { id: o.id, text: o.text, enforced: o.enforced, status, bindings };
90
+ });
91
+ const summary = { proven: 0, pending: 0, failed: 0, total: objectives.length };
92
+ for (const o of objectives)
93
+ summary[o.status] += 1;
94
+ return {
95
+ schemaVersion: 1,
96
+ commit: inputs.commit,
97
+ ...(inputs.headDiffHash !== undefined ? { diffHash: inputs.headDiffHash } : {}),
98
+ provenance: "consumer-attested",
99
+ generatedAt,
100
+ objectives,
101
+ summary,
102
+ };
103
+ }
104
+ const OBJECTIVES_MANIFEST_REL = ".darkfactory/objectives.yaml";
105
+ // Read the objectives manifest + gate evidence + review artifact from disk for a
106
+ // commit. Returns `null` when no manifest is present (nothing to prove). Throws
107
+ // (caller → exit 1) on a malformed manifest or unreadable config — a real error
108
+ // in the PR's own diff.
109
+ export async function collectProofInputs(cwd, commit) {
110
+ // Resolve the manifest against the git repo root, not cwd, so `df prove` works
111
+ // from a subdirectory (the common case). Fall back to cwd outside a git repo.
112
+ let root = cwd;
113
+ try {
114
+ root = await repoRoot(cwd);
115
+ }
116
+ catch {
117
+ root = cwd;
118
+ }
119
+ const manifestPath = resolve(root, OBJECTIVES_MANIFEST_REL);
120
+ if (!existsSync(manifestPath))
121
+ return null;
122
+ const manifest = parseObjectivesManifest(parseYaml(readFileSync(manifestPath, "utf8")), OBJECTIVES_MANIFEST_REL);
123
+ const loaded = await loadAgentReviewConfig({ cwd });
124
+ const sha = await resolveCommit(commit, cwd);
125
+ // HEAD's gated diff hash (the binding target). Fail-soft: a transient git
126
+ // error leaves it undefined → route bindings degrade to pending, never
127
+ // false-proven.
128
+ let headDiffHash;
129
+ try {
130
+ const parent = await safeParentOrThrow(sha, cwd);
131
+ headDiffHash = diffHash(await commitDiff(parent, sha, cwd));
132
+ }
133
+ catch {
134
+ headDiffHash = undefined;
135
+ }
136
+ // Route/test evidence.
137
+ const gateResults = {};
138
+ let evidenceDiffHash;
139
+ const { evidence } = await readQualityGateEvidence(loaded, sha);
140
+ if (evidence && evidence.commit === sha) {
141
+ evidenceDiffHash = evidence.diffHash;
142
+ for (const [routeId, res] of Object.entries(evidence.gateResults ?? {})) {
143
+ gateResults[routeId] = { exitCode: res.exitCode };
144
+ }
145
+ }
146
+ // Critic evidence (the per-SHA ReviewArtifact). Absent → empty → critic
147
+ // bindings resolve to pending.
148
+ const criticResults = {};
149
+ const { artifact } = await loadForCommit(cwd, sha);
150
+ if (artifact) {
151
+ for (const c of artifact.criticResults) {
152
+ criticResults[c.criticId] = {
153
+ status: c.status,
154
+ ...(c.verdict !== undefined ? { verdict: c.verdict } : {}),
155
+ };
156
+ }
157
+ }
158
+ return {
159
+ inputs: {
160
+ commit: sha,
161
+ ...(headDiffHash !== undefined ? { headDiffHash } : {}),
162
+ objectives: manifest.objectives,
163
+ gateResults,
164
+ ...(evidenceDiffHash !== undefined ? { evidenceDiffHash } : {}),
165
+ criticResults,
166
+ },
167
+ resolvedSha: sha,
168
+ };
169
+ }
170
+ //# sourceMappingURL=prove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prove.js","sourceRoot":"","sources":["../../src/evidence/prove.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { EvidenceProvenance, PublishedEvidence } from "@momentiq/dark-factory-schemas";
2
+ import type { LoadedConfig } from "../policy/config.js";
3
+ import type { CerebeUploadInput, CerebeUploadResult } from "./cerebe.js";
4
+ export interface EvidenceUploader {
5
+ uploadFile(input: CerebeUploadInput): Promise<CerebeUploadResult>;
6
+ }
7
+ export interface ArtifactSource {
8
+ path: string;
9
+ contentType: string;
10
+ bytes: Uint8Array;
11
+ }
12
+ export interface RouteArtifacts {
13
+ routeId: string;
14
+ exitCode: number;
15
+ sources: ArtifactSource[];
16
+ }
17
+ export interface BuildPublishManifestInput {
18
+ commit: string;
19
+ diffHash?: string;
20
+ gate?: ArtifactSource;
21
+ routes: RouteArtifacts[];
22
+ uploader: EvidenceUploader | null;
23
+ sessionId: string;
24
+ userId: string;
25
+ provenance?: EvidenceProvenance;
26
+ }
27
+ export declare function buildPublishManifest(input: BuildPublishManifestInput): Promise<PublishedEvidence>;
28
+ export interface CollectedArtifacts {
29
+ gate?: ArtifactSource;
30
+ routes: RouteArtifacts[];
31
+ diffHash?: string;
32
+ }
33
+ export declare function collectPublishArtifacts(loaded: LoadedConfig, commit: string, cwd: string): Promise<CollectedArtifacts | null>;
34
+ export declare function contentTypeForPath(p: string): string;
35
+ //# sourceMappingURL=publish.d.ts.map