Toolchain · 30 decisions across 7 layers
The toolchain,
and what it
ruled out.
A stack list without rejections is a list of things that were available. This is the record of decisions — what was selected at each layer of the corpus, and what was turned down for it. The reasoning is the part that survives when the specific tool is eventually replaced.
0
Selections on the record
0
Layers, boundary to boundary
0
Languages in production
0
Systems the stack has carried
01 — Languages
One per job, chosen at the boundary
The corpus runs nine languages in production. That is not eclecticism — each boundary was drawn where a measured cost justified crossing it.
-
Python
Modelling, pipelines, orchestrationChosen Every dependency that matters in machine learning and scientific computing ships wheels for it. It is where the ecosystem is, and arguing with that costs more than it saves.
Instead of Rewriting numerical stacks in a faster language is how you introduce bugs, not how you remove dependencies.
-
Rust
Application shells, real-time coresChosen Where a dropped frame is a defect. The terminal shell must stay responsive with a live feed attached, and a garbage-collected runtime cannot promise that.
Instead of Electron: proven at version one, and proven to have a ceiling once a chart surface, a terminal and a 3D view share a frame budget.
-
C++
Indicator hot pathsChosen Rolling volatility and channel extremes, bound in-process. The boundary is drawn at measured cost — everything else stays readable.
Instead of Rewriting whole strategies in C++ would make them faster and unmaintainable, and the strategies are not the bottleneck.
-
R
Econometric researchChosen Decades of statistical libraries with peer-reviewed implementations. It runs as a service so its process lifetime is nobody else’s problem.
Instead of Reimplementing time-series econometrics in Python to avoid a second runtime trades a dependency for a correctness risk.
-
JavaScript
InterfacesChosen Plain JavaScript with no transpilation where the surface is small. No bundler means no lockfile drift and nothing between the source and the browser.
Instead of TypeScript is used where a data model is shared across a team; it is overhead on a single-operator interface with no public API.
-
SQL · WGSL · Shell
Data, shaders, glueChosen Each is the native language of its layer. Querying through an ORM abstraction, or drawing through a wrapper, costs the thing you went there for.
Instead of Abstractions over SQL make the easy queries shorter and the hard ones impossible.
02 — Machine learning
Small trainable surface, strong pretrained base
Label scarcity is the binding constraint in every domain here, so the architecture is chosen to need as few labels as possible rather than to be as large as possible.
-
PyTorch + Lightning
TrainingChosen Lightning supplies loops, checkpointing and mixed precision for free at these model sizes, which is most of the boilerplate and none of the interesting part.
Instead of JAX was rejected on ecosystem friction with the geometry stack; TensorFlow on research reuse.
-
Self-supervised pretraining
Representation learningChosen Unlabelled sensor data is abundant and labelled data is measured in minutes. Pretraining first is the only route that respects that ratio.
Instead of Supervised training from scratch needs orders of magnitude more labelled data than any realistic study produces.
-
QLoRA on a small spine
Language generationChosen A compact instruction-tuned model with a low-rank adapter fits in consumer VRAM and trains in hours, not weeks.
Instead of Full fine-tuning of a large model buys fluency that was never the constraint, at a cost that was.
-
llama.cpp · quantised weights
ServingChosen Overnight batch work has no latency requirement, so CPU-capable inference removes a GPU from the production path entirely.
Instead of A GPU serving stack is the right answer for interactive inference and the wrong one for a nightly queue.
-
Retrieval before generation
Document systemsChosen Content is retrieved and ranked from a governed corpus before any prose exists. The corpus is the authority; the model is the writer.
Instead of Generation-first with citations attached afterwards produces fluent text and unverifiable claims.
03 — Estimation & geometry
Computed, never generated
Geometry, arithmetic and constraint satisfaction are solved by deterministic machinery. A language model that emits a coordinate is a language model producing a confident guess.
-
Factor-graph smoothing
Trajectory estimationChosen Heterogeneous constraints — odometry, heading, barometric floor, dock priors, loop closures — combine in one optimisation with principled uncertainty out the other side.
Instead of A filter processes measurements once and cannot revisit them; a smoother uses the whole shift, which is exactly what a batch pipeline can afford.
-
Learned heteroscedastic odometry
Motion modelChosen The network predicts displacement and its own uncertainty, so the optimiser knows which segments to trust.
Instead of A fixed noise model treats a confident stride and an ambiguous one identically, which corrupts the whole graph.
-
Deterministic vector rendering
Map outputChosen Maps render from a validated schema, so the geometry in the artifact is the geometry that was computed.
Instead of Raster or model-drawn output cannot be checked against its source, which makes it undisplayable under the evidence rule.
04 — Quantitative & trading
One implementation, live and historical
The seam between research and execution is where retail systems fail. Everything here is arranged so that seam does not exist.
-
Shared strategy objects
Research/execution parityChosen The identical strategy and risk-manager instances run in the live loop and in the backtester. There is no second implementation to drift.
Instead of A separate research implementation is faster to write and guarantees a divergence nobody notices until it costs money.
-
Event-driven replay
BacktestingChosen The engine cannot tell whether it is reading a live feed or a historical one, so anything a strategy cannot get from the event stream is something the backtest could not have known either.
Instead of Vectorised backtesting is fast and quietly permits lookahead that no live system could reproduce.
-
Layered conviction sizing
RiskChosen Position size is a function of a multi-factor conviction score under drawdown breakers and cooldowns.
Instead of Fixed fractional sizing treats a marginal setup and a strong one identically.
-
Kill switch · watchdog · auto-flatten
Operational safetyChosen The features that produce no return. An engine that dies must not leave a position open behind it.
Instead of Nothing. This layer has no acceptable alternative.
05 — Data & storage
Boring, typed, and priced for idle
Storage decisions are made against the cost model and the failure model, in that order. Both are more durable than any feature requirement.
-
PostgreSQL
Relational coreChosen Transactional, well understood, and rich enough that the interesting logic can live in queries rather than in application loops.
Instead of Document stores were rejected wherever the data is genuinely relational, which is nearly everywhere here.
-
A jobs table, not a broker
Work queuesChosen Row-level locking with skip-locked is transactional, observable in the same database as everything else, and one fewer service to operate.
Instead of A dedicated queue is correct at thousands of jobs an hour and unnecessary overhead at a hundred a night.
-
Serverless SQL with auto-pause
Scale-to-zero systemsChosen Chosen specifically for idle economics, accepting weaker native geospatial handling and filling the gap with a dedicated mapping service.
Instead of A richer geospatial engine that cannot pause breaks the cost model that justified the architecture.
-
Dataset and model versioning
ReproducibilityChosen Weights and the data that produced them are versioned together on zero-egress storage, so any published figure traces to an exact input.
Instead of Large-file versioning without dataset semantics stores the bytes and loses the lineage.
06 — Interfaces & delivery
Static where possible, native where necessary
The interface layer is chosen by what the surface actually has to do, which is usually far less than the default answer assumes.
-
Static generation
Sites and documentsChosen Content that changes when the author changes it does not need a server. Pages are generated from a data corpus at build time and served as files.
Instead of A CMS and a runtime add operational surface for content with one editor.
-
Queue and worker
Long jobsChosen Minute-scale analysis cannot live behind a request. Jobs enqueue, a worker drains, and transient failures re-queue rather than failing the user.
Instead of Synchronous request-response turns a rate limit into a lost job and a timeout into a support ticket.
-
Native GPU shells
Real-time desktopChosen Where a live chart, a terminal and a 3D view share one frame budget, the shell has to render through the platform graphics API.
Instead of A wrapped web runtime was measured against this requirement and failed it.
-
Model Context Protocol
Agent toolingChosen A new capability becomes a server rather than a fork. Slower for the first integration and dramatically cheaper by the tenth.
Instead of Bespoke integrations multiply, and each one is a place for behaviour to diverge.
07 — Discipline
What makes the rest of it checkable
The tools that produce nothing visible and prevent most of the expensive failures.
-
Typed I/O boundaries
CorrectnessChosen Validation at the edges of every pipeline stage, so a source that changes shape fails loudly at ingestion rather than silently at the model.
Instead of Trusting upstream schemas is how a pipeline learns the sensor instead of the task.
-
Structured logging
OperabilityChosen Logs that can be queried rather than read. A long pipeline will fail partway through, and the question is always which record and which stage.
Instead of Printed strings are unusable at the point you actually need them.
-
Property-based testing
Signal and geometry codeChosen Invariants over generated inputs catch the edge cases that hand-written examples do not, which is most of them in DSP and closure code.
Instead of Example-based tests confirm the cases the author already thought of.
-
Resumable stages
PipelinesChosen Every stage re-runnable without corrupting what came before, because rate limits, layout changes and exhausted quotas are certainties.
Instead of Designing for a clean single pass produces a pipeline that is nursed rather than operated.
The rule underneath all of it
Every boundary here was drawn
at a measured cost.
None of these are permanent. They are the current answers, each with the reasoning attached, so that when one stops being right the replacement is an argument rather than a preference.