diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index cef9903d..39a5f75f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,130 +1,6 @@ Status: Active -Last updated: 2026-01-03 +Last updated: 2026-09-22 -# Cherry • AI Agent Playbook +# Cherry • AI Agent Instructions -Read this alongside `AGENTS.md`, `docs/legal-constraints.md`, `docs/cherry-vision.md`, `docs/cherry-vine.md`, `docs/wallet-pass.md`, and `docs/api.md`. Never frame Cherry as a payment card/terminal; `/api/scan` is advisory with telemetry; `/api/wallet/cherry-pass` returns 501 until certs and the feature flag exist. - -## GitHub / PR Operating Rule -From now on, the agent must not treat direct commits to `main` as the normal workflow. - -The default development flow is: - -1. Start from updated `main`. -2. Create a focused branch. -3. Implement the requested change on that branch. -4. Run the relevant verification commands. -5. Commit the change with a clear conventional commit message. -6. Push the branch. -7. Open or prepare a pull request into `main`. -8. Do not merge unless explicitly instructed. - -Canonical command flow: - -```bash -git checkout main -git pull --ff-only -git checkout -b / - -# implement changes - -git status --short -npm run check -npm test -npm run build - -git add . -git commit -m ": " -git push -u origin / -``` - -The pull request must include: - -```md -## Summary -- what changed - -## Testing -- commands run -- results - -## Risk -- changed domains -- possible regressions -``` - -Hard rules: - -- Never commit directly to `main` unless the user explicitly says to. -- Never merge a PR unless the user explicitly says to. -- Never skip verification silently. -- If verification fails, stop and report the failure. -- If the working tree is dirty before starting, inspect it first and do not overwrite unrelated user changes. -- If a branch already exists, reuse it only if it matches the requested task; otherwise create a new branch. -- Each PR should represent one coherent change. Do not bundle unrelated fixes. -- Prefer `squash and merge` when the user later asks to merge. - -This is now the default operating model for all future repo work. - -## Current behavior (enforced / in code) -- Engine decisions run through `safeSolveDecisionForUser` / `safeSolveDecisionForWorld` with deterministic inputs and explicit `nowMs`. -- `/api/scan` logs `DecisionEvent` telemetry but does not create sessions or ledger entries. -- Zod schemas live in `lib/schemas/*` and are parsed via `parseJsonBody` from `lib/validation.ts`. -- Prisma is instantiated only in `lib/prisma.ts` and consumed via runtime adapters. - -## Runtime & Layout -- Next.js 16 App Router + React 19 (React Compiler). Default to server components; place interactive hooks in `app//client.tsx` gated with `'use client'`. -- Tailwind v4 tokens live in `app/globals.css`. Prefer semantic CSS vars and canonical utilities. -- `app/layout.tsx` is the shell: Geist fonts, `AuthProvider`, `SidebarNav`, `UserMenu`. - -## Auth & Session Flow -- NextAuth config: `app/api/auth/[...nextauth]/route.ts` (PrismaAdapter + Email/Google + dev credentials). Session callback stamps `session.user.id`. -- Server handlers must import `withUser` from `lib/with-user.ts` to enforce auth and surface `userId`. Never read cookies directly. -- Client code uses `useSession()` and reacts to `401` by calling `signIn()`. - -## Data & Money Rules (see `docs/legal-constraints.md`) -- Prisma models: `prisma/schema.prisma` (Bucket/Card/RewardRule/RecommendationSession/CherryPointLedger/etc.). Run `npx prisma migrate dev --name ` then `npx prisma generate` after schema edits. -- Monetary values are integer cents. Convert from dollars before hitting APIs; render via `formatCents` helpers. -- Buckets: `spentCents` is incremented once on session confirm after `ensureBucketFresh`; `currentAmount` is legacy and unused post-create. -- Bucket balances must be derived via canonical runtime helpers; do not recompute remaining amounts ad-hoc. -- `currentAmount` is legacy-only and must not be treated as authoritative input. -- Bucket mutation must occur only after freshness is ensured. -- Always import Prisma from `@/lib/prisma`; never create ad-hoc clients. - -## Simulation Engine & APIs -- Engine: `lib/engine.ts` is canonical (MCC-aware); invariants in `lib/engine-invariants.ts`. Do not fork logic in routes. -- All decision-making surfaces must route through `safeSolveDecisionForUser` / `safeSolveDecisionForWorld`; no route may implement decision logic inline. -- Validation: All engine-touching APIs (`/api/simulate`, `/api/scan`, `/api/sessions`, `/api/vine/order`) must use Zod schemas in `lib/schemas/*` plus `parseJsonBody`. -- Core APIs: - - `/api/simulate` — one-off simulation: returns verdict + card/bucket suggestion, records a `SimulatedTransaction`, does **not** mutate buckets. - - `/api/scan` — advisory “scan before pay”: runs the engine, MCC-aware, allows zero-amount snapshots; logs `DecisionEvent` telemetry but does not create sessions/ledger rows. - - `/api/sessions` — creates a `RecommendationSession` (source `APP_SCAN`) with orderToken/expiry and offered points. - - `/api/sessions/[id]/confirm` — blocks expired/duplicate claims, freshens bucket, increments `spentCents` once, writes PENDING ledger rows, flags anomalies (amount/time/card). - - `/api/sessions/[id]/verify` — simulated verification: flips ledger rows to POSTED/REVOKED, updates anomalies. - - `/api/vine/order` — Vine ingest (dev-only): accepts terminal events or `OrderContext`, enforces freshness window, runs engine, creates session with orderToken, returns decision. - - `/api/wallet/cherry-pass` — gated by `CHERRY_WALLET_PASS_ENABLED` + Apple env; returns 501 JSON when disabled; generates `storeCard` pass when fully configured. - -## Seed, MCC ingest, and Admin flows -- MCC ingest: `npm run ingest:mcc [path]` → `scripts/ingest-mcc.mts`. -- Demo seeding: `npm run seed:demo` → `scripts/seed-demo.mts` (also via `/api/seed-demo`). -- Admin tools (local-only): `/admin` links to `/api/admin/health`, `/api/health`, and dev-only seed/diagnostic surfaces. -- Integrity: `scripts/audit-integrity.mts` flags session/ledger anomalies. - -## UI Conventions -- Server components fetching data should use `{ cache: 'no-store' }` and await async `params`. -- Client forms: uppercase categories, confirm destructive actions, convert dollars to cents, call `router.refresh()`. -- Vine simulator: clearly mark “simulated Vine device” vs “manual scan”; hide confirm flows when verdict is `INSUFFICIENT_DATA`. - -## Product & Hardware Context -- `docs/cherry-vision.md` + `docs/legal-constraints.md`: Cherry is a spending copilot, not a card/terminal. -- `docs/cherry-vine.md`: Vine is a context beacon (merchant + amount), never a payment device. -- Recommendation sessions + verification glue Cherry Pass, Vine, and any future bank/receipt integrations—reuse them rather than inventing new reward trackers. -RecommendationSession + CherryPointLedger form the single spine for all reward and verification flows; do not introduce parallel tracking systems. - -## Future/Target behavior (explicitly speculative) -- Add new API surfaces only after updating `docs/api.md` and relevant guardrails. - -## Related docs -- `AGENTS.md` -- `docs/api.md` -- `docs/ci-and-guardrails.md` +Read `AGENTS.md` at the repo root. It is the single operating contract (legal framing, invariants, verification, branch/PR flow). Architecture navigation starts at `docs/architecture/index.md`. This file intentionally adds nothing. diff --git a/.gitignore b/.gitignore index f91f76bf..0035da53 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ workspace/ # misc .DS_Store -*.pem cookies.txt # editor settings @@ -56,6 +55,9 @@ certs/ *.pem *.pkpass +.evidence/* +!.evidence/.gitkeep + # Local temp + Node compile cache .tmp/ .cherry-tmp/ @@ -68,6 +70,5 @@ paste.txt abandoned_subsystems.md api_inventory.md architecture_map.md -scripts/audit/full-checkout-audit.mts workspace_audit.md repo_index.json diff --git a/AGENTS.md b/AGENTS.md index d39e113d..aaddebc8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,190 +1,113 @@ Status: Active -Last updated: 2026-01-29 +Last updated: 2026-09-22 -# Cherry Agents — Canonical Operating Guide +# Cherry Agents — Operating Contract -This file is the operating contract for humans and agents working in this repo. It is authoritative after CI/workflows and guardrail registries. If something conflicts, fix the lower authority, not the higher. +The single operating contract for humans and agents working in this repo. It is navigational: it tells you what must never change, where things live, how to verify, and how to hand off. Detail lives in the linked docs, never duplicated here. This guide defers to docs/doctrine.md for all execution invariants and enforcement rules. -## Authority Ladder (highest to lowest) +## Authority ladder (highest to lowest) 1. `package.json` scripts + `.github/workflows/*` (actual behavior) -2. Guardrail registries and tests (`scripts/guardrails/*`, `tests/guardrails/*`) -3. `AGENTS.md` (this file) -4. `docs/*` (specs and explanations) -5. Everything else (notes, drafts, marketing) - -## Product Identity and Legal Guardrails (non-negotiable) -- Cherry is a real-time spending copilot, not a card, proxy, processor, or payment terminal. -- Cherry never fronts transactions, holds funds, or touches payment rails. -- Cherry Vine is a context beacon (merchant + amount + timestamp), not a reader or terminal. -- Cherry Pass is a storeCard-style advisory pass; it is not a payment instrument. -- Recommendation sessions and Cherry Points are advisory and sandboxed. - -Forbidden framings: “fronting card,” “proxy BIN,” “tap to pay with Cherry,” “Cherry terminal,” “payment card.” - -## Current behavior (enforced / in code) -- Core loop: Observe → Evaluate → Recommend → Reward. -- `/api/scan` runs the engine and logs a `DecisionEvent` for telemetry; it does not create sessions or ledger rows. -- Sessions + ledger persistence happen via `/api/sessions` and confirm/verify flows. -- Vine ingest (`/api/vine/order`) is dev-only and context-only; no payment rails. -- Wallet pass (`/api/wallet/cherry-pass`) returns 501 unless fully configured and explicitly enabled. -- Engine is deterministic and pure: it consumes `EngineState` + `EngineContext` and emits ranked decisions. - -## Determinism and Time Injection -- Do not call `Date.now()` or `new Date()` in `lib/engine/*` or `lib/authority/*`. -- Time enters at boundaries (API routes, adapters) and is passed in as `nowMs`. -- Guardrails enforce deterministic core behavior. - -## SSR / Rendering Determinism -- Server components must not call `Date.now()`, `Math.random()`, or locale-dependent formatting. -- Pages must render from a single data snapshot; no structural changes on hydration. -- Empty/data states must share a stable outer container. - -## Data and DB Boundaries -- Prisma client must only be instantiated in `lib/prisma.ts` and consumed by runtime adapters. -- Engine and authority logic must not import Prisma or `@prisma/client`. -- Zod schemas live in `lib/schemas/*`; parse via `parseJsonBody` from `lib/validation.ts`. -- Stateful API routes must use `withUser` and return `401` for unauthenticated requests. -- Bank ingest invariants: - - `BankTransaction.id` is internal and never set from ingest data. - - Idempotency key is `(userId, externalId)` only. - - All ingest writes go through `upsertBankTransactions`. - -## Bucket Runtime Invariants -- Bucket math must flow through `lib/buckets-runtime.ts`. -- Authoritative fields: `budgetAmount`, `spentCents`. -- Derived only: `committedCents`, `remainingCents`. -- `currentAmount` is legacy-mirror only; never authoritative. - -## Offline Evaluator (hard boundary) -- Evaluator code is read-only with respect to Sessions, Ledger, Buckets. -- Outputs are diagnostic only and must never affect user-facing decisions. -- Must call `assertOfflineEvaluatorModelsReady()` before DB access. -- Gate execution behind `CHERRY_OFFLINE_EVALUATOR_ENABLED`. -- Never hard-code runIds; derive via `defaultRunIdForUser(userId, now)`. - -## Guardrails Policy -- Guardrails are registered in `scripts/guardrails/registry.mts` and must run via `npm run check`. -- Guardrails are unaddressable by path; run them only via `npm run check`. -- Guardrails must be deterministic and side-effect free; no network or DB I/O. -- Do not weaken guardrail severity or bypass guardrail tests. - -## DB Truth Surface (hard boundary) -- DB truth scripts and DB tests may assert only: existence, impossibility, conservation. -- Allowed: constraint exists, duplicate key fails, FK missing parent fails, NOT NULL fails, count stays 1. -- Forbidden: preferred outcomes, query plans, performance targets, business logic behaviors, ordering. -- Rule of thumb: if the DB could allow multiple valid outcomes, do not assert a preference in DB truth. - -## Script Runner Contract -- Repo is ESM by extension. `.mts` is allowed only under `scripts/`. -- `.mts` scripts must be run via `npm run ts:esm --