262 lines
8.8 KiB
Markdown
262 lines
8.8 KiB
Markdown
<!-- Moved from docs/04-quality/phase-tracking/phase-2-issues-identified.md to docs/working/archive/quality/phase-tracking/phase-2-issues-identified.md on 2026-06-16 (docs reorg Phase 2) -->
|
|
# Phase 2 Issues: Shrink/Grow, Decay Slope, Fixed-Point Violations
|
|
|
|
**Status:** Root cause analysis in progress
|
|
**Severity:** CRITICAL - Physics calculations violating hard rules
|
|
**Date:** 2025-11-08
|
|
|
|
---
|
|
|
|
## Critical Issue #1: Float/Double Violations (Hard Rule)
|
|
|
|
**Rule:** Only Q48.16 fixed-point math in StarForth physics. No doubles/floats. **ZERO exceptions.**
|
|
|
|
### Violations Found
|
|
|
|
#### File: src/doe_metrics.c (Metrics Extraction)
|
|
| Line | Code | Violation | Should Be |
|
|
|------|------|-----------|-----------|
|
|
| 88 | `float mhz = 0.0f;` | CPU freq to float | Q48.16 fixed-point |
|
|
| 134 | `100.0 * (double)cache_hits / (double)total_lookups` | % calculation as double | Q48.16 fixed-point ratio |
|
|
| 142 | `100.0 * (double)bucket_hits / (double)total_lookups` | % calculation as double | Q48.16 fixed-point ratio |
|
|
| 206-207 | `100.0 * (double)prefetch_hits / (double)prefetch_attempts` | % calculation as double | Q48.16 fixed-point ratio |
|
|
| 237 | `(double)stale_word_count / (double)word_count` | Ratio as double | Q48.16 fixed-point ratio |
|
|
| 238 | `(double)total_heat / (double)word_count` | Ratio as double | Q48.16 fixed-point ratio |
|
|
| 250-251 | `100.0 * (double)prefetch_hits / (double)prefetch_attempts` | % calculation as double | Q48.16 fixed-point ratio |
|
|
|
|
#### File: src/rolling_window_of_truth.c (Adaptive Shrinking)
|
|
| Line | Code | Violation | Should Be |
|
|
|------|------|-----------|-----------|
|
|
| 525 | `double capture_rate = ...` | Ratio as double | Q48.16 fixed-point ratio |
|
|
| 614-616 | `double growth_rate = (double)diversity_delta / (double)last_diversity` | Growth calculation as double | Q48.16 fixed-point ratio |
|
|
| 619 | `double threshold = (double)ADAPTIVE_GROWTH_THRESHOLD / 100.0` | Threshold as double | Q48.16 fixed-point |
|
|
|
|
#### File: include/doe_metrics.h (Struct Definition)
|
|
| Line | Field | Type | Should Be |
|
|
|------|-------|------|-----------|
|
|
| 56 | `cache_hit_percent` | `double` | `uint64_t (Q48.16)` |
|
|
| 58 | `bucket_hit_percent` | `double` | `uint64_t (Q48.16)` |
|
|
| 69 | `context_accuracy_percent` | `double` | `uint64_t (Q48.16)` |
|
|
| 72 | `window_diversity_percent` | `double` | `uint64_t (Q48.16)` |
|
|
| 75 | `decay_slope` | `double` | `uint64_t (Q48.16)` - **UNINITIALIZED** |
|
|
| 79 | `stale_word_ratio` | `double` | `uint64_t (Q48.16)` |
|
|
| 80 | `avg_word_heat` | `double` | `uint64_t (Q48.16)` |
|
|
|
|
**Impact:** Physics calculations contaminated with IEEE 754 floating-point. This affects:
|
|
- Shrinking decision accuracy
|
|
- Metrics comparability across runs
|
|
- Formal verification (Isabelle model doesn't include floating-point)
|
|
|
|
---
|
|
|
|
## Critical Issue #2: Decay Slope = 0.0 (Uninitialized)
|
|
|
|
**Location:** src/doe_metrics.c:216
|
|
|
|
```c
|
|
metrics.decay_slope = 0.0; // ❌ Hardcoded placeholder
|
|
```
|
|
|
|
### What Should It Be?
|
|
|
|
**Your statement:** "I kind of settled on `starting` at 2:1 for the slope and I don't know why that going ignored."
|
|
|
|
**Interpretation needed:**
|
|
- Does 2:1 mean `heat_at_start : heat_at_end = 2:1` (heat halved)?
|
|
- Should it be stored as Q48.16 ratio? (2:1 = 131072 in Q48.16 = 2 << 16)
|
|
- Or is it `decay_slope = (heat_start - heat_end) / time_elapsed` (rate)?
|
|
|
|
### Current Logic (Non-existent)
|
|
|
|
No tracking of:
|
|
1. Total dictionary heat at test START
|
|
2. Total dictionary heat at test END
|
|
3. Time elapsed during test
|
|
4. Calculation of slope as (heat_start - heat_end) / elapsed_time
|
|
|
|
### What Exists
|
|
|
|
```c
|
|
// In physics_metadata.c:164-203
|
|
void physics_metadata_apply_linear_decay(DictEntry *entry, uint64_t elapsed_ns)
|
|
{
|
|
// decay_amount = (elapsed_us * DECAY_RATE_PER_US_Q16) >> 16
|
|
// Individual words decay correctly, but aggregate isn't tracked
|
|
}
|
|
```
|
|
|
|
**Problem:** Individual word decay works, but we never capture:
|
|
- Dictionary heat snapshot at test start
|
|
- Dictionary heat snapshot at test end
|
|
- Calculate the actual observed slope
|
|
|
|
---
|
|
|
|
## Critical Issue #3: Adaptive Window Not Changing (Root Cause Analysis)
|
|
|
|
### Hypothesis 1: Pattern Diversity Never Plateaus ❌ (You don't buy this)
|
|
|
|
**Current Logic:**
|
|
```c
|
|
growth_rate = (current_diversity - last_diversity) / last_diversity
|
|
// Threshold = 1% (ADAPTIVE_GROWTH_THRESHOLD = 1)
|
|
// If growth_rate < 1% → shrink
|
|
```
|
|
|
|
**Your Challenge:** "Pattern diversity never plateaus - I don't buy it. Something isn't instrumented correctly."
|
|
|
|
**Likely Root Cause:** The diversity measurement itself may be wrong.
|
|
|
|
Looking at `rolling_window_measure_diversity()`:
|
|
```c
|
|
uint64_t unique_transitions = 0;
|
|
for each word in window:
|
|
if (current != prev_word):
|
|
unique_transitions++
|
|
return unique_transitions
|
|
```
|
|
|
|
This counts:
|
|
```
|
|
Execution: A B A C A D A E A F
|
|
Transitions: A→B, B→A, A→C, C→A, A→D, D→A, A→E, E→A, A→F = 9 unique transitions
|
|
```
|
|
|
|
**But:** If execution is `A B C D E F ... Z AA AB AC ...` (new patterns keep arriving), diversity grows forever.
|
|
|
|
**Question:** Is the test harness producing bounded or unbounded word sequences?
|
|
|
|
### Missing Instrumentation
|
|
|
|
Need to log EVERY 256 executions:
|
|
```
|
|
[Check #1]
|
|
total_executions = 512
|
|
current_diversity = 847
|
|
last_diversity = 0 (baseline)
|
|
growth_rate = undefined (first check)
|
|
|
|
[Check #2]
|
|
total_executions = 768
|
|
current_diversity = 852
|
|
last_diversity = 847
|
|
growth_rate = (852-847)/847 = 0.59% < 1% threshold
|
|
→ SHRINK: 4096 → 3072
|
|
|
|
[Check #3]
|
|
total_executions = 1024
|
|
current_diversity = 856
|
|
last_diversity = 852
|
|
growth_rate = (856-852)/852 = 0.47% < 1% threshold
|
|
→ SHRINK: 3072 → 2304
|
|
```
|
|
|
|
**Current State:** We have NO logging to see this sequence. `effective_window_size` always reads as 4096 at metrics extraction time.
|
|
|
|
---
|
|
|
|
## Critical Issue #4: Bidirectional Feedback (Shrink AND Grow)
|
|
|
|
**Architecture:** Currently UNIDIRECTIONAL
|
|
```
|
|
Pattern Diversity Measurement
|
|
↓
|
|
Growth Rate < 1%?
|
|
↓ YES
|
|
SHRINK
|
|
↓ NO
|
|
Do Nothing (never grow)
|
|
```
|
|
|
|
**Your Question:** "Does it shrink AND grow? Is there a driving metric and input into maybe a gauge study and inference?"
|
|
|
|
**Answer:** Currently NO. To make it bidirectional:
|
|
|
|
```
|
|
Loop #4 (Prefetch Accuracy) → Feedback Signal
|
|
↓
|
|
Loop #5 (Window Tuner)
|
|
↓
|
|
Measure: prefetch_accuracy at current window_size
|
|
↓
|
|
Binary Chop Logic:
|
|
IF accuracy improved:
|
|
→ Try shrinking more
|
|
IF accuracy degraded:
|
|
→ Grow back up
|
|
IF stable:
|
|
→ Hold current size
|
|
```
|
|
|
|
**Missing:** Loop #4 → Loop #5 wiring. Prefetch accuracy isn't feeding into window size decisions.
|
|
|
|
---
|
|
|
|
## Summary of Required Fixes
|
|
|
|
### IMMEDIATE (Blocking Phase 2 Validation)
|
|
|
|
1. **Add Instrumentation** to `rolling_window_check_adaptive_shrink()`
|
|
- Log diversity measurements every check
|
|
- Log growth_rate calculations
|
|
- Log shrink decisions and results
|
|
- **Capture:** When/why effective_window_size changes
|
|
|
|
2. **Clarify Decay Slope**
|
|
- What is "2:1 starting slope"? (ratio? rate? direction?)
|
|
- How should it be calculated? (total heat delta? per-word average?)
|
|
- How should it be stored? (Q48.16?)
|
|
|
|
3. **Fix Float/Double Violations**
|
|
- Replace all `double` calculations with Q48.16
|
|
- Update doe_metrics.h struct to use `uint64_t` instead of `double`
|
|
- Update doe_metrics.c to use fixed-point arithmetic
|
|
|
|
4. **Implement Decay Slope Extraction**
|
|
- Capture dictionary heat at test start
|
|
- Capture dictionary heat at test end
|
|
- Calculate slope: (heat_start - heat_end) / elapsed_time (in Q48.16)
|
|
- Store in metrics
|
|
|
|
### FOLLOW-UP (Phase 2 Architecture)
|
|
|
|
5. **Wire Loop #4 → Loop #5 Feedback**
|
|
- Prefetch accuracy as input to window tuning
|
|
- Binary chop to suggest grow/shrink/hold
|
|
- Bidirectional adaptation
|
|
|
|
6. **Implement Gauge Study**
|
|
- Track (window_size → accuracy) pairs
|
|
- Measure if shrinking actually improves prediction
|
|
- Adjust knobs based on observed trade-offs
|
|
|
|
---
|
|
|
|
## Questions for User
|
|
|
|
1. **Decay Slope:** What does "2:1 starting slope" mean?
|
|
- Is it `initial_heat : final_heat` ratio?
|
|
- Is it a decay rate (heat units per second)?
|
|
- Should it be stored as Q48.16?
|
|
|
|
2. **Adaptive Shrinking:** Should we add logging to see if shrinking is actually happening?
|
|
- Would help diagnose why metrics show 4096 always
|
|
- Can pinpoint if problem is measurement, calculation, or no shrinking
|
|
|
|
3. **Bidirectional Growth:** Should Loop #5 be wired now or after Phase 2 design validation?
|
|
- Need binary chop + prefetch feedback loop
|
|
- Or focus on fixing shrinking first?
|
|
|
|
---
|
|
|
|
## Validation Checklist (Once Fixed)
|
|
|
|
- [ ] All physics math uses Q48.16 only (no doubles/floats)
|
|
- [ ] doe_metrics.h struct updated to uint64_t
|
|
- [ ] Instrumentation logging shows shrinking happening
|
|
- [ ] decay_slope extracted and calculated correctly
|
|
- [ ] Test-03+ runs show varying rolling_window_width in metrics
|
|
- [ ] test-03+ runs show non-zero decay_slope
|
|
- [ ] Bidirectional tuning (grow + shrink) working
|
|
- [ ] Gauge study metrics captured
|