From b4eef09867fde9dbfc41b3deb33bea527b0f5a1d Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Fri, 26 Jun 2026 01:35:33 -0700 Subject: [PATCH] release: cut stable 0.0.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promote the 0.0.11-beta line to the first stable 0.0.11 release: - package.json 0.0.11-beta.13 -> 0.0.11 (drops the -beta suffix so publish.yml publishes under the `latest` dist-tag, not `beta`). - Consolidate every 0.0.11-beta.* CHANGELOG entry into a single `## 0.0.11 — 2026-06-26` section (Breaking / Features / Fixes / Dependencies / Tests / Docs), preserving all 104 bullets and their PR references. The individual per-beta sections are removed. Done on a luv-cut-0.0.11 branch per the repo's release convention (block-version-bumps reserves version edits for luv-cut-X.Y.Z). Sanity-checked against all CI gates locally: lint (0 errors), tsc, 1895 unit tests, build, validate:mdx (300 pages), 298 e2e tests, and a frozen-lockfile install — all green. Publishing to npm happens when the GitHub Release v0.0.11 is created; publish.yml then auto-bumps main to 0.0.12-beta.0. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01TD26MQ8M3gyaTLN2cwufTf --- CHANGELOG.md | 194 ++++++++++++++------------------------------------- package.json | 2 +- 2 files changed, 52 insertions(+), 144 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab7735e8..db42ec39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,120 +1,23 @@ # Changelog -## 0.0.11-beta.12 — 2026-06-24 +## 0.0.11 — 2026-06-26 + +### Breaking +- Remove the undocumented cloud auth + event relay subsystem ahead of a from-scratch redesign. Deletes `src/auth/` (OAuth 2.0 device-flow login against `api.befailproof.ai`, `~/.failproofai/auth.json` token store) and `src/relay/` (WebSocket event relay daemon, sanitized JSONL queue at `~/.failproofai/cache/server-queue/`, PID tracking). Strips the `failproofai login` / `logout` / `whoami` / `relay start|stop|status` / `sync` subcommands and the internal `--relay-daemon` mode from `bin/failproofai.mjs`, along with their `--help` entries and "did you mean" suggestions. Removes the fire-and-forget `appendToServerQueue` + `ensureRelayRunning` calls from `src/hooks/handler.ts` so hook evaluation no longer enqueues events or lazy-spawns a daemon. The whole subsystem had zero references in `README.md`, `docs/`, `examples/`, or `__tests__/`, and only had internal cross-imports — `tsc`, `eslint`, `vitest` (1623 tests), and the `bun run build` bundles all stay green. Users who ran `failproofai login` should also wipe `~/.failproofai/{auth.json,cache/server-queue,relay.pid}` and stop any running relay daemon by hand; new auth/cloud surface will land in a follow-up. +- Default policy namespace renamed from `exospherehost` to `failproofai`. Configs that explicitly reference builtins as `exospherehost/` must update to `failproofai/`. Flat-name shorthand (e.g. `"sanitize-jwt"`) continues to work unchanged because it auto-resolves to the new default namespace. Builtin docs (EN + 14 translations) updated to show the new namespace. ### Features - Collapse the dashboard "Reach Us" dropdown's three GitHub links (Request a Feature / Report an Issue / Ask a Question) into a single **Feedback & Issues** entry pointing at the GitHub issue chooser (`/issues/new/choose`). - Reorder the policies → activity table columns to: time · decision · event · cli · tool · policy · reason · mode · duration · session. - -### Fixes -- Fix the policies → activity table collapsing on narrow / portrait windows. Columns no longer overlap — each data cell clips with an ellipsis at its own edge and headers stay on one line — and the table holds a readable `min-width` (1280px), scrolling horizontally below that via a themed scrollbar instead of squeezing columns into each other. The badge / long-header columns (decision, event, cli, mode, duration, session) were widened so their content fits — the **mode** column in particular now holds its widest pill (`bypassPermissions`) instead of clipping it mid-word, and the mode pill truncates with an ellipsis + hover tooltip if a longer / custom mode ever appears. - -### Docs -- Replace the community Slack invite with Discord (`https://discord.gg/2zjBZP7yQJ`) everywhere it's user-facing: the `failproofai --help` LINKS banner, the dashboard "Reach Us" dropdown, and the README community badge (English + 14 translations). The Slack *webhook notification example* (`examples/policies-notification.js`) is intentionally left as-is — it's a feature integration, not a community link. -- Reword the `/audit` invite card ("Share with friends" / "wanna know how your friends' agents score?") and grammar-pass the X/LinkedIn share templates (article/adverb/coordination/comma-splice fixes only — no behavioral or structural change). - -## 0.0.11-beta.11 — 2026-06-23 - -### Features - Add a PR-level MDX parse check (`bun run validate:mdx`, wired into the CI `docs` job) that compiles every `docs/**/*.mdx` with the same MDX engine Mintlify runs at deploy time. `mintlify validate` only checks `docs.json` structure and nav links — it never parses page content — so syntax errors slipped through to the post-merge deploy. This catches them on the PR instead (#455). - Invite emails now include the inviter's audit score: `sendInvites()` and the `/api/audit/invite` proxy forward a clamped (0–100) score to the api-server, which renders "my agent scored a N/100" in the body. Threaded `AuditDashboard → ComeBackBetterSection → InviteDialog`; optional end-to-end so it degrades to score-free copy when absent (#456). - Rewrite the X/LinkedIn share templates (10 each): lead on the score and archetype and end on the `npx -y failproofai audit` CTA + handle (`@failproofai` / `@Failproof AI`), with no URLs in the copy so the pasted audit-card image isn't replaced by a link-preview card (#456). - Enlarge the audit poster's four corner labels so they read clearly at share size, on both the dashboard render and the downloaded PNG (#456). - -### Fixes -- Fix three translated docs pages that failed the Mintlify deploy parse. `docs/tr/cli/audit.mdx` had a dropped closing backtick that pushed `` out of its inline-code span (parsed as an unclosed JSX tag); `docs/ja/built-in-policies.mdx` and `docs/zh/built-in-policies.mdx` carried translator-injected `{#id}` heading anchors that MDX reads as JS expressions. All three now match the other 12 locales (#455). -- Stop the failproofai server log from repeating the benign Next.js "Failed to find Server Action" deployment-skew error. A browser tab left open across a dashboard rebuild/upgrade POSTs a stale Server Action ID; the client recovers via Next's graceful 404, but the standalone server still logged a 3-line error block to stderr per stale request. The `start` launcher now pipes the server's output through a filter (`scripts/skew-log-filter.ts`) that drops just that block — all other output, and color via `FORCE_COLOR`, passes through untouched; `dev` is unchanged (#456). - -### Dependencies -- Add `@mdx-js/mdx` as a dev dependency, used by the new `validate:mdx` docs parse check (#455). - -## 0.0.11-beta.10 — 2026-06-23 - -### Features - Add the `failproofai audit` CLI command: scans local agent-CLI session history, pre-warms the dashboard cache, and opens the `/audit` report — also runs install-free via `npx -y failproofai audit`. New `src/audit/cli.ts` (animated progress mirroring the dashboard's stages) and `src/audit/open-browser.ts`, wired into `bin/failproofai.mjs` (#453). - Rework the shareable `/audit` card (dashboard render + downloadable PNG): remove the bottom-tier rank pill, center the score, and rebuild the footer as a glowing white `befailproof.ai` stamp + a glowing `npx -y failproofai audit` CTA. Expand the social-share copy to 10 X + 10 LinkedIn templates (short, on-brand) tagging `@failproofai` / `@Failproof AI`, drop the raw site URL, and append a clipboard paste hint on share (#453). - -### Fixes -- Show login-required copy ("Oops! Login required" / "What's your email?") on the invite-a-friend CTA's shared `AuthDialog` so it reads distinctly from the reminder CTA — content only, the auth flow is unchanged (#453). -- LinkedIn share now opens the feed composer with the post text pre-filled (`feed/?shareActive=true&text=`) instead of the deprecated `share-offsite` `summary` param that LinkedIn ignores (#453). - -### Docs -- Document the `failproofai audit` command and `npx -y failproofai audit` usage in `docs/cli/audit.mdx`, and refresh the `docs/dashboard.mdx` Audit section to the current poster flow (#453). -- Point the docs community anchor (`docs.json`) and the CLI launch banner at the Discord server instead of the Slack invite (#453). - -## 0.0.11-beta.9 — 2026-06-22 - -### Features - Add `invite a friend` flow on `/audit#come-back-better`: new `InviteDialog` modal takes a comma/space/newline-separated list of friend emails (validates inline, hard-cap of 10 per submit, dedupes against the sender's own address), POSTs them to the new `/api/audit/invite` Next.js proxy route, which forwards to the api-server's `POST /v0/invite` endpoint with the user's Bearer token. Anonymous users get routed through `AuthDialog` first so we have a sender identity to Cc. Removes the placeholder `1 of 3 invited` perks progress bar — the perks copy now says invites are sent from failproof.ai + Cc'd to you. The upstream `/v0/invite` endpoint contract is handed over to the `FailproofAI/platform` team separately (#435). - -### Fixes -- Fix the failing **Supply Chain** (OSV-Scanner) CI gate, which was red on every open PR. The dependency tree resolved `vite@8.0.14`, which carries two advisories with no in-tree patch — GHSA-fx2h-pf6j-xcff (CVSS 8.2, high) and GHSA-v6wh-96g9-6wx3 (CVSS 5.5, medium), both fixed in 8.0.16. A plain `bun update vite` only bumped the top-level copy (used by `@vitejs/plugin-react`) and left a nested `vitest`-owned `vite@8.0.14` behind, so the fix pins `vite` to `8.0.16` via `package.json` `overrides` (the mechanism `osv-scanner.toml` recommends) to dedupe the whole tree. The same scan also flagged `undici@7.27.2` — 7 advisories disclosed since the per-PR CI runs, pulled in transitively by the `jsdom` test environment — pinned to `7.28.0` via `overrides`. OSV-Scanner now reports "No issues found" (#446). -- Swap the `/audit` poster PNG export from `html2canvas` to `html-to-image`. html2canvas reimplements CSS in JavaScript and was producing broken dashed borders on the poster's outer rule (Canvas's `setLineDash` doesn't connect cleanly at corners) and a stray pink square cutting through the wordmark's "l" (the `/logo.svg` uses an SVG `` for the "i" character, which html2canvas ignored). `html-to-image` serializes the live DOM into an SVG `` and rasterizes it through the browser's native rendering engine, so dashed borders, SVG masks, gradients, and font metrics render exactly as they do on screen. Implementation in `app/audit/_components/audit-poster.tsx#captureCardBlob` (#435). -- Lock the html-to-image capture's `width`/`height` (and the matching inline `style` override) to the live poster element's `offsetWidth`/`offsetHeight`. html-to-image clones the node without its parent's flex context (the `.poster-section`'s `flex: 1` stretching), so the clone would collapse to intrinsic content width while the canvas inherited the original `offsetWidth` — content rendered anchored to the left of empty space (#435). -- Capture the poster from an off-screen clone instead of the live element. Even with explicit `width`/`height`, the live `.poster` carried its parent's flex context + `margin: 0 auto`, which html-to-image preserved during capture — the content ended up centered inside an oversized canvas, with the poster's left dashed border visible at canvas edge and the right meta clipped. The fix clones the node into a fresh `position: fixed; left: -10000px` wrapper with a fixed width matching `getBoundingClientRect().width`, captures the clone, then removes the wrapper. The clone has no flex parent and no margin auto, so the canvas dimensions match the poster exactly (#435). -- Drop the `━━` glyph prefix and the amber slipping-count badge (`182` etc.) from every navbar tab. The badge surfaced a number that was already prominent on the audit page itself and the prefix was decorative chrome left over from the brutalist redesign. `Navbar` no longer accepts `auditSlippingCount`; `app/layout.tsx` no longer reads the dashboard cache to derive the count (#435). -- Correct the CLI binary name in `how-to-improve-section.tsx`'s install commands. The per-policy install row and the `[install all]` bulk command both emitted `failproof policy add ` — the shipped binary is `failproofai`, so a copied command would fail with `command not found`. Updates the three call sites (header docstring, `bulkInstall()`, and the per-row install string), plus the matching example in `docs/dashboard.mdx#Audit` (#435). -- Calm the `/project/[name]` single-project page chrome. The header dropped the brutalist `━━ back to projects` link, the `● N sessions` green-dot count, the `section-h` display-font title, and the green-eyebrow `path` / `modified` definition list — replaced with a flat back chip, a mono `h1`, and a single inline meta line (`path … · modified … · sessions N`). `SessionsList` was rebuilt with the same calm chrome as the audit page: sharp 1px borders (no rounded corners), dim small-caps labels (`filter by` / `range` / `session id`), pink-outlined active chip, and JetBrains Mono throughout. The file icon goes from `text-primary` colored to dim. Empty state copy switches to the comment voice (`// no sessions found`). New CSS in `app/globals.css` under the `/project/[name]` and sessions-list blocks; tests updated to match the new copy / casing (#435). -- Address CodeRabbit review on the invite flow: `InviteDialog` now accepts an `onUnauthorized` callback and routes 401 responses back through `AuthDialog` (caller in `come-back-better-section.tsx` re-opens the auth flow) instead of dead-ending in a generic inline error. `/api/audit/invite` no longer forwards raw upstream exception text to either telemetry or the client response — surfaces a stable generic message and logs only the bounded `err.name` so internal hostnames / IPs / payload fragments stay server-side (#435). -- Address CodeRabbit review on the audit-poster + come-back-better paths. `audit-poster.tsx#handleShare`'s fallback telemetry no longer reports `status: "success"` when `fallbackMethod === "failed"` — share/capture analytics now correctly distinguish error vs. success. `come-back-better-section.tsx#refreshStatus` preserves the prior auth state on transient `/api/auth/status` failures (5xx, network blips) instead of downgrading to `anon` and clearing a valid reminder — it only falls through to `anon` on the very first probe (still `unknown`) so the cadence buttons unlock when the server is unreachable. Adds `:focus-visible` outlines to the new interactive controls (`.poster-share-btn`, `.cadence-btn`, `.invite-btn`, `.install-all-btn`, `.copy-icon-btn`, `.fix-install-btn`) so keyboard navigation has a perceptible focus indicator (#435). - -### Dependencies -- Consolidate the open Dependabot bumps #436–#445 into this single PR, each landing at the exact version its PR proposed: `next` 16.2.7 → 16.2.9 (#436), `eslint` 10.4.1 → 10.5.0 (#437), `@tailwindcss/postcss` 4.3.0 → 4.3.1 (#438), `tailwindcss` 4.3.0 → 4.3.1 (#439), `@anthropic-ai/sdk` 0.102.0 → 0.104.2 (#440, the one bump that also moves a `package.json` range, `^0.102.0` → `^0.104.2`), `vitest` 4.1.8 → 4.1.9 (#441), `lucide-react` 1.17.0 → 1.18.0 (#442), `@tanstack/react-virtual` 3.14.2 → 3.14.3 (#443), `posthog-node` 5.36.5 → 5.37.1 (#444), and `eslint-config-next` 16.2.7 → 16.2.9 (#445). The ten superseded PRs are closed in favour of this one (#446). -- Add `html-to-image@^1.11.13` for the audit-poster PNG export. Replaces (but does not remove) `html2canvas` — the latter remains for any non-audit screenshot path still using it (#435). - -### Docs -- Update `docs/dashboard.mdx`'s `### Audit` section to describe the new 5-section flow (poster + strengths + quirks + how to improve + come back better), replacing the prior 6-section description (identity + show off + strengths + score+leaderboard + findings + prescribed policies+return loop). Calls out the html-to-image swap so the documented behaviour matches what users see when they click `download poster` (#435). -- Update `docs/dashboard.mdx`'s description of the `come back better` perks card to document the new `invite a friend` flow (modal → `/api/audit/invite` → upstream `/v0/invite` → one email per recipient with sender Cc'd) — replacing the prior "progress bar + invite a friend CTA" description (#435). - -## 0.0.11-beta.8 — 2026-06-11 - -### Features - Restructure `/audit` into a single-screen shareable poster + four below-fold sections (`strengths` / `quirks` / `how to improve` / `come back better`). The poster is the PNG-export region and now self-contains the wordmark, archetype index, audit date, score + rank, persona name + keywords + rarity, sigil tile, and a `audit yours → failproof.ai` footer — so screenshots and shares carry the brand without the surrounding dashboard chrome. `// how to improve` becomes a calm row list per prescribed policy (name in white, one-line description, command + copy button on the right) topped by an `[install all]` button that copies the combined `failproof policy add a b c …` command. `// come back better` adds a 3d/7d/14d/30d reminder-cadence picker and a perks card (mock data — invite tracking + entitlement lands in a follow-up). `/policies` and `/projects` revert to plain title-case English headings (`Policies` / `Configure Policies` / `Projects`) per commit a0a18415. Site-wide chrome strips down to a calm dark canvas — body gridline + noise overlays, hard-offset pink shadows, text-shadow stamps, gridline-on-card backgrounds, and the floating share dock all go away. Pink migrates from `#e4587d` → `#e4587c` across `app/globals.css`, `app/audit/audit-styles.css`, and the audit asset CSS files. Deleted: `identity-section`, `score-section`, `findings-section`, `policies-section`, `return-section`, `show-off-cta`, `share-dock`; new: `audit-poster`, `quirks-section`, `how-to-improve-section`, `come-back-better-section`, `src/audit/social-proof.ts` (seeded archetype rarity + score-rank bands). Design spec lives at `docs/superpowers/specs/2026-06-11-audit-poster-restructure-design.md`. - -### Fixes -- Fix the `/audit` first-run audit failing on the first click (a retry worked) and stop capping how much it scans. The run was driven by a synchronous `/api/audit/run` POST that `triggerRun` (`app/audit/_components/rerun-button.tsx`) aborted after the 15s `DEFAULT_FETCH_TIMEOUT_MS` (`lib/fetch-with-timeout.ts`, sized for fast upstream calls), so a cold run (measured ~17s locally) timed out and dropped back to the empty state while the server kept running and warmed the caches — making the second click succeed. The run is now fire-and-forget: the POST starts `runAudit()` as a detached task in the long-lived server process and returns `202` immediately, the client polls `/api/audit/status` with **no duration cap** until it finishes (only a ~10-poll lost-connection backstop stops it), and a server-side run error is surfaced through the status endpoint (`app/api/audit/_state.ts` gains an `error` field + `finishRun(error)`, and its 5-min lock auto-expiry — which would have prematurely "finished" a long run — is removed along with the route's `maxDuration = 120`). The default scan window also drops from 30 days to the user's entire history, so an audit runs over every session regardless of how long it takes; the empty-state CTA and `run-progress` copy update from "10–30s" to "may take a while". New tests cover the fire-and-forget route, unbounded polling, and the run-state machine (`__tests__/api/audit-run-route.test.ts`, `__tests__/audit/rerun-button.test.ts`, `__tests__/api/audit-state.test.ts`) (#434). - -### Dependencies -- Reconcile `bun.lock` with the pinned `@types/node` / `@types/react` / typescript versions so CI's `bun install --frozen-lockfile` step succeeds (#434). - -## 0.0.11-beta.7 — 2026-06-10 - -### Fixes -- Remove the top-of-page `[ re-audit ]` bar from `/audit` (added in #428). On the empty/expired path it stacked a second "run an audit" CTA directly above the existing first-run panel — the duplication read as broken — and on loaded reports the `audited 3d ago` / `expires in 14h` strip earned little, so the whole `TopAuditBar` component (`app/audit/_components/top-audit-bar.tsx`), its `.top-audit-bar*` CSS, and its test (`__tests__/audit/top-audit-bar.test.tsx`) are deleted. Re-auditing still works from `[ run audit ]` on the empty state and `[ re-audit now ]` at the bottom of a report; the sticky `AuditProgressStrip`, soft-refresh-on-success, and the 7-day cache TTL are untouched, and the per-report generation timestamp still renders in the footer. Past the TTL, `/audit` now falls through to the standard empty state instead of a dedicated `audit expired` banner. `RerunSource` drops its now-dead `"top_bar"` variant; `docs/dashboard.mdx` and `docs/cli/audit.mdx` updated to match (#431). -- Make `/audit` re-audit force a genuinely fresh scan instead of silently returning the cached result. The `[ re-audit now ]` button — and the shared `startRerun` handler behind it — now sends `noCache: true` through `triggerRun` → `paramsToBody` → the `/api/audit/run` route (which already honored `noCache`), so re-audit bypasses the per-transcript cache (`src/audit/cache.ts`) and re-scans every transcript from scratch rather than returning the identical cached result when nothing changed on disk. The fresh result overwrites the dashboard cache on success; a failed re-audit leaves the prior cache (and report) intact. The empty-state first-run CTA deliberately stays on the fast cached path — it's a first scan, not a re-audit. `ScanParams` / `paramsToBody` gain an optional `noCache`; `paramsToBody` is exported and covered by a new `__tests__/audit/rerun-button.test.ts` (#432). - -## 0.0.11-beta.6 — 2026-06-10 - -### Fixes -- Fix the `/audit` archetype classifier collapsing nearly every agent onto **the goldfish**. PR #426's GOLDFISH_ENTROPY 0.75 → 0.70 retune and the move to an empirical-firing-share `BASELINE_SHARE` were both correct, but they exposed a latent flaw in the goldfish gate: normalised entropy of the LIFT vector cannot distinguish "every cluster fires at typical ambient rate" (all lifts ≈ 1.0 → entropy pegs at the max) from "real scatter" (multiple clusters genuinely over-indexing → also high entropy). A 765-transcript / 42k-event local audit measured every active-fault cluster sitting at 0.96–1.04 of baseline — no concentration anywhere — yet the classifier returned goldfish because entropy 0.91 cleared the 0.70 gate. Fix: add `GOLDFISH_MIN_SECOND_LIFT = 1.3` and require the second-highest cluster lift to clear it, so goldfish only fires when at least TWO clusters are genuinely above baseline (the actual definition of scatter); uniform-at-baseline profiles fall through to the existing argmax. New `secondLift` feature on `AuditFeatures`. New regression block in `__tests__/audit/distribution.test.ts` reproduces the uniform-at-baseline lift shape and asserts it never auto-classifies goldfish; the now-out-of-date "must not be explorer" assertion on the representative-ambient agent is rewritten to verify the lift-normalisation mechanism (explorer's raw dominance → lift < 2) instead of forbidding a specific outcome; the ambient-cohort explorer-share bound is relaxed from 20% → 50% to reflect the post-fix distribution (#429). -- Stop the Next.js 16 dev-overlay "signal is aborted without reason" console warning at `lib/fetch-with-timeout.ts:25`. The previous implementation called `controller.abort()` with no argument — when the 15s timer fired (or, in dev hot-reload, when a stale closure's polling iteration ran after the page navigated away) the resulting `AbortSignal` carried the default bare-DOMException reason that Next.js 16's React-dev-overlay surfaces as the warning. While there, fixes a latent bug in the same function: `{ ...init, signal: controller.signal }` was silently dropping any caller-supplied `init.signal` (because the spread placed it before the overwrite), so component-unmount cancellations could not stop in-flight fetches. New implementation replaces the manual `AbortController + setTimeout` pair with the platform `AbortSignal.timeout()` — which aborts with a typed `DOMException(..., "TimeoutError")` — composed with the caller signal via `AbortSignal.any()` (Node 17.3+/20.3+ respectively, both covered by Next.js 16's Node >= 20.9 floor; Chrome 116+, Firefox 124+, Safari 17.4+). `isAbortError` is hardened to duck-type on `name` so it correctly classifies cross-realm errors and jsdom's polyfilled DOMException (which is not `instanceof Error`) — production callers (`requestLoginCode`, `triggerRun`, `auth-dialog.tsx`) keep their existing timeout-vs-network discrimination. `readCachedTranscriptResult` now uses `Number.isFinite(entry.cachedAt)` (not `typeof === "number"`) so a malformed JSON `Infinity`/`NaN` can't pin a stale entry as valid forever; `readDashboardCacheMeta` gates on schema version + parseable timestamp before surfacing the entry as "expired" so a schema-incompatible cache falls through to the first-run empty copy rather than triggering the wrong banner. New `__tests__/lib/fetch-with-timeout.test.ts` covers happy path, composed-signal forwarding, TimeoutError firing, external-signal cancellation, already-aborted short-circuit, and duck-typed name matching (#428). - -### Docs -- Update `docs/dashboard.mdx` and `docs/cli/audit.mdx` to reflect the 7-day TTL on both audit caches and the new top-of-page `[ re-audit ]` bar (last-audit timestamp, amber "expires in Xh" chip in the final 24h of the window, sticky pink progress strip during the run with `RerunError.kind`-keyed copy on failure, soft-refresh on success instead of `window.location.reload()`). The Caches section in `docs/cli/audit.mdx` is reworded so `cachedAt` is described as TTL metadata (not part of the cache key, which stays `(mtime, size, engineVersion, detectorVersion)`). The Findings example command in `docs/dashboard.mdx` is fixed from `failproof policy add` to the correct `failproofai policy add`. The 14 translated mirrors (`docs/{zh,pt-br,it,he,hi,…}/...`) will pick the changes up via the existing translation job (#428). - -### Features - Add a 7-day TTL to both audit caches and a top-of-page re-audit affordance. (1) Per-transcript cache (`src/audit/cache.ts`) gains a `cachedAt: number` field and a `CACHE_TTL_MS = 7d` reject-on-read check; schema bumps `2 → 3` so v2 entries (no `cachedAt`) force a clean re-scan instead of being trusted forever. (2) Dashboard cache (`src/audit/dashboard-cache.ts`) reuses the existing `isCacheStale(cachedAt, 7d)` helper to reject expired entries on read — `getAuditResultAction()` already maps `null` to `{status: "empty"}`, so `/audit` falls through to the empty state automatically; a new `readDashboardCacheMeta()` helper bypasses the TTL so the empty path can distinguish "first run" from "your last audit expired" and show distinct copy. (3) New `TopAuditBar` component (`app/audit/_components/top-audit-bar.tsx`) renders as the first child of `.report` — three modes (cached, expired, empty), shows relative-time (`audited 3d ago`), an amber `expires in 14h — re-audit to refresh` chip when within 24h of the TTL boundary, and a `[ re-audit ]` button reusing `.share-btn`. (4) Re-audit flow rewrite: `audit-dashboard.tsx` lifts the run state out of `return-section.tsx` so the top bar and bottom button share a single `startRerun(source)` handler — concurrent clicks are impossible and the success path soft-refreshes the dashboard cache (via the existing `getAuditResultAction`) instead of `window.location.reload()`. (5) New `AuditProgressStrip` component renders a sticky top banner during the run with an elapsed timer + CSS-only edge pulse, and a red error variant whose copy is keyed off `RerunError.kind` (`timeout` / `network` / `post_failed`); pinks/dashed/hard-offset shadows reuse the existing `.share-btn` / `.arch-mast` vocabulary so the new chrome reads as a sibling of what's already on the page (no new fonts, colors, or animation curves). New tests: `__tests__/audit/cache.test.ts` round-trips the per-transcript cache and asserts TTL + schema-v2 rejection; `__tests__/audit/dashboard-cache.test.ts` gains TTL + meta-probe cases; `__tests__/audit/top-audit-bar.test.tsx` covers the pure relative-time helpers and the three render modes (#428). - -## 0.0.11-beta.5 — 2026-06-10 - -### Fixes -- Fix the `/audit` archetype classifier collapsing nearly every agent onto **the explorer**. The lift denominator (`BASELINE_SHARE` in `src/audit/features.ts`) was derived from `SIGNAL_MAP` *catalog weights* — each persona's share of the catalog — on the theory that lift would cancel cowboy's surface-area advantage. But catalog share ≠ real firing rate: the ambient policies feeding `explorer` (env access + secrets-in-tool-output) and `architect` (`reread-after-edit` / `redundant-cd-cwd`) fire on benign, volume-scaled activity in essentially every session, far above their catalog share, so explorer's lift stayed > 1 for almost everyone and won the active-fault argmax. A real-corpus audit (674 transcripts / 41k events) measured explorer at ~60% of all mapped signal against a 22% catalog baseline. Fix: (1) drop `block-read-outside-cwd` from `SIGNAL_MAP` — it is `defaultEnabled: false` and fires on ubiquitous ambient reads, ~37% of all mapped signal on its own; (2) replace the catalog-weight `BASELINE_SHARE` with an **empirical firing-share** baseline (floored at `MIN_BASELINE` so a rare cluster can't explode to a huge lift off one hit), so a persona now wins only when it fires *more than typical*; (3) retune `GOLDFISH_ENTROPY` 0.75 → 0.70 for the reshaped lift vector. The synthetic population now spreads all 8 personas across ~8–20% (explorer down from a forced ~100% to ~13%). New regression block in `__tests__/audit/distribution.test.ts` reproduces the real ambient profile (explorer as the largest *raw* cluster) and asserts it is never auto-classified explorer and that an ambient cohort never collapses onto one persona; the two `__tests__/audit/archetypes.test.ts` lift examples are rewritten for the empirical baseline (#426). - -### Docs -- Document that contributors must build the project before the in-repo dev hooks work — the hooks resolve the `failproofai` import against the compiled `dist/index.js`, so a missing or stale `dist/` produces `Cannot find package 'failproofai'` hook errors. Adds a "Build before the in-repo dev hooks will work" section to `CONTRIBUTING.md` (with the fast `dist/index.js`-only build command for iterating on policies) and a build-first callout to the README `Contributing` section (#426). - -## 0.0.11-beta.4 — 2026-06-10 - -### Fixes -- Fix the wrong site URL embedded in every `/audit` social-share template. `app/audit/_components/share-templates.ts` and `app/audit/_components/share-dock.tsx` had `SITE_URL = "https://failproof.ai"` (and one bare `failproof.ai` mention in the 4th X template) — the actual marketing domain is `befailproof.ai`, so every shared post linked to a dead URL. Updates both `SITE_URL` constants + the bare mention to `befailproof.ai`, and tightens `__tests__/audit/share-templates.test.ts` to assert `befailproof.ai` so a future regression to `failproof.ai` fails (#425). -- Stop the `/audit` ShareDock's "share on X" / "share on LinkedIn" buttons from opening the Windows OS share dialog on desktop Chromium / Edge. `lib/share-card.ts` `shareCardNative()` now early-returns `false` on non-mobile devices (detected via `navigator.userAgentData.mobile` with a UA-string fallback for Safari / Firefox + a touch-points check for iPadOS 13+) so the existing clipboard + `x.com/intent/tweet` / `linkedin.com/sharing/share-offsite` fallback runs instead. On mobile, the system share sheet still fires as before because it actually surfaces the X / LinkedIn apps as targets. +1 test for the desktop short-circuit, existing happy-path tests opt into mobile via `navigator.userAgentData.mobile = true` (#425). - -## 0.0.11-beta.3 — 2026-06-09 - -### Dependencies -- Swap the Vitest DOM environment from `happy-dom` to `jsdom` (`vitest.config.mts`, `package.json`, 15 `docs/*/testing.mdx`). happy-dom is single-maintainer and had a 2024 critical CVE; jsdom has 6 maintainers, ~7× the weekly downloads, and a perfect Snyk maintenance score. Test suite (1691 tests across 82 files) stays green on jsdom (#419). - -### Features - Send the raw verified email to PostHog (replacing the SHA-256 `email_hash`) and strengthen the verified-account → device identity stitch. `app/api/auth/login-request/route.ts` drops the `hashEmail()` helper and emits the normalised raw `email` on all three `audit_otp_requested` events; the login logic still passes the original address to the api-server unchanged. The `audit_user_identity_linked` event (both the dashboard `login-verify` route and the `failproofai auth login` CLI in `src/auth/cli.ts`) now carries the verified `email` alongside `user_id` + `local_random_id`, plus a PostHog `$set: { email, user_id }` so the device person — whose `distinct_id` is the local random instance id — is persistently associated with the verified account, not just logged. `audit_otp_verified` success events gain `email` too for consistency. Telemetry-only change; no auth/share core logic touched. Note: this now sends user email (PII) to PostHog where a hash was sent before — still gated by `FAILPROOFAI_TELEMETRY_DISABLED=1`. (The `/audit` ShareDock social buttons were already fully instrumented — `audit_card_share_clicked` / `audit_card_capture_completed` / `audit_share_dock_toggled` — so no change was needed there.) - Tighten the `/audit` share flow: drop the inline share buttons (the floating dock from the prior change is the single share surface now), wire the dock to try the Web Share API with an image file attached (`navigator.share({ files: [pngFile], text })`) before falling back to clipboard + intent URL, and route the dedicated "save audit-card" button through a new `downloadCard()` helper that always downloads (no clipboard try). On iOS / Android / Safari / recent Chrome desktop the X / LinkedIn buttons now produce a one-tap share-with-image via the system sheet. On browsers without `navigator.share` files-support, the existing clipboard-then-paste path is unchanged. The save button finally just saves. New `shareCardNative()` helper (returns boolean + early-exits on `AbortError`) and split `downloadCard()` / `copyOrDownloadCard()` in `lib/share-card.ts`; `shareCardToastMessage()` adds a `"native"` variant ("✅ image attached — pick where to post"). `app/audit/_components/identity-section.tsx` is now display-only — the share handlers, state, helpers, and three-button strip JSX are gone; `score` / `grade` / `missing` props removed too (the dock owns them via its own props from `audit-dashboard`). Telemetry `image_method` field gains a `"native"` value so we can measure native-share success rates. +4 tests for `downloadCard` (anchor click) and `shareCardNative` (no-API / resolves / AbortError). - Rework the `/audit` share-card experience so the audit PNG actually lands in the user's social post. (1) New `lib/share-card.ts` exports `copyOrDownloadCard(blob, filename)` — tries `navigator.clipboard.write([new ClipboardItem({ "image/png": blob })])` first (Chromium ≥63 / Safari ≥13.1) and falls back to a local download on permission denial or older browsers; returns `"clipboard" | "download" | "failed"` so callers can show method-specific toasts via the existing site-wide ``. (2) `app/audit/_components/identity-section.tsx` `captureCard` is split into `captureCardBlob()` (returns a `Blob | null`) and the three click handlers (`handleShareX`, `handleShareLI`, `handleDownload`) now sequence `captureCardBlob → copyOrDownloadCard → toast → window.open`. Telemetry events (`audit_card_share_clicked`, `audit_card_capture_completed`) gain `image_method` ("clipboard" / "download" / "failed") and `source` ("identity" / "dock") so we can measure how often the clipboard path succeeds and which surface drove the share. (3) Inline share buttons are redesigned around a new shared `.share-btn` class — 44px square platform mark on the left (X tile in black with white `𝕏`, LinkedIn tile in `#0a66c2` blue with white `in`, download tile with pink-crosshair corner adornment), small green "share on" / "save" eyebrow + 13px platform label in the middle, pink trailing arrow on the right; a 2px pink right-edge stroke at rest reads as "armed", hover fills the border + adds a 4px hard-offset pink shadow + lifts (-1px, -1px), press translates (2px, 2px) and collapses the shadow. (4) New `app/audit/_components/share-dock.tsx` mounts a floating bottom-right dock that shares the same `.share-btn` styling — three full-width buttons stacked vertically, pink corner brackets on the outer panel, a collapse caret in the header that shrinks the dock to a single 56px pink FAB (preference persists in `sessionStorage`), slide-in animation, hidden under 760px viewports. Mounted once from `audit-dashboard.tsx`, sharing the same `identityFrameRef` the inline buttons already capture. All new motion respects `prefers-reduced-motion: reduce`. +4 tests: `__tests__/lib/share-card.test.ts` covers clipboard-success, clipboard-rejection-fallback-to-download, `ClipboardItem`-undefined-fallback-to-download, and method-keyed toast copy. @@ -123,7 +26,6 @@ - Bump base font-size from `14.5px` → `16px` in `app/globals.css` for general readability, and round the smallest mono chrome labels up to compensate: `.btn` and `.tab` go `12px → 13px`, `.section-label` and `.section-meta` go `11px → 12px`. Tailwind text utilities downstream (`text-xs` = 0.75rem, `text-[0.7rem]`, etc.) scale automatically with the new root — the policies activity table that read ~11px now reads ~12px without touching `hooks-client.tsx`. - Make the dashboard chrome scale to fill ultrawide monitors. `.report` in `app/globals.css` swaps the fixed `max-width: 1380px; padding: 0 40px` for `max-width: clamp(720px, 96vw, 1840px); padding: 0 clamp(20px, 3vw, 56px)` — on a 2400px viewport the content shell now occupies ~1840px (~530px of empty side margin → ~280px) without letting tabular line measure get unreadably long on 4K. The audit-page override in `app/audit/audit-styles.css` matches, narrower: `clamp(720px, 92vw, 1480px)` so the archetype hero stays composed. `.archetype-frame` itself gets a `max-width: 1320px` cap with `margin: 0 auto` so the giant Bitcount headline + pink-shadowed border don't stretch past their compositional break-point on huge screens. Prose blocks (`.arch-desc`, `.arch-tagline` at 580px max-width) and side gutters keep readability tight at every step of the clamp. - Subtle polish pass across all 5 pages — same brutalist pixel-craft aesthetic, more carefully made. `app/globals.css` gets a global `::selection` pink wash, an opt-in `:focus-visible` ring system that fires keyboard-only on every interactive element (`a`, `button`, `input`, `.btn`, `.tab`, `.btn-press`), and the existing `.btn` / `.btn-press` / `.tab` / `.panel` transitions are repointed at the `cubic-bezier(0.22, 1, 0.36, 1)` curve already used by `.audit-bar-fill` (away from `transition: all 120ms ease`, which was animating layout properties unintentionally). New: a `.btn:active` press-down, a `.btn-press:active` collapse, a `.tab::after` underline that emerges from center on hover for inactive tabs, and an opt-in `.panel.is-interactive` hover that grows the pink corner brackets from 10px → 16px. `app/projects/page.tsx` gains a section-mast row with the `━━ projects` glyph + folder counter, swaps "Projects" for the lowercased "your agent footprint." headline, and the empty state now renders a 6×6 pixel-grid "no projects" sigil with a 4px hard-offset pink shadow. `app/projects/loading.tsx` staggers its 8 skeleton rows with the same `audit-row-enter` keyframe used by the audit findings table and adds an `aria-busy` "loading…" pip in the mast. `app/project/[name]/page.tsx` migrates from the old shadcn-style `container mx-auto bg-card rounded-lg` chrome to the unified `.report` + `.section` + `.panel` shell — `` becomes a `.btn` with the same `━━` glyph, the path / modified pair is a tight green-eyebrow `
` grid, and the sessions block gets its own section-label mast. `components/navbar.tsx` tightens the slipping-through badge aria (pluralised, `role="status"`, native title tooltip). All new motion respects `prefers-reduced-motion: reduce` — `globals.css` and `audit-styles.css` each got a guard that stills the new tab underline, panel corner growth, button micro-motion, the audit terminal cursor blink, spinner step, marquee shine, and identity dot pulse for vestibular-sensitive users. - - Personalise the `/audit` share copy. The single hardcoded X / LinkedIn template is replaced with five quirky emoji-forward templates for X and five measured professional templates for LinkedIn (`app/audit/_components/share-templates.ts`), each interpolating the run's score, grade, archetype and missing-policy count (with correct singular/plural and clean-run phrasing). One is chosen deterministically per audit via the behaviour-fingerprint seed (`classification.variantSeed`), so the same run always shows the same post while different runs / personas vary. The `ShareDock` now renders these instead of the prior one-liner; the image-attach flow (native share → clipboard → download) is unchanged. New unit test `__tests__/audit/share-templates.test.ts` covers personalisation, clean-run phrasing, X-quirky/LinkedIn-professional tone, and deterministic-but-varied selection. - Rework the `/audit` archetype + score engine so personas are evenly reachable and scores are dynamic rather than locked to a few thresholds. New shared feature layer `src/audit/features.ts` derives everything both consumers need from one pure function (`deriveFeatures`): the full 47-signal `SIGNAL_MAP` (every builtin + detector mapped exactly once, rebalanced — cowboy 20 / explorer 10 / ghost 7 / optimist 6 / hammer 2 / architect 2), a self-calibrated `BASELINE_SHARE` per persona, per-persona **lift** (observed-share ÷ baseline-share), lift entropy, an architect caution-share, an overall fault-rate, and a deterministic behaviour `fingerprint`. `classifyAgent` (`src/audit/archetypes.ts`) becomes a 5-step pipeline that makes all 8 personas reachable: `precision` (no *concentrated* fault tendency — total weighted signal below an absolute floor, or a trace amount thinly spread over a high-volume session; deliberately not a hit-rate, so a real tendency like 8 rm-rf attempts across 2000 clean calls still classifies as its persona rather than collapsing to "clean"), `architect` (the two over-verification detectors dominate — ratio), `goldfish` (high lift entropy across ≥4 clusters — spread), then argmax **lift** over the 5 active-fault personas, with near-ties broken deterministically by the fingerprint. A realistic-population Monte-Carlo (50k simulated users) confirms every persona lands at 10–18% share — no skew — with all 8 present in any 100-user cohort. Ranking by lift instead of raw weighted-hits removes the cowboy surface-area skew (cowboy owns 20 of 47 signals but must now over-index its own baseline to win). `deriveScore` (`src/audit/scoring.ts`) is rewritten to be rate-normalised against a `REF_EVENTS` reference volume and saturating (`cap·(1−e^(−p/k))` per severity bucket instead of hard `min(p,cap)` clips, so the curve is strictly monotonic and no two hit-counts collide on a fixed value), with a small strengths-derived credit so clean agents spread upward; `projectedScore` reuses the same shared penalty curve. `src/audit/index.ts` now derives each builtin row's severity from its name prefix (`severityForBuiltin`) instead of hardcoding `"deny"`, so the score's medium/gentle buckets actually populate. Copy-variant selection is seeded by the behaviour fingerprint (`classification.variantSeed`) so two agents that land on the same primary still see different language, while the same input is byte-identical on every run. New tests: rewritten `__tests__/audit/archetypes.test.ts`, new `__tests__/audit/scoring.test.ts` (monotonicity / volume-normalisation / determinism), and a seeded `__tests__/audit/distribution.test.ts` harness proving all 8 personas are reachable and no single-cluster profile is hijacked by another persona. - Drop the standalone pixel icon from the top navbar (`components/navbar.tsx`) — the brand cluster is now wordmark-only. Logo resolution is also reworked: a new `useBrandLogo` hook attempts a runtime `fetch` of the remote brand URL on mount, blob-wraps the response into an object URL on success, and falls back to the bundled `/logo.svg` (served from `public/`, mirrored at `assets/logos/company/logo.svg`) on any error/non-OK status. The local fallback is also rendered as the initial state so SSR + pre-fetch frames show the brand without a flash. @@ -141,75 +43,81 @@ - Add a `bump-platform-submodule.yml` workflow that pushes a matching `failproofai/oss` gitlink bump to `FailproofAI/platform` `main` on every merge into this repo's `main`, so the monorepo's pinned submodule commit tracks upstream automatically. Uses a `PLATFORM_BUMP_TOKEN` repo secret (fine-grained PAT, contents: read & write on `FailproofAI/platform`) for cross-repo auth, a concurrency group to serialize back-to-back merges, and a rebase-and-retry loop to stay race-safe against humans pushing to platform `main` between checkout and push (#394). - Add a supply-chain security CI gate: OSV-Scanner (`.github/workflows/osv-scanner.yml`) scans the resolved `bun.lock` tree against OSV.dev (GitHub/npm advisories + the OpenSSF malicious-packages feed) on every PR (incl. Dependabot bumps), on pushes to `main`, and weekly, and **blocks on any known-vulnerable or malicious dependency**. Adds a Socket GitHub App behavioral early-warning layer, an `osv-scanner.toml` allow-list for unfixable advisories, a README supply-chain status badge, and a `SECURITY.md` policy/runbook. Remediates the 18 pre-existing transitive advisories surfaced by the new gate (brace-expansion, flatted, minimatch, picomatch, postcss, vite, ws) by refreshing `bun.lock` within range, with `overrides` pinning `postcss` to the patched 8.5.x line (Next.js pins the vulnerable 8.4.31) and holding `eslint-plugin-react-hooks` at main's 7.0.1 so the refresh doesn't also bump the linter (#391). - Stamp `product: "failproofai-oss"` on every PostHog event across all four telemetry channels — hooks/audit (`trackHookEvent`), server (`trackEvent`), web UI (`captureClientEvent`), and npm-lifecycle install/uninstall (`trackInstallEvent`) — so OSS events stay distinguishable from any future hosted surface. The value lives in a single `POSTHOG_PRODUCT` constant in `src/posthog-key.ts`, reused by the three TypeScript channels; the standalone `scripts/install-telemetry.mjs` inlines the same literal because it can't import the TS module at install time. Honors `FAILPROOFAI_TELEMETRY_DISABLED=1` like all other telemetry (#380). +- Expand PostHog telemetry coverage to close the 16 server-side and 12 web-UI gaps surfaced by the May audit (#376). Server-side adds `cli_install_success` / `cli_install_failure` / `cli_uninstall_success` / `cli_uninstall_failure` / `cli_list_invoked` / `cli_parse_error` / `cli_unexpected_error` / `hook_dispatch_error` (CLI lifecycle outcomes in `bin/failproofai.mjs`), `hook_stdin_error` / `hook_payload_parse_error` (hook handler input errors in `src/hooks/handler.ts`), `policy_evaluation_error` (builtin policy crashes in `src/hooks/policy-evaluator.ts`, distinct from the existing `custom_hook_error`), `custom_policy_validation_failed` / `custom_hooks_load_error` / `policy_params_validation_warning` / `scope_validation_failed` / `hook_write_failed` / `multi_scope_warning_shown` / `cli_detection_summary` / `beta_policies_installed` (manager / loader / install-prompt internals), and `first_install` / `version_changed` (lifecycle detection in `scripts/postinstall.mjs` via a new `~/.failproofai/last-version` file). Web-UI adds `policies_tab_switched` / `activity_filter_changed` (debounced) / `activity_row_toggled` / `activity_copy_clicked` / `activity_pagination_changed` / `cli_selection_toggled` / `cli_install_remove_submitted` / `cli_reinstall_submitted` / `policy_config_modal_opened` / `policy_config_modal_closed` / `action_error_displayed` / `hooks_install_from_error_clicked` via `usePostHog()` in `app/policies/hooks-client.tsx`. The deny-/instruct-only condition at `handler.ts:344` (allow-path tracking) is intentionally left unchanged. All events go through the existing helpers (`trackHookEvent`, `trackInstallEvent`, `captureClientEvent`) and honor `FAILPROOFAI_TELEMETRY_DISABLED=1`. +- Add a first-run install prompt on bare `failproofai` invocations. PostHog showed only ~10% of npm-installed users ever ran `failproofai policies --install`; the no-args dashboard launch now detects "zero hooks installed across any detected CLI" and offers to run the existing interactive policy-selection inline (covering all of Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini). Non-TTY contexts (CI, piped invocations) print a short stderr hint and fall through to the dashboard. New `src/hooks/first-run-nudge.ts` module, a guard in `bin/failproofai.mjs` before `launch("start")`, plus four new PostHog events (`first_run_nudge_shown`, `_accepted`, `_declined`, `_skipped_noninteractive`) so the uplift is measurable. Postinstall message extended with a "Next steps" block when the brand-new-user case is detected (`!configured && !registered`). Opt-out via `FAILPROOFAI_NO_FIRST_RUN=1`. +- Add `failproofai audit` command (beta) — retrospectively scan past agent transcripts across all 7 CLIs and report wasteful/risky behavior via the 39 builtin policies + 8 new audit-only detectors (`redundant-cd-cwd`, `prefer-edit-over-read-cat`, `prefer-edit-over-sed-awk`, `prefer-write-over-heredoc`, `sleep-polling-loop`, `find-from-root`, `git-commit-no-verify`, `reread-after-edit`). Outputs ANSI table + markdown report; supports `--cli`, `--project`, `--since`, `--policy`, `--limit`, `--show-examples`, `--report`, `--no-report`, `--json`, `--no-cache`. Per-transcript cache at `~/.failproofai/cache/audit/` auto-invalidates on policy/detector code changes (#377). ### Fixes +- Fix the policies → activity table collapsing on narrow / portrait windows. Columns no longer overlap — each data cell clips with an ellipsis at its own edge and headers stay on one line — and the table holds a readable `min-width` (1280px), scrolling horizontally below that via a themed scrollbar instead of squeezing columns into each other. The badge / long-header columns (decision, event, cli, mode, duration, session) were widened so their content fits — the **mode** column in particular now holds its widest pill (`bypassPermissions`) instead of clipping it mid-word, and the mode pill truncates with an ellipsis + hover tooltip if a longer / custom mode ever appears. +- Fix three translated docs pages that failed the Mintlify deploy parse. `docs/tr/cli/audit.mdx` had a dropped closing backtick that pushed `` out of its inline-code span (parsed as an unclosed JSX tag); `docs/ja/built-in-policies.mdx` and `docs/zh/built-in-policies.mdx` carried translator-injected `{#id}` heading anchors that MDX reads as JS expressions. All three now match the other 12 locales (#455). +- Stop the failproofai server log from repeating the benign Next.js "Failed to find Server Action" deployment-skew error. A browser tab left open across a dashboard rebuild/upgrade POSTs a stale Server Action ID; the client recovers via Next's graceful 404, but the standalone server still logged a 3-line error block to stderr per stale request. The `start` launcher now pipes the server's output through a filter (`scripts/skew-log-filter.ts`) that drops just that block — all other output, and color via `FORCE_COLOR`, passes through untouched; `dev` is unchanged (#456). +- Show login-required copy ("Oops! Login required" / "What's your email?") on the invite-a-friend CTA's shared `AuthDialog` so it reads distinctly from the reminder CTA — content only, the auth flow is unchanged (#453). +- LinkedIn share now opens the feed composer with the post text pre-filled (`feed/?shareActive=true&text=`) instead of the deprecated `share-offsite` `summary` param that LinkedIn ignores (#453). +- Fix the failing **Supply Chain** (OSV-Scanner) CI gate, which was red on every open PR. The dependency tree resolved `vite@8.0.14`, which carries two advisories with no in-tree patch — GHSA-fx2h-pf6j-xcff (CVSS 8.2, high) and GHSA-v6wh-96g9-6wx3 (CVSS 5.5, medium), both fixed in 8.0.16. A plain `bun update vite` only bumped the top-level copy (used by `@vitejs/plugin-react`) and left a nested `vitest`-owned `vite@8.0.14` behind, so the fix pins `vite` to `8.0.16` via `package.json` `overrides` (the mechanism `osv-scanner.toml` recommends) to dedupe the whole tree. The same scan also flagged `undici@7.27.2` — 7 advisories disclosed since the per-PR CI runs, pulled in transitively by the `jsdom` test environment — pinned to `7.28.0` via `overrides`. OSV-Scanner now reports "No issues found" (#446). +- Swap the `/audit` poster PNG export from `html2canvas` to `html-to-image`. html2canvas reimplements CSS in JavaScript and was producing broken dashed borders on the poster's outer rule (Canvas's `setLineDash` doesn't connect cleanly at corners) and a stray pink square cutting through the wordmark's "l" (the `/logo.svg` uses an SVG `` for the "i" character, which html2canvas ignored). `html-to-image` serializes the live DOM into an SVG `` and rasterizes it through the browser's native rendering engine, so dashed borders, SVG masks, gradients, and font metrics render exactly as they do on screen. Implementation in `app/audit/_components/audit-poster.tsx#captureCardBlob` (#435). +- Lock the html-to-image capture's `width`/`height` (and the matching inline `style` override) to the live poster element's `offsetWidth`/`offsetHeight`. html-to-image clones the node without its parent's flex context (the `.poster-section`'s `flex: 1` stretching), so the clone would collapse to intrinsic content width while the canvas inherited the original `offsetWidth` — content rendered anchored to the left of empty space (#435). +- Capture the poster from an off-screen clone instead of the live element. Even with explicit `width`/`height`, the live `.poster` carried its parent's flex context + `margin: 0 auto`, which html-to-image preserved during capture — the content ended up centered inside an oversized canvas, with the poster's left dashed border visible at canvas edge and the right meta clipped. The fix clones the node into a fresh `position: fixed; left: -10000px` wrapper with a fixed width matching `getBoundingClientRect().width`, captures the clone, then removes the wrapper. The clone has no flex parent and no margin auto, so the canvas dimensions match the poster exactly (#435). +- Drop the `━━` glyph prefix and the amber slipping-count badge (`182` etc.) from every navbar tab. The badge surfaced a number that was already prominent on the audit page itself and the prefix was decorative chrome left over from the brutalist redesign. `Navbar` no longer accepts `auditSlippingCount`; `app/layout.tsx` no longer reads the dashboard cache to derive the count (#435). +- Correct the CLI binary name in `how-to-improve-section.tsx`'s install commands. The per-policy install row and the `[install all]` bulk command both emitted `failproof policy add ` — the shipped binary is `failproofai`, so a copied command would fail with `command not found`. Updates the three call sites (header docstring, `bulkInstall()`, and the per-row install string), plus the matching example in `docs/dashboard.mdx#Audit` (#435). +- Calm the `/project/[name]` single-project page chrome. The header dropped the brutalist `━━ back to projects` link, the `● N sessions` green-dot count, the `section-h` display-font title, and the green-eyebrow `path` / `modified` definition list — replaced with a flat back chip, a mono `h1`, and a single inline meta line (`path … · modified … · sessions N`). `SessionsList` was rebuilt with the same calm chrome as the audit page: sharp 1px borders (no rounded corners), dim small-caps labels (`filter by` / `range` / `session id`), pink-outlined active chip, and JetBrains Mono throughout. The file icon goes from `text-primary` colored to dim. Empty state copy switches to the comment voice (`// no sessions found`). New CSS in `app/globals.css` under the `/project/[name]` and sessions-list blocks; tests updated to match the new copy / casing (#435). +- Address CodeRabbit review on the invite flow: `InviteDialog` now accepts an `onUnauthorized` callback and routes 401 responses back through `AuthDialog` (caller in `come-back-better-section.tsx` re-opens the auth flow) instead of dead-ending in a generic inline error. `/api/audit/invite` no longer forwards raw upstream exception text to either telemetry or the client response — surfaces a stable generic message and logs only the bounded `err.name` so internal hostnames / IPs / payload fragments stay server-side (#435). +- Address CodeRabbit review on the audit-poster + come-back-better paths. `audit-poster.tsx#handleShare`'s fallback telemetry no longer reports `status: "success"` when `fallbackMethod === "failed"` — share/capture analytics now correctly distinguish error vs. success. `come-back-better-section.tsx#refreshStatus` preserves the prior auth state on transient `/api/auth/status` failures (5xx, network blips) instead of downgrading to `anon` and clearing a valid reminder — it only falls through to `anon` on the very first probe (still `unknown`) so the cadence buttons unlock when the server is unreachable. Adds `:focus-visible` outlines to the new interactive controls (`.poster-share-btn`, `.cadence-btn`, `.invite-btn`, `.install-all-btn`, `.copy-icon-btn`, `.fix-install-btn`) so keyboard navigation has a perceptible focus indicator (#435). +- Fix the `/audit` first-run audit failing on the first click (a retry worked) and stop capping how much it scans. The run was driven by a synchronous `/api/audit/run` POST that `triggerRun` (`app/audit/_components/rerun-button.tsx`) aborted after the 15s `DEFAULT_FETCH_TIMEOUT_MS` (`lib/fetch-with-timeout.ts`, sized for fast upstream calls), so a cold run (measured ~17s locally) timed out and dropped back to the empty state while the server kept running and warmed the caches — making the second click succeed. The run is now fire-and-forget: the POST starts `runAudit()` as a detached task in the long-lived server process and returns `202` immediately, the client polls `/api/audit/status` with **no duration cap** until it finishes (only a ~10-poll lost-connection backstop stops it), and a server-side run error is surfaced through the status endpoint (`app/api/audit/_state.ts` gains an `error` field + `finishRun(error)`, and its 5-min lock auto-expiry — which would have prematurely "finished" a long run — is removed along with the route's `maxDuration = 120`). The default scan window also drops from 30 days to the user's entire history, so an audit runs over every session regardless of how long it takes; the empty-state CTA and `run-progress` copy update from "10–30s" to "may take a while". New tests cover the fire-and-forget route, unbounded polling, and the run-state machine (`__tests__/api/audit-run-route.test.ts`, `__tests__/audit/rerun-button.test.ts`, `__tests__/api/audit-state.test.ts`) (#434). +- Remove the top-of-page `[ re-audit ]` bar from `/audit` (added in #428). On the empty/expired path it stacked a second "run an audit" CTA directly above the existing first-run panel — the duplication read as broken — and on loaded reports the `audited 3d ago` / `expires in 14h` strip earned little, so the whole `TopAuditBar` component (`app/audit/_components/top-audit-bar.tsx`), its `.top-audit-bar*` CSS, and its test (`__tests__/audit/top-audit-bar.test.tsx`) are deleted. Re-auditing still works from `[ run audit ]` on the empty state and `[ re-audit now ]` at the bottom of a report; the sticky `AuditProgressStrip`, soft-refresh-on-success, and the 7-day cache TTL are untouched, and the per-report generation timestamp still renders in the footer. Past the TTL, `/audit` now falls through to the standard empty state instead of a dedicated `audit expired` banner. `RerunSource` drops its now-dead `"top_bar"` variant; `docs/dashboard.mdx` and `docs/cli/audit.mdx` updated to match (#431). +- Make `/audit` re-audit force a genuinely fresh scan instead of silently returning the cached result. The `[ re-audit now ]` button — and the shared `startRerun` handler behind it — now sends `noCache: true` through `triggerRun` → `paramsToBody` → the `/api/audit/run` route (which already honored `noCache`), so re-audit bypasses the per-transcript cache (`src/audit/cache.ts`) and re-scans every transcript from scratch rather than returning the identical cached result when nothing changed on disk. The fresh result overwrites the dashboard cache on success; a failed re-audit leaves the prior cache (and report) intact. The empty-state first-run CTA deliberately stays on the fast cached path — it's a first scan, not a re-audit. `ScanParams` / `paramsToBody` gain an optional `noCache`; `paramsToBody` is exported and covered by a new `__tests__/audit/rerun-button.test.ts` (#432). +- Fix the `/audit` archetype classifier collapsing nearly every agent onto **the goldfish**. PR #426's GOLDFISH_ENTROPY 0.75 → 0.70 retune and the move to an empirical-firing-share `BASELINE_SHARE` were both correct, but they exposed a latent flaw in the goldfish gate: normalised entropy of the LIFT vector cannot distinguish "every cluster fires at typical ambient rate" (all lifts ≈ 1.0 → entropy pegs at the max) from "real scatter" (multiple clusters genuinely over-indexing → also high entropy). A 765-transcript / 42k-event local audit measured every active-fault cluster sitting at 0.96–1.04 of baseline — no concentration anywhere — yet the classifier returned goldfish because entropy 0.91 cleared the 0.70 gate. Fix: add `GOLDFISH_MIN_SECOND_LIFT = 1.3` and require the second-highest cluster lift to clear it, so goldfish only fires when at least TWO clusters are genuinely above baseline (the actual definition of scatter); uniform-at-baseline profiles fall through to the existing argmax. New `secondLift` feature on `AuditFeatures`. New regression block in `__tests__/audit/distribution.test.ts` reproduces the uniform-at-baseline lift shape and asserts it never auto-classifies goldfish; the now-out-of-date "must not be explorer" assertion on the representative-ambient agent is rewritten to verify the lift-normalisation mechanism (explorer's raw dominance → lift < 2) instead of forbidding a specific outcome; the ambient-cohort explorer-share bound is relaxed from 20% → 50% to reflect the post-fix distribution (#429). +- Stop the Next.js 16 dev-overlay "signal is aborted without reason" console warning at `lib/fetch-with-timeout.ts:25`. The previous implementation called `controller.abort()` with no argument — when the 15s timer fired (or, in dev hot-reload, when a stale closure's polling iteration ran after the page navigated away) the resulting `AbortSignal` carried the default bare-DOMException reason that Next.js 16's React-dev-overlay surfaces as the warning. While there, fixes a latent bug in the same function: `{ ...init, signal: controller.signal }` was silently dropping any caller-supplied `init.signal` (because the spread placed it before the overwrite), so component-unmount cancellations could not stop in-flight fetches. New implementation replaces the manual `AbortController + setTimeout` pair with the platform `AbortSignal.timeout()` — which aborts with a typed `DOMException(..., "TimeoutError")` — composed with the caller signal via `AbortSignal.any()` (Node 17.3+/20.3+ respectively, both covered by Next.js 16's Node >= 20.9 floor; Chrome 116+, Firefox 124+, Safari 17.4+). `isAbortError` is hardened to duck-type on `name` so it correctly classifies cross-realm errors and jsdom's polyfilled DOMException (which is not `instanceof Error`) — production callers (`requestLoginCode`, `triggerRun`, `auth-dialog.tsx`) keep their existing timeout-vs-network discrimination. `readCachedTranscriptResult` now uses `Number.isFinite(entry.cachedAt)` (not `typeof === "number"`) so a malformed JSON `Infinity`/`NaN` can't pin a stale entry as valid forever; `readDashboardCacheMeta` gates on schema version + parseable timestamp before surfacing the entry as "expired" so a schema-incompatible cache falls through to the first-run empty copy rather than triggering the wrong banner. New `__tests__/lib/fetch-with-timeout.test.ts` covers happy path, composed-signal forwarding, TimeoutError firing, external-signal cancellation, already-aborted short-circuit, and duck-typed name matching (#428). +- Fix the `/audit` archetype classifier collapsing nearly every agent onto **the explorer**. The lift denominator (`BASELINE_SHARE` in `src/audit/features.ts`) was derived from `SIGNAL_MAP` *catalog weights* — each persona's share of the catalog — on the theory that lift would cancel cowboy's surface-area advantage. But catalog share ≠ real firing rate: the ambient policies feeding `explorer` (env access + secrets-in-tool-output) and `architect` (`reread-after-edit` / `redundant-cd-cwd`) fire on benign, volume-scaled activity in essentially every session, far above their catalog share, so explorer's lift stayed > 1 for almost everyone and won the active-fault argmax. A real-corpus audit (674 transcripts / 41k events) measured explorer at ~60% of all mapped signal against a 22% catalog baseline. Fix: (1) drop `block-read-outside-cwd` from `SIGNAL_MAP` — it is `defaultEnabled: false` and fires on ubiquitous ambient reads, ~37% of all mapped signal on its own; (2) replace the catalog-weight `BASELINE_SHARE` with an **empirical firing-share** baseline (floored at `MIN_BASELINE` so a rare cluster can't explode to a huge lift off one hit), so a persona now wins only when it fires *more than typical*; (3) retune `GOLDFISH_ENTROPY` 0.75 → 0.70 for the reshaped lift vector. The synthetic population now spreads all 8 personas across ~8–20% (explorer down from a forced ~100% to ~13%). New regression block in `__tests__/audit/distribution.test.ts` reproduces the real ambient profile (explorer as the largest *raw* cluster) and asserts it is never auto-classified explorer and that an ambient cohort never collapses onto one persona; the two `__tests__/audit/archetypes.test.ts` lift examples are rewritten for the empirical baseline (#426). +- Fix the wrong site URL embedded in every `/audit` social-share template. `app/audit/_components/share-templates.ts` and `app/audit/_components/share-dock.tsx` had `SITE_URL = "https://failproof.ai"` (and one bare `failproof.ai` mention in the 4th X template) — the actual marketing domain is `befailproof.ai`, so every shared post linked to a dead URL. Updates both `SITE_URL` constants + the bare mention to `befailproof.ai`, and tightens `__tests__/audit/share-templates.test.ts` to assert `befailproof.ai` so a future regression to `failproof.ai` fails (#425). +- Stop the `/audit` ShareDock's "share on X" / "share on LinkedIn" buttons from opening the Windows OS share dialog on desktop Chromium / Edge. `lib/share-card.ts` `shareCardNative()` now early-returns `false` on non-mobile devices (detected via `navigator.userAgentData.mobile` with a UA-string fallback for Safari / Firefox + a touch-points check for iPadOS 13+) so the existing clipboard + `x.com/intent/tweet` / `linkedin.com/sharing/share-offsite` fallback runs instead. On mobile, the system share sheet still fires as before because it actually surfaces the X / LinkedIn apps as targets. +1 test for the desktop short-circuit, existing happy-path tests opt into mobile via `navigator.userAgentData.mobile = true` (#425). - Fix the `bump-platform-submodule.yml` workflow's `Bump failproofai/oss gitlink and push` step, which failed on the merge of #397 with `printf: write error: Broken pipe`. The step's `SUBJECT_LINE=$(printf '%s\n' "${COMMIT_SUBJECT:-Manual trigger}" | head -n 1)` raced under `set -o pipefail`: `head -n 1` closed the pipe after the first line of the squash-merge commit body, `printf` died with SIGPIPE on the next write, and the pipeline propagated the non-zero exit. Replace the pipe with pure bash parameter expansion (`SUBJECT_LINE=${COMMIT_SUBJECT:-Manual trigger}; SUBJECT_LINE=${SUBJECT_LINE%%$'\n'*}`) so no subprocess pipe is involved and `pipefail` has nothing to fail on. - Drop the literal `━━` escape sequences that were rendering as visible text inside the three `.stat-cell` eyebrow labels on the `/policies` activity tab (`app/policies/hooks-client.tsx:297,302,307`). JSX text content doesn't interpret `\uXXXX` escapes — those only work inside JS string literals — so the railroad-track glyph was painting as eight raw characters. The eyebrow rule + green accent color already give the captions enough visual weight; the decorative glyph was net negative. - Tier-C polish + efficiency pass from the deferred-review plan. **`app/audit/_components/audit-dashboard.tsx`** — `detectorsTriggered` + `missing` were two independent O(N) scans over `result.results` per render; merged into a single `useMemo` keyed on `result`. The scroll handler now coalesces events through `requestAnimationFrame` so reading `scrollHeight` (a layout-reflow trigger) fires at most once per frame instead of dozens per second during a fast scroll. **`app/audit/_components/policies-section.tsx`** — wrapped `buildPolicyCards(result)` in `useMemo`; previously it rebuilt a `Map + Set + sort` aggregation on every parent re-render. **`app/audit/_components/identity-section.tsx`** — wrapped `pickArchetypeVariant(archetypeKey, seed)` in `useMemo`; previously re-hashed the seed string and ran four `xmur3` mix passes per axis on every IdentitySection state change (the share buttons toggle `downloadState` which rerenders us 4× per click). **`app/audit/_components/return-section.tsx`** — added a 5s throttle to the focus + visibilitychange handlers' `refreshStatus()` calls so rapid alt-tabbing doesn't thrash `/api/auth/status` (two disk reads each); also extracted a `` helper that takes a `showSetReminder` slot so the authed and anon branches stop duplicating the `[ re-audit now ]` + `[ install policies ]` buttons (they had already drifted on `marginTop` styling). **`bin/failproofai.mjs`** — `policy remove ` no longer threads `--beta` into the manager call as `betaOnly`; the manager only used `betaOnly` for telemetry tagging (`removal_mode: "beta_policies"`), so passing `--beta` to `policy remove` was a mislabel that produced ghost "beta removal" events in PostHog without affecting which policy was actually removed. The flag is dropped from this path so `beta_only: false` is emitted unconditionally — match the actual semantics. No tests changed; 1769 still pass. - - Tier-B refactor pass from the deferred-review plan. Consolidates the duplication the prior review surfaced before it can cause another drift (the prior PR already shipped `REQUEST_TIMEOUT_MS=15s` on the client and `=10s` on the server with no comment tying them together). **`lib/fetch-with-timeout.ts`** — new shared module exporting `fetchWithTimeout(input, init, timeoutMs)` and an `isAbortError(err)` predicate. Replaces three byte-equivalent implementations: the client-side helpers in `app/audit/_components/auth-dialog.tsx` + `rerun-button.tsx` (15s default) and the inline `err.name === "AbortError" || err.name === "TimeoutError"` check inside `lib/auth/api-server-client.ts`'s server-side wrapper (which keeps its `trackEvent`-on-timeout side-effect but delegates the predicate). Also pulls `app/audit/_components/return-section.tsx` onto the same `isAbortError` predicate. **`lib/atomic-write.ts`** — new shared module exporting `writeJsonAtomically(filePath, value, { mode, dirMode })`. Replaces the near-identical temp-file-then-rename dances in `lib/auth/auth-store.ts` (for `auth.json` + `next-audit.json`) and the inline version in `src/audit/dashboard-cache.ts` (added in the prior PR). Single helper means any future on-disk JSON writer gets the same crash-safety + perm-reassertion logic without copy-pasting. **`app/audit/_components/rerun-button.tsx`** — deleted the unused `` React component (exported but never rendered by anyone — the rerun UI is integrated into `return-section.tsx` and `empty-state.tsx` which call `triggerRun` directly). The deletion also drops the stale `lucide-react` / `usePostHog` / `cn` imports and a duplicate `audit_rerun_failed` capture branch that would never fire from this file. **`lib/telemetry.ts`** — `initTelemetry()` now wraps its **entire** body in a single outer try/catch with a "never throws" guarantee documented on the function. Removed the now-redundant per-route `try { await initTelemetry(); } catch {}` wrapper from `app/api/auth/login-verify/route.ts` (and the file comment now points future readers at the helper-level contract so they don't re-add a defensive wrapper). Net delta: ~30 LOC deleted across the touched files plus 2 new shared modules. - - Tier-A correctness pass from the deferred-review plan. **`lib/auth/auth-store.ts`** — `getValidAccessToken` and `whoAmI`'s post-401 retry now dedup in-flight refresh-token exchanges through a `Map>`. Without it, two concurrent callers (the `/api/auth/status` poll + an in-flight `/api/auth/reminder` POST is the canonical case) could each call `refreshAccessToken` with the same refresh token; the api-server treats the second as token-replay and revokes every session for the user (silent logout). **`app/api/audit/_state.ts`** — the run-lock now auto-expires after 5 min (matches the rerun-button's `MAX_POLL_MS`), so a SIGKILL / OOM / uncaught throw between `tryAcquireRun` and `releaseRun` can no longer 409 every subsequent POST until process restart. The header comment honestly calls out the remaining multi-worker limitation (cross-process locking needs external storage; the OSS dashboard expects a single worker). **`src/audit/cache.ts`** — added a `CACHE_SCHEMA_VERSION = 2` constant included in the cache-key check; pre-PR per-transcript cache entries are now rejected on read so the new v2 `TranscriptAuditResult` fields (`cwd`, `eventsScanned`) get populated correctly instead of silently rendering as `cwd: undefined` / `eventsScanned: 0`. **`lib/auth/api-server-client.ts`** — `decodeJwt` now strictly validates header and payload against `/^[A-Za-z0-9_-]+={0,2}$/` before calling `Buffer.from(s, "base64url")`; the legacy `Buffer.from` silently truncates illegal chars rather than throwing, so a corrupted JWT could decode to garbage that happens to parse as JSON with a numeric `exp` field and produce synthetic "valid" claims. Also added a manual `AbortSignal.any` fallback in `timeoutSignal()` so the caller-supplied `extra` signal isn't dropped on runtimes without native `AbortSignal.any` (Node < 20.3, older Bun). **`docs/docs.json`** — added `cli/auth` and `cli/audit` to the Mintlify CLI nav group so both the new auth subcommand doc and the rewritten audit doc are reachable from the sidebar (the docs existed on disk but weren't discoverable). **+10 tests:** `__tests__/lib/auth-store-refresh.test.ts` (3 — concurrent refresh dedup, retry on failure, sequential calls), `__tests__/api/audit-state.test.ts` (5 — acquire/release contract, auto-expiry, multi-release no-op), `__tests__/lib/api-server-client.test.ts` (2 — illegal-base64url rejection, empty-payload rejection). 1769 tests pass total. - - Max-effort code-review hardening pass on the same branch. **`src/audit/findings.ts:293`** — corrected `failproof policy add ${slug}` → `failproofai policy add ${slug}` so the "fix" install command on every finding card is actually copy-pasteable. **`app/layout.tsx:25`** — fixed `icons.icon` pointer from the deleted `/icon.png` to the live `/public/icon.svg` so the dashboard favicon stops 404'ing. **`lib/auth/auth-store.ts:246`** — `whoAmI()`'s 401-retry catch now only wipes `auth.json` on an unambiguous 401, matching `getValidAccessToken`'s contract; a transient timeout / 5xx during the post-refresh `/me` no longer throws away the freshly-written valid tokens. **`app/api/auth/{login-request,login-verify}/route.ts`** — `AuthApiError` from a client-side timeout has `status: 0`, which `NextResponse.json(..., { status: 0 })` rejects with `RangeError`; both routes now map any out-of-range status to 504 so the browser sees a real status code instead of a 500 stack trace. **`src/audit/index.ts:311`** — the per-transcript scan error fallback now emits the v2-required `cwd: ""` and `eventsScanned: 0` fields so errored transcripts don't silently drop from `projectsScanned` / `eventsScanned` aggregates. **`src/audit/dashboard-cache.ts:73`** — `writeDashboardCache` now writes atomically (temp file → rename) so a concurrent `readDashboardCache` from the 1s status poll can't observe a torn JSON file; the directory is created with mode `0700` and `DASHBOARD_CACHE_SCHEMA_VERSION` is bumped to `2` (matching the `AuditResult.version 1→2` bump) so stale v1 caches are properly rejected to the empty state instead of rendering as "0 tool calls". **`app/api/auth/reminder/route.ts:117`** — added an upper-bound guard on `body.at` (rejects values > `now + MAX_OFFSET_DAYS`) that catches the common `Date.now()` (ms) vs unix-seconds foot-gun — would otherwise persist a year-55000 reminder. **`lib/auth/api-server-client.ts:97`** — `parseError` now clamps `Retry-After` to `[0, 86400]` so a misbehaving server can't tell the dashboard to "wait -3600s" or "wait 1e20s". **`app/audit/_components/auth-dialog.tsx:144`** — `requestCode` accepts an `{ isResend: true }` opt; on resend failures it now shows the error inline on the OTP step instead of bouncing the dialog back to the email step (the previously-sent code may still be usable). **`app/audit/_components/return-section.tsx:175`** — removed a duplicate `audit_set_reminder_clicked` capture that fired one line after `audit_reminder_cta_clicked` with the same property bag (was splitting funnels). **`app/audit/_components/audit-dashboard.tsx:226`** — renamed `const window = inferWindow(params)` → `scopeWindow` so future maintenance can't accidentally hit `"30d".location` via the shadowed global. **`__tests__/lib/api-server-client.test.ts:122`** — the `cancelReminder` test now also asserts the `Authorization: Bearer ` header so a regression there can't ship silently. **`docs/cli/audit.mdx`** — replaced the docs for the removed `failproofai audit` CLI subcommand with a description of the `/audit` dashboard page (the audit functionality moved to the dashboard in this PR but the doc still told users to run `failproofai audit`). **`docs/cli/auth.mdx`** — updated the canonical examples from the legacy `auth --login` / `--logout` / `--whoami` flag form to the current subcommand form (`auth login` / `logout` / `whoami`), with a note that the legacy form is still accepted as an alias. - - CodeRabbit-flagged hardening pass across `/audit` + `/auth`. `app/api/auth/login-verify/route.ts` wraps `initTelemetry()` in its own `try/catch` so a telemetry-init failure can no longer turn a valid OTP verify into a 500. Both the dashboard route and `src/auth/cli.ts` drop `user_email` from the `audit_user_identity_linked` event payload — `user_id` + `local_random_id` are sufficient for anon→authed session stitching and shipping raw PII to analytics was avoidable. `bin/failproofai.mjs`'s typo-suggestion `primary` array now includes `policy` alongside `policies` / `auth` / `--*` so closest-match no longer steers users at the wrong subcommand. `src/audit/dashboard-cache.ts` explicitly rejects `params: null` / `result: null` during structural validation (`typeof null === "object"` was letting those slip through to the renderer). `app/audit/_components/return-section.tsx`'s `persistReminder()` now (1) flips local auth state back to `anon` on a 401 from `/api/auth/reminder` so the UI doesn't get stuck on an authed panel whose actions silently no-op, and (2) wraps the fetch in a 10s `AbortController` so a hung route can't permanently disable the `[ set a reminder ]` CTA. `app/audit/_components/rerun-button.tsx`'s `triggerRun` + status poll now use a `fetchWithTimeout(15s)` wrapper so a single stalled request can't hang the poll loop indefinitely; per-request timeouts surface as `RerunError.kind === "timeout"` distinct from `"network"`. `app/audit/_components/auth-dialog.tsx`'s `requestCode` + `verifyCode` both wrap their fetches in `fetchWithTimeout(15s)` and surface `AbortError` as a user-readable "request timed out" string so a hung api-server can no longer wedge the modal in `busy` state. - - Audit + auth hardening sweep across the dashboard and CLI surfaces. `lib/auth/auth-store.ts` now writes `auth.json` and `next-audit.json` atomically (temp-file-then-rename with the same `0600` perm enforcement on both temp and final paths) so a concurrent write or crash can no longer leave a half-written / truncated session file behind. `lib/auth/api-server-client.ts` puts a 10s `AbortSignal.timeout` on every `/v0/auth/*` and `/v0/reminders` fetch — a wedged DNS resolver, a hung api-server, or a stalled refresh no longer pins the CLI or a dashboard request indefinitely; timeouts now surface as `AuthApiError(code: "timeout")` so callers can render the same "could not reach the api-server" copy already wired for transport failures. `src/auth/cli.ts` `runLogin()` now treats `auth.json` as stale when its `refresh_expires_at` claim has lapsed locally — instead of bouncing the user with "already signed in" against a file the server would reject on the first /me, it wipes the stale file and walks through the OTP flow again (telemetry now carries `replaced_stale: true` on the resulting `_login_started` event). `app/api/auth/reminder/route.ts` distinguishes empty body (defaults to a 7-day offset) from malformed JSON / non-object body (now 400 with a `validation_error` code instead of silently coercing to `{}` and writing a default-offset reminder). `app/api/audit/run/route.ts` likewise rejects `null`, arrays, and primitives in the request body with a 400 instead of letting `sanitize(null)` 500 — guards both the JSON.parse path and the post-parse shape check. `app/audit/_components/rerun-button.tsx` now `throw`s a `RerunError` on POST failure / network failure / poll-loop timeout so the button can render a distinct "rerun failed — retry" pink-border state for 4s instead of pretending the run completed; `triggerRun` is now typed as `Promise` that explicitly throws, so the EmptyState CTA can adopt the same UX. `app/audit/_components/run-progress.tsx` caps the fake-progress bar at 90% and swaps the last-stage detail to "finishing up…" so a run that genuinely takes 30s no longer paints 4/4 + 100% at the 16s mark. `app/audit/_components/identity-section.tsx` LinkedIn-share copy "every key policy is live" now requires both `grade === "A"` AND `missing === 0` (previously any A-grade triggered the verbatim "every key policy is live" copy even when there were unenabled prescribed policies). `src/audit/dashboard-cache.ts` adds an explicit `schemaVersion` field on the cached entry; entries written by older code versions are now rejected as null instead of being rendered against the wrong shape. `assets/audit/archetypes.jsx` `Sigil()` normalizes an unknown archetypeKey once at the top so the index lookup uses the same safe key as the sigil grid (previously the sigil lookup had a fallback but `ARCHETYPES[archetypeKey].index` crashed on unknown keys). `app/audit/_components/score-section.tsx` drops the `useMemo` around `pointsToNext` that tripped `react-hooks/preserve-manual-memoization` — replaced with a plain `pointsToNextFor(score)` scan of 5 thresholds. - Treat GitHub `neutral` check-run conclusions as non-failing in the `require-ci-green-before-stop` policy (e.g. Socket Security: Pull Request Alerts when the head branch is from an outside contributor and Socket can't process it). Previously the policy treated anything other than `success` / `skipped` / `cancelled` as failing, producing false-positive Stop blocks on PRs whose only "non-green" check was an explicit `neutral` (#410). - Fix the `bump-platform-submodule.yml` workflow's first post-merge push, which failed with `fatal: could not read Username for 'https://github.com'`. The `persist-credentials: false` hardening from #394 left the cross-repo `git push`/`fetch` unauthenticated, and the inline `Authorization: bearer …` extraheader only authenticates GitHub's REST API — git-over-HTTPS smart-protocol expects Basic auth with `x-access-token:`. Switch to a base64-encoded Basic header (matching `actions/checkout`'s own internal extraheader format) so the push and the rebase-and-retry fetch in the loop both authenticate (#395). +- Remove orphan `exospheresmall` token from the Next.js proxy matcher in `proxy.ts` — no asset by that name exists in the repo. +- Restore `FailproofAI` org casing in `package.json` `homepage`, `repository.url`, and `bugs.url` (was lowercased to `failproofai/failproofai` during the org rename). npm provenance verification compares the field byte-for-byte against `${{ github.repository }}` (`FailproofAI/failproofai`) and rejected `0.0.11-beta.1` publish with `422 Error verifying sigstore provenance bundle: Failed to validate repository information`. GitHub URL routing is case-insensitive so this only affected provenance verification, not link resolution. +- Dashboard `/policies` activity-tab subheading: replace the hardcoded "Policy evaluations for Claude" with a dynamic list of installed CLIs ("Policy evaluations across Claude Code, Cursor"), collapsing to "across N agents" when 4 or more are installed and falling back to "Policy evaluations" when none are. Reads from the existing `getHooksConfigAction()` payload — no new server work. The text was a leftover from when failproofai only supported Claude Code and was inaccurate against the now-7-CLI surface (Claude, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) (#358). + +### Dependencies +- Add `@mdx-js/mdx` as a dev dependency, used by the new `validate:mdx` docs parse check (#455). +- Consolidate the open Dependabot bumps #436–#445 into this single PR, each landing at the exact version its PR proposed: `next` 16.2.7 → 16.2.9 (#436), `eslint` 10.4.1 → 10.5.0 (#437), `@tailwindcss/postcss` 4.3.0 → 4.3.1 (#438), `tailwindcss` 4.3.0 → 4.3.1 (#439), `@anthropic-ai/sdk` 0.102.0 → 0.104.2 (#440, the one bump that also moves a `package.json` range, `^0.102.0` → `^0.104.2`), `vitest` 4.1.8 → 4.1.9 (#441), `lucide-react` 1.17.0 → 1.18.0 (#442), `@tanstack/react-virtual` 3.14.2 → 3.14.3 (#443), `posthog-node` 5.36.5 → 5.37.1 (#444), and `eslint-config-next` 16.2.7 → 16.2.9 (#445). The ten superseded PRs are closed in favour of this one (#446). +- Add `html-to-image@^1.11.13` for the audit-poster PNG export. Replaces (but does not remove) `html2canvas` — the latter remains for any non-audit screenshot path still using it (#435). +- Reconcile `bun.lock` with the pinned `@types/node` / `@types/react` / typescript versions so CI's `bun install --frozen-lockfile` step succeeds (#434). +- Swap the Vitest DOM environment from `happy-dom` to `jsdom` (`vitest.config.mts`, `package.json`, 15 `docs/*/testing.mdx`). happy-dom is single-maintainer and had a 2024 critical CVE; jsdom has 6 maintainers, ~7× the weekly downloads, and a perfect Snyk maintenance score. Test suite (1691 tests across 82 files) stays green on jsdom (#419). +- Bump `tailwindcss` 4.2.4 → 4.3.0 (#357) +- Bump `react` 19.2.5 → 19.2.6 (#357) +- Bump `react-dom` 19.2.5 → 19.2.6 (#357) ### Tests - Add coverage for previously untested audit + auth modules: `__tests__/audit/archetypes.test.ts` (zero-signal → precision, broad-spread → goldfish, secondary ≥40% promotion vs authored fallback, deterministic variant picker), `__tests__/audit/findings.test.ts` (ranking, zero-hit drop, detector→policy remapping, `alsoCoveredBy`, `alreadyEnabled` enable-set + builtin-config heuristics, relative-time + missing `lastSeen` fallback), `__tests__/audit/strengths.test.ts` (clean-rate headline, credential / retry / push-to-main absence gates, 5-item cap, fallback row when too few qualify), and `__tests__/lib/auth-store.test.ts` (round-trip, mode 0600, atomic write leaves no `.tmp` siblings, shape-mismatch rejection, reminder scoping, atomic overwrite). +40 tests; full suite at 1741 passing. ### Docs +- Replace the community Slack invite with Discord (`https://discord.gg/2zjBZP7yQJ`) everywhere it's user-facing: the `failproofai --help` LINKS banner, the dashboard "Reach Us" dropdown, and the README community badge (English + 14 translations). The Slack *webhook notification example* (`examples/policies-notification.js`) is intentionally left as-is — it's a feature integration, not a community link. +- Reword the `/audit` invite card ("Share with friends" / "wanna know how your friends' agents score?") and grammar-pass the X/LinkedIn share templates (article/adverb/coordination/comma-splice fixes only — no behavioral or structural change). +- Document the `failproofai audit` command and `npx -y failproofai audit` usage in `docs/cli/audit.mdx`, and refresh the `docs/dashboard.mdx` Audit section to the current poster flow (#453). +- Point the docs community anchor (`docs.json`) and the CLI launch banner at the Discord server instead of the Slack invite (#453). +- Update `docs/dashboard.mdx`'s `### Audit` section to describe the new 5-section flow (poster + strengths + quirks + how to improve + come back better), replacing the prior 6-section description (identity + show off + strengths + score+leaderboard + findings + prescribed policies+return loop). Calls out the html-to-image swap so the documented behaviour matches what users see when they click `download poster` (#435). +- Update `docs/dashboard.mdx`'s description of the `come back better` perks card to document the new `invite a friend` flow (modal → `/api/audit/invite` → upstream `/v0/invite` → one email per recipient with sender Cc'd) — replacing the prior "progress bar + invite a friend CTA" description (#435). +- Update `docs/dashboard.mdx` and `docs/cli/audit.mdx` to reflect the 7-day TTL on both audit caches and the new top-of-page `[ re-audit ]` bar (last-audit timestamp, amber "expires in Xh" chip in the final 24h of the window, sticky pink progress strip during the run with `RerunError.kind`-keyed copy on failure, soft-refresh on success instead of `window.location.reload()`). The Caches section in `docs/cli/audit.mdx` is reworded so `cachedAt` is described as TTL metadata (not part of the cache key, which stays `(mtime, size, engineVersion, detectorVersion)`). The Findings example command in `docs/dashboard.mdx` is fixed from `failproof policy add` to the correct `failproofai policy add`. The 14 translated mirrors (`docs/{zh,pt-br,it,he,hi,…}/...`) will pick the changes up via the existing translation job (#428). +- Document that contributors must build the project before the in-repo dev hooks work — the hooks resolve the `failproofai` import against the compiled `dist/index.js`, so a missing or stale `dist/` produces `Cannot find package 'failproofai'` hook errors. Adds a "Build before the in-repo dev hooks will work" section to `CONTRIBUTING.md` (with the fast `dist/index.js`-only build command for iterating on policies) and a build-first callout to the README `Contributing` section (#426). - Extend `docs/cli/auth.mdx` with a "Persistent re-audit reminder" section covering the new `~/.failproofai/next-audit.json` file and the `GET / POST / DELETE /api/auth/reminder` dashboard endpoint that backs the `/audit` `[ set a reminder ]` CTA — including the file shape, the per-email scoping rule, and the 7-day default offset. - Document the new `failproofai auth --login | --logout | --whoami` subcommand in a dedicated `docs/cli/auth.mdx` page (mirrors the style of `cli/audit.mdx`: usage block, sign-in / sign-out / whoami sections, on-disk `auth.json` shape, env-var table, and a short troubleshooting list for the common `Could not reach the api-server` / `Rate limited` / `Code rejected` cases). Add an Authentication section to `docs/cli/environment-variables.mdx` covering `FAILPROOF_API_URL` (override the api-server base URL) and `FAILPROOFAI_AUTH_DIR` (override where `auth.json` is stored). i18n mirrors left for the translation-sync workflow. - Add `docs/.vale.ini` and a `Mintlify` Vocab accept-list to suppress noisy `Mintlify Validation (exosphere) - vale-spellcheck` CI failures. Disables `Vale.Spelling` on the 14 translated language subdirs (`ar/`, `de/`, …, `zh/`) and `i18n/`, since running an English dictionary over auto-translated content produces only noise; keeps spellcheck active on the canonical English `*.{md,mdx}` files with a project Vocab covering brand names (`failproofai`, `Claude`, `Codex`, …), CLI tooling (`npx`, `bunx`, `gcloud`, `systemctl`, …), and Claude Code event names (`PreToolUse`, `SessionStart`, …) (#410). - Update the README logo (EN + 14 translated READMEs) from `logo-wordmark.png` to the new `fa_updated_full.svg` wordmark served on befailproof.ai (#387). - Change the README supply-chain badge from the live OSV-Scanner workflow-status badge (`supply chain: passing`) to a static `supply chain: secure` badge, still linked to the workflow runs (#393). - Add a Bitcount Prop Single font template under `templates/bitcount-font/` (next/font loader + framework-agnostic CSS with tunable knobs) capturing the befailproof.ai title treatment for reuse. Bundles a self-hosted static instance (`bitcount-prop-single.woff2`, wght 417 + ELSH 55 baked in) so the rounded-square shape renders consistently on every device, avoiding Google Fonts' CDN serving a static default-instance to mobile user-agents (where `font-variation-settings: "ELSH" 55` silently no-ops and the title renders as round dots) (#390). - -## 0.0.11-beta.2 — 2026-05-21 - -### Features -- Expand PostHog telemetry coverage to close the 16 server-side and 12 web-UI gaps surfaced by the May audit (#376). Server-side adds `cli_install_success` / `cli_install_failure` / `cli_uninstall_success` / `cli_uninstall_failure` / `cli_list_invoked` / `cli_parse_error` / `cli_unexpected_error` / `hook_dispatch_error` (CLI lifecycle outcomes in `bin/failproofai.mjs`), `hook_stdin_error` / `hook_payload_parse_error` (hook handler input errors in `src/hooks/handler.ts`), `policy_evaluation_error` (builtin policy crashes in `src/hooks/policy-evaluator.ts`, distinct from the existing `custom_hook_error`), `custom_policy_validation_failed` / `custom_hooks_load_error` / `policy_params_validation_warning` / `scope_validation_failed` / `hook_write_failed` / `multi_scope_warning_shown` / `cli_detection_summary` / `beta_policies_installed` (manager / loader / install-prompt internals), and `first_install` / `version_changed` (lifecycle detection in `scripts/postinstall.mjs` via a new `~/.failproofai/last-version` file). Web-UI adds `policies_tab_switched` / `activity_filter_changed` (debounced) / `activity_row_toggled` / `activity_copy_clicked` / `activity_pagination_changed` / `cli_selection_toggled` / `cli_install_remove_submitted` / `cli_reinstall_submitted` / `policy_config_modal_opened` / `policy_config_modal_closed` / `action_error_displayed` / `hooks_install_from_error_clicked` via `usePostHog()` in `app/policies/hooks-client.tsx`. The deny-/instruct-only condition at `handler.ts:344` (allow-path tracking) is intentionally left unchanged. All events go through the existing helpers (`trackHookEvent`, `trackInstallEvent`, `captureClientEvent`) and honor `FAILPROOFAI_TELEMETRY_DISABLED=1`. -- Add a first-run install prompt on bare `failproofai` invocations. PostHog showed only ~10% of npm-installed users ever ran `failproofai policies --install`; the no-args dashboard launch now detects "zero hooks installed across any detected CLI" and offers to run the existing interactive policy-selection inline (covering all of Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini). Non-TTY contexts (CI, piped invocations) print a short stderr hint and fall through to the dashboard. New `src/hooks/first-run-nudge.ts` module, a guard in `bin/failproofai.mjs` before `launch("start")`, plus four new PostHog events (`first_run_nudge_shown`, `_accepted`, `_declined`, `_skipped_noninteractive`) so the uplift is measurable. Postinstall message extended with a "Next steps" block when the brand-new-user case is detected (`!configured && !registered`). Opt-out via `FAILPROOFAI_NO_FIRST_RUN=1`. -- Add `failproofai audit` command (beta) — retrospectively scan past agent transcripts across all 7 CLIs and report wasteful/risky behavior via the 39 builtin policies + 8 new audit-only detectors (`redundant-cd-cwd`, `prefer-edit-over-read-cat`, `prefer-edit-over-sed-awk`, `prefer-write-over-heredoc`, `sleep-polling-loop`, `find-from-root`, `git-commit-no-verify`, `reread-after-edit`). Outputs ANSI table + markdown report; supports `--cli`, `--project`, `--since`, `--policy`, `--limit`, `--show-examples`, `--report`, `--no-report`, `--json`, `--no-cache`. Per-transcript cache at `~/.failproofai/cache/audit/` auto-invalidates on policy/detector code changes (#377). - -### Docs - Document the new first-run prompt in the README and `docs/introduction.mdx` quickstart snippets (calling out that `failproofai policies --install` is now optional — running bare `failproofai` will offer to do it), and add a new "First-run prompt" section to `docs/cli/environment-variables.mdx` for `FAILPROOFAI_NO_FIRST_RUN=1`. Chinese mirror and the 14 translated env-vars files left for the translation-sync workflow. - -### Breaking -- Remove the undocumented cloud auth + event relay subsystem ahead of a from-scratch redesign. Deletes `src/auth/` (OAuth 2.0 device-flow login against `api.befailproof.ai`, `~/.failproofai/auth.json` token store) and `src/relay/` (WebSocket event relay daemon, sanitized JSONL queue at `~/.failproofai/cache/server-queue/`, PID tracking). Strips the `failproofai login` / `logout` / `whoami` / `relay start|stop|status` / `sync` subcommands and the internal `--relay-daemon` mode from `bin/failproofai.mjs`, along with their `--help` entries and "did you mean" suggestions. Removes the fire-and-forget `appendToServerQueue` + `ensureRelayRunning` calls from `src/hooks/handler.ts` so hook evaluation no longer enqueues events or lazy-spawns a daemon. The whole subsystem had zero references in `README.md`, `docs/`, `examples/`, or `__tests__/`, and only had internal cross-imports — `tsc`, `eslint`, `vitest` (1623 tests), and the `bun run build` bundles all stay green. Users who ran `failproofai login` should also wipe `~/.failproofai/{auth.json,cache/server-queue,relay.pid}` and stop any running relay daemon by hand; new auth/cloud surface will land in a follow-up. - -## 0.0.11-beta.1 — 2026-05-20 - -### Breaking -- Default policy namespace renamed from `exospherehost` to `failproofai`. Configs that explicitly reference builtins as `exospherehost/` must update to `failproofai/`. Flat-name shorthand (e.g. `"sanitize-jwt"`) continues to work unchanged because it auto-resolves to the new default namespace. Builtin docs (EN + 14 translations) updated to show the new namespace. - -### Docs - Rename GitHub org URLs across `package.json` metadata, README CI badge (EN + 14 translated READMEs), CONTRIBUTING, in-app "Star us" banners (`bin/failproofai.mjs`, `scripts/launch.ts`, navbar, reach-developers component), Mintlify `docs/docs.json`, and 30 translated docs (`package-aliases.mdx` issues link + `examples.mdx` repo-tree link) to reflect the `exospherehost` → `failproofai` org rename. X social handle in `docs/docs.json` updated from `x.com/exospherehost` to `x.com/failproofai`. - -### Fixes -- Remove orphan `exospheresmall` token from the Next.js proxy matcher in `proxy.ts` — no asset by that name exists in the repo. -- Restore `FailproofAI` org casing in `package.json` `homepage`, `repository.url`, and `bugs.url` (was lowercased to `failproofai/failproofai` during the org rename). npm provenance verification compares the field byte-for-byte against `${{ github.repository }}` (`FailproofAI/failproofai`) and rejected `0.0.11-beta.1` publish with `422 Error verifying sigstore provenance bundle: Failed to validate repository information`. GitHub URL routing is case-insensitive so this only affected provenance verification, not link resolution. - -## 0.0.11-beta.0 — 2026-05-13 - -### Docs - SEO and copy pass on the docs landing page (`docs/introduction.mdx`): rewrite the 84-char generic meta description into a tighter, keyword-bearing line naming the 39 built-in policies and key failure modes (loops, secret leaks, destructive tool calls); seed the page body with the missing search keywords (`AI failure handling`, `error recovery`, `LLM reliability`) by reframing the lede; expand the CLI list to the actual 7-CLI surface; correct the stale `26 built-in policies` card to the current `39`; and drop em dashes from the page body and card subtitles for a cleaner read. Also corrects the same stale `26` count in `docs/architecture.mdx` (both the Builtin policies section and the file tree comment) (#366). - Swap the docs header logo to the freshly-uploaded FailproofAI brand PNGs (`logo/Failproof_AI_logo_light.png` for light-mode UI, `logo/Failproof_AI_logo.png` for dark-mode UI). Replaces the previous Exosphere PNGs and the older stock `light.svg` / `dark.svg` wordmarks, both of which were removed from `docs/logo/`. `docs.json`'s `logo.light` and `logo.dark` paths updated accordingly (#366). - Refresh the docs favicon: replace the old `.ico` with a new FailproofAI F-mark `docs/favicon.ico` (32x32, 32-bit). An intermediate attempt to use `docs/icon.svg` was reverted because Mintlify did not render the SVG favicon in the live preview; the SVG asset is removed (#366). -### Fixes -- Dashboard `/policies` activity-tab subheading: replace the hardcoded "Policy evaluations for Claude" with a dynamic list of installed CLIs ("Policy evaluations across Claude Code, Cursor"), collapsing to "across N agents" when 4 or more are installed and falling back to "Policy evaluations" when none are. Reads from the existing `getHooksConfigAction()` payload — no new server work. The text was a leftover from when failproofai only supported Claude Code and was inaccurate against the now-7-CLI surface (Claude, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) (#358). - -### Dependencies -- Bump `tailwindcss` 4.2.4 → 4.3.0 (#357) -- Bump `react` 19.2.5 → 19.2.6 (#357) -- Bump `react-dom` 19.2.5 → 19.2.6 (#357) - ## 0.0.10 — 2026-05-10 ### Docs diff --git a/package.json b/package.json index 15c4f2e4..78dfa899 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "failproofai", - "version": "0.0.11-beta.13", + "version": "0.0.11", "description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK", "bin": { "failproofai": "./dist/cli.mjs"