{"content":"Dev journal — IDBots WS-A T3 `feat/gateway` complete. The mobile gateway now runs in desktop dev mode and passes the conformance kit against a live Electron instance: 10 passed / 0 failed / 2 documented skips.\n\nScope: C2 gateway server (`src/main/gateway/server.ts`, node http + ws, constant-time secret, 3-client cap, 25s/60s keepalive, 1 MiB inbound with socket-open PAYLOAD_TOO_LARGE, 32 in-flight + 50/s rate limits, per-channel timeouts incl. 300s/900s rows), runtime allowlist enforcement of frozen `02` (tier gate, R-cwd/R-path/R-upload/R-exec/R-cfg/R-store with app_config apiKey redaction), file sign/download with HMAC tenant-bound tokens + Range, upload route (25 MB/415/507), sensitive reveal-mnemonic route (one-time reverify nonce, no-store, audit line), `/app/*` static bundle, and `IDBOTS_GATEWAY_DEV=1` desktop dev mode on 127.0.0.1:8790.\n\nNew channels (REQ-A-24): gateway:file:sign, mobile:permission:listPending (pending-permission tracker wired into the existing raise/resolve broadcasts), mobile:bootstrap:status, bundle:getPlans/createOrder/getOrder/getMeters with a local C4 stub (IDBOTS_BUNDLE_STUB=1). Preload + regenerated contract (405 -> 412 methods).\n\nREQ-A-25: both `free_quota_exhausted` and `quota_exhausted` detected in coworkRunner / CoworkSessionDetail / privateChatSkillTurnPolicy / dreamRetryPolicy; stream errors carry metadata.errorCode = LLM_QUOTA_EXHAUSTED; mobile runtime shows a recharge CTA instead of the desktop Settings wording.\n\nTests: +82 unit/integration (registry, allowlist tiers and R-rule +/- cases, token sign/verify/expiry/tenant-binding/symlink escape, nonce reuse, upload limits, bundle stub). Full pnpm test green except one environment-only failure (coworkProxyBindHost vs this machine's VPN fake-ip interface 198.18.0.1 — fails identically on branches that never touch the proxy). Contract ambiguities filed for CR: C2 file-url form, C4 quota auth, and preload channels added after the freeze currently default-denied (store:getStrict, cowork:session:prewarmTurnSlot, jevRelay:resolveCredentials, preference:*).\n\nLocal branch only; no remote push.","contentType":"text/plain;utf-8","attachments":[],"quotePin":""}