Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ craftstack/
- **OpenAPI 3.1 contract** at [`apps/collab/src/openapi.ts`](apps/collab/src/openapi.ts). Browsable in-app at <https://craftstack-collab.vercel.app/docs/api> (server-rendered, inside the strict CSP, zero external CDN), served as raw JSON at <https://craftstack-collab.vercel.app/api/openapi.json>. Hand-written so the spec **is** the contract ([ADR-0035](docs/adr/0035-hand-written-openapi-as-the-contract.md)). `pnpm --filter collab generate:api-types` emits a fully-typed `paths` interface into [`src/openapi-types.ts`](apps/collab/src/openapi-types.ts) via `openapi-typescript`
- **Release hygiene** — human-readable [CHANGELOG.md](CHANGELOG.md) per Keep-a-Changelog, signed tags, GitHub Releases, and a **CycloneDX 1.5 SBOM** auto-generated and attached to every `v*` release (see [`.github/workflows/sbom.yml`](.github/workflows/sbom.yml)) for supply-chain inspection
- **Undo / redo on card moves** — `Ctrl-Z` / `⌘-Z` reverses the last drag, `Ctrl-Shift-Z` / `⌘-Shift-Z` re-applies it. Bounded 25-entry LIFO stack, replays against the existing optimistic-lock-protected `/api/cards/:id/move` endpoint so concurrent-edit rejection behaves exactly like a fresh drag. Pure state-machine module (6 Vitest cases) in [ADR-0036](docs/adr/0036-move-undo-redo-client-only.md)
- **Cost safety by construction** — every service the project touches (Vercel, Neon, Gemini via AI Studio, Pusher, Resend, GitHub Actions, Upstash, Sentry) is on a free tier that **caps out to zero cost** rather than auto-scaling to the attacker's credit card. In-code defense-in-depth: per-IP + global daily/monthly budget on `/api/kb/ask` **and** `/api/kb/ingest` (Knowlex parity, see [ADR-0043](docs/adr/0043-knowlex-ops-cost-ci-eval.md)), per-user rate limits on authenticated reads, three-layer cap on invitation emails. The guarantee is enforced, not declared: [`scripts/check-free-tier-compliance.mjs`](scripts/check-free-tier-compliance.mjs) runs as a **PR-blocking `free-tier-compliance` gate** in [`ci.yml`](.github/workflows/ci.yml) that fails merges introducing paid-plan `vercel.json`, billable SDKs, or leaked secret patterns. A single-flag kill switch `EMERGENCY_STOP=1` short-circuits every write + AI endpoint on the next request (runbook §9); its counterpart observability endpoint [`/api/kb/budget`](https://craftstack-knowledge.vercel.app/api/kb/budget) mirrors `/api/kb/stats` to expose the current used/cap state. STRIDE threat model covers this attack shape explicitly as `C-01..C-06`. Decision record: [ADR-0046](docs/adr/0046-zero-cost-by-construction.md). Credit-card-free signup walk-through in [`docs/FREE_TIER_ONBOARDING.md`](docs/FREE_TIER_ONBOARDING.md); cost-attack threat model in [`COST_SAFETY.md`](COST_SAFETY.md)
- **Cost safety by construction** — every service the project touches (Vercel, Neon, Gemini via AI Studio, Pusher, Resend, GitHub Actions, Upstash, Sentry) is on a free tier that **caps out to zero cost** rather than auto-scaling to the attacker's credit card. In-code defense-in-depth: per-IP + global daily/monthly budget on `/api/kb/ask` **and** `/api/kb/ingest` (Knowlex parity, see [ADR-0043](docs/adr/0043-knowlex-ops-cost-ci-eval.md)), per-user rate limits on authenticated reads, three-layer cap on invitation emails. The guarantee is enforced, not declared: [`scripts/check-free-tier-compliance.mjs`](scripts/check-free-tier-compliance.mjs) runs as a **PR-blocking `free-tier-compliance` gate** in [`ci.yml`](.github/workflows/ci.yml) that fails merges introducing paid-plan `vercel.json`, billable SDKs, or leaked secret patterns. A single-flag kill switch `EMERGENCY_STOP=1` short-circuits every write + AI endpoint on the next request (runbook §9); its counterpart observability endpoint [`/api/kb/budget`](https://craftstack-knowledge.vercel.app/api/kb/budget) mirrors `/api/kb/stats` to expose the current used/cap state (disabled-by-default in production per ADR-0046 § Trade-offs; returns a structured 404 `{"code":"DISABLED"}` until `ENABLE_OBSERVABILITY_API=1` is set on the server). STRIDE threat model covers this attack shape explicitly as `C-01..C-06`. Decision record: [ADR-0046](docs/adr/0046-zero-cost-by-construction.md). Credit-card-free signup walk-through in [`docs/FREE_TIER_ONBOARDING.md`](docs/FREE_TIER_ONBOARDING.md); cost-attack threat model in [`COST_SAFETY.md`](COST_SAFETY.md)
- **Error-capture pipeline with demo mode** — both apps boot `@sentry/nextjs` via Next's `instrumentation.ts` + `instrumentation-client.ts` hooks; server and browser errors, unhandled rejections, and every `error.tsx` boundary flow through a unified `lib/observability.ts` seam. When `SENTRY_DSN` is configured the captures ship upstream; when it's not, they land in an in-memory ring buffer surfaced at `/api/observability/captures`, so a reviewer can prove the pipeline works end-to-end **without signing up for Sentry**. Rationale in [ADR-0044](docs/adr/0044-knowlex-openapi-a11y-sentry-v0.4.0.md) (wiring) and [ADR-0045](docs/adr/0045-observability-demo-mode.md) (demo-mode dual-backend)
- **Knowlex RAG regression stack** — `retrieve.integration.test.ts` exercises the real pgvector kNN path against a `pgvector/pgvector:pg16` service container in CI, asserting "returns every row when `k ≥ corpus size`" — the exact regression a misconfigured ivfflat(lists, probes) silently produces ([ADR-0041](docs/adr/0041-knowlex-ivfflat-to-hnsw.md) documents the production diagnosis). `scripts/bench-retrieve.ts` reports min / p50 / p95 / p99 / max latency over N=1000 / M=100 probes. `scripts/eval.ts` seeds a self-contained **10-doc / 30-question golden set v4** (21 OR-mode + 6 AND-mode + 3 adversarial) and scores substring-faithfulness + citation-coverage + refusal correctness against the live deploy — full measurement methodology in [ADR-0042](docs/adr/0042-knowlex-test-observability-stack.md) / [ADR-0043](docs/adr/0043-knowlex-ops-cost-ci-eval.md) / [ADR-0049 § 7th arc](docs/adr/0049-rag-eval-client-retry-contract.md) (substring-OR scoring + 12 expanded refusal markers) and [`docs/eval/README.md`](docs/eval/README.md)
- **Live deploy smoke, scheduled** — [`.github/workflows/smoke.yml`](.github/workflows/smoke.yml) runs Playwright against both production URLs every 6 h (plus on `workflow_dispatch` and on main pushes after a 90-second Vercel-settle sleep). Knowlex smoke asserts `indexType === "hnsw"` so an accidental ivfflat rollback trips the workflow, not production users
Expand Down
Loading