Skip to content

Harden public discovery with cost-minimal revision caching - #75

Merged
ejmockler merged 14 commits into
mainfrom
agent/discovery-cache-efficiency
Jul 21, 2026
Merged

Harden public discovery with cost-minimal revision caching#75
ejmockler merged 14 commits into
mainfrom
agent/discovery-cache-efficiency

Conversation

@ejmockler

@ejmockler ejmockler commented Jul 16, 2026

Copy link
Copy Markdown
Member

What changed

  • replaces request-path public discovery scans with bounded Convex list and relation materializations plus a compact readiness manifest
  • publishes matching all and excludeCwc list/relation variants atomically under one revision from one newest-250 indexed scan; each public variant is capped at 50 and never includes embeddings
  • validates candidates before the 50-card limit so invalid or oversized recent cards are backfilled by later valid candidates; a zero-valid nonempty corpus preserves the last-known-good generation and remains unhealthy until repair
  • recursively projects exact public list and relation payloads at both producer and consumer boundaries; projectionVersion: 4 cards contain only the bounded public contract, while cache schema v5 prevents older envelopes from bypassing the new exhaustive allowlists
  • keeps the anonymous direct-email roster only on the indexed, published-only detail query, where provider/CWC configs and unknown opaque recipient fields are redacted and the exact public UX roster is normalized and capped at 50; SvelteKit responses remain private, no-store to prevent retention
  • enforces shared authoring/public/config/geography input budgets, including stored scopes and jurisdictions, across HTTP, Convex, metadata updates, and seed paths
  • couples every discovery-source writer to an explicit invalidation contract, coalesces ordinary changes behind durable dirty tokens, and retains a six-hour heavy-rebuild ceiling plus daily backstops
  • freezes last-good snapshots when output is unsafe, including aggregate oversize output; deterministically sheds whole cards, records durable failure, reports the condition, and keeps readiness degraded until a clean repair
  • caches immutable revision-qualified generations in Cloudflare Cache API, with Workers KV as a durable last-known-good shield; healthy exact-revision reads do not list KV
  • bounds outage recovery to one 1,000-key KV list operation per cache location and 24-hour retry window, never certifies overflow as latest, and preserves a usable local last-known-good candidate without unbounded pagination
  • coordinates embedding repair across Pages isolates with a secret-gated, expiring Convex lease and a 20-row request cap; every write and immediate rebuild revalidates the lease token and expiry
  • removes the unused mixed-auth embedding mutation and duplicate native backfill path, validates finite 768-dimensional vectors and domain hue, and returns structured snapshot-rebuild failures while releasing the same lease
  • validates public API config objects and HTTP(S)-only source URLs, aborts the five-second health request, and adds deployment-time cache-contract verification
  • expands the query-efficiency guard into a module-aware call-graph scanner for aliases, destructured database handles, imported helpers, and cycles; baseline acceptance now requires explicit owner, reason, and future expiry
  • documents the cache state machine, concurrency/cost ceilings, release hypergraph, and operator cutover/removal procedures

Why

The shared Convex Free-plan database-I/O quota was exhausted by ordinary homepage SSR traffic. A Sentry uptime check requested / once per minute; three queries hydrated the full embedding-bearing public corpus on every request. This was low-rate read amplification, not meaningful adoption and not evidence of a volumetric attack.

Freshness, cache, and outage contract

  • manifest revalidation: at most 60 seconds
  • ordinary invalidations: about one minute when outside the cost window, otherwise coalesced until the remaining six-hour relation window
  • content changes commit a new logical revision; edge readers observe it on manifest revalidation and fill the immutable revision-qualified generation
  • first embedding completion uses the same durable/coalesced path; it does not bypass the rebuild ceiling
  • daily backstops: list at 04:07 UTC, relations at 04:17 UTC, and producer supervision at 04:27 UTC
  • healthy payload renewal: 24 hours; prior last-known-good payloads may be served for up to seven days during Convex/manifest failure; KV expiry is eight days
  • authoritative ready: false, durable producer failure, legacy projection, recipient-bearing list data, or overdue dirty work remains fail-closed for readiness
  • generation ordering is logical-revision-major with timestamp as a tiebreaker; resetting revisions in the same backend requires a cache-schema bump or purge
  • immediate legal/privacy recall requires a namespace cut or key deletion/purge followed by rebuild and cache warm; revision invalidation alone does not revoke prior cached bytes

Cloudflare cost boundary

The deployed zero-cost shield is the explicit in-Worker Cache API plus PUBLIC_DISCOVERY_KV. This PR does not enable or rely on Cloudflare's front-of-Worker Workers Caching: the current Pages artifact has one personalized SvelteKit entrypoint, so enabling it globally would be unsafe. Browser responses use Cache-Control: public, max-age=60, must-revalidate; the optional Cloudflare-CDN-Cache-Control policy matters only if a future route-scoped outer cache is deliberately enabled.

The one-page KV recovery path is intentionally bounded. Normal daily/six-hour publication cadence stays far below 1,000 live eight-day generations. The first cold-outage wave can still cost up to C × F × L list operations across racing isolates, families, and Cache API locations; Free KV cannot provide a hard global lock. Exhaustion therefore fails closed at cold locations, and exceeding this envelope is an explicit migration trigger for a serialized coordinator or paid capacity.

The production workflow makes two /api/templates probes, enforces the browser cache contract semantically, and records CF-Cache-Status/Age. DYNAMIC or an absent cache-status header is compatible with the current design. No front-cache savings may be claimed without a verified second HIT; Age: 0 is valid for an immediate cache hit.

API and deployment behavior

  • GET /api/templates applies the same pre-congressional CWC gate as the homepage
  • authoritative cold state returns 200 [] with the 60-second browser policy; unexpected discovery failures return 503 with Cache-Control: no-store
  • /api/live is a zero-dependency, no-store liveness probe; /api/health remains the dependency/readiness and release gate, including producer freshness and PUBLIC_DISCOVERY_KV binding availability
  • automatic deploys accept only a successful same-repository push CI result for the current branch head; a secret-free job validates repository identity and ancestry before requested code can run in a secret-bearing job
  • the workflow parses the actual PUBLIC_DISCOVERY_KV binding from wrangler.toml, requires exactly one binding, matches its approved ID, and verifies the live namespace ID/title
  • every branch requires native Pages production deploys and preview deploys to be disabled; workflow_dispatch is the sole documented uploader and direct Wrangler production uploads are prohibited
  • each deploy target maps to a fixed GitHub environment (Production or Staging) rather than creating a branch-named environment
  • every Pages branch runs the producer contract gate before artifact upload; production additionally requires nonempty snapshots no older than 26 hours
  • the workflow does not deploy Convex: the same Convex revision must be deployed and rematerialized before Pages can pass the production gate

Current state

  • review head: 1cda46a1 — pushed, open, non-draft, not merged, and not deployed to production
  • Convex function execution remains blocked by the team Free-plan suspension, so marker migration, snapshot rebuild, live load testing, and live readiness validation cannot complete until reactivation
  • native Cloudflare Git production deploys remain disabled and origin/production has not advanced; native preview deploys were last observed as all, while this workflow now requires none, so that external Pages setting must be changed before a gated upload can pass
  • GitHub currently has only Production and Staging environments, but neither has protection rules and administrators can bypass them; adding required reviewers/branch restrictions is an external repository-admin action
  • all locally known review findings are addressed; fresh CI, Brutalist, CodeRabbit, Cloudflare preview, and security checks are running against 1cda46a1

Verification at review head

  • full suite: 349 test files passed; 5,536 tests passed; 12 repository-known skips and one todo remain
  • affected public-discovery, readiness, cache, health, privacy, and Convex producer suites pass, including transaction-budget, coherent-publication, overflow/LKG, and public-roster regressions
  • npm run check: 0 errors and 151 existing warnings
  • production build, Convex TypeScript, query-efficiency guard (231 public queries; 106 exact reviewed hazards), actionlint, selected Prettier, and diff safety pass
  • independent final audits found no remaining correctness, privacy, relation, or database-I/O blocker

Required cutover after Convex reactivation

  1. Deploy the Convex functions from this exact review/merge SHA.
  2. Run the one-time topic-marker migration and poll its durable status to complete.
  3. Rebuild both snapshot families so stored payloads carry projectionVersion: 4; verify exact redaction, revision agreement, nonempty output, semantic membership, size, freshness, and peak-QPS/OCC readiness.
  4. Merge the hardened workflow to default main before advancing production, because GitHub resolves workflow_run from the default branch.
  5. In Cloudflare Pages, keep native production deploys disabled and change native preview deployments from the observed all setting to none; rerun the gated workflow.
  6. Add repository environment protection rules for Production and Staging.
  7. Point the liveness monitor at /api/live (one minute) and the readiness monitor at /api/health (five minutes); never monitor / as the uptime target.

Summary by CodeRabbit

  • New Features
    • Public discovery now uses bounded, revisioned snapshot materialization with a readiness manifest and strict API contract validation.
    • Added revision-aware public-discovery caching (with last-known-good recovery) and snapshot-backed public queries for homepage and relations.
    • Introduced /api/live plus servicePing-driven /api/health readiness checks; embedding backfill is now secret-gated and lease-coordinated.
  • Bug Fixes
    • Improved public-discovery cache invalidation across more mutation paths and hardened special tag handling (e.g., __proto__).
  • Documentation
    • Updated deployment/cron/ops runbooks and added public-discovery incident recovery + query-efficiency audit docs.
  • Chores / Tests
    • Strengthened CI guardrails and added extensive readiness/cache/contract regression tests.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR replaces embedding-heavy public template and relation reads with bounded materialized snapshots, adds layered caching and readiness gates, invalidates snapshots across writes and maintenance flows, introduces query-efficiency CI enforcement, and documents SHA-pinned deployment, cron, recovery, and rollback procedures.

Changes

Public discovery pipeline

Layer / File(s) Summary
Snapshot contracts and publication
convex/schema.ts, convex/lib/publicDiscovery.ts, convex/lib/templateInputBudget.ts, convex/templates.ts
Adds manifest and snapshot tables, revisioned publication, bounded list/relation rebuilds, snapshot-backed queries, embedding marker migration, and template input budgets.
Invalidation and maintenance
convex/{templates,debates,organizations,seed,submissions}.ts, convex/crons.ts
Marks discovery data dirty after relevant writes, adds essential rebuild crons, and cleans discovery state during seed operations.
Cached consumers and API changes
src/lib/server/*, src/routes/**, convex/observability.ts, wrangler.toml
Adds memory, edge, and KV caching; routes public reads through cached helpers; adds health probing, route validation, and privileged backfill calls.
Guardrails and deployment gates
scripts/*, .github/workflows/*, package.json
Adds AST query auditing, readiness validation, CI enforcement, manual SHA verification, and production deployment checks.
Validation coverage
convex/*test.ts, tests/unit/**
Tests snapshot atomicity, read budgets, cache behavior, migration progress, readiness validation, health probing, route authorization, writer contracts, and deterministic statistical tests.
Operational documentation
docs/development/*, docs/ops/*, docs/architecture/*, docs/strategy/public-discovery-release-hypergraph/*
Documents cron profiles, production cutover, incident recovery, cache invariants, release topology, query audits, readiness checks, and rollback constraints.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.30% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the core change: hardening public discovery with bounded, revision-aware caching.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/discovery-cache-efficiency

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 16, 2026

Copy link
Copy Markdown

Deploying communique-site with  Cloudflare Pages  Cloudflare Pages

Latest commit: e73d3a8
Status: ✅  Deploy successful!
Preview URL: https://073c7840.communique-site.pages.dev
Branch Preview URL: https://agent-discovery-cache-effici.communique-site.pages.dev

View logs

@ejmockler ejmockler changed the title Add revision-aware zero-cost discovery caching Harden public discovery with cost-minimal revision caching Jul 16, 2026
@ejmockler
ejmockler marked this pull request as ready for review July 16, 2026 18:31
@strix-security

Copy link
Copy Markdown

Strix is installed on this repository, but we couldn't run this PR security review because this workspace's trial has ended. Add a card to resume code reviews here.

@ejmockler ejmockler closed this Jul 16, 2026
@ejmockler ejmockler reopened this Jul 16, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/2: Two of three critics (native Claude + GLM-routed Claude) actually read the tree and agree the PR's hardest parts are correct: snapshot publication is atomic (size-guard-both-before-writing-either, manifest revision as commit marker, single-transaction rollback), the coalescing state machine and edge-cache LKG logic are sound under Convex OCC serialization, and the marker migration is idempotent. Codex could not read files (sandbox failure) and its two 'High' race/cache claims were traced and refuted by the file-readers — I discarded them. The genuine, verified issues are seam/operability defects, not core-logic breakage: (1) the dirty-mark abstraction is asymmetric — only the LIST is invalidated on writes; the relation graph has no write-driven dirty path and patchTagEmbeddings/patchMetadata(topics) leave the concept graph stale until the daily cron (glm, Medium); (2) deferHomepageRebuild silently also strips the ownership check on a public mutation (glm, Medium); (3) the automatic workflow_run deploy path bypasses the svelte-check + Convex tsc that only manual-verify runs (both file-readers, verified against ci.yml — Medium). The remaining items are low-severity operability/cost notes (oversize silent stall, per-rebuild edge refresh from Date.now()-based generation, guardrail scope narrower than its CI authority, secret-leak blast radius). Headline: the migration pays down real read-cost principal but takes out three undocumented invariants load-bearing on human memory — codify a relation dirty path, rename the auth flag, and unify the deploy checks before merge.

Chunk 2/2: All three completing critics agree the tests are largely correct and net debt-reducing, but manufacture false confidence exactly where this PR claims to harden. The strongest cross-CLI signal: the 'authoring cost gate' auth suite tests only the 401 arm and skips the 403 INSUFFICIENT_TRUST gate (the real cost-rationing path, verified at +server.ts:257) with no positive control — all three flagged it. GLM's headline, verified against source, is that expect.any(Object) (line 79) cannot assert the excludeCwc argument and FEATURES.CONGRESSIONAL is unmocked, so the CWC-leak invariant has no enforceable test. They diverge on the wrangler KV binding: GLM rated it HIGH ('possibly fabricated id'), but I confirmed this is a Cloudflare Pages project with correct top-level env-scoping, downgrading it to a medium convention/provenance concern (the binding uniquely omits the provisioning comment its four siblings carry). Codex ran diff-only after a sandbox failure, so its unconfirmable claims (spy leakage, not-ready availability) are held at lower confidence. Agy timed out and contributed nothing.

Inline comments: 8 (1 🟠 high · 7 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 429357ms)

Native Claude read the changed files and their consumers/callers. Concluded the core mechanism is correct (snapshot publication atomicity, marker migration idempotency, secret gating all sound) but flagged the CI/deploy typecheck bypass on the auto-deploy path (High), the undocumented manifest-singleton OCC invariant + write-contention hot spot (High/latent), fail-closed deploy couplings, oversize silent stall, and the _secret leak blast radius. High signal, evidence-anchored to real line numbers.

Native Claude Code critic. Read all four test files, the three source modules under test, and wrangler.toml. Confirmed no incorrect assertions — the epoch-aware reload/rejection tests are genuinely valuable. Flagged the auth suite's missing 403 arm + positive control (medium), coalescing-coupled call counts, KV-mock type-arg blindness, log-string brittleness, over-mocking, and the wrangler provisioning-comment omission. Verified this is a Pages project so top-level KV env-scoping is correct.

✅ Codex (default, 79490ms)

Codex could NOT read the repository — every shell command failed with a bwrap loopback/RTM_NEWADDR sandbox error, which it honestly disclosed. Its findings are diff-speculation only. Its two 'High' claims (lost-update dirty coalescing; LKG serving across revisions) were independently traced and REFUTED by the two file-reading critics (OCC serializes writers; LKG is revision-keyed and backoff won't clobber global LKG). Its overlapping valid points (secret-bearer concentration, generation-token design direction) are captured via the file-verified critics. Discarded its unverified High severities.

Codex critic. Sandbox blocked disk reads (bwrap loopback error), so review was diff-only and explicitly caveated. Independently flagged the graph-failure test covering only total-manifest failure, the 'not ready' caching-availability concern, global spy leakage risk, shape-based (toMatchObject) assertions, the single-arm auth test, and the wrangler preview/prod parity gap. Some findings (spy leakage, not-ready availability) were not confirmable against source and are treated as lower-confidence.

✅ glm (Claude) (glm-5.1, 608747ms)

GLM-routed Claude did the deepest read (schema, tests, cron config, cache tests, all dirty call sites across 5 files). Strongest finding: relation snapshot has no write-driven invalidation and patchTagEmbeddings calls no dirty mark — a verified freshness asymmetry. Also verified deferHomepageRebuild auth-skip, oversize silent retry, edge-cache per-rebuild refresh cost, guardrail scope gap, and confirmed the coalescing state machine and cache LKG logic are correct under OCC. All findings anchored to verified line numbers.

Claude-routed GLM-5.1 client. Most thorough: traced every assertion against production code. Headline finding — expect.any(Object) cannot assert excludeCwc and FEATURES is unmocked, so the CWC/congressional-leak invariant is untested (high). Also flagged magic-number timing constants, the misleading concurrency comment, the auth 403 gap, missing readiness/URL-guard branches, and the wrangler KV id provenance. Its 'fabricated UUID' framing was downgraded to unverifiable convention-drift after confirming Pages env-scoping is sound.

❌ agy (Gemini 3.5 Flash (Medium), 360017ms)

Antigravity (Gemini 3.5 Flash) timed out after 360s and produced no output.

Antigravity/Agy critic timed out after 360000ms and produced no analysis. No findings contributed.

Out-of-diff findings (14)

correctness

  • 🔵 low convex/templates.tsglm (Claude) [unanchored]: Marker migration carries scanned/marked counts in scheduler args rather than the row, so a duplicate schedule can double-count the operator's completion proof
  • 🔵 low tests/unit/routes/home-page-load.test.tsglm (Claude) [sub-threshold]: Comment describes a concurrency model the loader does not have

testing

  • 🔵 low src/lib/server/public-template-queries.tsglm (Claude) [unanchored]: snapshotGeneration — the load-bearing epoch-aware cache key — has no direct unit test
  • 🔵 low scripts/verify-public-discovery-readiness.mjsglm (Claude) [unanchored]: validatePublicDiscoveryReadiness branches untested: future-timestamp, missing manifest halves, non-array payloads, multi-error aggregation
  • 🔵 low tests/unit/server/public-discovery-cache.test.tsClaude [sub-threshold]: KV mock always JSON.parses and ignores the read-type argument, leaving the kv.get(key,'json') contract unverified

maintainability

  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: Persistently-oversize snapshot silently freezes the public list at last-good, retrying every 6h with only a console.error
  • 🔵 low tests/unit/routes/home-page-load.test.tsClaude [sub-threshold]: toHaveBeenCalledTimes(1) pins an in-flight coalescing implementation detail under a behavioral name
  • 🔵 low tests/unit/routes/home-page-load.test.tsglm (Claude) [sub-threshold]: Magic-number clock advance couples the test to an unexported freshness constant
  • 🔵 low tests/unit/routes/templates-api-auth.test.tsClaude [sub-threshold]: Auth test mocks five modules unreachable on the only tested path
  • ⚪ nit tests/unit/server/public-discovery-cache.test.tsClaude [sub-threshold]: Exact console.warn/error message-text matching throughout the cache tests is refactor-hostile

design

  • 🔵 low convex/lib/publicDiscovery.tsClaude [sub-threshold]: The entire coalescing scheme is correct only because Convex OCC serializes writers through the manifest singleton — an invisible, unenforced invariant plus a write-contention hot spot
  • 🔵 low wrangler.tomlCodex [sub-threshold]: No preview_id: the global KV shield is production-only and shares one namespace across preview/prod

perf

  • 🔵 low src/lib/server/public-template-queries.tsglm (Claude) [sub-threshold]: Edge-cache generation folds updatedAt (Date.now() at rebuild) into the key, so every rebuild forces a synchronous refresh + KV write even when the payload is byte-identical

security

  • 🔵 low convex/templates.tsClaude [sub-threshold]: updateEmbeddings/createTemplate are now public mutations protected purely by a shared bearer _secret — leak blast radius includes ownership-bypassed embedding writes and mis-attributed creation

1 finding(s) dropped due to unverifiable verbatim quotes (likely fabrication).

Brutalist orchestrator schemaVersion=1 · context_id=936e8ea4-4cd2-4104-8030-d9f296e4a93f

Comment thread tests/unit/routes/home-page-load.test.ts Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread convex/templates.ts Outdated
Comment thread convex/templates.ts Outdated
Comment thread tests/unit/routes/home-page-load.test.ts
Comment thread tests/unit/routes/templates-api-auth.test.ts
Comment thread tests/unit/scripts/public-discovery-readiness.test.ts Outdated
Comment thread wrangler.toml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/lib/server/public-template-queries.ts (1)

2-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use relative imports between src/lib modules.

Proposed fix
-import { api } from '$lib/convex';
+import { api } from '../convex';
 import {
 	PUBLIC_DISCOVERY_MANIFEST_FRESH_MS,
 	PUBLIC_DISCOVERY_PAYLOAD_FRESH_MS,
 	getCachedPublicData
-} from '$lib/server/public-discovery-cache';
+} from './public-discovery-cache';

As per coding guidelines, use relative paths for imports within the src/lib directory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/server/public-template-queries.ts` around lines 2 - 7, Update the
imports in public-template-queries.ts to use relative paths for the src/lib
modules, including the convex and public-discovery-cache dependencies, while
preserving the existing imported symbols.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@convex/templates.ts`:
- Around line 733-735: Update the relation-rebuild vector collection around
computeCalibration and the topic/tag mapping logic to retain only vectors whose
dimension is exactly 768. Apply this canonical-dimension filter before
calibration and for both topicEmbedding and tag vectors, excluding malformed
legacy dimensions while preserving the existing non-empty-vector checks and
relation generation flow.
- Around line 815-843: Update publicDiscoveryRelations to accept the public-list
variant and select the corresponding relation snapshot key, including the
excludeCwc variant. Update the relation snapshot publication flow to build and
atomically publish separate keyed snapshots for both variants, so each list
receives edges only for its own ranked templates.

In `@src/lib/server/public-discovery-cache.ts`:
- Around line 57-59: Update the shared KV write coordination around
latestRequestedRevision, kvCacheKey(), and the persistence flow near lines
326-387 so stale requests from different isolates cannot overwrite the latest
fallback payload. Use revision-qualified KV keys plus a globally coordinated
pointer, or serialize pointer updates through a Durable Object, while preserving
the existing per-instance in-flight and revision checks.

In `@src/routes/api/admin/backfill-embeddings/`+server.ts:
- Around line 51-52: Update the backfill handler around the empty
missing-embeddings branch and the successful write flow so snapshot publication
remains retryable after embeddings are persisted. Invoke the existing idempotent
rebuild operation before returning when missing.length is zero, while preserving
the current response for successfully published empty backlogs.

In `@src/routes/api/health/`+server.ts:
- Around line 15-22: Bound the Convex probe in the health handler by racing
serverQuery(api.observability.servicePing, {}) against an application-level
timeout, returning false when the deadline expires so Promise.all cannot hang.
Add a test covering a never-settling query promise and verify the health
response completes with Convex reported unhealthy.

In `@src/routes/api/templates/`+server.ts:
- Around line 151-191: Update the template validation flow around templateData
and validData construction to reject malformed optional fields before casting:
require string fields such as description, type, deliveryMethod, and domain to
be strings when provided, require sources and research_log to be arrays with
valid entry types, and enforce appropriate maximum lengths for nested source/log
strings. Preserve the existing count and validation-error conventions while
ensuring invalid input returns validation errors instead of reaching Convex.
- Around line 227-239: Update the GET handler’s getCachedPublicTemplates call to
apply the congressional visibility gate instead of passing false, matching the
filtering behavior used by homepage and browse routes while preserving the
existing response construction.

---

Nitpick comments:
In `@src/lib/server/public-template-queries.ts`:
- Around line 2-7: Update the imports in public-template-queries.ts to use
relative paths for the src/lib modules, including the convex and
public-discovery-cache dependencies, while preserving the existing imported
symbols.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9013259c-3fc3-4be5-8c63-75a69e91633a

📥 Commits

Reviewing files that changed from the base of the PR and between f883164 and b225aed.

⛔ Files ignored due to path filters (1)
  • convex/_generated/api.d.ts is excluded by !**/_generated/**
📒 Files selected for processing (49)
  • .github/workflows/ci.yml
  • .github/workflows/deploy.yml
  • convex/crons.ts
  • convex/debates.ts
  • convex/lib/publicDiscovery.ts
  • convex/lib/relatedness.ts
  • convex/observability-service-ping.convex.test.ts
  • convex/observability.ts
  • convex/organizations.ts
  • convex/schema.ts
  • convex/seed-public-discovery.convex.test.ts
  • convex/seed.ts
  • convex/submissions.ts
  • convex/templates-embedding-backfill.convex.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/templates-snapshots.convex.test.ts
  • convex/templates.ts
  • docs/development/cron-setup.md
  • docs/development/deployment.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • docs/ops/CRON-PROFILES.md
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • docs/strategy/public-discovery-release-hypergraph/edges/blocks.json
  • docs/strategy/public-discovery-release-hypergraph/edges/requires.json
  • docs/strategy/public-discovery-release-hypergraph/edges/rollback.json
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • docs/strategy/public-discovery-release-hypergraph/topology.json
  • package.json
  • scripts/check-convex-query-efficiency.mjs
  • scripts/convex-query-efficiency-baseline.json
  • scripts/verify-public-discovery-readiness.mjs
  • src/app.d.ts
  • src/lib/components/template/TemplateCard.svelte
  • src/lib/server/public-discovery-cache.ts
  • src/lib/server/public-template-queries.ts
  • src/lib/types/template.ts
  • src/routes/+page.server.ts
  • src/routes/api/admin/backfill-embeddings/+server.ts
  • src/routes/api/health/+server.ts
  • src/routes/api/templates/+server.ts
  • src/routes/browse/+page.server.ts
  • tests/unit/dp-property-tests.test.ts
  • tests/unit/routes/health-endpoint.test.ts
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • wrangler.toml

Comment thread convex/templates.ts
Comment thread convex/templates.ts
Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/routes/api/admin/backfill-embeddings/+server.ts
Comment thread src/routes/api/health/+server.ts Outdated
Comment thread src/routes/api/templates/+server.ts
Comment thread src/routes/api/templates/+server.ts Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/2: All three CLIs that could read the repo (claude-native, agy, glm) independently converged on four issues: (1) the first-embedding rebuild bypass in templates.ts that fires an uncoalesced O(n^3) relation rebuild per new public template, sidestepping the 6h/60s coalescing the rest of the PR relies on; (2) the deploy.yml workflow_run path skips the entire manual-verify job (SHA-ancestry check, focused suite, tsc) that gates only workflow_dispatch; (3) the cache generation comparison in public-discovery-cache.ts orders on the timestamp component before the logical revision; and (4) unbounded module-global cache maps. They disagree on emphasis and severity: agy escalated the workflow_run untrusted-checkout to a Critical fork-deploy exploit (a real CI supply-chain concern the others underweighted — CI Tests runs on fork PRs and the deploy job checks out workflow_run.head_sha, runs npm ci, and later steps hold CLOUDFLARE_API_TOKEN, with no repo-identity guard), while glm surfaced the .unique() duplicate-row homepage SPOF and the 8-day KV replication of a public payload that includes recipientEmails/message_body. Codex was blocked at the sandbox layer, could not read files, and only speculated from the diff, so its findings are treated as unverified corroboration. Headline: the read-path optimization is genuinely sound, but the new write-path scheduler + two-level cache trade an obviously-correct slow path for a fast path whose failure modes are silent and global — and the workflow_run untrusted-checkout is the one item worth resolving before merge.

Chunk 2/2: All four critics independently converge on one structural theme: this PR routes homepage, browse, and /api/templates through a single manifest-gated cache whose failure modes are silent and inconsistent. The two highest-confidence, cross-CLI-agreed issues are (1) GET /api/templates now throws a 500 on a not-ready/cold snapshot where the old listPublic returned [] — the page loaders catch this, the API does not; and (2) the readiness gate throws before the 7-day last-known-good store it fronts can serve, so cold starts and manifest loss render empty even when servable cached data exists. GLM adds a well-evidenced observability regression: the health check was reduced to a constant ping that cannot detect a data-plane outage, while browse explicitly treats /api/health as the authoritative availability signal. The critics disagree on severity for the manifest SPOF (Agy High vs Claude/GLM Medium — moderated to Medium since the stale-ready outage path does engage LKG). Two adversarial 'critical' claims were verified false and discarded: Codex's 'getInternalSecret is unimported' (the import is present at line 9) and Agy's 'background auth silently broken' (the diff adds _secret: params precisely to move those mutations off JWT auth). The duplicated/dead trust gate and the CWC-in-API divergence are lower-severity but real and worth resolving before merge.

Inline comments: 16 (2 🟠 high · 14 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 360319ms)

Read the repository directly. Traced write→schedule→flush→rebuild and the cache read/write path. Flagged the uncoalesced first-embedding cubic rebuild bypass, the deferred-waitUntil auth risk on updateEmbeddings, the undocumented OCC dependency in coalescing, scheduled-function accumulation, and cache nits. Endorsed the new schema indexes as correctly shaped.

Native Claude critic. Traced the cache module, Convex publicDiscovery queries, and secret-auth. Strongest verified findings: GET /api/templates 500 regression (High), readiness gate defeating LKG (Medium), TOCTOU generation-mismatch throw (Medium), dead duplicated trust gate (Low). Acknowledged the cache machinery is well-considered.

✅ Codex (default, 76303ms)

Environment-blocked: every local read failed at the sandbox layer (bwrap loopback RTM_NEWADDR) and the GitHub connector could not resolve the repo. Produced only diff-level speculation (listPublic empty-on-missing, updateEmbeddings auth coupling, deploy SHA resolution, coalescing debounce). Explicitly stated it could not meet the evidence standard. Treated as unverified corroboration.

Codex critic ran read-only (sandbox blocked shell reads, so review was diff-scoped). Valid findings: page-vs-API divergence on the same cache dep, Cache-Control set before load, mutable-locals trust gate, may_have_more off-by-one, endorsementCount ambiguity. One CRITICAL claim (getInternalSecret unimported) is FALSE — import present at line 9 — discarded.

✅ agy (Gemini 3.5 Flash (Medium), 109753ms)

Read the repository directly. Headline finding: workflow_run deploy path checks out untrusted head_sha and runs with production secrets (fork-deploy exploit). Also flagged the inverted cache generation tuple comparison, unbounded memory maps, and the first-embedding cooldown bypass.

Antigravity/Gemini critic. Valid: manifest SPOF, sequential backfill mutations, cross-isolate backfill guard. Its CRITICAL 'background auth silently broken' claim is contradicted by the diff itself (the PR adds _secret: to exactly those background mutations, moving them off JWT auth) — discarded. Several other findings anchor to public-discovery-cache.ts, which is outside this commentable chunk.

✅ glm (Claude) (glm-5.1, 506009ms)

Read the repository directly and traced the scheduler end-to-end (found it sound with a load-bearing two-step token-clear caveat). Flagged the .unique() single-row homepage SPOF, the workflow_run verify-gate gap, the approximate excludeCwc snapshot, the production-deploy/snapshot-health coupling, write amplification on the hot templates table, and the 8-day KV replication of recipient PII.

Claude-routed GLM-5.1 client. Deepest trace: verified servicePing reads no document, cold-manifest semantics, and zero callers for the two relation selectors. Headline verified findings: health check can't see data-plane outages (Medium), CWC included in API but excluded on pages pre-launch (Medium), dead selectors and JSON.stringify deep-equality (Low).

Out-of-diff findings (8)

maintainability

  • 🔵 low src/routes/api/templates/+server.tsClaude [unanchored]: Pre-existing trust gate is now dead code duplicating the new early gate
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [sub-threshold]: Module-global cache maps have no eviction
  • 🔵 low src/lib/server/public-template-queries.tsglm (Claude) [sub-threshold]: Two exported 'compatibility selectors' have zero callers
  • 🔵 low src/lib/types/template.tsCodex [sub-threshold]: endorsementCount added as optional preserves the count ambiguity it means to fix

correctness

  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: excludeCwc snapshot is approximate beyond the 250-row cap but materialized as authoritative
  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsCodex [sub-threshold]: may_have_more is an off-by-one guess from the batch cap, not authoritative pagination
  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsagy [sub-threshold]: In-memory backfillRunning guard does not prevent concurrent runs across isolates

perf

  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsagy [sub-threshold]: Backfill awaits up to 100 sequential Convex mutations in one request

Brutalist orchestrator schemaVersion=1 · context_id=b4314560-4c8e-424d-b497-6ebf9af331f4

Comment thread .github/workflows/deploy.yml Outdated
Comment thread src/routes/api/templates/+server.ts Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread src/lib/server/public-template-queries.ts Outdated
Comment thread src/lib/server/public-template-queries.ts Outdated
Comment thread src/routes/api/health/+server.ts Outdated
Comment thread src/routes/api/templates/+server.ts Outdated
Comment thread src/routes/api/templates/+server.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/verify-public-discovery-readiness.mjs (1)

340-370: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Retry when publication changes between readiness reads.

A healthy rebuild after the manifest query but before the payload queries produces coordinate mismatches and fails the one-shot production gate. Retry the complete read once when the manifest generation changes, or compare a second manifest read before validating.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/verify-public-discovery-readiness.mjs` around lines 340 - 370, Update
the public discovery readiness flow around the manifest and payload queries to
detect publication-generation changes caused by a rebuild between reads. Retry
the complete manifest-and-payload read once, or perform a second manifest
comparison before validation, and only report readiness failure after the
retry/consistent-read attempt still mismatches; preserve the existing
validatePublicDiscoveryReadiness inputs and options.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/server/public-discovery-cache.ts`:
- Around line 366-369: Update the recovery flow around readKvForRevision,
priorEdgePromise, and the pointer-based early return so an older revision cannot
overwrite or pin the shared edge LKG pointer. Make pointer updates monotonic
across isolates; alternatively, revalidate the pointer-selected entry with
readLatestKvRevision before returning it, ensuring newer revision-qualified KV
data is checked.

In `@src/routes/api/templates/`+server.ts:
- Around line 160-166: Extend the validation loop in the template-data
validation flow to cover delivery_config, cwc_config, and recipient_config,
requiring each provided value to satisfy isRecord(...). Add a
VALIDATION_INVALID_FORMAT error for scalar or array values before these fields
are cast to UnknownRecord and sent to Convex, while preserving the existing
string validation for slug, description, and domain.

---

Outside diff comments:
In `@scripts/verify-public-discovery-readiness.mjs`:
- Around line 340-370: Update the public discovery readiness flow around the
manifest and payload queries to detect publication-generation changes caused by
a rebuild between reads. Retry the complete manifest-and-payload read once, or
perform a second manifest comparison before validation, and only report
readiness failure after the retry/consistent-read attempt still mismatches;
preserve the existing validatePublicDiscoveryReadiness inputs and options.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d4412a2f-17b8-49c0-8030-4a7c6403e73c

📥 Commits

Reviewing files that changed from the base of the PR and between b225aed and ee270a9.

📒 Files selected for processing (29)
  • .github/workflows/deploy.yml
  • convex/crons.ts
  • convex/lib/publicDiscovery.ts
  • convex/lib/tag_concepts.test.ts
  • convex/lib/tag_concepts.ts
  • convex/observability-service-ping.convex.test.ts
  • convex/observability.ts
  • convex/schema.ts
  • convex/templates-embedding-backfill.convex.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/templates-snapshots.convex.test.ts
  • convex/templates.ts
  • docs/development/deployment.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • scripts/verify-public-discovery-readiness.mjs
  • src/lib/server/public-discovery-cache.ts
  • src/lib/server/public-template-queries.ts
  • src/routes/+page.server.ts
  • src/routes/api/health/+server.ts
  • src/routes/api/templates/+server.ts
  • tests/unit/routes/health-endpoint.test.ts
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • tests/unit/server/public-template-queries.test.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • src/routes/api/health/+server.ts
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • tests/unit/routes/health-endpoint.test.ts
  • convex/crons.ts
  • convex/schema.ts
  • src/routes/+page.server.ts
  • tests/unit/routes/home-page-load.test.ts
  • convex/templates-read-budget.convex.test.ts
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • tests/unit/server/public-discovery-cache.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • docs/development/deployment.md
  • convex/lib/publicDiscovery.ts
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • convex/templates.ts

Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/routes/api/templates/+server.ts

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/2: All four critics agree the read-path win is real (per-request scans of the embedding-heavy templates corpus replaced by one indexed snapshot read) but converge on the same core liability: the entire discovery write-path now serializes on a single publicDiscoveryManifest singleton, and the "no-drop" correctness guarantee is a hand-maintained convention (every snapshot-relevant write must call a mark*Dirty in the same mutation) that nothing enforces — the new guardrail is query-only and cannot see it. Secondary agreements: non-unique by_key snapshot tables "tolerated" via .order('desc').first() with no GC for orphaned ~900KB rows, and listPublic returning a v.any() producer-trusted payload with no query-time shaping. Disagreement worth flagging: agy called the .eq(topicEmbeddingsUpdatedAt, undefined) backfill index "broken (0 results)" and updateEmbeddings "dead/impossible to call" — both are contradicted by the PR's own passing tests and by Convex's undefined-indexing semantics, so I discarded/downgraded them. On the deploy gate, claude and glm judged always() && needs.*.result=='success' correct (always() is needed because manual-verify is skipped on workflow_run); codex/agy preferred !cancelled() — the explicit success checks already fail closed on cancel, so this is stylistic. Headline: sound optimization, but correctness rests on an unenforced convention plus an unmonitored hot singleton with no steady-state freshness/oversize alerting.

Chunk 2/2: All four critics converge on two themes: (1) the new 764-line public-discovery-cache is a load-bearing, hand-rolled multi-region cache-coherence protocol whose invariants live in prose comments rather than types/tests, and whose outage-recovery path does an unbounded KV list; (2) the template-API 'hardening' stops short — it bounds string/array lengths but leaves the sources[].url scheme unvalidated (stored-XSS/open-redirect), the *_config objects and geographic_scope enum unvalidated, and duplicates the auth trust check as unreachable dead code. GLM adds the sharpest operational risk: a 7-day stale-if-error window stacked with 7–8 day app/KV LKG and NO purge path, so a retracted/leaking template stays publicly servable for days during any Convex degradation. The critics agree the security-critical excludeCwc cache gate does NOT collide (independently verified) and the readiness-script URL validation is sound. Disagreement is mostly severity inflation: Codex ran blind (sandbox failure) and Agy rated the KV-list 'critical' — both downgraded here after file verification, since hot memory/edge/pointer paths short-circuit the scan in the common case. Headline actionable item: add a scheme allowlist to source URLs and an explicit cache-purge lever before merge.

Inline comments: 10 (1 🟠 high · 9 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 424567ms)

Native Claude read the actual files. Judged the serializability proof correct but fragile (undocumented empty-patch invariant), flagged the unenforced dirty-mark convention, the manifest hot-row on the send path, deploy freshness coupled to backstop-cron health, non-transactional readiness verifier, and duplicate-key no-GC. Confirmed auth/secret layering and oversize-atomicity are sound.

Native Claude: verified the excludeCwc cache gate does NOT collide (clean, per-variant logicalKey across all three layers) and the readiness-script URL validation is genuinely tight. Real issues: source URL scheme not validated (stored-XSS surface), redundant dead auth gate, unbounded *_config objects, 764-line cache god-module with invariants only in comments, warn-only degradation with no metrics, health query not aborted.

✅ Codex (default, 79848ms)

Codex sandbox could not read the workspace (bwrap loopback failure); review is diff-only, self-labeled. Flagged non-unique snapshot keys, an incomplete rebuild-vs-dirty race argument, dirty-coalescing timestamp suppression, v.any() producer-trusted payload, hybrid auth on updateEmbeddings, userId-from-args in createTemplate, and always() fragility. Some concerns speculative due to no file access.

Codex was blocked from reading the repo by a sandbox networking error and reasoned only from the diff excerpts (self-labeled). Flagged unbounded module-level cache state (OOM/DoS), inFlight cleanup risk, stale-if-error masking failures, health timeout without cancellation, and CWC-variant keying — the last two later confirmed benign/handled by native Claude's file reads.

✅ agy (Gemini 3.5 Flash (Medium), 126974ms)

Agy flagged the manifest singleton bottleneck (Critical), duplicate snapshot creep, and always()→!cancelled(). Two Critical/High claims discarded: the 'broken index returns 0 results' claim is contradicted by Convex undefined-indexing and the PR's own test; the 'updateEmbeddings is dead code impossible to call' claim is contradicted by a passing test that calls it via forwarded identity + secret.

Antigravity/Gemini: strongest concrete finding is the unbounded paginated KV list on the outage-recovery path. Also flagged source-URL scheme XSS, _secret in Convex logs, waitUntil portability, unbounded module maps, and dead is_public/status schema. Its 'critical' KV-list severity was downgraded to medium (hot paths short-circuit the scan in the common case).

✅ glm (Claude) (glm-5.1, 842382ms)

GLM-routed Claude did the deepest audit: enumerated every dirty-mark call site and confirmed coverage is complete by manual inspection only. Best articulation of the no-drop-as-convention risk (A1), manifest god-object (A2), oversize silent-freeze with no alert (C1), unobservable flush outcomes (O1), no-src-caller updateEmbeddings (S1), dead schema literal (E2). Judged the deploy gate sound with one ci.yml coupling caveat.

GLM-routed Claude: deepest read, traced route→queries→cache→Cache API/KV/Convex and verified servicePing reads the manifest singleton. Headline: 7-day stale at two layers with no purge path; also blocking manifest on the hot path, LKG bypassing the ready gate, moderation covering only title+body, dead duplicate auth gate, and health query not aborted / discarding discoveryManifestPresent.

Out-of-diff findings (17)

maintainability

  • 🔵 low src/routes/api/templates/+server.tsClaude [unanchored]: New POST auth gate makes the pre-existing inner trust check unreachable dead code (drift trap)
  • 🔵 low convex/templates.tsClaude [sub-threshold]: Duplicate-key tolerance self-heals reads but leaks up to 900KB orphan rows with no GC
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: Flush outcomes are unobservable; only deploy-time gate ever reads freshness
  • ⚪ nit convex/schema.tsglm (Claude) [sub-threshold]: Dead 'public' literal in templateRelationSnapshots.key union

security

  • 🔵 low src/routes/api/templates/+server.tsglm (Claude) [unanchored]: Validation hardening skips the *_config objects and geographic_scope enum
  • 🔵 low src/routes/api/templates/+server.tsglm (Claude) [unanchored]: Moderation covers only title + message_body while other public fields are echoed verbatim
  • 🔵 low convex/templates.tsCodex [sub-threshold]: createTemplate accepts userId from args and authorizes via stringified comparison
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: updateEmbeddings has a dual secret+auth+ownership gate and no discoverable src/ caller
  • 🔵 low src/routes/api/templates/+server.tsagy [sub-threshold]: Internal secret passed as a Convex function argument may surface in execution logs

design

  • 🔵 low src/routes/api/templates/+server.tsagy [unanchored]: Deferred embedding/CWC work relies on Cloudflare waitUntil with a fire-and-forget fallback
  • 🔵 low .github/workflows/deploy.ymlClaude [sub-threshold]: always() in deploy gate is correct but !cancelled() is the safer idiom

correctness

  • 🔵 low convex/organizations.tsglm (Claude) [sub-threshold]: Org update dirties list only on avatar change — verify no other snapshot-embedded org field can change here
  • 🔵 low src/lib/server/public-discovery-cache.tsCodex [sub-threshold]: Module-level unbounded Maps (memoryCache/inFlight/latestRequestedRevision) are an unsafe default
  • ⚪ nit src/routes/api/health/+server.tsglm (Claude) [unanchored]: Reported uptime is per-isolate, not per-deployment
  • ⚪ nit convex/templates.tsagy [sub-threshold]: DISCARDED: 'backfill index returns 0 results for undefined' claim is contradicted by Convex semantics and the PR's own test

perf

  • 🔵 low src/lib/server/public-discovery-cache.tsClaude [sub-threshold]: Change-detection double-stringifies the full payload (~1.8MB) and is key-order-fragile
  • 🔵 low src/lib/server/public-template-queries.tsglm (Claude) [sub-threshold]: Manifest query is blocking on the critical path of every anonymous read

1 finding(s) dropped due to unverifiable verbatim quotes (likely fabrication).

Brutalist orchestrator schemaVersion=1 · context_id=9f9bcdec-6c09-4e7f-8f05-9934e64f269e

Comment thread convex/lib/publicDiscovery.ts Outdated
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/schema.ts
Comment thread convex/submissions.ts
Comment thread convex/templates.ts Outdated
Comment thread src/lib/server/public-discovery-cache.ts Outdated
Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/routes/api/health/+server.ts Outdated
Comment thread src/routes/api/templates/+server.ts
Comment thread src/routes/api/templates/+server.ts Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/2: Three of four critics (native Claude, GLM-routed Claude, Gemini/agy) independently read the tree and converged on the same shape: the security/auth tightening is genuinely good (secret+identity gating on createTemplate/updateEmbeddings, missing-only embedding bridges, allowlist-gated clearTable, thorough deploy source-verify/ancestry gating), while the new risk is concentrated in the public-discovery materialization's coupling and blast radius. Strongest agreement: (1) one malformed/legacy row can freeze the whole homepage list rebuild (Claude native), and the read path is fallback-free with a 6h freshness ceiling (GLM); (2) the no-drop freshness invariant is load-bearing — both agy and GLM flag it, though GLM adds the crucial context agy lacked that a CI writer-contract AST ratchet DOES enforce it (heuristically, not type-level). Notable disagreement worth weighing: agy rates the global-manifest OCC contention on the hot submission path 'High', but the coalescing design (first-writer-only patch, later writers skip) bounds steady-state write-write conflicts, so it is downgraded to Medium pending load-test evidence. Codex was blind (sandbox failure) and contributed nothing verifiable — discarded. Net: no critical/RCE-class defects; the actionable items are the corpus-wide rebuild freeze coupling and the silent-failure paths (projection drop, single-boolean readiness bypass).

Chunk 2/2: Three of four critics ran (Codex was blocked by a sandbox bwrap failure and correctly declined to fabricate). The strong consensus headline is that this PR's endpoint hardening — early auth/trust gating before AI spend, input-budget validation, strict source-URL and convex.cloud-URL checks, the health AbortController deadline, and the self-checking AST guardrail — is genuine net debt reduction, well-tested and well-scoped. The risk is concentrated in two places all three critics independently flagged: (1) public-discovery-cache.ts, a ~1,051-line three-tier distributed coherence state machine that is now the sole read path for the homepage, browse, and public API, whose correctness lives in prose + ~34 tests rather than enforced invariants, and whose recovery path leans on a per-isolate KV-list that can self-throttle during the outage it exists to survive; and (2) the admin backfill endpoint, whose per-isolate backfillRunning guard cannot serialize across isolates and whose post-loop snapshot rebuild silently no-ops if the unbounded request is evicted. Disagreement is mainly on severity calibration: agy rated the KV-list ceiling Critical and the health probe High, but the daily snapshot-cron cadence, the graceful overflow degradation, and WORKFLOW.md's explicit readiness-not-liveness contract for /api/health justify downgrading both — I applied those corrections. Lower-severity but valid: duplicate trust gate (dead second copy), Date.now-only AST bypass, moderation-before-dedup cost, generation-mismatch one-shot retry, and minor info disclosure in health/moderation errors. Recommend decomposing the cache behind a frozen surface with property tests, and making the backfill idempotent/chunked or cron-driven with a durable lock, before this sits behind real traffic."

Inline comments: 13 (2 🟠 high · 11 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 280837ms)

Native Claude read the actual tree end-to-end. Rated the change architecturally sound (verified the OCC no-drop argument holds). Headline: one malformed producer row freezes the whole homepage list rebuild (corpus-wide, not row-scoped). Also flagged unbounded _listMissingDomainHue collect, unauth servicePing, and praised the deploy source-verify/ancestry gating as the strongest part of the PR. All quotes verified.

Native Claude Code critic. Read the full working tree. Flagged the 1,051-line cache as a high-risk single-point-of-failure read path for three surfaces, the per-isolate backfill guard, double-JSON.stringify deep compare, KV-list recovery ceiling, duplicate trust gate, moderation error passthrough, and unauthenticated Atlas baseUrl disclosure. Credited the strict URL validation, self-checking AST analyzer, and health AbortController fix as genuinely well done. No merge-blocker on security grounds.

❌ Codex (default, 75300ms)

Codex's read-only shell failed before every command (bwrap loopback RTM_NEWADDR error) and the GitHub connector returned 404, so it could not read any changed file. It offered only speculative risk areas without line citations and explicitly declined to assert confirmed findings. No anchorable findings extracted; discarded.

FAILED TO PRODUCE FINDINGS. Every read-only shell command aborted before execution with 'bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted' — a sandbox startup failure, not a repo issue. Codex correctly refused to fabricate findings from the summarized diff. No Codex-original findings; overlapping items above are attributed to codex only where they match another critic's verified observation.

✅ agy (Gemini 3.5 Flash (Medium), 77580ms)

Agy (Gemini) focused on architecture: global manifest OCC contention on the hot submission path (rated High; downgraded to Medium given the coalescing mitigation it did not fully account for), the fragile manual write-path dirty-flag coupling, v.any() snapshot typing, and O(N^3) tag clustering cost. Some line numbers cited slightly off (e.g. convex/tag_concepts.ts vs convex/lib/tag_concepts.ts) but the underlying files exist.

Antigravity/Gemini critic. Flagged slug TOCTOU, KV lexicographic 1000-key list ceiling (rated Critical — downgraded to medium given daily cron cadence + graceful overflow handling), health-probe 503 (rated High — downgraded to low given documented readiness-not-liveness contract), thundering herd, synchronous rebuild in request, and the Date.now-only AST bypass. Estimated 18% tech-debt interest rate driven by Cloudflare-coupled custom cache infra.

✅ glm (Claude) (glm-5.1, 380004ms)

GLM-routed Claude did the deepest trace, including reading the writer-contract test to validate the OCC argument. Headline concerns: fallback-free read path + 6h ceiling = large blast radius, the single-boolean readiness bypass, silent projection-drop with no alert, and unauth patchEmbeddings/servicePing. Correctly credited the auth-boundary tightening (secret+identity gating, missing-only bridges, allowlist clearTable) as genuinely good. All quotes verified.

GLM-routed Claude critic. Deepest trace (Convex manifest/list/relations + servicePing). Strongest articulation of the backfill fictitious-guard + unbounded-work + rebuild-skip-on-partial defect (High), the cache complexity vs thin coverage (High), KV self-DOS during outage, generation-mismatch one-shot retry vs Convex query caching (Medium), moderation-before-dedup cost, double-stringify perf, and baseline expiry/ownership dilution. Rated tech-debt interest HIGH and accelerating.

Out-of-diff findings (10)

perf

  • 🟡 medium src/routes/api/templates/+server.tsglm (Codex) [unanchored]: POST pays two external moderation calls before the cheap content-hash dedup short-circuits
  • 🔵 low convex/templates.tsClaude [unanchored]: _listMissingDomainHue does an unbounded .collect() over all templates

security

  • 🔵 low convex/templates.tsglm (Claude) [unanchored]: patchEmbeddings is an unauthenticated internal overwrite primitive, inconsistent with the PR's tightening
  • 🔵 low src/routes/api/health/+server.tsClaude [unanchored]: Unauthenticated /api/health returns the Atlas base URL in its JSON body
  • 🔵 low src/routes/api/templates/+server.tsClaude [unanchored]: Raw upstream moderation Error.message is forwarded to the client
  • 🔵 low convex/observability.tsClaude [sub-threshold]: servicePing exposes producer health/overdue timestamps to anonymous callers

maintainability

  • 🔵 low convex/lib/publicDiscovery.tsagy [sub-threshold]: No-drop freshness invariant is load-bearing and enforced only by a heuristic CI ratchet, not the type system

correctness

  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsClaude [sub-threshold]: Comment claims a global concurrency guarantee a per-isolate boolean cannot provide
  • 🔵 low src/routes/api/templates/+server.tsClaude [sub-threshold]: Trust/auth gate is repeated after moderation; the second copy is unreachable-on-failure dead code

design

  • 🔵 low src/routes/api/health/+server.tsglm (agy) [sub-threshold]: Health probe returns 503 when the snapshot producer is overdue — safe only because it is documented as a readiness (not liveness) signal

1 finding(s) dropped due to unverifiable verbatim quotes (likely fabrication).

Brutalist orchestrator schemaVersion=1 · context_id=07b665f7-091b-4e41-b63d-469fb2b7e074

Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/routes/api/admin/backfill-embeddings/+server.ts Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread convex/submissions.ts
Comment thread convex/templates.ts Outdated
Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/lib/server/public-discovery-cache.ts Outdated
Comment thread src/lib/server/public-template-queries.ts
Comment thread src/routes/api/templates/+server.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md (1)

164-172: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not require nonzero counts unconditionally.

Lines 56-59 define a legitimately empty corpus as ready:true, but this activation procedure requires nonzero source/list counts. Gate that requirement on an explicit production-corpus invariant, or accept zero counts when readiness, revision, timestamp, and size checks pass.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md` around lines 164 - 172, Revise the
rebuild acceptance criteria so nonzero source/list counts are not required
unconditionally. In the activation procedure, either gate the nonzero-count
requirement behind an explicit production-corpus invariant or accept zero counts
when list.ready and relations.ready, revisions, timestamps, and snapshot-size
checks pass; preserve the existing empty-corpus readiness behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@convex/lib/templateInputBudget.ts`:
- Around line 276-289: Update the validation loop for input.scopes and
input.jurisdictions so non-array values return the invalid-format reason, while
only arrays exceeding their respective limits return max_container_entries.
Preserve the existing actual and limit fields for oversized arrays.

In `@docs/architecture/public-discovery-cache-invariants.md`:
- Around line 135-142: Update the architecture documentation before the first `F
× L` cost formula to explicitly define `F` as the number of hot logical families
and `L` as the number of Cache API locations, then preserve the existing
steady-state and concurrency-bound statements.

In `@tests/unit/convex/public-discovery-writer-contract.test.ts`:
- Around line 97-107: Update the writer scan around the variable-statement
handling to include non-exported top-level const/let declarations whose
initializers are arrow functions or function expressions, while preserving
existing exported-variable behavior. Ensure these helper declarations are
collected for delegated write detection, and add a regression test covering an
exported mutation that delegates through such a helper; run the relevant tests
with npm test.

In `@tests/unit/routes/health-endpoint.test.ts`:
- Around line 71-77: Update the manifest-missing health test fixture and the
corresponding producer-focused case to isolate the intended gate: set
discoveryProducerOverdueAt to null and set discoveryProducerHealthy to true in
the manifest-only case, while keeping all other health fields healthy so
failures specifically validate the targeted predicate.

---

Outside diff comments:
In `@docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md`:
- Around line 164-172: Revise the rebuild acceptance criteria so nonzero
source/list counts are not required unconditionally. In the activation
procedure, either gate the nonzero-count requirement behind an explicit
production-corpus invariant or accept zero counts when list.ready and
relations.ready, revisions, timestamps, and snapshot-size checks pass; preserve
the existing empty-corpus readiness behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 19890dc0-9b73-4ea3-bb63-1df9047db493

📥 Commits

Reviewing files that changed from the base of the PR and between ee270a9 and 6684b58.

📒 Files selected for processing (23)
  • .github/workflows/deploy.yml
  • convex/crons.ts
  • convex/lib/publicDiscovery.ts
  • convex/lib/templateInputBudget.ts
  • convex/observability-service-ping.convex.test.ts
  • convex/observability.ts
  • convex/schema.ts
  • convex/seed.ts
  • convex/templates-input-budget.convex.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/templates-snapshots.convex.test.ts
  • convex/templates.ts
  • docs/architecture/public-discovery-cache-invariants.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • src/lib/server/public-discovery-cache.ts
  • src/routes/api/health/+server.ts
  • src/routes/api/templates/+server.ts
  • tests/unit/convex/public-discovery-writer-contract.test.ts
  • tests/unit/convex/template-input-budget.test.ts
  • tests/unit/routes/health-endpoint.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • .github/workflows/deploy.yml
  • tests/unit/routes/templates-api-auth.test.ts
  • convex/schema.ts
  • convex/templates-read-budget.convex.test.ts
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • convex/lib/publicDiscovery.ts
  • src/lib/server/public-discovery-cache.ts
  • src/routes/api/templates/+server.ts
  • convex/templates.ts

Comment thread convex/lib/templateInputBudget.ts
Comment thread docs/architecture/public-discovery-cache-invariants.md Outdated
Comment thread tests/unit/convex/public-discovery-writer-contract.test.ts Outdated
Comment thread tests/unit/routes/health-endpoint.test.ts

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/2: All four critics agree the public-discovery materialization is well-engineered and defensive, with correctness concentrated in the dirty-bit scheduler and singleton control plane. Native Claude and the glm-routed client both traced the OCC no-drop argument as sound but fragile — it depends on an invisible 'every projection writer calls the dirty helper in-transaction' convention enforced only by a CI ratchet, which glm showed is a name-inference heuristic, not a soundness proof. The strongest cross-CLI agreements: the singleton tables have no uniqueness backstop (readers use .order('desc').first() while only leases use fail-loud .unique()), and the deploy.yml probe is brittle (gawk-only IGNORECASE, exact-string Cache-Control match, Age>=1-on-HIT flakiness). The highest-severity item unique to glm is recipientEmails being materialized unredacted into the unauthenticated, edge-cached payload while every metric field around it is K-floored — a materialized PII surface that needs a product decision. Disagreement/noise: Codex could not read the files (sandbox failure) and produced a false 'missing null guard' finding and a refuted 'wrong-commit' provenance claim; agy's 'Critical' backfill loop is conditional on skipping the marker migration and its 'updateEmbeddings dead code' claim is disputed. Net: no blocking defect proven, but ship-gating decisions are owed on recipientEmails redaction and singleton uniqueness/fail-loud reads, plus the cheap deploy-probe hardening.

Chunk 2/2: All four critics independently converge on the same headline: the new query-efficiency guardrail (scripts/check-convex-query-efficiency.mjs) is the weakest link — a syntactic AST scan with multiple verified bypasses (hazards factored into helpers, aliased/renamed query imports, { db } destructuring defeating the .filter() rule, non-export const export forms) plus a regeneration path that defaults to a hardcoded owner/expiry and an env-spoofable 'today', so real read-cost regressions can ship with green CI. The second cluster is the embedding-backfill route: the post-write snapshot rebuild is unguarded inside an outer try that has no catch, so a rebuild failure turns a successful batch into an opaque 500. Where the critics DISAGREE is the two-level cache: agy rated cross-isolate LKG-pointer regression and KV lexicographic truncation as High, but the deeper-reading glm and native-Claude passes (plus the module's own tests) show these races are contained by revision-qualified immutable KV keys, overflow detection, and a tested recovery path — downgraded to low. Two claims were discarded or downgraded on verification: Codex's High 'missing trust_score bypasses the gate' is factually wrong (code uses (trust_score ?? 0) < 100; Codex never read the repo), and the health-endpoint atlas coupling/info-leak is largely pre-existing rather than introduced here. The genuinely PR-introduced, actionable defects are the guardrail bypasses and the unguarded backfill rebuild.

Inline comments: 12 (12 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 290130ms)

Native Claude read the working tree and delivered a measured review: it refuted the brief's premise that readers use .first() while writers use .unique() (both use .order('desc').first() consistently; only leases use .unique()). Headline: the change is unusually defensive and mostly low-severity. Load-bearing item is the OCC no-drop argument, which it traced as sound but fragile, depending on the CI writer-contract ratchet it could not verify. Also flagged NaN/Infinity in embedding vectors, awk IGNORECASE gawk-dependence, Age>=1 flakiness, Cache-Control exact-string brittleness, and the dead 'public' schema literal. Confirmed source-verify checkout is pinned to head_sha and clearTable hardening is correct.

Native Claude read all changed files. Strongest, best-evidenced critique: the query-efficiency guardrail has real bypasses (helper extraction, import aliasing) and the regen path defaults to a rubber-stamp baseline. Also flagged forceRefresh/in-flight coalescing, backfill lease serializing only starts, and a redundant post-moderation trust gate. Correctly cleared the health abort/timeout handling and the readiness validator as sound.

✅ Codex (default, 83798ms)

Codex's local shell was unusable (bwrap loopback failure) and it could not resolve the repo via the GitHub connector, so its review was limited to the supplied diff/context and never read the files. Several findings were false or refuted on verification: the 'missing null template guard' in updateEmbeddings does not exist (line 2517 has it), and the 'source-verify may verify the wrong commit' concern is refuted (checkout is pinned to head_sha). Its duplicate-row / dirty-bit / SPOF findings restated the brief's premise that native Claude refuted, though the underlying singleton-uniqueness concern is valid (covered by glm). Genuinely useful: the _secret+requireAuth boundary question and the branch-derived environment-name concern.

Codex's sandbox blocked all repo reads (bwrap loopback failure) and the GitHub connector could not resolve the repo, so it reasoned from the diff summary only. Its single High finding (missing trust_score bypasses the gate) is FALSE — actual code uses (trust_score ?? 0) < 100. Its other notes were unverified pointers that overlap with what the reading critics confirmed. Discarded the false finding.

✅ agy (Gemini 3.5 Flash (Medium), 166729ms)

Agy read the files extensively and produced grounded findings, though with inflated severities. Its 'Critical' backfill starvation loop is real only if Gemini repair runs before the marker migration completes (downgraded to low). Solid verified findings: the backfill mutation does not validate the lease token; the clearTable cascade is skipped when deleted==0; embeddingBackfillLeases is omitted from SEED_TABLES; and a failed migration page wedges into 'already-running' requiring restart. Its 'updateEmbeddings dead code' claim is disputed (glm argues the server path is viable). Its OCC write-starvation claim overstates the risk given the 60s coalescing token.

Agy read the files and contributed two genuinely additive guardrail gaps the others missed: ctx { db } destructuring defeats the query-builder .filter() rule, and non-export const export forms escape the scan. Its cache findings (LKG pointer regression, KV lexicographic truncation) and health version-skew were real observations but over-rated as High; the cache races are contained by revision-qualified KV keys, overflow detection, and tested recovery — downgraded to low.

✅ glm (Claude) (glm-5.1, 541921ms)

The glm-routed Claude client did the deepest read: it verified the writer-contract ratchet exists and couples source reads to the classifier's field set, traced the OCC no-drop argument end-to-end as sound, and confirmed the cross-file metric writer (submissions.incrementTemplateReach) is covered. Its highest-value findings: recipientEmails materialized unredacted into the edge-cached public payload (contradicting the K-anon discipline around it); singleton tables have no uniqueness backstop; the oversize-freeze cliff has no recovery; the embeddingBackfillLeases .unique() wedge; asymmetric corruption defense between list and relation reads; and the ratchet being a heuristic (name-based table inference) rather than a soundness proof. Deploy.yml gate assessed as well-built with no injection.

The deepest read: verified lease/mutation internals and Convex OCC slug atomicity. Uniquely surfaced the --print-current rubber-stamp regen, the CONVEX_QUERY_EFFICIENCY_TODAY expiry spoof, and the unguarded post-backfill rebuild that breaks the JSON response contract via an outer try with no catch. Concluded the cache/lease are well-engineered with only minor nits, and correctly cleared slug atomicity and the health abort handling.

Out-of-diff findings (22)

maintainability

  • 🔵 low src/routes/api/templates/+server.tsClaude [unanchored]: Trust gate is re-checked identically after moderation — dead/duplicated authorization
  • 🔵 low convex/seed.tsagy [unanchored]: embeddingBackfillLeases is omitted from SEED_TABLES, leaving stale leases after a clean seed
  • 🔵 low convex/templates.tsagy [unanchored]: A failed migration page leaves the manifest 'already-running', forcing a full restart
  • 🔵 low convex/schema.tsClaude [sub-threshold]: templateRelationSnapshots.key retains dead 'public' literal with no GC
  • 🔵 low scripts/check-convex-query-efficiency.mjsClaude [sub-threshold]: Guardrail skips any query authored via an aliased/renamed query import
  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsClaude [sub-threshold]: Backfill lease serializes starts, not overlap; batch slice is dead
  • 🔵 low scripts/check-convex-query-efficiency.mjsagy [sub-threshold]: Guardrail only scans export const variable statements — other export forms escape
  • 🔵 low scripts/check-convex-query-efficiency.mjsglm (Claude) [sub-threshold]: CONVEX_QUERY_EFFICIENCY_TODAY env override can spoof 'today' past any baseline expiry

correctness

  • 🔵 low convex/templates.tsglm (Claude) [unanchored]: domainHue accepted with no finite/range validation while embedding vectors are strictly validated
  • 🔵 low convex/templates.tsClaude [sub-threshold]: assertEmbeddingDimensions checks length but not that components are finite
  • 🔵 low .github/workflows/deploy.ymlClaude [sub-threshold]: Exact-string Cache-Control comparison is brittle to whitespace/ordering
  • 🔵 low .github/workflows/deploy.ymlClaude [sub-threshold]: Age>=1-on-HIT assertion is intermittently flaky
  • 🔵 low convex/templates.tsagy [sub-threshold]: Pre-migration rows with valid vectors but no marker can loop through paid Gemini repair
  • 🔵 low convex/seed.tsagy [sub-threshold]: Discovery-state cascade is skipped when the source table was already empty
  • 🔵 low src/lib/server/public-discovery-cache.tsClaude [sub-threshold]: forceRefresh joins a pre-existing in-flight load instead of forcing a new one
  • 🔵 low src/routes/api/health/+server.tsagy [sub-threshold]: Health probe reports 503 if discoveryProducerOverdueAt is absent (deploy version skew)
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [sub-threshold]: Shared LKG edge pointer is gated by an isolate-local map (cross-isolate regression risk)
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [sub-threshold]: KV recovery scans a single 1000-key page; newest generation could be missed past that bound
  • ⚪ nit src/lib/server/public-discovery-cache.tsglm (Claude) [sub-threshold]: loadAndCache unconditionally sets memoryCache, unlike the guarded write in persistLoadedEnvelope
  • ⚪ nit src/routes/api/templates/+server.tsCodex [sub-threshold]: [DISPROVEN] Claimed missing-trust_score bypass does not exist

security

  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: Relation snapshot reads skip the runtime re-projection the list path applies
  • 🔵 low src/routes/api/health/+server.tsglm (Claude) [sub-threshold]: Health probe couples liveness to non-critical Atlas and returns backend topology to anonymous callers

1 finding(s) dropped due to unverifiable verbatim quotes (likely fabrication).

Brutalist orchestrator schemaVersion=1 · context_id=6deef47d-4ac8-45f6-a18e-c0e61165002d

Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/templates.ts Outdated
Comment thread convex/templates.ts
Comment thread scripts/check-convex-query-efficiency.mjs
Comment thread scripts/check-convex-query-efficiency.mjs Outdated
Comment thread scripts/check-convex-query-efficiency.mjs Outdated
Comment thread src/routes/api/admin/backfill-embeddings/+server.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
docs/development/deployment.md (1)

30-30: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe PUBLIC_DISCOVERY_KV as a recovery cache, not only ephemeral state.

This namespace also serves as the last-known-good public-discovery shield. Update the adjacent architecture label so operators do not infer that its retained recovery payloads are disposable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/development/deployment.md` at line 30, Update the adjacent KV namespaces
architecture label in the deployment documentation to describe
PUBLIC_DISCOVERY_KV as a recovery cache, explicitly reflecting its retained
last-known-good public-discovery payloads rather than classifying it only as
ephemeral state.
docs/features/templates.md (1)

95-105: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the bounded snapshot semantics.

GET /api/templates no longer returns all public templates; it returns the bounded newest-50 materialized projection. State that limit so API consumers do not treat the response as a complete corpus.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/features/templates.md` around lines 95 - 105, Update the GET
/api/templates documentation to state that it returns only the newest 50 public
templates from the bounded materialized projection, rather than the complete
public-template corpus; preserve the existing ordering and computed-field
descriptions.
scripts/verify-public-discovery-readiness.mjs (2)

63-89: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Enforce the snapshot’s 50-item and unique-ID contracts.

The readiness gate currently accepts more than 50 templates and duplicate IDs, despite the public-output contract. Reject both so a malformed producer generation cannot pass release verification.

Proposed validation
+const MAX_PUBLIC_TEMPLATE_COUNT = 50;
+
 function validateTemplateProjection(name, templates, excludeCwc, errors) {
 	const ids = new Set();
+	if (templates.length > MAX_PUBLIC_TEMPLATE_COUNT) {
+		errors.push(`${name}.templates has more than ${MAX_PUBLIC_TEMPLATE_COUNT} entries`);
+	}
 	for (const [index, template] of templates.entries()) {
 		if (!isRecord(template) || typeof template.id !== 'string' || template.id.length === 0) {
 			errors.push(`${name}.templates[${index}] has no string id`);
 			continue;
 		}
+		if (ids.has(template.id)) {
+			errors.push(`${name}.templates[${index}] duplicates id ${template.id}`);
+		}
 		ids.add(template.id);

The PR objective specifies that public outputs are capped at 50.

Also applies to: 234-245

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/verify-public-discovery-readiness.mjs` around lines 63 - 89, Update
validateTemplateProjection to reject template collections exceeding the 50-item
public-output limit and to report duplicate template.id values instead of
silently accepting them. Preserve the existing per-template validations and use
the ids set to detect duplicates while continuing validation of all entries.

395-426: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Retry if publication changes during the five-query read.

The manifest is fetched before four independent payload queries. A publication between them produces mixed revisions and falsely blocks a healthy deployment. Fetch the manifest again afterward or retry a bounded number of times until one coherent generation is observed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/verify-public-discovery-readiness.mjs` around lines 395 - 426, Update
the public-discovery read flow around the manifest and four payload queries to
detect publication changes during the read by refetching the manifest afterward
and comparing generations. Retry the complete read a bounded number of times
when the generations differ, and pass only a coherent manifest/payload set to
validatePublicDiscoveryReadiness; preserve the existing timeout handling and
query parameters.
src/routes/api/templates/+server.ts (1)

54-63: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Guarantee a non-empty slug before calling Convex.

Titles containing only non-ASCII characters or punctuation resolve to '', causing an unusable route or generic mutation failure. Return a non-empty fallback or a structured slug validation error.

Proposed fallback
 function resolveTemplateSlug(title: string, requestedSlug: string | undefined): string {
 	const sanitized = sanitizeSlug(requestedSlug);
 	if (sanitized) return sanitized;

-	return title
+	const generated = title
 		.toLowerCase()
 		.replace(/[^a-z0-9\s-]/g, '')
 		.replace(/\s+/g, '-')
 		.substring(0, 100);
+
+	return generated || `template-${createHash('sha256').update(title).digest('hex').slice(0, 12)}`;
 }

Also applies to: 403-406, 438-440, 754-762

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/routes/api/templates/`+server.ts around lines 54 - 63, Update
resolveTemplateSlug to guarantee a non-empty result after sanitizing and
deriving the slug from title; when both inputs produce an empty slug, return the
established non-empty fallback or propagate the structured slug validation error
before any Convex call. Ensure all callers, including the referenced template
creation/update flows, use this validation consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@convex/templates.ts`:
- Around line 1037-1075: Update the snapshot generation flow around
candidateScan and the relation-building logic to derive relations from the same
validated, selected template-ID corpus used by the lists, rather than the raw
newest 50 candidates. Ensure invalid or oversized templates cannot remain
relation endpoints and replacement templates receive corresponding edges. Extend
the existing invalid/oversized regression coverage to assert list–relation ID
alignment.

In `@docs/development/deployment.md`:
- Around line 168-197: The deployment documentation currently permits direct
wrangler pages deploy without the release safeguards. Update the manual Pages
deployment guidance to either require the same
verify-public-discovery-readiness.mjs checks, RELEASE_SHA, manifest revision,
and producer-readiness gates as the standard workflow, or explicitly prohibit
direct production uploads; ensure the documented emergency path cannot bypass
those protections.

In `@scripts/check-convex-query-efficiency.mjs`:
- Around line 212-240: Update isQueryFactoryExpression and resolveQueryCall to
follow imported, locally re-exported, and wrapped query-factory bindings instead
of returning false or null when the factory is not locally declared. Ensure
scanPublicQueries fails closed for unresolved query-like public exports so they
are not silently omitted, and add a self-check covering wrapper-factory
resolution.

---

Outside diff comments:
In `@docs/development/deployment.md`:
- Line 30: Update the adjacent KV namespaces architecture label in the
deployment documentation to describe PUBLIC_DISCOVERY_KV as a recovery cache,
explicitly reflecting its retained last-known-good public-discovery payloads
rather than classifying it only as ephemeral state.

In `@docs/features/templates.md`:
- Around line 95-105: Update the GET /api/templates documentation to state that
it returns only the newest 50 public templates from the bounded materialized
projection, rather than the complete public-template corpus; preserve the
existing ordering and computed-field descriptions.

In `@scripts/verify-public-discovery-readiness.mjs`:
- Around line 63-89: Update validateTemplateProjection to reject template
collections exceeding the 50-item public-output limit and to report duplicate
template.id values instead of silently accepting them. Preserve the existing
per-template validations and use the ids set to detect duplicates while
continuing validation of all entries.
- Around line 395-426: Update the public-discovery read flow around the manifest
and four payload queries to detect publication changes during the read by
refetching the manifest afterward and comparing generations. Retry the complete
read a bounded number of times when the generations differ, and pass only a
coherent manifest/payload set to validatePublicDiscoveryReadiness; preserve the
existing timeout handling and query parameters.

In `@src/routes/api/templates/`+server.ts:
- Around line 54-63: Update resolveTemplateSlug to guarantee a non-empty result
after sanitizing and deriving the slug from title; when both inputs produce an
empty slug, return the established non-empty fallback or propagate the
structured slug validation error before any Convex call. Ensure all callers,
including the referenced template creation/update flows, use this validation
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f13fac04-48eb-4a23-998f-bfc55a194840

📥 Commits

Reviewing files that changed from the base of the PR and between 6684b58 and ed91f36.

📒 Files selected for processing (44)
  • .github/workflows/ci.yml
  • .github/workflows/deploy.yml
  • convex/lib/publicDiscovery.ts
  • convex/lib/templateInputBudget.ts
  • convex/observability-service-ping.convex.test.ts
  • convex/observability.ts
  • convex/schema.ts
  • convex/seed-public-discovery.convex.test.ts
  • convex/seed.ts
  • convex/templates-embedding-backfill.convex.test.ts
  • convex/templates-input-budget.convex.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/templates-snapshots.convex.test.ts
  • convex/templates.ts
  • docs/architecture/public-discovery-cache-invariants.md
  • docs/development/deployment.md
  • docs/features/templates.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • scripts/check-convex-query-efficiency.mjs
  • scripts/convex-query-efficiency-baseline.json
  • scripts/verify-public-discovery-readiness.mjs
  • src/lib/components/template-browser/MessageMetrics.svelte
  • src/lib/components/template-browser/parts/ActionBar.svelte
  • src/lib/components/template-browser/parts/PreviewContent.svelte
  • src/lib/server/public-discovery-cache.ts
  • src/lib/server/public-template-queries.ts
  • src/lib/types/component-props.ts
  • src/lib/types/template.ts
  • src/routes/api/admin/backfill-embeddings/+server.ts
  • src/routes/api/templates/+server.ts
  • src/routes/s/[slug]/+layout.server.ts
  • src/routes/template-modal/[slug]/+page.server.ts
  • tests/unit/convex/public-discovery-writer-contract.test.ts
  • tests/unit/convex/template-input-budget.test.ts
  • tests/unit/routes/admin-backfill-embeddings.test.ts
  • tests/unit/routes/health-endpoint.test.ts
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/routes/public-template-recipient-boundary.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • tests/unit/server/public-template-queries.test.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • .github/workflows/ci.yml
  • convex/seed-public-discovery.convex.test.ts
  • tests/unit/convex/public-discovery-writer-contract.test.ts
  • tests/unit/server/public-template-queries.test.ts
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • tests/unit/routes/health-endpoint.test.ts
  • convex/schema.ts
  • tests/unit/convex/template-input-budget.test.ts
  • docs/architecture/public-discovery-cache-invariants.md
  • src/lib/server/public-template-queries.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • src/lib/types/template.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/lib/publicDiscovery.ts
  • convex/seed.ts
  • convex/lib/templateInputBudget.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • src/lib/server/public-discovery-cache.ts
  • convex/observability.ts
  • tests/unit/routes/home-page-load.test.ts

Comment thread convex/templates.ts
Comment thread docs/development/deployment.md
Comment thread scripts/check-convex-query-efficiency.mjs Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/3: Three of four critics (Claude native, Agy/Gemini, and the GLM-routed Claude client) independently converged on one headline: the whole public-discovery subsystem's correctness rests on a single publicDiscoveryManifest singleton and a no-drop OCC invariant that is enforced only by a load-bearing proof comment plus a CI writer-contract ratchet — not by the type system or the database. All three agree the core OCC argument is actually correct today; the risk is fragility (silent breakage when a future writer/projection field/ordering change slips the convention) and, per Agy, write-serialization contention on that hot row. Beyond the shared headline, the critics surfaced several specific, verifiable defects: an asymmetric freeze classifier that lets a non-oversize relations-rebuild failure rethrow while servicePing still reports healthy (GLM); a relations rebuild with no size-shed fallback that freezes forever on oversize (Agy); a permanently-invalid card that re-arms the dirty bit and fires Sentry on every rebuild (Claude native); a self-paging marker migration that stalls permanently if any continuation page throws (GLM); and cold-start listPublic returning an empty homepage indistinguishable from an empty corpus with no live-scan fallback (Claude native). The createTemplate _secret gate was independently judged a genuine security improvement (GLM verified it clean), so the residual concerns there are low. Codex was blocked by a sandbox loopback error and could not read the tree, so it contributed no grounded findings. I verified every quote below against the actual files.

Chunk 2/3: All four critics independently converge on two structural issues: (1) the anonymous-redaction privacy boundary is enforced for the list snapshot family but NOT the relations family (select: (snapshot) => snapshot), and the list check is itself a 3-field denylist rather than an allowlist projection — a producer refactor that adds a field bypasses the guarantee and gets promoted to a 7-day LKG value; and (2) /api/health couples whole-service health and the deploy gate to background discovery-producer readiness, so a homepage-snapshot stall can cascade into a false outage and a deploy freeze. They also agree on the un-instrumented/unbounded cache internals: module-level Maps with no eviction, a single unpaginated KV list whose lexicographic-vs-numeric ordering plus overflow-backoff can yield a blank homepage during recovery, and console.warn-only observability on the critical path. Disagreement is mainly severity: agy rates the KV overflow 'Critical' (overstated — TTL and non-certified overflow handling mitigate it), while native Claude and glm both explicitly declare no ship blockers and credit genuinely correct fixes (abortable health client, fail-closed generation mismatch, atomic slug uniqueness moved into the mutation, distributed backfill lease). Note codex reviewed the diff only (its sandbox could not read files), so its findings were re-verified against the real tree before inclusion. Headline recommendations: add a symmetric relations redaction contract and split liveness from readiness before merge; bound the cache Maps and add metrics shortly after."

Chunk 3/3: All four critics independently converge on one operational risk — the newly committed PUBLIC_DISCOVERY_KV namespace id whose own comment reads as an un-performed 'create then replace' TODO, with no preview/production environment split and no runtime binding assertion; confirm the id is a created namespace before merge. The dominant test-quality theme is change-detector coupling: byte-exact log/header/error strings, exact KV call counts, and positional waitUntil indexing that will veto behavior-preserving refactors of the cache god-object. The critics DISAGREE with the review brief's 'hardcoded time bomb' premise: all clock values are injected (validate(..., { now }) and Date.now spies), so the suites are deterministic — that concern should be downgraded to a cosmetic note about inconsistent epoch conventions. The most consequential genuine gap, raised by the GLM client, is that the POST /api/templates success path (dedup hit + deferred waitUntil work) has zero coverage, making the mocked embedding pipeline dead infrastructure. Codex's review was diff-only (its sandbox failed) and Agy's PII/SSRF/substring-matching claims target source files outside this diff chunk, so those are routed to outOfDiff as unverified follow-ups.

Inline comments: 18 (2 🟠 high · 16 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 454750ms)

Native Claude traced the OCC no-drop argument end-to-end and confirmed it holds, then flagged its fragility (enforced by comment+CI ratchet, not types), cold-start empty-homepage with no live-scan fallback, a perpetual Sentry re-dirty loop on any permanently-invalid card, the createTemplate dual-gate coupling, and post-hoc deploy verification. High-signal, well-grounded with real line numbers.

Native Claude read the files end-to-end. Strongest signal: the anonymous redaction boundary is a 3-field denylist and the relations family has no contract at all (A1/A2), plus the load-bearing 1000-line cache state machine is un-instrumented. Correctly credited fixes: request-local abortable health client, fail-closed generation mismatch, safe embedding index arithmetic (asserted output length), distributed backfill lease. Flagged duplicated trust gate/dead branch (S1). All cited lines verified.

Native Claude read all four test files plus the production modules they exercise. Verdict: tests are under-mocked (good), but are white-box change-detectors welded to log strings, KV key encodings, error substrings, and exact call counts. Headline real risk: unverified PUBLIC_DISCOVERY_KV id degrading silently. Correctly debunked the 'time bomb' premise — clocks are injected.

✅ Codex (default, 67550ms)

Blocked before execution by a sandbox loopback error (bwrap: loopback: Failed RTM_NEWADDR: Operation not permitted). Could not read any file. Honestly declined to fabricate findings and returned only unverified review leads — no groundable output.

Codex could NOT read files (bwrap loopback sandbox failure) and reviewed the diff only, so it partly reacted to injected summary comments. Its substantive findings nonetheless verified against real files: unbounded module-level Maps (memoryCache et al.), unbounded BigInt revision parsing, health endpoint liveness/readiness coupling, and the calendar-driven guardrail expiry. Could not verify createTemplate atomicity or the redaction shape.

Codex's shell sandbox failed (bwrap loopback error), so its review is diff-grounded only, not file-verified. Flagged wrangler KV id + missing preview_id split, over-mocking of the route, mocked error class, byte-exact cache header, and the injected-clock date (which it over-rated as a time bomb). Treat unverified source claims cautiously.

✅ agy (Gemini 3.5 Flash (Medium), 102069ms)

Agy led with the manifest-singleton OCC write hotspot (claimed Critical; downgraded to Medium here as coalescing bounds repeated patches), plus a real gap: rebuildRelationSnapshotImpl has no size-shed fallback and freezes forever on oversize. Also raised a stuck-token-on-rollback concern and createTemplate DoS. Two findings referenced files outside this diff chunk and could not be quote-verified, so were dropped.

Agy read files and produced a dependency map. Overlapping high-value findings: KV list-overflow -> 24h backoff -> blank-homepage recovery risk, relations/list privacy asymmetry, health clock-skew zero tolerance, and scanner AST bypass classes. Its 'Critical' rating on the KV overflow is overstated given the 8-day TTL mitigation and overflow-non-certified handling; downgraded to medium.

Gemini/Agy focused on architecture + security: shared KV namespace pollution across environments, residual v3 PII in KV, SSRF looseness in the readiness script, brittle waitUntil-index assertions, and the brute-force budget loop. Several claims reference source files outside this diff chunk and are routed to outOfDiff as unverified.

✅ glm (Claude) (glm-5.1, 356412ms)

GLM-routed Claude did the most thorough verification: confirmed the OCC argument sound, verified the createTemplate secret gate is clean, and surfaced the sharpest specific defects — asymmetric freeze classifier (relations rethrow leaves servicePing reporting healthy), 6h staleness on live-presented metrics, permanent stall risk in the marker migration, and no lease renewal. Strongest per-finding grounding.

GLM-routed Claude did the deepest end-to-end trace including the Convex backend and the test suite. It confirmed the redaction boundary holds for the list family via v4 namespace isolation and that KV (but not in-memory) is guarded against stale overwrites, then sharpened the two structural findings: health liveness/readiness+deploy-gate coupling (F1) and the relations privacy asymmetry (F2) as the highest-stakes gap. Declared no ship blockers.

GLM-routed Claude client read the full tree and gave the most grounded critique: the 1187-line cache test mirrors a god-object and vetoes refactors; the POST success path is entirely untested with dead embedding mocks; circular api mock hides query-name drift; re-declared error class hides identity drift; brute-force slug boundary. Also correctly debunked the time-bomb premise.

Out-of-diff findings (19)

maintainability

  • 🟡 medium src/lib/server/public-discovery-cache.tsClaude [unanchored]: Load-bearing recovery state machine emits no metrics — only console.warn
  • 🔵 low src/routes/api/templates/+server.tsClaude [unanchored]: Trust gate duplicated with a dead fall-through branch that can drop off the handler with no Response
  • 🔵 low .github/workflows/deploy.ymlClaude [sub-threshold]: Deploy verification is post-hoc with no automated rollback
  • 🔵 low src/lib/server/public-template-queries.tsClaude [sub-threshold]: Privacy invariant is upheld by convention across two files, not by a chokepoint
  • 🔵 low scripts/check-convex-query-efficiency.mjsagy [sub-threshold]: Query-efficiency guardrail is syntactic and routable-around, but its header claims deterministic coverage
  • 🔵 low scripts/check-convex-query-efficiency.mjsCodex [sub-threshold]: Baseline expiry is pinned to the CI runner UTC clock with no override, producing calendar-driven CI reds

correctness

  • 🔵 low src/routes/api/templates/+server.tsagy [unanchored]: Deferred embedding generation failures are only logged, leaving new templates unindexed
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [unanchored]: In-memory cache lacks the stale-revision overwrite guard that protects the KV layer
  • 🔵 low src/routes/api/health/+server.tsagy [sub-threshold]: Producer-overdue health compares edge clock to backend timestamp with zero tolerance
  • 🔵 low src/lib/server/public-discovery-cache.tsCodex [sub-threshold]: revisionOrder BigInt-parses unbounded digit strings

testing

  • 🟠 high tests/unit/routes/templates-api-auth.test.tsglm (Claude) [unanchored]: POST /api/templates success path is completely untested — mocked embedding pipeline is dead test infrastructure
  • 🔵 low tests/unit/server/public-discovery-cache.test.tsagy [sub-threshold]: Asserting execution order by indexing captured waitUntil promises locks tests to the exact count of async ops
  • 🔵 low tests/unit/routes/templates-api-auth.test.tsglm (Claude) [sub-threshold]: Slug-budget test brute-forces a boundary it invented, producing an opaque failure if budgets shift
  • 🔵 low tests/unit/routes/templates-api-auth.test.tsCodex [sub-threshold]: Byte-exact Cache-Control assertion breaks on harmless directive reordering or additions
  • 🔵 low tests/unit/routes/templates-api-auth.test.tsagy [sub-threshold]: Congressional visibility gate is only half-covered — the CONGRESSIONAL:true rail is never exercised

security

  • 🟡 medium wrangler.tomlagy [unanchored]: Legacy v3 KV envelopes containing recipient PII may persist in the shared namespace after the v4 cutover
  • 🔵 low convex/templates.tsClaude [sub-threshold]: createTemplate now couples secret + auth into one call; correct gate, residual coupling/DoS notes

design

  • 🔵 low convex/lib/publicDiscovery.tsClaude [sub-threshold]: 6-hour min rebuild interval presents a stale materialization as live civic-reach metrics
  • 🔵 low convex/templates.tsClaude [sub-threshold]: Embedding backfill lease has no renewal; slow Gemini batches expire mid-batch and fragment

2 finding(s) dropped due to unverifiable verbatim quotes (likely fabrication).

Brutalist orchestrator schemaVersion=1 · context_id=0de34adc-6eac-42a6-8670-830f8ba7981a

Comment thread src/lib/server/public-template-queries.ts Outdated
Comment thread wrangler.toml
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/templates.ts Outdated
Comment thread src/routes/api/health/+server.ts
Comment thread tests/unit/routes/templates-api-auth.test.ts Outdated
Comment thread tests/unit/routes/templates-api-auth.test.ts Outdated
Comment thread tests/unit/server/public-discovery-cache.test.ts
Comment thread tests/unit/server/public-template-queries.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@convex/templates.ts`:
- Around line 1895-1900: Update the fallback in the resolvedSelection flow to
derive relation-only refreshes from the published discovery-list generation
rather than rescanning live templates via preparePublicDiscoveryListPublication.
Reuse the published list IDs or coordinate the list and relation publication so
endpoints cannot include cards absent from the displayed list, and add a
regression covering relation-first scheduling.
- Around line 2236-2323: Update projectPublicDetailRecipientConfig to enforce
one shared 50-address allowlist across projected.emails and decisionMakers:
preserve the existing extraction order, consume the shared budget for
decision-maker email fields, and omit or redact any email that falls outside the
allowlist. Ensure recipientEmails continues to account for every exposed address
without allowing up to 100 combined addresses.

In `@docs/development/deployment.md`:
- Around line 259-264: Update the deployment examples to ensure RELEASE_SHA is
reachable from the target branch before invoking deploy.yml: in
docs/development/deployment.md lines 259-264 and
docs/development/production-secrets-checklist.md lines 456-458, validate against
or derive from origin/staging; in docs/development/quickstart.md lines 361-364
and docs/runbooks/DISASTER-RECOVERY.md lines 108-111, validate against or derive
from origin/production.

In `@docs/runbooks/DISASTER-RECOVERY.md`:
- Around line 25-30: Reword the “Deploy cutover” step so it explicitly describes
running `npx convex deploy --env-file .env.production` after the Convex data
import/recovery step, clarifying that it deploys recovered functions, schema,
and indexes rather than restoring database contents. Preserve the snapshot
verification, gated workflow, exact release SHA, and prohibited direct Wrangler
deployment guidance.

In `@src/lib/server/public-template-queries.ts`:
- Around line 190-193: Update projectObjectArray and its callers to fail closed
for malformed nested arrays: reject non-array values and any elements that are
not valid record/object inputs instead of returning them unchanged, so
disallowed structures such as nested arrays cannot cross the anonymous cache
boundary. Preserve projection only for validated object arrays and ensure the
related handling around the additional referenced block follows the same
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2222a731-5fc5-43e3-afde-90f9c4258850

📥 Commits

Reviewing files that changed from the base of the PR and between ed91f36 and 1cda46a.

📒 Files selected for processing (33)
  • .github/workflows/deploy.yml
  • convex/templates-embedding-backfill.convex.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/templates-snapshots.convex.test.ts
  • convex/templates.ts
  • docs/architecture/rate-limiting.md
  • docs/development/deployment.md
  • docs/development/maintenance.md
  • docs/development/production-secrets-checklist.md
  • docs/development/quickstart.md
  • docs/features/templates.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • docs/runbooks/DISASTER-RECOVERY.md
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • scripts/check-convex-query-efficiency.mjs
  • scripts/verify-public-discovery-readiness.mjs
  • src/lib/core/security/rate-limiter.ts
  • src/lib/server/public-discovery-cache.ts
  • src/lib/server/public-template-queries.ts
  • src/routes/api/health/+server.ts
  • src/routes/api/live/+server.ts
  • src/routes/api/templates/+server.ts
  • tests/unit/routes/health-endpoint.test.ts
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/routes/live-endpoint.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • tests/unit/security/rate-limiter.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • tests/unit/server/public-template-queries.test.ts
  • wrangler.toml
🚧 Files skipped from review as they are similar to previous changes (13)
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • src/routes/api/health/+server.ts
  • convex/templates-read-budget.convex.test.ts
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • tests/unit/routes/health-endpoint.test.ts
  • convex/templates-embedding-backfill.convex.test.ts
  • wrangler.toml
  • src/routes/api/templates/+server.ts
  • docs/features/templates.md
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • scripts/check-convex-query-efficiency.mjs

Comment thread convex/templates.ts Outdated
Comment thread convex/templates.ts
Comment thread docs/development/deployment.md
Comment thread docs/runbooks/DISASTER-RECOVERY.md Outdated
Comment thread src/lib/server/public-template-queries.ts Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/3: All three reachable critics converge on four themes: (1) the public unauthenticated servicePing query leaks internal producer-health and refresh-timing state, giving anonymous callers a liveness/degradation oracle; (2) the entire "no-drop" snapshot guarantee is correct but load-bearing on an unconditional in-transaction manifest read plus a static-AST CI ratchet — a concurrency property enforced only by a linter with documented blind spots, never a real interleaving test; (3) the 6-hour minimum rebuild interval means write-driven public changes (new published templates, endorsement/reach counts) can be stale for up to 6h with no fast-path, a likely launch-blocker; and (4) deploy-workflow hygiene nits (hardcoded Cloudflare account/KV IDs, an inconsistent direct ${{ secrets }} interpolation in the pre-existing CDN-purge step, a brittle double-quote-only TOML parser). The critics also independently verified that the deploy gating (source-verify ancestry + fork protection + secret ordering) and the prototype-pollution fixes (Object.create(null), isPlainObject) are genuinely correct — the review's positive findings, not just its complaints. Codex could not access the filesystem and contributed only unverified corroboration; agy timed out. I downgraded severities to match verified evidence: nothing here is critical or high — the deploy gating that would carry high severity was found sound.

Chunk 2/3: All four critics agree the core thesis is sound and well-executed: the PR replaces three unbounded embedding-bearing .collect() scans with bounded materialized snapshots and force-redacts recipient data at BOTH the producer (enrichPublicTemplates) and the read boundary (projectStoredPublicTemplate), so even un-migrated legacy snapshot rows cannot leak on the anonymous list path. No critic could construct an end-to-end raw-recipient leak on the discovery/list path. The strongest agreed concern (glm + codex, high) is the getBySlugPublic detail boundary: it is a directly-public Convex query whose decision-maker allowlist includes email plus scraping-provenance metadata (emailSource, source_url, provenance, positionSourceDate, recencyCheck) — a real exposure to anonymous scraping that is either an undocumented privacy tradeoff or an over-broad allowlist. The most actionable correctness bug (glm, medium) is the write-driven relation flush leaving the family dirty-but-unscheduled when publish throws, relying on the daily cron backstop for recovery. Notable disagreement/error: agy's two most severe findings (Critical getBySlug raw-doc leak; High transient-failure freeze clearing listDirtyAt) were both verified FALSE against the source and discarded — getBySlug returns a minimal 5-field projection and is unchanged by this PR, and the freeze path never passes previousFailure so listDirtyAt is retained. Remaining valid items are medium/low: manifest-singleton OCC contention, aggregate-shed not backfilling, legacy queries ignoring excludeCwc, two divergent top-50 selectors, strict-schema silent card shedding, and several count/dead-code nits.

Chunk 3/3: All four critics converge on two genuine systemic risks: (1) the preview/production KV namespace is shared (isolated only by Convex-backend origin + schema version), so a preview build can pollute production's last-known-good discovery state, and (2) readLatestKvRevision does a single un-cursored KV list({limit:1000}) while revision keys sort lexicographically, creating a silent LKG-recovery cliff once published revisions exceed ~1000 in the 8-day TTL window. Both are real but fail closed (the overflow path marks results uncertified and backs off), so they degrade availability/recovery quality rather than leak data or serve certified-wrong data — I've downgraded the "Critical" framings accordingly. The critics also legitimately flagged the health endpoint coupling a hard 503 to an optional KV binding (checked structurally, not functionally), the fail-closed public projection turning one malformed template into a global 503, denormalized recipient_count now outranking the authoritative recipient list on private send screens, and a NaN-trust_score edge that bypasses only the early cost-shield gate (the post-moderation gate still rejects, so it wastes AI calls rather than granting write access — agy's "security bypass" is overstated). The strongest-verified positive: the recipient redaction contract, exhaustive-allowlist compile-time guard, BigInt digit-bound, and readiness URL validation are all sound. Remaining items (slug collapse divergence, endorsementCount decoupling, backfill 200-on-failure, non-transitive comparator, http source URLs) are low-severity.

Inline comments: 16 (3 🟠 high · 13 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 448844ms)

Native Claude read every changed file and traced source-write -> dirty-mark -> scheduler -> flush -> snapshot -> read. Verified the no-drop OCC argument holds but flagged its fragility (unconditional manifest read + AST ratchet blind spots), the servicePing overdueAt timing leak, the CDN-purge direct-secret interpolation, brittle KV TOML parser, hardcoded infra IDs, and the JSON-budget post-parse (not request-size) limitation. Confirmed deploy gating and prototype-pollution fixes are correct.

Native Claude critic. Read the real dependencies (lib/publicDiscovery.ts, submissions.ts dailyArrivals writer, schema, getBySlugPublic gate). Concluded the PR closes a pre-existing PII leak rather than opening one: list path fully redacted at producer + read boundary, endorsement count uses the authoritative denormalized counter, aggregate-shed is deterministic, normalizeDailyArrivalsForSnapshot matches writer semantics, and classifyPublicTemplateSnapshotFreeze handles all thrown prefixes. Independent findings: F1 strict snapshot schema silently sheds cards if a required field becomes optional-in-DB (medium), F2 cross-family coherence only holds within the composite rebuild (low).

Native Claude read the actual files and largely validated the design as careful/over-engineered; earned findings on the KV recovery cadence ceiling, shared preview/prod KV, denormalized recipient_count trusted on the private send path, endorsementCount overflow assumption, budgeted-vs-sent slug divergence, and kvBound being shape-only. Verified BigInt bound, redaction, health abort, and readiness URL validation as sound.

✅ Codex (default, 83424ms)

Sandbox blocked filesystem and the GitHub connector could not resolve the repo, so Codex reviewed only the pasted diff summary without exact line citations. Corroborated (unverified) the servicePing oracle, missed-dirty-marking brittleness, OCC race concern, 6h staleness tradeoff, prototype-pollution narrowness, and recursive-JSON DoS surface.

Codex critic ran without filesystem access (sandbox bwrap/loopback failure) and reviewed from the diff + included schema/docs, disclosed explicitly. Findings: public detail boundary broad by design exposing emails + decision-maker metadata to anonymous callers (high); SNAPSHOT_CONFIG validates config-shaped fields generically so safety depends entirely on the read-boundary projection (architectural foot-gun); relation cron swallows unknown prep failures as 'failed' (medium); aggregate shedding does not backfill (medium); legacy relatednessEdges/conceptRelations ignore the excludeCwc variant (medium); endorsingOrgs is now a sampled array while endorsementCount looks authoritative (medium).

Codex's sandbox shell failed (bwrap loopback) and its GitHub fetch 404'd, so it reviewed from the diff text only without line numbers. Its substantive claims (shared KV namespace, one-page KV list recovery, string-parsed revision monotonicity, silent empty homepage on cache failure, http URL acceptance) match the code, but it could not cite exact lines and overstated two items to Critical.

✅ glm (Claude) (glm-5.1, 361423ms)

glm-5.1 via routed Claude client read the code and independently identified the empty-patch branch as the real no-drop hinge (dependent on Convex range-read conflict tracking, untested by any concurrency test), the 6h freshness floor as a launch-blocker, the servicePing public health oracle, hardcoded Cloudflare account/KV IDs, the JSON double-serialize amplification, and the writer-contract ratchet's dynamic-patch blind spots. Confirmed deploy gating and the tagConceptMap null-prototype fix are correct.

GLM-routed Claude client. Traced the full producer path, coalescing control plane, input-budget gate, secret helper, and schema. Agreed the list/discovery redaction is the strongest part (force-redacted at producer AND read boundary; found no provable end-to-end raw-recipient leak). Findings: H1 getBySlugPublic publishes decision-maker provenance/scraping-source fields to anonymous users (high); H2 write-driven flush stalls the family dirty-but-unscheduled on a publish throw until the daily cron (medium/high); M1 two divergent top-50 selectors; M3 countRecipientsConvex dedup mismatch; M4 cloneSnapshotConfig dead code; L4 migration can leave a valid-vector row permanently 'missing'; L5 isFiniteEmbeddingVector silently drops non-768 vectors; plus god-module and OCC load-bearing observations.

glm-routed Claude traced paths end-to-end and produced the most rigorous writeup: shared-namespace quota contention, health coupled to an optional binding, TTL-vs-monotonic-write-gate interaction under producer stall, list-limit staleness cliff, plus low-severity slug/endorsement/dead-branch defects. Explicitly listed the parts it verified as sound (redaction, allowlist guard, BigInt bound, readiness URL, backfill lease, /api/live exemption).

✅ agy (Gemini 3.5 Flash (Medium), 360017ms)

Antigravity (Gemini 3.5 Flash) timed out after 360s and produced no analysis.

Antigravity/Gemini critic. Its headline 'Critical' (getBySlug returns raw Doc with recipientConfig/embeddings) was FALSE and discarded — getBySlug returns only {id,slug,title,status,isPublic} and is unchanged by this PR. Its 'High' transient-freeze-clears-listDirtyAt claim was also FALSE and discarded — the freeze path passes no previousFailure, so listDirtyAt is retained. Valid retained findings: OCC contention on the publicDiscoveryManifest singleton across every mutation (medium); O(n^3*d) twin/calibration compute inside a mutation, bounded by the 50-row cap (low); concept-entry prefix shedding not quality-ranked (low, and its 'non-deterministic' framing was overstated); legacy endorsementCount fallback capped at 6 (low).

Agy gave the most specific line-cited critique: lexicographic KV truncation, NaN trust_score early-gate bypass, single-record fail-closed 503, non-transitive newestEnvelope comparator, MessageMetrics/ActionBar recipient-count divergence, and backfill 200-on-failure. Severity inflation on the trust gate (caught by the later gate) and the KV cliff (fails closed), but the underlying code references are accurate.

Out-of-diff findings (24)

maintainability

  • 🔵 low src/routes/api/templates/+server.tsglm (Claude) [unanchored]: Trust gate is duplicated after moderation; NaN handling differs between the two copies
  • 🔵 low .github/workflows/deploy.ymlClaude [sub-threshold]: Hand-rolled KV TOML parser only matches double-quoted binding/id and fails closed on any reformat
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: cloneSnapshotConfig / SNAPSHOT_CONFIG is unreachable dead code masquerading as a safety net
  • 🔵 low src/routes/+page.server.tsCodex [sub-threshold]: Cache/Convex failure on the homepage is masked as an empty template list
  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsagy [sub-threshold]: Backfill returns 200 with processed:0 when the whole batch fails

security

  • 🔵 low .github/workflows/deploy.ymlClaude [unanchored]: CDN-purge step interpolates ${{ secrets }} directly into the run script, inconsistent with every other CF-token consumer
  • 🔵 low convex/observability.tsClaude [sub-threshold]: Public unauthenticated servicePing leaks producer-health and refresh-timing as an anonymous oracle
  • 🔵 low convex/observability.tsglm (Claude) [sub-threshold]: servicePing turns internal producer failure into a public beacon
  • 🔵 low convex/observability.tsCodex [sub-threshold]: servicePing exposing manifest state can become an operational oracle
  • 🔵 low .github/workflows/deploy.ymlClaude [sub-threshold]: Cloudflare account ID and KV namespace ID hardcoded as literals in the workflow
  • 🔵 low src/routes/api/templates/+server.tsCodex [sub-threshold]: Source URL validation accepts plain http:// links

correctness

  • 🔵 low convex/templates.tsCodex [unanchored]: Relation cron attempt swallows unknown preparation failures as a normal 'failed' status
  • 🔵 low convex/templates.tsClaude [unanchored]: Cross-family list/relation coherence only holds within the composite rebuild, not across the independent crons/tokens
  • 🔵 low convex/templates.tsagy [sub-threshold]: Concept entries derived via Object.entries are prefix-sheddable in key order, not quality order
  • 🔵 low convex/templates.tsagy [sub-threshold]: Legacy templates without denormalized endorsementCount fall back to a value capped at 6
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: countRecipientsConvex can exceed recipientEmails.length because decision-maker count is not deduped
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: migrateTopicEmbeddingMarkers can leave a valid-vector row permanently 'missing' when both timestamps are undefined
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [sub-threshold]: Lexicographic revision keys make the 1000-key list bound a hard limit, not a sample
  • 🔵 low src/lib/components/template-browser/MessageMetrics.svelteagy [sub-threshold]: Recipient-count fallback order diverges between MessageMetrics and ActionBar
  • 🔵 low src/routes/api/templates/+server.tsglm (Claude) [sub-threshold]: Title-derived slug skips the hyphen-collapse/trim that sanitizeSlug performs
  • 🔵 low src/lib/components/template/TemplateCard.svelteClaude [sub-threshold]: endorsementCount overflow math assumes it equals endorsingOrgs.length but the type says otherwise
  • ⚪ nit src/lib/server/public-discovery-cache.tsagy [sub-threshold]: newestEnvelope sort comparator is non-transitive when a candidate revision is unparseable

perf

  • 🔵 low convex/lib/templateInputBudget.tsClaude [sub-threshold]: JSON byte budget is enforced after a full JSON.stringify + TextEncoder pass, not as a streaming/request-size limit
  • 🔵 low convex/templates.tsagy [sub-threshold]: computeTwinEdges/computeCalibration run heavy O(n^3*d) math synchronously inside a Convex mutation

1 finding(s) dropped due to unverifiable verbatim quotes (likely fabrication).

Brutalist orchestrator schemaVersion=1 · context_id=6bcb2bbf-5d4d-4ebf-8c4c-b4e56b7d62af

Comment thread convex/templates.ts Outdated
Comment thread convex/templates.ts Outdated
Comment thread wrangler.toml Outdated
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/templates.ts Outdated
Comment thread src/lib/components/template-browser/parts/ActionBar.svelte
Comment thread src/lib/server/public-discovery-cache.ts
Comment thread src/routes/api/health/+server.ts Outdated
Comment thread src/routes/api/templates/+server.ts Outdated
@ejmockler

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Brutalist Review

Chunk 1/4: All four critics converge on three issues and broadly agree the PR is unusually well-reasoned rather than broken. (1) servicePing is flagged by every critic as an unauthenticated public query leaking discovery-producer health and an overdue scheduler timestamp — severity ranges low-to-high; calibrated to low/medium since it exposes booleans + one derived timestamp, not PII or raw revisions. (2) The seed.ts clearTable cascade (all four) wipes ALL public-discovery state tables on ANY single source-table clear, and the unguarded delete sits outside the per-row try/catch that protects the ordered wipe — fail-closed but over-broad and a half-wipe hazard. (3) The 'no-drop' OCC guarantee (claude, codex, glm) is correct today but enforced only by comments, an AST writer-contract test, and hand-maintained table inventories that already disagree (seed.ts includes debateArguments; the contract test does not) — verified. Disagreement is mainly on severity and on codex's JSON.stringify concern, which native-claude and agy independently verified as actually correct. Deploy gate logic, stale-CI skip, the tag_concepts prototype-pollution fix, and templateInputBudget cross-runtime validation were checked and confirmed sound by multiple critics — no findings emitted there. Headline: no live bug, but a cluster of correct-but-fragile implicit invariants (snapshot ordering, writer contract, dual inventories, v.any() snapshot payload) that CI does not defend, plus one genuine unauthenticated info-disclosure surface.

Chunk 2/4: All four critics converge on one theme: the request-path snapshot refactor and its freeze/recover/token state machine are well-engineered (GLM traced the scheduler end-to-end and found no lost-update or double-execution race; size-guard/shedding, lease protocol, and composite atomicity check out), but the PUBLIC REDACTION BOUNDARY is applied inconsistently. The list path is doubly redacted and safe, yet the neighboring anonymous getBySlugPublic query still (a) rebuilds a recipient roster classified by email shape rather than value, (b) exposes personalPrompt/accountabilityOpener prompt assets, and (c) passes raw sources/research_log through unfiltered. GLM's sharpest structural point (A1): the load-bearing redaction is a hardcoded string list decoupled from the type system, so cloneSnapshotConfig is dead-but-dangerous and the next config-typed schema field could silently leak. Disagreement is mostly severity calibration: codex (no file access) and agy inflate several items to CRITICAL, and agy's 'infinite backfill loop' is incorrect (backfill self-resolves non-768 rows). The recipient-roster exposure is documented as intentional, so it is a design/enforcement-gap to confirm rather than a clear bug. Headline actionable items: fix the cron-recovery token equality asymmetry (native Claude), encode config redaction as a type-level invariant rather than a string list (GLM A1), and restrict projectPublicHttpUrl to https with a non-author-asserted grounding flag.

Chunk 3/4: All four critics agree the hardest pieces are correctly built: the mailto header-injection hardening (independent component encoding) and the distributed backfill lease (atomic, token-checked) are sound — claude and glm explicitly traced and refused to manufacture doubt about them. The real, verified issues cluster in defense-in-depth and operability: (1) the runtime projection never re-enforces excludeCwc or is_public/status, trusting the producer where the deploy-time verify script does not (claude, glm); (2) the backfill batches 20 templates into one Gemini call, so one oversized/poison row stalls the entire backlog permanently (claude, codex, agy); (3) /api/health couples whole-app health and the deploy gate to a single KV binding (all four); and (4) the KV-list overflow path can serve a non-newest LKG generation and install a 24h backoff, plus parseEnvelope returns cached values unre-projected (agy, glm, codex). Disagreements were resolved by reading the tree: agy's two most severe claims (setCwcVerification _secret, unconditional 429 lease release) are factually wrong and were discarded, and its 'High' mailto severity was overstated. Headline: the code is high-quality, but its privacy and availability invariants live in prose and single boundaries — the excludeCwc runtime gate and the backfill poison-pill are the two items worth fixing before merge.

Chunk 4/4: All four critics converge on one clear pre-merge fix: the SSR-hydration 'test' that readFileSync-greps src/routes/+page.svelte for a source string (templates-ssr-hydration.test.ts:127-133) is a spelling check masquerading as behavioral coverage — brittle to reformatting and blind to the untrack invariant it appears to guard. Strong secondary agreement on the wrangler.toml risks: a future-dated 'verified' comment (line 110) in a file that deploys treat as authoritative, and a single KV namespace shared by preview and production with admittedly shared quotas (line 113), where the 'configured backend' isolation dimension is degenerate because both environments share one PUBLIC_CONVEX_URL. The deepest disagreement-driven signal is glm's argument that the last-known-good outage path returns cached v5 envelopes without re-applying the anonymous allowlist — a latent (not present) PII risk the green test suite cannot currently expose; surfaced as an outOfDiff FILE note. Two claims were discarded/downgraded after verification: Codex's 'High: tests bless exposure of secret/private fields' is a demonstrable misread (Codex was sandbox-blocked; the tests actually assert not.toContain('webhookSecret'/'private@example.test'/'ownerEmail')), and Agy's 'Critical: permanent 24h backoff' is mitigated by the tested daily-retry behavior. Net: the test suites are strong where they lock down security-critical write-time invariants; the actionable debt is the grep test, the future date, the shared-quota SPOF, and the un-tested LKG read-path allowlist gap.

Inline comments: 23 (2 🟠 high · 21 🟡 medium)

Per-CLI breakdown

✅ Claude (default, 397652ms)

Native Claude: unusually careful engineering; most load-bearing reasoning holds. Flagged the no-drop proof's unstated creation-time ordering premise (medium), the clearTable cascade being outside the per-row try/catch and its over-broad blast radius (medium x2), and servicePing operational leak (low). Verified deploy gate, stale-CI skip, prototype-pollution fix, and templateInputBudget as correct.

Native Claude read the file at HEAD. Confirmed the list-path redaction holds (projectStoredPublicTemplate hard-overrides all config/recipient fields; object case iterates schema keys only). Found: (1) detail-path recipient projection classifies emails by shape not value on an uncapped anonymous query; (2) cron failure-recovery clears scheduler tokens without the equality guard the scheduled path has; (3) daily_arrivals/tier_counts length not clamped before validation (latent, guarded upstream); (4) raw sources/research_log on detail page. Cleared size/shedding logic, lease protocol, composite atomicity, and URL projection as correct.

Native Claude read the working tree at HEAD. Rated the PR 'unusually careful': allowlist projection, revision-generation matching, bounded maps, BigInt-parse guard, and mailto hardening all sound. Two merge-blockers: runtime excludeCwc not re-enforced in the projection (only checked at deploy), and the backfill batch poison-pill stall. Traced the LKG/revision state machine and epoch guard and found no defect. Flagged is_public/status projection gap and internal-cache-path exposure as lower-severity notes.

Native Claude Code. Strongest signal: the source-grep meta test (#1) and the future-dated wrangler verification comment (#2) as cheap pre-merge fixes; flagged shared preview/prod KV quota and divergent test fakes. Credited the genuinely strong v4->v5 security regression tests and KV-write-frugality coverage. Balanced and accurate.

✅ Codex (default, 93066ms)

Codex ran without filesystem access (sandbox bwrap failure) and reviewed from the diff text only, labeling that limitation. Raised servicePing disclosure (high→calibrated medium), clearTable cascade (high), scattered no-drop contract (high), organizations.update under-scoped invalidation (medium), JSON.stringify undefined handling (medium→calibrated low, largely refuted), and CI coverage artifact hiding (low).

Codex could NOT read the workspace (sandbox networking failure) or the PR via connector; its review is grounded only in the paraphrased diff, so line references are unverified and severities are inflated. Raised: createTemplate mixing public-mutation auth with internal secret (CRITICAL — mitigated by documented server-only call path), detail-path PII reintroduction, no live-scan fallback = outage risk, token-only scheduler guards, largest-card shedding, 250-row index-order dependency, projectPublicHttpUrl accepting http:/private hosts, and 768-dim hardcoding. Directionally overlaps the other critics but should be weighted lightly given no file access.

Codex's sandbox blocked all shell access (bwrap loopback failure) and GitHub lookup could not resolve the repo, so its review was constrained to the diff summary without exact-line verification (self-disclosed). Raised architectural concerns: public discovery now a load-bearing consistency system, two-tier cache poisoning surface if cached values aren't revalidated on read, projection allowlist as single privacy boundary, health mixing readiness with liveness, and lease-release ownership. Its parseEnvelope/two-tier-trust concern was anchorable and overlaps glm; other items were paraphrase-only.

Sandbox-blocked (bwrap loopback failure) so reviewed from the diff summary only. Its headline 'High: tests bless exposure of secret/private fields' is a misread — the tests assert those fields are NOT persisted (not.toContain). Discarded. Its KV get() eager-parse observation is a valid low-severity note.

✅ agy (Gemini 3.5 Flash (Medium), 67074ms)

Antigravity/Gemini: flagged brittle double-quote-only TOML regex in deploy.yml (high→calibrated medium), 6-hour rebuild staleness window (medium), seed cascade cold-start (medium), and servicePing exposure (low). Verified OCC no-drop reasoning, deploy gate skip path, stale-CI guard, prototype fix, and input budget as sound/correct.

Agy (Gemini) produced line-cited findings. Strongest: getBySlugPublic exposes personalPrompt/accountabilityOpener + roster to anonymous callers (real, though documented as intentional), and aggregate-shed shrinks the catalog without backfill (real behavior, fail-safe). Overstated: 'infinite backfill loop' for non-768 vectors (backfill actually overwrites and sets the marker, so it self-resolves), OCC-abort framing (bounded by batching), and the God-object/refactor complaint (structural opinion, not a defect). patchMetadata cache-churn is a minor bounded concern.

Agy produced the most findings and the most misses. Two headline claims were verified FALSE and discarded: 'setCwcVerification missing _secret causes silent failure' (that mutation uses requireAuth, not requireInternalSecret) and 'unconditional lease release on failed 429 acquisition' (the throw is before the try/finally). Verified-valid contributions: backfill poison-pill, health kvBound coupling, KV-list overflow lockout, non-transitive newestEnvelope sort, and the pre-existing isTemplate subject/title bug and ADMIN_USER_IDS whitespace. Its mailto 'High' severity was overstated (recipients are bare addresses, not display names).

Cited many source-file line numbers outside this diff chunk. Its 'Critical: permanent 24h backoff on 1000-key overflow' is mitigated by the tested daily-retry behavior (kept in synthesis, not as a critical finding). Valid contributions: shared preview/prod KV namespace risk and the filesystem-coupling angle on the grep test.

✅ glm (Claude) (glm-5.1, 460932ms)

GLM-routed Claude: deepest trace. Headline is that the whole no-drop guarantee rests on an AST writer-contract test plus two hand-maintained table inventories that already diverge (debateArguments). Additional findings: publicTemplateSnapshots.templates v.any() has no embedding-strip backstop (medium), inventory divergence (medium), manual-verify vs workflow_run coverage asymmetry (medium), servicePing failure-state leak (medium), incrementTemplateReach hot-path staleness (low). Confirmed deploy gate, stale-CI skip, prototype fix, and input budget correct.

GLM-routed Claude read the file plus schema and writers, and traced the scheduler token state machine end-to-end, finding NO lost-update or double-execution race — the strongest verification of the change. Best-grounded findings: A1 (redaction is a hardcoded string list divorced from the type system; cloneSnapshotConfig is dead-but-dangerous — a future config field silently leaks), S1 (raw sources/research_log on detail), S2 (http:/author-controlled emailGrounded trust URL), C1 (inconsistent cold-start contract), C2 (blocked-by-list relation freeze has no relations-side recovery until a list write or daily cron). Verified array caps match writers (no daily_arrivals bug) and size/shedding logic is correct.

GLM-routed Claude did the deepest cross-repo tracing: confirmed /api/health is a hard deploy gate, the backfill lease is atomic and token-checked, content-hash dedup is user-scoped (no IDOR), and the mailto hardening is genuinely sound. Strongest net-new findings: parseEnvelope returns cached value unre-projected (shared-KV origin-scope assumption is the only backstop), KV-list overflow serves a non-newest generation, and the verify script re-checks fewer invariants than the TS contract plus a duplicated projection-version literal. Correctly refuted several agy claims.

Claude-routed (GLM) client. Deepest read; strongest unique contribution is the LKG-read-path-serves-raw-v5-envelope argument (surfaced as an outOfDiff FILE finding, downgraded to medium since present writers all project). Also corroborated the grep test, setTimeout(0) flake, divergent mocks, and count-based assertion brittleness.

Out-of-diff findings (23)

security

  • 🟡 medium convex/templates.tsglm (Claude) [unanchored]: getBySlugPublic returns raw sources/research_log (v.any) to anonymous callers while carefully allowlisting recipient_config
  • 🟡 medium tests/unit/server/public-template-queries.test.tsglm (Claude) [unanchored]: LKG outage path returns cached envelope values without re-applying the anonymous allowlist (latent PII risk)
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: projectPublicHttpUrl accepts http: and any host, backing an author-controlled 'emailGrounded' trust signal
  • 🔵 low convex/templates.tsCodex [sub-threshold]: createTemplate now gates a public mutation on an internal shared secret (verify server-only call path)
  • 🔵 low src/lib/server/public-template-queries.tsClaude [sub-threshold]: Projection allowlists fields but never re-checks is_public/status row selection

maintainability

  • 🟡 medium tests/unit/convex/public-discovery-writer-contract.test.tsglm (Claude) [unanchored]: Entire no-drop correctness invariant is enforced only by a single AST-walking Vitest file with hand-maintained literal maps
  • 🔵 low scripts/verify-public-discovery-readiness.mjsglm (Claude) [sub-threshold]: Deploy-gate verify script checks fewer invariants than the TS projection contract
  • 🔵 low tests/unit/stores/templates-ssr-hydration.test.tsagy [sub-threshold]: readFileSync of a Svelte source file inside a unit test couples the suite to CWD/layout

correctness

  • 🔵 low convex/templates.tsCodex [unanchored]: No live-scan fallback makes any bad/missing snapshot state a hard availability regression
  • 🔵 low src/lib/stores/templates.svelte.tsagy [unanchored]: isTemplate type-guard validates template.title for the 'subject' field (pre-existing)
  • 🔵 low src/routes/api/admin/backfill-embeddings/+server.tsagy [unanchored]: ADMIN_USER_IDS split on raw commas without trimming whitespace (pre-existing)
  • 🔵 low convex/lib/templateInputBudget.tsCodex [sub-threshold]: Byte budget is computed from JSON.stringify output, so undefined/omitted fields are counted differently than the structural node walk
  • 🔵 low convex/templates.tsglm (Claude) [sub-threshold]: Inconsistent cold-start contract: listPublic throws, publicDiscoveryList returns revision-0 empty payload for the same missing-snapshot condition
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [sub-threshold]: newestEnvelope comparator can be non-transitive when compareRevisions returns null
  • 🔵 low src/lib/server/public-discovery-cache.tsagy [sub-threshold]: Edge LKG pointer write is gated on per-isolate requested-revision state
  • 🔵 low src/lib/services/emailService.tsClaude [sub-threshold]: encodeMailboxForMailto neutralizes header injection but does not validate mailbox well-formedness

perf

  • 🔵 low convex/templates.tsagy [unanchored]: Snapshot rebuild issues hundreds of reads in one mutation transaction (OCC contention risk)
  • 🔵 low convex/submissions.tsglm (Claude) [sub-threshold]: incrementTemplateReach dirties the list on every verified congressional send (delivery hot path)

testing

  • 🔵 low .github/workflows/ci.ymlCodex [sub-threshold]: Coverage steps gated on hashFiles(...) silently vanish if test:coverage stops emitting the artifact
  • 🔵 low tests/unit/server/public-template-queries.test.tsClaude [sub-threshold]: Divergent KV mock ignores cursor/limit, unlike the sibling suite's paginated fake
  • 🔵 low tests/unit/server/public-template-queries.test.tsCodex [sub-threshold]: KV get() fake eagerly JSON.parses, which can mask a real Cloudflare KV parse-mode mismatch

design

  • 🔵 low convex/templates.tsagy [sub-threshold]: Aggregate-size shedding shrinks the public catalog without backfilling from remaining candidates
  • 🔵 low convex/templates.tsagy [sub-threshold]: patchMetadata lets any template owner force repeated public-discovery dirtying / rebuild scheduling

Brutalist orchestrator schemaVersion=1 · context_id=07b2eae4-c1d9-442e-829f-6ef9d331405f

Comment thread convex/lib/publicDiscovery.ts
Comment thread convex/seed.ts Outdated
Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/deploy.yml Outdated
Comment thread convex/lib/publicDiscovery.ts
Comment thread src/routes/api/health/+server.ts Outdated
Comment thread tests/unit/server/public-discovery-cache.test.ts Outdated
Comment thread tests/unit/stores/templates-ssr-hydration.test.ts Outdated
Comment thread wrangler.toml Outdated
Comment thread wrangler.toml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
convex/templates.ts (1)

4003-4006: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Treat non-finite 768-length tag vectors as missing.

The selector checks only vector length, while relation generation requires isFiniteEmbeddingVector. A legacy NaN/Infinity vector is therefore considered covered here, rejected by the graph builder, and never repaired.

Proposed fix
-            .filter((te) => te && Array.isArray(te.embedding) && te.embedding.length === 768)
+            .filter((te) => te && isFiniteEmbeddingVector(te.embedding))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@convex/templates.ts` around lines 4003 - 4006, Update the tag embedding
filter used to build covered in the relation-generation flow so 768-length
vectors are included only when they also pass isFiniteEmbeddingVector. This
keeps invalid NaN or Infinity vectors uncovered and eligible for repair,
matching the graph builder’s validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/server/public-template-queries.ts`:
- Around line 213-270: Update projectPublicTemplateCard to validate every field
selected by PUBLIC_TEMPLATE_FIELDS before caching, including required-field
presence and primitive/array runtime shapes such as message_body. Reconstruct
the projected card from validated values rather than relying on pickFields and
the final type assertion; preserve the existing nested-object validation and
sanitized recipient/config fields.

---

Outside diff comments:
In `@convex/templates.ts`:
- Around line 4003-4006: Update the tag embedding filter used to build covered
in the relation-generation flow so 768-length vectors are included only when
they also pass isFiniteEmbeddingVector. This keeps invalid NaN or Infinity
vectors uncovered and eligible for repair, matching the graph builder’s
validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: af6cb7f0-c636-4ec1-a3f3-fdfbf98a7317

📥 Commits

Reviewing files that changed from the base of the PR and between ed91f36 and 81cfd2b.

📒 Files selected for processing (46)
  • .github/workflows/deploy.yml
  • convex/crons.ts
  • convex/lib/publicDiscovery.ts
  • convex/templates-embedding-backfill.convex.test.ts
  • convex/templates-read-budget.convex.test.ts
  • convex/templates-snapshots.convex.test.ts
  • convex/templates.ts
  • docs/architecture/public-discovery-cache-invariants.md
  • docs/architecture/rate-limiting.md
  • docs/development/deployment.md
  • docs/development/maintenance.md
  • docs/development/production-secrets-checklist.md
  • docs/development/quickstart.md
  • docs/features/templates.md
  • docs/ops/CONVEX-PUBLIC-DISCOVERY-IO.md
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • docs/ops/CRON-PROFILES.md
  • docs/runbooks/DISASTER-RECOVERY.md
  • docs/strategy/public-discovery-release-hypergraph/docs/WORKFLOW.md
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • scripts/check-convex-query-efficiency.mjs
  • scripts/verify-public-discovery-readiness.mjs
  • src/lib/core/security/rate-limiter.ts
  • src/lib/server/public-discovery-cache.ts
  • src/lib/server/public-template-queries.ts
  • src/lib/services/emailService.ts
  • src/lib/stores/templates.svelte.ts
  • src/routes/+page.server.ts
  • src/routes/+page.svelte
  • src/routes/api/health/+server.ts
  • src/routes/api/live/+server.ts
  • src/routes/api/templates/+server.ts
  • src/routes/s/[slug]/+page.svelte
  • tests/unit/convex/public-discovery-cron-contract.test.ts
  • tests/unit/convex/public-discovery-writer-contract.test.ts
  • tests/unit/email/mailto-url-security.test.ts
  • tests/unit/routes/health-endpoint.test.ts
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/routes/live-endpoint.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts
  • tests/unit/security/rate-limiter.test.ts
  • tests/unit/server/public-discovery-cache.test.ts
  • tests/unit/server/public-template-queries.test.ts
  • tests/unit/stores/templates-ssr-hydration.test.ts
  • wrangler.toml
🚧 Files skipped from review as they are similar to previous changes (26)
  • tests/unit/routes/live-endpoint.test.ts
  • src/routes/api/live/+server.ts
  • wrangler.toml
  • docs/development/quickstart.md
  • tests/unit/routes/health-endpoint.test.ts
  • docs/strategy/public-discovery-release-hypergraph/nodes/tasks.json
  • src/routes/+page.server.ts
  • docs/development/production-secrets-checklist.md
  • docs/features/templates.md
  • docs/architecture/public-discovery-cache-invariants.md
  • src/routes/api/health/+server.ts
  • tests/unit/routes/home-page-load.test.ts
  • tests/unit/server/public-template-queries.test.ts
  • tests/unit/routes/templates-api-auth.test.ts
  • tests/unit/convex/public-discovery-writer-contract.test.ts
  • .github/workflows/deploy.yml
  • convex/templates-read-budget.convex.test.ts
  • docs/ops/CONVEX-QUERY-EFFICIENCY-AUDIT.md
  • scripts/check-convex-query-efficiency.mjs
  • src/routes/api/templates/+server.ts
  • convex/lib/publicDiscovery.ts
  • convex/templates-snapshots.convex.test.ts
  • scripts/verify-public-discovery-readiness.mjs
  • tests/unit/server/public-discovery-cache.test.ts
  • convex/templates-embedding-backfill.convex.test.ts
  • tests/unit/scripts/public-discovery-readiness.test.ts

Comment thread src/lib/server/public-template-queries.ts Outdated
@ejmockler

Copy link
Copy Markdown
Member Author

Final hardening is pushed in e73d3a8f.

  • Coordinated clear/reseed now uses a token-owned lock with bounded stale takeover; ordinary writers, cron/recovery, partial clears, wrong owners, and partial publication fail closed while last-good snapshots remain coherent.
  • The health probe pins secret-bearing Convex traffic to the build-pinned hosted origin before reading the secret.
  • KV recovery no longer trusts an uncertified mutable legacy value when revision listing is unavailable.
  • Public template cards have a runtime 50-card ceiling before mapping or cache persistence.

Validation on this head:

  • Focused public-discovery gate: 17 files, 283 tests passed.
  • Full local suite: 352 files, 5,609 tests passed; 12 skipped, 1 todo.
  • Convex TypeScript, query-efficiency guardrail, Svelte checks, production build, workflow lint, and diff checks passed.
  • Required GitHub test, Cloudflare Pages, CodeRabbit, and GitGuardian are green.
  • Authoritative review-thread refresh: 0 unresolved of 138.

Brutalist distinction: run 29621825791 failed before any critic ran because GitHub REST rejects this 25,776-line PR diff above its 20,000-line limit. The released @v1 action fetches that full REST diff before its own truncation/chunking and exposes no diff-file or base/head input, so rerunning or changing max-diff-chars cannot repair it. The final delta received independent security, edge-cache, and concurrency-contract audits, but this failed action is not being represented as a Brutalist review of e73d3a8f.

@github-actions

Copy link
Copy Markdown

Code Coverage

Package Line Rate Branch Rate Health
packages.sdk-typescript.src 74% 64%
src 0% 0%
src.lib 100% 100%
src.lib.components.action 0% 0%
src.lib.components.activation 0% 0%
src.lib.components.auth 0% 0%
src.lib.components.auth.address-steps 0% 0%
src.lib.components.auth.parts 0% 0%
src.lib.components.automation 0% 0%
src.lib.components.billing 0% 0%
src.lib.components.crypto 0% 0%
src.lib.components.debate 0% 0%
src.lib.components.error 0% 0%
src.lib.components.events 0% 0%
src.lib.components.fundraising 0% 0%
src.lib.components.geographic 0% 0%
src.lib.components.identity 0% 0%
src.lib.components.layout 0% 0%
src.lib.components.layout.header 0% 0%
src.lib.components.modals 0% 0%
src.lib.components.networks 0% 0%
src.lib.components.onboarding 0% 0%
src.lib.components.org 2% 5%
src.lib.components.org.os 17% 17%
src.lib.components.org.studio 26% 23%
src.lib.components.profile 0% 0%
src.lib.components.scorecard 0% 0%
src.lib.components.segments 0% 0%
src.lib.components.setup 0% 0%
src.lib.components.sms 0% 0%
src.lib.components.submission 0% 0%
src.lib.components.template 0% 0%
src.lib.components.template-browser 0% 0%
src.lib.components.template-browser.parts 0% 0%
src.lib.components.template-browser.relation 0% 0%
src.lib.components.template-browser.spectrum 0% 0%
src.lib.components.template.creator 0% 0%
src.lib.components.template.parts 0% 0%
src.lib.components.thoughts 0% 0%
src.lib.components.ui 0% 0%
src.lib.components.verify 0% 0%
src.lib.components.visualization 0% 0%
src.lib.components.wallet 0% 0%
src.lib.components.wallet.debate 0% 0%
src.lib.config 53% 53%
src.lib.constants 25% 100%
src.lib.core 3% 5%
src.lib.core.agents 91% 82%
src.lib.core.agents.agents 49% 40%
src.lib.core.agents.prompts 10% 0%
src.lib.core.agents.providers 29% 29%
src.lib.core.agents.types 100% 100%
src.lib.core.agents.utils 63% 55%
src.lib.core.analytics 31% 12%
src.lib.core.api 0% 0%
src.lib.core.auth 42% 40%
src.lib.core.blockchain 26% 25%
src.lib.core.census 100% 100%
src.lib.core.crypto 91% 72%
src.lib.core.email 98% 100%
src.lib.core.encoding 100% 100%
src.lib.core.gas 0% 0%
src.lib.core.identity 62% 60%
src.lib.core.legislative 100% 100%
src.lib.core.locale 0% 0%
src.lib.core.location 55% 56%
src.lib.core.location.resolvers 100% 90%
src.lib.core.near 0% 0%
src.lib.core.org 91% 92%
src.lib.core.privacy 100% 100%
src.lib.core.proof 2% 6%
src.lib.core.search 0% 0%
src.lib.core.security 60% 60%
src.lib.core.server 57% 70%
src.lib.core.server.moderation 20% 25%
src.lib.core.shadow-atlas 66% 60%
src.lib.core.shadow-atlas.shared-vectors 100% 100%
src.lib.core.targets 100% 70%
src.lib.core.thoughts 0% 0%
src.lib.core.tools 2% 0%
src.lib.core.topic 98% 79%
src.lib.core.wallet 6% 7%
src.lib.core.zkp 50% 57%
src.lib.data 98% 87%
src.lib.design 0% 0%
src.lib.server 85% 78%
src.lib.server.agents 0% 0%
src.lib.server.api-v1 68% 75%
src.lib.server.auth 96% 98%
src.lib.server.billing 50% 31%
src.lib.server.billing.providers 100% 88%
src.lib.server.calls 0% 0%
src.lib.server.delegation 100% 100%
src.lib.server.email 84% 65%
src.lib.server.events 90% 67%
src.lib.server.exa 85% 74%
src.lib.server.firecrawl 14% 0%
src.lib.server.geographic 100% 100%
src.lib.server.ground 62% 58%
src.lib.server.identity 98% 89%
src.lib.server.internal 91% 79%
src.lib.server.legislation 0% 0%
src.lib.server.legislation.ingest 100% 100%
src.lib.server.legislation.receipts 0% 0%
src.lib.server.legislation.scorecard 100% 100%
src.lib.server.platform-sync 100% 91%
src.lib.server.reducto 0% 0%
src.lib.server.shims 0% 100%
src.lib.server.sms 55% 39%
src.lib.server.smt 77% 62%
src.lib.server.tee 96% 91%
src.lib.server.workflows 0% 0%
src.lib.services 25% 14%
src.lib.services.ai 100% 86%
src.lib.stores 31% 27%
src.lib.types 19% 18%
src.lib.types.analytics 48% 0%
src.lib.utils 25% 20%
src.routes 2% 1%
src.routes..well-known.jwks.json 0% 0%
src.routes.about.integrity 0% 0%
src.routes.accountability.[id] 0% 0%
src.routes.api.(dev).dev-login 0% 0%
src.routes.api.admin.backfill-embeddings 89% 69%
src.routes.api.admin.reconcile-registrations 0% 0%
src.routes.api.agents.generate-subject 0% 0%
src.routes.api.agents.message-jobs.[jobId] 0% 0%
src.routes.api.agents.stream-decision-makers 0% 0%
src.routes.api.agents.stream-message 77% 71%
src.routes.api.agents.stream-subject 78% 64%
src.routes.api.agents.traces.[traceId] 0% 0%
src.routes.api.analytics.increment 0% 0%
src.routes.api.auth.passkey 100% 83%
src.routes.api.auth.passkey.authenticate 0% 0%
src.routes.api.auth.passkey.current 0% 0%
src.routes.api.auth.passkey.register 0% 0%
src.routes.api.automation.process 0% 0%
src.routes.api.billing.checkout 0% 0%
src.routes.api.billing.checkout-individual 0% 0%
src.routes.api.billing.portal 0% 0%
src.routes.api.blast.[blastId].dispatch-claim 0% 0%
src.routes.api.blast.[blastId].unsubscribe-tokens 0% 0%
src.routes.api.c.[slug].stats 0% 0%
src.routes.api.c.[slug].verify-district 0% 0%
src.routes.api.campaigns.[id].debate 0% 0%
src.routes.api.d.[campaignId].checkout 0% 0%
src.routes.api.d.[campaignId].stats 0% 0%
src.routes.api.debates.[debateId].ai-resolution 0% 0%
src.routes.api.debates.[debateId].appeal 0% 0%
src.routes.api.debates.[debateId].arguments 0% 0%
src.routes.api.debates.[debateId].claim 0% 0%
src.routes.api.debates.[debateId].commit 0% 0%
src.routes.api.debates.[debateId].cosign 0% 0%
src.routes.api.debates.[debateId].governance-resolve 0% 0%
src.routes.api.debates.[debateId].position-proof 0% 0%
src.routes.api.debates.[debateId].resolve 0% 0%
src.routes.api.debates.[debateId].reveal 0% 0%
src.routes.api.debates.[debateId].settle 0% 0%
src.routes.api.debates.[debateId].stream 0% 0%
src.routes.api.debates.by-template.[templateId] 0% 0%
src.routes.api.debates.create 0% 0%
src.routes.api.delegation 0% 0%
src.routes.api.delegation.[id] 0% 0%
src.routes.api.delegation.parse-policy 0% 0%
src.routes.api.delegation.review.[reviewId] 0% 0%
src.routes.api.deliveries.record 100% 100%
src.routes.api.dm.[id].scorecard 0% 0%
src.routes.api.dm.scorecard.compare 0% 0%
src.routes.api.e.[id].checkin 0% 0%
src.routes.api.e.[id].rsvp 0% 0%
src.routes.api.e.[id].stats 0% 0%
src.routes.api.email.confirm.[token] 0% 0%
src.routes.api.emails.report-bounce 0% 0%
src.routes.api.embed.scorecard.[id] 100% 61%
src.routes.api.embeddings.generate 0% 0%
src.routes.api.geographic.infer-scope 92% 100%
src.routes.api.geographic.resolve 0% 0%
src.routes.api.ground.bundle 0% 0%
src.routes.api.ground.restore-state 0% 0%
src.routes.api.ground.state 0% 0%
src.routes.api.ground.wrapper 0% 0%
src.routes.api.health 96% 82%
src.routes.api.identity.delete-blob 0% 100%
src.routes.api.identity.retrieve-blob 0% 100%
src.routes.api.identity.store-blob 0% 100%
src.routes.api.identity.verify-address 69% 56%
src.routes.api.identity.verify-mdl 0% 0%
src.routes.api.identity.verify-mdl.start 76% 69%
src.routes.api.identity.verify-mdl.verify 51% 38%
src.routes.api.internal.alert 0% 0%
src.routes.api.internal.anchor-incidents 0% 0%
src.routes.api.internal.anchor-proof 0% 0%
src.routes.api.internal.billing.report-usage 82% 30%
src.routes.api.internal.dev-login 95% 63%
src.routes.api.internal.emit-revocation 87% 87%
src.routes.api.internal.health.empty-tree-root 88% 82%
src.routes.api.internal.identity.mdl-readiness 92% 73%
src.routes.api.internal.metrics.client-event 88% 79%
src.routes.api.internal.revocation-root 0% 0%
src.routes.api.live 100% 100%
src.routes.api.location.ip-lookup 0% 0%
src.routes.api.location.resolve 0% 0%
src.routes.api.location.resolve-address 96% 75%
src.routes.api.location.search 0% 0%
src.routes.api.moderation.check 92% 92%
src.routes.api.moderation.personalization 0% 0%
src.routes.api.org 0% 0%
src.routes.api.org.[slug] 0% 0%
src.routes.api.org.[slug].alerts 0% 0%
src.routes.api.org.[slug].alerts.[id] 0% 0%
src.routes.api.org.[slug].bills.[billId].watch 0% 0%
src.routes.api.org.[slug].bills.browse 0% 0%
src.routes.api.org.[slug].bills.search 0% 0%
src.routes.api.org.[slug].bills.watching 0% 0%
src.routes.api.org.[slug].branding 0% 0%
src.routes.api.org.[slug].calls 0% 0%
src.routes.api.org.[slug].campaigns 0% 0%
src.routes.api.org.[slug].campaigns.[campaignId].receipts 0% 0%
src.routes.api.org.[slug].campaigns.[campaignId].responses 0% 0%
src.routes.api.org.[slug].campaigns.[campaignId].stream 0% 0%
src.routes.api.org.[slug].campaigns.targeting 0% 0%
src.routes.api.org.[slug].decision-makers.[dmId].activity 0% 0%
src.routes.api.org.[slug].decision-makers.[dmId].follow 0% 0%
src.routes.api.org.[slug].decision-makers.feed 0% 0%
src.routes.api.org.[slug].decision-makers.following 0% 0%
src.routes.api.org.[slug].dm.receipts 0% 0%
src.routes.api.org.[slug].dm.receipts.export.csv 0% 0%
src.routes.api.org.[slug].endorsements 0% 0%
src.routes.api.org.[slug].events 0% 0%
src.routes.api.org.[slug].events.[id] 0% 0%
src.routes.api.org.[slug].fundraising 0% 0%
src.routes.api.org.[slug].fundraising.[id] 0% 0%
src.routes.api.org.[slug].fundraising.[id].donors 0% 0%
src.routes.api.org.[slug].invites 0% 0%
src.routes.api.org.[slug].issue-domains 0% 0%
src.routes.api.org.[slug].issue-domains.rescore 0% 0%
src.routes.api.org.[slug].members 0% 0%
src.routes.api.org.[slug].networks 0% 0%
src.routes.api.org.[slug].networks.[networkId] 0% 0%
src.routes.api.org.[slug].networks.[networkId].accept 0% 0%
src.routes.api.org.[slug].networks.[networkId].decline 0% 0%
src.routes.api.org.[slug].networks.[networkId].invite 0% 0%
src.routes.api.org.[slug].networks.[networkId].leave 0% 0%
src.routes.api.org.[slug].networks.[networkId].members.[orgId] 0% 0%
src.routes.api.org.[slug].networks.[networkId].report 0% 0%
src.routes.api.org.[slug].profile 0% 0%
src.routes.api.org.[slug].representatives 0% 0%
src.routes.api.org.[slug].representatives.resolve 0% 0%
src.routes.api.org.[slug].scorecards 0% 0%
src.routes.api.org.[slug].scorecards.export 85% 84%
src.routes.api.org.[slug].segments 0% 0%
src.routes.api.org.[slug].ses-token 0% 0%
src.routes.api.org.[slug].settings.alert-preferences 0% 0%
src.routes.api.org.[slug].sms 0% 0%
src.routes.api.org.[slug].sms.[id] 0% 0%
src.routes.api.org.[slug].sms.[id].messages 0% 0%
src.routes.api.org.[slug].sms.audience-count 0% 0%
src.routes.api.org.[slug].workflows 89% 88%
src.routes.api.org.[slug].workflows.[id] 100% 90%
src.routes.api.org.[slug].workflows.[id].executions 100% 50%
src.routes.api.org.check-slug 0% 0%
src.routes.api.positions.batch-register 0% 0%
src.routes.api.positions.confirm-send 0% 0%
src.routes.api.positions.count.[templateId] 0% 0%
src.routes.api.positions.engagement-by-district.[templateId] 0% 0%
src.routes.api.positions.register 0% 0%
src.routes.api.proofs.revocation-witness 0% 0%
src.routes.api.shadow-atlas.engagement 0% 0%
src.routes.api.shadow-atlas.register 0% 0%
src.routes.api.submissions.[id].retry 0% 0%
src.routes.api.submissions.[id].status 0% 0%
src.routes.api.submissions.create 62% 54%
src.routes.api.tee.public-key 0% 0%
src.routes.api.tee.resolve 92% 89%
src.routes.api.templates 71% 67%
src.routes.api.templates.check-slug 0% 0%
src.routes.api.templates.search 0% 0%
src.routes.api.user.profile 0% 0%
src.routes.api.user.templates 0% 0%
src.routes.api.v1 100% 100%
src.routes.api.v1.activity 0% 0%
src.routes.api.v1.calls 0% 0%
src.routes.api.v1.campaigns 18% 9%
src.routes.api.v1.campaigns.[id] 0% 0%
src.routes.api.v1.campaigns.[id].actions 0% 0%
src.routes.api.v1.docs 67% 50%
src.routes.api.v1.donations 0% 0%
src.routes.api.v1.donations.[id] 0% 0%
src.routes.api.v1.events 0% 0%
src.routes.api.v1.events.[id] 0% 0%
src.routes.api.v1.keys 0% 0%
src.routes.api.v1.keys.[id] 0% 0%
src.routes.api.v1.networks 0% 0%
src.routes.api.v1.networks.[id] 0% 0%
src.routes.api.v1.networks.[id].stats 0% 0%
src.routes.api.v1.orgs 0% 0%
src.routes.api.v1.representatives 0% 0%
src.routes.api.v1.resolve-address 100% 89%
src.routes.api.v1.sms 0% 0%
src.routes.api.v1.stream 0% 0%
src.routes.api.v1.supporters 30% 18%
src.routes.api.v1.supporters.[id] 0% 0%
src.routes.api.v1.tags 0% 0%
src.routes.api.v1.tags.[id] 0% 0%
src.routes.api.v1.usage 0% 0%
src.routes.api.v1.webhooks 0% 0%
src.routes.api.v1.webhooks.[id] 0% 0%
src.routes.api.v1.webhooks.[id].rotate-secret 0% 0%
src.routes.api.v1.webhooks.[id].test-fire 0% 0%
src.routes.api.v1.workflows 100% 88%
src.routes.api.v1.workflows.[id] 100% 58%
src.routes.api.waitlist 0% 0%
src.routes.api.wallet 0% 0%
src.routes.api.wallet.balance 0% 0%
src.routes.api.wallet.connect 0% 0%
src.routes.api.wallet.disconnect 0% 0%
src.routes.api.wallet.near.sponsor 0% 0%
src.routes.api.wallet.nonce 0% 0%
src.routes.api.wallet.sponsor-userop 99% 77%
src.routes.api.wallet.status 0% 0%
src.routes.auth.coinbase 0% 0%
src.routes.auth.coinbase.callback 0% 0%
src.routes.auth.discord 0% 100%
src.routes.auth.discord.callback 0% 100%
src.routes.auth.facebook 0% 0%
src.routes.auth.facebook.callback 0% 100%
src.routes.auth.google 0% 0%
src.routes.auth.google.callback 0% 100%
src.routes.auth.linkedin 0% 0%
src.routes.auth.linkedin.callback 0% 100%
src.routes.auth.logout 0% 0%
src.routes.auth.prepare 0% 0%
src.routes.auth.twitter 0% 100%
src.routes.auth.twitter.callback 0% 100%
src.routes.browse 0% 0%
src.routes.c.[slug] 0% 0%
src.routes.d.[campaignId] 0% 0%
src.routes.deliberation 0% 0%
src.routes.developers 0% 0%
src.routes.directory 0% 0%
src.routes.dm.[id] 0% 0%
src.routes.dm.[id].scorecard 0% 0%
src.routes.e.[id] 0% 0%
src.routes.embed 0% 100%
src.routes.embed.campaign.[slug] 0% 0%
src.routes.governance 0% 0%
src.routes.help.verification 0% 0%
src.routes.migrate 0% 0%
src.routes.n.[slug] 0% 0%
src.routes.og.campaign.[id] 0% 0%
src.routes.og.integrity 0% 100%
src.routes.og.org 0% 100%
src.routes.og.org-for.[segment] 0% 0%
src.routes.org 0% 0%
src.routes.org.[slug] 0% 0%
src.routes.org.[slug].calls 0% 0%
src.routes.org.[slug].campaigns 0% 0%
src.routes.org.[slug].campaigns.[id] 0% 0%
src.routes.org.[slug].campaigns.[id].report 0% 0%
src.routes.org.[slug].campaigns.[id].report.email-html 0% 0%
src.routes.org.[slug].campaigns.new 0% 0%
src.routes.org.[slug].emails 0% 0%
src.routes.org.[slug].emails.[blastId] 0% 0%
src.routes.org.[slug].emails.[blastId].receipts 0% 0%
src.routes.org.[slug].emails.compose 0% 0%
src.routes.org.[slug].events 0% 0%
src.routes.org.[slug].events.[id] 0% 0%
src.routes.org.[slug].events.[id].attendees.csv 0% 0%
src.routes.org.[slug].events.[id].calendar.ics 0% 0%
src.routes.org.[slug].events.new 0% 0%
src.routes.org.[slug].fundraising 0% 0%
src.routes.org.[slug].fundraising.[id] 0% 0%
src.routes.org.[slug].fundraising.new 0% 0%
src.routes.org.[slug].legislation 0% 0%
src.routes.org.[slug].networks 0% 0%
src.routes.org.[slug].networks.[networkId] 0% 0%
src.routes.org.[slug].networks.new 0% 0%
src.routes.org.[slug].representatives 0% 0%
src.routes.org.[slug].representatives.[repId] 0% 0%
src.routes.org.[slug].results 0% 100%
src.routes.org.[slug].scorecards 0% 0%
src.routes.org.[slug].settings 0% 0%
src.routes.org.[slug].settings.webhooks 0% 0%
src.routes.org.[slug].sms 0% 0%
src.routes.org.[slug].sms.[id] 0% 0%
src.routes.org.[slug].sms.new 0% 0%
src.routes.org.[slug].studio 0% 0%
src.routes.org.[slug].supporters 0% 0%
src.routes.org.[slug].supporters.[id] 0% 0%
src.routes.org.[slug].supporters.import 0% 0%
src.routes.org.[slug].supporters.import.action-network 0% 100%
src.routes.org.[slug].supporters.import.platform-api 0% 0%
src.routes.org.[slug].workflows 0% 0%
src.routes.org.[slug].workflows.[id] 0% 0%
src.routes.org.[slug].workflows.new 0% 0%
src.routes.org.for 0% 100%
src.routes.org.for.agency-rulemaking 0% 0%
src.routes.org.for.local-government 0% 0%
src.routes.org.for.state-legislature 0% 0%
src.routes.org.invite.[token] 0% 0%
src.routes.org.new 0% 0%
src.routes.profile 5% 8%
src.routes.profile.receipts 0% 0%
src.routes.profile.security 5% 6%
src.routes.record 100% 100%
src.routes.record.vol-1.issue-1 0% 0%
src.routes.s.[slug] 2% 1%
src.routes.s.[slug].debate.[debateId] 0% 0%
src.routes.s.[slug].og-image 0% 0%
src.routes.settings.delegation 0% 0%
src.routes.spec 0% 0%
src.routes.template-modal.[slug] 19% 21%
src.routes.unsubscribe 0% 0%
src.routes.unsubscribe.[supporterId].[orgId].[token] 0% 0%
src.routes.v.[hash] 0% 0%
src.routes.verify.[hash] 0% 0%
src.routes.verify.receipt.[id] 0% 0%
Summary 20% (10257 / 50677) 18% (7298 / 39783)

@ejmockler
ejmockler merged commit 4bff0a0 into main Jul 21, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant