Known technical debt
Accepted debt, recorded so it is paid deliberately instead of rediscovered.
Every entry states why the debt exists (the trade that was made), the risk of
ignoring it, the trigger that converts it into scheduled work, and the
protocol for paying it. Items here are not bugs: each one was examined and
left in place on purpose. Feature backlog lives in Roadmap;
architectural rationale lives in
Design decisions.
Run-loop mirror duplication
|
|
| What |
ExecutionEngine::run_ir_quantum and run_ir_interpret_quantum (src/runtime/src/engine_translate.cpp) duplicate ~115 lines of shared invariants: block-cache lookup, untranslatable-block handling, the quantum-exact yield, GDB interior-breakpoint single-step, and the raise_block_exception fault tail. |
| Why it exists |
Entity-model S9 added the universal interpret path as a deliberate mirror so the JIT arm stayed byte-identical (frozen hot-path guardrail). Extraction was judged riskier than duplication at the time. |
| Risk |
A fix to the shared logic applied to only one loop drifts the paths apart under SMP — the exact failure class smpschedaffinity04 exposed. Mitigated 2026-06-10: MIRROR WARNING comments at both loop heads name the shared invariants and demand fixes land in both. |
| Trigger |
The next bug whose fix touches the shared invariants in both loops, or a third consumer of the loop shape. |
| Protocol |
Extract a shared loop parameterised by a block-execution callback. Hot-path work: gate with JIT==Switch lockstep (byte-identical per-test RTEMS outcomes) and same-host back-to-back dhrystone before/after. |
Machine::build() size
|
|
| What |
One 435-line function (src/compose/src/machine.cpp:229) lowers the whole object graph: cores, clocks, AMBA bridges, RAM, peripherals, PnP placement, port wiring. |
| Why it exists |
The stages are sequentially dependent (bridges must exist before slave placement); the three passes over im.objects are deliberate phases, not accidents. |
| Risk |
Modification cost grows with each new composable concept; testing intermediate stages requires running the whole lowering. |
| Trigger |
Compose change velocity — the next two features that each have to thread state through build(). |
| Protocol |
Extract per-stage helpers with explicit intermediate types (e.g. the bridge table). Pure host-side assembly code; the normal fast suite is the gate. |
RTEMS result CSVs live in the tracked source tree
|
|
| What |
The sptests/smptests/fptests iterators write their result CSVs to tests/results/*.csv — tracked files — via harness::results_csv_path. Every local suite run dirties the working tree. |
| Why it exists |
The committed CSVs double as the recorded pass-rate baseline; writing in place was the shortest path to that record. |
| Risk |
Flaky single-test variations show up as spurious diffs; sessions must remember to git checkout -- tests/results/ before committing (this has already caused near-misses). |
| Trigger |
The next accidental commit of a flaky CSV, or the next baseline update. |
| Protocol |
Write run outputs to the build directory; keep the committed files as explicit read-only baselines the harness compares against (and update them only in deliberate baseline commits). |
GDB RTEMS layout offsets are hardcoded
|
|
| What |
src/runtime/include/tero/runtime/gdb_stub.hpp carries ~48 constexpr offsets into RTEMS 5 kernel objects (per-CPU envelope, thread object layout) for thread-aware debugging. |
| Why it exists |
Thread awareness is guest-OS vocabulary, not ISA — the coupling is documented at the declarations. The offsets were verified against DWARF for RCC 1.3.2 (RTEMS 5.3). |
| Risk |
An RCC/RTEMS upgrade silently breaks thread enumeration. Mitigated: try_read_rtems_threads degrades gracefully when the layout does not parse. |
| Trigger |
Any RCC toolchain or RTEMS version bump. |
| Protocol |
Re-derive the offsets from the new toolchain's DWARF and update the constants; the [gdb_stub] suite is the gate. |
Flat SystemBus dispatch; no address-translation cache
|
|
| What |
MMIO dispatch is a linear search over MmioRegions in bus::SystemBus; the AMBA AHB/APB model (bus::AmbaBus) is a descriptive overlay, not the dispatch path. There is no ATC/software-TLB. |
| Why it exists |
Declined twice with measurements (Decision 73): the RAM fast paths are RAM-typed (TSO atomics over Ram's buffer) and the JIT inlines a host-pointer RamWindow, so erased-interface dispatch buys nothing today. |
| Risk |
None measured at current peripheral counts; linear search is off the RAM fast path. |
| Trigger |
The SRMMU (roadmap P3) — an ATC then doubles as the software TLB — or a profile showing MMIO dispatch in the hot tail. |
| Protocol |
Route dispatch through MemorySpace/IMemoryAccess together with the MMU work, with the 1:1 perf gates of the post-MVP roadmap. |
Registry hands out mutable handles from const lookup
|
|
| What |
Soc::find_entity is const but returns IEntity* (mutable), using const_cast for the directly-owned fabric members (soc.cpp, the system_bus/ahb/apb returns). |
| Why it exists |
Entities are stateful by nature (a found UART is written to); a const/non-const accessor split ripples through IEntityRegistry and every plugin for no consumer benefit. The casts are commented at the site. |
| Risk |
Cosmetic const-correctness violation; no observed misuse. |
| Trigger |
Only if IEntityRegistry grows a second implementation where the distinction matters. |
| Protocol |
Accepted as-is. Recorded here so it is not "fixed" casually — changing the signature is an API break for plugins. |
TERO_OPCODE_HISTOGRAM is a compile-time flag
|
|
| What |
Per-instruction opcode counting in core::step is gated by a CMake option, an exception to the no-compile-flags rule. |
| Why it exists |
The counter increment sits in the per-instruction hot loop; a runtime gate would cost a branch per retired instruction in every build. The flag gates instrumentation cost, not behaviour. The I/O half of the old exception (CSV dump + env read in the engine destructor) was removed 2026-06-09 (Decision 74). |
| Risk |
None for guests; histogram builds are profiling-only (build-histogram/). |
| Trigger |
None — accepted permanently unless the instrumentation itself is removed. |
| Protocol |
n/a. |
Non-SPARC GDB single-step
|
|
| What |
With a GDB stub attached, interior-breakpoint single-step uses the SPARC switch oracle (core::step); a non-SPARC frontend runs whole blocks past interior breakpoints (entry breakpoints work). Documented at the gate in engine_translate.cpp. |
| Why it exists |
Single-step needs a per-instruction reference path; only SPARC has one (its switch oracle). The toy frontend validated the seam without needing one. |
| Risk |
None today — there is no non-SPARC production frontend. |
| Trigger |
The first real second frontend (ARM/RISC-V). |
| Protocol |
Either implement IArchitecture::reference_step for the new frontend or translate single-instruction blocks under the stub. |
Unresolved RTEMS test failures
|
|
| What |
GR712RC sptests hold at 182/190 (JIT == Switch byte-identical): sp18, spmrsp01, sptimecounter03 fail without a recorded root cause; sp04 is a known flake; GR740 N=1 additionally times out on spcontext01 (passes on GR712RC — timing-sensitive). |
| Why it exists |
Each remaining failure survived the campaigns that fixed the rest; they need individual diagnosis. |
| Risk |
These block the primary project metric (RTEMS pass rate). |
| Trigger |
Already eligible — highest-value correctness work available (see Roadmap and docs/testing/rtems-known-failures.md). |
| Protocol |
Per test: SIS oracle lockstep (scripts/lockstep_compare.py) to find the first divergence, then the usual fix + full-suite gate. |