Skip to content

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.