// Moved from docs/src/internal/PHYSICS_IMPLEMENTATION_STATUS.adoc to docs/working/scratch/src/internal/PHYSICS_IMPLEMENTATION_STATUS.adoc on 2026-06-16 (docs reorg Phase 2) = Physics Engine Implementation Status: POSIX vs L4Re Porting Strategy :toc: left :toclevels: 2 xref:../README.adoc[← Back to Documentation Index] == Executive Summary **Good News**: The word execution hooks are **already wired**. The `physics_metadata_touch()` calls are in place at both: 1. **Outer interpreter** (`src/vm.c:533`) - for primitive word execution 2. **Colon word executor** (`src/vm.c:456`) - for nested word calls **Current Status**: Phase 1 infrastructure is complete, but the **POSIX/L4Re abstraction needs refinement** to follow the existing porting strategy (currently mixing `#ifdef` inline, should use vtable pattern like `platform_time.h`). --- == What's WIRED NOW ✅ === Execution Hook Points (Already Called) Each word execution updates physics metadata: [source,c] ---- // Outer interpreter (vm.c:533) - direct word execution entry->func(vm); physics_metadata_touch(entry, entry->entropy, sf_monotonic_ns()); // Colon word executor (vm.c:456) - nested word calls w->func(vm); physics_metadata_touch(w, w->entropy, sf_monotonic_ns()); ---- Both paths update: - `temperature_q8` - via exponential moving average from entropy - `last_active_ns` - monotonic timestamp of last execution - Already integrated with profiler hooks (`profiler_word_enter/exit`) === Dictionary Initialization [source,c] ---- // dictionary_management.c - when words are created physics_metadata_init(entry, header_bytes); physics_metadata_apply_seed(entry); // Pre-seed hotwords ---- Seeds 20 high-impact words (IF, LOOP, EMIT, BLOCK, SAVE-BUFFERS, etc.) with domain knowledge from `src/physics_metadata.c`. === Analytics Heap & Host Snapshots [source,c] ---- // main.c - startup/shutdown physics_runtime_init(size_t bytes); // 10 MiB default physics_runtime_shutdown(); // Called on demand (not automatic yet) physics_host_snapshot(&snapshot); // Captures scheduler state physics_analytics_publish_event(...); // Publishes to ring buffer ---- --- == What's INCOMPLETE ⏳ === 1. POSIX/L4Re Abstraction Pattern **Problem**: Architecture differs from established porting strategy. **Current Code** (`src/physics_runtime.c`): Inline conditionals throughout: ---- #if !defined(__l4__) snapshot_posix(); // ~90 lines, comprehensive #endif #ifdef __l4__ snapshot_l4re(); // ~15 lines, STUBBED #endif ---- **Comparison: Platform Time Pattern** (`include/platform_time.h`): Uses vtable with separate backend implementations: ---- include/platform_time.h ├─ sf_time_backend_t vtable ├─ extern const sf_time_backend_t sf_time_backend_posix; ├─ extern const sf_time_backend_t sf_time_backend_l4re; └─ sf_time_init() [selects backend at runtime] src/platform/linux/time.c [POSIX implementation] src/platform/l4re/time.c [L4Re implementation] ---- **Verdict**: Physics runtime should follow same pattern for: - Clear separation of platform concerns - Parallel development (platform teams work independently) - Testability (POSIX fully testable without L4Re headers) - Governance alignment (matches existing architecture) === 2. Periodic Host Snapshot Capture Currently `physics_host_snapshot()` is **defined but never called automatically**. Missing: - No heartbeat mechanism to invoke snapshots - No events published to analytics ring buffer - Analytics heap is allocated but unused === 3. Temperature Decay Model Currently `temperature_q8` is updated on execution but **never decayed**. Missing: - Exponential moving average with configurable half-life - Cooling logic for inactive words - No age-based eviction strategy --- == POSIX Side Completeness ✅ === What Works Today [cols="1,2",options="header"] |=== |Signal |Implementation |CPU count |`sysconf(_SC_NPROCESSORS_ONLN)` ✅ |Scheduler policy |`sched_getscheduler(0)` ✅ |Scheduler priority |`sched_getparam()` ✅ |Time quantum |`sched_rr_get_interval()` ✅ |Load average |`getloadavg()` (GNU extension) ✅ |PSI metrics |`/proc/pressure/{cpu,io,memory}` ✅ |/proc/stat jiffies |CPU total & idle counters ✅ |cgroup v2 |`cpu.stat` and `memory.current` ✅ |Flag bits |Advertise which sources populated ✅ |=== === Graceful Degradation The POSIX implementation is **well-defended**: - `getloadavg()` - guarded by `_GNU_SOURCE` - PSI files - `read_psi_file()` returns 0 if unavailable (kernel <4.20) - cgroup v2 - `resolve_cgroup_path()` returns -1 gracefully - All missing metrics result in `flags = 0` for that category **Verdict**: POSIX path is **production-ready** and **robust against missing procfs interfaces**. --- == L4Re Side Status ⏳ === Current Implementation (Stub) From `src/physics_runtime.c:487-500`: [source,c] ---- #ifdef __l4__ static int snapshot_l4re(physics_host_snapshot_t *out) { memset(out, 0, sizeof(*out)); out->backend = PHYSICS_HOST_BACKEND_L4RE; out->monotonic_time_ns = sf_monotonic_ns(); // ✅ works (via platform_time) out->realtime_ns = sf_realtime_ns(); // ✅ works (via platform_time) l4_kernel_info_t *kip = l4re_kip(); (void) kip; out->cpu_count = 1u; // ❌ TODO: query processor count from KIP out->backend_seq = ++g_runtime.backend_seq; return 0; } #endif ---- === What Could Be Added **KIP Queries** (via `l4re_kip()`): [source,c] ---- l4_kernel_info_t *kip = l4re_kip(); out->cpu_count = l4_kip_nr_cpus(kip); // once API exposed ---- **Scheduler Info** (via `l4_scheduler_info()`): [source,c] ---- l4_sched_param_t params; l4_scheduler_info(L4_MYSELF, ¶ms); out->scheduler_quantum_ns = params.quantum; out->scheduler_priority = params.prio; ---- **RTC Synchronization**: Already integrated in `src/platform/l4re/time.c` ✅ **IO Server Capabilities** (vbus_storage, ahci_chan): Future phases --- == Recommended Refactoring: Vtable Pattern To align with the **existing porting strategy**, refactor physics snapshot to use the vtable pattern: === New File Structure [source] ---- include/physics_runtime.h [unchanged - public API] src/physics_runtime.c [refactored] ├─ physics_analytics_header_t [unchanged] ├─ physics_runtime_state_t [unchanged] ├─ analytics_heap_allocate() [unchanged] ├─ physics_analytics_publish_event() [unchanged] ├─ typedef physics_snapshot_backend_t [NEW vtable] ├─ extern const physics_snapshot_backend_t physics_snapshot_backend_posix ├─ extern const physics_snapshot_backend_t physics_snapshot_backend_l4re └─ physics_host_snapshot() [NEW dispatcher] src/platform/linux/snapshot.c [NEW - POSIX backend] ├─ parse_avg_milli() ├─ read_psi_file() ├─ read_proc_stat_totals() ├─ resolve_cgroup_path() ├─ read_cgroup_cpu_usage_us() ├─ read_cgroup_memory_current() └─ snapshot_posix_impl() src/platform/l4re/snapshot.c [NEW - L4Re backend] ├─ snapshot_l4re_impl() └─ [Future: KIP, scheduler queries] ---- === Benefits 1. **Separation of Concerns**: POSIX code doesn't pollute L4Re builds (and vice versa) 2. **Parallel Development**: Platform teams can work independently 3. **Testability**: POSIX path fully testable without L4Re headers/libraries 4. **Consistency**: Matches `platform_time.h` pattern already in codebase 5. **Extensibility**: Easy to add new backends (embedded, minimal, test harnesses) 6. **Documentation**: Clear boundaries make porting requirements explicit --- == Answers to Your Questions === Q1: Is the POSIX side fully wired such as emulation of KIP? ✅ POSIX side is **feature-complete** for what POSIX can measure:: - Uses appropriate POSIX APIs for everything (no fake/emulated KIP) - Gracefully handles missing procfs files (PSI, cgroup v2) - Well-integrated with scheduler and profiler ❌ There is **NO KIP emulation** (intentional and correct):: - No point creating fake KIP on POSIX - Each backend should use native APIs of its platform 🔴 Missing: **Periodic heartbeat** to actually call the snapshot function:: - Function is defined but never invoked - Need mechanism to capture host state periodically - Events should be published to analytics ring buffer === Q2: Clear division with overall porting strategy? 🟡 **Currently**: Inline `#ifdef` throughout physics_runtime.c:: - **Not** following platform_time pattern - Mixes platform-specific logic in same file - Makes L4Re development harder (can't test without L4Re headers) ✅ **Recommended**: Refactor to vtable + separate backend implementations:: - Follows platform_time.h pattern (already proven architecture) - Aligns with porting strategy (clear platform abstraction) - Enables independent platform development === Q3: What should we tackle for Option A (Wire Execution Counting)? ✅ Execution hooks are **already wired** - no action needed:: - Both outer interpreter and colon executor paths call `physics_metadata_touch()` - Temperature updates are calculated correctly - No changes needed to execution path 🟡 Need to add: **Periodic host snapshot capture**:: - Call `physics_host_snapshot()` on VM heartbeat - Publish events to analytics ring buffer - Can be added to REPL input loop or VM tick 🟡 Need to add: **Temperature decay model**:: - Exponential moving average with configurable half-life - Implement in `physics_metadata.c` alongside seed table - Test decay across multiple execution cycles 💡 **Recommendation**: Start POSIX-first, then mirror to L4Re:: 1. Verify temperature updates in tests (starforth_words_test.c) 2. Add periodic snapshot capture 3. Implement decay model 4. Refactor to vtable pattern once logic is proven --- == Summary: Execution Status by Component [cols="1,1,1,3",options="header"] |=== |Component |POSIX |L4Re |Status |Host snapshot |Comprehensive |Stub (1 CPU) |🟡 Needs platform abstraction |PSI metrics |Full (4.20+) |N/A |🟢 POSIX complete |Scheduler info |Via sched APIs |Via KIP |🟡 L4Re TODO |Execution hooks |Wired ✅ |Wired ✅ |🟢 COMPLETE |Metadata init |Wired ✅ |Wired ✅ |🟢 COMPLETE |Periodic capture |Not called |Not called |🔴 MISSING |Temperature decay |Calculated |Calculated |🟡 No decay logic |Profiler integration |Not wired |Not wired |🔴 MISSING |Analytics heap |Ready |Ready |🟢 COMPLETE |=== --- == Immediate Action Items For **Option A (Wire Execution Counting)**: 1. **Verify Temperature Updates Work** - Create test in `src/test_runner/modules/starforth_words_test.c` - Define word, execute N times, inspect `temperature_q8` - Verify EMA calculation is correct 2. **Add Periodic Host Snapshots** - Hook `physics_host_snapshot()` into REPL input loop or VM tick - Publish snapshots to analytics ring buffer - Verify events appear in heap dump 3. **Implement Temperature Decay** - Add exponential moving average with half-life - Implement in `physics_metadata.c` - Test decay behavior over multiple ticks 4. **Refactor to Platform Abstraction** (After proving logic works) - Create `include/physics_snapshot_backend.h` with vtable - Extract POSIX code to `src/platform/linux/snapshot.c` - Create stub for `src/platform/l4re/snapshot.c` - Update dispatcher in `src/physics_runtime.c` --- == References - Physics Scheduling Plan: xref:./PHYSICS_SCHEDULING_PLAN.adoc[PHYSICS_SCHEDULING_PLAN.adoc] - Physics Signal Map: xref:./PHYSICS_SIGNAL_MAP.adoc[PHYSICS_SIGNAL_MAP.adoc] - Platform Time Abstraction: `include/platform_time.h` (reference implementation) - Word Execution: `src/vm.c` (lines 456, 533, 507-533) - Physics Metadata: `src/physics_metadata.c`, `include/physics_metadata.h` - Physics Runtime: `src/physics_runtime.c`, `include/physics_runtime.h`