## Web Publishing Design (Final)

CogOS provides the bridge. The cogent decides what to build.

### Architecture

Request Flow
Browser
│
▼ Cloudflare (Access JWT + DNS)
│
▼ Web Gateway Lambda (per-cogent, Function URL, no VPC)
│
▼ Validate Cloudflare Access JWT
│
├─── Static: /*
│ ▼ map URL → web/{path}
│ ▼ lookup: web/{path} → web/{path}/index.html → 404
│ ▼ read from Postgres via RDS Data API
│ ▼ return content + Cache-Control: no-store
│
└─── Dynamic: /api/*
▼ append to io:web:request channel (audit + delivery)
▼ invoke executor Lambda synchronously (like awaiting a future)
▼ executor runs handler process
▼ handler calls web.respond() → captured in executor memory
▼ executor returns response payload to gateway
▼ gateway returns HTTP
No polling. No correlation table. Just a function call.

### Three Layers

Layer 1: AWS Infrastructure (cogtainer CDK stack)
Gateway Lambda
Python 3.12, 512 MB, 60s timeout, Function URL, no VPC (RDS Data API). The only new AWS resource.
Cloudflare DNS
Points subdomain at Function URL. Access policy already exists. Gateway validates JWT.
IAM Role
RDS Data API (file store + channels), invoke executor Lambda.
Layer 2: CogOS Runtime (image boot)
web capability
publish(), unpublish(), respond(), list() — registered in init/capabilities.py like discord.
io:web:request
System channel for inbound HTTP requests. Created at boot like io:discord:dm.

Every cogent gets these. A cogent that doesn't use web pays nothing.

Layer 3: Cogent Application (optional)
Web cog
Defined in apps/website/init/cog.py. Daemon subscribed via handlers=["io:web:request"].
Handler prompt
Coglet's main.md — reads request, does work, calls web.respond(). Route logic lives here.
Published files
Any process with web capability calls web.publish("path", content). Stored at web/* in file store.

### Response Mechanism

Synchronous invocation — no intermediate storage
Gateway invokes executor Lambda (synchronous, like a future)
│
▼
Executor runs handler process
│
▼
Handler calls web.respond(request_id, 200, headers, body)
│
▼ response captured in executor memory
│
▼
Executor returns response payload
│
▼
Gateway returns HTTP to browser
No polling. No correlation table. No response channels.
Same pattern as parent spawning child + recv() in CogOS.

### Discord Analogy

Concept | Discord | Web
--- | --- | ---
IO Bridge | Discord Bridge (Fargate) | Web Gateway Lambda
Inbound Channel | io:discord:dm | io:web:request
Capability | discord.send_message() | web.respond() / web.publish()
Response path | Fire-and-forget (post to Discord API) | Return value through executor invocation
Dispatch | append → SQS → ingress → executor | append → gateway invokes executor directly
Handler | discord cog handler coglet | web cog handler coglet

### Concurrency (v1) + Limitations

Concurrency

Serial handler. One daemon, requests queue.

Mitigations:

- Executor timeout → 502 on crash/slow
- Respond fast + spawn children (202)
- Future: handler process pool

v1 Limitations

- Text-only static files
- Serial request handling
- 6 MB payload limit
- Same-origin only (no CORS)
- No caching (every req → Lambda)