@exaudeus/workrail 3.28.0 → 3.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/console/assets/{index-C146q2kN.js → index-BZ6HkxGf.js} +1 -1
- package/dist/console/index.html +1 -1
- package/dist/manifest.json +3 -3
- package/docs/README.md +57 -0
- package/docs/adrs/001-hybrid-storage-backend.md +38 -0
- package/docs/adrs/002-four-layer-context-classification.md +38 -0
- package/docs/adrs/003-checkpoint-trigger-strategy.md +35 -0
- package/docs/adrs/004-opt-in-encryption-strategy.md +36 -0
- package/docs/adrs/005-agent-first-workflow-execution-tokens.md +105 -0
- package/docs/adrs/006-append-only-session-run-event-log.md +76 -0
- package/docs/adrs/007-resume-and-checkpoint-only-sessions.md +51 -0
- package/docs/adrs/008-blocked-nodes-architectural-upgrade.md +178 -0
- package/docs/adrs/009-bridge-mode-single-instance-mcp.md +195 -0
- package/docs/adrs/010-release-pipeline.md +89 -0
- package/docs/architecture/README.md +7 -0
- package/docs/architecture/refactor-audit.md +364 -0
- package/docs/authoring-v2.md +527 -0
- package/docs/authoring.md +873 -0
- package/docs/changelog-recent.md +201 -0
- package/docs/configuration.md +505 -0
- package/docs/ctc-mcp-proposal.md +518 -0
- package/docs/design/README.md +22 -0
- package/docs/design/agent-cascade-protocol.md +96 -0
- package/docs/design/autonomous-console-design-candidates.md +253 -0
- package/docs/design/autonomous-console-design-review.md +111 -0
- package/docs/design/autonomous-platform-mvp-discovery.md +525 -0
- package/docs/design/claude-code-source-deep-dive.md +713 -0
- package/docs/design/console-cyberpunk-ui-discovery.md +504 -0
- package/docs/design/console-execution-trace-candidates-final.md +160 -0
- package/docs/design/console-execution-trace-candidates.md +211 -0
- package/docs/design/console-execution-trace-design-candidates-v2.md +113 -0
- package/docs/design/console-execution-trace-design-review.md +74 -0
- package/docs/design/console-execution-trace-discovery.md +394 -0
- package/docs/design/console-execution-trace-final-review.md +77 -0
- package/docs/design/console-execution-trace-review.md +92 -0
- package/docs/design/console-performance-discovery.md +415 -0
- package/docs/design/console-ui-backlog.md +280 -0
- package/docs/design/daemon-architecture-discovery.md +853 -0
- package/docs/design/daemon-design-candidates.md +318 -0
- package/docs/design/daemon-design-review-findings.md +119 -0
- package/docs/design/daemon-engine-design-candidates.md +210 -0
- package/docs/design/daemon-engine-design-review.md +131 -0
- package/docs/design/daemon-execution-engine-discovery.md +280 -0
- package/docs/design/daemon-gap-analysis.md +554 -0
- package/docs/design/daemon-owns-console-plan.md +168 -0
- package/docs/design/daemon-owns-console-review.md +91 -0
- package/docs/design/daemon-owns-console.md +195 -0
- package/docs/design/data-model-erd.md +11 -0
- package/docs/design/design-candidates-consolidate-dev-staleness.md +98 -0
- package/docs/design/design-candidates-walk-cache-depth-limit.md +80 -0
- package/docs/design/design-review-consolidate-dev-staleness.md +54 -0
- package/docs/design/design-review-walk-cache-depth-limit.md +48 -0
- package/docs/design/implementation-plan-consolidate-dev-staleness.md +142 -0
- package/docs/design/implementation-plan-walk-cache-depth-limit.md +141 -0
- package/docs/design/layer3b-ghost-nodes-design-candidates.md +229 -0
- package/docs/design/layer3b-ghost-nodes-design-review.md +93 -0
- package/docs/design/layer3b-ghost-nodes-implementation-plan.md +219 -0
- package/docs/design/list-workflows-latency-fix-plan.md +128 -0
- package/docs/design/list-workflows-latency-fix-review.md +55 -0
- package/docs/design/list-workflows-latency-fix.md +109 -0
- package/docs/design/native-context-management-api.md +11 -0
- package/docs/design/performance-sweep-2026-04.md +96 -0
- package/docs/design/routines-guide.md +219 -0
- package/docs/design/sequence-diagrams.md +11 -0
- package/docs/design/subagent-design-principles.md +220 -0
- package/docs/design/temporal-patterns-design-candidates.md +312 -0
- package/docs/design/temporal-patterns-design-review-findings.md +163 -0
- package/docs/design/test-isolation-from-config-file.md +335 -0
- package/docs/design/v2-core-design-locks.md +2746 -0
- package/docs/design/v2-lock-registry.json +734 -0
- package/docs/design/workflow-authoring-v2.md +1044 -0
- package/docs/design/workflow-docs-spec.md +218 -0
- package/docs/design/workflow-extension-points.md +687 -0
- package/docs/design/workrail-auto-trigger-system.md +359 -0
- package/docs/design/workrail-config-file-discovery.md +513 -0
- package/docs/docker.md +110 -0
- package/docs/generated/v2-lock-closure-plan.md +26 -0
- package/docs/generated/v2-lock-coverage.json +797 -0
- package/docs/generated/v2-lock-coverage.md +177 -0
- package/docs/ideas/backlog.md +3927 -0
- package/docs/ideas/design-candidates-mcp-resilience.md +208 -0
- package/docs/ideas/design-review-findings-mcp-resilience.md +119 -0
- package/docs/ideas/implementation_plan.md +249 -0
- package/docs/ideas/third-party-workflow-setup-design-thinking.md +1948 -0
- package/docs/implementation/02-architecture.md +316 -0
- package/docs/implementation/04-testing-strategy.md +124 -0
- package/docs/implementation/09-simple-workflow-guide.md +835 -0
- package/docs/implementation/13-advanced-validation-guide.md +874 -0
- package/docs/implementation/README.md +21 -0
- package/docs/integrations/claude-code.md +300 -0
- package/docs/integrations/firebender.md +315 -0
- package/docs/migration/v0.1.0.md +147 -0
- package/docs/naming-conventions.md +45 -0
- package/docs/planning/README.md +104 -0
- package/docs/planning/github-ticketing-playbook.md +195 -0
- package/docs/plans/README.md +24 -0
- package/docs/plans/agent-managed-ticketing-design.md +605 -0
- package/docs/plans/agentic-orchestration-roadmap.md +112 -0
- package/docs/plans/assessment-gates-engine-handoff.md +536 -0
- package/docs/plans/content-coherence-and-references.md +151 -0
- package/docs/plans/library-extraction-plan.md +340 -0
- package/docs/plans/mr-review-workflow-redesign.md +1451 -0
- package/docs/plans/native-context-management-epic.md +11 -0
- package/docs/plans/perf-fixes-design-candidates.md +225 -0
- package/docs/plans/perf-fixes-design-review-findings.md +61 -0
- package/docs/plans/perf-fixes-new-issues-candidates.md +264 -0
- package/docs/plans/perf-fixes-new-issues-review.md +110 -0
- package/docs/plans/prompt-fragments.md +53 -0
- package/docs/plans/ui-ux-workflow-design-candidates.md +120 -0
- package/docs/plans/ui-ux-workflow-discovery.md +100 -0
- package/docs/plans/ui-ux-workflow-review.md +48 -0
- package/docs/plans/v2-followup-enhancements.md +587 -0
- package/docs/plans/workflow-categories-candidates.md +105 -0
- package/docs/plans/workflow-categories-discovery.md +110 -0
- package/docs/plans/workflow-categories-review.md +51 -0
- package/docs/plans/workflow-discovery-model-candidates.md +94 -0
- package/docs/plans/workflow-discovery-model-discovery.md +74 -0
- package/docs/plans/workflow-discovery-model-review.md +48 -0
- package/docs/plans/workflow-source-setup-phase-1.md +245 -0
- package/docs/plans/workflow-source-setup-phase-2.md +361 -0
- package/docs/plans/workflow-staleness-detection-candidates.md +104 -0
- package/docs/plans/workflow-staleness-detection-review.md +58 -0
- package/docs/plans/workflow-staleness-detection.md +80 -0
- package/docs/plans/workflow-v2-design.md +69 -0
- package/docs/plans/workflow-v2-roadmap.md +74 -0
- package/docs/plans/workflow-validation-design.md +98 -0
- package/docs/plans/workflow-validation-roadmap.md +108 -0
- package/docs/plans/workrail-platform-vision.md +420 -0
- package/docs/reference/agent-context-cleaner-snippet.md +94 -0
- package/docs/reference/agent-context-guidance.md +140 -0
- package/docs/reference/context-optimization.md +284 -0
- package/docs/reference/example-workflow-repository-template/.github/workflows/validate.yml +125 -0
- package/docs/reference/example-workflow-repository-template/README.md +268 -0
- package/docs/reference/example-workflow-repository-template/workflows/example-workflow.json +80 -0
- package/docs/reference/external-workflow-repositories.md +916 -0
- package/docs/reference/feature-flags-architecture.md +472 -0
- package/docs/reference/feature-flags.md +349 -0
- package/docs/reference/god-tier-workflow-validation.md +272 -0
- package/docs/reference/loop-optimization.md +209 -0
- package/docs/reference/loop-validation.md +176 -0
- package/docs/reference/loops.md +465 -0
- package/docs/reference/mcp-platform-constraints.md +59 -0
- package/docs/reference/recovery.md +88 -0
- package/docs/reference/releases.md +177 -0
- package/docs/reference/troubleshooting.md +105 -0
- package/docs/reference/workflow-execution-contract.md +998 -0
- package/docs/roadmap/README.md +22 -0
- package/docs/roadmap/legacy-planning-status.md +103 -0
- package/docs/roadmap/now-next-later.md +70 -0
- package/docs/roadmap/open-work-inventory.md +389 -0
- package/docs/tickets/README.md +39 -0
- package/docs/tickets/next-up.md +76 -0
- package/docs/workflow-management.md +317 -0
- package/docs/workflow-templates.md +423 -0
- package/docs/workflow-validation.md +184 -0
- package/docs/workflows.md +254 -0
- package/package.json +3 -1
- package/spec/authoring-spec.json +61 -16
- package/workflows/workflow-for-workflows.json +3 -3
- package/workflows/workflow-for-workflows.v2.json +3 -3
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# Feature Flags Architecture
|
|
2
|
+
|
|
3
|
+
## System Overview
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
7
|
+
│ ENVIRONMENT VARIABLES │
|
|
8
|
+
│ │
|
|
9
|
+
│ WORKRAIL_ENABLE_SESSION_TOOLS=true │
|
|
10
|
+
│ WORKRAIL_ENABLE_EXPERIMENTAL_WORKFLOWS=false │
|
|
11
|
+
│ WORKRAIL_VERBOSE_LOGGING=false │
|
|
12
|
+
└────────────────────────┬────────────────────────────────────────┘
|
|
13
|
+
│
|
|
14
|
+
│ reads at startup
|
|
15
|
+
▼
|
|
16
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ EnvironmentFeatureFlagProvider │
|
|
18
|
+
│ │
|
|
19
|
+
│ • Parses environment variables │
|
|
20
|
+
│ • Validates boolean values │
|
|
21
|
+
│ • Creates immutable flag map │
|
|
22
|
+
│ • Logs enabled experimental features │
|
|
23
|
+
└────────────────────────┬────────────────────────────────────────┘
|
|
24
|
+
│
|
|
25
|
+
│ implements
|
|
26
|
+
▼
|
|
27
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ IFeatureFlagProvider (Interface) │
|
|
29
|
+
│ │
|
|
30
|
+
│ isEnabled(key: FeatureFlagKey): boolean │
|
|
31
|
+
│ getAll(): FeatureFlags │
|
|
32
|
+
│ getSummary(): string │
|
|
33
|
+
└────────────────────────┬────────────────────────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
│ injected into
|
|
36
|
+
▼
|
|
37
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
38
|
+
│ Application Container │
|
|
39
|
+
│ (Dependency Injection) │
|
|
40
|
+
│ │
|
|
41
|
+
│ { │
|
|
42
|
+
│ featureFlags: IFeatureFlagProvider, │
|
|
43
|
+
│ storage: IWorkflowStorage, │
|
|
44
|
+
│ workflowService: WorkflowService, │
|
|
45
|
+
│ validationEngine: ValidationEngine, │
|
|
46
|
+
│ ... │
|
|
47
|
+
│ } │
|
|
48
|
+
└────────────────────────┬────────────────────────────────────────┘
|
|
49
|
+
│
|
|
50
|
+
│ provides to
|
|
51
|
+
▼
|
|
52
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
53
|
+
│ WorkflowOrchestrationServer │
|
|
54
|
+
│ │
|
|
55
|
+
│ constructor(container?: AppContainer) { │
|
|
56
|
+
│ this.featureFlags = container.featureFlags; │
|
|
57
|
+
│ │
|
|
58
|
+
│ if (this.featureFlags.isEnabled('sessionTools')) { │
|
|
59
|
+
│ // Initialize session tools │
|
|
60
|
+
│ this.sessionTools = createSessionTools(...); │
|
|
61
|
+
│ } else { │
|
|
62
|
+
│ this.sessionTools = []; │
|
|
63
|
+
│ } │
|
|
64
|
+
│ } │
|
|
65
|
+
└────────────────────────┬────────────────────────────────────────┘
|
|
66
|
+
│
|
|
67
|
+
│ registers
|
|
68
|
+
▼
|
|
69
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
70
|
+
│ MCP Tools │
|
|
71
|
+
│ │
|
|
72
|
+
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
|
|
73
|
+
│ │ Core Tools │ │ Conditional Tools │ │
|
|
74
|
+
│ │ (always enabled) │ │ (feature flag gated) │ │
|
|
75
|
+
│ ├─────────────────────┤ ├────────────────────────────┤ │
|
|
76
|
+
│ │ • workflow_list │ │ • workrail_create_session │ │
|
|
77
|
+
│ │ • workflow_get │ │ • workrail_update_session │ │
|
|
78
|
+
│ │ • workflow_next │ │ • workrail_read_session │ │
|
|
79
|
+
│ │ • workflow_validate │ │ • workrail_open_dashboard │ │
|
|
80
|
+
│ └─────────────────────┘ └────────────────────────────┘ │
|
|
81
|
+
│ │
|
|
82
|
+
│ Tools are only registered if feature flag is enabled │
|
|
83
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Data Flow: Feature Check
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
Agent calls tool
|
|
90
|
+
│
|
|
91
|
+
▼
|
|
92
|
+
MCP Server receives request
|
|
93
|
+
│
|
|
94
|
+
▼
|
|
95
|
+
Is tool name "workrail_*"?
|
|
96
|
+
│
|
|
97
|
+
├─── No ──► Route to workflow tools
|
|
98
|
+
│
|
|
99
|
+
└─── Yes ─► Check feature flag
|
|
100
|
+
│
|
|
101
|
+
▼
|
|
102
|
+
featureFlags.isEnabled('sessionTools')?
|
|
103
|
+
│
|
|
104
|
+
├─── true ──► Execute session tool
|
|
105
|
+
│ Return result
|
|
106
|
+
│
|
|
107
|
+
└─── false ─► Return error
|
|
108
|
+
"Session tools not enabled.
|
|
109
|
+
Set WORKRAIL_ENABLE_SESSION_TOOLS=true"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Testing Flow: Dependency Injection
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
116
|
+
│ PRODUCTION │
|
|
117
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
118
|
+
│ │
|
|
119
|
+
│ const container = createAppContainer(); │
|
|
120
|
+
│ // Uses EnvironmentFeatureFlagProvider │
|
|
121
|
+
│ // Reads from process.env │
|
|
122
|
+
│ │
|
|
123
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
124
|
+
|
|
125
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
126
|
+
│ TESTING │
|
|
127
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
128
|
+
│ │
|
|
129
|
+
│ const testFlags = new StaticFeatureFlagProvider({ │
|
|
130
|
+
│ sessionTools: true, // ← Explicit test values │
|
|
131
|
+
│ experimentalWorkflows: false, │
|
|
132
|
+
│ }); │
|
|
133
|
+
│ │
|
|
134
|
+
│ const container = createAppContainer({ │
|
|
135
|
+
│ featureFlags: testFlags, // ← Inject test provider │
|
|
136
|
+
│ }); │
|
|
137
|
+
│ │
|
|
138
|
+
│ // Tests run with known, predictable flag values │
|
|
139
|
+
│ // No environment manipulation needed │
|
|
140
|
+
│ // Fast, isolated, deterministic │
|
|
141
|
+
│ │
|
|
142
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Class Diagram
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
┌──────────────────────────────────────────────────────┐
|
|
149
|
+
│ <<interface>> │
|
|
150
|
+
│ IFeatureFlagProvider │
|
|
151
|
+
├──────────────────────────────────────────────────────┤
|
|
152
|
+
│ + isEnabled(key: FeatureFlagKey): boolean │
|
|
153
|
+
│ + getAll(): FeatureFlags │
|
|
154
|
+
│ + getSummary(): string │
|
|
155
|
+
└─────────────────┬────────────────────────────────────┘
|
|
156
|
+
│
|
|
157
|
+
│ implements
|
|
158
|
+
┏━━━━━━━━━━┻━━━━━━━━━━┓
|
|
159
|
+
▼ ▼
|
|
160
|
+
┌──────────────────┐ ┌────────────────────┐
|
|
161
|
+
│ Environment │ │ Static │
|
|
162
|
+
│ FeatureFlag │ │ FeatureFlag │
|
|
163
|
+
│ Provider │ │ Provider │
|
|
164
|
+
├──────────────────┤ ├────────────────────┤
|
|
165
|
+
│ - flags: Map │ │ - flags: Map │
|
|
166
|
+
├──────────────────┤ ├────────────────────┤
|
|
167
|
+
│ Production use │ │ Testing use │
|
|
168
|
+
│ Reads env vars │ │ Explicit values │
|
|
169
|
+
│ At startup │ │ No I/O │
|
|
170
|
+
└──────────────────┘ └────────────────────┘
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Lifecycle
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
177
|
+
│ APPLICATION STARTUP │
|
|
178
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
179
|
+
│
|
|
180
|
+
▼
|
|
181
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
182
|
+
│ 1. Read Environment Variables │
|
|
183
|
+
│ - WORKRAIL_ENABLE_SESSION_TOOLS │
|
|
184
|
+
│ - WORKRAIL_ENABLE_EXPERIMENTAL_WORKFLOWS │
|
|
185
|
+
│ - WORKRAIL_VERBOSE_LOGGING │
|
|
186
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
187
|
+
▼
|
|
188
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
189
|
+
│ 2. Parse & Validate │
|
|
190
|
+
│ - true/1/yes/on → true │
|
|
191
|
+
│ - false/0/no/off/undefined → false │
|
|
192
|
+
│ - Invalid values → warn + use default │
|
|
193
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
194
|
+
▼
|
|
195
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
196
|
+
│ 3. Create Immutable Flag Map │
|
|
197
|
+
│ { │
|
|
198
|
+
│ sessionTools: false, │
|
|
199
|
+
│ experimentalWorkflows: false, │
|
|
200
|
+
│ verboseLogging: false, │
|
|
201
|
+
│ } │
|
|
202
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
203
|
+
▼
|
|
204
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
205
|
+
│ 4. Log Enabled Experimental Features │
|
|
206
|
+
│ [FeatureFlags] Session tools disabled │
|
|
207
|
+
│ [FeatureFlags] (enable with WORKRAIL_ENABLE_SESSION_TOOLS)│
|
|
208
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
209
|
+
▼
|
|
210
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
211
|
+
│ 5. Inject into Container │
|
|
212
|
+
│ container.featureFlags = provider │
|
|
213
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
214
|
+
▼
|
|
215
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
216
|
+
│ 6. Services Check Flags at Runtime │
|
|
217
|
+
│ if (featureFlags.isEnabled('sessionTools')) { ... } │
|
|
218
|
+
└──────────────────────────┬──────────────────────────────────────┘
|
|
219
|
+
▼
|
|
220
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
221
|
+
│ 7. MCP Server Ready │
|
|
222
|
+
│ Tools registered based on enabled features │
|
|
223
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Decision Tree: Adding a New Feature
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
┌───────────────────┐
|
|
230
|
+
│ New Feature Ready │
|
|
231
|
+
└─────────┬─────────┘
|
|
232
|
+
│
|
|
233
|
+
▼
|
|
234
|
+
┌───────────────────┐
|
|
235
|
+
│ Is it stable? │
|
|
236
|
+
└─────────┬─────────┘
|
|
237
|
+
│
|
|
238
|
+
┌────────────┴────────────┐
|
|
239
|
+
│ │
|
|
240
|
+
▼ ▼
|
|
241
|
+
┌─────────────┐ ┌─────────────┐
|
|
242
|
+
│ YES │ │ NO │
|
|
243
|
+
│ Stable │ │ Experimental│
|
|
244
|
+
└──────┬──────┘ └──────┬──────┘
|
|
245
|
+
│ │
|
|
246
|
+
▼ ▼
|
|
247
|
+
┌──────────────────────┐ ┌──────────────────────┐
|
|
248
|
+
│ Add with │ │ Add with │
|
|
249
|
+
│ defaultValue: true │ │ defaultValue: false │
|
|
250
|
+
│ stable: true │ │ stable: false │
|
|
251
|
+
└──────┬───────────────┘ └──────┬───────────────┘
|
|
252
|
+
│ │
|
|
253
|
+
└────────────┬────────────┘
|
|
254
|
+
│
|
|
255
|
+
▼
|
|
256
|
+
┌──────────────────────┐
|
|
257
|
+
│ Add to │
|
|
258
|
+
│ FEATURE_FLAG_ │
|
|
259
|
+
│ DEFINITIONS │
|
|
260
|
+
└──────┬───────────────┘
|
|
261
|
+
│
|
|
262
|
+
▼
|
|
263
|
+
┌──────────────────────┐
|
|
264
|
+
│ Use in code: │
|
|
265
|
+
│ if (featureFlags │
|
|
266
|
+
│ .isEnabled('key')) │
|
|
267
|
+
└──────┬───────────────┘
|
|
268
|
+
│
|
|
269
|
+
▼
|
|
270
|
+
┌──────────────────────┐
|
|
271
|
+
│ Write tests │
|
|
272
|
+
│ (enabled & disabled) │
|
|
273
|
+
└──────┬───────────────┘
|
|
274
|
+
│
|
|
275
|
+
▼
|
|
276
|
+
┌──────────────────────┐
|
|
277
|
+
│ Merge to main │
|
|
278
|
+
│ (flag OFF by default)│
|
|
279
|
+
└──────┬───────────────┘
|
|
280
|
+
│
|
|
281
|
+
▼
|
|
282
|
+
┌──────────────────────┐
|
|
283
|
+
│ Test in staging │
|
|
284
|
+
│ (enable with env var)│
|
|
285
|
+
└──────┬───────────────┘
|
|
286
|
+
│
|
|
287
|
+
▼
|
|
288
|
+
┌──────────────────────┐
|
|
289
|
+
│ Feature proven │
|
|
290
|
+
│ stable? │
|
|
291
|
+
└──────┬───────────────┘
|
|
292
|
+
│
|
|
293
|
+
┌────────────┴────────────┐
|
|
294
|
+
│ │
|
|
295
|
+
▼ ▼
|
|
296
|
+
┌────────┐ ┌────────────┐
|
|
297
|
+
│ YES │ │ NO - Iterate│
|
|
298
|
+
└────┬───┘ └────────────┘
|
|
299
|
+
│
|
|
300
|
+
▼
|
|
301
|
+
┌────────────────────┐
|
|
302
|
+
│ Flip default to ON │
|
|
303
|
+
│ stable: true │
|
|
304
|
+
└────┬───────────────┘
|
|
305
|
+
│
|
|
306
|
+
▼
|
|
307
|
+
┌────────────────────┐
|
|
308
|
+
│ After 2+ releases │
|
|
309
|
+
│ Remove flag │
|
|
310
|
+
└────────────────────┘
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## SOLID Principles Visualization
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
317
|
+
│ S - Single Responsibility Principle │
|
|
318
|
+
├────────────────────────────────────────────────────────────────┤
|
|
319
|
+
│ │
|
|
320
|
+
│ ┌───────────────────────────┐ │
|
|
321
|
+
│ │ EnvironmentFeatureFlag │ One job: Read env vars │
|
|
322
|
+
│ │ Provider │ and parse booleans │
|
|
323
|
+
│ └───────────────────────────┘ │
|
|
324
|
+
│ │
|
|
325
|
+
│ ┌───────────────────────────┐ │
|
|
326
|
+
│ │ StaticFeatureFlagProvider │ One job: Provide test │
|
|
327
|
+
│ │ │ values │
|
|
328
|
+
│ └───────────────────────────┘ │
|
|
329
|
+
│ │
|
|
330
|
+
└────────────────────────────────────────────────────────────────┘
|
|
331
|
+
|
|
332
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
333
|
+
│ O - Open/Closed Principle │
|
|
334
|
+
├────────────────────────────────────────────────────────────────┤
|
|
335
|
+
│ │
|
|
336
|
+
│ Add new flags without modifying existing code: │
|
|
337
|
+
│ │
|
|
338
|
+
│ FEATURE_FLAG_DEFINITIONS.push({ │
|
|
339
|
+
│ key: 'newFeature', │
|
|
340
|
+
│ envVar: 'WORKRAIL_NEW_FEATURE', │
|
|
341
|
+
│ defaultValue: false, │
|
|
342
|
+
│ }); │
|
|
343
|
+
│ │
|
|
344
|
+
│ No changes needed to provider classes! │
|
|
345
|
+
│ │
|
|
346
|
+
└────────────────────────────────────────────────────────────────┘
|
|
347
|
+
|
|
348
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
349
|
+
│ L - Liskov Substitution Principle │
|
|
350
|
+
├────────────────────────────────────────────────────────────────┤
|
|
351
|
+
│ │
|
|
352
|
+
│ Any IFeatureFlagProvider implementation works: │
|
|
353
|
+
│ │
|
|
354
|
+
│ function useProvider(provider: IFeatureFlagProvider) { │
|
|
355
|
+
│ return provider.isEnabled('sessionTools'); │
|
|
356
|
+
│ } │
|
|
357
|
+
│ │
|
|
358
|
+
│ useProvider(new EnvironmentFeatureFlagProvider()); │
|
|
359
|
+
│ useProvider(new StaticFeatureFlagProvider()); │
|
|
360
|
+
│ useProvider(new CustomProvider()); │
|
|
361
|
+
│ │
|
|
362
|
+
└────────────────────────────────────────────────────────────────┘
|
|
363
|
+
|
|
364
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
365
|
+
│ I - Interface Segregation Principle │
|
|
366
|
+
├────────────────────────────────────────────────────────────────┤
|
|
367
|
+
│ │
|
|
368
|
+
│ Focused interface (only 3 methods): │
|
|
369
|
+
│ │
|
|
370
|
+
│ interface IFeatureFlagProvider { │
|
|
371
|
+
│ isEnabled(key): boolean; ← Most used │
|
|
372
|
+
│ getAll(): FeatureFlags; ← Bulk access │
|
|
373
|
+
│ getSummary(): string; ← Debugging │
|
|
374
|
+
│ } │
|
|
375
|
+
│ │
|
|
376
|
+
│ No bloat, no unused methods │
|
|
377
|
+
│ │
|
|
378
|
+
└────────────────────────────────────────────────────────────────┘
|
|
379
|
+
|
|
380
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
381
|
+
│ D - Dependency Inversion Principle │
|
|
382
|
+
├────────────────────────────────────────────────────────────────┤
|
|
383
|
+
│ │
|
|
384
|
+
│ ┌──────────────────────┐ │
|
|
385
|
+
│ │ WorkflowServer │ Depends on abstraction │
|
|
386
|
+
│ │ (High-level) │ (not concrete class) │
|
|
387
|
+
│ └──────────┬───────────┘ │
|
|
388
|
+
│ │ │
|
|
389
|
+
│ ▼ │
|
|
390
|
+
│ ┌──────────────────────┐ │
|
|
391
|
+
│ │ IFeatureFlagProvider │ ← Interface (abstraction) │
|
|
392
|
+
│ └──────────┬───────────┘ │
|
|
393
|
+
│ │ │
|
|
394
|
+
│ ▼ │
|
|
395
|
+
│ ┌──────────────────────┐ │
|
|
396
|
+
│ │ EnvironmentFeature │ Concrete implementation │
|
|
397
|
+
│ │ FlagProvider │ depends on interface │
|
|
398
|
+
│ └──────────────────────┘ │
|
|
399
|
+
│ │
|
|
400
|
+
│ Easy to swap implementations │
|
|
401
|
+
│ Easy to test │
|
|
402
|
+
│ │
|
|
403
|
+
└────────────────────────────────────────────────────────────────┘
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Comparison: Before vs After
|
|
407
|
+
|
|
408
|
+
### Before (Hardcoded Comments)
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
class WorkflowOrchestrationServer {
|
|
412
|
+
constructor() {
|
|
413
|
+
// Manual commenting/uncommenting
|
|
414
|
+
// Not testable
|
|
415
|
+
// Blocks releases
|
|
416
|
+
|
|
417
|
+
// Initialize session management (DISABLED for release)
|
|
418
|
+
// TODO: Re-enable session tools when ready for production
|
|
419
|
+
this.sessionManager = new SessionManager();
|
|
420
|
+
this.httpServer = new HttpServer(this.sessionManager);
|
|
421
|
+
this.sessionTools = []; // Disabled: createSessionTools(...)
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async initialize(): Promise<void> {
|
|
425
|
+
// Start HTTP server (DISABLED for release)
|
|
426
|
+
// TODO: Re-enable when ready
|
|
427
|
+
// await this.httpServer.start();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### After (Clean Feature Flags)
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
class WorkflowOrchestrationServer {
|
|
436
|
+
constructor(container?: AppContainer) {
|
|
437
|
+
// Clean boolean check
|
|
438
|
+
// Fully testable
|
|
439
|
+
// Never blocks releases
|
|
440
|
+
|
|
441
|
+
this.container = container ?? createAppContainer();
|
|
442
|
+
this.featureFlags = this.container.featureFlags;
|
|
443
|
+
|
|
444
|
+
if (this.featureFlags.isEnabled('sessionTools')) {
|
|
445
|
+
this.sessionManager = new SessionManager();
|
|
446
|
+
this.httpServer = new HttpServer(this.sessionManager);
|
|
447
|
+
this.sessionTools = createSessionTools(this.sessionManager, this.httpServer);
|
|
448
|
+
} else {
|
|
449
|
+
this.sessionTools = [];
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
async initialize(): Promise<void> {
|
|
454
|
+
if (this.featureFlags.isEnabled('sessionTools') && this.httpServer) {
|
|
455
|
+
await this.httpServer.start();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Benefits Summary
|
|
462
|
+
|
|
463
|
+
| Aspect | Before | After |
|
|
464
|
+
|--------|--------|-------|
|
|
465
|
+
| **Enabling feature** | Edit code, uncomment lines | Set env var |
|
|
466
|
+
| **Testing** | Manual mocking, hard to test | Inject `StaticFeatureFlagProvider` |
|
|
467
|
+
| **Release blocking** | Yes, must manually disable | No, flags control features |
|
|
468
|
+
| **Type safety** | No | Full TypeScript support |
|
|
469
|
+
| **Trunk-based dev** | Difficult | Easy |
|
|
470
|
+
| **Code cleanliness** | Comments everywhere | Clean conditional logic |
|
|
471
|
+
| **Debugging** | Unclear what's disabled | Clear logs |
|
|
472
|
+
|