Rocoto backend — the module map
Generated by tools/backend-map.py on 2026-09-09 · 205 modules · 88,985 lines · 25 kernel · 94 app · 86 untagged.
The tag in the layer column is the layering law of tests/vital_kernel_boundary.py: the KERNEL is the generic
employee nervous system (versioned in KERNEL-VERSION, surface in KERNEL-API.md), the APP is
Rocoto's commerce world built on it. A kernel module importing an app module is the breach the
vital fails on. The sets hold import names, so every module under brain/ reads the tag of
brain. untagged means the law names the module nowhere yet — that is the work the map
makes visible, and each one belongs on one side.
Regenerate with python3 tools/backend-map.py. CI runs --check; an edit here alone goes back.
backend/ — the modules at the top level
117 modules · 53,976 lines · 25 kernel · 18 app · 74 untagged
| module | layer | lines | what it is |
|---|---|---|---|
actions.py |
untagged | 494 | actions.py — Rocoto's outward AGENCY beyond replying (SPEC §5/§7). Each fail-soft + evented. |
agent_chat.py |
app | 150 | Customize-your-agent chat — every AI employee's setup assistant (Opus 4.8). |
agent_reply.py |
app | 1,102 | agent_reply.py — Rocoto himself on WhatsApp: the agentic runtime, with hands + memory + awareness. |
ai_disclosure.py |
untagged | 328 | ai_disclosure.py — telling a caller they are talking to a machine, because the law now requires it. |
api_v1.py |
untagged | 403 | THE PUBLIC READ API — /v1/*, the surface soyrocoto.com/docs describes. |
app.py |
app | 7,317 | Rocoto backend — FastAPI. |
assemble.py |
kernel | 537 | assemble.py — the bounded turn (SPEC §4.1/§4.1.1/§4.5 ③; BUILD-PLAN 3.1). DETERMINISTIC, no LLM. |
auth_headers.py |
untagged | 7 | Shared parsing of the existing bearer header contract. |
avisos.py |
untagged | 608 | avisos.py — EL AVISO: the message that arrives at the right place, and the conversation it |
backfill.py |
untagged | 358 | backfill.py — REPLAYING A CUSTOMER'S PAST THROUGH THE MIND THAT WOULD HAVE LIVED IT. |
behaviour.py |
kernel | 271 | behaviour.py — the per-tenant behaviour settings (KERNEL: config + db only) (§17.46, §17.35, §17.51's S vocabular… |
business_day.py |
untagged | 75 | business_day.py — the working day of a market that starts before dawn. |
cal_webhook.py |
untagged | 51 | Authenticate Cal webhook bytes before parsing or applying booking effects. |
cascade.py |
kernel | 81 | cascade.py — the tab cognitive cascade (SPEC §5.0.1): T0 match → T1 classify → execute_branch. |
channels.py |
untagged | 400 | channels.py — HOW A TENANT IS REACHABLE, and which number we answer from. |
claim.py |
untagged | 494 | claim.py — THE CLAIM RAIL (THE-JOURNEY-CANON §2.1 · step 1 of the mono-account journey). |
confidence.py |
kernel | 60 | confidence.py — TRANSCRIPTION CONFIDENCE GATING (Peter 2026-07-22). |
config.py |
kernel | 813 | Rocoto backend config — all read from the environment (see deploy/.env). |
consent.py |
untagged | 328 | consent.py — CONSENT AS EVIDENCE, NOT AS A BOOLEAN (SPEC §17.56c; GDPR Art. 4(11) + Recital 32). |
control_room.py |
app | 472 | control_room.py — Rocoto's Control Room (SPEC §15): Peter's real CRM cockpit, desktop-first. |
cr_auth.py |
untagged | 138 | Control Room HTTP authentication; existing cookies, roles and CSRF policy. |
cr_control.py |
app | 334 | cr_control.py — Control Room CONTROL surfaces (WP-9 cr-control): account · refunds · GDPR data. |
cr_session.py |
app | 222 | cr_session.py — Control Room real auth + server-side sessions (WP-9 cr-auth). |
cr_web_policy.py |
untagged | 16 | Browser policy shared by the existing Control Room and playbook shells. |
credit.py |
untagged | 81 | §5.11.7 / §17.32 — CREDIT: money on the desk, derived ONLY from the ledger. |
crm_api.py |
untagged | 344 | Maintained CRM HTTP routes and Control Room shell. |
db.py |
kernel | 1,040 | Postgres data layer (asyncpg) — local DB on the prod box. |
delivery.py |
untagged | 424 | delivery.py — EL REPARTO: the stop state machine and the money ledger (SPEC §5.11). |
demo_api.py |
untagged | 1,143 | Maintained product demo/account sandbox HTTP routes. |
demo_auth.py |
untagged | 939 | demo_auth.py — /demo SIGNS IN FOR REAL, AND THE ACCOUNT IS A REAL TENANT (SPEC §17.56c). |
demo_call.py |
app | 612 | Landing "See it live" demo call — places a REAL Twilio call to a website visitor, streams the |
demo_flow.py |
untagged | 2,111 | demo_flow.py — /demo: «Prueba Rocoto con tus productos» (SPEC §17.56). |
demo_media.py |
untagged | 642 | demo_media.py — /demo HEARS AND SEES: voice notes in, photos in (SPEC §17.56, build order ⑤). |
demo_phone.py |
untagged | 478 | demo_phone.py — «Escanea para seguir en tu móvil» (SPEC §17.56 phone handoff, §17.20 extended). |
demo_reap.py |
untagged | 72 | demo_reap.py — the /demo retention sweep, as a runnable unit (python -m demo_reap). |
directory.py |
kernel | 626 | directory.py — THE SUPPLIER-CARD PRODUCT DIRECTORY (PRODUCT-SPEC §5.10.1; §6/WP-4). Organ ③. |
dispatch_sched.py |
untagged | 184 | §17.4c / §17.36 — DISPATCH SCHEDULES: many scheduled sends, per tenant, honestly bounded. |
doubt.py |
untagged | 323 | doubt.py — THE DOUBT FACULTY (Peter, 2026-07-26; SPEC §5.7a). |
duties.py |
kernel | 548 | duties.py — the ONE generic duty-binder (L0 kernel; SPEC §16.6 LAW: situations are DATA). |
el_convai.py |
app | 151 | ElevenLabs ConvAI — the VOICE side of "customize your agent". |
eleven.py |
app | 356 | Twilio Media Stream ↔ ElevenLabs Conversational AI bridge (the ON path). |
fcm.py |
untagged | 99 | Firebase Cloud Messaging (HTTP v1) — push notifications to the Android app. |
gate.py |
kernel | 298 | gate.py — the deterministic outbound gate (SPEC §5 canonical rule list; BUILD-PLAN 4.1). |
historial.py |
untagged | 227 | §17.21 — EL HISTORIAL: uploading a customer's past, landing as PROPOSALS, never writes. |
http_serialization.py |
untagged | 13 | JSON-safe values shared by product HTTP adapters. |
identity_phone.py |
untagged | 38 | Canonical phone identity — the dedupe key across WhatsApp / voice / storefront / Medusa. |
install.py |
kernel | 115 | install.py — WP-10 SENTIENT SELF-CONFIGURATION (SPEC §16.3): the employee configures ITSELF by |
intake_api.py |
untagged | 503 | intake_api.py — INGESTION EVERYWHERE (SPEC §5.10.5). |
join.py |
untagged | 828 | join.py — the /join application: a fixed ladder, voice notes, and Peter's desk. |
learn.py |
kernel | 64 | learn.py — LEARN FROM CONFIRMATION (Peter 2026-07-22). A spoken order the runtime couldn't fully |
lifecycle.py |
kernel | 518 | lifecycle.py — THE HARD LIFECYCLE SWITCH (Peter, 2026-07-22, after the live-demo FREEZE). |
logging_setup.py |
untagged | 113 | Structured logs, redacted at the door — the kit runtime's mock-api/app/logging_setup.py, |
mail_inbound.py |
untagged | 175 | §17.47b — HOW INBOUND MAIL ACTUALLY WORKS: there is no inbox (WP-G3's rail). |
market_voice.py |
untagged | 135 | market_voice.py — what Rocoto is ALLOWED to say to a customer, enforced after the model. |
mcp_auth.py |
untagged | 283 | §17.48c — THE MCP AUTHORISATION SERVER. OAuth 2.1, exactly the slice the contract needs. |
mcp_server.py |
untagged | 305 | §17.48c — THE MCP ENDPOINT: Streamable HTTP, tools = the §17.48b registry ∩ the token's caps. |
memory.py |
kernel | 317 | memory.py — the deterministic memory organs (SPEC §4.1, §4.3; BUILD-PLAN 2.1–2.2). |
mindcheck.py |
untagged | 208 | mindcheck.py — IS THE MIND ACTUALLY ABLE TO THINK? (2026-07-27) |
narrate.py |
untagged | 172 | narrate.py — Rocoto narrates his own build to Peter, in first person, in character. |
operator_access.py |
untagged | 123 | Database-owner maintenance CLI for explicit, expiring support grants; plans unless --apply. |
operator_api.py |
untagged | 100 | Internal console HTTP boundary, mounted with the deployment's explicit environment. |
operator_login.py |
untagged | 188 | Server-side Supabase Google PKCE exchange into the maintained sup_session identity flow. |
operator_service.py |
untagged | 275 | Governed support operations: exact grants, bounded reads, atomic audit and repeatable writes. |
operator_ui.py |
untagged | 32 | Serve the separately built support interface alongside its authenticated API. |
ops.py |
untagged | 93 | Operational alerts and unit heartbeats. |
order_receipt.py |
untagged | 508 | order_receipt.py — THE CONFIRMATION THE CUSTOMER ACTUALLY GETS. |
orders.py |
app | 892 | Phase-A order intake — UNGROUNDED extraction → Excel dispatch. |
orders_tool.py |
app | 498 | orders_tool.py — placing/editing a real Medusa order as a runtime AGENCY action (SPEC §5/§7). |
pedidos_meter.py |
untagged | 282 | Rocoto Pedidos — the orders METER (PEDIDOS-PRICING-BUILD.md §3). |
playbook.py |
untagged | 226 | playbook.py — the data layer behind /internal/playbook, Peter's sales tool. |
playbook_api.py |
untagged | 126 | Sales playbook HTTP routes; Control Room auth and service-owned business logic. |
portal.py |
untagged | 739 | portal.py — THE CUSTOMER'S OWN DOOR (SPEC §5.9). |
postcall.py |
app | 289 | Hermes-style 2-channel post-call diarization. |
presence.py |
kernel | 49 | presence.py — WP-8b person-layer (R6 pacing + R8 relationship stage). Deterministic, no LLM. |
presence_call.py |
kernel | 179 | presence_call.py — CHANNEL PRESENCE (§15 CHANNEL CONTINUITY): call lifecycle events + AHORA MISMO. |
projector.py |
app | 99 | projector.py — WP-9 P0: the OUTBOUND projector. Every spine msg.sent becomes a whatsapp_messages |
provisioning.py |
untagged | 312 | provisioning.py — AN EMAIL BECOMES A WORKSPACE. One writer, two doors (§17.17, §17.56c). |
reach.py |
kernel | 69 | reach.py — WP-6b THE PROACTIVE-REACH ENGINE (SPEC §3 channel law; a channel-reachability PERCEPTION, |
reparto_api.py |
untagged | 1,366 | reparto_api.py — LA PUERTA DEL REPARTIDOR, y no hay otra (SPEC §5.11). |
review.py |
untagged | 599 | review.py — THE REVIEW RULE (SPEC §5.8). The comercial's queue is near-EMPTY by design. |
rocoto_processes.py |
app | 61 | rocoto_processes.py — APP-side fabric registrations (kernel-boundary pass, 2026-07-22). |
rt_embed.py |
kernel | 139 | rt_embed.py — the EMPLOYEE-RUNTIME dense embedder (SPEC §5: 384-d multilingual). |
runtime.py |
kernel | 968 | runtime.py — THE one event-sourced cycle every sense funnels into (SPEC §4.5 / §5.0). |
schema_migrations.py |
untagged | 308 | Explicit Alembic lifecycle for the maintained backend's PostgreSQL schema. |
soul.py |
kernel | 332 | soul.py — the SOUL is ASSEMBLED, not forked (SPEC §6 "The SOUL question" / §16.2 L0–L3). |
spine.py |
kernel | 482 | spine.py — the event spine's sensing→append organ (SPEC §4.5 ①, §3, §6). |
sup_api.py |
untagged | 4,007 | sup_api.py — the supplier web-app surface (/api/sup/*), ONE kernel organ (Wave-3). |
sup_session.py |
untagged | 334 | sup_session.py — supplier web-app auth + server-side sessions (Wave-3 sup-auth, ONE kernel organ). |
sup_verbs.py |
untagged | 733 | §17.48b — THE ONE VERB REGISTRY the copilot and the MCP server share. |
sweep.py |
kernel | 344 | sweep.py — THE DAILY SUMMARY SWEEP (SPEC §4.3, with the §4.1 roll-off it enables). |
sync.py |
untagged | 140 | sync.py — THE PANEL IS A VIEW OF THE SPINE (§17.39 · WP-E2). |
tenancy.py |
kernel | 376 | tenancy.py — scope→tenant resolution, KERNEL-owned (kernel-boundary pass, 2026-07-22). |
test_account.py |
untagged | 221 | test_account.py — THE FOUNDER VERB: mint a whole working account, end to end. |
test_join.py |
untagged | 342 | test_join.py — the /join doors (JOIN-PAGE-SPEC-2026-09-04.md §2 Verification). |
testdata_adapter.py |
untagged | 464 | Product adapter for the company testdata protocol; owns one local throwaway cluster. |
trackers.py |
untagged | 759 | trackers.py — THE TRACKER REGISTRY (BLOCK C; SPEC §5.6 "Vigilancias", product name Trackers). |
transcribe.py |
untagged | 306 | Transcription + OCR — Deepgram nova-3 (diarized) then Claude Sonnet 4.6. |
trends.py |
untagged | 500 | trends.py — THE TREND ENGINE (OFERTA-DEL-DIA-SPEC §3). Organ ①. |
triggers.py |
kernel | 22 | triggers.py — TRIGGER VOCABULARY, one owner (de-workflow pass, 2026-07-22). |
try_chat.py |
untagged | 283 | try_chat.py — «Prueba la IA» / "Try the AI" (SITE-V2-PLAN.md §6, WP-E). |
twilio_wa.py |
untagged | 272 | Twilio WhatsApp: media download (Basic auth) + outbound send. |
urlfetch.py |
untagged | 446 | urlfetch.py — A LINK A STRANGER PASTED, TURNED INTO BYTES WE ARE WILLING TO READ. |
voice.py |
app | 295 | Twilio Voice TwiML + the Deepgram live-transcription socket. |
voice_fabric.py |
kernel | 227 | voice_fabric.py — THE PROCESS FABRIC (IN-CALL-RUNTIME-DESIGN §9.1/§14, review C3). Organ ④. |
voice_protocol.py |
kernel | 754 | voice_protocol.py — the in-call §7 LATENCY PROTOCOL brain (answer-first / check-aside / rejoin). |
voice_reply.py |
app | 1,269 | WhatsApp auto-reply — two rails, one first-person soul. |
voice_toggle.py |
app | 238 | voice_toggle.py — THE ONE VOICE MIND: our runtime agent, or nothing. |
voice_turn.py |
app | 63 | Native voice mode — one low-latency spoken turn. |
vroom.py |
untagged | 185 | vroom.py — the route-optimisation client organ (Wave-3 §2d/§3, ONE kernel organ). |
wa_calling.py |
untagged | 264 | wa_calling.py — WhatsApp calling: the capability, the settings, and answering the phone honestly. |
wa_coexistence.py |
untagged | 310 | wa_coexistence.py — the half of coexistence that is NOT the Connect button. |
wa_onboard.py |
untagged | 247 | wa_onboard.py — CONNECT: a customer attaches their own WhatsApp number to Rocoto. |
whatsapp_cloud.py |
untagged | 642 | whatsapp_cloud.py — Meta WhatsApp Cloud API DIRECT rail (our own WABA, no BSP in the path). |
widget_build.py |
untagged | 58 | Live in-call UI builder — turns a one-line spec into a self-contained HTML preview. |
worker.py |
untagged | 898 | worker.py — THE TIMER WORKER, the runtime's only clock (SPEC §5.0 / §5.0.1 / §3.1). |
worker_capture.py |
untagged | 65 | Typed, scope-bound provider capture for the maintained timer operation's staging proof. |
worker_policy.py |
untagged | 34 | Deployment policy for the maintained worker's automatic, cross-tenant sweeps. |
backend/brain/ — the domain layer
76 modules · 32,224 lines · 0 kernel · 76 app · 0 untagged
| module | layer | lines | what it is |
|---|---|---|---|
brain/__init__.py |
app | 9 | Order-brain: grounded WhatsApp/voice order intake. |
brain/accept.py |
app | 240 | Acceptability engine (acceptability-engine.md) — DETERMINISTIC at runtime, no LLM. |
brain/auth.py |
app | 961 | Supabase identity ↔ Rocoto lead bridge. |
brain/autoaccept.py |
app | 81 | Auto-accept sweep (acceptability-engine.md §6 + medusa-integration.md §2). |
brain/baskets.py |
app | 343 | Storefront custom-order baskets — the draft that lands in the supplier's WhatsApp thread. |
brain/billing.py |
app | 632 | brain/billing.py — M1M2 WP-4: the €500 credit ledger + the 0,3% GMV meter (SPEC §16.4). |
brain/calbook.py |
app | 342 | cal.com API v2 client for Rocoto onboarding (brain/calbook.py). |
brain/catalogue.py |
app | 640 | E-commerce catalogue read-model + product editor (medusa-integration.md §3/§4). |
brain/choco.py |
app | 175 | §17.49 — A CHOCO LINK IS AN ORDER (WP-G5, the Bidfood gate). |
brain/context.py |
app | 141 | Multi-scale context for the readers (Register #8, memory windows). |
brain/decision.py |
app | 174 | Decision agent (Sonnet) — pick the SKU from the matcher's candidates, and CARRY THE DOUBT. |
brain/drip.py |
app | 540 | Re-engagement drip — the abandoned-signup email ladder. |
brain/embed.py |
app | 128 | Dense embeddings — self-hosted ONNX (fastembed), warm-loaded singleton. |
brain/enrich.py |
app | 64 | Reverse-phone location enrichment (Stage 7, the founder-hermes way). |
brain/entitlement.py |
app | 171 | entitlement.py — which products a tenant has, and what «on» means (§17.2, §17.30k · WP-A2). |
brain/events.py |
app | 650 | Event-sourced, bi-temporal orders (Register #12, #19, #21). |
brain/founder_prices.py |
app | 618 | Rocoto — PINNED FOUNDER PRICES: the founder_ Stripe namespace the public tooling can never touch. |
brain/geocode.py |
app | 118 | §2b.2 (WEB-PRODUCT-BUILD-PLAN) — the customer-coordinate WRITER that never existed. |
brain/golive.py |
app | 773 | brain/golive.py — the catalogue→grounding bridge (M1M2-BUILD-PLAN WP-1 + its hardening). |
brain/habits.py |
app | 155 | §17.30g / §17.35-adjacent — THE HABIT ENGINE: order habits as a POPULATION, with confidence. |
brain/identity.py |
app | 267 | Identity resolution (Register #14) — right customer every time, hard tenant isolation. |
brain/invitations.py |
app | 170 | invitations.py — §17.41's invitation, whose TOKEN IS THE LINK (WP-A3). |
brain/invoice.py |
app | 177 | brain/invoice.py — THE ORDER DOCUMENT, as a downloadable PDF, for the customer portal (portal.py). |
brain/jobs.py |
app | 57 | Background drainer for the durable ingest queue (Stage 3). |
brain/journey.py |
app | 320 | brain/journey.py — the account's journey as a fold of the event spine (THE-JOURNEY-CANON §1). |
brain/junkgate.py |
app | 70 | Deterministic junk gate (Register #6, risk #7) — NO model. |
brain/keepinmind.py |
app | 60 | Keep-in-mind bands (Register #16, #20, RUNTIME L4) — the three attention levels. |
brain/lead_notify.py |
app | 449 | The two alerts Peter gets: somebody priced themselves on /precios, and somebody opened an account. |
brain/learn.py |
app | 164 | Learn from the operator's edit trail (RUNTIME L5 — "make it cheaper" running live). |
brain/livecall.py |
app | 117 | Live in-call order draft (Stage 7) — the same read→match→decide, throttled + cheap. |
brain/llm.py |
app | 62 | Anthropic tool-call helper for the brain agents (mirrors orders.extract_order_sync). |
brain/matcher.py |
app | 802 | Mention -> formal SKU matching (the grounding step). |
brain/medusa_client.py |
app | 156 | Async HTTP client for the Medusa Admin API — localhost only (medusa-integration.md §6). |
brain/medusa_drain.py |
app | 136 | The Medusa outbox drainer (medusa-integration.md §1). |
brain/medusa_map.py |
app | 152 | Pure mappers between Rocoto's order shape and Medusa's order shape. |
brain/metrics.py |
app | 124 | Per-employee goal metrics — the console goal hero + ops band (employee-goals.md). |
brain/notify.py |
app | 295 | Customer comms loop for the storefront custom/ASAP flow (medusa-integration.md §1-2, plan Stage 5a). |
brain/onboard_q.py |
app | 118 | Central test/live isolation chokepoint for the onboarding / CRM tables. |
brain/onboarding.py |
app | 2,503 | Rocoto onboarding / CRM spine. |
brain/onboarding_ext.py |
app | 573 | Rocoto onboarding — endpoint orchestration layer (brain/onboarding_ext.py). |
brain/order_card.py |
app | 191 | brain/order_card.py — THE CLEAN ORDER CARD, rendered as an actual image for WhatsApp. |
brain/order_payment.py |
app | 211 | brain/order_payment.py — «Paga con tarjeta» on the customer portal (portal.py / SPEC §5.9). |
brain/otp.py |
app | 56 | Phone OTP for the PUBLIC shop endpoints — Twilio Verify (the supplier's own Twilio account). |
brain/pedidos_billing.py |
app | 1,881 | Rocoto Pedidos — LIVE Stripe billing (PEDIDOS-PRICING-BUILD.md, "THE SETTLED SHAPE — 2026-08-12", |
brain/pedidos_usage_report.py |
app | 403 | Rocoto Pedidos — THE USAGE REPORTER: what turns a counted order into a billed one. |
brain/pedidos_welcome_email.py |
app | 317 | The welcome email — sent once, when a Pedidos Checkout completes. |
brain/personalise.py |
app | 51 | Personalisation pass (Sonnet, Register #19) — the human touch, last. |
brain/pin_watch.py |
app | 255 | The PIN CAPABILITY WATCHER — a once-a-week knock on a door Meta has not opened yet. |
brain/pipeline.py |
app | 1,595 | Order pipeline — the seam the durable queue drains into. |
brain/pricing_quote.py |
app | 569 | What a /precios quiz submission is actually worth — recomputed here, never read off the wire. |
brain/profile.py |
app | 377 | Customer profile — the "always" scale + Customer DNA source (Register #5, Stage 5). |
brain/prompts.py |
app | 265 | Prompts + tool schemas for the brain agents (Register #18, #23, RUNTIME L2). |
brain/queue.py |
app | 164 | Durable ingest queue — "always follow the queue" (Register #76, Stage 3). |
brain/range.py |
app | 442 | brain/range.py — WHERE THEY DELIVER, STORED AS A RULE (SPEC §5.8a item 2). |
brain/rerank.py |
app | 61 | Cross-encoder reranker — the biggest precision lift on the matching tail. |
brain/route.py |
app | 103 | Route optimization for the Delivery Manager (deliveries.md) — sequences the day's stops into the |
brain/scales.py |
app | 49 | Five parallel Haiku scale-readers (Register #18/#23). |
brain/seed.py |
app | 3,094 | brain/seed.py — THE SEEDED WORLD (Peter, 2026-07-27). |
brain/setupfee.py |
app | 445 | Rocoto onboarding SETUP FEE — the €50 one-time 'alta' that gates the waitlist. |
brain/skuparse.py |
app | 1,025 | Rocoto onboarding — catalogue file → normalized SKU rows (brain/skuparse.py). |
brain/stock.py |
app | 1,265 | brain/stock.py — STOCK LEVELS, so «no hay stock» is a REASON and not a screen (SPEC §5.8a row 3). |
brain/stripe_connect.py |
app | 173 | Rocoto's OWN Stripe Connect layer — clean, self-contained, Medusa-adjacent. |
brain/stripe_subs.py |
app | 396 | Rocoto's Stripe SUBSCRIPTIONS layer — OUR SaaS billing of the supplier for their AI employees. |
brain/synthesiser.py |
app | 108 | Synthesiser (Sonnet) — merge the 5 scale-reads into the real order, then run the SKU match. |
brain/tabular.py |
app | 138 | Build the tabular SKU order (Register #19): code · qty · unit · price · date + the doubt band. |
brain/tasks.py |
app | 378 | Modular scheduled tasks + the recommendation→accept loop (employee-scheduled-tasks.md). |
brain/teams.py |
app | 417 | Operator teams — the typed contract behind multi-team operation. |
brain/tenants.py |
app | 175 | Tenant registry — the canonical list of supplier shops (= teams). |
brain/testdata.py |
app | 584 | Test-data generator + seeder for owner-driven TEST MODE (TEST-MODE-AND-ACCESS spec §4). |
brain/theme.py |
app | 132 | The design-shotgun theme generator (ecommerce-manager.md §8) — Opus 4.8 builds the storefront FOR |
brain/understand.py |
app | 729 | The post-upload understand pass — colloquial call transcript ↔ uploaded SKUs (Opus 4.8). |
brain/validators.py |
app | 196 | Deterministic validators (RUNTIME L3) — code, not vibes. |
brain/vocab.py |
app | 734 | brain/vocab.py — THE VOCABULARY PASS (PRODUCT-SPEC §5.7 / §5.7a). |
brain/wa_watch.py |
app | 202 | Self-terminating WhatsApp-template-approval watcher + a tiny durable flag store. |
brain/waitlist.py |
app | 171 | Rocoto referral-only waitlist. |
brain/window.py |
app | 1,145 | brain/window.py — THE DELIVERY WINDOW, AND WHO PROMISED IT (SPEC §5.8a · WP-5 «Reparto»). |
backend/migrations/
6 modules · 182 lines · 0 kernel · 0 app · 6 untagged
| module | layer | lines | what it is |
|---|---|---|---|
migrations/__init__.py |
untagged | 1 | Versioned, immutable PostgreSQL migration sources. |
migrations/env.py |
untagged | 54 | Alembic asyncpg environment; lock and transaction cover the whole revision chain. |
migrations/versions/0001_baseline.py |
untagged | 38 | Freeze the existing maintained schema and isolation policies as the adoption floor. |
migrations/versions/0002_inbound_idempotency.py |
untagged | 38 | Enforce inbound webhook idempotency atomically; duplicate data requires explicit repair. |
migrations/versions/0003_operator_console.py |
untagged | 29 | Add explicitly granted operator support operations and immutable audit receipts. |
migrations/versions/0004_module_schema.py |
untagged | 22 | Move optional modules' lazy schema into the explicit deployment transaction. |
backend/scripts/
3 modules · 1,637 lines · 0 kernel · 0 app · 3 untagged
| module | layer | lines | what it is |
|---|---|---|---|
scripts/provision_stripe_pedidos.py |
untagged | 195 | Idempotently create/update the Stripe catalogue for Rocoto Pedidos (PEDIDOS-PRICING-BUILD.md §2/§5): |
scripts/provision_stripe_v2.py |
untagged | 1,202 | Build the Stripe catalogue for the SEAT-BAND model — Ventas · Compras · Reparto · Radar · |
scripts/reprice_stripe_pedidos.py |
untagged | 240 | Move a Rocoto Pedidos lookup_key onto a NEW Stripe Price when BANDS says the amount changed. |
backend/seed/
3 modules · 966 lines · 0 kernel · 0 app · 3 untagged
| module | layer | lines | what it is |
|---|---|---|---|
seed/authenticated.py |
untagged | 203 | Owned development proof through the normal identity, HTTP and product-service boundaries. |
seed/staging_worker.py |
untagged | 346 | Explicit staging proof of one owned timer through real domain processing and captured effects. |
seed/testdata.py |
untagged | 417 | Canonical synthetic account/data and bounded application proofs in an owned database. |
How it hangs together
The tables above are generated. Everything from this heading down is written by hand and lives in
tools/backend-map-prose.md; the generator pastes it back every run.
One process. app.py is the whole HTTP surface: a single FastAPI app on 127.0.0.1:8092 with
Caddy in front of it. It carries 261 routes of its own and mounts nine more organs, each on one
line at the bottom of the file — sup_api (the supplier panel, /api/sup/*), demo_auth and
claim (the two doors into an account), intake_api, mcp_server, mail_inbound, join,
api_v1 (the public read API, /v1/*) and reparto_api (the driver's door). Mount order is a
contract, stated in the comment beside each line: the later organs bind sup_api's own session
dependency, so a consent is exactly as authenticated as the panel.
Boot. app._startup() refuses first (see «Failing closed» below), then calls db.init(), which
opens the pools and applies the schema. After it: the tenant and team rows the surfaces read, the
founder tenant completed, the transcriptions a restart stranded retried, orphaned call rows swept,
and the embedding model warmed off the event loop so the first spoken turn after a restart meets a
hot model.
The turn. Every sense funnels into runtime.run_turn: spine appends the event, assemble
builds the bounded fold (the card, the seven-day window, the open tabs, recall, the product
directory, presence), the mind decides from that fold, gate checks every outbound sentence that
mentions money, and agency acts. sweep is its daily summary and worker its only clock — and
worker is one of the sixty the law names on neither side, though what it does is kernel work.
Voice inverts the order: it answers from the pinned fold and folds the heavy work between turns on
voice_fabric. That set of modules is the kernel — the generic employee, versioned in
KERNEL-VERSION.
The domain. brain/ is Rocoto's commerce world, and the largest single thing in the backend:
per message → durable queue → junk gate → a debounce → identity → parallel scale-readers → the
synthesiser that merges and matches SKUs → the decision → deterministic validators → the tabular
order → operator hold-to-submit and undo → an event-sourced order. Billing, entitlement, onboarding,
tenants and the catalogue sit beside it. It is app-side by law: the kernel imports nothing from it.
The data. db.py holds the schema as python string blocks plus schema_runtime.sql, and hands
out three pools — the owner pool for DDL and legacy reads, the runtime pool that connects as a
non-owner role so FORCE ROW LEVEL SECURITY binds it, and the control pool for cross-scope
background scans. backend/README.md says which to reach for.
Failing closed (WP-E, 2026-09-06)
The doors that verify a stranger's request now verify it always, and the boot refuses a production process that cannot.
- Boot.
config.assert_prod_ready()runs first inapp._startup(). UnderIS_PRODit raises and NAMES anything unset from:ROCOTO_API_KEY,ROCOTO_AGENT_TOOL_SECRET,FB_APP_SECRET,WA_CLOUD_VERIFY_TOKEN,OWNER_EMAILS, plus each rail's webhook secret once that rail is configured (TWILIO_AUTH_TOKEN,ELEVENLABS_WEBHOOK_SECRET,STRIPE_WEBHOOK_SECRET). - Webhooks. Meta, every Twilio callback (
_require_twilio_signature) and the ElevenLabs post-call webhook verify unconditionally; a missing secret is a refusal (403/401), never a skip. The one bypass isROCOTO_ALLOW_UNSIGNED_WEBHOOKS, andconfig.allow_unsigned_webhooks()ignores it underIS_PROD. Stripe and the Resend inbound rail already refused unsigned bodies. - Schema.
db.init()applies its six schema blocks through_apply, which logs and RAISES: a half-applied schema never serves traffic. Boot talks throughlogging.getLogger("rocoto.db"). - RLS.
ROCOTO_REQUIRE_RLS=truemakes the fallback to the owner pool a refusal to boot, and/healthzpublishesrls: {runtime_role, forced}—forced:falsealso lands indegraded. - Owners.
OWNER_EMAILS/MASTER_OWNER_EMAILhave no source defaults; who owns a box is a deployment fact (backend/tests/conftest.pysets the test box's own). - Logs.
logging_setup.configure()(ported frommock-api/app/logging_setup.py) installs one redacting JSON formatter for the backend, the worker, the sweep and the reaper: phone numbers keep four digits, emails keep their domain, configured secrets and key-shaped tokens vanish, anduvicorn.accessis silenced. Message bodies are dropped at the call site — the formatter cannot recognise a sentence, so content is logged as a length and an id.