Skip to content

Core: generic per-feature config-as-code resolver #4094

Description

@JSONbored

Part of #4092.

Motivation

Every sub-issue under #4092 needs the same 3-state gating logic: config true ⇒ feature ON regardless of the env-var+allowlist gate; config false ⇒ feature OFF regardless of it; config unset/null ⇒ defer to today's envFlag && isConvergenceRepoAllowed(env, repo) gate (byte-identical default). Building this ONCE as a shared, reusable helper avoids 10+ near-identical bespoke implementations and keeps the semantics consistent across every feature.

review.visual.enabled (#4083) already implements this exact 3-state shape, but inline in src/queue/processors.ts rather than as a reusable helper — it was scoped narrowly on purpose. This issue generalizes it.

Requirements

  • A small, pure, unit-testable helper (e.g. in src/review/cutover-gate.ts alongside isConvergenceRepoAllowed, or its own module) with a signature roughly like resolveConvergedFeature(configValue: boolean | null, envFlag: boolean, repoAllowed: boolean): boolean implementing the 3-state precedence above.
  • Decide the NAMESPACING question explicitly (this is the one design decision every other sub-issue depends on): extend CONVERGED_FEATURE_KEYS/FocusManifestFeaturesConfig (packages/gittensory-engine/src/focus-manifest.ts:176-182) — which already models rag/reputation/unifiedComment/safety as a boolean-or-null record — to be the ONE shared home for every simple on/off feature toggle (grounding, impactMap, cultureProfile, reviewMemory, selftune, parityAudit, inlineComments, fixHandoff, etc.), OR give each feature its own review.<feature>.enabled key mirroring visual's shape. Recommendation: extend features: for simple booleans (reuses an existing, already-parsed schema surface instead of adding N new ones); keep review.visual.enabled and contentLane in their own richer namespaces since they carry more than a single boolean.
  • Write the resolver's own unit tests covering all 9 combinations of {config: true/false/null} × {envFlag: true/false} × {repoAllowed: true/false}.
  • Do NOT wire it into any specific feature in this PR — that's each subsequent sub-issue's job. This issue ships the shared primitive only.

Deliverables

  • The shared resolver function + its unit tests
  • A written decision (in the PR description, doesn't need new code) on the namespacing question above, since every downstream sub-issue depends on it
  • If extending features:: the CONVERGED_FEATURE_KEYS array and FocusManifestFeaturesConfig type, parse/overlay/present/serialize updated to accept the new keys (mirroring parseVisualConfig's pattern)

Expected outcome

A single, tested primitive every other sub-issue under #4092 imports instead of reimplementing.

Effort

S — a small pure function plus a config-schema extension decision. No feature migration yet.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions