aedaa5d11b
Drop the gitignore entries for both dirs; align the CLAUDE.md note from "git-ignored, local-only" to "git-tracked — committed while the cycle is live, removed (git rm) at cycle close". The durable record stays the ledger + git history; specs/plans are transient in the repo, present only for their own cycle.
156 lines
9.6 KiB
Markdown
156 lines
9.6 KiB
Markdown
# aura — project rules
|
|
|
|
aura is a "game engine for traders": a Rust framework **and** a playground to
|
|
author trading nodes, backtest them deterministically and massively in parallel,
|
|
compose them fractally, validate them (sweep / Monte-Carlo / walk-forward), and
|
|
freeze a validated strategy into a standalone bot with a broker connection.
|
|
|
|
This file is the project sittenkodex. It imports the universal discipline from
|
|
`~/dev/skills/templates/CLAUDE.md.fragment` and adds aura's domain invariants.
|
|
The full architecture lives in the design ledger (`docs/design/`), not here.
|
|
Per-cycle specs (`docs/specs/`) and plans (`docs/plans/`) are ephemeral working
|
|
artifacts, kept git-tracked — committed while their cycle is live and removed
|
|
(`git rm`) at cycle close, valid only for the cycle that produces them. Durable
|
|
rationale is lifted to the ledger; a spec/plan is never treated as a live API
|
|
reference (its code snippets drift the moment the code moves). The canonical
|
|
record of past cycles is the ledger plus the git history.
|
|
|
|
## Roles
|
|
|
|
I am the **orchestrator**, not the implementer. The skills-plugin agents are my
|
|
workers: I plan, design, decide, and integrate; they implement, refactor, test,
|
|
and diagnose. Trivial mechanical edits I may do directly; anything needing broad
|
|
reading or judgement goes to an agent. Agent reports describe intent, not
|
|
outcome — I verify the diff and the test output myself before committing.
|
|
|
|
## Commit discipline and main-branch sanctity
|
|
|
|
- **Only the orchestrator commits.** No skill agent runs `git commit`; agents
|
|
leave their output as unstaged working-tree changes for me to inspect and shape
|
|
into commits.
|
|
- **main HEAD is sacrosanct.** No `git reset`/`git revert` on main. main moves
|
|
forward only via my commits. Wrong agent output is discarded with
|
|
`git checkout -- <paths>`/`git stash`; a bad landing is fixed forward, never
|
|
rewound.
|
|
- When a commit closes a Gitea issue, reference it in the body: `closes #N`
|
|
(or `refs #N` for non-final work).
|
|
|
|
## Design rationale ≠ implementation effort
|
|
|
|
Design choices are justified by substance — semantics, structural fit, what the
|
|
design permits vs forbids, compositional clarity, future-proofing. Implementation
|
|
effort ("approach A touches 250 sites, B touches 1") is an observation about the
|
|
current code, not a rationale. Effort is at most a named tiebreaker after
|
|
substantive reasons tie.
|
|
|
|
## Bug fixes — TDD, always
|
|
|
|
Bug fixes are RED-first and autonomous: the failing test exists in the working
|
|
tree before any fix. The `debug` skill is mandatory for any observable
|
|
misbehaviour (failing test, panic, wrong output).
|
|
|
|
## Domain invariants (load-bearing — never silently violate)
|
|
|
|
These are the contracts the whole design rests on. A change that breaks one is a
|
|
design decision, not a refactor, and belongs in the ledger.
|
|
|
|
1. **Determinism.** A backtest is a deterministic, synchronous, non-concurrent
|
|
event loop that reaches a unique state after each input tick. Same input →
|
|
same run, reproducibly. Two backtests are fully disjoint → concurrently
|
|
executable without locking. Parallelism is *across* sims, never within one.
|
|
2. **Causality / no look-ahead.** A node sees only the past. Look-ahead is made
|
|
structurally impossible (read-only input windows that end at the cursor;
|
|
resamplers emit a bar only once it is complete), not merely discouraged.
|
|
3. **One merge, at ingestion only.** Heterogeneous timestamped sources are
|
|
k-way-merged into a single chronological cycle stream at the ingestion
|
|
boundary. There is no merge / as-of join inside the graph.
|
|
4. **The four scalar base types, streamed as SoA.** Only `i64`, `f64`, `bool`,
|
|
`timestamp` are streamed, as columnar Structure-of-Arrays. Composite streams
|
|
(e.g. OHLCV) are bundles of base columns. Non-scalars (String, Records,
|
|
tables, calendars) exist as metadata beside the hot path, never in it.
|
|
5. **Acyclic dataflow.** The graph is a DAG; the only feedback path is an
|
|
explicit delay/state node (the RTL "register"). The "cycle" of the research
|
|
workflow is not a dataflow cycle.
|
|
6. **Record-then-replay determinism boundary.** Anything non-deterministic,
|
|
external, or slow (LLM news agents, web sources) is materialized into a
|
|
recorded, timestamped stream *before* it enters the engine. The sim never
|
|
makes a live external call mid-replay. (See `~/.claude/CLAUDE.md` for the
|
|
IONOS consent rule: external LLM calls happen at the recording/live-source
|
|
edge, with explicit per-session consent, never inside a backtest.)
|
|
7. **Strategy output is an intent/exposure stream; position management is a
|
|
decoupled derived layer.** The DAG expresses one state at t (C8: ≤1 record per
|
|
`eval`), so a strategy's primary, backtestable output is a signed, bounded
|
|
**exposure** `f64 ∈ [-1,+1]` per cycle, not an equity curve. **Signal quality**
|
|
is measured by the **sim-optimal broker** — a downstream consumer node that
|
|
integrates `exposure·return` into a deterministic, frictionless synthetic
|
|
equity stream in **pips**. The broker-independent **position-event table**
|
|
(`event_ts, action[buy/sell/close], position_id, instrument_id, volume`) is a
|
|
**decoupled, derivable** layer — the first difference of the exposure state, a
|
|
computed table (not a per-`eval` output, since one decision instant may yield
|
|
>1 event) — that feeds **realistic broker nodes** (currency equity, real
|
|
frictions) for viability and deploy. The two broker classes attach at two
|
|
points: sim-optimal on the exposure stream, realistic on the derived
|
|
position-event table; brokers are ordinary downstream nodes, never part of the
|
|
strategy.
|
|
8. **Deploy artifacts are frozen.** Hot-reload (cdylib) is an authoring-loop
|
|
tool only. The live bot is a statically-linked, versioned, frozen artifact —
|
|
never hot-swapped (audit trail: this bot = this commit).
|
|
9. **Engine / project separation.** This repo is the reusable *engine*. Research
|
|
projects are separate external repos that depend on it. Project-specific
|
|
signals live in a project's `nodes/`; cross-project-reusable nodes in shared
|
|
crates; universal blocks in `aura-std` (shipped here). Reuse is cargo-native;
|
|
the hot-reload unit is always the project-side `cdylib`. No user/project
|
|
signals in this repo (only `examples/` fixtures for the engine's own tests);
|
|
no multi-project manager or node registry inside aura. **A project is always
|
|
a Rust crate** (a cdylib library of node / strategy / experiment blueprints +
|
|
a static `Aura.toml`), hosted by `aura` during research and frozen to a
|
|
standalone binary for deploy.
|
|
10. **Authoring surface — all logic is Rust.** Nodes, strategies, *and*
|
|
experiments/harnesses are authored in native Rust via Claude Code + the
|
|
skills pipeline, using builder APIs. Declarative config (`Aura.toml`) carries
|
|
only static project context, never logic — no experiment/strategy DSL (the
|
|
RustAst trap). aura ships no embedded coding-LLM; IONOS LLMs are used only as
|
|
a runtime data source (news bias), with per-session consent, never in the
|
|
code path.
|
|
11. **Construction is a bootstrap phase.** Blueprints (param-generic graph-as-
|
|
data from a Rust builder) are bootstrapped into frozen instances (buffers
|
|
sized, topology fixed) by binding params + data + seed. Params configure and
|
|
size nodes but never change topology (a topology change is a different
|
|
blueprint). The harness — sources + strategy + broker node(s) + sinks — is
|
|
the root sim graph, itself bootstrapped, and is C1's disjoint unit; its
|
|
structural axes form the experiment matrix, its tuning params the sweep.
|
|
**The bootstrap is a compilation** to a flat, type-erased `FlatGraph`, wired
|
|
by raw index (composites inline — a composite is an authoring-level node, not
|
|
a runtime object; names survive only as non-load-bearing debug symbols, as
|
|
today). The flat graph is the target of **behaviour-preserving** optimisation,
|
|
C1 the correctness invariant — intra-graph (CSE/DCE) and across a sweep family
|
|
(sweep-invariant sub-graph computed once, shared via C11/C12). See C9/C19/C23.
|
|
12. **The World is the product; the playground is a trace explorer.** Three
|
|
ontological tiers: a *node* is an open, composable fragment (at most one
|
|
output, C8); a *harness* is the closed root graph that runs (sources +
|
|
strategy + brokers + sinks + clock — C1's disjoint unit / root scope),
|
|
**not** a node; the *World* is the program that dynamically constructs and
|
|
orchestrates *families* of harnesses (walk-forward / sweep / MC / comparison)
|
|
— aura's differentiator, not the single backtest. The World is a program:
|
|
nothing is displayable until it runs, and what is displayable is exactly what
|
|
a **sink** (C8) records into the registry (C18). The playground plays *any*
|
|
harness and is an execution viewer / trace explorer (structure before, live
|
|
streams during, recorded traces after) — never a scene editor; topology is
|
|
grown in Rust + hot-reload, runtime params are UI-tunable.
|
|
|
|
## Skills plugin: project facts
|
|
|
|
The few facts the skills plugin needs that genuinely vary per project.
|
|
Everything else is a fixed convention (see `~/dev/skills/docs/conventions.md`).
|
|
|
|
- **Code roots** — `crates`
|
|
- **Build** — `cargo build --workspace`
|
|
- **Test** — `cargo test --workspace`
|
|
- **Lint** — `cargo clippy --workspace --all-targets -- -D warnings`
|
|
- **Doc build** — `cargo doc --workspace --no-deps 2>&1`
|
|
- **Design ledger** — `docs/design/INDEX.md`
|
|
- **Glossary** — `docs/glossary.md`
|
|
- **Issue tracker** — Gitea, repo `Brummel/Aura`:
|
|
- browsable URL: `http://192.168.178.103:3000/Brummel/Aura/issues`
|
|
- list open issues: `tea issues ls --repo Brummel/Aura --state open`
|