Changelog¶
What's shipped, when. Newest first. Items move here from roadmap.md as they go live.
Last updated: 2026-05-18
2026-05-18 — Methodology learning-loop telemetry — Phase B engineering COMPLETE¶
Final engineering slice of Phase B. Aggregates accept/reject signal across a firm's engagement history into per-dimension slices (primitive, archetype, severity, framework, engagement). Surfaced as the partner-facing methodology telemetry — feeds manual methodology version bumps in Phase D, not automated tuning.
Why human-in-the-loop refinement is non-negotiable:
- False positives are asymmetric — auto-tuned weight reduction to "lower reject rate" risks missing the next critical finding. Cost of miss >> cost of extra rejection.
- Partner authority is the moat — named-human methodology refinements (founder + founding-firm partner collaboration) make the methodology a professional artifact with named authorship, defensible to AICPA, insurance carriers, procurement. Auto-tuned methodology = replicable in weeks.
- Cross-firm contamination risk — auto-tuning on firm A's accept/reject signal would propagate firm A's biases to firm B's engagements. The cross-firm library is for aggregate empirical reporting, not training.
What the dashboard exposes per firm: overall accept/reject rates; per-primitive breakdown (which primitives produce signal vs. noise); per-archetype breakdown (do remediation-pipeline engagements over-produce vs. capability-leverage?); per-severity breakdown (severity bias detection); per-framework breakdown (SOC 2 vs. CMMC vs. HIPAA patterns); per-engagement breakdown (outlier detection for manual re-read).
Phase B engineering is COMPLETE. Three workstreams shipped:
| Slice | Status |
|---|---|
| B.1 Partner signoff (moat 13) | ✅ |
| B.2 End-client identity (moat 6 partial) | ✅ |
| B.3 Methodology telemetry (moat 8 deepening) | ✅ |
Cumulative Phase B engineering: 68 new tests, 264/264 backend tests pass.
Phase B content workstreams remaining (not engineering — submit + wait): B.4 peer-reviewed journal submissions to The CPA Journal + Audit: A Journal of Practice & Theory; B.5 conference CFPs (AICPA ENGAGE, state-CPA-society circuit); B.6 defensive publication round 2 (IP.com filing on v1.1 refinements).
2026-05-18 — End-client identity — Phase B.2 (moat 6 partial)¶
The audit firm's client is now a first-class identity in AuditForge, distinct from the audit firm performing the audit and from the users who log in to operate the engagement. Engagement records gain end_client_id; deliverable covers render co-branding with the end-client's logo and color alongside the audit firm's brand.
What this enables for partners and end-clients:
- Co-branded deliverables. The end-client's procurement / audit-committee readers see their own brand on the deliverable cover. The document reads as something prepared for them, not generic AuditForge output.
- Longitudinal client view. A firm running quarterly audits for the same client over years sees the full engagement history in one view. Useful for cross-engagement methodology comparisons and pattern detection within a single end-client's audit history.
- Foundation for the Phase C end-client portal. End-clients will authenticate against these identities to verify deliverables offline. The identity exists today; the portal arrives in Phase C.1.
- Cross-firm findings library integration. When firms opt in to the cross-firm anonymized library (moat 11), the end-client's industry tag becomes a joinable signal for cross-vertical aggregation.
Phase B progress: 2 of 6 workstreams shipped. B.3 (methodology learning-loop telemetry), B.4 (journal submissions), B.5 (conference CFPs), B.6 (defensive publication round 2) remain.
2026-05-18 — Partner signoff attestation — Phase B.1 (moat 13) live¶
The cryptographic chain now binds human authorship to the deliverable. After review, the partner re-authenticates with their password and the AuditForge server signs a canonical attestation payload combining engagement ID, deliverable hash, partner user ID, timestamp, nonce, and audit-log terminal hash. The signature persists on the engagement record and verifies offline via the firm's public key (embedded in the regulator archive).
What this enables for partners and end-clients:
- The deliverable is now a notarized professional attestation. Before B.1, an end-client could verify "this deliverable came from AuditForge under this methodology." After B.1, the end-client can verify "Partner X cryptographically attested this deliverable on date Y." That elevates the artifact from software output to defensible signed work product.
- Six tamper-detection categories caught, plus cross-engagement replay protection: a signature copy-pasted from one engagement to another does not verify because engagement_id is part of the signed payload.
- Bridges to the insurance / liability moat. When we approach professional-liability carriers in Phase C, the partner-signoff signature is the strongest single piece of evidence that AuditForge users follow a procedurally rigorous workflow.
Trust model: the firm's Ed25519 private key (server-side, AWS Secrets Manager) signs after the AuditForge server validates the partner's password re-authentication. Same posture as Adobe Sign / DocuSign server-side signatures bound to user-validated authentication events.
Password re-auth rationale: session tokens prove a user is signed in; password re-auth at signoff time proves a fresh, deliberate intent — the same posture as "type your password to confirm" in banking apps.
Phase B progress: B.1 shipped. B.2 (end-client identity), B.3 (methodology learning-loop telemetry), B.4 (journal submissions), B.5 (conference CFPs), B.6 (defensive publication round 2) remain.
2026-05-18 — Source-system connectors live — Phase A of the moat plan COMPLETE¶
Partners can now connect SharePoint, OneDrive, or Google Drive to an engagement instead of manually exporting documents. The full OAuth flow plus per-engagement refresh-token isolation plus background ingest with progress streaming all ship in this drop.
Flow:
- Partner clicks "Connect SharePoint / OneDrive / Google Drive" — frontend gets back a consent URL bound to this engagement via an HMAC-signed state token.
- Browser redirects to Microsoft / Google. Customer tenant admin consents (first time only; subsequent users see immediate consent).
- Provider redirects to AuditForge's callback. Refresh token persists encrypted in AWS Secrets Manager scoped per-firm and per-engagement.
- Partner provides folder/drive/site IDs (post-consent picker). Background task walks the source, downloads each file, writes to the engagement corpus, emits progress events on the existing /corpus/stream SSE, then routes through the standard ingest pipeline.
Security posture:
- State token binds the OAuth flow to the engagement + product + provider. Attackers cannot redirect callbacks to a different engagement, even with leaked authorization codes.
- Cross-product check rejects state tokens issued for other Base2ML products.
- Callback-path-vs-claim consistency: an attacker who flips the URL from
/oauth/callback/microsoftto/oauth/callback/googlegets rejected. - Per-firm + per-engagement refresh-token isolation: compromise of one engagement's token does not contaminate another.
invalid_grant(revoked refresh token) clears the SSM entry and surfaces a "re-authenticate" prompt rather than a generic error.
Phase A of the moat plan is COMPLETE.
| Workstream | Status |
|---|---|
| A.2 Defensibility cluster (snapshot + tamper-evident audit log + signing + signed deliverables) | ✅ |
| A.4 Regulator-export archive (one signed tarball, verifiable offline) | ✅ |
| A.3 Cross-firm findings library schema (data moat clock ticking) | ✅ |
| A.1 Source-system connector wire-up (SharePoint / OneDrive / Google Drive) | ✅ |
Production readiness on the connector flow: code paths are end-to-end tested against mocked OAuth + token store. Real OAuth against Azure AD + Google Cloud requires the operator OAuth-app-setup runbook to be executed — user-side work that unblocks production deployment.
Next active workstreams: Phase B (partner review queue, end-client identity, methodology learning-loop telemetry, journal submissions, conference circuit) and Phase C (end-client portal — the two-sided network surface, anti-Big-4 deck, NASBA-accredited CPE course, state-CPA-society strategic alliance).
2026-05-18 — Cross-firm findings library — data moat schema live¶
The data moat starts compounding from engagement #1. Schema + contribution pipe for the cross-firm anonymized findings library — every accepted, rejected, or refined finding from opted-in firms emits an anonymized record (PII stripped, structural signal preserved) to a shared pool.
Why this matters: the catalog of "this auditor accepted/rejected this finding because of these reasons" cannot be assembled by anyone else — not by competitors, not by LLM training, not by web scraping. It only exists because we're sitting in the partner-feedback loop. After ~100 engagements this dataset is the irreplicable foundation of moat 11.
Customer-trust-preserving design:
- Opt-in default is OFF. Firms must consciously agree (typically via founding-firm Tier C contract's explicit clause).
- Deterministic anonymization (no LLM, no randomness). Firms can audit the anonymizer.
- What's stripped: all free-text (description, root_cause, auditor_notes, scope_of_work, dependencies, risk_if_unaddressed, evidence verbatim_quotes, doc titles, doc IDs), exact effort estimates (bucketed), exact creation timestamps (date only), firm_id / engagement_id / finding_id (replaced with salted hashes that cannot be reversed without the firm salt).
- What's preserved: primitive, dimension, severity, confidence, filter_status, accept/reject status, industry tag, framework tags, archetype, evidence shape (counts only), effort bucket, creation date, salted dedupe hashes.
- Schema stability test prevents future field additions from silently leaking PII — any change requires conscious code review.
Productization deferred to Phase C. The Phase C work delivers the LLM clustering of cross-firm themes and a public "industry patterns" surface. This phase just runs the pipe so the pool has data when the consumer ships.
Phase A progress: 3 of 4 workstreams complete (defensibility cluster, data-moat schema, regulator-export archive). The remaining workstream is the source-system connector consumer wire-up (Phase A.1), which depends on the operator OAuth-app provisioning runbook being executed.
2026-05-18 — Regulator-export archive — Phase A defensibility cluster COMPLETE¶
Single signed tar.gz that bundles every artifact a regulator or end-client needs to verify an engagement end-to-end offline. Closes the last engineering workstream of the Phase A defensibility cluster (moat 12, system of record).
What partners can do with one downloaded archive:
- Hand it off as the regulator deliverable. Partner pulls the archive from
GET /auditforge/engagement/{id}/regulator-archive, transfers it to the regulator, end-client, or external auditor. The recipient verifies offline — no contact with AuditForge needed. - Verify at three independent levels (defense in depth):
- Archive level — manifest signature binds the file set + methodology snapshot + audit-log terminal hash
- Deliverable level — each deliverable inside also self-verifies via its provenance block
- Audit log level — hash chain self-verifies via shard rotation
- Detect any tampering — mutated file bytes, smuggled files, missing files, forged methodology snapshot, forged audit-log terminal hash, forged signature, swapped public key — each raises a specific cryptographic diagnostic.
The Phase A defensibility cluster is now complete. Cumulative across slices A.2.1 through A.2.4 and A.4:
- ✅ Methodology snapshot stamped at engagement creation
- ✅ Hash-chained audit log with terminal-record sealing
- ✅ Per-firm Ed25519 keypairs in AWS Secrets Manager
- ✅ Signed deliverables with embedded offline-verifiable provenance
- ✅ Signed regulator-export archive bundling the lot
A buyer asking "prove this audit was authentic" gets one tarball, one verifier, and cryptographic guarantees.
Next active workstreams (both can run independently): - Phase A.1 — Source-system connectors (SharePoint / OneDrive / Google Drive) in AuditForge - Phase A.3 — Cross-firm findings library schema (the data moat)
2026-05-18 — Signed deliverables — Phase A.2 of the moat plan COMPLETE¶
Every deliverable now carries a cryptographic provenance block binding the deliverable bytes, the methodology version that produced it, and the audit log chain via a single Ed25519 signature. End-clients and regulators verify offline — no contact with AuditForge required.
What partners and end-clients can do with a signed deliverable:
- Verify authenticity offline. Open the deliverable file (JSON, Markdown, or DOCX), extract the provenance block, feed to any Ed25519-aware verifier with the embedded
firm_public_key_pem. No phone-home, no key servers. - Detect any tampering — mutated deliverable text, forged methodology snapshot, tampered audit log terminal hash, forged signature, or swapped public key — each surfaces a specific cryptographic diagnostic.
- Demonstrate chain of custody to regulators with running code, not policy statements. The signed binding to the methodology snapshot and audit log means a single signature simultaneously proves three independent properties.
This completes Phase A.2 of the 18-month moat plan. Cumulative:
- ✅ Slice 1: Methodology snapshot stamped at engagement creation
- ✅ Slice 2: Hash-chained audit log with terminal-record sealing
- ✅ Slice 3: Per-firm Ed25519 keypairs in AWS Secrets Manager
- ✅ Slice 4: Signed deliverables with embedded offline-verifiable provenance
Foundation for Phase A.4 (regulator-export archive) is now complete — that phase just bundles what already exists into a single tarball with a top-level manifest signature.
Next active phases: Phase A.1 (connector consumer wire-up — SharePoint / OneDrive / Google Drive in AuditForge) and Phase A.3 (cross-firm findings library schema). Both can proceed independently.
2026-05-18 — Per-firm Ed25519 signing infrastructure¶
Each audit firm now has a long-lived cryptographic keypair: private key in AWS Secrets Manager (KMS-encrypted at rest, only the AuditForge ECS task role can decrypt), public key persisted on the firm record and embedded in regulator archives. The deliverable signature (next slice) will use this infrastructure.
Why this matters for partners and end-clients:
- Offline verification by anyone with the archive. The public-key verifier is a pure function — no contact with AuditForge required. A regulator or end-client opens the archive years later and proves authenticity locally.
- Per-firm isolation. Each firm's keypair is independent. One firm's compromised key affects only that firm's engagements; the rest stay verifiable.
- Industry-standard primitive. Ed25519 is what SSH and signed git commits use. Fast, deterministic, 64-byte signatures, no known weaknesses.
Up next (final slice of this phase): wire the deliverable signature into the report renderer so every deliverable carries signature = sign(deliverable_hash + methodology_snapshot + audit_log_terminal_hash). That single hex string + the firm's public key + the methodology snapshot + the audit log = end-to-end tamper-evident chain of custody for the engagement.
2026-05-18 — Tamper-evident audit logs¶
Audit logs are now a cryptographic hash chain. Every LLM-call event carries prev_hash + line_hash; line 0's prev is the engagement's methodology snapshot; close() writes a terminal record sealing the chain. Any tampering — mid-line edit, line swap, deletion, fabricated insertion — is detectable in seconds by the new verify_chain() function.
What this enables for partners:
- The audit log is now evidence, not hearsay. A regulator reviewing an archive five years later can run a single verify call against the stored shards plus the engagement's stored methodology snapshot and prove the log is unmodified — or surface exactly which line was tampered with.
- Cross-engagement forgery detection. The terminal hash binds the log to a specific engagement's specific methodology version. Two archives that disagree on terminal hash for the same engagement ID reveal forgery cryptographically.
- Multi-day engagements remain verifiable. The chain spans shards (rotation at 10MB), so long-running engagements with hundreds of MB of LLM telemetry stay end-to-end verifiable.
Tamper-detection coverage (all tested): mid-line field mutation, line swap, line deletion, stripped hash fields, malformed JSON. All five raise diagnostic errors identifying the first inconsistency.
Up next (same week): per-firm Ed25519 signing infrastructure (private keys in AWS Secrets Manager), then signature on every deliverable binding the deliverable hash + methodology snapshot + audit log terminal hash.
2026-05-18 — Methodology snapshot stamped on every engagement¶
First engineering slice of the 18-month moat plan. Every new audit engagement now carries a cryptographic identity of the engine, primitives, archetypes, prompts, model routing, and methodology paper that produced it — a tamper-evident fingerprint that lets a regulator reviewing the archive years later verify exactly which methodology version produced the deliverable.
What this enables for partners:
- Reproducibility: an old engagement can be re-rendered against its frozen methodology snapshot even after AuditForge ships v2 of the engine. Methodology evolves; finished engagements stay stable.
- Chain-of-custody anchor: the snapshot's
combined_hashis what later phases will bind audit-log hashes and deliverable signatures to. End-to-end tamper-evidence starts here. - Methodology equivalence: two engagements with the same
combined_hashare guaranteed to have run identical methodology. The basis for the cross-firm findings library's "did these two firms run the same audit version?" claim.
Backwards compatibility: old engagement records (without a snapshot) load cleanly. Snapshot stamping kicks in at the next engagement created.
Up next (same week): hash-chained audit log, per-firm Ed25519 signing infrastructure, signature on every deliverable.
2026-05-11 — In-product guided walkthrough (Phase 29)¶
Demo-ready interactive tour overlay built with react-joyride.
Behavior:
- Auto-launches the first time a user lands in AuditForge after authentication
- Restartable any time via a Take tour button in the header
- Completion persists in localStorage.auditforge_tour_completed
- 21 steps covering the complete audit workflow from orientation through
delivery, including all major features (corpus upload, intake, finding
review, bulk actions, investigate further, comments, deliverable export,
chain-of-custody freeze, cross-engagement search, portfolio patterns)
- Tooltips placed next to relevant UI (tabs, primary action buttons) or
centered with prose for conceptual explanations
- "Skip tour" available at every step; non-blocking overlay
Why it matters: - Onboarding: first-time partner users learn the workflow without needing a Loom video or hand-held demo - Demo aid: when Chris is on a sales call, the tour narrates the product so it's not all "let me show you this — and this — and this" monologue. Prospects see the same overlay as a user would
Implementation:
- New frontend/src/components/AuditForgeTour.tsx with useTour() hook
+ step definitions
- data-tour-id attributes added to tab buttons + new-engagement +
upload-corpus buttons so tour can target specific elements
- Wired into AuditForge.tsx shell
2026-05-11 — Admin-token rotation + per-token rate limits¶
Closes a real cost-exposure gap surfaced in the security review of the new public AuditForge landing page.
Admin-token rotation:
- The legacy Lindy101 shared admin token was published in the public
user-manual.md at docs.base2ml.com — anyone reading the docs had
full admin access including running expensive audits
- Token rotated to a strong randomly-generated value via SSM Parameter
Store (version 2); old Lindy101 now returns 401
- User-manual.md scrubbed: admin token no longer published; instead
refers readers to chris@base2ml.com to request one
Per-token daily rate limits (defense in depth):
- New app/auditforge/rate_limit.py module
- Daily caps per token per action_kind:
- run — 20 audit runs/day per token
- investigate_further — 50/day
- recompute (portfolio clusters) — 10/day
- intake_extract — 100/day
- Bucket id is user:<id> for per-user sessions, admin:<sha256-prefix>
for admin token (raw token never stored)
- Returns 429 with retry-after hint when exceeded; counters reset daily
- In-process state (single ECS task today); promote to Redis when
scaling to multi-task
Audit findings (no changes needed): - All 42 mutating endpoints confirmed auth-gated. Anonymous callers cannot reach any cost-bearing endpoint.
2026-05-11 — Hygiene pass¶
Three small but meaningful cleanups that came out of the customer-pitch gap review.
Signed-URL export lifecycle (30-day expiry). Every delivery=signed_url
audit-log export writes an artifact to auditforge/exports/<id>-<ts>.<ext>
in S3. The presigned URL itself expires in ≤1 hour, so the underlying
object has no operational value beyond a short retention window.
- S3 lifecycle rule applied to the shared platform bucket (live now)
- Same rule auto-applied to every new per-engagement bucket via
app/auditforge/buckets.py provisioning code
- Prevents unbounded accumulation; cost-bounded indefinitely
Pre-flag engagement migration. 15 engagements that pre-dated the
AUDITFORGE_PROVISION_PER_ENGAGEMENT_BUCKET=true default were still in
the shared bucket. Ran scripts/auditforge_migrate_buckets.py --execute
--yes:
- 24 objects copied across 15 engagements (1.6 MB total)
- Each engagement now has a dedicated metis-af-<short_id>-<account>
bucket with encryption, versioning, public-access-block, and tagging
- Source-bucket objects preserved (rollback path intact)
- Engagement records updated with source_bucket field
Real-PDF stress test. Validated the self-serve corpus flow with two
real-world public PDFs:
- NIST SP 800-171 r2 (1.5 MB, ~250 pages of compliance controls)
- NIST Cybersecurity Framework v1.1 (1.0 MB)
- Both uploaded cleanly via the + Upload corpus UI
- Ingestion (chunking + FAISS + BM25 build) completed in ~50 seconds
- client_id auto-bound to engagement id on completion
- Confirms the pipeline handles realistic government-domain PDFs at
production scale, not just synthetic test text files
2026-05-10 — Multi-reviewer collaboration + budget cap UX (Phase 28)¶
Two related improvements that close partner-workflow gaps at moderate-to-high engagement volume.
Phase 28a — Default budget cap UX - "Default audit budget" field promoted to a prominent "Engagement defaults" section in firm setup - Explanatory hint: $15 is conservative (12-doc synthetic corpus); $200 is suggested for 50–200 document real-world corpora
Phase 28b — Engagement assignment + threaded comments
- POST /auditforge/engagement/{id}/assignment sets the lead reviewer; chip in the engagement header shows current assignee + dropdown picker
- Per-finding threaded comments (GET / POST / DELETE /auditforge/finding/{id}/comments) — internal-only context for fellow reviewers, not rendered in deliverables
- User-list endpoint auto-scopes to caller's firm so partners can pick a colleague without seeing other firms' rosters
- 9 new endpoint tests; 106 endpoint tests pass total
2026-05-10 — Self-serve corpus onboarding (Phase 25–27)¶
The biggest workflow gap: partners can now drag-and-drop their own documents directly into AuditForge. No more "send Chris your files and wait." End-to-end onboarding from "I have files on my laptop" to "I'm running an audit" in 5–10 minutes.
- New endpoint
POST /auditforge/engagement/{id}/corpus/upload(per-file granularity for network resilience) - Per-engagement bucket isolation flipped on by default for new engagements
- New endpoint
POST /auditforge/engagement/{id}/corpus/ingestruns the chunking + indexing pipeline as a background task - SSE progress stream at
/corpus/streamsurfaces stage transitions engagement.client_idauto-binds to the engagement id once ingested — no separate corpus-tenant concept to manageCorpusUploadModalUI: drag-drop, per-file Retry, live ingest progress- + Upload corpus button on the Engagements tab
2026-05-09 — Audit log signed URL (Phase 24)¶
Large audit logs (50+ MB) can now be downloaded via a presigned S3 URL instead of streaming through the FastAPI request — bypasses ALB timeouts for very large engagements.
delivery=signed_urlquery param on the existing audit-log endpoint- 60–3600 second URL expiry, controllable per request
- Empty audit-log short-circuit returns
signed_url: null, empty: truewithout an S3 round-trip
2026-05-09 — Engagement template library (Phase 23)¶
A firm running the same shape of audit (CMMC pre-assessment, HIPAA review, etc.) for many clients can save an engagement's intake config + archetype as a reusable template.
- Templates are firm-scoped (admin token sees all)
- Two creation modes: snapshot from existing engagement, or pass intake fields directly
- Instantiate → creates a new engagement pre-filled
- Save-as-template button in engagement header; Start-from-template picker in new-engagement form
2026-05-09 — Cluster diff over time (Phase 22)¶
Patterns view now shows how the firm's accumulated cross-engagement patterns evolve between recompute snapshots. Each cluster is classified as added / grew / shrank / unchanged / removed with member-overlap percentages.
- Greedy Jaccard matching with 0.30 threshold pairs current vs. previous clusters
- Single-hop history (only the most-recent prior snapshot retained for diff)
- Toggle "Show diff vs previous snapshot" in the Patterns tab
2026-05-08 — Engagement archive (Phase 21)¶
After delivery, an admin can archive an engagement to declutter the active list. Reversible, non-destructive — findings, audit logs, deliverables all preserved.
POST /engagement/{id}/archive+/unarchive(admin only)include_archived=truequery param on list endpoint reveals archived- UI: Archive/Unarchive buttons in engagement header; Include-archived checkbox on engagement list
2026-05-08 — Engagement freeze on deliver (Phase 20)¶
Chain-of-custody preservation. Once a partner marks an engagement as delivered to the client, finding mutations are blocked until an admin explicitly unfreezes. Removes the "what if you change findings after we approved them?" procurement question.
POST /engagement/{id}/deliver(partner or admin) → freezes mutationsPOST /engagement/{id}/unfreeze(admin only) → re-allows edits- All mutating endpoints check is_frozen and return 423 LOCKED when frozen
- Audit trail records who delivered and who unfroze
2026-05-08 — Firm logo upload (Phase 19)¶
Self-serve white-labeling — partners upload their logo via the Firms tab. Stored as a data URL so it embeds cleanly in DOCX without an external CDN.
POST /auditforge/firm/{id}/logoaccepts multipart upload (PNG, JPEG, SVG, WebP, ≤200 KB)- Logo data URL flows into deliverable rendering
- LogoUploader widget in FirmManagement firm-edit modal
2026-05-08 — Per-engagement bucket migration script (Phase 18)¶
CLI tool to move pre-Phase-7 engagements into their own isolated S3 buckets. Dry-run by default; never deletes from source; idempotent.
scripts/auditforge_migrate_buckets.py- 10 unit tests covering plan, execute, verify-only, NoSuchBucket / AccessDenied non-destructive paths
2026-05-08 — Bulk finding actions (Phase 17)¶
Partner workbench efficiency: select multiple findings via checkboxes and accept/reject/refine all at once. Up to 200 per call; per-id results so partial failures don't abort the batch.
2026-05-08 — Admin recovery endpoints (Phase 16)¶
Closes the SOC 2 readiness gap where a user who lost their TOTP device or forgot their password had no recovery path. Admin-only clear-MFA, clear-lockout, reset-password endpoints. Each writes a structured audit-log line.
2026-05-08 — Fine-grained roles (Phase 15)¶
Three roles inside a firm: admin, partner, associate. Associate is read-only — enforces partner-reviews-before-decision discipline by refusing finding mutations from associate users.
Earlier phases (Phase 0 – 14)¶
Key milestones (technical detail available to prospect firms after a signed agreement; investors under NDA):
- Phase 14 — Audit log export (procurement-review artifact)
- Phase 13 — Pagination on long-list endpoints
- Phase 12 — Brute-force lockout (5 failures / 15 min → 15 min lock)
- Phase 11 — TOTP MFA with backup codes
- Phase 10 — Cross-engagement portfolio clusters
- Phase 9 — Per-engagement firm scoping (closes ID enumeration risk)
- Phase 8 — Per-user authentication (argon2 + opaque session tokens)
- Phase 7 — Per-engagement S3 bucket isolation (feature flag, default-on as of 2026-05-10)
- Phase 5 — Cross-engagement findings search
- Phase 4 — AI-assisted intake extraction
- Phase 3 — Investigate-further per finding
- Phase 2.5 — White-label firms + methodology white paper
- Phase 2 — Partner-driven engagement creation UI
- Phase 1 — Steering UI (review / accept / reject / refine / export)
- Phase 0 — Foundation: async multi-provider LLM client, engagement store, intake module skeleton