|
| 1 | +# Launch Readiness Checklist |
| 2 | + |
| 3 | +**Status:** Draft for team sign-off |
| 4 | +**Scope:** Production launch (v1 / GA) of the ObjectStack framework monorepo |
| 5 | +**Last reviewed:** 2026-06-04 (`main` @ `9f311f8` — ADR-0030 P3b-2 digest) |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## How to use this document |
| 10 | + |
| 11 | +Each item has an **owner**, a **verification box**, and a **sign-off box**. The |
| 12 | +two are deliberately separate: |
| 13 | + |
| 14 | +- ☐ **Verify** — a named engineer has confirmed the finding is real (or a false |
| 15 | + positive) by reading the actual code / running a repro. Several items below |
| 16 | + originate from an automated package-by-package sweep and are **not yet |
| 17 | + hand-verified** — do not action them before verifying. |
| 18 | +- ☐ **Sign-off** — the fix is merged (or the risk is formally accepted and the |
| 19 | + acceptance recorded in the "Notes" column). |
| 20 | + |
| 21 | +A "false positive" still gets ticked on Verify, with a one-line note explaining |
| 22 | +why no fix is needed. **Do not mark a P0 signed-off on the strength of the sweep |
| 23 | +alone.** |
| 24 | + |
| 25 | +Priority key: **P0** = blocks launch · **P1** = fix at/just-after launch · |
| 26 | +**P2** = test-coverage / hardening gap · **Roadmap** = explicitly out of v1. |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## Overall posture |
| 31 | + |
| 32 | +The codebase is mature and disciplined. A repo-wide scan found **zero** |
| 33 | +`TODO/FIXME/HACK` markers, `console.log` in source, empty `catch` blocks, |
| 34 | +`@ts-ignore`, or hard-coded secrets. `main` CI is green (Build/Test Core, Lint & |
| 35 | +Type Check, CodeQL). The core tier — `spec`, `objectql`, `plugin-security`, |
| 36 | +`runtime`, the SQL drivers, `service-ai` — is assessed production-ready. |
| 37 | + |
| 38 | +Launch risk is concentrated in a small number of themes below, not in code |
| 39 | +quality. **The single most important caveat: the security- and data-integrity |
| 40 | +findings (§P0) are from an automated sweep and MUST be hand-verified before any |
| 41 | +fix or acceptance.** |
| 42 | + |
| 43 | +--- |
| 44 | + |
| 45 | +## P0 — Blockers (verify, then fix or formally accept) |
| 46 | + |
| 47 | +> Every P0 below must be **hand-verified** first — some may be false positives or |
| 48 | +> already-guarded. Do not ship without each row at Verify ✓ **and** Sign-off ✓. |
| 49 | +
|
| 50 | +### P0-1 — Auth secret falls back to a weak dev secret |
| 51 | +- **Area:** `plugin-auth` — `src/auth-manager.ts` (~L1052–1071, `generateSecret()`) |
| 52 | +- **Risk:** If `OS_AUTH_SECRET` is unset in production, the manager logs a warning |
| 53 | + and falls back to `dev-secret-<timestamp>`. Session tokens become predictable → |
| 54 | + session forgery. (HIGH, security) |
| 55 | +- **Action:** Throw (fail boot) when no secret is configured and |
| 56 | + `NODE_ENV === 'production'`; add a pre-boot config validation. Document |
| 57 | + `OS_AUTH_SECRET` as a required go-live env var. |
| 58 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 59 | + |
| 60 | +### P0-2 — Metadata-service failure bypasses all RBAC/RLS (fail-open) |
| 61 | +- **Area:** `plugin-security` — `src/security-plugin.ts:309–312` |
| 62 | +- **Risk:** A metadata-resolution error is swallowed and the request proceeds via |
| 63 | + `next()` with **no permission checks**. If the metadata service degrades, every |
| 64 | + user bypasses RBAC/RLS. (HIGH, security) |
| 65 | +- **Action:** Add a circuit-breaker + ERROR-level alerting; add an integration |
| 66 | + test asserting "metadata service down ⇒ request denied", not allowed. Decide |
| 67 | + fail-closed vs. fail-open explicitly and record the decision. |
| 68 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 69 | + |
| 70 | +### P0-3 — Unescaped LIKE metacharacters in `contains` |
| 71 | +- **Area:** `driver-sql` — `src/sql-driver.ts:1565, 1656` |
| 72 | +- **Risk:** The `contains` / `$contains` operator embeds the user value into a |
| 73 | + `%...%` LIKE pattern without escaping `%` / `_`. Parameterization prevents SQL |
| 74 | + injection, but a `%` value matches everything → logic-level filter bypass. |
| 75 | + (HIGH, data) |
| 76 | +- **Action:** Escape `%` and `_` (and the escape char) before building the LIKE |
| 77 | + pattern; add a test with a `%`/`_` payload. |
| 78 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 79 | + |
| 80 | +### P0-4 — MongoDB filter passes arbitrary `$` operators through |
| 81 | +- **Area:** `driver-mongodb` — `src/mongodb-filter.ts:82–84` |
| 82 | +- **Risk:** Operator keys are passed straight to MongoDB with no allowlist, so |
| 83 | + `$where` / `$function` (server-side JS) reach the engine → query-intent bypass |
| 84 | + and a potential JS-execution surface. (HIGH **if MongoDB is a launch driver**) |
| 85 | +- **Action:** Allowlist safe operators (`$eq/$ne/$gt/$gte/$lt/$lte/$in/$nin/$and/$or/...`); |
| 86 | + reject unknown ones at filter-build time. If MongoDB is not a v1 driver, mark |
| 87 | + Roadmap instead. |
| 88 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 89 | + |
| 90 | +### P0-5 — Realtime & feed are in-memory only (no cluster coordination) |
| 91 | +- **Area:** `service-realtime` (`in-memory-realtime-adapter.ts`), `service-feed` |
| 92 | + (`in-memory-feed-adapter.ts`) |
| 93 | +- **Risk:** Publish/subscribe and feed storage are process-local. In a multi-node |
| 94 | + deployment, clients connected to node B never receive node A's events, and feed |
| 95 | + data is lost on restart / unbounded in memory. (HIGH **for HA/cluster**; |
| 96 | + N/A for single-instance) |
| 97 | +- **Action (cluster launch):** Provide a Redis-backed realtime adapter and a |
| 98 | + DB-backed feed adapter, **or** formally restrict v1 to single-instance and |
| 99 | + document it as non-HA. Enforce a `maxItems` cap if shipping in-memory feed. |
| 100 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 101 | + |
| 102 | +--- |
| 103 | + |
| 104 | +## P1 — Fix at launch or immediately after |
| 105 | + |
| 106 | +### P1-1 — External calls have no timeout / retry / backoff |
| 107 | +- **Area:** `embedder-openai` (`src/index.ts:~157`), `connector-rest` (~L157), |
| 108 | + `connector-slack` (~L155), `connector-mcp` |
| 109 | +- **Risk:** Naked `fetch` with no timeout or 429/5xx backoff → a slow or |
| 110 | + rate-limited external API hangs the entire agent turn with no recovery. |
| 111 | +- **Action:** Add a default request timeout (e.g. 30s, configurable) + exponential |
| 112 | + backoff (3 tries) + a circuit breaker; tests for 429 / timeout paths. |
| 113 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 114 | + |
| 115 | +### P1-2 — Unbounded growth: execution logs, job runs, event log |
| 116 | +- **Area:** `service-automation` (in-memory exec logs, hard 1000 cap), |
| 117 | + `service-job` (`sys_job_run`, no retention), `service-messaging` |
| 118 | + (event log retention is opt-in) |
| 119 | +- **Risk:** Long-running pods OOM; history tables grow without bound. |
| 120 | +- **Action:** Make retention **default-on** for all event/run tables; schedule |
| 121 | + sweepers at startup; persist automation logs to a table rather than memory. |
| 122 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 123 | + |
| 124 | +### P1-3 — No process-level graceful shutdown |
| 125 | +- **Area:** `runtime` (`http-server.ts`) + framework adapters |
| 126 | +- **Risk:** No SIGTERM/SIGINT handling → in-flight requests dropped on |
| 127 | + rolling deploys (K8s SIGKILL after grace period); cluster (Redis) + kernel + |
| 128 | + HTTP not drained in a coordinated order. |
| 129 | +- **Action:** Ship a graceful-shutdown utility (drain HTTP → stop kernel services |
| 130 | + → close cluster) and wire it into app scaffolding; document a ≥60s grace floor. |
| 131 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 132 | + |
| 133 | +### P1-4 — Per-request hostname → environment resolution (no cache) |
| 134 | +- **Area:** `rest` — `src/rest-server.ts:~504–530` |
| 135 | +- **Risk:** `resolveByHostname()` runs on every unscoped request → control-plane |
| 136 | + latency spike under load; silent fallback to default project masks it. |
| 137 | +- **Action:** Add an in-memory TTL cache (~30s) for `hostname → environmentId`. |
| 138 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 139 | + |
| 140 | +### P1-5 — Cluster pub/sub is fire-and-forget (metadata-changed) |
| 141 | +- **Area:** `service-cluster-redis` — `src/pubsub.ts:~75–90` |
| 142 | +- **Risk:** `publish()` doesn't wait for subscribers; a crash right after a schema |
| 143 | + change leaves other nodes with a stale schema until the next full reload. |
| 144 | +- **Action:** Acceptable for non-critical events if documented; ensure schema |
| 145 | + mutations re-sync on error boundaries (history exists in `sys_metadata_history`). |
| 146 | + Record the durability contract. |
| 147 | +- **Owner:** _______ · Verify ☐ · Sign-off ☐ · Notes: _______ |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +## P2 — Test-coverage & hardening gaps (ready, but shore up) |
| 152 | + |
| 153 | +| ID | Area | Gap | Action | Owner | Verify | Sign-off | |
| 154 | +|----|------|-----|--------|-------|:------:|:--------:| |
| 155 | +| P2-1 | `metadata-fs` | **NEEDS-WORK.** Atomicity / `watch` replay consistency under concurrent FS writes; 200ms chokidar self-write suppression is racy on slow/network FS | Add fault-injection tests (crash mid-write, concurrent put+delete, watch replay); validate `writeJsonAtomic` | ____ | ☐ | ☐ | |
| 156 | +| P2-2 | `cli` | Missing `serve` integration test (kernel init + HMR reload + SIGINT); possible missing `environments.ts` implementation (test exists) | Add serve/dev integration test; confirm `environments` command exists | ____ | ☐ | ☐ | |
| 157 | +| P2-3 | `plugin-webhooks` | Thin tests (1 test file); `eventId` dedup can collide on identical-ms timestamps | Add UUID suffix to `eventId`; expand auto-enqueuer tests | ____ | ☐ | ☐ | |
| 158 | +| P2-4 | `service-queue` | CAS claim (read-then-update) is not atomic → tolerated duplicate delivery; empty idempotency key bypasses dedup | Enforce non-empty idempotency key; add a lease safety margin; document at-least-once | ____ | ☐ | ☐ | |
| 159 | +| P2-5 | `plugin-audit` | `sys_session` mutations are not audited | Confirm login/logout are logged elsewhere (`sys_audit_log`); close the compliance gap if not | ____ | ☐ | ☐ | |
| 160 | +| P2-6 | `core` / `runtime` | `getService()` is sync but may return a Promise → unhandled-rejection footgun for plugin authors | Tighten the type / add a guard; document the sync-only contract | ____ | ☐ | ☐ | |
| 161 | + |
| 162 | +--- |
| 163 | + |
| 164 | +## Roadmap — Explicitly out of scope for v1 (no action to launch) |
| 165 | + |
| 166 | +These are **designed but unbuilt** and should be named "not in v1" in the release |
| 167 | +notes, not treated as blockers. |
| 168 | + |
| 169 | +- ☐ **Unverified features — confirm stub vs. minimal, then include or exclude:** |
| 170 | + `knowledge-ragflow`, `connector-openapi` (the sweep could not locate full |
| 171 | + implementations; the packages exist — verify scope before GA). |
| 172 | +- ☐ **Proposed ADRs (roadmap):** ADR-0021 (analytics semantic layer), |
| 173 | + ADR-0022/0023/0024 (connectors / OpenAPI→connector / MCP connectors), |
| 174 | + ADR-0025/0026 (plugin & client-UI distribution), ADR-0027 (metadata authoring |
| 175 | + lifecycle), ADR-0028 (naming/namespace isolation), ADR-0029 (kernel object |
| 176 | + ownership — **partially landed**: K0 + D7 + several K2 domains), ADR-0033 |
| 177 | + Phase D (enterprise AI-authoring governance). |
| 178 | + |
| 179 | +--- |
| 180 | + |
| 181 | +## Release mechanics |
| 182 | + |
| 183 | +- ☐ `main` CI green at the release commit (Build/Test Core, Lint & Type Check, CodeQL). |
| 184 | +- ☐ Pending changesets reviewed (4 at last check) and version bump intentional. |
| 185 | +- ☐ `pnpm run release` path verified (`build` → `build-console.sh` → `changeset publish`). |
| 186 | +- ☐ Required env vars documented for go-live (at minimum `OS_AUTH_SECRET`; see P0-1). |
| 187 | +- ☐ Deployment topology decided: **single-instance** vs. **HA/cluster** (drives P0-5). |
| 188 | + |
| 189 | +--- |
| 190 | + |
| 191 | +## Provenance |
| 192 | + |
| 193 | +The per-package findings were produced by an automated, read-only package-by-package |
| 194 | +sweep on 2026-06-04 and synthesized here. They are a **starting point for review, |
| 195 | +not a verified defect list** — each item carries its own Verify box for exactly |
| 196 | +this reason. File:line references are approximate and must be confirmed against |
| 197 | +`main` before acting. |
0 commit comments