Codex Dev Environment

Historical proposal. Read Reaktor Shadow for the current textbook direction and Operations & Reliability for the reconciled source state. This draft's capsule/environment ideas are retained as history; they do not establish shipped materialization, universal replay or permanent retention.

Design for a BestBuds/Reaktor development environment that is continuously refreshed from production-shaped data and traffic while staying safe, redacted, replayable, and resettable.

  • Author Codex
  • Date 2026-05-28
  • Scope Supabase, Cloudflare D1, Workers, Durable Objects, R2, Memgraph, server APIs
  • Status Design proposal

1. Summary

The development environment should not be a hand-maintained mock universe. It should be a moving shadow of production: the latest active traffic and data, plus a curated library of rare crashes, slow paths, invalid payloads, data-shape surprises, and incident traces that must never regress again.

The right abstraction is reaktor-shadow: an application-layer capture, materialization, and replay system. Keploy remains a useful runner for HTTP-style regression tests, but Reaktor should capture above raw HTTP so one trace can include a Worker request, service handler, D1 query, Durable Object message, R2 object reference, Supabase row closure, Memgraph subgraph, queue event, and downstream server response.

Moving window

Keep a rolling 7-day active dataset generated from real traffic, recently touched entities, and dependency closures.

Pinned anomalies

Preserve crash, timeout, DLQ, auth, media, graph, and high-latency capsules beyond the moving window until they are fixed and covered.

Writable overlays

Developers and CI write only to disposable overlays. The golden shadow snapshot is immutable and can be recreated every day.

2. Spec alignment

The Reaktor spec places reaktor-shadow in the tooling layer and intelligence/tooling plane. It calls for application-layer production traffic capture, local/CI replay, graph-community-scoped regression matrices, visual snapshot diffing, Keploy integration, and k6/Gatling load generation from captured traffic patterns.

Spec conceptConcrete interpretation for BestBuds
reaktor-shadowOwns capture manifests, redaction, resource dependency closure, replay fixtures, and shadow environment hydration.
Application-layer captureCapture typed Service envelopes and graph events, not raw packets. The same envelope works on Spring, Workers, queues, Pub/Sub, WebSocket, and Durable Object messages.
Keploy-style regressionKeploy can replay HTTP captures, but Reaktor wraps it with service-aware fixtures and response comparators that understand allowed drift.
Graphify community scopingA change in chat nodes replays chat community traffic first; auth, media, notification, and campaign capsules run only when impacted or on nightly builds.
Performance section 29k6/Gatling scripts are generated from captured rates, payload sizes, and route mixes. CI can replay at 1x/2x/5x against the shadow environment.

3. Target shape

Production Workers / Spring / DO / D1 / R2 / Supabase / Memgraph / Queues
        |
        | application-layer capture + resource references + redaction
        v
Shadow Lake
  R2 raw bodies + trace artifacts
  D1/Postgres catalog index
  pinned capsule registry
  graph/community labels from reaktor-graphify
        |
        | nightly + on-demand materializers
        v
Shadow Environments
  shadow-current      rolling 7-day moving window
  shadow-pinned/*     incident/anomaly capsules
  shadow-pr-<id>      ephemeral CI overlay
  shadow-local-<user> developer overlay
        |
        | replay + load + UI + workbench
        v
Tests, local dev, Reaktor Desktop, CI gates, agent diagnosis

Environment classes

EnvironmentPurposeMutation policyLifetime
shadow-currentDefault shared dev baseline, built from latest active production traffic.Read-only base plus resettable overlay.Rebuilt daily or every 6 hours when traffic grows.
shadow-pinnedCurated anomaly and incident corpus.Immutable capsules; overlays for replay.180 days by default, longer for unresolved incidents.
shadow-pr-<id>CI and load-test target for a branch.Disposable write overlay.Destroyed after PR close or 48 hours.
shadow-local-<user>Developer sandbox with realistic data.Disposable write overlay.Self-service recreate.

4. Capture plane

Capture should happen at the same typed boundary the app already uses: Reaktor service handlers, graph actions, repository calls, bus envelopes, and actor/worker messages. Raw HTTP capture is not enough because BestBuds spans Cloudflare Workers, Durable Objects, queues, R2, Supabase/Postgres, Memgraph, and JVM services.

Shadow envelope

{
  "schemaVersion": "reaktor.shadow.v1",
  "captureId": "sha256(traceId + spanId + route + capturedAt)",
  "traceId": "00-...",
  "capturedAt": "2026-05-28T10:30:00Z",
  "source": { "env": "prod", "service": "messaging-service", "runtime": "cloudflare-worker" },
  "route": { "method": "POST", "pattern": "/messages/{chatId}", "transport": "HTTP" },
  "graph": { "appId": "bestbuds", "nodeId": "ChatInteractor", "community": "chat" },
  "request": {
    "headersAllowlist": { "traceparent": "...", "x-app-build": "..." },
    "bodyRef": "r2://shadow-raw/2026/05/28/body.req.flex",
    "redaction": "policy:user-content-v1"
  },
  "response": {
    "status": 200,
    "bodyRef": "r2://shadow-raw/2026/05/28/body.res.flex",
    "comparator": "json-shape-and-stable-fields"
  },
  "resources": [
    { "type": "supabase", "table": "messages", "keys": ["msg_..."], "mode": "read-write" },
    { "type": "durable-object", "class": "ChatRoom", "idHash": "room_...", "snapshotRef": "r2://..." },
    { "type": "r2", "bucket": "media", "keyHash": "img_...", "transform": "thumbnail-or-placeholder" }
  ],
  "timing": { "durationMs": 84, "dbMs": 22, "workerCpuMs": 8 },
  "classification": { "sample": "rolling", "anomalyScore": 0.12, "retention": "7d" }
}

Capture adapters

SurfaceCapture hookWhat to storeWhat not to store
Cloudflare WorkerstracedHandler() / Service.toHono() wrapperRoute pattern, status, timing, sanitized request/response, binding names, subrequest count, Worker CPU.Raw cookies, auth tokens, full IPs, secret bindings.
Durable ObjectsActor mailbox wrapper plus periodic admin snapshot endpointMessages, alarms, state snapshot refs, storage operation counts, WebSocket events.Unredacted room text or user identity outside policy.
D1Query wrapper around typed D1 bindingParameterized SQL template hash, row keys, changed row ids, timing, error class.SQL with substituted literals, unbounded result sets.
R2Object access wrapperObject key hash, content type, size, transform policy, thumbnail/generated placeholder refs.Original private media unless explicitly approved.
Supabase/PostgresService repository instrumentation plus logical export jobTable row ids, FK closure, query hash, pg_stat statement hash, sanitized row snapshot.Credentials, raw PII, full unrelated tenant tables.
Memgraph on GCP CEGraphDb wrapper plus Cypher export jobTouched nodes/edges, query templates, route/community labels, compact subgraph export.Full graph dump unless needed for a pinned incident.
Server APIsOtelServiceInterceptor plus ShadowServiceInterceptorTyped request/response envelopes, dependency refs, response comparator, graph node attribution.Plaintext secrets, bearer tokens, personal headers.

5. Data plane

The shadow environment needs data closure, not a blind production clone. A captured trace is useful only if the rows, objects, graph nodes, Durable Object state, and feature flags it depends on can be materialized together.

Resource materializers

Production sourceShadow targetMaterialization strategy
Supabase/PostgresShadow Supabase project or Postgres schemaExport rows touched in the rolling window plus FK closure. Tokenize user identity, preserve referential integrity, store base snapshot as immutable schema and developer writes in overlay schema.
Cloudflare D1Shadow D1 database per environmentUse scheduled export/backup and row filters keyed by trace resource refs. Recreate daily; apply pinned capsule migrations on top.
Durable ObjectsShadow DO namespaceAdd explicit snapshot/restore command per DO class. Snapshots write to R2 and restore into a shadow namespace. If a DO cannot snapshot, replay its mailbox log from the capsule.
R2Shadow R2 bucketCopy safe objects, generate placeholders for sensitive media, preserve metadata and object sizes when performance behavior depends on it.
MemgraphShadow Memgraph on GCP CE or local containerCypher export of touched subgraphs plus anomaly subgraphs. Keep tenant labels, replace direct user fields, rebuild indexes before replay.
Workers secrets/configGCP Secret Manager + Wrangler env secretsUse non-prod credentials and provider sandboxes. No production token is captured into shadow.

Base plus overlay

shadow-current-base-2026-05-28
  supabase_base schema       immutable sanitized rows
  d1_base database           immutable export
  r2_base bucket prefix      copied/transformed objects
  memgraph_base              imported subgraph
  do_base snapshots          per-class snapshot refs

shadow-local-ovd
  supabase_overlay schema    developer writes
  d1_overlay database        developer writes
  r2_overlay prefix          new objects
  memgraph_overlay           local changes
  do_overlay namespace       actor state mutations

6. Shadow capsules

A shadow capsule is the unit of replay. It packages traffic, resource closure, expected outcomes, comparators, and retention metadata. Rolling capsules expire quickly. Pinned capsules preserve incidents and weird edge cases.

Capsule taxonomy

ClassTriggerRetentionReplay cadence
RollingRepresentative successful traffic from the latest 7 days, sampled by route/community/user segment.7 days hot, replaced continuously.Local smoke, nightly, selected PRs.
LatencyP95/P99 route spike, slow query, Worker CPU warning, Memgraph slow Cypher.30 days or until budget covered.Performance PRs, nightly load.
Crash5xx, uncaught exception, mobile crash breadcrumb, Durable Object panic, queue DLQ.180 days minimum.Every PR touching the graph community.
AnomalyRare data shape, invalid payload, auth-provider edge case, media object mismatch, graph disconnected component.Until explicitly retired.Community-scoped PR replay.
IncidentHuman-pinned production bug, support ticket, Grafana alert, deploy rollback.Until postmortem action closes.Release gate and regression suite.

Pinning rules

  • Pin any trace with 5xx, timeout, retry exhaustion, DLQ write, crash breadcrumb, auth rejection after valid input, media upload failure, or data-integrity violation.
  • Pin any trace whose latency is above route budget by 2x or is in the top 0.5% for a service.
  • Pin any trace manually linked to a support ticket, incident, customer complaint, or team debugging session.
  • Deduplicate by route + error class + stack fingerprint + graph community + resource shape hash.
  • Retire only after a replay test exists, passes on main for 14 days, and the owning team accepts the removal.

7. Materialization workflow

Materialization converts capture refs into a runnable shadow environment. It should be deterministic, repeatable, and cheap enough to run nightly.

Step 1 - Select window and capsules

Select representative rolling traffic for the latest 7 days, then union pinned capsules relevant to the target environment. Partition by graph community so small PRs do not hydrate the world.

Step 2 - Compute resource closure

For every selected trace, walk resource refs: Supabase rows, D1 rows, Durable Object snapshots, R2 objects, Memgraph nodes/edges, feature flags, and provider stubs. Add parent rows and foreign-key dependencies.

Step 3 - Redact and tokenize

Apply deterministic tokenization for ids and relationship fields, synthetic replacements for direct PII, media transformations, geo bucketing, and header allowlists. Emit a redaction report with rejected fields.

Step 4 - Hydrate targets

Create or reset shadow Supabase/Postgres schema, D1 database, R2 prefixes, DO namespace, Memgraph instance, Workers env bindings, and non-prod secrets. Base is immutable; overlays take writes.

Step 5 - Verify replay

Replay a smoke subset and verify status, schema shape, stable fields, graph side effects, idempotency records, and resource writes. Publish a ShadowManifest artifact.

Developer commands

# Pull the current moving shadow into local config
./shadow env pull rolling-7d

# Boot BestBuds with shadow bindings and disposable overlay
./shadow run local -- ./targets/appServer/dev.sh

# Replay one incident capsule against a local branch
./shadow replay capsule incident-chat-send-timeout-2026-05-21

# Run route-mix load test generated from captured traffic
./shadow load rolling-7d --rate 2x --duration 15m

# Refresh Cloudflare Worker secrets/bindings for shadow env
./shadow sync cloudflare --env shadow-current

8. Replay and testing

Replay has two layers. Keploy-style HTTP replay verifies externally visible API behavior. Reaktor replay verifies the full service graph, including non-HTTP work: Durable Object state transitions, queue messages, Pub/Sub events, R2 writes, Memgraph mutations, and repository side effects.

RunnerInputChecksUsed in
KeployHTTP request/response envelopes generated from ShadowEnvelope.Status, body shape, stable fields, error class, latency baseline.PR API regression.
Reaktor service replayTyped ServiceRequest plus dependency capsule.Handler output, repository reads/writes, idempotency, telemetry spans, graph node attribution.Local, CI, workbench.
Durable Object replayMailbox log or object snapshot plus messages.State transition, alarms, WebSocket fanout, storage ops.Chat/realtime regressions.
k6/GatlingRoute mix, payload sizes, concurrency, think time from rolling traffic.Throughput, P95/P99, error rate, resource saturation.Nightly and release gates.
Playwright/MaestroUser journeys bound to shadow accounts and graph routes.Crash-free UI, route state, visual snapshots, accessibility, app vitals.Feature PRs and smoke tests.

Response comparison policy

  • Strict: deterministic internal service outputs, schema migrations, idempotency records, auth decisions.
  • Shape plus stable fields: API responses with generated ids, timestamps, signed URLs, pagination cursors.
  • Statistical: load-test latency, fanout count, retry distribution, Worker CPU, Memgraph query timing.
  • Side-effect: R2 object created, D1 row inserted, DO state changed, notification attempt classified.

9. Workbench integration

The Reaktor workbench should make the shadow environment visible and usable. It should not only show dashboards; it should let developers select a graph community, inspect captured traces, hydrate a shadow dataset, replay a capsule, and see the exact graph nodes and resources involved.

Workbench surfaceShadow feature
Run AppLaunch BestBuds against shadow-current, selected pinned capsule, or a PR overlay.
GraphColor nodes by captured traffic volume, replay failures, latency deltas, and pinned anomalies.
DatabaseBrowse only shadow Supabase/D1/R2/Memgraph/DO data, with redaction badges and source trace refs.
TestsShow capsules as test inventory: rolling, latency, crash, anomaly, incident. Run scoped replay from UI.
InsightsDisplay route mix, drift from production, anomaly fingerprints, and replay history.
DeployBlock release until impacted shadow capsules pass and latency drift is within budget.

10. Security and governance

Redaction contract

Data classShadow handling
User identityDeterministic pseudonymous ids; optional test-user mapping for login flows. No prod auth tokens.
Email, phone, display nameSynthetic replacements with stable shape and locale where needed.
Free text messagesPolicy decision: redact by default, preserve only approved bug capsules with irreversible tokenization.
MediaGenerated placeholder, blurred thumbnail, or synthetic object with same size/content type.
LocationCoarse geohash or region bucket; never exact coordinates unless generated.
Secrets and headersAllowlist trace/build/debug headers only. Everything else dropped or hashed.
Deletion requestsDelete from rolling store and pinned capsules unless a legal hold exists; maintain tombstone index.

Access model

  • Developers get read access to shadow data and write access only to their overlays.
  • Production capture service has write-only access to raw shadow lake and no read access to developer overlays.
  • Materializers run as service principals with explicit scopes for Supabase export, D1 export, R2 copy, DO snapshot, and Memgraph export.
  • Every capsule read, hydrate, replay, and export emits an audit record.
  • All shadow secrets live in GCP Secret Manager and are synced to Cloudflare Worker shadow environments as non-prod secrets.

11. Rollout plan

Phase 0 - Policy and schemas

Define ShadowEnvelope, ShadowResourceRef, ShadowCapsule, redaction policies, retention classes, access roles, and comparator types.

Phase 1 - Service capture

Add ShadowServiceInterceptor to server APIs and Worker service wrappers. Capture route pattern, request/response shape, timing, graph node id, and resource refs.

Phase 2 - Shadow lake and catalog

Write raw sanitized bodies to R2, index envelopes in D1/Postgres, expose catalog queries by time, route, service, graph community, and anomaly fingerprint.

Phase 3 - Data materializers

Implement Supabase row closure, D1 snapshot import, R2 copy/transform, Durable Object snapshot/restore, and Memgraph subgraph export/import.

Phase 4 - Replay runners

Build Reaktor replay runner, Keploy adapter, k6 generator, response comparators, side-effect checkers, and report artifacts.

Phase 5 - Dev and CI integration

Add ./shadow CLI, PR overlays, GitHub Actions workflow, workbench panels, and release gates.

12. Risks and mitigations

RiskMitigation
PII leaks into devFail-closed redaction policy, field classifiers, denylisted headers, automated scans before materialization, audit logs for capsule access.
Shadow accidentally writes to productionSeparate credentials, separate Cloudflare envs, separate Supabase/D1/R2/DO/Memgraph targets, network egress guardrails, write-block tests.
Durable Object state is not enumerableAdd explicit snapshot endpoints and mailbox logging per DO class; use replay from mailbox when snapshots are unavailable.
Dataset becomes too expensiveRolling 7-day default, sampled success traffic, pinned anomaly dedupe, R2 lifecycle rules, materialize by graph community.
Replay is nondeterministicFreeze clocks, stub third-party providers, compare allowed drift, seed ids, preserve idempotency keys, record dependency responses.
Schema drift breaks old capsulesVersion every envelope and capsule, run migration adapters, mark un-migratable capsules as archived but inspectable.
Developers distrust the environmentPublish freshness, source traffic window, replay pass rate, redaction report, and drift score in the workbench.

Open decisions

  • Whether the shadow catalog index lives in D1, Postgres, or both.
  • How much free-text chat content can be safely preserved after tokenization.
  • Whether every PR gets a full overlay or only graph-community overlays.
  • Whether Memgraph shadow runs on the existing GCP CE host, a second CE host, or local containers for developer mode.
  • Whether Keploy is embedded as the HTTP runner only, or exposed directly to developers as a first-class tool.
  • Shadow Dev - Use before building production-like test and replay environments.
  • Claude Dev Env - Use only when comparing prior shadow environment proposals.
  • Perf and Observability - Use before optimizing or adding instrumentation.
  • Reaktor Secrets - Use before moving, rotating, distributing, caching, or materializing secrets.
  • DevOps - Use before changing the build/deploy/ops pipeline, the Kotlin platform model, deployment partitioning, gated deploy operations, or the reaktorDesktop Deploy pane; pairs with reaktor-cloud-pane (operator view) and secrets-management.
  • FlexBuffer Plan - Use for history only; prefer the FlexBuffer Binary Serialization document.