Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,8 @@ script. With neither, it reports `no_gate` with exit code 2. An unconfigured gat
| `proofloop report latest [--json]` | Summarize the latest gate receipt. |
| `proofloop charts latest` | Write local JSON/SVG proof charts under `.proofloop/charts/`. |
| `proofloop receipt verify --file <path>` | Verify app-produced proof receipts such as NodeAgent ingestion receipts. |
| `proofloop receipt envelope verify --file <path>` | Verify a `proofloop.receipt/v1` envelope, authority semantics, and local content hashes. |
| `proofloop receipt schema [--json]` | Locate or print the packaged `proofloop.receipt/v1` JSON Schema. |
| `proofloop solo setup --source <repo> --agent both` | Install one canonical Solo skill for Codex and Claude Code and compose one Stop gate. |
| `proofloop solo ingest --file <envelope> --write-runner-plan` | Validate Solo evidence and optionally compile advisory tasks without executing them. |
| `proofloop solo status\|resume\|gate` | Inspect or enforce the NodeProof-derived Solo interop state. |
Expand Down Expand Up @@ -421,6 +423,27 @@ The verifier checks the receipt type/version, `ok: true`, document-pool to memor
created document and memory-object counts, proof hashes/keys, zero source/chunk failures, and positive
batch/concurrency config. Failed receipts exit 1, while malformed CLI usage exits 2.

### Canonical receipt envelope

`proofloop.receipt/v1` is the general transport envelope for gate, Solo, hosted, UI-QA, evaluation,
runner, maturity, and app-specific receipts. It preserves each existing payload under a versioned,
content-hashed `payload` field while keeping the verdict authority separate:

- Only deterministic gates or official scorers may produce an authoritative verdict.
- Model judges, human reviews, and imported pass claims remain advisory.
- Decisive checks must reference locally verifiable, content-hashed evidence.
- Inline payloads use sorted-key canonical JSON SHA-256; referenced files use raw-byte SHA-256.

```bash
npx proofloop receipt schema
npx proofloop receipt schema --json
npx proofloop receipt envelope verify --file proof/receipt.json
```

See [`docs/receipt-envelope-v1.md`](docs/receipt-envelope-v1.md) for the public TypeScript API,
authority rules, and migration mapping for existing schemas. Existing receipt schemas and the
`receipt verify --kind nodeagent-ingestion` command remain supported.

## Scope

This package is the portable core: gate, refuse-fake-done hooks, expected-tool-use contracts,
Expand Down
38 changes: 34 additions & 4 deletions dist/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const proofloopHooks_1 = require("./proofloopHooks");
const proofloopCi_1 = require("./proofloopCi");
const proofloopToolUse_1 = require("./proofloopToolUse");
const receipts_1 = require("./receipts");
const proofReceipt_1 = require("./proofReceipt");
const mcp_1 = require("./mcp");
const project_1 = require("./project");
const runner_1 = require("./runner");
Expand Down Expand Up @@ -113,6 +114,8 @@ function usage() {
" report latest [--json] latest gate report",
" charts latest write local JSON/SVG proof charts",
" receipt verify --file <path> verify app-produced proof receipts",
" receipt envelope verify --file <path> verify a proofloop.receipt/v1 envelope",
" receipt schema [--json] locate or print the proofloop.receipt/v1 JSON Schema",
" solo setup --source <path> [--agent codex|claude-code|both] [--install-deps] [--verify]",
" solo ingest|status|gate|resume validate and inspect Solo interop evidence",
" solo attest --file <envelope> --gate-receipt <receipt> --out <receipt> --key-id <id>",
Expand Down Expand Up @@ -190,7 +193,7 @@ function runCli(argv) {
case "charts":
return runChartsCommand(positional[1], root);
case "receipt":
return runReceiptCommand(positional[1], options, root);
return runReceiptCommand(positional[1], positional[2], options, root);
case "solo":
return runSoloCommand(positional[1], options, root);
case "runner":
Expand Down Expand Up @@ -743,9 +746,36 @@ function runChartsCommand(sub, root) {
console.log(`proofloop charts: wrote ${result.svgPath}`);
return 0;
}
function runReceiptCommand(sub, options, root) {
if (sub !== "verify") {
console.error("proofloop receipt: expected `verify`.");
function runReceiptCommand(sub, action, options, root) {
if (sub === "schema") {
if (action !== undefined) {
console.error("proofloop receipt schema: unexpected positional argument.");
return 2;
}
if (options.json === true)
console.log(JSON.stringify((0, proofReceipt_1.readProofReceiptSchema)(), null, 2));
else
console.log((0, proofReceipt_1.proofReceiptSchemaPath)());
return 0;
}
if (sub === "envelope") {
if (action !== "verify") {
console.error("proofloop receipt envelope: expected `verify`.");
return 2;
}
const filePath = str(options.file);
if (!filePath) {
console.error("proofloop receipt envelope verify: --file <path> is required.");
return 2;
}
return (0, proofReceipt_1.runProofReceiptEnvelopeVerify)({
root,
filePath,
json: options.json === true,
});
}
if (sub !== "verify" || action !== undefined) {
console.error("proofloop receipt: expected `verify`, `envelope verify`, or `schema`.");
return 2;
}
const filePath = str(options.file);
Expand Down
1 change: 1 addition & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export * from "./maturity";
export * from "./productivity";
export * from "./contextReport";
export * from "./receipts";
export * from "./proofReceipt";
export * from "./agentAdapters";
export * from "./agentLoop";
export * from "./codexRelaunch";
Expand Down
1 change: 1 addition & 0 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ __exportStar(require("./maturity"), exports);
__exportStar(require("./productivity"), exports);
__exportStar(require("./contextReport"), exports);
__exportStar(require("./receipts"), exports);
__exportStar(require("./proofReceipt"), exports);
__exportStar(require("./agentAdapters"), exports);
__exportStar(require("./agentLoop"), exports);
__exportStar(require("./codexRelaunch"), exports);
Expand Down
164 changes: 164 additions & 0 deletions dist/proofReceipt.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
export declare const PROOFLOOP_RECEIPT_SCHEMA: "proofloop.receipt/v1";
export declare const PROOFLOOP_RECEIPT_SCHEMA_VERSION: 1;
export declare const PROOFLOOP_RECEIPT_SCHEMA_FILE: "proofloop-receipt-v1.schema.json";
export type ProofReceiptAuthority = "authoritative" | "advisory" | "informational";
export type ProofReceiptStatus = "passed" | "failed" | "blocked" | "incomplete" | "error" | "unknown";
export type ProofReceiptDecisionMethod = "deterministic_gate" | "official_scorer" | "model_judge" | "human_review" | "external_claim" | "none";
export type ProofReceiptCheckStatus = "passed" | "failed" | "blocked" | "error" | "skipped" | "unknown";
export type ProofReceiptCheckMethod = "deterministic" | "official_scorer" | "model_judge" | "human_review" | "external";
export type ProofReceiptHashMethod = "raw-bytes-sha256" | "canonical-json-sha256" | "utf8-sha256";
export interface ProofReceiptResource {
id: string;
kind: string;
description?: string;
path?: string;
uri?: string;
inline?: unknown;
sha256: string;
hashMethod: ProofReceiptHashMethod;
mediaType?: string;
visibility?: "private" | "team" | "public";
redacted?: boolean;
}
export interface ProofReceiptCheck {
id: string;
status: ProofReceiptCheckStatus;
role: "decisive" | "advisory";
method: ProofReceiptCheckMethod;
summary: string;
evidenceRefs: string[];
durationMs?: number;
exitCode?: number;
score?: number;
threshold?: number;
scorer?: {
name: string;
version: string;
digest?: string;
};
}
export interface ProofReceiptPayload {
schema: string;
version?: string | number;
mode: "inline" | "reference";
data?: unknown;
ref?: string;
sha256: string;
hashMethod: "raw-bytes-sha256" | "canonical-json-sha256";
}
export interface ProofReceiptEnvelope {
$schema?: string;
schema: typeof PROOFLOOP_RECEIPT_SCHEMA;
schemaVersion: typeof PROOFLOOP_RECEIPT_SCHEMA_VERSION;
receiptId: string;
kind: string;
createdAt: string;
producer: {
id: string;
version: string;
runtime?: string;
configHash?: string;
};
subject: {
type: "repository" | "deployment" | "run" | "workflow" | "artifact" | "evaluation" | "application";
id: string;
runId?: string;
artifactId?: string;
targetUrl?: string;
repository?: {
url?: string;
baseCommit?: string;
candidateCommit?: string;
branch?: string;
dirty?: boolean;
};
};
claim?: {
text: string;
boundary: "product_path" | "proxy" | "official" | "internal";
tier?: "local_ready" | "team_ready" | "certification_ready";
};
verdict: {
status: ProofReceiptStatus;
authority: ProofReceiptAuthority;
decisionMethod: ProofReceiptDecisionMethod;
decisiveCheckIds: string[];
summary: string;
};
checks: ProofReceiptCheck[];
evidence: ProofReceiptResource[];
artifacts?: ProofReceiptResource[];
payload: ProofReceiptPayload;
lineage?: {
parentReceiptIds?: string[];
sourceReceiptIds?: string[];
migration?: string;
};
timing?: {
startedAt?: string;
completedAt?: string;
durationMs?: number;
phases?: Array<{
id: string;
startedAt?: string;
completedAt?: string;
durationMs: number;
}>;
};
budget?: {
maxUsd?: number;
spentUsd?: number;
maxRuntimeMs?: number;
maxModelCalls?: number;
modelCalls?: number;
};
privacy?: {
visibility: "private" | "team" | "public";
redacted: boolean;
containsPersonalData?: boolean;
externalEgress?: boolean;
};
extensions?: Record<string, unknown>;
}
export interface ProofReceiptIssue {
path: string;
code: string;
message: string;
}
export interface ProofReceiptValidation {
ok: boolean;
errors: ProofReceiptIssue[];
warnings: ProofReceiptIssue[];
envelope?: ProofReceiptEnvelope;
}
export interface ProofReceiptFileVerification extends ProofReceiptValidation {
receiptPath: string;
}
export declare function proofReceiptSchemaPath(): string;
export declare function readProofReceiptSchema(): unknown;
export declare function canonicalJson(value: unknown): string;
export declare function sha256Utf8(value: string): string;
export declare function sha256CanonicalJson(value: unknown): string;
export declare function createInlineProofReceiptPayload(schema: string, data: unknown, version?: string | number): ProofReceiptPayload;
export declare function createInlineProofReceiptResource(options: {
id: string;
kind: string;
inline: unknown;
description?: string;
mediaType?: string;
visibility?: "private" | "team" | "public";
redacted?: boolean;
}): ProofReceiptResource;
export declare function validateProofReceiptEnvelope(value: unknown): ProofReceiptValidation;
export declare function verifyProofReceiptEnvelopeFile(options: {
root: string;
filePath: string;
}): ProofReceiptFileVerification;
export declare function formatProofReceiptVerification(result: ProofReceiptFileVerification): string;
export declare function runProofReceiptEnvelopeVerify(options: {
root: string;
filePath: string;
json?: boolean;
log?: (message: string) => void;
logError?: (message: string) => void;
}): number;
Loading
Loading