# Project export: RedressCI

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: RedressCI is the remediation platform that turns reported AI failures into privacy-safe, evidence-backed regression tests, verifies fixes, and prevents them from returning in production.
- Devpost: https://devpost.com/software/redressci
- GitHub: https://github.com/ankitlade12/redressci
- Demo: https://redressci.onrender.com/
- Video: https://player.vimeo.com/video/1211845089?byline=0&portrait=0&title=0#t=
- Team: 1 GitHub contributor(s) — ankitlade12 (35 commits)

## Devpost submission (written by the team)

### Inspiration

When an AI system gives someone an unsafe, inaccessible, or misleading answer, the experience usually becomes a support ticket, screenshot, or incident report. The affected person rarely learns whether the problem was reproduced, whether it was fixed, or whether the same failure can happen again. Traditional incident databases preserve what happened. Evaluation platforms help engineering teams test datasets they already own. RedressCI connects the missing middle: it turns an affected person’s experience into a privacy-safe, evidence-backed regression test, proves that the test catches the failure, and carries that protection into CI. Our goal is simple: one person’s experience should protect the next person.

### What it does

RedressCI is an AI remediation and continuous-assurance platform. It guides a reported failure through four stages: Report the failure A reporter submits an interaction using text, private evidence, or browser voice dictation. The original evidence starts private and remains separate from anything developers can access. Report the failure A reporter submits an interaction using text, private evidence, or browser voice dictation. The original evidence starts private and remains separate from anything developers can access. Review the evidence RedressCI proposes a redacted case, structures the incident, identifies unanswered questions, and helps discover relevant evidence. Human reviewers approve privacy, evidence, expected behavior, and consent. Review the evidence RedressCI proposes a redacted case, structures the incident, identifies unanswered questions, and helps discover relevant evidence. Human reviewers approve privacy, evidence, expected behavior, and consent. Prove the fix The approved case compiles into a portable regression test containing deterministic checks and GPT-5.6 semantic grading. RedressCI requires comparative proof: the known-broken response must fail and the corrected response must pass. Prove the fix The approved case compiles into a portable regression test containing deterministic checks and GPT-5.6 semantic grading. RedressCI requires comparative proof: the known-broken response must fail and the corrected response must pass. Prevent regression Developers can export the privacy-safe evaluation into GitHub Actions or another CI system. If the harmful behavior returns after a model, prompt, retrieval, or application change, the runner exits non-zero and can block the release. Prevent regression Developers can export the privacy-safe evaluation into GitHub Actions or another CI system. If the harmful behavior returns after a model, prompt, retrieval, or application change, the runner exits non-zero and can block the release. RedressCI carefully distinguishes two levels of proof: Evaluation verified means the test successfully distinguishes reviewer-approved recorded broken and corrected responses. Verified fixed requires running that evaluation against a configured live deployment and producing a separate signed deployment proof. Reporters receive a private status link, a remediation timeline, consent controls, and a tamper-evident Redress Receipt describing exactly what was proven.

### How we built it

RedressCI is built as a full-stack TypeScript application with a React and Vite interface, an Express API, portable evaluation files, and a standalone CI runner. GPT-5.6 is used for tasks where semantic understanding adds real value: extracting interactions from text and screenshots using strict structured outputs; transforming an unstructured experience into a reviewable incident; surfacing uncertainty and unanswered questions; discovering evidence candidates from privacy-approved content; and grading semantic requirements that cannot be evaluated reliably with keyword matching alone. Deterministic assertions remain local and deterministic. GPT-5.6 can propose and grade, but it cannot approve privacy, consent, evidence, expected behavior, or verified status. We used Codex throughout development to inspect and evolve the architecture, implement the reporter-to-CI workflow, build the privacy and evaluation gates, create regression tests, diagnose product issues, and prepare the application for deployment. The platform also includes: role-enforced privacy boundaries; encrypted private artifact storage; evidence-to-assertion provenance; immutable grader-policy hashes; signed receipts and proof bundles; allowlisted deployed-system adapters; privacy-safe aggregate failure detection; reporter consent withdrawal; GitHub Actions workflow generation; and a resettable synthetic demonstration workspace. The application is containerized with Docker, deployed on Render, and continuously tested through GitHub Actions.

### Challenges we ran into

The hardest challenge was making every product claim truthful. A recorded corrected response is not proof that a deployed system is fixed. We created separate states and proof artifacts for evaluation verification and live deployment verification so the interface never overstates what was tested. Privacy was another architectural challenge. A developer needs enough information to reproduce a failure without automatically gaining access to the reporter’s identity, original transcript, or private artifacts. We enforce this separation on the server rather than treating redaction as a visual-only feature. We also needed to prevent generated evaluations from encoding unsupported expectations. Every assertion must cite reviewer-approved evidence, and changing that evidence invalidates dependent evaluations and returns them to review. Finally, model-based grading introduces uncertainty. We combine deterministic assertions with GPT-5.6 semantic grading, preserve a shared immutable grader-policy identifier, support inconclusive outcomes, and require the same evaluation to run against both broken and corrected responses.

### Accomplishments we're proud of

We are proud that RedressCI is a working remediation loop rather than a collection of disconnected AI features. The hosted product demonstrates: private failure reporting; human-approved redaction and evidence; portable evaluation compilation; broken-versus-corrected comparative proof; live deployed-target verification; signed receipts and proof bundles; private reporter follow-up; GitHub CI protection; and privacy-safe trend analysis. The application currently passes 37 automated tests covering privacy gates, role boundaries, evidence provenance, compiler behavior, comparative validation, proof integrity, reporter links, deployed verification, routing, voice-input behavior, and CI exports. Most importantly, the affected person remains connected to the engineering outcome instead of disappearing after submitting a report.

### What we learned

We learned that the difficult part of responsible AI evaluation is not simply generating more test cases. It is establishing why an expected behavior is legitimate, protecting the person who reported the failure, proving that the evaluation detects the intended problem, and communicating closure without exaggeration. We also learned that AI works best here as a bounded collaborator. GPT-5.6 accelerates extraction, structuring, discovery, and semantic evaluation, while explicit human approval protects the decisions that require authority and accountability. Portable evaluations are also essential. RedressCI becomes more useful when it complements existing engineering systems instead of requiring organizations to replace their current observability, evaluation, or CI platforms.

### What's next

The next milestone is a design-partner pilot with organizations operating public-interest or high-impact AI systems. We plan to add: managed organizational identity and reviewer assignment; PostgreSQL-backed production persistence; regional object storage and managed encryption; expanded GitHub, GitLab, Jira, Linear, Slack, and Teams workflows; multilingual reporting and accessibility validation; notification delivery and remediation service-level objectives; governed community evaluation packs; and independent verification by domain and accessibility experts. RedressCI’s long-term vision is a remediation network where reported AI failures become durable, evidence-backed protections that can travel across products, organizations, and releases.

## README (from the GitHub repository)

# RedressCI — From AI Failure to Verified Fix

[![Node.js 22+](https://img.shields.io/badge/Node.js-22+-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178C6.svg?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
[![OpenAI](https://img.shields.io/badge/OpenAI-GPT--5.6-111111.svg?logo=openai&logoColor=white)](https://developers.openai.com/api/docs/models/gpt-5.6-sol)
[![Render](https://img.shields.io/badge/Render-live-46E3B7.svg?logo=render&logoColor=111111)](https://redressci.onrender.com)
[![CI](https://github.com/ankitlade12/redressci/actions/workflows/redressci.yml/badge.svg)](https://github.com/ankitlade12/redressci/actions/workflows/redressci.yml)
[![Tests](https://img.shields.io/badge/tests-37%20passing-brightgreen.svg)](#reproducible-testing)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

> **A closed ticket says someone tried. RedressCI proves the fix and keeps testing it.**

RedressCI is an AI remediation and continuous-assurance platform. It turns a reported AI failure into a privacy-safe, evidence-backed regression test, proves that the test catches the broken behavior, recognizes the correction, and carries that protection into CI.

The product begins with the person who experienced the failure—not with a dataset an engineering team already owns. Reporters retain a visible path to closure while reviewers and developers receive only the evidence and artifacts appropriate to their roles.

**OpenAI Build Week track:** Developer Tools<br>
**Demo data:** entirely fictional and synthetic<br>
**Hosted product:** <https://redressci.onrender.com>

## Quick Highlights

- **Reporter-to-CI Remediation** — one governed path from a real-world experience to permanent regression protection
- **Privacy Before Engineering Access** — original evidence remains separate until a human approves the redacted case
- **Evidence-Backed Assertions** — every compiled check cites an approved source; changed evidence invalidates dependents
- **Comparative Proof** — the same evaluation must fail on the known-broken response and pass on the correction
- **Truthful Verification States** — recorded-response proof and deployed-system verification are labeled separately
- **Visible Reporter Closure** — private status links, consent withdrawal, timelines, signed receipts, and deployment proof
- **GPT-5.6 With Boundaries** — AI extracts, structures, discovers, and grades; humans approve truth and authority
- **CI-Native Protection** — portable JSON evaluations, a standalone runner, GitHub Actions, and optional Checks API output
- **Measured Evaluation Quality** — mutation detection, calibration, repeat stability, scope guarding, and inconclusive outcomes
- **Privacy-Safe Network Learning** — recurring mechanisms surface only after minimum-group privacy thresholds are met

## Live Deployment

| Surface | URL | Access |
|---|---|---|
| **Product** | <https://redressci.onrender.com> | Public synthetic judge workspace |
| **Health check** | <https://redressci.onrender.com/api/health> | Public JSON status |
| **Reporter status** | `/status/:token` | Expiring and revocable private link |
| **Portable runner** | [`runner/cli.ts`](runner/cli.ts) | Local or CI execution |
| **GitHub workflow** | [`.github/workflows/redressci.yml`](.github/workflows/redressci.yml) | Repository CI |

The hosted workspace is intentionally resettable and credential-free for judging. GPT-5.6 is configured on the server, while deterministic fixtures keep the primary demo reliable. The public deployment is a synthetic demonstration—not a destination for sensitive reports.

## Architecture Overview

### The Remediation Loop

```mermaid
flowchart LR
    R[Report the failure] --> P[Privacy review]
    P --> E[Approved evidence]
    E --> C[Compile portable evaluation]
    C --> G{Comparative gate}
    G -->|Broken must fail| B[Known-broken proof]
    G -->|Correction must pass| F[Corrected proof]
    B --> V[Evaluation verified]
    F --> V
    V --> X[Receipt and CI export]
    X --> D[Deployed target run]
    D -->|Passes reviewed evaluation| L[Verified fixed]
    L --> N[Reporter closure and recurrence monitoring]
```

### System Architecture

```mermaid
graph TB
    subgraph "PRODUCT EXPERIENCE"
        REPORT[Reporter intake and private evidence]
        REVIEW[Privacy and evidence review]
        CASE[Case, validation, timeline, and CI views]
        STATUS[Private reporter status]
        RADAR[Privacy-safe failure radar]
    end

    subgraph "APPLICATION LAYER"
        UI[React + TypeScript client]
        API[Express API]
        COMPILER[Evidence-linked compiler]
        GRADER[Deterministic + semantic grader]
        ASSURANCE[Assurance and governance engine]
        EXPORT[Runner, SDK, proofs, and exports]
    end

    subgraph "TRUST BOUNDARY"
        GPT[GPT-5.6 Responses API]
        HUMAN[Human approval gates]
        AUTH[Signed roles and ownership checks]
        CRYPTO[AES-GCM storage + Ed25519 proof signing]
    end

    subgraph "DATA AND DELIVERY"
        STATE[(Case and platform state)]
        PRIVATE[(Encrypted private artifacts)]
        EVAL[(Portable evaluation JSON)]
        CI[GitHub Actions / external CI]
        TARGET[Allowlisted deployed target]
    end

    REPORT --> UI
    REVIEW --> UI
    CASE --> UI
    STATUS --> API
    RADAR --> API
    UI --> API
    API --> AUTH
    API --> HUMAN
    API --> GPT
    API --> COMPILER
    COMPILER --> GRADER
    GRADER --> ASSURANCE
    API --> STATE
    API --> CRYPTO
    CRYPTO --> PRIVATE
    COMPILER --> EVAL
    EVAL --> EXPORT
    EXPORT --> CI
    API --> TARGET

    style HUMAN fill:#e4f0e8,stroke:#146b48,stroke-width:2px
    style GPT fill:#eef0ff,stroke:#4e5ba6,stroke-width:2px
    style PRIVATE fill:#f7e9e5,stroke:#a94336,stroke-width:2px
    style EVAL fill:#f4f8dc,stroke:#72851f,stroke-width:2px
```

### Hosted Runtime

```mermaid
graph LR
    GH[GitHub main] --> BUILD[Render Docker build]
    BUILD --> SERVICE[RedressCI web service]
    SERVICE --> WEB[React application]
    SERVICE --> API[Express API]
    SERVICE --> HEALTH[GET /api/health]
    SERVICE --> OPENAI[GPT-5.6 Responses API]
    SERVICE --> STORE[(Encrypted local demo state)]
```

The central design rule is enforced in code: **GPT-5.6 may propose and grade, but only reviewed evidence, human approval, and successful execution can establish verified status.**

### Tech Stack

| Layer | Technology | Purpose |
|---|---|---|
| **Interface** | React + Vite | Reporter, reviewer, developer, verifier, and status-link experiences |
| **Language** | TypeScript in strict mode | Shared contracts across product, API, runner, and SDK |
| **API** | Node.js 22 + Express | Workflow enforcement, role boundaries, artifacts, and exports |
| **Model layer** | OpenAI GPT-5.6 Responses API | Extraction, incident structuring, evidence discovery, and semantic grading |
| **Deterministic evaluation** | Custom compiler and grader | Evidence-linked rules, comparative gate, and portable results |
| **Private storage** | AES-256-GCM artifact boundary | Encryption of reporter-supplied private evidence |
| **Proof** | Ed25519 signatures + SHA-256 | Receipts, deployment proof, proof bundles, and tamper detection |
| **CI** | Standalone TypeScript runner + GitHub Actions | Release regression protection and machine-readable results |
| **Deployment** | Docker + Render | Hosted judge build and health checks |
| **Production foundation** | PostgreSQL migration + vendor-neutral SDK | Design-partner persistence and interoperability path |

## The Problem

An AI failure usually becomes a support ticket, screenshot, or incident entry. Even when a team closes the ticket, three questions remain unanswered:

- Was the harmful behavior reproduced for the intended reason?
- Did the correction actually satisfy an evidence-backed expectation?
- Will the same failure be caught after

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 41 recognized source files, 360 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- HTML (language) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- SQL (language) — detected in the code
- TypeScript (language) — detected in the code
- Docker (technology) — claimed on Devpost, not found in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (52 of 52)

```
.env.example
.github/workflows/redressci.yml
.gitignore
data/encrypted/.gitkeep
data/originals/.gitkeep
data/state/.gitkeep
db/migrations/001_all_phases.sql
Dockerfile
evals/cooling-center-accessibility-001.json
fixtures/facilities.json
index.html
LICENSE
package.json
README.md
render.yaml
runner/cli.ts
runner/evaluation.test.ts
scripts/issue-token.ts
sdk/index.ts
server/ai.ts
server/api.test.ts
server/auth.ts
server/compiler.test.ts
server/compiler.ts
server/evaluation.ts
server/fixtures.ts
server/index.ts
server/platform.test.ts
server/platform.ts
server/privacy.test.ts
server/privacy.ts
server/receipt.ts
server/secure-storage.ts
server/store.ts
server/workflow.test.ts
src/api.ts
src/App.tsx
src/case-state.test.ts
src/case-state.ts
src/icons.tsx
src/main.tsx
src/platform-types.ts
src/product-features.tsx
src/routing.test.ts
src/routing.ts
src/styles.css
src/types.ts
src/vite-env.d.ts
src/voice-input.test.ts
src/voice-input.ts
tsconfig.json
vite.config.ts
```

### Dependencies

- package.json: @types/express@latest, @types/multer@latest, @types/node@latest, @types/react@latest, @types/react-dom@latest, @vitejs/plugin-react@latest, concurrently@latest, dotenv@^17.4.2, express@latest, multer@latest, openai@latest, react@latest, react-dom@latest, tsx@latest, typescript@latest, vite@latest

### Recent commits (newest first)

- Remove repository agent metadata
- Merge pull request #26 from ankitlade12/agent/remove-feature-spec
- Remove internal feature specification
- Merge pull request #25 from ankitlade12/agent/public-docs-cleanup
- Remove internal planning documents
- Merge pull request #24 from ankitlade12/agent/repository-cleanup
- Fix npm 10 lockfile compatibility
- Rewrite README as product and engineering guide
- Remove stale repository artifacts
- Merge pull request #23 from ankitlade12/agent/guided-judge-demo
- Guide judges through the remediation flow
- Merge pull request #22 from ankitlade12/agent/fix-voice-dictation
- Fix browser voice dictation
- Merge pull request #21 from ankitlade12/agent/live-remediation-features
- Add live remediation product features
- Merge pull request #20 from ankitlade12/agent/fix-case-presentation
- Fix case title and impact copy
- Merge pull request #7 from ankitlade12/agent/fix-grader-provenance
- Fix comparative grader provenance
- Make recorded verification truthful

## Key source files (fetched from GitHub, selected and truncated for size)

### Dockerfile

```
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci
COPY --from=build /app/dist ./dist
COPY --from=build /app/server ./server
COPY --from=build /app/src ./src
COPY --from=build /app/evals ./evals
COPY --from=build /app/fixtures ./fixtures
COPY --from=build /app/runner ./runner
COPY --from=build /app/scripts ./scripts
COPY --from=build /app/sdk ./sdk
EXPOSE 8787
CMD ["npm", "start"]

```

### package.json

```
{
  "name": "redressci",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "description": "Turn real AI failures into tests that stay fixed.",
  "packageManager": "npm@10.9.8",
  "scripts": {
    "dev": "concurrently -k -n api,web -c cyan,green \"node --watch --import tsx server/index.ts\" \"vite\"",
    "build": "tsc --noEmit && vite build",
    "start": "node --import tsx server/index.ts --production",
    "auth:token": "node --import tsx scripts/issue-token.ts",
    "test": "node --import tsx --test server/api.test.ts server/compiler.test.ts server/platform.test.ts server/privacy.test.ts server/workflow.test.ts runner/evaluation.test.ts src/case-state.test.ts src/routing.test.ts src/voice-input.test.ts",
    "test:ci": "node --import tsx runner/cli.ts evals/cooling-center-accessibility-001.json --target fixed",
    "lint": "tsc --noEmit"
  },
  "dependencies": {
    "@vitejs/plugin-react": "latest",
    "concurrently": "latest",
    "dotenv": "^17.4.2",
    "express": "latest",
    "multer": "latest",
    "openai": "latest",
    "react": "latest",
    "react-dom": "latest",
    "vite": "latest"
  },
  "devDependencies": {
    "@types/express": "latest",
    "@types/multer": "latest",
    "@types/node": "latest",
    "@types/react": "latest",
    "@types/react-dom": "latest",
    "tsx": "latest",
    "typescript": "latest"
  },
  "engines": {
    "node": ">=22"
  }
}

```

### src/main.tsx

```typescript
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./styles.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

```

### runner/cli.ts

```typescript
#!/usr/bin/env node
import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
import path from "node:path";
import type { EvaluationCase } from "../src/types.js";
import { runEvaluation } from "../server/evaluation.js";

function usage() {
  console.error("Usage: tsx runner/cli.ts <evaluation.json> --target <broken|fixed> [--response <text>]");
  process.exit(2);
}

const args = process.argv.slice(2);
if (!args[0]) usage();
const targetIndex = args.indexOf("--target");
const target = args[targetIndex + 1];
if (target !== "broken" && target !== "fixed") usage();
const selectedTarget = target as "broken" | "fixed";
const responseIndex = args.indexOf("--response");
const targetResponse = responseIndex >= 0 ? args[responseIndex + 1] : undefined;
const file = path.resolve(args[0]);
const evaluation = JSON.parse(readFileSync(file, "utf8")) as EvaluationCase;
const result = runEvaluation(evaluation, selectedTarget, targetResponse);

mkdirSync(path.resolve("results"), { recursive: true });
const output = path.resolve("results", `${evaluation.id}-${selectedTarget}.json`);
writeFileSync(output, JSON.stringify(result, null, 2));

const symbol = result.state === "pass" ? "✓" : result.state === "fail" ? "✗" : "?";
console.log(`${symbol} ${evaluation.title}: ${result.state.toUpperCase()} (${Math.round(result.score * 100)}%)`);
for (const assertion of result.assertionResults) console.log(`  ${assertion.state === "pass" ? "✓" : assertion.state === "fail" ? "✗" : "?"} ${assertion.label} — ${assertion.explanation}`);
console.log(`Machine-readable result: ${output}`);
process.exitCode = result.state === "pass" ? 0 : 1;

```

### sdk/index.ts

```typescript
import type { PlatformDashboard, SignedProofBundle } from "../src/platform-types.js";
import type { RedressCase } from "../src/types.js";

export interface RedressCIOptions {
  baseUrl: string;
  token?: string;
}

export class RedressCIClient {
  constructor(private readonly options: RedressCIOptions) {}

  private async request<T>(path: string, init?: RequestInit): Promise<T> {
    const response = await fetch(new URL(path, this.options.baseUrl), {
      ...init,
      headers: { "Content-Type": "application/json", ...(this.options.token ? { Authorization: `Bearer ${this.options.token}` } : {}), ...init?.headers },
    });
    const payload = await response.json();
    if (!response.ok) throw new Error(payload.error || `RedressCI request failed with ${response.status}.`);
    return payload as T;
  }

  dashboard() { return this.request<{ platform: PlatformDashboard }>("/api/platform"); }
  case(id: string) { return this.request<{ case: RedressCase }>(`/api/cases/${encodeURIComponent(id)}`); }
  runAssurance(id: string) { return this.request(`/api/cases/${encodeURIComponent(id)}/assurance`, { method: "POST", body: "{}" }); }
  proof(id: string) { return this.request<SignedProofBundle>(`/api/cases/${encodeURIComponent(id)}/proof`); }
  verifyProof(bundle: SignedProofBundle) { return this.request<{ valid: boolean }>("/api/platform/proofs/verify", { method: "POST", body: JSON.stringify(bundle) }); }
  recordRecurrence(id: string, productVersion: string, runId: string) {
    return this.request(`/api/cases/${encodeURIComponent(id)}/recurrences`, { method: "POST", body: JSON.stringify({ productVersion, runId }) });
  }
}

```

### server/index.ts

```typescript
import "dotenv/config";
import express from "express";
import multer from "multer";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { createHash, randomUUID } from "node:crypto";
import { aiStatus, discoverEvidence, extractInteraction, proposeIncident } from "./ai.js";
import { attachIdentity, issueToken, requireRole, type Identity } from "./auth.js";
import { compileCase } from "./compiler.js";
import { passesValidationGate, runEvaluation, runEvaluationHybrid } from "./evaluation.js";
import { createDemoCase } from "./fixtures.js";
import { createRedressReceipt } from "./receipt.js";
import { findUnredactedPersonalData, proposeRedaction } from "./privacy.js";
import {
  adapterMetadata,
  calculateSlo,
  completeReviewTask,
  configureAdapter,
  configurePlatformPersistence,
  createDeploymentProof,
  createProofBundle,
  createReporterAccessLink,
  dashboard,
  deliverIntegration,
  enqueueEvaluation,
  executeAdapter,
  exportDataset,
  fingerprintCase,
  getPlatformState,
  githubCheckBundle,
  listJobs,
  oecdExport,
  patternReport,
  phaseReadiness,
  publishGitHubCheck,
  proposeCounterfactuals,
  publicCase,
  recordConsent,
  recordDeploymentVerification,
  recordRecurrence,
  regulatoryMappings,
  releasePack,
  resetPlatform,
  resolveReporterAccessLink,
  reviewCounterfactual,
  runAssuranceSuite,
  sealEscrow,
  synchronizeEvidence,
  updateEvidenceVersion,
  updateReporterPreferences,
  updateWorkspacePolicy,
  verifyAuditChain,
  verifyPlatformDocument,
  verifyProofBundle,
} from "./platform.js";
import { readEncryptedArtifact, storeEncryptedArtifact } from "./secure-storage.js";
import { createCase, getCase, listCases, parseTranscript, resetStore, saveCase } from "./store.js";
import type { Assertion } from "../src/types.js";
import { areReviewTextsEquivalent, caseTitleFromDescription } from "../src/case-state.js";
import type { SignedProofBundle, WorkspaceRole } from "../src/platform-types.js";

const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 8 * 1024 * 1024 },
  fileFilter: (_request, file, callback) => {
    const allowed = ["image/png", "image/jpeg", "image/webp", "text/plain", "application/pdf"];
    if (!allowed.includes(file.mimetype)) return callback(new Error("Unsupported file type"));
    callback(null, true);
  },
});

const app = express();
app.use(express.json({ limit: "2mb" }));
app.use(attachIdentity);

const aiRequests = new Map<string, number[]>();
function limitAiUsage(request: express.Request, response: express.Response, next: express.NextFunction) {
  if (!aiStatus().configured) return next();
  const now = Date.now();
  const windowStart = now - 60 * 60 * 1000;
  const maximum = Math.max(1, Math.min(100, Number(process.env.REDRESSCI_AI_RATE_LIMIT_PER_HOUR) || 20));
  const key = request.ip || request.socket.remoteAddress || "unknown";
  const recent = (aiRequests.get(key) || []).filter((timestamp) => timestamp > windowStart);
  if (recent.length >= maximum) {
    response.setHeader("Retry-After", "3600");
    return response.status(429).json({ error: "Live AI limit reached for this hour. The deterministic workflow remains available." });
  }
  recent.push(now);
  aiRequests.set(key, recent);
  next();
}

configurePlatformPersistence(root);
if (!process.env.REDRESSCI_PERSIST) resetPlatform(listCases());
else listCases().forEach(synchronizeEvidence);

app.get("/api/health", (_request, response) => response.json({ ok: true, ai: aiStatus(), demoMode: process.env.REDRESSCI_AUTH_REQUIRED !== "1", authRequired: process.env.REDRESSCI_AUTH_REQUIRED === "1" }));
app.post("/api/auth/demo/:role", (request, response) => {
  if (process.env.REDRESSCI_AUTH_REQUIRED === "1") return response.status(404).json({ error: "Demo authentication is disabled." });
  const role = String(request.params.role) as WorkspaceRole;
  const member = getPlatformState().workspace.members.find((entry) => entry.role === role);
  if (!member || !["reporter", "reviewer", "developer", "admin", "partner"].includes(role)) return response.status(404).json({ error: "Demo role not found." });
  response.json({ token: issueToken({ id: member.id, name: member.displayName, role, workspaceId: getPlatformState().workspace.id }), member });
});
function canAccessOriginal(item: NonNullable<ReturnType<typeof getCase>>, identity?: Identity) {
  if (!identity) return false;
  if (identity.role === "admin" || identity.role === "reviewer") return true;
  if (identity.role === "reporter") return item.reporterId === identity.id;
  return identity.role === "developer" && item.intakeType === "internal-incident" && item.reporterId === identity.id;
}

function visibleCase(item: ReturnType<typeof getCase>, identity?: Identity) {
  if (!item) return item;
  if (!canAccessOriginal(item, identity)) return {
    ...item,
    reporterName: "[REDACTED]",
    originalTranscript: "",
    artifacts: [],
    title: item.privacyApproved ? item.redactedTitle : "Case awaiting privacy review",
    description: item.privacyApproved ? item.redactedDescription : "[PENDING PRIVACY REVIEW]",
    userInput: item.privacyApproved ? item.redactedUserInput : "[PENDING PRIVACY REVIEW]",
    observedResponse: item.privacyApproved ? item.redactedObservedResponse : "[PENDING PRIVACY REVIEW]",
    redactions: item.redactions.map((entry) => ({ ...entry, value: "[PRIVATE]" })),
  };
  return item;
}

app.get("/api/cases", requireRole("reporter", "reviewer", "developer", "admin", "partner"), (request, response) => {
  const available = request.identity?.role === "reporter" ? listCases().filter((item) => item.reporterId === request.identity?.id) : listCases();
  response.json({ cases: available.map((item) => visibleCase(item, request.identity)) });
});
app.get("/api/cases/:id", requireRole("reporter", "reviewer", "developer", "admin", "partner"), (request, response) => {
  const item = getCase(String(reque
[truncated — 41124 more characters]
```

### vite.config.ts

```typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    proxy: { "/api": "http://localhost:8787" },
  },
  build: { outDir: "dist" },
});

```

### index.html

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="theme-color" content="#f4f1ea" />
    <meta name="description" content="RedressCI turns reported AI failures into evidence-backed regression tests." />
    <title>RedressCI — Failures that stay fixed</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

```

### render.yaml

```yaml
services:
  - type: web
    name: redressci
    runtime: docker
    plan: free
    healthCheckPath: /api/health
    envVars:
      - key: REDRESSCI_AUTH_SECRET
        generateValue: true
      - key: REDRESSCI_STORAGE_KEY
        generateValue: true
      - key: REDRESSCI_ESCROW_KEY
        generateValue: true
      - key: REDRESSCI_PERSIST
        value: "1"
      - key: REDRESSCI_STORAGE_REGION
        value: us
      - key: OPENAI_API_KEY
        sync: false
      - key: REDRESSCI_TARGET_ALLOWLIST
        sync: false
      - key: REDRESSCI_TARGET_TOKEN
        sync: false
      - key: REDRESSCI_GITHUB_REPOSITORY
        sync: false
      - key: REDRESSCI_GITHUB_TOKEN
        sync: false
      - key: REDRESSCI_AI_RATE_LIMIT_PER_HOUR
        value: "20"

```

### src/vite-env.d.ts

```typescript
/// <reference types="vite/client" />

```

[30 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]