diff --git a/.github/actions/verify/README.md b/.github/actions/verify/README.md index 2746cd5..75787d3 100644 --- a/.github/actions/verify/README.md +++ b/.github/actions/verify/README.md @@ -12,7 +12,7 @@ supplied by you and is not collection-attested. Gate an OFF and an ON evidence bundle (both must pass): ```yaml -- uses: AlexPaiva/PromiseProof/.github/actions/verify@main +- uses: AlexPaiva/PromiseProof/.github/actions/verify@submission-rc-03 with: mode: gate off_evidence: artifacts/personalization-off.json @@ -23,7 +23,7 @@ Gate an OFF and an ON evidence bundle (both must pass): Verify a single bundle: ```yaml -- uses: AlexPaiva/PromiseProof/.github/actions/verify@main +- uses: AlexPaiva/PromiseProof/.github/actions/verify@submission-rc-03 with: mode: verify evidence: artifacts/personalization-off.json @@ -32,7 +32,7 @@ Verify a single bundle: Reproduce a report from its evidence: ```yaml -- uses: AlexPaiva/PromiseProof/.github/actions/verify@main +- uses: AlexPaiva/PromiseProof/.github/actions/verify@submission-rc-03 with: mode: check report: artifacts/promiseproof/report.json diff --git a/ADOPTION.md b/ADOPTION.md index 2d10f99..c424a11 100644 --- a/ADOPTION.md +++ b/ADOPTION.md @@ -211,7 +211,7 @@ A bundled GitHub Action runs the same frozen verifier in a workflow with no `npm Gate an OFF and an ON bundle: ```yaml -- uses: AlexPaiva/PromiseProof/.github/actions/verify@main +- uses: AlexPaiva/PromiseProof/.github/actions/verify@submission-rc-03 with: mode: gate off_evidence: artifacts/personalization-off.json diff --git a/JUDGE_START_HERE.md b/JUDGE_START_HERE.md new file mode 100644 index 0000000..9c17b78 --- /dev/null +++ b/JUDGE_START_HERE.md @@ -0,0 +1,88 @@ +# PromiseProof: Judge Start Here + +## 15-second explanation + +When AI says "fixed," that is a claim, not a fact. GPT-5.6 investigates. Codex repairs. Neither decides PASS. An unchanged deterministic verifier does. + +## Judge in 60 seconds + +**1. Watch the recorded repair lifecycle.** +https://promiseproof.alex0paiva0.workers.dev/walkthrough/ + +Five stages: Observe, Investigate, Replay, Repair, Prove. It replays one authentic run: a user turned personalization off, one identifiable request still reached the recommendation service, GPT-5.6 ranked competing hypotheses and selected one allowlisted factual replay, Codex proposed a two-file repair, a human approved the exact patch, and an unchanged test decided PASS. + +**2. Challenge the proof yourself.** +https://promiseproof.alex0paiva0.workers.dev/verify/?judge=1 + +After the page loads, verification runs entirely in the browser. The verdict path uses no backend API, evidence upload, or model call. Expected states: + +- On load: `PASS` and `BOUND_AND_REPRODUCED`. +- After you tamper one OFF observation: `BROKEN_PROMISE`, violation `PP_IDENTIFIABLE_EVENT_LEAK`, and the report you sealed a moment earlier becomes `STALE_OR_MISMATCH`. +- After you seal the failing evidence: `BROKEN_PROMISE` and `BOUND_AND_REPRODUCED`. A report can honestly bind a failing verdict; it cannot manufacture a PASS. +- After reset: the original `PASS` and original evidence bindings return. + +**3. Inspect the GitHub Action.** +https://github.com/AlexPaiva/PromiseProof/tree/submission-rc-03/.github/actions/verify + +A bundled Action that runs the same verifier in CI with no `npm install`, no browser, and no API key. + +## Who has authority + +| Actor | May investigate | May propose source changes | May approve the exact patch | May decide PASS | +| --- | --- | --- | --- | --- | +| GPT-5.6 | Yes | No | No | No | +| Codex | Yes | Yes, in isolation | No | No | +| Human | Yes | No | Yes | No | +| Unchanged verifier | No | No | No | Yes | + +## Recorded versus fresh + +- **Recorded and authentic:** the GPT-5.6 investigation, the Codex source repair, and the five-stage walkthrough that presents them. These happened once and are replayed, not re-run live. +- **Fresh every time you interact:** the browser verification, the semantic tamper, the CLI verification, and the GitHub Action verification. These re-run the deterministic evaluator on the evidence in front of you. + +## Developer Tool path + +One deterministic authority, three surfaces: + +- **Hosted verifier** at `/verify/?judge=1`, no login and no key. +- **Repository-local CLI:** `npm run promiseproof -- gate|verify|check`. +- **Bundled GitHub Action:** `uses: AlexPaiva/PromiseProof/.github/actions/verify@submission-rc-03`. + +No API key, no browser, and no model call in the verdict path. Exactly one contract family is supported: `activity-personalization/v1`. External evidence is evaluated but not collection-attested. + +## Test locally + +Requirements: Node.js 22.12+, npm 10+, and (for the walkthrough tests) Playwright Chromium. + +```bash +npm ci +npx playwright install chromium + +# No-key recorded repair rehearsal: applies the approved patch in a +# disposable worktree and runs the unchanged verifier. +npm run demo:rehearse + +# Deterministic external verification from evidence: +npm run promiseproof -- init --out .promiseproof +npm run promiseproof -- gate \ + --off .promiseproof/passing-off.example.json \ + --on .promiseproof/passing-on.example.json \ + --out .promiseproof/report +npm run promiseproof -- check \ + --report .promiseproof/report/report.json \ + --off .promiseproof/passing-off.example.json \ + --on .promiseproof/passing-on.example.json + +# Test suites: +npm run test:external # CLI, bound-report reproduction, strict validation +npm run test:action # the bundled Action, spawned as a real Action +``` + +## Scope and limitations + +- Signal Shelf is a synthetic reference application. It exists to make one broken promise visible and repairable end to end. This is not a legal or regulatory compliance statement. +- Exactly one external contract family is supported: `activity-personalization/v1`. +- Evidence is externally supplied and is not collection-attested. Content binding proves a report matches its evidence and the pinned evaluator source; it does not prove the evidence was collected honestly. +- The `main` branch stays intentionally seeded-broken so the red-to-green repair can be demonstrated. Production main is not automatically repaired. +- Integrity is repository-level and content-addressed. It is not a signature, notarization, certification, or third-party attestation. +- The CLI is verified on Windows. The bundled Action is exercised on Windows, Ubuntu, and macOS runners. diff --git a/README.md b/README.md index 6046add..101b2e2 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ ### When software breaks a promise, the AI that repairs it doesn't get the final word. +**GPT-5.6 investigates. Codex repairs. Neither decides PASS.** + Carry a broken product promise all the way through bounded diagnosis, constrained repair, and independent verification, where a deterministic test, *never a model*, decides PASS. [](https://openai.com) @@ -12,7 +14,7 @@ Carry a broken product promise all the way through bounded diagnosis, constraine [](https://playwright.dev/) [](https://workers.cloudflare.com/) -**[▶ Live demo](https://promiseproof.alex0paiva0.workers.dev/)** · **[Judge walkthrough](https://promiseproof.alex0paiva0.workers.dev/walkthrough/)** · [How it works](#how-it-works) · [Quick start](#quick-start-the-judge-path) +**[▶ Live demo](https://promiseproof.alex0paiva0.workers.dev/)** · **[Judge Start Here](JUDGE_START_HERE.md)** · **[Judge walkthrough](https://promiseproof.alex0paiva0.workers.dev/walkthrough/)** · [How it works](#how-it-works) · [Quick start](#quick-start-the-judge-path)  @@ -132,7 +134,7 @@ npm run promiseproof -- check \ **GitHub Action**, drop the verifier into any workflow with no `npm install`, browser, or key: ```yaml -- uses: AlexPaiva/PromiseProof/.github/actions/verify@main +- uses: AlexPaiva/PromiseProof/.github/actions/verify@submission-rc-03 with: mode: gate off_evidence: artifacts/personalization-off.json @@ -140,7 +142,7 @@ npm run promiseproof -- check \ output_directory: artifacts/promiseproof ``` -The step fails on `BROKEN_PROMISE` and still leaves `report.json` and `report.md` behind. Replace `@main` with an immutable release tag once one contains the Action. Details in the [Action README](.github/actions/verify/README.md). +The step fails on `BROKEN_PROMISE` and still leaves `report.json` and `report.md` behind. `@submission-rc-03` is the immutable release tag that contains the Action; `@main` also works if you prefer to track the branch. Details in the [Action README](.github/actions/verify/README.md). What it is, stated exactly: diff --git a/landing/index.html b/landing/index.html index 17dc43a..7023743 100644 --- a/landing/index.html +++ b/landing/index.html @@ -258,6 +258,7 @@
@@ -269,10 +270,12 @@GPT-5.6 investigates. Codex repairs. Neither decides PASS.
PromiseProof turns one "off means off" promise into cross-system evidence. GPT-5.6 proposes and ranks candidate explanations, then requests one allowlisted replay; PromiseProof runs it. Codex proposes a constrained two-file repair, a human approves the exact patch, and an unchanged Playwright journey and deterministic evaluator, never a model, decide PASS.
Monitoring can tell you a promise broke. PromiseProof carries the failure through bounded diagnosis, constrained repair, and independent verification.
diff --git a/src/judge/main.ts b/src/judge/main.ts index 4621c69..8545f12 100644 --- a/src/judge/main.ts +++ b/src/judge/main.ts @@ -516,7 +516,7 @@ function renderInvestigate(data: JudgeData): HTMLElement { element( "p", "replay-caption", - "A registered replay is one allowlisted factual experiment the model can request; deterministic code runs it and records the facts. This recorded replay confirms the leading explanation — it does not decide the verdict.", + "A registered replay is one allowlisted factual experiment the model can request; deterministic code runs it and records the facts. This recorded replay confirms the leading explanation, but it does not decide the verdict.", ), ); fork.append(down); @@ -658,7 +658,7 @@ function renderReplay(data: JudgeData): HTMLElement { section.append(toolbar); // The reveal is a fresh CSS animation on mount, so re-rendering these nodes - // replays it on demand — the crossing is the one moment judges should see move. + // replays it on demand. The crossing is the one moment judges should see move. // `data-replaying` marks the explicit "Play the crossing" click: under // prefers-reduced-motion the crossing stays still on stage entry (honoring the // preference) and only animates when the user actually asks for it. @@ -1252,7 +1252,7 @@ function start(): void { return; } stageHost.replaceChildren(definition.render(data)); - // Marks that the DOM now holds THIS stage — the signal transitions settle on. + // Marks that the DOM now holds THIS stage. The signal transitions settle on. root.dataset.rendered = stage; if (focus) { stageHost.focus(); @@ -1294,7 +1294,7 @@ function start(): void { return; } - // Ease the outgoing content out, swap, then ease the incoming content in — + // Ease the outgoing content out, swap, then ease the incoming content in, // a real crossfade instead of a hard cut. stageHost.classList.remove("is-entering"); stageHost.classList.add("is-leaving"); diff --git a/src/verify-ui/main.ts b/src/verify-ui/main.ts index f55dbe7..7894c19 100644 --- a/src/verify-ui/main.ts +++ b/src/verify-ui/main.ts @@ -125,7 +125,7 @@ function offFacts(ev: WorkEvidence): Fact[] { const captured = ev.activity.capturedActivities.length; const receipts = ev.activity.recommendationServiceReceipts.length; return [ - { k: "Scenario", v: "OFF — personalization off" }, + { k: "Scenario", v: "OFF, personalization off" }, { k: "Subject", v: ev.subjectId }, { k: "Preference (ui / stored / backend)", @@ -142,7 +142,7 @@ function offFacts(ev: WorkEvidence): Fact[] { } function onFacts(ev: WorkEvidence): Fact[] { return [ - { k: "Scenario", v: "ON — personalization on" }, + { k: "Scenario", v: "ON, personalization on" }, { k: "Subject", v: ev.subjectId }, { k: "Preference (ui / stored / backend)", @@ -224,7 +224,7 @@ function renderViolations(list: HTMLElement, violations: readonly ViolationLike[ list.replaceChildren(); if (violations.length === 0) { list.className = "vf-violations empty"; - list.append(tag("li", undefined, "Promise verified — no violations.")); + list.append(tag("li", undefined, "Promise verified, no violations.")); return; } list.className = "vf-violations"; @@ -232,7 +232,7 @@ function renderViolations(list: HTMLElement, violations: readonly ViolationLike[ const item = tag("li"); item.append( tag("code", undefined, violation.code), - document.createTextNode(` (${violation.clause}) — ${violation.message}`), + document.createTextNode(` (${violation.clause}): ${violation.message}`), ); list.append(item); } @@ -259,13 +259,13 @@ function noteFor(outcome: string, repro: string, tampered: boolean): string { return "This evidence does not pass strict validation, so the deterministic evaluator does not run on it."; } if (outcome === "PASS" && repro === "BOUND_AND_REPRODUCED") { - return "PASS. The deterministic evaluator verified the promise over the recorded evidence, and the sealed report reproduces exactly from it. No model graded this — an unchanged evaluator did."; + return "PASS. The deterministic evaluator verified the promise over the recorded evidence, and the sealed report reproduces exactly from it. No model graded this. An unchanged evaluator did."; } if (outcome === "BROKEN_PROMISE" && repro !== "BOUND_AND_REPRODUCED") { - return "Broken promise. Identifiable activity is present in the OFF evidence, so the same evaluator now fails no_identifiable_activity and raises PP_IDENTIFIABLE_EVENT_LEAK. The report sealed a moment ago no longer reproduces from this evidence — a PASS cannot be silently carried onto changed evidence."; + return "Broken promise. Identifiable activity is present in the OFF evidence, so the same evaluator now fails no_identifiable_activity and raises PP_IDENTIFIABLE_EVENT_LEAK. The report sealed a moment ago no longer reproduces from this evidence. A PASS cannot be silently carried onto changed evidence."; } if (outcome === "BROKEN_PROMISE" && repro === "BOUND_AND_REPRODUCED") { - return "Broken promise, sealed honestly. A new report was sealed for the current evidence and it reproduces — as BROKEN_PROMISE. Sealing binds whatever is true; it cannot manufacture a PASS."; + return "Broken promise, sealed honestly. A new report was sealed for the current evidence and it reproduces, as BROKEN_PROMISE. Sealing binds whatever is true; it cannot manufacture a PASS."; } if (tampered) { return "The evidence changed. Re-evaluate it, and verify the sealed report against it."; @@ -324,8 +324,8 @@ const APP_HTML = `