docs: reorganise -- current reference gathered, finished work archived, superseded and dead ideas marked as such

docs/CLAUDE.md Phase 2, 2026-10-14.  All moves by git mv; every archived
file carries a header saying what it is, why, and where to look instead.

- docs/reference/ (new): roadmap and versioning policy, M7.1, word-ACL
  design, kernel args, hosted acceptance test, dictionary, primitives,
  ontology, L8 table -- previously spread over docs/, docs/lithosananke/
  and docs/03-architecture/.
- docs/working/archive/historical/: finished work (session plan, test-gap
  audit, birthing plan, fix write-ups, the January architecture draft).
- docs/working/archive/superseded/: the Hermes-VM Tripod docs and July
  Hermes designs (-> FABRIC-3.5/3.6), the StarForth roadmap, every working
  doc already flagged superseded or obsolete.
- docs/working/archive/dead/: the hal_* target contract (never adopted),
  L4Re, metrics-and-knobs.
- Papers and proposals into docs/working/papers/.
- References rewritten across the repo (not logs/, not docs/patent/);
  CLAUDE.md's documentation section rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-14 16:03:56 -04:00
co-authored by Claude Opus 5.5
parent 1a4b163861
commit 7aed588f78
116 changed files with 305 additions and 175 deletions
@@ -1,341 +0,0 @@
<!-- Moved from docs/02-experiments/heartbeat-doe/corrected-design.md to docs/working/experiments/02-experiments/heartbeat-doe/corrected-design.md on 2026-06-16 (docs reorg Phase 2) -->
> **⚠ SUPERSEDED (flagged 2026-10-09).** Superseded by `phase2-corrected.md` (the
> "corrected and finalized" revision). Kept for historical record.
# StarForth Heartbeat DoE – CORRECTED Design (Heartrate Focus)
**Date:** November 20, 2025
**CORRECTION:** Previous design missing critical metric: **HEARTBEAT RATE (tick_ns)**
**Status:** Ready for implementation
---
## The Critical Insight You Caught
The heartbeat isn't just a **fixed tick**. The system has a **variable heartbeat rate** controlled by:
```c
/* HeartbeatWorker.tick_ns — this is DYNAMIC, not constant! */
uint64_t tick_ns; /* Nanoseconds between ticks — VARIES with load! */
```
**What this means:**
- Default: `HEARTBEAT_TICK_NS` (~1 millisecond)
- **But:** The inference engine can adaptively adjust `tick_target_ns`
- Different configurations may modulate heartbeat frequency differently
- **This is the KEY physics behavior we must measure!**
---
## Stage 1 Problem (What We Got Wrong)
Stage 1 baseline ran **without heartbeat thread** (HEARTBEAT_THREAD_ENABLED=0):
- Fixed 1ms tick (no modulation)
- No adaptive heartrate
- Doesn't reflect StarForth's intended physics-driven behavior
**Stage 1 conclusion:** "System is deterministic, no heartbeat variation"
**Stage 1 was incomplete** because it disabled the very mechanism that makes the system adaptive!
---
## Stage 2 Correction (What We Should Do)
### Primary Hypothesis
The 5 elite configurations differ in **how they modulate heartbeat rate**:
| Config | Expected Behavior |
|--------|-------------------|
| 1_0_1_1_1_0 | Tight, responsive heartrate (low jitter, fast modulation) |
| 1_0_1_1_1_1 | Similar, with decay inference slowing response? |
| 1_1_0_1_1_1 | Window-driven, may have different modulation pattern |
| 1_0_1_0_1_0 | Lean, may have sluggish response |
| 0_1_1_0_1_1 | Window-without-heat, baseline behavior |
### Key Metrics for Heartrate (Not Just Intervals)
**We need to measure:**
1. **Heartbeat Rate Modulation (NOT just interval jitter)**
```
heartbeat_rate_trajectory = [tick_ns_t0, tick_ns_t1, tick_ns_t2, ...]
What we measure:
- Mean heartbeat rate (expected: ~1,000,000 ns = 1 kHz baseline)
- Responsiveness to load (does rate slow under heavy load?)
- Convergence time (how long until rate stabilizes?)
- Modulation range (min to max tick_ns observed)
```
2. **Heartrate vs. Workload Coupling**
```
For each tick:
workload_intensity = lookups_this_tick / lookups_per_second_baseline
heartrate_hz = 1_000_000_000 / tick_ns
Measure: correlation(workload_intensity, heartrate_hz)
- Positive correlation: heartrate slows under load (good physics)
- Negative correlation: heartrate speeds up under load (bad physics)
- No correlation: heartrate doesn't respond to load (broken physics)
```
3. **Heartrate Stability (Not "jitter" but "rate consistency")**
```
- Does heartrate converge to a steady state?
- How quickly does it adapt to workload changes?
- Does it oscillate or settle smoothly?
```
4. **Heartrate Efficiency**
```
- Is the system running faster/slower with adapted heartrate?
- Workload duration: should improve with optimized heartrate
- Memory: should be more efficient with tuned heartrate
```
---
## Corrected Metrics Collection
### Per-Tick Collection (During Execution)
```c
/* In heartbeat_thread_main(), before nanosleep() */
struct HeartbeatTickData {
uint64_t tick_number;
uint64_t tick_ns; /* THIS IS THE HEARTBEAT RATE! */
uint64_t workload_ops_this_tick; /* Dictionary lookups in this tick */
uint64_t wall_clock_ns; /* Actual wall-clock time */
uint64_t hot_word_count; /* Physics state */
uint64_t total_heat; /* Physics state */
};
/* Store in circular buffer or rolling window */
```
### Post-Run Analysis Metrics
```c
typedef struct {
/* === Original Metrics === */
/* ... existing 38 metrics ... */
/* === CORRECTED: Heartbeat Rate Metrics === */
/* Heartbeat rate trajectory */
uint64_t total_ticks_executed;
double mean_heartbeat_rate_hz; /* Hz = 1e9 / mean_tick_ns */
double heartbeat_rate_stddev_hz; /* Variation in Hz */
double heartbeat_rate_cv; /* Coefficient of variation */
uint64_t heartbeat_rate_min_ns; /* Slowest (highest tick_ns) */
uint64_t heartbeat_rate_max_ns; /* Fastest (lowest tick_ns) */
double heartbeat_rate_range_hz; /* max_hz - min_hz */
/* Heartrate vs Load Coupling */
double load_to_heartrate_correlation; /* Does rate respond to load? */
int load_response_direction; /* +1 = slower under load (good) */
double heartrate_adaptation_latency_ticks; /* Ticks until rate responds */
double heartrate_settling_time_ticks; /* Ticks to settle after change */
/* Heartrate Convergence */
double heartrate_convergence_time_ms; /* Time to reach stable rate */
int heartrate_converged; /* 1 = yes, 0 = still oscillating */
double heartrate_oscillation_amplitude_hz; /* Peak-to-peak variation */
/* Overall Heartrate Stability Score */
double heartrate_stability_score; /* 0-100: how stable is heartrate? */
} DoeMetrics_CORRECTED;
```
---
## The Missing Piece: Heartbeat Rate Logging
**Critical code addition needed:**
```c
/* In vm.c heartbeat_thread_main() - CAPTURE tick_ns BEFORE and AFTER */
static inline void capture_heartbeat_rate_sample(VM *vm, uint64_t tick_ns, uint64_t workload_ops) {
/* Store sample in rolling buffer */
if (!vm->heartbeat_rate_samples) {
vm->heartbeat_rate_samples = calloc(HEARTBEAT_RATE_SAMPLE_MAX, sizeof(HeartbeatRateSample));
}
HeartbeatRateSample *sample = &vm->heartbeat_rate_samples[vm->heartbeat_rate_sample_count];
sample->tick_number = vm->heartbeat.tick_count;
sample->tick_ns = tick_ns; /* THE HEARTBEAT RATE! */
sample->workload_ops = workload_ops;
sample->timestamp_ns = platform_monotonic_ns();
vm->heartbeat_rate_sample_count++;
}
/* In heartbeat_thread_main() */
static void* heartbeat_thread_main(void *arg) {
VM *vm = (VM*)arg;
while (!vm->heartbeat.worker->stop_requested) {
uint64_t tick_start_ns = platform_monotonic_ns();
vm_heartbeat_run_cycle(vm); /* May adjust tick_ns */
uint64_t tick_ns = vm->heartbeat.worker->tick_ns;
uint64_t workload_ops = vm->execution_heat_current_tick; /* Need to track */
/* CAPTURE THE HEARTBEAT RATE! */
capture_heartbeat_rate_sample(vm, tick_ns, workload_ops);
/* Sleep */
nanosleep(...);
}
}
```
---
## Corrected Analysis (R Script)
```r
# Load heartbeat rate samples from CSV
doe_data <- read.csv("experiment_results_heartbeat.csv") %>%
mutate(
# Convert heartbeat rates (tick_ns → Hz)
mean_heartbeat_hz = 1e9 / mean_heartbeat_rate_ns,
heartrate_stability = 1 / (1 + heartbeat_rate_cv), # Lower CV = higher score
)
# PRIMARY ANALYSIS: Heartrate Stability
stability_by_heartrate <- doe_data %>%
group_by(configuration) %>%
summarize(
mean_heartrate_hz = mean(mean_heartbeat_hz),
mean_heartrate_stability = mean(heartrate_stability),
mean_load_coupling = mean(load_to_heartrate_correlation),
mean_workload_ms = mean(vm_workload_duration_ns_q48 / 1e6)
) %>%
mutate(
# Golden config = best heartrate stability + strongest load coupling
golden_score = (heartrate_stability * 0.5) + (load_coupling * 0.3) + (workload_improvement * 0.2)
)
# Golden Config = Highest golden_score
```
---
## Why This Matters
### Stage 1 Got Lucky
Stage 1 found 5 good configs **by accident** because it measured final performance, not physics.
### Stage 2 Should Be Different
Stage 2 should measure **whether the physics is working correctly**:
- **Can the system modulate heartbeat rate** in response to load?
- **Is the modulation smooth** or does it oscillate?
- **Does heartrate modulation improve overall performance?**
- **Which configuration has the most responsive, stable heartrate?**
**The golden configuration should be the one where heartbeat rate modulation is:**
1. ✓ **Responsive** (correlates with workload)
2. ✓ **Smooth** (doesn't oscillate wildly)
3. ✓ **Efficient** (results in best overall performance)
---
## Revised DoE Experiment Design
### What Actually Gets Measured
Instead of just "jitter in fixed 1ms tick intervals", measure:
**Per-Run Heartbeat Rate Trajectory:**
```
Tick 0: tick_ns = 1,000,000 (1 ms baseline)
Tick 1: tick_ns = 1,500,000 (slowing under load)
Tick 2: tick_ns = 2,000,000 (further slowdown)
Tick 10: tick_ns = 1,200,000 (adapting back)
Tick 100: tick_ns = 1,050,000 (converged to steady state)
```
**What we analyze:**
1. Did heartrate change at all? (some configs might keep it fixed)
2. How much did it vary? (CV of tick_ns, not CV of fixed intervals)
3. Did it respond to load? (correlation with workload)
4. Did it converge smoothly? (no oscillation)
5. Did it improve performance? (faster execution with adaptive heartrate?)
---
## Implementation Checklist (Revised)
- [ ] Add `HeartbeatRateSample` struct to capture `tick_ns` per tick
- [ ] Modify `heartbeat_thread_main()` to log `tick_ns` trajectory
- [ ] Extend `DoeMetrics` with heartrate-specific fields (not just interval jitter)
- [ ] Update CSV schema to include heartrate trajectory metrics
- [ ] Modify R analysis to focus on **heartrate modulation patterns**
- [ ] Update golden config selection: prioritize **load responsiveness**
---
## Expected Results (Corrected)
### Hypothesis: Configs Differ in Heartrate Modulation
**Config 1 (1_0_1_1_1_0) - Expected WINNER:**
- Heartrate slowly increases under load (tick_ns increases, Hz decreases)
- Smooth adaptation (no oscillation)
- Converges within 1000 ticks
- Performance improves (faster overall execution)
- Load coupling: 0.8+ (strong)
**Config 5 (0_1_1_0_1_1) - Expected LOSER:**
- Heartrate doesn't respond to load (fixed tick_ns)
- No correlation with workload
- Performance degrades (why? system can't adapt)
---
## Key Realization
The heartbeat isn't just a **timer**. It's a **feedback mechanism**:
```
Load increases
↓
Inference engine detects change
↓
Adjusts tick_target_ns (slower heartbeat = more thinking time)
↓
Heartbeat rate modulates (tick_ns increases)
↓
Physics engine gets more time to tune parameters
↓
System adapts and performance improves
```
**We need to measure whether this feedback loop is working!**
---
## Next Steps
1. **Extend HeartbeatWorker:** Add rate sample collection
2. **Modify heartbeat_thread_main():** Log `tick_ns` per tick
3. **Update DoeMetrics:** Heartrate trajectory analysis
4. **Rewrite CSV schema:** Focus on heartrate modulation
5. **Rewrite R analysis:** Measure load-response coupling and heartrate stability
6. **Re-run experiment:** Focus on configs that modulate heartrate best
---
**This changes the entire experiment focus.**
Instead of measuring "jitter in a fixed heartbeat", we're measuring "**how well does the system modulate its heartbeat in response to load?**"
That's the real physics story.
@@ -1,431 +0,0 @@
<!-- Moved from docs/02-experiments/heartbeat-doe/design.md to docs/working/experiments/02-experiments/heartbeat-doe/design.md on 2026-06-16 (docs reorg Phase 2) -->
> **⚠ SUPERSEDED (flagged 2026-10-09).** Pre-correction draft; superseded first by
> `corrected-design.md`, then by `phase2-corrected.md` (the finalized design). Kept for
> historical record.
# StarForth Factorial DoE with Heartbeat Integration
**Date:** November 20, 2025
**Status:** Design Phase
**Experiment:** 2^6 Factorial with Heartbeat-Aware Metrics Collection
---
## Overview
This document describes the **second-generation factorial DoE** that incorporates heartbeat observability into metric collection. Building on the baseline DOE (Stage 1: 3200 runs, 6 factors, no heartbeat), this experiment captures **per-tick heartbeat dynamics** to identify configurations with optimal stability characteristics.
### Key Innovation
Instead of measuring static performance, this experiment measures **temporal stability**:
- How quickly does the system converge under load changes?
- How much does heartbeat interval modulate in response to workload?
- What is the jitter envelope after settling?
- Which configuration achieves smoothest load→heartbeat coupling?
---
## Design Points (Top 5 Configurations from Stage 1)
Based on Stage 1 analysis, the elite configurations are:
1. **Config 1:** `1_0_1_1_1_0` (F1=ON, F2=OFF, F3=ON, F4=ON, F5=ON, F6=OFF)
2. **Config 2:** `1_0_1_1_1_1` (F1=ON, F2=OFF, F3=ON, F4=ON, F5=ON, F6=ON)
3. **Config 3:** `1_1_0_1_1_1` (F1=ON, F2=ON, F3=OFF, F4=ON, F5=ON, F6=ON)
4. **Config 4:** `1_0_1_0_1_0` (F1=ON, F2=OFF, F3=ON, F4=OFF, F5=ON, F6=OFF)
5. **Config 5:** `0_1_1_0_1_1` (F1=OFF, F2=ON, F3=ON, F4=OFF, F5=ON, F6=ON)
**Factors Mapping:**
- F1 = ENABLE_LOOP_1_HEAT_TRACKING
- F2 = ENABLE_LOOP_2_ROLLING_WINDOW
- F3 = ENABLE_LOOP_3_LINEAR_DECAY
- F4 = ENABLE_LOOP_4_PIPELINING_METRICS
- F5 = ENABLE_LOOP_5_WINDOW_INFERENCE
- F6 = ENABLE_LOOP_6_DECAY_INFERENCE
---
## New Heartbeat Metrics (Per-Tick Collection)
### 1. Heartbeat Interval Dynamics
```c
struct HeartbeatTickMetrics {
uint64_t tick_count; /* Absolute tick number */
uint64_t tick_interval_ns; /* Wall-clock duration of this tick */
uint64_t instantaneous_workload_ops; /* Dictionary lookups in this tick */
double instantaneous_load_ratio; /* (ops this tick) / (avg ops/tick) */
};
```
**Purpose:** Capture how heartbeat frequency modulates in response to workload intensity.
### 2. Cache Performance (Per-Tick Window)
```c
struct CacheWindowMetrics {
uint64_t tick_start;
uint64_t cache_hits_window; /* Hits in last 100 ticks */
uint64_t cache_attempts_window; /* Attempts in last 100 ticks */
double cache_hit_percent_window; /* Rolling window %, 0-100 */
};
```
**Purpose:** Measure cache stability, not just final hit rate.
### 3. Rolling Window Diagnostics
```c
struct WindowDiagnostics {
uint32_t effective_window_size; /* Current adaptive size */
uint64_t pattern_diversity; /* Unique word IDs observed */
double diversity_growth_rate; /* % new patterns per 1000 executions */
int is_warm; /* 1 if window is representative */
};
```
**Purpose:** Track window convergence and saturation.
### 4. Jitter Envelope
```c
struct JitterMetrics {
double tick_interval_mean_ns; /* Average heartbeat interval */
double tick_interval_stddev_ns; /* StdDev of interval */
double tick_interval_cv; /* Coefficient of variation (σ/μ) */
uint64_t outlier_count; /* Ticks >3σ from mean */
double outlier_ratio; /* Outliers / total ticks */
};
```
**Purpose:** Measure temporal smoothness and jitter control.
### 5. Decay Slope Tracking
```c
struct DecayTrajectory {
uint64_t tick_sample_count; /* How many ticks sampled */
double decay_slope_observed; /* Fitted slope from observations */
double slope_convergence_rate; /* Speed of slope convergence */
int slope_direction; /* -1=decreasing, 0=stable, +1=increasing */
};
```
**Purpose:** Monitor whether decay slope inference is tracking correctly.
### 6. Load-Response Coupling
```c
struct LoadResponseCoupling {
double correlation_load_to_interval; /* Correlation(workload, heartbeat_interval) */
double response_latency_ticks; /* Ticks until interval reacts to load change */
double overshoot_ratio; /* Peak response / steady-state response */
double settling_time_ticks; /* Ticks to settle within 10% of target */
};
```
**Purpose:** Measure how quickly and smoothly heartbeat responds to workload shifts.
---
## Extended DoeMetrics Struct
Add to `include/doe_metrics.h`:
```c
typedef struct {
/* === Original Metrics (preserved) === */
/* ... existing 35+ metrics ... */
/* === NEW: Heartbeat Stability Metrics === */
/* Tick dynamics */
uint64_t total_heartbeat_ticks; /* Total ticks during run */
double tick_interval_mean_ns; /* Average heartbeat interval */
double tick_interval_stddev_ns; /* StdDev of heartbeat interval */
double tick_interval_cv; /* Coefficient of variation */
uint64_t tick_outlier_count_3sigma; /* Ticks >3σ from mean */
double tick_outlier_ratio; /* Outliers / total ticks */
/* Cache stability window */
double cache_hit_percent_rolling_mean; /* Rolling avg, last 100 ticks */
double cache_hit_percent_rolling_stddev; /* Rolling stddev */
double cache_stability_index; /* How stable is cache hit %? */
/* Window convergence */
uint32_t window_final_effective_size; /* Final adaptive window size */
double pattern_diversity_final; /* Final unique patterns observed */
double diversity_growth_final; /* Growth rate at end */
int window_warmth_achieved; /* 1 = warm, 0 = still cold */
/* Decay slope convergence */
double decay_slope_fitted_final; /* Final fitted decay slope */
double decay_slope_convergence_rate; /* How fast did slope converge? */
int decay_slope_stable; /* 1 = stable direction, 0 = oscillating */
/* Load-response */
double load_interval_correlation; /* Correlation(load, heartbeat_interval) */
double response_latency_ticks; /* Ticks until response to workload change */
double overshoot_ratio; /* Peak response / steady-state */
double settling_time_ticks; /* Time to 10% settling band */
/* Aggregate stability score */
double overall_stability_score; /* Composite metric: (low jitter + fast convergence + tight correlation) */
} DoeMetrics; /* Now extends to ~65+ columns */
```
---
## Heartbeat Data Collection Architecture
### Per-Tick Logging (Lightweight)
During VM execution, capture minimal per-tick data:
```c
/* In vm.c vm_tick_heartbeat_worker() */
void vm_tick_heartbeat_worker(VM *vm) {
HeartbeatSnapshot snapshot = {
.published_tick = vm->heartbeat.tick_count,
.published_ns = platform_monotonic_ns(),
.window_width = vm->rolling_window.effective_window_size,
.decay_slope_q48 = vm->decay_slope_q48,
.hot_word_count = vm->hot_word_count_at_check,
.stale_word_count = vm->stale_word_count_at_check,
.total_heat = vm->total_heat_at_last_check,
};
/* Publish snapshot (double-buffered, lock-free read) */
int next_slot = 1 - vm->heartbeat.snapshot_index;
vm->heartbeat.snapshots[next_slot] = snapshot;
vm->heartbeat.snapshot_index = next_slot;
}
```
### Post-Run Analysis (Batch Processing)
After test execution completes, analyze collected tick data:
```c
/* In src/doe_metrics.c metrics_from_vm() */
void analyze_heartbeat_trajectory(VM *vm, DoeMetrics *metrics) {
HeartbeatSnapshot *snapshots = vm->heartbeat.snapshots;
uint64_t total_ticks = vm->heartbeat.tick_count;
/* 1. Compute tick interval statistics */
double intervals[total_ticks];
for (size_t i = 1; i < total_ticks; i++) {
intervals[i] = snapshots[i].published_ns - snapshots[i-1].published_ns;
}
metrics->tick_interval_mean_ns = compute_mean(intervals, total_ticks);
metrics->tick_interval_stddev_ns = compute_stddev(intervals, total_ticks);
metrics->tick_interval_cv = metrics->tick_interval_stddev_ns / metrics->tick_interval_mean_ns;
/* 2. Compute outlier ratio (ticks >3σ from mean) */
double threshold_3sigma = metrics->tick_interval_mean_ns + 3.0 * metrics->tick_interval_stddev_ns;
uint64_t outliers = 0;
for (size_t i = 0; i < total_ticks; i++) {
if (intervals[i] > threshold_3sigma) outliers++;
}
metrics->tick_outlier_ratio = (double)outliers / total_ticks;
/* 3. Compute decay slope convergence */
double slopes[total_ticks];
for (size_t i = 100; i < total_ticks; i++) { /* Skip warm-up */
slopes[i] = snapshots[i].decay_slope_q48 / 65536.0;
}
metrics->decay_slope_fitted_final = slopes[total_ticks - 1];
metrics->decay_slope_convergence_rate = compute_convergence_rate(slopes, total_ticks);
/* 4. Compute overall stability score */
double stability = 0.0;
stability += (100.0 - metrics->tick_interval_cv); /* Lower CV = higher score */
stability += (100.0 - metrics->tick_outlier_ratio * 100.0); /* Fewer outliers = higher */
stability += metrics->decay_slope_convergence_rate; /* Fast convergence = higher */
metrics->overall_stability_score = stability / 3.0;
}
```
---
## CSV Output Schema (Extended)
**New columns (per heartbeat experiment run):**
```
timestamp,configuration,run_number,
[... original 38 columns ...],
total_heartbeat_ticks,
tick_interval_mean_ns,tick_interval_stddev_ns,tick_interval_cv,
tick_outlier_count_3sigma,tick_outlier_ratio,
cache_hit_percent_rolling_mean,cache_hit_percent_rolling_stddev,cache_stability_index,
window_final_effective_size,pattern_diversity_final,diversity_growth_final,window_warmth_achieved,
decay_slope_fitted_final,decay_slope_convergence_rate,decay_slope_stable,
load_interval_correlation,response_latency_ticks,overshoot_ratio,settling_time_ticks,
overall_stability_score
```
**Total:** ~60 columns per run
---
## R Analysis Template
```r
library(tidyverse)
library(ggplot2)
library(gridExtra)
# Load heartbeat DoE data
doe_data <- read.csv("experiment_results_with_heartbeat.csv") %>%
mutate(
configuration = as.factor(configuration),
timestamp = as.POSIXct(timestamp)
)
# ========== MAIN ANALYSIS ==========
# 1. Stability Ranking
stability_rank <- doe_data %>%
group_by(configuration) %>%
summarize(
mean_stability_score = mean(overall_stability_score),
mean_jitter_cv = mean(tick_interval_cv),
mean_convergence_rate = mean(decay_slope_convergence_rate),
mean_settling_time = mean(settling_time_ticks),
n_runs = n()
) %>%
mutate(
rank = rank(-mean_stability_score, ties.method = "min")
) %>%
arrange(rank)
print("=== STABILITY RANKINGS ===")
print(stability_rank)
# 2. Visualization: Stability Scores
ggplot(doe_data, aes(x = reorder(configuration, overall_stability_score, FUN=median),
y = overall_stability_score,
fill = configuration)) +
geom_boxplot(alpha = 0.7) +
geom_jitter(width = 0.2, alpha = 0.4) +
coord_flip() +
theme_minimal() +
labs(title = "Overall Stability Scores by Configuration",
x = "Configuration",
y = "Stability Score (0-100)")
ggsave("01_stability_scores.png", width = 10, height = 6)
# 3. Visualization: Jitter Control (CV)
ggplot(doe_data, aes(x = reorder(configuration, tick_interval_cv, FUN=median),
y = tick_interval_cv,
fill = configuration)) +
geom_boxplot(alpha = 0.7) +
coord_flip() +
theme_minimal() +
labs(title = "Heartbeat Jitter (Coefficient of Variation)",
x = "Configuration",
y = "CV (lower = less jitter)")
ggsave("02_jitter_control.png", width = 10, height = 6)
# 4. Visualization: Convergence Speed
ggplot(doe_data, aes(x = reorder(configuration, decay_slope_convergence_rate, FUN=median),
y = decay_slope_convergence_rate,
fill = configuration)) +
geom_boxplot(alpha = 0.7) +
coord_flip() +
theme_minimal() +
labs(title = "Decay Slope Convergence Speed",
x = "Configuration",
y = "Convergence Rate (ticks)")
ggsave("03_convergence_speed.png", width = 10, height = 6)
# 5. Correlation: Load Response Coupling
ggplot(doe_data, aes(x = load_interval_correlation,
y = overall_stability_score,
color = configuration)) +
geom_point(alpha = 0.6, size = 2) +
facet_wrap(~configuration) +
theme_minimal() +
labs(title = "Load-Response Coupling vs Stability",
x = "Correlation(load, interval)",
y = "Overall Stability Score")
ggsave("04_load_response_coupling.png", width = 12, height = 8)
# 6. Statistical Test: Is top config significantly better?
top_config <- stability_rank$configuration[1]
other_configs <- stability_rank$configuration[-1]
top_data <- doe_data %>% filter(configuration == top_config) %>% pull(overall_stability_score)
other_data <- doe_data %>% filter(configuration %in% other_configs) %>% pull(overall_stability_score)
t_test <- t.test(top_data, other_data)
print(sprintf("\nT-test: %s vs others\np-value: %.4f", top_config, t_test$p.value))
# 7. Golden Configuration Summary
cat("\n=== GOLDEN CONFIGURATION CANDIDATE ===\n")
golden <- stability_rank %>% slice(1)
print(golden)
cat("\nInterpretation:")
cat(sprintf("\n- Lowest jitter (CV): %.4f", golden$mean_jitter_cv))
cat(sprintf("\n- Fastest convergence: %.1f ticks", golden$mean_convergence_rate))
cat(sprintf("\n- Settling time: %.1f ticks", golden$mean_settling_time))
cat(sprintf("\n- Recommendation: Use '%s' as golden configuration\n", golden$configuration))
```
---
## Execution Plan
### Phase 1: Implementation (3-4 hours)
1. Extend `DoeMetrics` struct with heartbeat columns
2. Implement `analyze_heartbeat_trajectory()` in `doe_metrics.c`
3. Capture snapshot data during heartbeat ticks
4. Update CSV schema
### Phase 2: Experiment Execution (2-4 hours)
1. Create `run_factorial_doe_with_heartbeat.sh` script
2. Run 5 elite configurations × 50 runs each = 250 total runs
3. Collect heartbeat + performance data
### Phase 3: Analysis (2-3 hours)
1. Load CSV in R
2. Compute stability rankings
3. Generate visualizations
4. Identify golden configuration
---
## Expected Outcomes
**Primary Question:** Which of the 5 elite configurations exhibits:
- Lowest heartbeat jitter (CV)?
- Fastest convergence to steady state?
- Strongest load-response correlation?
- Cleanest temporal signature?
**Expected Winner:** Configuration with balanced F-factors, likely:
- F1=1 (heat tracking required)
- F3=1 or F5=1 (decay or inference, but not both)
- F6=0 or F6=1 (decay inference optional)
**Golden Configuration:** Becomes baseline physics for MamaForth & PapaForth downstream work.
---
## Success Criteria
✓ All 5 configurations build and run without segfault
✓ Heartbeat data collected for all 250 runs
✓ Stability rankings computed and visualized
✓ Golden configuration identified with p < 0.05 significance
✓ R analysis report generated with 5+ plots
---
**Version:** 1.0
**Status:** Ready for implementation
**Next Step:** Implement heartbeat metrics capture and extended DoE script