Skip to content

Commit 84043ae

Browse files
feat: clarify precipitate pattern as runtime state documentation tool
- Updated ROADMAP.md to redefine precipitate pattern as a display-only observability tool, not disk sync - Added detailed explanation of what --precipitate does: queries runtime state and displays as declarative config - Clarified that precipitate never writes to disk, requiring manual user action to persist changes - Added comparison table between drift detection and precipitate features - Added new --caddy flag to debug command for
1 parent 28b6096 commit 84043ae

6 files changed

Lines changed: 415 additions & 46 deletions

File tree

ROADMAP.md

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3702,45 +3702,60 @@ sudo eos update hecate --migrate-to-vault # Migrates existing .env to Vault
37023702
37033703
---
37043704
3705-
### Phase C: Option C - Precipitate Pattern (Runtime → Disk Sync) 📅 DEFERRED (2026-01 → 2026-02)
3706-
3707-
**Goal**: Automatically sync live Caddy API state and Docker runtime back to disk files
3708-
3709-
**Status**: ⚠️ DEFERRED - Blocked by technical challenges (see below)
3710-
3711-
**Rationale for Deferral**:
3712-
1. **Caddy JSON → Caddyfile conversion is lossy/impossible** (Issue #11 from Option B analysis)
3713-
- Caddy Admin API returns JSON format
3714-
- No official JSON → Caddyfile converter exists
3715-
- Manual conversion loses comments, formatting, and some directives
3716-
- Would require building custom AST parser (100+ hours effort)
3717-
3718-
2. **Comment preservation is non-trivial**
3719-
- User's working Caddyfile has inline comments explaining config
3720-
- JSON format doesn't preserve comments
3721-
- Precipitating would destroy all documentation
3722-
3723-
3. **Secret handling complexity**
3724-
- Environment variables in docker-compose.yml may contain secrets
3725-
- Precipitating runtime values could expose secrets in version control
3726-
- Need secret detection + Vault integration first
3727-
3728-
4. **Option B (drift detection) solves 80% of the problem**
3729-
- Users get actionable drift reports with remediation commands
3730-
- Manual fixes are well-documented and low-risk
3731-
- Automatic precipitation adds complexity without proportional value
3732-
3733-
**Alternative Approach** (if demand emerges):
3734-
- **Manual Sync Workflow**: User reviews `21_DRIFT_REPORT.md` → manually applies changes
3735-
- **Assisted Sync**: `eos update hecate --suggest-fixes` generates bash script with recommended changes (user reviews before executing)
3736-
- **Partial Precipitation**: Sync ONLY routes (not env vars) using Caddy Admin API → Caddyfile template regeneration
3737-
3738-
**Revisit Criteria**:
3739-
- User feedback: 5+ requests for automatic precipitation
3740-
- Caddy upstream: Official JSON → Caddyfile converter released
3741-
- Secret manager: Phase 4-6 complete (Vault integration mature)
3742-
3743-
**Revisit Date**: January 15, 2026 (after Phase B.2 complete, gather user feedback)
3705+
### Phase C: Option C - Precipitate Pattern (Runtime State Documentation) ✅ CLARIFIED (2025-10-31)
3706+
3707+
**Goal**: Document live Caddy API state and Docker runtime in declarative format for observability
3708+
3709+
**Status**: ✅ PATTERN CLARIFIED - Pure observability tool, no disk writes
3710+
3711+
**What --precipitate Does** (CORRECTED UNDERSTANDING):
3712+
1. **Query runtime state**:
3713+
- Caddy Admin API: `GET http://localhost:2019/config` (JSON)
3714+
- Docker API: `docker inspect hecate-*` containers
3715+
2. **Convert to declarative format**:
3716+
- Caddy JSON → Caddyfile format representation
3717+
- Docker inspect → docker-compose.yml format representation
3718+
3. **DISPLAY output to terminal** (does NOT write to disk)
3719+
4. **User manually copies** if they want to persist the runtime state
3720+
3721+
**Use Cases**:
3722+
- **Documentation**: Capture "what's actually running" for disaster recovery planning
3723+
- **Comparison**: Compare runtime state against git-tracked disk files
3724+
- **Drift understanding**: Visualize the delta between disk templates and live state
3725+
- **Troubleshooting**: See actual running config when debugging issues
3726+
3727+
**NOT Use Cases** (Anti-patterns):
3728+
- ❌ Automatic synchronization (precipitate is display-only)
3729+
- ❌ Writing files to disk (user must manually copy if desired)
3730+
- ❌ Configuration management (use drift detection + manual fixes instead)
3731+
- ❌ Backup/restore workflow (use proper backup tools)
3732+
3733+
**Why Pure Observability**:
3734+
1. **Comment preservation**: Never overwrites Caddyfiles with inline documentation
3735+
2. **Secret safety**: No risk of writing secrets to version control
3736+
3. **User control**: Explicit consent required for any disk changes
3737+
4. **No conversion challenges**: Display format can be approximate/lossy (not authoritative)
3738+
3739+
**Implementation Status**:
3740+
- ✅ Pattern documented in [pkg/hecate/authentik/export.go:870-890](pkg/hecate/authentik/export.go#L870-L890)
3741+
- ✅ Pattern documented in [pkg/hecate/authentik/drift.go:501-507, 661-668](pkg/hecate/authentik/drift.go#L501-L507)
3742+
- ⏳ Drift detection (Phase B) provides recommendations to use `--precipitate`
3743+
- ⏳ CLI flag `--precipitate` implementation (pending)
3744+
3745+
**Comparison with Drift Detection (Phase B)**:
3746+
3747+
| Feature | Drift Detection (Phase B) | Precipitate (Phase C) |
3748+
|---------|---------------------------|------------------------|
3749+
| **Purpose** | Identify differences | Document runtime state |
3750+
| **Output** | Drift report with remediation | Declarative config (display only) |
3751+
| **Actionable?** | Yes (commands to fix) | No (informational only) |
3752+
| **Writes files?** | Yes (drift report) | No (display only) |
3753+
| **Use case** | Ongoing monitoring | Ad-hoc documentation |
3754+
3755+
**Implementation Priority**: LOW (2026-02+)
3756+
- Drift detection (Phase B) solves operational monitoring
3757+
- Precipitate adds documentation value but not critical path
3758+
- Wait for user feedback after Phase B deployment
37443759
37453760
---
37463761

cmd/debug/hecate.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var (
1111
hecateComponent string
1212
hecateAuthentikCheck bool
1313
hecateBionicGPTCheck bool
14+
hecateCaddyCheck bool
1415
hecatePath string
1516
hecateVerbose bool
1617
)
@@ -68,10 +69,20 @@ BionicGPT integration diagnostics (--bionicgpt flag):
6869
• End-to-end authentication flow test
6970
• Common misconfigurations detection
7071
72+
Caddy Admin API diagnostics (--caddy flag):
73+
• Connection testing with retry attempts
74+
• Health endpoint verification
75+
• Configuration retrieval and parsing
76+
• Route listing and validation
77+
• Admin API port accessibility
78+
• Network connectivity diagnosis
79+
• Timeout and performance analysis
80+
7181
Flags:
7282
--component <name> Only check specific component (caddy|authentik|postgresql|redis|nginx|coturn)
7383
--authentik Run comprehensive Authentik health check + configuration export
7484
--bionicgpt Run BionicGPT integration diagnostics (Authentik-Caddy-BionicGPT)
85+
--caddy Run Caddy Admin API diagnostics (connection, health, routes)
7586
--path <path> Path to Hecate installation (default: /opt/hecate)
7687
--verbose Show detailed diagnostic output
7788
@@ -80,6 +91,7 @@ Examples:
8091
eos debug hecate --component authentik # Only diagnose Authentik
8192
eos debug hecate --authentik # Full Authentik health check + config export
8293
eos debug hecate --bionicgpt # BionicGPT integration diagnostics
94+
eos debug hecate --caddy # Caddy Admin API diagnostics
8395
eos debug hecate --path /custom/path # Custom installation path
8496
8597
Output is automatically saved to ~/.eos/debug/eos-debug-hecate-{timestamp}.txt`,
@@ -90,6 +102,7 @@ func init() {
90102
hecateCmd.Flags().StringVar(&hecateComponent, "component", "", "Specific component to check")
91103
hecateCmd.Flags().BoolVar(&hecateAuthentikCheck, "authentik", false, "Run comprehensive Authentik health check + configuration export")
92104
hecateCmd.Flags().BoolVar(&hecateBionicGPTCheck, "bionicgpt", false, "Run BionicGPT integration diagnostics (Authentik-Caddy-BionicGPT triangle)")
105+
hecateCmd.Flags().BoolVar(&hecateCaddyCheck, "caddy", false, "Run Caddy Admin API diagnostics (connection, health, routes)")
93106
hecateCmd.Flags().StringVar(&hecatePath, "path", "/opt/hecate", "Path to Hecate installation")
94107
hecateCmd.Flags().BoolVar(&hecateVerbose, "verbose", false, "Show detailed diagnostic output")
95108
debugCmd.AddCommand(hecateCmd)

pkg/hecate/authentik/drift.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,13 @@ func generateRecommendations(report *DriftReport) []string {
498498
if len(report.CaddyDrift.AddedRoutes) > 0 {
499499
recommendations = append(recommendations,
500500
"Add missing routes to /opt/hecate/Caddyfile to prevent loss on reload")
501+
// PRECIPITATE PATTERN: Query EXISTING RUNNING state → DOCUMENT as declarative .yml
502+
// For Caddy: GET /config via Admin API → Convert JSON to Caddyfile → DISPLAY (not write)
503+
// For Docker: docker inspect containers → Generate docker-compose.yml → DISPLAY (not write)
504+
// GOAL: Show "what's actually running" in declarative format for comparison/documentation
505+
// NOTE: Does NOT write to disk - purely observability
501506
recommendations = append(recommendations,
502-
fmt.Sprintf("Run: eos update hecate --precipitate (Option C) to sync API state to disk"))
507+
fmt.Sprintf("Run: eos update hecate --precipitate to document current runtime state"))
503508
}
504509

505510
if len(report.CaddyDrift.RemovedRoutes) > 0 {
@@ -653,8 +658,14 @@ func RenderDriftReport(report *DriftReport) string {
653658
// Remediation Commands
654659
sb.WriteString("## Remediation Commands\n\n")
655660
sb.WriteString("```bash\n")
656-
sb.WriteString("# Option 1: Precipitate runtime state to disk (COMING SOON)\n")
657-
sb.WriteString("eos update hecate --precipitate\n\n")
661+
sb.WriteString("# Option 1: Document runtime state (COMING SOON)\n")
662+
sb.WriteString("# PRECIPITATE: Query running state → Display as declarative config\n")
663+
sb.WriteString("# - Caddy Admin API (/config) → Convert to Caddyfile format → DISPLAY\n")
664+
sb.WriteString("# - Docker inspect → Convert to docker-compose.yml → DISPLAY\n")
665+
sb.WriteString("# - Shows what's ACTUALLY running vs what's on disk\n")
666+
sb.WriteString("# - Does NOT write files (purely observability/documentation)\n")
667+
sb.WriteString("eos update hecate --precipitate\n")
668+
sb.WriteString("# User can then manually copy output to disk files if desired\n\n")
658669
sb.WriteString("# Option 2: Reload Caddy from disk Caddyfile (loses API changes)\n")
659670
sb.WriteString("docker exec hecate-caddy caddy reload --config /etc/caddy/Caddyfile\n\n")
660671
sb.WriteString("# Option 3: Recreate containers from compose file\n")

pkg/hecate/authentik/export.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -905,11 +905,26 @@ ls -lh 19_Caddyfile.disk 19_Caddyfile.live.json
905905
906906
### Reconciling Drift:
907907
908-
**Option 1: Precipitate API → Disk (coming soon)**
908+
**Option 1: Document Runtime State (coming soon)**
909909
`+"```"+`
910-
# This will be implemented in Option C
910+
# PRECIPITATE PATTERN: Query running state → Document as declarative config
911+
#
912+
# What --precipitate does:
913+
# 1. Query Caddy Admin API: GET http://localhost:2019/config
914+
# 2. Convert JSON response to Caddyfile format
915+
# 3. Query Docker API: docker inspect hecate-* containers
916+
# 4. Generate docker-compose.yml with actual networks, volumes, env vars
917+
# 5. DISPLAY both configs (does NOT write to disk)
918+
#
919+
# Output shows:
920+
# - What Caddyfile SHOULD look like to match runtime
921+
# - What docker-compose.yml SHOULD look like to match runtime
922+
#
923+
# User can then:
924+
# - Copy output to /opt/hecate/Caddyfile if desired
925+
# - Version control the "runtime reality" for documentation
926+
# - Compare against git history to understand drift
911927
eos update hecate --precipitate
912-
# Writes live API state back to disk files
913928
`+"```"+`
914929
915930
**Option 2: Manual Reconciliation**

pkg/hecate/debug.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,21 @@ func RunHecateDebug(rc *eos_io.RuntimeContext, cmd *cobra.Command, args []string
5656
component, _ := cmd.Flags().GetString("component")
5757
authentikCheck, _ := cmd.Flags().GetBool("authentik")
5858
bionicgptCheck, _ := cmd.Flags().GetBool("bionicgpt")
59+
caddyCheck, _ := cmd.Flags().GetBool("caddy")
5960
hecatePath, _ := cmd.Flags().GetString("path")
6061
verbose, _ := cmd.Flags().GetBool("verbose")
6162

6263
logger.Info("Starting Hecate diagnostics",
6364
zap.String("component_filter", component),
6465
zap.String("path", hecatePath),
6566
zap.Bool("authentik_check", authentikCheck),
66-
zap.Bool("bionicgpt_check", bionicgptCheck))
67+
zap.Bool("bionicgpt_check", bionicgptCheck),
68+
zap.Bool("caddy_check", caddyCheck))
69+
70+
// If --caddy flag is set, run Caddy Admin API diagnostics
71+
if caddyCheck {
72+
return RunCaddyAdminAPIDebug(rc, hecatePath, verbose)
73+
}
6774

6875
// If --bionicgpt flag is set, run BionicGPT integration diagnostics
6976
if bionicgptCheck {

0 commit comments

Comments
 (0)