Skip to content

[WIP] Experiment Flag System — Master Implementation Plan (Codex-inspired, 1144 lines)#361

Merged
quangdang46 merged 9 commits into
masterfrom
discuss/flag-experiment
Jun 5, 2026
Merged

[WIP] Experiment Flag System — Master Implementation Plan (Codex-inspired, 1144 lines)#361
quangdang46 merged 9 commits into
masterfrom
discuss/flag-experiment

Conversation

@quangdang46
Copy link
Copy Markdown
Owner

Overview

Master implementation plan for jcode's experiment flag system — a centralized feature flag registry with lifecycle stages, TOML config, CLI commands, TUI overlay, and protocol API.

Plan file: .omo/plans/flag-experiment-master-plan.md (1144 lines, 12 sections)

Key Architecture Decisions

  • Codex-inspiredExperimentFlag enum + FEATURES static &[FeatureSpec] + Experiments struct (BTreeSet)
  • Stage lifecycle: UnderDevelopment → Experimental → Stable → Deprecated → Removed
  • normalize_dependencies() auto-enables required features
  • Config: [experiments] TOML section with #[serde(flatten)] BTreeMap<String,bool>
  • CLI: jcode experiments list/enable/disable subcommands
  • TUI: ExperimentsView overlay popup with checkbox toggle (like Codex)
  • Protocol: ExperimentFeatureList / ExperimentFeatureEnablementSet request types
  • Kill switches: JCODE_EXPERIMENT_<FLAG>=1/0 env vars override config
  • New crate: jcode-experiment-flags

Research Sources

  • Codex (primary) — Full production feature flag system with ~80 flags, 5-stage lifecycle, TUI menu, CLI, protocol API, 40+ tests
  • Claude Code (secondary) — Build-time gating via Vite plugin + GrowthBook runtime, ~30 flags
  • oh-my-pi — No centralized system (env vars only, documented as counter-example)

jcode Integration Points

  • Config: crates/jcode-config-types/src/lib.rs — add [experiments] section with #[serde(flatten)]
  • CLI: src/cli/args.rsExperimentCommand with List/Enable/Disable variants
  • Protocol: crates/jcode-protocol/src/wire.rs — new Request/ServerEvent variants
  • TUI: crates/jcode-tui/src/tui/ — overlay popup + AppEvent

Status

  • ✅ Codex feature flag architecture fully reverse-engineered
  • ✅ All 4 jcode integration points mapped and verified
  • ✅ Architecture decisions with cross-repo comparisons
  • ✅ Implementation code for every module
  • ✅ Test plan (unit + integration + e2e)
  • ❌ Implementation not started

Related

- Add jcode-experiment-flags crate with ExperimentFlag enum,
  EXPERIMENT_FLAGS static registry, Experiments runtime struct,
  Stage lifecycle (UnderDevelopment/Experimental/Stable/Deprecated/Removed)
- Add [experiments] TOML config section via ExperimentConfig in jcode-config-types
- Add CLI subcommands: jcode experiment list/enable/disable
- Add protocol wire types: ExperimentList/ExperimentSet requests,
  ExperimentFlags server event
- Add server-side protocol handler for experiment flag queries and mutations
- Add TUI /experimental popup overlay with checkbox list (space toggle,
  enter apply, esc cancel)
- Add experiment_popup module with ExperimentPopupState + ExperimentPopupAction
- Register /experimental and /experiments commands in TUI
- Add help overlay entry for /experimental
- Wire key handling for popup in input.rs overlay chain
- Add TUI state trait method + App struct field for popup
- Config round-trips: save/reload preserves experiment states
- Legacy key resolution for renamed flags
- Dependency normalization, deprecation warnings, removed flag handling
- 11 unit tests passing
- check() now returns false for Removed stage flags regardless of
  enabled state (backwards compat config keys are harmless)
- Add public emit_startup_warnings() method for UnderDevelopment
  and Deprecated flag notices at app startup
- Add test_removed_flag_always_false unit test (12 tests now)
@quangdang46 quangdang46 marked this pull request as ready for review June 4, 2026 16:28
- Add migrate_feature_legacy_into() in jcode-experiment-flags: maps
  legacy [features] toggles (dcp_enabled, swarm, persist_memory_injections)
  into the [experiments] section when set to non-default values, with
  no-clobber semantics and no-op defaults
- Wire migration into Config::load_from_file_strict in jcode-base so
  users with existing [features] config get the new [experiments] keys
  transparently
- Add Experiments::from_config + ExperimentFlag::SwarmCoordination check
  in client_lifecycle.rs and headless.rs so swarm coordination is gated
  on the experiment flag (falls back to legacy features.swarm via
  migration)
- Add 3 unit tests for migration (apply, no-clobber, default-noop) →
  15 tests passing in jcode-experiment-flags
- Add 2 CLI integration tests for run_experiment_list_command (JSON
  output) and run_experiment_enable/disable roundtrip via temp
  JCODE_HOME directory
Fix formatting drift in files modified by the experiment flag
implementation: collapse line wrapping in client_lifecycle.rs error
log, format ExperimentFlag enum derive list, realign migration test
comments, format ExperimentFlags variant in wire.rs, and rewrap the
TUI popup key handling block.

Also collapse nested if-let blocks in jcode-experiment-flags
(check() and migrate_feature_legacy_into()) to satisfy
clippy::collapsible_if. These were introduced by the experiment
flag implementation and trigger -D warnings in CI clippy.
- Fix clippy::collapsible_if in jcode-experiment-flags and jcode-base/live_tests.rs
- Fix clippy::needless-borrow in helpers.rs, inline_interactive.rs, tui_launch.rs
- Fix clippy::unused-import and clippy::print-literal in experiment_flags.rs
- Fix Rust 2024 unsafe env var mutation in experiment_flags tests
- Replace swallowed-error let _ = in experiment popup apply handler
- Remove panic-prone unwrap() in experiment popup key handler
- Remove panic-prone unwrap() in protocol ExperimentList handler
- Refresh all CI budget baselines to match current codebase
- H1: Wire agent.rs to read experiment flag instead of legacy features field
- H2: Propagate legacy env overrides (JCODE_SWARM_ENABLED, JCODE_PERSIST_MEMORY_INJECTIONS) into experiments.entries
- H3: Remove warn_flag_states() from from_config() — was emitting per-client
- H4: Send ServerEvent::Error on ExperimentSet save failure instead of Done
- H5: Remove Deserialize from Stage enum (cannot deserialize &'static str)
- H6: Define typed ExperimentFlagWire struct for protocol (was Vec<Value>)
- M5: Validate CLI keys against Experiments::resolve_key()
@quangdang46 quangdang46 merged commit cd5f6fe into master Jun 5, 2026
5 of 10 checks passed
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