The whole lesson in one breath
Paras has a file — tracking/DECISIONS.md — that is the memory of every choice the system must never re-argue. Each entry is numbered (D-001, D-002, ... up to D-094), dated, and carries its rationale. They are LOCKED: a build session does not get to relitigate them, and the only way to reverse one is a new dated entry that explicitly supersedes the old (the old text is annotated, never deleted). This lesson walks the load-bearing ones, grouped by what they protect — architecture, the AI boundary, data, model-research, and operations — so that for each you understand the choice, the reason, and the cost if it were undone. Hold these and you hold the spine of the system.
You're building Paras solo, leaning hard on AI to move fast. That speed is the whole point — and it's also the danger. An eager assistant, left to its own judgment, will quietly re-open the same questions every session and let the answers drift, until a thousand small 'reasonable' edits have turned the system into something else. DECISIONS.md is the antidote. Its own header is blunt: 'Do NOT relitigate these inside build sessions.' And CLAUDE.md gives the operating rule: 'If a build request conflicts with a locked decision, stop and flag it rather than silently complying.' This page is your map of the decisions that matter most, so you can recognize when one is being violated — and say so.
A 'decision' here is not a code change. It is a durable choice about HOW the system works that you never want to argue twice: 'all three apps are WPF,' 'the kernel is a pure library,' 'no LLM in any order path,' 'Topstep rule values live in config, never as constants.' We'll take them in five groups, in roughly the order they shape the system: (1) ARCHITECTURE — the bones; (2) the AI BOUNDARY — what the machine is and is not allowed to do; (3) DATA — the ground truth everything stands on; (4) MODEL & RESEARCH — how edges are found honestly; (5) OPERATIONS — how it's run, graded, and kept alive. For each, the choice, the why, and the consequence of reversal.
How to read a D-entry (and why the format matters)
Every entry has the same skeleton: a number (D-0xx), the decision in one line, the source it traces to (a doc section or a Constitution Principle), and a dated rationale. The number is permanent — code reviews and other decisions cite it. The date lets you reconstruct history. The source means a decision is never free-floating opinion; it descends from a spec or a Principle. When you see 'supersedes D-070' (as D-080 does), that is the reversal mechanism working correctly: dated, explicit, traceable — never a silent rewrite.
GROUP 1 — ARCHITECTURE: the bones. These five decisions fix the shape of the system. Everything else is built inside the box they draw. The keystone is D-001: there is ONE shared C# kernel; SENTINEL backtests it and AXIOM trades it — so the code that trades IS the code that backtests. That single choice is what makes a backtest result mean anything: if the live system ran different code, your backtest would be measuring a system you'll never actually trade. D-003 protects it by keeping the kernel a PURE library — no venue SDKs, no HTTP, no UI, no LLM, no Topstep values, no wall-clock reads (the clock is injected). Purity is what lets the same kernel run identically in a backtest, a parity court, and live.
Principle 3D-001 · One shared kernel
SENTINEL backtests the kernel; AXIOM trades the kernel. The code that trades is the code that backtests. Reverse it and your backtest measures a system you never actually run — every result becomes a guess.
the shapeD-002 · Three apps, named Paras
PULSE (tray monitor) + SENTINEL (research) + AXIOM (execution). Three jobs, three apps, one kernel. Separation of concerns by construction.
docs/01 §7D-003 · Pure kernel
No venue SDKs, HTTP, UI, LLM, Topstep values, or wall-clock in the kernel — the clock is injected. Reverse it and the kernel can no longer run identically in backtest, parity court, and live — parity dies.
concurrencyD-004 · Process isolation default
Process isolation for work; threads only over immutable/mmap data; UI on its own dispatcher. The default that prevents shared-state corruption between the plant, the engines, and the UI.
supersedes D-073/docs02D-084 · All three apps are WPF
PULSE, SENTINEL, AXIOM are all Windows WPF (.NET 8). The Next.js/React design output is a UI reference prototype only, never a runtime dependency. Supersedes the old 'AXIOM stays WinUI 3' / 'SENTINEL = Next.js' lines — one UI stack is the right solo-operator simplification.
GROUP 2 — THE AI BOUNDARY: what the machine is allowed to do. This is the most important group for a system whose whole pitch is 'AI-automated.' The line is absolute and it is drawn at D-005: NO LLM in any order path; the AI sidecar can only veto, narrate, resist, or reflect — never approve, place, size, or modify. The runtime AI's only power is to say NO. Why so strict? Because LLMs are reasoners and veto filters, never forecasters or order managers (Principles 4–5). An LLM that could place or size an order would be a non-deterministic component in the one place — the order path — where you need provable, repeatable behavior. The consequence of reversing this is catastrophic: a hallucination could become a live trade.
| Decision | What it locks | Why — and the cost of reversing it |
|---|
| D-005 | No LLM in any order path; sidecar may only veto/narrate/resist/reflect. | LLMs are reasoners, not forecasters or order managers (P4–P5). Reverse it and a hallucination could place a live trade — the order path must be deterministic. |
| D-050 | Two AIs, two clocks: Claude (research-time, $0 marginal) proposes; local Ollama sidecar (runtime) can only say no. | Separates the 'thinking' AI from the 'trading' moment. The runtime AI has zero authority and costs $0 at the margin (local Ollama only). |
| D-067 | Gemma verdict is schema-constrained JSON enforced at the decoder level; any failure coerces to NEUTRAL, never a retry-loop; the verdict is read-only advisory with zero authority. | A malformed or stalled model can never block or distort execution. GO-class verdicts carry no permissive power — the LLM cannot approve anything. |
| D-068 | Reflections are local, $0, injected as read-only context — and NEVER feed a parameter, filter, threshold, gate, size, or entry. Behavior changes go through G0–G6. | Stops the 'AI learned something overnight and changed how we trade' failure. Adaptation must pass full gates, not leak in through a reflection. |
| D-069 | External-framework adoption policy + standing DO-NOTs: no LLM order/sizing authority ever; no bar-level LLM calls (session cadence is the runtime ceiling); zero new API token spend at runtime. | Caps both the authority and the cost of runtime AI. A step that 'needs' a cloud model at runtime is, by definition, a wrong step. |
The one sentence that governs the whole AI boundary
From D-067/D-068 and the standing risk T-06: 'No verdict- or reflection-derived value may reach execution, sizing, filters, or gates — LLM outputs are read-only advisory context.' This is the wall. The AI can narrate, it can warn, it can refuse — but it cannot touch a number that affects a trade. Every time you see an AI feature proposed, the first question is: does any of its output reach a behavior? If yes, it's wrong as designed, no matter how clever it is.
GROUP 3 — DATA: the ground truth. Every backtest, every indicator, every decision stands on the bars in the vault. So the data decisions are about provenance and integrity. D-010 makes TradeStation the primary source (free, deepest history). D-011 stores M1 from 2008 so stress regimes (2008, COVID) are in-sample. D-012 is the discipline that prevents silent corruption: ALL intermediate timeframes (M5/M15/H1...) are DERIVED from canonical M1 by one consolidator — never extracted separately. If you pulled M5 separately, it could silently disagree with the M1 it should aggregate to, and you'd never know which was right (Principle 7: one source of truth per concern). The most recent and most important data decisions, though, came from a hard lesson during the M1 soak.
1
D-081 · Accept-and-gate the deep history
2008–2020 M1 has ~25% of days missing >2% of minutes — but this is TradeStation's actual coverage sparsity, NOT an engine bug (the same QualityEngine yields 97–99% clean on 2022+). Decision: keep it, flag faulty days via the data_quality table, do NOT re-backfill blindly. Revisit only if a second-source audit shows the gaps are recoverable AND a pre-2021 family needs them.
2
D-092 · Databento fill ABANDONED — sources are in different price frames
The free cost-check passed, but a 5-cent sample audit revealed TradeStation continuous (@ES/@CL/@GC) is BACK-ADJUSTED while Databento (*.c.0) is RAW/unadjusted — a near-constant per-symbol offset (@ES +529.5, @CL -21.31, @GC +376). Co-mingling would splice a ~530-700pt discontinuity at the join: a corrupt series violating P3 (parity) and P7. Hard STOP at Gate 1; recorded FAIL, no fill, ~$0.06 spent.
3
D-093 · The correct architecture — RAW is canonical, back-adjusted is DERIVED
Lock: RAW unadjusted bars are the immutable ground truth (like M1); the back-adjusted series is a DERIVED, versioned, frozen, reproducible transform from raw + a frozen roll schedule (exactly as M5/H1 derive from M1). Both frames stored and provenance-tagged. NEVER co-mingle vendors. This is why: TradeStation's back-adjustment is opaque and MUTABLE — it silently re-shifts historical prices on every roll, a determinism hazard. Own the adjustment yourself.
4
D-094 · Asset-class-agnostic market model — a HARD RULE
Found during the soak: one CME-equity calendar applied to all symbols over-closed the market (Juneteenth + an evening-skip rule pushed the close to Sunday when the market actually reopened Thursday afternoon). Lock: session geometry, calendars, and bar-expectation logic MUST be per-instrument and asset-class-aware — so US equities, FX, and crypto can be added by a config profile, never a rewrite. No CME literal may live in shared session/calendar/quality code.
Why D-092/D-093 are a textbook 'kill it cleanly' moment
The data team wanted deep history. The honest path didn't fight for it — it ran the cheap free check, then a 5-cent sample, found the two sources fundamentally incompatible, and STOPPED at the first gate rather than splice a corrupt series to get the result they wanted. That recorded FAIL (D-092) is the Constitution's 'honest discovery over impressive results' in miniature. And it produced the better answer (D-093): don't borrow someone else's adjusted prices — own your own adjustment from raw, deterministically. A reversal here would re-introduce exactly the silent ~530-point discontinuity the audit caught.
GROUP 4 — MODEL & RESEARCH: how edges are found honestly. This group exists to stop the single most common way trading research lies to itself — torturing data until something looks profitable. D-031 is the gatekeeper: G0 requires a stated one-sentence MECHANISM — no mechanism, no run; pure pattern-mining is BANNED. D-030 makes every run a counted trial against a pre-registered budget, with re-rolls facing a higher hurdle (DSR), and that budget gate is CODE, not Claude. D-020/D-021 give you the two-speed engines and the three-engine parity court (kernel / TradeStation EasyLanguage / LEAN) where an unexplained delta is a STOP-EVERYTHING event. And D-087 makes 'the code that trades is the code that backtests' concrete at the feature level while explicitly DROPPING the seductive 'compose combos and see what works' idea.
| Decision | What it locks | Why it matters |
|---|
| D-031 | G0 demands a one-sentence mechanism — no mechanism, no run. Pure pattern-mining is banned. | Pattern-mining finds noise that looks like signal. A required mechanism forces a real economic 'why' before any compute is spent. |
| D-030 | Gate ladder G0→G6; every run is a counted trial vs a pre-registered budget; re-rolls face a higher DSR hurdle; the budget gate is code. | Counting trials is how you stay honest about multiple testing — the more you try, the higher the bar to call something real (Principle 2). |
| D-021 | Three-engine parity court: kernel / TradeStation / LEAN. An unexplained delta is STOP-EVERYTHING. | Three independent implementations agreeing is strong evidence the result is real and not a single-engine artifact (G4). |
| D-032 | Holdout months are frozen and opened exactly once, at G5. | A holdout you can peek at isn't a holdout. Opening it once is the only honest out-of-sample test. |
| D-087 | Feature-cache approved with guardrails (cached==uncached byte-for-byte; populated by the kernel's incremental walk, no look-ahead); combo-search REJECTED. | Speed without changing results. Combo-search is rejected because it violates D-031 (no mechanism) and Principle 2 (every trial counted). Model ideas enter via G0–G6 with no special status. |
GROUP 5 — OPERATIONS: how it's run, graded, and kept alive. These decisions are about the system staying trustworthy day to day. D-040 keeps Topstep rule values as versioned config (config/topstep-rules.json), re-checked WEEKLY (D-063) — never as constants — so a rule change is a config edit that activates at the next pre-flight, never a code change. D-041/D-042 lock the safety rails: automation only on Combine/Express (hard-blocked on Live Funded), no VPS/VPN, no manual order entry in AXIOM, config immutable during market hours, and the only 'override' opens a Gemma chat that can grant nothing. D-071 is the continuity doctrine — nightly VERIFIED backups, a drilled restore path ('a backup that has never been restored is a hope, not a backup'). And two decisions changed how the whole project is built and graded.
Principle 9D-040 / D-063 · Topstep rules are config
Rule values live in config/topstep-rules.json, re-verified WEEKLY against the live rulebook, and treated as RiskConfig changes that activate at the next pre-flight — never mid-session, never as code constants (Principle 9).
docs/03 §3.1D-042 · Hard execution locks
No manual order entry in AXIOM; config immutable during market hours; cooling-off staging; the only 'override' opens a Gemma chat that can grant nothing. The fortress only says no.
docs/09 · R-08D-071 · Continuity doctrine
Nightly VERIFIED backup to a second disk + weekly offline copy + git for text; restore drilled monthly; no absolute paths or machine assumptions in code. 'A backup that has never been restored is a hope, not a backup.'
supersedes D-070D-080 · ultracode-xHigh + independent grading
Maximum-effort Workflow on every substantive task (no opt-out); gates graded by independent auditor subagents in separate contexts — never by the author. Supersedes D-070 (Fable retired). The author never grades their own gate.
one datastoreD-072 · PostgreSQL declined
DuckDB remains the ONLY datastore; the operator's local PostgreSQL is not used by Paras. No new infra dependency without a superseding entry (Principle 7).
namingD-091 · The DataPlant is named
The always-on ingestion process (Sponaitech.Sentinel --run) is the 'Paras DataPlant' — the single DuckDB writer. Distinct from the on-demand SENTINEL research dashboard and the read-only PULSE tray watcher.
The model reversal: D-070 → D-080 (how a lock is undone correctly)
D-070 originally said 'Fable 5 grades every gate' (a two-model build protocol). When Fable was retired from public use, the team did NOT quietly delete D-070. They wrote D-080, dated 2026-06-15, stating it 'supersedes D-070,' and re-routed grading to independent auditor subagents (phase-gatekeeper, test-sentinel, constitution-guardian, design-reviewer, parity-auditor) run in separate contexts. The old entry stays, annotated as superseded. That is the only legal way to reverse a lock — and it preserves the deeper invariant (ULTRACODE U4: the author never grades their own gate) that mattered more than the specific tool.
WHY THIS WHOLE FILE EXISTS — the deepest reason. Constitution Principle 11 says: 'The system adapts by saying no more often — never by quietly becoming a different system. Live params are immutable; adaptation = suppression, retirement, and new pre-registered hypotheses through full gates.' DECISIONS.md is the memory that makes Principle 11 enforceable. Without it, a solo operator and an eager AI would re-open settled questions every session and drift. With it, you can trust that the system you designed last month is the system running today — and that any change is dated, sourced, and traceable. The file is not bureaucracy; it is the thing that keeps Paras honest about its own identity.
Watch-outs — how a locked decision gets violated in practice
1) A request re-argues a settled choice ('let's just have the AI size the position this once') — that's a D-005/D-067 violation; STOP and cite the D number. 2) A 'reversal' that just edits the old D-entry's text instead of writing a new dated superseding entry — history is being rewritten; that's not allowed. 3) A Topstep value appearing as a constant in code instead of config — D-040 violation. 4) A second process opening the DuckDB vault, or PostgreSQL creeping in — D-072/D-073 violation. 5) Any LLM output reaching a parameter, filter, gate, or size — the AI-boundary wall (D-067/D-068) is breached. 6) A 'fill the deep history from Databento' suggestion — that path is closed (D-092); the correct architecture is D-093.
What to remember
DECISIONS.md is the system's spine: numbered, dated, sourced choices that are never relitigated, only superseded by a new dated entry. ARCHITECTURE: one pure kernel, three WPF apps (D-001/D-003/D-084). AI BOUNDARY: the runtime AI can only say no — no LLM output ever reaches a trade (D-005/D-067/D-068). DATA: raw is canonical, back-adjusted is derived, never co-mingle vendors, market model is per-instrument (D-093/D-094). RESEARCH: no mechanism no run, every trial counted, parity is sacred (D-031/D-030/D-021). OPS: Topstep rules are config, backups are verified, the author never grades their own gate (D-040/D-071/D-080). When a request conflicts with one of these, the correct move is always the same: stop, name the D number, and flag it.
What to stay aware of
- DECISIONS.md is never relitigated in a build session. If a request conflicts with a locked D-entry, the correct move is to STOP and flag it, citing the D number — not to silently comply (CLAUDE.md).
- A lock is only reversed by a NEW dated entry that explicitly says it supersedes the old; the old text is annotated, never deleted. An edit to the old entry's text is a history rewrite and is not allowed (see D-070 → D-080).
- The AI boundary is absolute: no verdict- or reflection-derived value may reach execution, sizing, filters, or gates (D-067/D-068, risk T-06). If any LLM output touches a trade-affecting number, the feature is wrong as designed.
- Topstep rule values are config, re-verified WEEKLY, never code constants (D-040/D-063). A Topstep number appearing as a literal in code is a violation.
- DuckDB is the ONLY datastore (D-072) and the DataPlant is its single writer (D-091); a second process opening the vault, or PostgreSQL creeping in, is a violation.
- Deep-history 'fill from Databento' is a closed path (D-092) — the sources are in different price frames. The correct architecture is D-093: raw is canonical, back-adjusted is a derived, frozen, reproducible transform; never co-mingle vendors.
- The market model must be per-instrument and asset-class-agnostic (D-094) — no CME literal in shared session/calendar/quality code, so US equities/FX/crypto can be added by config, not a rewrite.
- Research stays honest by construction: no mechanism, no run (D-031); every run is a counted trial against a pre-registered budget (D-030); the holdout opens exactly once at G5 (D-032); a parity delta is STOP-EVERYTHING (D-021).
- The author never grades their own gate — gates are graded by independent auditor subagents in separate contexts (D-080, ULTRACODE U4).
Locked decisions & the why
D-001One shared C# kernel; SENTINEL backtests it and AXIOM trades it — the code that trades is the code that backtests.
Why: Parity by construction (Principle 3). If live ran different code from the backtest, every backtest result would be measuring a system you never actually trade — results would be meaningless. This is the architectural keystone.
D-003The kernel is a pure library — no venue SDKs, HTTP, UI, LLM, Topstep values, or wall-clock reads; the clock is injected.
Why: Purity is what lets the identical kernel run in a backtest, the three-engine parity court, and live without behavioral difference (docs/01 §7). Reverse it and parity (D-021) and determinism die.
D-005No LLM in any order path; the AI sidecar may only veto/narrate/resist/reflect — never approve, place, size, or modify.
Why: LLMs are reasoners and veto filters, never forecasters or order managers (Principles 4–5). The order path must be deterministic; an LLM there means a hallucination could become a live trade. This is the central AI-boundary line.
D-067The Gemma verdict is schema-constrained JSON enforced at the decoder level; any failure coerces to NEUTRAL (never a retry-loop); the verdict is read-only advisory with zero authority — GO-class verdicts carry no permissive power.
Why: A malformed or stalled model can never block or distort execution, and the LLM can never approve anything. Any verdict→behavior mapping is deterministic versioned config that enters live paths only through G0–G6 (risk T-06).
D-068Session reflections are local ($0), injected next session as read-only context — and NEVER feed a parameter, filter, threshold, gate, size, or entry. Stored once in DuckDB (SQLite declined, Principle 7).
Why: Stops the 'the AI learned something overnight and silently changed how we trade' failure. Adaptation must pass full gates G0–G6, never leak in through a reflection (standing risk T-06).
D-031G0 requires a stated one-sentence mechanism — no mechanism, no run. Pure pattern-mining is banned.
Why: Pattern-mining finds noise that looks like signal; a required economic 'why' before any compute is the first honesty filter. Paired with D-030 (every run is a counted trial vs a pre-registered budget, DSR hurdle rises with re-rolls), it is how the research stays honest about multiple testing (Principle 2).
D-021Three-engine parity court (kernel / TradeStation EasyLanguage / LEAN QCAlgorithm); an unexplained delta is a STOP-EVERYTHING event.
Why: Three independent implementations agreeing is strong evidence a result is real and not a single-engine artifact (G4, docs/01 §6). A determinism/parity mismatch is never a flaky test — it halts everything.
D-092Databento deep-history fill ABANDONED — TradeStation continuous bars are BACK-ADJUSTED while Databento is RAW/unadjusted (near-constant offsets: @ES +529.5, @CL -21.31, @GC +376). Hard STOP at Gate 1; recorded FAIL, no fill, ~$0.06 spent.
Why: Co-mingling the two would splice a ~530–700pt discontinuity at the join — a corrupt, untradeable series violating P3 (parity) and P7 (one source of truth per bar). A textbook 'kill it cleanly' moment: ran the cheap checks, found the incompatibility, stopped honestly rather than fake a clean fill.
D-093Data-frames architecture LOCKED: RAW unadjusted bars are canonical and immutable; the back-adjusted series is a DERIVED, versioned, frozen, reproducible transform from raw + a frozen roll schedule. Both frames stored, provenance-tagged; never co-mingle vendors.
Why: TradeStation's back-adjustment is opaque and MUTABLE — it silently re-shifts historical prices on every roll, a reproducibility/determinism hazard for a system built on cached==uncached and parity. Owning the adjustment yourself (like M5/H1 derive from M1, D-012) restores determinism and lets you test any model type, not just indicator/regime.
D-094Market-model architecture must be asset-class-agnostic and per-instrument — a HARD RULE. Session geometry, calendars, and bar-expectation logic resolve per-instrument via a market profile so US equities, FX, and crypto can be added by config, never a rewrite. No CME literal in shared session/calendar/quality code.
Why: Found during the M1 soak: one CME-equity calendar applied to all symbols over-closed the market (Juneteenth + an evening-skip rule pushed the close to Sunday when the market actually reopened Thursday afternoon). The fix is a design law that future-proofs the system for new asset classes (motivating evidence + risk R-09).
D-040Topstep rule values are versioned config (config/topstep-rules.json), re-checked WEEKLY (D-063) and treated as RiskConfig changes that activate at the next pre-flight — never as code constants, never mid-session.
Why: Constitution Principle 9. A prop-firm rule change must be a config edit the operator can verify against the live rulebook, not a code change buried in a build. Constants would make rule drift invisible and dangerous to a live account.
D-080OS-level default is ultracode-xHigh + Workflow on every substantive task (no opt-out); gates are graded by independent auditor subagents (phase-gatekeeper / test-sentinel / constitution-guardian / design-reviewer / parity-auditor) in separate contexts — never by the author. Supersedes D-070 (Fable retired).
Why: Preserves ULTRACODE U4 — 'the author never grades their own gate' — after the prior two-model protocol (D-070, Fable grades) became unworkable. It is also the model of a correct reversal: dated, explicit supersession, old entry annotated not deleted, deeper invariant preserved.
Sources: tracking/DECISIONS.md — header ('Do NOT relitigate these inside build sessions'; reversals require an explicit dated superseding entry) · tracking/DECISIONS.md — Architecture: D-001, D-002, D-003, D-004, D-084 (+ D-073 superseded clause) · tracking/DECISIONS.md — AI operations / boundary: D-005, D-050, D-051, D-052, D-067, D-068, D-069 · tracking/DECISIONS.md — Data plant + data-frames: D-010, D-011, D-012, D-015, D-081, D-088, D-092, D-093, D-094 · tracking/DECISIONS.md — Engines & validation + Gates & discipline: D-020, D-021, D-022, D-024, D-030, D-031, D-032, D-087 · tracking/DECISIONS.md — Execution & Topstep: D-040, D-041, D-042, D-043, D-044 (+ OS/tooling D-062, D-063, D-064) · tracking/DECISIONS.md — Execution protocol & continuity: D-070 → D-080 supersession, D-071, D-072, D-091 · CLAUDE.md — The Constitution (Principles 3, 4–5, 7, 9, 11) + Hard rules (no LLM in order path; Topstep values in config; pure kernel; no verdict/reflection value in execution) + 'never relitigate locked decisions'