diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a18f3da..1642fa5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,5 +40,11 @@ jobs: - name: Build production bundle run: npm run build + - name: Install Chromium for browser smoke test + run: npx playwright install --with-deps chromium + + - name: Run browser smoke test + run: npm run test:e2e + - name: Audit production dependencies run: npm audit --omit=dev --audit-level=high diff --git a/.gitignore b/.gitignore index 55f588a..96568a7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ lerna-debug.log* node_modules dist dist-ssr +playwright-report +test-results *.local # Local env files (hold the private deck path; never commit) diff --git a/README.md b/README.md index 83947b6..324bd86 100644 --- a/README.md +++ b/README.md @@ -1,159 +1,197 @@ # SourceDeck [![CI](https://github.com/Xyloth/SourceDeck/actions/workflows/ci.yml/badge.svg)](https://github.com/Xyloth/SourceDeck/actions/workflows/ci.yml) +[![Live demo](https://img.shields.io/badge/live-sourcedeck.vercel.app-f0b45d)](https://sourcedeck.vercel.app) +[![Trust model](https://img.shields.io/badge/trust-explicit-73c7cb)](TRUST_MODEL.md) + +**A local-first evidence command center for high-stakes meetings.** SourceDeck turns +PDFs, Word documents, notes, and record folders into source-linked evidence cards, +issue maps, live retrieval, and exportable packets—while deterministic gates keep +unsupported claims out of the strongest path. + +[![SourceDeck evidence workspace](docs/screenshots/live-evidence.png)](https://sourcedeck.vercel.app) + +**[Open the live worked example](https://sourcedeck.vercel.app)** · +**[Read the explicit trust model](TRUST_MODEL.md)** · +**[Inspect the 63-case adversarial gauntlet](reports/source-gauntlet-report.md)** + +## What This Repository Demonstrates + +- **Document engineering:** real browser-side PDF.js and Mammoth extraction, + page-aware source records, rendered PDF page geometry, and encrypted source-byte + custody. +- **Deterministic trust boundaries:** exact-quote resolution, content addressing, + append-only hash chains, signed packet manifests, redaction hard walls, and + fail-closed packet assembly. +- **Bounded AI architecture:** source text is treated as hostile data, model output + can propose candidates but cannot create verified facts, and privacy mode is a + hard routing ceiling. +- **Adversarial validation:** 90 unit/security tests, a 63-case evidence gauntlet, + and a production-browser critical-path test. +- **Secure local integration:** optional speech and CLI-intelligence sidecars bind + to loopback, reject arbitrary browser origins, and require per-process bearer + capabilities. +- **Shipping discipline:** locked dependencies, zero current npm advisories, + automated lint/test/build/browser/audit CI, a live Vercel deployment, and an + explicit list of what the system does **not** yet guarantee. + +## Product Walkthrough + +SourceDeck is designed for the moment when a meeting moves faster than a folder +tree. The worked example opens with a meeting battle card, lets the user retrieve +the precise supporting record, and blocks packet export when source proof is +insufficient. + +![SourceDeck battle card and meeting posture](docs/screenshots/live-battle-card.png) + +The main workflow supports: + +1. Import records locally and index text, pages, metadata, and custody hashes. +2. Search exact and fuzzy retrieval lanes without merging their confidence levels. +3. Turn findings into evidence cards with quote, source, page, meaning, question, + likely defense, and counter-response. +4. Review source-chain diagnostics and human verification state. +5. Assemble Markdown, HTML, CSV, encrypted workspace, or signed forensic outputs; + packet hard walls fail the complete export when selected claims are unresolved. +6. Enter live meeting mode for rapid quote, question, refusal, commitment, and + action-item capture. + +## System Design + +```mermaid +flowchart LR + A[Local PDF / DOCX / records] --> B[Browser extraction + page geometry] + B --> C[Content-addressed artifact + encrypted source vault] + C --> D[Source graph: document → page → span → evidence] + D --> E{Deterministic verification gate} + F[Bounded model / OCR candidate lanes] --> E + E -->|proof resolves| G[Human signoff + packet factory] + E -->|proof fails| H[Blocked with exact diagnostic] + G --> I[Signed manifest / encrypted workspace / forensic bundle] +``` -SourceDeck is a local-first evidence command center for high-stakes meetings. -It turns PDFs, Word documents, notes, and record folders into searchable -evidence cards with exact quotes, source references, issue maps, meeting -questions, missing-record trackers, and exportable packets. - -Live demo: [https://sourcedeck.vercel.app](https://sourcedeck.vercel.app) - -> The right quote, the right page, the right moment. - -## Why This Exists +The kernel owns factual truth. Intelligence lanes may rank, extract, or suggest, +but no model result becomes verified evidence until its quote and source chain +resolve deterministically. -Important meetings often turn on records: vendor and SLA disputes, legal prep, HR -disputes, medical appeals, insurance reviews, compliance audits, and -investigations. People may know the evidence exists, but still lose leverage -because they cannot find the exact quote, page, or document fast enough. +## Verifiable Engineering Evidence -SourceDeck is built around one principle: +| Control | Current proof | +| --- | --- | +| Unit and contract behavior | `npm test`: 87 Vitest cases + 3 Node sidecar-security cases | +| Adversarial evidence behavior | [`reports/source-gauntlet-report.md`](reports/source-gauntlet-report.md): 63/63 cases pass | +| Browser critical path | `npm run test:e2e`: Chromium navigation, record search, and textless document persistence | +| Production bundle | `npm run build`: TypeScript project build + Vite production bundle | +| Dependency posture | `npm audit`: 0 current vulnerabilities | +| Continuous verification | [GitHub Actions](https://github.com/Xyloth/SourceDeck/actions/workflows/ci.yml) runs lint, tests, build, Chromium smoke, and production audit | +| Deployment | [sourcedeck.vercel.app](https://sourcedeck.vercel.app) | -> Never say "I will find it later." +Run the same evidence locally: -The user can preload records, organize the issues, enter live meeting mode, and -pull up the source-backed quote or question while the conversation is happening. +```powershell +npm ci +npm run lint +npm test +npm run build +npx playwright install chromium +npm run test:e2e +npm run gauntlet:report +npm audit +``` ## Current Capabilities -- Local document vault with DOCX, PDF, text, CSV, JSON, image, and legacy DOC - handling. -- Browser-side DOCX extraction through Mammoth. -- Browser-side PDF text extraction through PDF.js. +- DOCX, PDF, text, CSV, JSON, image, and legacy DOC handling. +- Browser PDF extraction through PDF.js and DOCX extraction through Mammoth. - Local Node case-folder preloader for private folders and legacy `.doc` files. -- Evidence cards with quote, source, exhibit, page, meaning, strategic use, - likely defense, counter-response, tags, priority, and confidence. -- Search across evidence cards, source document text, detected dates/entities, - and missing-record rows. -- Issue maps, contradiction map, timeline, document completeness score, and - source-integrity audit. -- Live meeting mode with critical issue buttons, quote copy, question copy, - refusal logging, commitment logging, action items, transcript companion, and - source-grounded response composer. -- Case templates for vendor/SLA, HR, medical/insurance, legal, - compliance, and audit workflows. -- Agreement guard that flags vague or risky terms and generates cleaner - replacement language. -- Export tools for Markdown packets, printable HTML, CSV quote indexes, exhibit - indexes, missing-record requests, remedy plans, meeting briefs, redacted - packets, and encrypted workspace JSON. -- Local-first privacy posture: sensitive records are processed locally and are - not committed to this repository. -- Verbatim extracted text is session-only and removed before browser - `localStorage` serialization; encrypted workspace export is the durable path. - -## Case Folder Importer - -For private record folders, SourceDeck includes a local importer that builds a -workspace JSON without uploading files to a server. +- Search across evidence, source text, detected dates/entities, and missing records. +- Issue maps, contradiction views, timeline, completeness score, verification queue, + and source-integrity audit. +- Case templates for vendor/SLA, HR, medical/insurance, legal, compliance, and + audit workflows. +- Agreement guard for vague or risky language and cleaner replacement terms. +- Markdown, printable HTML, CSV, exhibit, missing-record, remedy, briefing, + redacted, encrypted-workspace, and forensic-bundle outputs. +- ECDSA P-256 signing-key custody, independently verifiable packet manifests, and + signer-fingerprint pinning. +- Local-first privacy controls: original bytes and rendered page images can be + encrypted in IndexedDB; verbatim extracted text is session-only and removed + before browser `localStorage` serialization. + +## Run Locally + +Requirements: Node.js 24 and npm. ```powershell -npm run case:import -- "C:\Example Case Folder" +npm ci +npm run dev ``` -The importer writes these files into the selected folder: +The public app starts with fictional records and a complete worked example. No +private case material is committed to this repository. -- `sourcedeck-workspace.json` -- `sourcedeck-pressure-test-report.md` +## Private Case Folder Import -The generated workspace can be imported from SourceDeck's export screen. Private -case exports are ignored by git and should not be committed. +The local importer builds a workspace JSON beside the selected folder without +uploading files to a server: -The importer currently extracts: +```powershell +npm run case:import -- "C:\Example Case Folder" +``` -- `.docx` files through Mammoth -- legacy `.doc` files through `word-extractor` -- text-based PDFs through PDF.js -- text-like files such as `.txt`, `.md`, and `.csv` +It extracts `.docx`, legacy `.doc`, text-based `.pdf`, `.txt`, `.md`, and `.csv`. +Image-only PDFs and chart-only documents are marked `Needs OCR`; the importer does +not pretend those records are quote-searchable. -Image-only PDFs, chart-only DOCX files, and scanned records are marked as -`Needs OCR` so the user knows they are not quote-searchable yet. +The generated files are: -## Architecture +- `sourcedeck-workspace.json` +- `sourcedeck-pressure-test-report.md` -- React 19 -- TypeScript -- Vite -- PDF.js for PDF text extraction -- Mammoth for DOCX extraction -- `word-extractor` for local legacy DOC preloading -- Browser localStorage for the current workspace prototype -- Session-only extracted source text plus encrypted source-byte custody in IndexedDB -- Web Crypto PBKDF2/AES-GCM for encrypted workspace export/import -- Vercel deployment +Private case exports are gitignored and should never be committed. ## Local Sidecar Security The optional speech and CLI-intelligence sidecars bind to `127.0.0.1`. Browser operations accept only the shipped SourceDeck origin or loopback development and -Electron origins, then require a per-process bearer capability. There is no -wildcard CORS access. Additional exact origins can be configured through -`SOURCEDECK_ALLOWED_ORIGINS`; see `.env.example`. +Electron origins, then require a per-process capability. Wildcard CORS is not +used. Additional exact origins can be configured through +`SOURCEDECK_ALLOWED_ORIGINS`; see [`.env.example`](.env.example). -These controls prevent an unrelated web page from invoking a local model command +These controls prevent an unrelated webpage from invoking a local model command or reading its output. They are a browser boundary, not an operating-system -sandbox: processes running as the same local user remain in the local trust +sandbox: processes running as the same local user remain inside the local trust boundary. -## Run Locally - -```powershell -npm install -npm run dev -``` - -Build: +## Honest Current Boundaries -```powershell -npm run build -``` +SourceDeck intentionally documents its unfinished edges: -Lint: +- No live frontier-model runtime or OCR worker is wired in yet; those lanes are + typed and gated scaffolding. +- Re-anchoring is primarily lexical, not full semantic/geometric relocation. +- Signer trust is local/manual; there is no third-party key directory. +- There is no collaboration, sync, account system, or multi-tenant backend. +- Derived fields such as evidence-card quotes and meeting notes still use + plaintext browser `localStorage`; use a trusted browser profile and encrypted + export for durable private custody. +- SourceDeck organizes a user's records and does not provide legal advice. -```powershell -npm run lint -``` +See [`TRUST_MODEL.md`](TRUST_MODEL.md) for the guarantee-by-guarantee boundary and +the conditions under which a packet must be treated as unverified. ## Roadmap -- OCR worker for scanned PDFs and image-only DOCX/chart files. -- True highlighted PDF/page export with source-page overlays. -- Human-confirmed page anchors for Word imports, because raw DOCX extraction - does not preserve original page layout. -- Durable encrypted local database instead of browser localStorage. -- Guided case-prep workflow for first-time users. -- AI provider layer for stronger evidence extraction, contradiction detection, - likely defenses, and source-grounded meeting prep. -- Collaboration/export workflow for attorney review, mediation packets, and - post-meeting follow-up packets. - -## Privacy Note - -The sample data in the demo is fictional. Do not commit real contract, -medical, HR, legal, financial, or other private records to a public -repository. SourceDeck's product direction is local-first because the target -documents are often sensitive. - -The current browser prototype still persists derived workspace fields such as -evidence-card quotes and meeting notes in plaintext `localStorage`. Use a trusted -browser profile, reset the workspace after sensitive sessions, and use encrypted -workspace export when durable custody is required. The full boundary is stated -in [TRUST_MODEL.md](TRUST_MODEL.md). +- Real OCR worker with page-image review and human-confirmed anchors. +- Full-workspace encrypted persistence rather than derived-field `localStorage`. +- Semantic and structural re-anchoring with relocation diagnostics. +- Controlled collaboration and independently reviewable trust exchange. +- Production model connectors that remain subordinate to the deterministic + source and privacy gates. ## Product Rule AI can prepare the deck, organize issues, suggest evidence cards, draft clean questions, detect contradictions, and retrieve quotes live. The human remains in -control of what gets used in the meeting, but the AI is not artificially blocked -from doing useful work. +control of what gets used in the meeting, and the deterministic kernel remains in +control of what can be called verified. diff --git a/docs/screenshots/live-battle-card.png b/docs/screenshots/live-battle-card.png new file mode 100644 index 0000000..1e287f3 Binary files /dev/null and b/docs/screenshots/live-battle-card.png differ diff --git a/docs/screenshots/live-evidence.png b/docs/screenshots/live-evidence.png new file mode 100644 index 0000000..d831104 Binary files /dev/null and b/docs/screenshots/live-evidence.png differ diff --git a/e2e/critical-path.e2e.ts b/e2e/critical-path.e2e.ts new file mode 100644 index 0000000..025b10e --- /dev/null +++ b/e2e/critical-path.e2e.ts @@ -0,0 +1,61 @@ +import { expect, test } from "@playwright/test"; + +test("worked example supports source search and textless browser persistence", async ({ page }) => { + const consoleErrors: string[] = []; + page.on("console", (message) => { + if (message.type() === "error") consoleErrors.push(message.text()); + }); + + await page.goto("/"); + + await expect( + page.getByRole("heading", { + name: "The right quote, page, and question at the right moment.", + }), + ).toBeVisible(); + await expect(page.getByRole("navigation", { name: "Primary" })).toBeVisible(); + + await page.getByRole("button", { name: "Evidence", exact: true }).click(); + await expect(page.getByRole("heading", { name: "Evidence cards" })).toBeVisible(); + await expect( + page.getByRole("heading", { + name: "Written admission: contracted work not delivered", + }).first(), + ).toBeVisible(); + + await page + .getByPlaceholder(/Search records or commands/i) + .fill("contracted reporting work"); + await page.getByRole("button", { name: "Search records" }).click(); + await expect(page.getByRole("heading", { name: "Record search" })).toBeVisible(); + await expect(page.getByText("Exact lane", { exact: true }).first()).toBeVisible(); + + const privateMarker = "E2E_PRIVATE_SOURCE_TEXT_MUST_NOT_PERSIST"; + await page.evaluate((marker) => { + window.localStorage.setItem( + "sourcedeck.documents", + JSON.stringify([ + { + id: "privacy-smoke-document", + title: "Privacy smoke document", + type: "TXT", + date: "2026-08-31", + author: "Test fixture", + pages: 1, + exhibit: "Test", + tags: [], + status: "Indexed", + extractedText: marker, + pageTexts: [{ page: 1, text: marker }], + }, + ]), + ); + }, privateMarker); + await page.reload(); + await expect(page.getByText("SourceDeck", { exact: true })).toBeVisible(); + const persistedDocuments = await page.evaluate(() => + window.localStorage.getItem("sourcedeck.documents"), + ); + expect(persistedDocuments).not.toContain(privateMarker); + expect(consoleErrors).toEqual([]); +}); diff --git a/package-lock.json b/package-lock.json index 7b5efea..6a5730c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@playwright/test": "^1.62.1", "@types/node": "^24.12.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", @@ -1280,6 +1281,22 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@playwright/test": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.62.1.tgz", + "integrity": "sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@rolldown/binding-android-arm-eabi": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", @@ -3529,6 +3546,53 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/playwright": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.62.1.tgz", + "integrity": "sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.62.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/postcss": { "version": "8.5.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", diff --git a/package.json b/package.json index 8e719e9..b55a74e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "speech:sidecar": "node scripts/speech-transcription-sidecar.mjs", "lint": "eslint .", "preview": "vite preview", - "test": "vitest run && node --test scripts/*.node-test.mjs" + "test": "vitest run && node --test scripts/*.node-test.mjs", + "test:e2e": "playwright test" }, "dependencies": { "clsx": "^2.1.1", @@ -35,6 +36,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@playwright/test": "^1.62.1", "@types/node": "^24.12.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..ee26ce7 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,27 @@ +import { defineConfig, devices } from "@playwright/test"; + +export default defineConfig({ + testDir: "./e2e", + testMatch: "**/*.e2e.ts", + fullyParallel: true, + forbidOnly: Boolean(process.env.CI), + retries: process.env.CI ? 1 : 0, + reporter: process.env.CI ? "github" : "list", + use: { + baseURL: "http://127.0.0.1:4173", + screenshot: "only-on-failure", + trace: "retain-on-failure", + }, + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + ], + webServer: { + command: "npm run preview -- --host 127.0.0.1 --port 4173", + url: "http://127.0.0.1:4173", + reuseExistingServer: !process.env.CI, + timeout: 30_000, + }, +}); diff --git a/reports/source-gauntlet-custody-bundle.json b/reports/source-gauntlet-custody-bundle.json index b7da871..6ab1d8e 100644 --- a/reports/source-gauntlet-custody-bundle.json +++ b/reports/source-gauntlet-custody-bundle.json @@ -1,6 +1,6 @@ { "format": "sourcedeck.sourcestack-bundle.v1", - "generatedAt": "2026-06-17T00:13:10.793Z", + "generatedAt": "2026-08-31T14:25:01.015Z", "caseName": "SourceStack custody gauntlet fixture", "graph": { "documents": { @@ -370,7 +370,7 @@ "format": "sourcedeck.packet-manifest.v1", "packetId": "bundle-packet:sha256:515aa201f31ae352f459815e18199182469c635c581a58c5ca00f1dfb4ea25f1", "packetType": "forensic_bundle", - "packetHash": "sha256:fe09f349df1a8052653aa3a449389b5fa9d8f3aa461eb30c0592a1599837de5e", + "packetHash": "sha256:5520d0a72f3ccf197d4349b8b2bc6dece99988b84c170d1730170f2674d48faf", "sourceDocumentHashes": [ { "documentId": "doc_a", @@ -399,9 +399,9 @@ } ], "redactionOperations": [], - "exportTimestamp": "2026-06-17T00:13:10.793Z", + "exportTimestamp": "2026-08-31T14:25:01.015Z", "issuerIdentity": "SourceStack custody gauntlet fixture", - "manifestHash": "sha256:39744c95e72eba7503ea683942a0567b26d32fc3119f6d75d0c2c683e118a818" + "manifestHash": "sha256:89168367795573e6043990bdcdfc2d28e529cab608c9a2169a29d2cab9fa5995" } ], "caseStore": { @@ -472,7 +472,7 @@ "packetManifestVerifications": [ { "ok": true, - "manifestHash": "sha256:39744c95e72eba7503ea683942a0567b26d32fc3119f6d75d0c2c683e118a818" + "manifestHash": "sha256:89168367795573e6043990bdcdfc2d28e529cab608c9a2169a29d2cab9fa5995" } ], "packetManifestSignatureVerifications": [ @@ -622,5 +622,5 @@ ], "bitemporalContradictions": [], "graphHash": "sha256:a8b071810463ca882b80801a2bc36b710ed9e6850144e6f4d0f45f8aaacd8644", - "bundleHash": "sha256:8b51ca6527d141cbf076ce3072fdbabd53372d09b21845515fba756977167c38" + "bundleHash": "sha256:4fadaf6bb3c638217ea2c19b87f1873e0917bca512546e303de251156c651b57" } \ No newline at end of file diff --git a/reports/source-gauntlet-report.hashes.json b/reports/source-gauntlet-report.hashes.json index 07260e3..a2881a6 100644 --- a/reports/source-gauntlet-report.hashes.json +++ b/reports/source-gauntlet-report.hashes.json @@ -1,6 +1,6 @@ { - "markdownBodyHash": "sha256:31136b53d7cdfd42fed7402d78d9fe9fba2b20c58f53565372c1800c8b65bed9", - "jsonReportHash": "sha256:0f71da449427c56bb0df40518cff8c96114eaab60130d763deac1772d72e3056", - "custodyBundleHash": "sha256:8b51ca6527d141cbf076ce3072fdbabd53372d09b21845515fba756977167c38", - "custodyBundleFileHash": "sha256:08aa178ba5c5e6c748b769e1800e453267ce63d90c2ec88b4123032d251929ff" + "markdownBodyHash": "sha256:6e17873ad517556ea4d6ac75a61f228dc51201ba7d6bb16a606307bbe0c57568", + "jsonReportHash": "sha256:9ed7e0dd5726ae1120a51614d15e38fd73eeb383bedbc1ccbd5e0d352ad214e5", + "custodyBundleHash": "sha256:4fadaf6bb3c638217ea2c19b87f1873e0917bca512546e303de251156c651b57", + "custodyBundleFileHash": "sha256:4635985c640ab367c869f021eaea9c7931840c62cd523f32504a25080ef5c8aa" } \ No newline at end of file diff --git a/reports/source-gauntlet-report.json b/reports/source-gauntlet-report.json index 83326a6..b9a709a 100644 --- a/reports/source-gauntlet-report.json +++ b/reports/source-gauntlet-report.json @@ -1,5 +1,5 @@ { - "generatedAt": "2026-06-17T00:13:10.790Z", + "generatedAt": "2026-08-31T14:25:01.012Z", "passed": true, "results": [ { @@ -54,19 +54,19 @@ "id": "cryptographic_manifest_signature", "category": "packet_integrity", "passed": true, - "detail": "signature verified for sha256:e6130bdc736410b5312d61389f14f51b9cfb5608fd4444bd23222cab7503d363; malformed/timestamp attacks blocked" + "detail": "signature verified for sha256:def64004b1575cdcfb60c13ad3967915fb12f16f0c356a3e68e79da1d1285447; malformed/timestamp attacks blocked" }, { "id": "packet_signer_trust_registry", "category": "packet_integrity", "passed": true, - "detail": "trusted signer accepted (13B4 EF7E 0024...); unknown signer pinned out" + "detail": "trusted signer accepted (B4F3 E2BC 9CB0...); unknown signer pinned out" }, { "id": "encrypted_signing_key_custody", "category": "packet_integrity", "passed": true, - "detail": "wrapped custody verified for sha256:4be10d1b0ded574bdbc6b3883c6cd79aa9e1827509b6106218aa6562a0359ba1; custody hash signed and tamper blocked" + "detail": "wrapped custody verified for sha256:6785a3e0eb52491a567a5686afe3f5a77ba1ebc60f5a8cafc9466a517a08d717; custody hash signed and tamper blocked" }, { "id": "kdf_iteration_bounds", @@ -216,7 +216,7 @@ "id": "sourcestack_forensic_bundle_tamper", "category": "source_integrity", "passed": true, - "detail": "bundle verified sha256:726ddc503241d323f22ef88e099eb86cf05e4c2f0c5955f18e93f7327553adf0; 1 invariant failure(s); 1 packet manifest(s); signed embedded manifest verified" + "detail": "bundle verified sha256:b3da07af12f8624aa02c4bd338088cffbfd8ee9a8f5f274e021cc46778bba81d; 1 invariant failure(s); 1 packet manifest(s); signed embedded manifest verified" }, { "id": "forensic_bundle_includes_artifact_and_ledger", diff --git a/reports/source-gauntlet-report.md b/reports/source-gauntlet-report.md index 51477a7..22c8377 100644 --- a/reports/source-gauntlet-report.md +++ b/reports/source-gauntlet-report.md @@ -1,6 +1,6 @@ # SourceStack Evidence Gauntlet Report -Generated: 2026-06-17T00:13:10.790Z +Generated: 2026-08-31T14:25:01.012Z Overall: PASS Cases: 63 Failures: 0 @@ -25,9 +25,9 @@ Failures: 0 | unverified_export_attempt | packet_integrity | PASS | cited card blocked | | duplicate_card_packet_attempt | packet_integrity | PASS | packet hard wall: selected card is duplicated | | hash_manifest_verification | packet_integrity | PASS | manifest verified against source graph; page drift page hashes mismatch | -| cryptographic_manifest_signature | packet_integrity | PASS | signature verified for sha256:e6130bdc736410b5312d61389f14f51b9cfb5608fd4444bd23222cab7503d363; malformed/timestamp attacks blocked | -| packet_signer_trust_registry | packet_integrity | PASS | trusted signer accepted (13B4 EF7E 0024...); unknown signer pinned out | -| encrypted_signing_key_custody | packet_integrity | PASS | wrapped custody verified for sha256:4be10d1b0ded574bdbc6b3883c6cd79aa9e1827509b6106218aa6562a0359ba1; custody hash signed and tamper blocked | +| cryptographic_manifest_signature | packet_integrity | PASS | signature verified for sha256:def64004b1575cdcfb60c13ad3967915fb12f16f0c356a3e68e79da1d1285447; malformed/timestamp attacks blocked | +| packet_signer_trust_registry | packet_integrity | PASS | trusted signer accepted (B4F3 E2BC 9CB0...); unknown signer pinned out | +| encrypted_signing_key_custody | packet_integrity | PASS | wrapped custody verified for sha256:6785a3e0eb52491a567a5686afe3f5a77ba1ebc60f5a8cafc9466a517a08d717; custody hash signed and tamper blocked | | kdf_iteration_bounds | privacy_redaction | PASS | floor enforced, ceiling enforced | | encrypted_signing_key_recoverable | packet_integrity | PASS | custody confirms key is recoverable; wrong passphrase rejected | | legacy_bridge_no_self_anchor | source_integrity | PASS | fabricated legacy quote downgraded and blocked | @@ -52,7 +52,7 @@ Failures: 0 | duplicate_records | source_integrity | PASS | 1 duplicate content hash bucket(s) found | | bitemporal_contradiction_detection | graph_logic | PASS | 1 source-span-classified contradiction(s) detected | | claim_issue_theory_source_chain_gate | graph_logic | PASS | packet-ready claim repeats supporting card card_verified; ready issue theory strongest path failed: packet hard wall: card is cited, not verified; ready issue theory references suggested claim claim_suggested_ready; ready issue theory support failed: packet hard wall: card is cited, not verified; ready issue theory repeats claim claim_duplicate_support; ready issue theory repeats strongest-path card card_verified; ready issue theory strongest path references missing card card_missing | -| sourcestack_forensic_bundle_tamper | source_integrity | PASS | bundle verified sha256:726ddc503241d323f22ef88e099eb86cf05e4c2f0c5955f18e93f7327553adf0; 1 invariant failure(s); 1 packet manifest(s); signed embedded manifest verified | +| sourcestack_forensic_bundle_tamper | source_integrity | PASS | bundle verified sha256:b3da07af12f8624aa02c4bd338088cffbfd8ee9a8f5f274e021cc46778bba81d; 1 invariant failure(s); 1 packet manifest(s); signed embedded manifest verified | | forensic_bundle_includes_artifact_and_ledger | source_integrity | PASS | 1 artifact(s), 3 trust event(s), 1 case artifact(s), 1 packet manifest(s), signed ledger head present, forged verification blocked, detached graph blocked, missing artifact blocked | | source_artifact_case_store_custody | source_integrity | PASS | case artifact artifact:sha256:c37117c86a5bb78f32d2e2dc2dacc2c94443751cb0ff187a1835269b6fbdf28c verified, alias blocked: artifact store key mismatch/artifact id content hash mismatch, tamper blocked: artifact byte length mismatch | | durable_artifact_payload_tamper | source_integrity | PASS | artifact byte length mismatch | @@ -83,5 +83,5 @@ Failures: 0 ## Report Hashes -- Markdown body: sha256:31136b53d7cdfd42fed7402d78d9fe9fba2b20c58f53565372c1800c8b65bed9 -- JSON report: sha256:0f71da449427c56bb0df40518cff8c96114eaab60130d763deac1772d72e3056 +- Markdown body: sha256:6e17873ad517556ea4d6ac75a61f228dc51201ba7d6bb16a606307bbe0c57568 +- JSON report: sha256:9ed7e0dd5726ae1120a51614d15e38fd73eeb383bedbc1ccbd5e0d352ad214e5