Skip to content

fix(content): move Option-B fast-path flags from env vars to DB config (ImsConfig) - #2061

Merged
jung-thomas merged 1 commit into
DEVfrom
feat/content-delta-flags-db-config
Aug 28, 2026
Merged

jung-thomas merged 1 commit into
DEVfrom
feat/content-delta-flags-db-config

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Why

The three Option-B content fast-path flags — CONTENT_DELTA_WRITE_ENABLED, CONTENT_DELTA_READ_ENABLED, CONTENT_DELTA_SKIP_CARRYFORWARD — were read directly from process.env (16 sites) and declared kind:'env' in the feature-flag registry. Env flags are set via cf set-env and silently dropped on every blue-green MTA deploy (new -idle apps start from the descriptor, not the old app's runtime env), which reverted the PROD fast path during the 1.20.0 deploy and forced a manual multi-step re-activation. Feature flags must be DB-configurable (standing rule; matches ngds-autosend).

What

Move the three flags to the ImsConfig key/value table, read through a cached, fail-safe resolver. All process.env.CONTENT_DELTA_* reads removed — no env fallback. They're now data, so they survive every deploy.

  • New srv/lib/content-delta-flags.js — mirrors the ngds-autosend.js cached-DB-flag pattern. One warm cache (all 3 keys in a single SELECT), 60s TTL. Synchronous getters isDeltaWrite()/isDeltaRead()/isDeltaSkipCarryForward() return the last-known boolean immediately and kick off a non-blocking background refresh when stale — never block, never throw. Fail-safe default false (legacy path) so a cold cache or DB error never silently enables delta reads/writes. refreshContentDeltaFlags() (fail-safe) + bustContentDeltaFlagsCache(). Keys: content.delta.write, content.delta.read, content.delta.skipCarryForward.
  • srv/server.js — warms the cache in the served bootstrap (fail-open).
  • 16 call sites across content-store.js, content-publish-session.js, chrome-shell.js, admin-service.js, jobs/{cleanup,embedding-reconciliation}.js, embedding-pipeline.js, embedding-stats.js — exact boolean semantics preserved (incl. the !== 'true' → !isDeltaSkipCarryForward() inversion in the publish carry-forward gate).
  • registry.js — the 3 entries flipped kind:'env' → new kind:'db' (ImsConfig-backed; resolve.js resolves it live); env fields dropped.
  • Admin toggle — AdminService.setContentDeltaFlags(write, read, skipCarryForward) (per-flag upsert, busts cache) + getContentDeltaFlags(), @requires: 'Admin' (same as the NGDS kill-switch).
  • srv-qa cp-list — content-delta-flags.js added to .deploy/mta.yaml tutorials-srv-qa (transitive dep of content-store.js et al.).
  • Tests — new test/unit/content-delta-flags.test.js (defaults, read, TTL cache, bust, DB-error fail-safe); the 3 existing env-driven delta tests converted to seed ImsConfig. Verified: cds compile clean, grep process.env.CONTENT_DELTA_ srv/ empty, 18 delta tests + adjacent suites green.

Rollout after merge/deploy

  1. Deploy this to each env.
  2. Set the DB values once (admin action or ImsConfig upsert) — they persist across deploys.
  3. Remove the temporary cf set-env CONTENT_DELTA_* vars currently on PROD tutorials-srv/tutorials-srv-qa (the stopgap that restored the fast path tonight) so DB is the single source of truth.

Notes

  • Follow-up issue Migrate remaining kind:'env' feature flags to DB config (ImsConfig) #2060 tracks migrating the remaining ~14 kind:'env' registry flags the same way.
  • Minor: the admin action busts the cache but doesn't warm-refresh, so a just-toggled flag reads its fail-safe default for up to ~1s until the background refresh lands (safe: falls back to legacy, never errors). Can add an await refreshContentDeltaFlags() if we want instant toggle effect.

…nfig

Move the three Content Option-B feature flags (CONTENT_DELTA_WRITE_ENABLED,
CONTENT_DELTA_READ_ENABLED, CONTENT_DELTA_SKIP_CARRYFORWARD) off process.env
onto ImsConfig key/value rows (content.delta.write / .read / .skipCarryForward),
read through a new cached, fail-safe resolver.

- srv/lib/content-delta-flags.js: 60s-TTL warm cache (mirrors ngds-autosend),
  synchronous fail-open getters isDeltaWrite/Read/SkipCarryForward (default
  false, never block/throw on the hot path), async refreshContentDeltaFlags()
  plus bustContentDeltaFlagsCache().
- Warm on boot in srv/server.js (fail-open).
- Replace all process.env.CONTENT_DELTA_* reads across content-store,
  content-publish-session, chrome-shell, admin-service, jobs/cleanup,
  jobs/embedding-reconciliation, embedding-pipeline, embedding-stats.
- registry.js: add kind:'db' (ImsConfig-backed); resolve.js resolves it live.
- AdminService.setContentDeltaFlags / getContentDeltaFlags actions (busts cache).
- srv-qa cp list: add srv/lib/content-delta-flags.js.
- Tests: new content-delta-flags.test.js; convert env-setting delta tests to
  seed ImsConfig plus warm cache.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant