Executive Summary
The whitepaper introduces ZenTrader's Cognitive Memory Architecture (CMA) as the platform's structured, AAS-inspired long-term memory for trading agents. This dossier is the research-grade companion to that narrative: it states plainly what is implemented today, what is a working foundation rather than a finished capability, and what remains a proposed design. It exists so that reviewers — technical, scientific, or funding — can evaluate the architecture on verified evidence rather than marketing language.
ZenTrader already implements an AAS-inspired relational hierarchy (assets → shells → submodels → typed elements), a genuinely insert-only policy-decision ledger, a versioned, golden-set-evaluated scoring pipeline (GeoScore), and a dedicated, database-enforced append-only memory-event ledger (cma_memory_events, stage 1 of the roadmap below). Cryptographic tamper evidence (a SHA-256 hash chain and Ed25519 signatures) and a narrowly-scoped temporal retrieval API with hybrid lexical/dense search are also built and tested — neither is yet enabled in production. What remains genuinely open is retrieval scoring with explanations at a tenant-facing endpoint and a preregistered evaluation programme. This document specifies the research questions, hypotheses, methodology, and roadmap for closing the rest of that gap.
1. Purpose and Status of This Document
Every claim below is labelled so a reader never has to guess whether something exists in production:
| Label | Meaning |
| Implemented | Verified directly against the current source code and the live database schema. |
| Partial | A working foundation exists, but the complete behaviour described in the research programme is not yet present. |
| Proposed | A design recommended for implementation and validation; not yet built. |
This dossier was produced from an internal architecture review combined with a direct inspection of the relevant source files and the production database schema. Where the two disagreed, the verified code/database state is what is reported here.
2. The CMA Research Problem
Large language models have finite working context and no inherently persistent, trustworthy memory of earlier interactions, market states, or decisions. Retrieval-augmented generation addresses part of this limitation, but provenance, temporal validity, and updating remain open problems in the general literature. Financial agents raise the bar further: a retrieved statement may have been correct when generated but invalid after a regime change; an analysis may be an inference rather than an observation; a policy may have changed after a trade was placed; and a plausible narrative must never be confused with verified execution evidence.
Research problem. How can heterogeneous observations, probabilistic agent inferences, deterministic policies, execution states, and eventual outcomes be represented as temporally valid, semantically typed, retrievable, and independently verifiable memories — without allowing mutable projections or probabilistic agents to rewrite historical evidence?
3. Current Implementation, Verified Against Code and Database
core/aas_research.py builds AAS-inspired symbol shells and currently emits five submodels — Provenance, MacroRegimeContext, FactorEngineState, SignalDecision, and LiveExecution — normalised into four relational tables (aas_assets → aas_shells → aas_submodels → aas_submodel_elements).
| Submodel | Status | Purpose |
Provenance | Implemented | Source, task, profile, observed time |
MacroRegimeContext | Implemented | Market regime and readiness gate state |
FactorEngineState | Implemented | Deterministic factor values (price, volume, scores) |
SignalDecision | Implemented | Proposed or rejected trading signal, with rationale |
LiveExecution | Implemented | Selected broker route and readiness |
A direct schema inspection confirms that aas_shells and aas_submodels write via INSERT ... ON CONFLICT DO UPDATE SET raw_json = EXCLUDED.raw_json, so the SQL permits overwriting a shell or submodel row. In practice this almost never happens: both tables' identifiers embed the run's task_id, which is unique per market-watch cycle, so each cycle inserts fresh rows rather than colliding with an earlier one — a direct count found only 2 of 907,164 aas_shells rows have ever actually been updated via that conflict path, and both were from an unrelated, stable-ID closed-loop tracking shell, not a per-symbol research snapshot. The real risk these tables carry today is therefore not silent history loss but unbounded, uncompressed growth — 907K shell rows, 4.6M submodel rows, 16.5M element rows, ~14GB combined and rising with every cycle, the same growth pattern GeoScore had before its own hypertable migration (see the GeoScore research page). A dedicated, database-enforced event ledger closes the narrower "could theoretically be silently overwritten" gap and adds explicit temporal/authority semantics these tables don't have; it does not, by itself, address the growth problem, which needs its own compression treatment.
Phase 1 — event ledger and first producer. cma_memory_events now exists: a dedicated table with the four-clock temporal model above, enum-checked memory/authority/lifecycle columns, and — going one step further than gate_decisions — a BEFORE UPDATE OR DELETE trigger that blocks mutation unconditionally, independent of database role grants. This was verified live in production (a manual insert, then a blocked UPDATE and a blocked DELETE, both rolled back) in addition to 16 passing tests. A first producer is now wired: core/aas_research.py mirrors every written AAS submodel into the ledger as an observation-class event, additively and best-effort (a mirroring failure is logged, never breaks the primary AAS write). It is gated behind CMA_LEDGER_MIRROR, default-OFF — matching this codebase's established rollout convention for new observability hooks. A supervised observation run (one market-watch cycle with the flag temporarily enabled) confirmed it works end-to-end in production: 1,280 rows written, 0 mirroring failures, correct grouping and content — then the flag was turned back off. The table is now also a TimescaleDB hypertable on event_time with a compression policy (chunks older than 30 days compress automatically, data stays fully queryable) — but deliberately no retention/drop policy, unlike the GeoScore hypertables precedent: this table is CMA evidence, and the design principles above ("forgetting must not destroy auditability") explicitly require it to remain permanent, not decay-and-drop like GeoScore's narrower signal system. There is still no projection bridge reading the ledger back into aas_shells/aas_submodels, and no other producer (gate_decisions, GeoScore) is wired yet — those remain open roadmap stages (both were wired in later updates below).
Phase 2 — AAS hypertable compression. The growth problem flagged above is now partially solved: aas_shells is a TimescaleDB hypertable on created_at, with the same compression-only, no-retention policy as cma_memory_events — deliberately, because this data backs the whitepaper's trade-explainability claim rather than being disposable signal data. Its child tables (aas_submodels, aas_data_statements) gained a denormalised shell_created_at column and composite foreign keys pointing at the new hypertable, auto-populated by a BEFORE INSERT trigger so no existing writer code needed to change; one line in core/aas_research.py's ON CONFLICT target was updated to match the now-composite unique constraint. Verified live: the hypertable, compression policy, and both triggers are active in production, with the trigger proven correct by production writes that landed during the migration window itself (zero rows with a NULL shell_created_at). Stage 2: aas_submodels — the largest of the four AAS tables (4.58M rows, 13GB) — is now a hypertable too, with the identical compression-only treatment and the same denormalised-timestamp pattern extended to its own children (aas_submodel_elements, aas_data_statements). This stage surfaced a genuine Timescale limitation the first migration didn't: a hypertable cannot itself hold an outbound foreign key to another hypertable, which broke on the first attempt (rolled back cleanly, no damage) because aas_submodels already FKs into the now-hypertable aas_shells. Fixed by dropping that foreign key — aas_submodels.shell_id is now a soft, application-enforced reference rather than a database-checked one, the same trust model already accepted for cma_memory_events.supersedes_event_id. Stage 3: aas_submodel_elements — the largest AAS table by row count (16.56M rows, ~8GB) — is now a hypertable too. Applying the previous stage's lesson up front, its two outbound foreign keys (to the now-hypertable aas_submodels, and a self-reference via parent_element_id) were dropped before calling create_hypertable(), which then succeeded on the first attempt. Two things measured directly rather than assumed: aas_qualifiers, the only other table besides aas_data_statements that references elements, turned out to have zero rows and no writer anywhere in the codebase — dead schema; and parent_element_id itself is NULL on all 16.56M rows — the element-hierarchy feature this dropped foreign key protected has never actually been used in production. Stage 4 — plan complete. aas_data_statements (10.97M rows, 13GB) is now a hypertable too, closing out all four AAS tables. It turned out structurally simpler than the earlier stages expected: nothing foreign-keys into it, so no denormalised columns or triggers were needed at all — only dropping its three outbound composite foreign keys to the other, now-hypertable AAS tables (all becoming soft references, same as before) and partitioning on observed_at, its only timestamp column. No application code changed for this stage. All four AAS tables — aas_shells, aas_submodels, aas_submodel_elements, aas_data_statements — are now compressed TimescaleDB hypertables with no retention policy; only aas_assets stays a regular table, correctly, since it is genuinely upserted (~650 rows). The unbounded-growth limitation this whole update thread tracked is resolved.
Phase 3 — projection bridge (roadmap item 4). A read-only module (trading/cma/projection.py) now reconstructs the latest AAS submodel state purely from cma_memory_events and compares it against the live aas_submodels rows — the first direct test of the design principle above ("current state is a projection... always derived from immutable events") and of RQ-B (evidence reconstruction) against real data rather than an assumption. Run against every shell the ledger has seen (the Phase 1 mirroring proof run): 256 of 256 shells and 1,280 of 1,280 submodels reconstruct exactly — a measured 100% match rate. This is a narrow result, stated precisely rather than oversold: one producer (AAS submodel mirroring), one supervised run, observation-class events only, and content that is a direct verbatim copy by construction (the mirroring code passes the submodel dict unchanged into content_json), so exact equality is the expected outcome being verified, not yet a claim about reconstruction from more distantly related or partially-derived evidence. It is, however, a genuine live measurement with a real failure mode (a mismatch, or a row present on one side only) that did not occur — not a synthetic benchmark. 9 new rollback-isolated tests cover both directions of drift (ledger has it, AAS doesn't; and vice versa) plus the match/mismatch cases directly. Building this also surfaced and fixed a real bug unrelated to CMA specifically: a session-lifecycle helper that unconditionally closed any injected database session on exit, which breaks for any caller supplying a longer-lived session (not just tests) — fixed by mirroring the safer pattern already used by trading/db/order_store.py.
The gate_decisions table is a separate evidence structure. Its writer (trading/policy/decision_store.py) contains no update or delete path in code — every call either raises before writing (fail-closed validation) or inserts exactly one row. A live schema check found the distinction that matters for an honest claim: at that point the append-only guarantee was enforced by application code discipline only, not by the database — no trigger blocked mutation, and the application's own database role retained ordinary UPDATE/DELETE privileges on the table.
Phase 4 — gate_decisions database-enforced. That gap is closed: gate_decisions now carries the identical BEFORE UPDATE OR DELETE trigger already proven on cma_memory_events, unconditionally rejecting mutation independent of role grants. The database roles' own UPDATE/DELETE grants are deliberately left in place — revoking them is a separate, larger change touching every role with legitimate other privileges on this table — but the trigger alone already closes the actual gap: a manual UPDATE and DELETE via raw SQL were both tested live and blocked. gate_decisions and cma_memory_events are now both database-enforced append-only. Neither is yet cryptographically tamper-evident — no content hash, previous-hash chain, or signature column exists on any evidence table today.
Phase 5 — gate_decisions as second producer. gate_decisions is now wired as the ledger's second producer: every written decision is additionally mirrored into cma_memory_events as a memory_type='decision', authority='deterministic_derived' event (trading/policy/decision_store.py), best-effort and never blocking the primary write, gated behind its own default-OFF flag (CMA_LEDGER_MIRROR_GATE_DECISIONS) kept deliberately separate from the AAS producer's flag since this writer sits on the live order-execution path. Unlike the AAS producer, this one has not yet been proven live: two supervised overnight observation windows found no organic gate_decisions row to mirror — the platform runs globally in dry_run mode and neither attempt's paper-mode cycles produced an order intent to route. Both attempts happened on a Friday night/weekend, when the equity-hours-gated strategies don't fire at all; a third attempt is planned for a weekday with both crypto and equity timers active.
Phase 6 — GeoScore as third producer. GeoScore's scoring pipeline (trading/geoscore/scoring.py:score_pending) is now wired as the ledger's third producer: every assembled geoscore_event_scores row is additionally mirrored into cma_memory_events, one event per asset × horizon, as a memory_type='assertion', authority='model_inferred' event — the first producer to actually exercise model_inferred's cross-field validation rule (both model_version and prompt_version required), carrying GeoScore's own resolved model id and its geoscore-prompt-v2 contract version. Best-effort, never blocking the primary score write, gated behind its own default-OFF flag (CMA_LEDGER_MIRROR_GEOSCORE). Covered by mocked unit tests and a rollback-isolated real-database test asserting the mirrored rows' content and count against a seeded event — not yet observed live in production, the same open step as the second producer above.
Incident — a "rollback-isolated" real-DB test wasn't. While building the retrieval API below, an unrelated check surfaced that GeoscoreLedgerMirrorRealDbTest (the real-database test for the producer above) had been silently committing real rows to production cma_memory_events on every run since it was written — 27 rows, IDs 1480-1800, all with the unmistakable fake ticker stream_id='geoscore:ZZZTESTBTC:*'. Root cause: _mirror_geoscore_score_to_ledger() calls record_memory_event() without a session argument by design (the mirror deliberately runs in its own transaction, separate from the primary write's — the same convention every producer in this section uses); that fallback path resolves its session through trading.db.order_store._SESSION_FACTORY, and the test never redirected that hook to its own rollback-isolated session, unlike the equivalent gate_decisions test, which does. The primary GeoScore tables were correctly isolated throughout (verified: zero leaked rows in geoscore_events/geoscore_event_scores) — only the separate-transaction ledger mirror escaped. Fixed by adding the same session-factory redirect the gate_decisions test already used; verified clean on rerun (row count unchanged across two subsequent runs). The 27 leaked rows themselves were left in place rather than forced out through the append-only trigger that would otherwise need disabling to remove them — a deliberate call consistent with this ledger's own principle that mistakes get documented, not erased, and they are harmless: inert, unambiguously fake, and excluded from the reconstruction-rate and audit measurements elsewhere in this dossier by their fake ticker alone.
Phase 7 — hash chain (roadmap item 9, part 1 of 2). cma_memory_events' two reserved integrity columns (content_hash, previous_event_hash) are now populated when trading/cma/chain.py's hash chain is enabled: every row's content_hash is a SHA-256 of its canonicalized content_json, and previous_event_hash links it to the prior row's hash, forming a linked list any of the three producers can append to transparently — none of them had to change. A Postgres advisory transaction lock serializes the read-last-hash-then-insert step so concurrent producers can never race for the same link. A companion verify_chain() walks the ledger and checks both a content re-hash and the link continuity; its detection logic is unit-tested directly against fabricated tampered/deleted/spliced-in rows (constructing a genuinely tampered row in the live table is not possible — the append-only trigger above already blocks it, which is itself a meaningful result: this hash chain is defense-in-depth for a scenario where that trigger is bypassed, e.g. a restore from an externally tampered dump, not the primary defense). Practical canonical JSON (sorted keys, UTF-8, no whitespace), explicitly not a certified RFC 8785 (JCS) implementation — number formatting and non-BMP key ordering are not JCS-exact, a real gap against the roadmap item's original wording. Gated behind CMA_LEDGER_HASH_CHAIN, default OFF, not yet enabled in production.
Phase 8 — Ed25519 signatures (roadmap item 9, part 2 of 2). A migration added two more nullable columns (signature, signing_key_id) and trading/cma/signing.py now signs each row's hash-chain link (content_hash, previous_event_hash, plus stream_id/event_type/event_time so a signature cannot be replayed onto an unrelated row) with an Ed25519 private key, when enabled. signing_key_id is a short, non-secret fingerprint of the public key — deliberately not one hardcoded key baked into the verifier, so a future key rotation doesn't retroactively invalidate old rows' verifiability. A companion verify_signatures() checks every signed row against a caller-supplied key map and reports an unknown-key row separately from an actually-invalid signature, since those mean different things (verifier coverage gap vs. real tamper). The private key itself (CMA_LEDGER_SIGNING_KEY) is read from the environment only, never written to the database or this repository — and today it is unset: no signing key has been generated for production, CMA_LEDGER_SIGN_CHAIN is unset/OFF, and signing depends on the hash chain above also being enabled. Roadmap item 9 (hash chain and signatures) is now built end to end; item 10 (external Merkle checkpoints) remains open.
Phase 9 — retrieval API, part 1 (roadmap item 5). trading/cma/retrieval.py turns RQ-A into a queryable function rather than only a hypothesis: retrieve(as_of=T, ...) answers "what did the ledger know, and consider still valid, at time T" by requiring both ingested_at <= T (never let a point-in-time query see information the system only learned about later) and valid_from <= T < valid_to (half-open, NULL valid_to meaning still valid) — the two-clock distinction the CMA design principles describe, now enforced in a WHERE clause instead of only in prose. A companion retrieve_latest_per_stream() uses Postgres DISTINCT ON (not a naive top-N-then-group, which a rollback-isolated test proved would silently drop a real result: a stream with few events can get crowded out of a simple truncated result set by a stream with many). Both functions also accept ordinary scope filters (tenant, profile, strategy, asset, memory/event type, authority, correlation id) and default to excluding non-active lifecycle rows. Explicitly scoped narrow at the time this phase shipped: no ranking, no lexical or dense search, no Golden Set evaluation — this was the plumbing those later phases build on, not a finished retrieval system (roadmap items 7 and 8, both now shipped separately below). Its docstring carries an explicit warning against exposing it to a tenant-facing endpoint without passing tenant_id, given this codebase's own prior evidence-API cross-tenant leak history. 7 new rollback-isolated tests.
Phase 10 — prompt/model registry (roadmap item 6). trading/cma/model_registry.py is a small, code-level registry of known (component, prompt_version) pairs, each entry citing the real git commit and date that introduced it — not a database table, deliberately: GeoScore's own version discipline already lives in git history (a versioned PROMPT_VERSION constant, evaluated against a Golden Set before each change ships), and a separate mutable registry table could itself drift from the code it describes, the opposite of what a registry is for. Building it against real history surfaced a genuine, previously undocumented gap: an earlier calibration round that added 5 VIP/influencer golden-set events (commits 880e3e1a/99b35ad8, 7/10 → 14/15) never bumped PROMPT_VERSION — still geoscore-prompt-v2 as of this writing. Recorded honestly in the registry entry rather than retroactively inventing a "v2.1" this codebase never used. A read-only audit_ledger_versions() scans the live ledger for any model_inferred row using a (component, prompt_version) pair this registry doesn't recognise; run against production it found zero unregistered versions (the ledger's only model_inferred rows are the 27 leaked test rows noted above, which happen to carry a genuinely registered version). Not wired into record_memory_event as an enforcement gate — that would be a separate, later decision on an already HIGH-risk shared writer, not bundled into introducing the registry itself. 12 new tests, including one that pins the real current registry state so a future geoscore-prompt-v3 ship without a matching entry fails loudly.
Phase 11 — Golden Set + CI non-regression (roadmap item 7). trading/cma/golden/cma_retrieval_golden_set.json freezes 5 retrieve()/retrieve_latest_per_stream() queries against real, immutable rows from the Phase 1 AAS mirroring proof run (the TXN research shell's 5 submodels, ids 1276-1280), each with an exact expected event-ID set — not ranges, unlike GeoScore's LLM-graded golden set, because retrieval over an append-only ledger given fixed evidence has exactly one correct answer. tests/test_cma_golden_set_unittest.py replays every case against the live database as an ordinary part of the pytest suite: true CI non-regression, no separate eval script needed. Building the "latest state per stream" case caught a real bug before it was ever pinned: all 5 of the TXN shell's rows share one event_time (they were mirrored in a single market-watch cycle), and retrieve_latest_per_stream()'s tie-break — nonexistent until this phase — silently returned Postgres's scan order, observed picking the first-inserted row of the tied group, the wrong direction for "current state". Fixed by adding id DESC as an explicit tiebreaker (the row that actually entered the ledger last now wins); the golden set's tiebreak case pins the corrected behaviour against the same real data that exposed the bug, so a regression would be caught immediately, not rediscovered.
Phase 12 — hybrid retrieval (roadmap item 8). This codebase had zero vector-search infrastructure before this phase: no pgvector, no embedding-generation code anywhere, no embeddings surface on the AION MCP integration (checked directly rather than assumed). What it did have, already running, was nomic-embed-text (768-dim, a dedicated embedding model, confirmed present) on the same GPU Ollama instance GeoScore's LLM calls already depend on (100.98.188.22:11434) — so building this needed a new Postgres extension and a new Python client, not a new model or a new server. Installed pgvector 0.8.1 (confirmed installable by the existing zentrader_researcher role without superuser — it's a "trusted" extension) and added a nullable vector(768) column plus an HNSW cosine-distance index to cma_memory_events. Because the table is append-only, embeddings cannot be backfilled onto an existing row via UPDATE the way a normal "reserved column" would be — trading/cma/embeddings.py's apply_embedding() runs at insert time only, alongside the hash-chain and signing steps, computing a vector from search_text when present. Unlike those two, a failed embedding call is caught and logged, never raised: it is a network call to a remote GPU that can fail transiently even when correctly configured, and the ledger's evidence-recording contract must not depend on that GPU being reachable. lexical_search() (Postgres ts_rank over the GIN index this table has carried since Phase 1), dense_search() (pgvector cosine distance), and hybrid_search() (min-max-normalized weighted fusion of the two) are three independently swappable pieces — the "replaceable interface" the roadmap item asks for. Verified against the real GPU once, end to end, outside the permanent test suite (mocked in all committed tests, matching how GeoScore's own tests never call the real Ollama instance either): a query for "central bank monetary policy rate decision" correctly ranked a row about "Federal Reserve signals interest rate cuts" top via the dense signal alone (lexical score 0 -- no shared words), demonstrating genuine semantic match, not just keyword overlap. Both new flags (CMA_LEDGER_EMBED, gating insert-time computation) default OFF; no embedding has been written to a real production row. 22 new tests across three files; full cma/geoscore/gate_decision/aas suite green (263 passed), plus a full 1,826-test whole-suite run confirming no regressions elsewhere (2 pre-existing, unrelated failures in an unrelated API area, untouched by this work).
Phase 13 — the model registry catches its own kind of drift a second time. Phase 10 recorded, honestly, that GeoScore's prompt constant was still geoscore-prompt-v2 despite an undocumented calibration change. That has since shipped as geoscore-prompt-v3: a new golden-set-evaluated change (adding a TRACKED_ASSETS asset-naming preference list, golden set 13/15 with n=3 self-consistency runs) correctly bumped the version this time — geoscore-prompt-v2 is now marked deprecated in trading/cma/model_registry.py, geoscore-prompt-v3 is the new active entry, citing its real introducing commits. The two golden-set misses that remain under v3 (a memecoin-post score range, exchange-hack factor signs) are pre-existing calibration gaps unrelated to this change, not a new regression. This is a genuine, small proof point for the registry's own stated purpose: a real version change happened, and it landed in the registry rather than drifting silently a second time.
GeoScore, the platform's qualitative-narrative scoring pipeline, is the most mature in-repository template for CMA's evaluation discipline: every prompt or model change is evaluated against a versioned, range-graded Golden Set before it ships, scoring itself is a deterministic, unit-tested function of the LLM's structured (never numeric) output, and re-scoring an event never overwrites a row — it inserts a new one chained via superseded_by. This append-and-chain pattern is exactly what the proposed CMA event ledger should generalise across all memory classes, not only narrative scores.
4. Research Questions and Hypotheses
| Question | Hypothesis |
| RQ-A — Temporal retrieval. Does CMA retrieve information valid at the requested decision time more reliably than recency, lexical, or dense retrieval alone? | Hybrid CMA retrieval improves temporal-validity accuracy and nDCG@k over recency-only, BM25-only, and dense-only baselines. |
| RQ-B — Evidence reconstruction. Can a past decision be reconstructed from its exact data, memory, model, prompt, strategy, and policy state? | CMA achieves a higher complete-reconstruction rate and lower unsupported-claim rate than free-text journals or unversioned RAG. |
| RQ-C — Contradiction handling. Does explicit validity, supersession, and source authority reduce retrieval of stale or contradicted memories? | Validity-aware retrieval reduces stale-memory inclusion and contradiction errors versus timestamp-only retrieval. |
| RQ-D — Controlled consolidation. Can derived reflections improve multi-hop reasoning without being mistaken for primary evidence? | Provenance-bound reflections improve multi-hop retrieval while preserving evidence precision. |
| RQ-E — Memory economy. Can ranked, compressed memory reduce context size and latency without materially reducing decision quality? | CMA uses fewer prompt tokens than full-context baselines while remaining non-inferior on task accuracy. |
| RQ-F — Tamper evidence. Can canonicalisation, hashing, and signatures detect unauthorised alteration or omission of stored evidence? | Injected record mutations are detected, and omission attacks are detectable against independently retained checkpoints. |
Provisional engineering targets — to be fixed after a labelled pilot and before any holdout is opened — include a five-percentage-point absolute improvement in temporal-validity accuracy, at least 95% complete decision reconstruction, zero undetected mutation in an adversarial test suite, and at least 30% fewer prompt tokens than full-context retrieval at non-inferior accuracy. These are validation thresholds to be tested, not current product claims.
5. Design Principles
The formal CMA is governed by six invariants:
- Evidence is immutable. Observations, decisions, executions, and outcomes are appended, never overwritten.
- Current state is a projection. The "latest known state" may be rebuilt, but it is always derived from immutable events.
- Time has more than one meaning. Observation time, event time, ingestion time, and validity interval are stored separately.
- Authority is explicit. Broker facts, deterministic calculations, human assertions, and LLM inferences are distinct memory classes with distinct trust levels.
- Agents propose; deterministic services commit. An agent may request a memory write, but schema, tenancy, policy, provenance, and authority checks decide whether it is accepted.
- Forgetting must not destroy auditability. Decay, summarisation, and archiving affect retrieval and cost, never the underlying evidence ledger.
6. Memory Taxonomy (excerpt)
| Class | Definition | Mutability |
| Observation | Data received directly from a defined source | Append-only |
| Assertion | A claim derived from observations | Superseded, never overwritten |
| Decision | Deterministic or human gate outcome | Append-only |
| Execution | Broker-facing action and reported state | Append-only event stream |
| Reconciliation | Comparison between internal and broker states | Append-only |
| Outcome | Later evidence evaluating an earlier assertion or decision | Append-only |
| Projection | Materialised current view (e.g. today's aas_shells) | Rebuildable and mutable |
7. Relation to Prior Work
The reviewed literature supplies strong solutions for long-term retrieval, reflection, graph memory, financial memory, and provenance individually. ZenTrader's design is unusual in combining these with AAS-inspired semantic twins, deterministic policy evidence, and multi-broker reconciliation — but this is a research inference, not an established uniqueness claim; a systematic literature review is still required before publication.
| Field | Implication for CMA |
| AAS & digital twins (IDTA metamodel) | Use AAS identity/shell/submodel principles; maintain a documented ZenTrader compatibility profile rather than claiming conformance. |
| Retrieval-augmented generation | Retain external, queryable evidence rather than treating model weights as system memory. |
| Generative Agents (Park et al.) | Adopt scored retrieval and reflection, but bind reflections to evidence so they cannot silently become authoritative facts. |
| MemGPT | Expose explicit retrieval interfaces; never let an LLM bypass deterministic write policy. |
| MemoryBank | Apply decay to retrieval visibility only, never to immutable financial evidence. |
| HippoRAG | Consider graph/PageRank expansion only after the relational-temporal baseline is stable. |
| FinMem | Compare CMA against a layered financial-memory baseline; differentiate on evidence governance and temporal provenance, not layering alone. |
| LoCoMo | Reuse its task taxonomy as a general memory sanity check; build a finance-specific temporal benchmark separately. |
| W3C PROV | Map datasets, prompts, models, policies, agents, and decisions to an explicit provenance vocabulary. |
8. Validation Programme
Five properties are tested independently rather than collapsed into trading profitability, which is affected by strategy quality, regime, and cost and cannot alone establish that the memory architecture is better:
- Retrieval quality — does CMA find the correct evidence?
- Temporal correctness — does it retrieve only what was knowable and valid at the requested time?
- Decision reconstruction — can an independent evaluator reproduce what the system knew and why it acted?
- Operational efficiency — what latency, token, and storage cost does memory add?
- Integrity verification — can alteration, truncation, and inconsistent history be detected?
Baselines span no-memory and full-context extremes, recency/BM25/dense-RAG, Generative-Agents-style scoring, a FinMem-style layered baseline, and three CMA configurations (relational, hybrid, graph+reflection). The final confirmatory evaluation is intended to be preregistered — in the OSF sense of a timestamped, read-only plan frozen before the holdout is accessed — before any headline result is published.
Concrete validation milestones
| Milestone | Exit criterion |
| Memory-event schema | JSON Schema validation and database constraints agree on valid/invalid fixtures |
| Temporal queries | All synthetic bitemporal test cases pass, including delayed corrections |
| Evidence reconstruction | At least 95% of labelled decisions reconstruct with all mandatory evidence |
| Golden Set | Versioned query set, evaluator, and non-regression CI are operational |
| Hashing & signatures | Mutation, reorder, and wrong-predecessor tests fail verification as designed |
| Preregistered evaluation | Locked holdout analysed once under the registered plan |
9. Limitations
- Standards scope. ZenTrader borrows AAS concepts but uses a domain-specific JSON shape and relational normalisation. Full AAS conformance cannot be claimed until serialisation and interfaces are tested against the official IDTA specifications.
- Current event immutability; unbounded growth resolved. Gate decisions are append-only in application code and, in a later phase, database-enforced by a trigger too, matching
cma_memory_events; AAS shell and submodel writes are technically upserts, though a direct count found the conflict path fires almost never in practice (2 of 907,164 rows) because each cycle's task_id makes IDs unique — the real historical risk was unbounded, uncompressed growth (~14GB and rising across four AAS tables), not silent overwrite, and that growth problem is now resolved: all four AAS tables (aas_shells, aas_submodels, aas_submodel_elements, aas_data_statements) are now compressed TimescaleDB hypertables with no retention/drop policy, completed across four incremental migrations in one phase of this programme — and it is holding: measured again since, combined row counts have grown 20-30% across three of the four tables (now 1.15M / 5.80M / 21.0M / 10.97M rows respectively), yet the combined compressed footprint is ~8.3GB, down from the ~14GB pre-compression baseline. A dedicated, database-enforced event ledger (cma_memory_events) also now exists, with three producers wired (AAS submodel mirroring, gate_decisions, GeoScore) each gated behind its own default-OFF flag — a separate, narrower gap (overwrite-proofing and temporal/authority semantics) from the growth problem, and still open pending production enablement.
- Source truth. A future hash chain would prove content has not changed relative to a checkpoint — it would not prove that a broker, news source, model, or human assertion was correct.
- Non-stationarity. Financial regimes, broker behaviour, and models change over time; results from a fixed historical window may not generalise, so temporal cross-validation is mandatory.
- Private reproducibility. Proprietary data and code limit full external replication; a synthetic benchmark, public schemas, and frozen evaluation artefacts are planned to mitigate this without publishing trading IP.
10. Roadmap
The roadmap prioritises schema stability and temporal/evidence correctness before embeddings, graph databases, or autonomous reflection:
- Terminology and ADR freeze (memory taxonomy, authority classes, temporal semantics)
- JSON Schema package with valid/invalid fixtures
- Done Immutable event ledger (
cma_memory_events; insert-only, DB-trigger-enforced — three producers wired: AAS submodels, gate_decisions, GeoScore, each behind its own default-OFF flag; AAS producer proven live in production, the other two verified in tests only)
- Done Projection bridge from events into existing AAS tables (read-only reconstruction + verification; 100% match on the one dataset measured so far)
- Partial Read-only, temporally filtered retrieval API — point-in-time (
as_of) + scope filtering, a per-stream "latest state" query, and hybrid lexical/dense ranking now built (trading/cma/retrieval.py, item 8 below); still no tenant-facing endpoint and no preregistered evaluation harness (item 11)
- Done Prompt/model registry, generalising GeoScore's version discipline — code-level registry (
trading/cma/model_registry.py), not a DB table, deliberately matching how GeoScore itself already tracks versions (git history, not a mutable registry that could itself drift)
- Done Golden Set with expected evidence IDs and CI non-regression — 5 cases frozen against real, immutable production rows (
trading/cma/golden/cma_retrieval_golden_set.json), run as an ordinary part of the pytest suite; caught a real ordering bug while being built
- Done Hybrid (lexical + dense) retrieval behind a replaceable interface — pgvector installed, real GPU embedding calls verified end-to-end; not enabled by default
- Done Hash chain and signatures (JCS canonicalisation, SHA-256, Ed25519) — both built (practical canonical JSON, not certified JCS); neither enabled in production
- External checkpoints (Merkle batches, independently retained roots)
- Preregistered holdout evaluation and public research package
The first implementable release is scoped as CMA v1: immutable events, temporal retrieval, and evidence reconstruction. Graph memory, autonomous reflections, and external transparency logs are later increments — sequenced this way so sophisticated retrieval never hides weak temporal or provenance semantics underneath it.
References
- Park et al., Generative Agents: Interactive Simulacra of Human Behavior — DOI: 10.1145/3586183.3606763
- Packer et al., MemGPT: Towards LLMs as Operating Systems — arXiv: 2310.08560
- Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — NeurIPS 2020
- Gutiérrez et al., HippoRAG — DOI: 10.52202/079017-1902
- Zhong et al., MemoryBank — arXiv: 2305.10250
- Chhikara et al., Mem0 — arXiv: 2504.19413
- Yu et al., FinMem — DOI: 10.1109/TBDATA.2025.3593370
- Maharana et al., Evaluating Very Long-Term Conversational Memory of LLM Agents (LoCoMo) — DOI: 10.18653/v1/2024.acl-long.747
- IDTA, Asset Administration Shell Metamodel, IDTA-01001 — official metamodel and normative schemas
- W3C, PROV-O — W3C Recommendation
- RFC 8785, JSON Canonicalization Scheme (JCS) — rfc-editor.org/rfc/rfc8785
- RFC 9162, Certificate Transparency Version 2.0 — rfc-editor.org/rfc/rfc9162
- OSF, Registrations and Preregistrations — official OSF guidance
This dossier accompanies, and does not replace, the ZenTrader Whitepaper. It is an internal research protocol shared for technical and funding review; research questions, milestones, and dates are planning artefacts, not commitments to a fixed delivery date. Implementation status was verified against source code and the production database schema as of this revision and will drift as the codebase evolves — treat any specific claim as time-stamped, not evergreen.
Executive Summary
Das Whitepaper führt ZenTraders Cognitive Memory Architecture (CMA) als das strukturierte, AAS-inspirierte Langzeitgedächtnis der Plattform für Trading-Agenten ein. Dieses Dossier ist das forschungsseitige Begleitdokument dazu: Es benennt unmissverständlich, was heute implementiert ist, was eine belastbare Grundlage statt einer fertigen Fähigkeit ist, und was noch ein vorgeschlagenes Design bleibt. Es existiert, damit Prüfer — technisch, wissenschaftlich oder im Rahmen einer Förderung — die Architektur anhand verifizierter Evidenz bewerten können, nicht anhand von Marketing-Sprache.
ZenTrader implementiert bereits eine AAS-inspirierte relationale Hierarchie (Assets → Shells → Submodelle → typisierte Elemente), einen tatsächlich nur-einfügenden Policy-Entscheidungs-Ledger, eine versionierte, gegen ein Golden Set evaluierte Scoring-Pipeline (GeoScore) — und einen dedizierten, datenbankseitig erzwungenen Append-only-Memory-Event-Ledger (cma_memory_events, Stufe 1 der Roadmap unten). Kryptografische Manipulationssicherheit (eine SHA-256-Hash-Kette und Ed25519-Signaturen) sowie eine eng gefasste, zeitlich bewusste Retrieval-API mit hybrider lexikalischer/dichter Suche sind ebenfalls gebaut und getestet — beides ist in Produktion noch nicht aktiviert. Wirklich noch offen sind Retrieval-Scoring mit Erklärkomponenten an einem mandantenfähigen Endpunkt sowie ein präregistriertes Evaluationsprogramm. Dieses Dokument spezifiziert die Forschungsfragen, Hypothesen, Methodik und Roadmap, um den Rest dieser Lücke zu schließen.
1. Zweck und Status dieses Dokuments
Jede Aussage unten ist so gekennzeichnet, dass niemand raten muss, ob etwas bereits in Produktion existiert:
| Label | Bedeutung |
| Implementiert | Direkt gegen den aktuellen Quellcode und das produktive Datenbankschema verifiziert. |
| Teilweise | Eine funktionierende Grundlage existiert, aber das vollständige im Forschungsprogramm beschriebene Verhalten ist noch nicht vorhanden. |
| Vorgeschlagen | Ein für Umsetzung und Validierung empfohlenes Design; noch nicht gebaut. |
Dieses Dossier entstand aus einer internen Architektur-Review kombiniert mit einer direkten Prüfung der relevanten Quelldateien und des produktiven Datenbankschemas. Wo beide voneinander abwichen, ist hier der verifizierte Code-/Datenbankstand wiedergegeben.
2. Das CMA-Forschungsproblem
Large Language Models verfügen über ein begrenztes Arbeitsgedächtnis und kein inhärent persistentes, vertrauenswürdiges Gedächtnis früherer Interaktionen, Marktzustände oder Entscheidungen. Retrieval-Augmented Generation adressiert einen Teil dieser Einschränkung, doch Provenienz, zeitliche Gültigkeit und Aktualisierung bleiben in der allgemeinen Literatur offene Probleme. Finanzagenten verschärfen die Anforderungen weiter: Eine abgerufene Aussage kann zum Erzeugungszeitpunkt korrekt gewesen und nach einem Regimewechsel ungültig geworden sein; eine Analyse kann eine Inferenz statt einer Beobachtung sein; eine Policy kann sich geändert haben, nachdem ein Trade platziert wurde; und ein plausibles Narrativ darf niemals mit verifizierter Ausführungs-Evidenz verwechselt werden.
Forschungsproblem. Wie können heterogene Beobachtungen, probabilistische Agenten-Inferenzen, deterministische Policies, Ausführungszustände und spätere Outcomes als zeitlich gültige, semantisch typisierte, abrufbare und unabhängig verifizierbare Memories repräsentiert werden — ohne dass veränderliche Projektionen oder probabilistische Agenten historische Evidenz überschreiben können?
3. Aktuelle Implementierung, verifiziert gegen Code und Datenbank
core/aas_research.py baut AAS-inspirierte Symbol-Shells und erzeugt aktuell fünf Submodelle — Provenance, MacroRegimeContext, FactorEngineState, SignalDecision und LiveExecution — normalisiert in vier relationale Tabellen (aas_assets → aas_shells → aas_submodels → aas_submodel_elements).
| Submodell | Status | Zweck |
Provenance | Implementiert | Quelle, Task, Profil, Beobachtungszeitpunkt |
MacroRegimeContext | Implementiert | Marktregime und Readiness-Gate-Status |
FactorEngineState | Implementiert | Deterministische Faktorwerte (Preis, Volumen, Scores) |
SignalDecision | Implementiert | Vorgeschlagenes oder abgelehntes Handelssignal mit Begründung |
LiveExecution | Implementiert | Gewählte Broker-Route und Readiness |
Eine direkte Schema-Prüfung bestätigt, dass aas_shells und aas_submodels über INSERT ... ON CONFLICT DO UPDATE SET raw_json = EXCLUDED.raw_json schreiben — das SQL erlaubt also, eine Shell- oder Submodell-Zeile zu überschreiben. In der Praxis passiert das fast nie: Die IDs beider Tabellen enthalten die task_id des jeweiligen Laufs, die pro Market-Watch-Zyklus eindeutig ist, sodass jeder Zyklus frische Zeilen einfügt statt mit einer früheren zu kollidieren — eine direkte Zählung ergab, dass von 907.164 aas_shells-Zeilen nur 2 jemals tatsächlich über diesen Konflikt-Pfad aktualisiert wurden, und beide stammten von einer nicht verwandten, stabil-ID-basierten Closed-Loop-Tracking-Shell, nicht von einem Symbol-Research-Snapshot. Das reale Risiko dieser Tabellen ist heute also nicht stiller Historienverlust, sondern unbegrenztes, unkomprimiertes Wachstum — 907K Shell-Zeilen, 4,6 Mio. Submodell-Zeilen, 16,5 Mio. Element-Zeilen, zusammen ~14 GB und wachsend mit jedem Zyklus, dasselbe Wachstumsmuster, das GeoScore vor seiner eigenen Hypertable-Migration hatte (siehe die GeoScore-Research-Seite). Ein dedizierter, datenbankseitig erzwungener Event-Ledger schließt die engere Lücke "könnte theoretisch still überschrieben werden" und ergänzt explizite zeitliche/Autoritäts-Semantik, die diesen Tabellen fehlt; er löst für sich genommen nicht das Wachstumsproblem, das eine eigene Kompressions-Behandlung braucht.
Phase 1 — Event-Ledger und erster Producer. cma_memory_events existiert jetzt: eine dedizierte Tabelle mit dem oben beschriebenen Vier-Uhren-Zeitmodell, enum-geprüften Memory-/Autoritäts-/Lifecycle-Spalten und — einen Schritt weiter als gate_decisions — einem BEFORE UPDATE OR DELETE-Trigger, der Mutationen unbedingt blockiert, unabhängig von Datenbank-Rollenrechten. Das wurde live in Produktion verifiziert (ein manueller Insert, dann ein blockiertes UPDATE und ein blockiertes DELETE, beide zurückgerollt) zusätzlich zu 16 bestandenen Tests. Ein erster Producer ist jetzt angebunden: core/aas_research.py spiegelt jedes geschriebene AAS-Submodell zusätzlich als Event der Klasse observation in den Ledger, additiv und best-effort (ein Spiegelungsfehler wird geloggt, bricht nie den primären AAS-Write). Es ist hinter CMA_LEDGER_MIRROR gegated, default-OFF — passend zur etablierten Rollout-Konvention dieses Codebase für neue Observability-Hooks. Ein überwachter Beobachtungslauf (ein Market-Watch-Zyklus mit temporär aktiviertem Flag) bestätigte, dass es Ende-zu-Ende in Produktion funktioniert: 1.280 geschriebene Zeilen, 0 Spiegelungsfehler, korrekte Gruppierung und Inhalte — danach wurde das Flag wieder deaktiviert. Die Tabelle ist jetzt außerdem eine TimescaleDB-Hypertable auf event_time mit Compression-Policy (Chunks älter als 30 Tage werden automatisch komprimiert, Daten bleiben voll abfragbar) — aber bewusst ohne Retention-/Lösch-Policy, anders als beim GeoScore-Hypertable-Vorbild: Diese Tabelle ist CMA-Evidenz, und die Design-Prinzipien oben ("Vergessen darf die Auditierbarkeit nicht zerstören") verlangen ausdrücklich, dass sie dauerhaft erhalten bleibt, statt wie GeoScores enger gefasstes Signal-System zu verfallen und gelöscht zu werden. Es gibt weiterhin keine Projektions-Brücke, die den Ledger zurück in aas_shells/aas_submodels liest, und keinen weiteren angebundenen Producer (gate_decisions, GeoScore) — das bleiben offene Roadmap-Stufen (beide wurden in späteren Updates unten angebunden).
Phase 2 — AAS-Hypertable-Kompression. Das oben markierte Wachstumsproblem ist jetzt teilweise gelöst: aas_shells ist eine TimescaleDB-Hypertable auf created_at, mit derselben Nur-Kompression-Policy ohne Retention wie cma_memory_events — bewusst, weil diese Daten die Trade-Explainability-Behauptung des Whitepapers stützen und keine verwerfbaren Signal-Daten sind. Die Kind-Tabellen (aas_submodels, aas_data_statements) erhielten eine denormalisierte shell_created_at-Spalte und zusammengesetzte Fremdschlüssel auf die neue Hypertable, automatisch befüllt durch einen BEFORE INSERT-Trigger, sodass kein bestehender Writer-Code geändert werden musste; eine Zeile in core/aas_research.pys ON CONFLICT-Ziel wurde angepasst, um dem jetzt zusammengesetzten Unique-Constraint zu entsprechen. Live verifiziert: Hypertable, Compression-Policy und beide Trigger sind in Produktion aktiv, wobei der Trigger durch produktive Writes, die während des Migrationsfensters selbst eintrafen, als korrekt belegt wurde (null Zeilen mit NULL-shell_created_at). Stufe 2: aas_submodels — die größte der vier AAS-Tabellen (4,58 Mio. Zeilen, 13 GB) — ist jetzt ebenfalls eine Hypertable, mit derselben Nur-Kompressions-Behandlung und demselben denormalisierten-Zeitstempel-Muster, erweitert auf ihre eigenen Kind-Tabellen (aas_submodel_elements, aas_data_statements). Diese Stufe deckte eine echte Timescale-Einschränkung auf, die die erste Migration nicht betraf: Eine Hypertable darf selbst keinen ausgehenden Fremdschlüssel auf eine andere Hypertable halten, was beim ersten Versuch scheiterte (sauber zurückgerollt, kein Schaden), weil aas_submodels bereits auf die jetzt-Hypertable aas_shells verweist. Behoben durch Löschen dieses Fremdschlüssels — aas_submodels.shell_id ist jetzt eine weiche, anwendungsseitig erzwungene Referenz statt einer datenbankgeprüften, dasselbe Vertrauensmodell, das bereits für cma_memory_events.supersedes_event_id akzeptiert wurde. Stufe 3: aas_submodel_elements — die größte AAS-Tabelle nach Zeilenzahl (16,56 Mio. Zeilen, ~8 GB) — ist jetzt ebenfalls eine Hypertable. Unter Anwendung der Lehre aus der vorherigen Stufe wurden ihre beiden ausgehenden Fremdschlüssel (auf die jetzt-Hypertable aas_submodels sowie eine Selbstreferenz über parent_element_id) vor dem Aufruf von create_hypertable() gelöscht, wodurch dieser beim ersten Versuch gelang. Zwei Dinge wurden direkt gemessen statt angenommen: aas_qualifiers, die einzige weitere Tabelle neben aas_data_statements, die auf Elemente verweist, hat sich als leer und ohne Writer im gesamten Code erwiesen — totes Schema; und parent_element_id selbst ist bei allen 16,56 Mio. Zeilen NULL — das Element-Hierarchie-Feature, das dieser gelöschte Fremdschlüssel schützte, wurde in Produktion nie tatsächlich genutzt. Stufe 4 — Plan abgeschlossen. aas_data_statements (10,97 Mio. Zeilen, 13 GB) ist jetzt ebenfalls eine Hypertable, womit alle vier AAS-Tabellen abgeschlossen sind. Diese Stufe erwies sich als strukturell einfacher als die vorherigen Stufen erwarten ließen: Nichts referenziert diese Tabelle per Fremdschlüssel, daher waren überhaupt keine denormalisierten Spalten oder Trigger nötig — nur das Löschen ihrer drei ausgehenden zusammengesetzten Fremdschlüssel auf die anderen, jetzt-Hypertable-AAS-Tabellen (alle werden zu weichen Referenzen, wie zuvor) und die Partitionierung auf observed_at, ihre einzige Zeitstempel-Spalte. Für diese Stufe war keine Code-Änderung nötig. Alle vier AAS-Tabellen — aas_shells, aas_submodels, aas_submodel_elements, aas_data_statements — sind jetzt komprimierte TimescaleDB-Hypertables ohne Retention-Policy; nur aas_assets bleibt zu Recht eine reguläre Tabelle, da sie tatsächlich upserted wird (~650 Zeilen). Die Wachstumslimitation, die dieser gesamte Update-Strang verfolgt hat, ist damit gelöst.
Phase 3 — Projektions-Brücke (Roadmap-Punkt 4). Ein schreibgeschütztes Modul (trading/cma/projection.py) rekonstruiert jetzt den letzten AAS-Submodell-Zustand rein aus cma_memory_events und vergleicht ihn mit den lebenden aas_submodels-Zeilen — der erste direkte Test des oben genannten Design-Prinzips ("der aktuelle Zustand ist eine Projektion... immer aus unveränderlichen Events abgeleitet") und von RQ-B (Evidenz-Rekonstruktion) gegen echte Daten statt einer Annahme. Ausgeführt gegen jede Shell, die der Ledger je gesehen hat (der Spiegelungs-Nachweislauf aus Phase 1): 256 von 256 Shells und 1.280 von 1.280 Submodellen rekonstruieren exakt — eine gemessene 100%-Trefferquote. Das ist ein eng gefasstes Ergebnis, präzise formuliert statt überverkauft: ein Producer (AAS-Submodell-Spiegelung), ein überwachter Lauf, nur Events der Klasse observation, und Inhalte, die konstruktionsbedingt eine wörtliche Kopie sind (der Spiegelungscode übergibt das Submodell-Dict unverändert in content_json) — exakte Gleichheit ist also das erwartete, hier verifizierte Ergebnis, noch keine Aussage über Rekonstruktion aus entfernter verwandter oder teilweise abgeleiteter Evidenz. Es ist dennoch eine echte Live-Messung mit einem realen Fehlermodus (eine Abweichung, oder eine nur einseitig vorhandene Zeile), der nicht eingetreten ist — kein synthetischer Benchmark. 9 neue rollback-isolierte Tests decken beide Drift-Richtungen ab (nur im Ledger; nur in AAS) sowie die Match-/Mismatch-Fälle direkt. Beim Bau wurde zudem ein echter, CMA-unabhängiger Bug gefunden und behoben: Ein Session-Lifecycle-Helfer schloss jede übergebene Datenbank-Session bedingungslos beim Verlassen — das bricht für jeden Aufrufer, der eine länger lebende Session übergibt (nicht nur Tests) — behoben durch Angleichung an das bereits sicherere Muster in trading/db/order_store.py.
Die Tabelle gate_decisions ist eine separate Evidenzstruktur. Ihr Writer (trading/policy/decision_store.py) enthält im Code keinen Update- oder Delete-Pfad — jeder Aufruf wirft entweder vor dem Schreiben eine Exception (fail-closed-Validierung) oder fügt genau eine Zeile ein. Eine Live-Schema-Prüfung fand die Nuance, die für eine ehrliche Aussage zählt: Zu diesem Zeitpunkt wurde die Append-only-Garantie nur durch Code-Disziplin der Anwendung erzwungen, nicht durch die Datenbank — kein Trigger blockierte Mutationen, und die eigene Datenbankrolle der Anwendung besaß weiterhin reguläre UPDATE/DELETE-Rechte auf der Tabelle.
Phase 4 — gate_decisions datenbankseitig erzwungen. Diese Lücke ist geschlossen: gate_decisions trägt jetzt denselben BEFORE UPDATE OR DELETE-Trigger, der bereits bei cma_memory_events bewiesen wurde, und weist Mutationen unbedingt zurück, unabhängig von Rollenrechten. Die eigenen UPDATE/DELETE-Rechte der Datenbankrollen bleiben bewusst bestehen — sie zu entziehen wäre eine separate, größere Änderung, die jede Rolle mit legitimen anderen Rechten auf dieser Tabelle betrifft — aber der Trigger allein schließt die eigentliche Lücke bereits: Ein manuelles UPDATE und DELETE per Raw-SQL wurden beide live getestet und blockiert. gate_decisions und cma_memory_events sind jetzt beide datenbankseitig erzwungenes Append-only. Keines von beiden ist bereits kryptografisch manipulationssicher — es existiert heute keine Content-Hash-, Previous-Hash-Ketten- oder Signatur-Spalte auf irgendeiner Evidenz-Tabelle.
Phase 5 — gate_decisions als zweiter Producer. gate_decisions ist jetzt als zweiter Producer des Ledgers angebunden: Jede geschriebene Entscheidung wird zusätzlich als memory_type='decision'-, authority='deterministic_derived'-Event in cma_memory_events gespiegelt (trading/policy/decision_store.py), best-effort und ohne den Primärschreibvorgang je zu blockieren, hinter einem eigenen, standardmäßig deaktivierten Flag (CMA_LEDGER_MIRROR_GATE_DECISIONS), bewusst getrennt vom AAS-Producer-Flag, da dieser Writer auf dem Live-Order-Ausführungspfad liegt. Anders als beim AAS-Producer ist dies noch nicht live nachgewiesen: Zwei überwachte nächtliche Beobachtungsfenster fanden keine organische gate_decisions-Zeile zum Spiegeln — die Plattform läuft global im dry_run-Modus, und in keinem der beiden Fenster erzeugten die Paper-Mode-Zyklen eine zu routende Order-Intention. Beide Versuche fanden Freitagnacht/am Wochenende statt, wenn die Handelszeiten-gegateten Equity-Strategien gar nicht feuern; ein dritter Versuch ist für einen Werktag mit aktiven Krypto- und Equity-Timern geplant.
Phase 6 — GeoScore als dritter Producer. Die Scoring-Pipeline von GeoScore (trading/geoscore/scoring.py:score_pending) ist jetzt als dritter Producer des Ledgers angebunden: Jede zusammengesetzte geoscore_event_scores-Zeile wird zusätzlich gespiegelt, eine Zeile pro Asset × Horizont, als memory_type='assertion'-, authority='model_inferred'-Event — der erste Producer, der tatsächlich die Cross-Field-Validierungsregel von model_inferred auslöst (sowohl model_version als auch prompt_version erforderlich), mit GeoScores eigener aufgelöster Modell-ID und ihrer geoscore-prompt-v2-Vertragsversion. Best-effort, blockiert nie den primären Score-Write, hinter einem eigenen, standardmäßig deaktivierten Flag (CMA_LEDGER_MIRROR_GEOSCORE). Abgedeckt durch gemockte Unit-Tests und einen rollback-isolierten Real-DB-Test, der Inhalt und Anzahl der gespiegelten Zeilen gegen ein geseedetes Event prüft — noch nicht live in Produktion beobachtet, derselbe offene Schritt wie beim zweiten Producer oben.
Vorfall — ein "rollback-isolierter" Real-DB-Test war es nicht. Beim Bau der Retrieval-API unten kam bei einer unabhängigen Prüfung heraus, dass GeoscoreLedgerMirrorRealDbTest (der Real-DB-Test für den Producer oben) seit seiner Erstellung bei jedem Lauf still echte Zeilen in die produktive cma_memory_events committed hatte — 27 Zeilen, IDs 1480–1800, alle mit dem unverwechselbaren Fake-Ticker stream_id='geoscore:ZZZTESTBTC:*'. Ursache: _mirror_geoscore_score_to_ledger() ruft record_memory_event() bewusst ohne session-Argument auf (die Spiegelung läuft absichtlich in einer eigenen Transaktion, getrennt vom Primär-Write — dieselbe Konvention wie bei jedem Producer in diesem Abschnitt); dieser Fallback-Pfad löst seine Session über trading.db.order_store._SESSION_FACTORY auf, und der Test hat diesen Hook nie auf seine eigene rollback-isolierte Session umgeleitet — anders als der entsprechende gate_decisions-Test, der das tut. Die primären GeoScore-Tabellen waren durchgehend korrekt isoliert (verifiziert: null Leichen in geoscore_events/geoscore_event_scores) — nur die separat-transaktionale Ledger-Spiegelung entkam. Behoben durch denselben Session-Factory-Redirect, den der gate_decisions-Test bereits nutzte; nach dem Fix über zwei weitere Läufe hinweg als sauber verifiziert (Zeilenzahl unverändert). Die 27 bereits geleakten Zeilen wurden bewusst nicht über eine Deaktivierung des Append-only-Triggers entfernt — konsistent mit dem eigenen Grundsatz dieses Ledgers, dass Fehler dokumentiert statt getilgt werden, und sie sind harmlos: inert, eindeutig als Fake erkennbar und allein durch ihren Fake-Ticker aus den Rekonstruktions- und Audit-Messungen dieses Dossiers ausgeschlossen.
Phase 7 — Hash-Kette (Roadmap-Punkt 9, Teil 1 von 2). Die beiden reservierten Integritäts-Spalten von cma_memory_events (content_hash, previous_event_hash) werden jetzt befüllt, wenn die Hash-Kette in trading/cma/chain.py aktiviert ist: Der content_hash jeder Zeile ist ein SHA-256 ihres kanonisierten content_json, und previous_event_hash verkettet sie mit dem Hash der vorherigen Zeile — eine verkettete Liste, an die alle drei Producer transparent anschließen können, ohne selbst geändert zu werden. Eine Postgres-Advisory-Transaktionssperre serialisiert den Schritt „letzten Hash lesen, dann einfügen", sodass konkurrierende Producer nie um denselben Kettenglied konkurrieren können. Ein begleitendes verify_chain() durchläuft den Ledger und prüft sowohl einen Content-Re-Hash als auch die Ketten-Kontinuität; die Erkennungslogik ist direkt gegen konstruierte manipulierte/gelöschte/eingeschleuste Zeilen unit-getestet (eine echte manipulierte Zeile in der Live-Tabelle zu erzeugen ist nicht möglich — der Append-only-Trigger oben blockiert das bereits, was selbst ein aussagekräftiges Ergebnis ist: Diese Hash-Kette ist Verteidigung in der Tiefe für ein Szenario, in dem dieser Trigger umgangen wird, z. B. eine Wiederherstellung aus einem extern manipulierten Dump, nicht die primäre Absicherung). Praktisches kanonisches JSON (sortierte Schlüssel, UTF-8, keine Leerzeichen), ausdrücklich keine zertifizierte RFC-8785(JCS)-Implementierung — Zahlenformatierung und Nicht-BMP-Schlüsselreihenfolge sind nicht JCS-exakt, eine echte Lücke gegenüber der ursprünglichen Formulierung des Roadmap-Punkts. Hinter CMA_LEDGER_HASH_CHAIN gegated, default-OFF, noch nicht in Produktion aktiviert.
Phase 8 — Ed25519-Signaturen (Roadmap-Punkt 9, Teil 2 von 2). Eine Migration fügte zwei weitere nullable Spalten hinzu (signature, signing_key_id), und trading/cma/signing.py signiert jetzt bei Aktivierung das Hash-Ketten-Glied jeder Zeile (content_hash, previous_event_hash, plus stream_id/event_type/event_time, damit eine Signatur nicht auf eine fremde Zeile übertragen werden kann) mit einem Ed25519-Private-Key. signing_key_id ist ein kurzer, nicht-geheimer Fingerabdruck des öffentlichen Schlüssels — bewusst kein fest im Verifier verdrahteter Schlüssel, sodass eine künftige Schlüsselrotation die Verifizierbarkeit alter Zeilen nicht rückwirkend zerstört. Ein begleitendes verify_signatures() prüft jede signierte Zeile gegen eine vom Aufrufer übergebene Schlüssel-Map und meldet eine Zeile mit unbekanntem Schlüssel getrennt von einer tatsächlich ungültigen Signatur, da beides Unterschiedliches bedeutet (Abdeckungslücke des Verifiers vs. echte Manipulation). Der private Schlüssel selbst (CMA_LEDGER_SIGNING_KEY) wird ausschließlich aus der Umgebung gelesen, nie in die Datenbank oder dieses Repository geschrieben — und ist heute nicht gesetzt: Es existiert kein generierter Produktions-Schlüssel, CMA_LEDGER_SIGN_CHAIN ist nicht gesetzt/OFF, und Signieren setzt voraus, dass auch die Hash-Kette oben aktiviert ist. Roadmap-Punkt 9 (Hash-Kette und Signaturen) ist jetzt Ende-zu-Ende gebaut; Punkt 10 (externe Merkle-Checkpoints) bleibt offen.
Phase 9 — Retrieval-API, Teil 1 (Roadmap-Punkt 5). trading/cma/retrieval.py macht aus RQ-A eine abfragbare Funktion statt nur einer Hypothese: retrieve(as_of=T, ...) beantwortet „was wusste der Ledger zum Zeitpunkt T, und hielt es zu diesem Zeitpunkt für gültig" durch zwei Bedingungen: ingested_at <= T (eine Point-in-Time-Abfrage darf nie Informationen sehen, die das System erst später erfahren hat) und valid_from <= T < valid_to (halboffen, NULL bei valid_to bedeutet weiterhin gültig) — die Zwei-Uhren-Unterscheidung der CMA-Design-Prinzipien, jetzt in einer WHERE-Klausel erzwungen statt nur in Prosa behauptet. Ein begleitendes retrieve_latest_per_stream() nutzt Postgres DISTINCT ON (nicht ein naives Top-N-dann-Gruppieren, was ein rollback-isolierter Test nachweislich zum stillen Verlust eines echten Ergebnisses geführt hätte: Ein Stream mit wenigen Events kann von einem Stream mit vielen aus einer einfach abgeschnittenen Ergebnismenge verdrängt werden). Beide Funktionen akzeptieren zusätzlich gewöhnliche Scope-Filter (Tenant, Profil, Strategie, Asset, Memory-/Event-Typ, Autorität, Correlation-ID) und schließen standardmäßig nicht-aktive Lifecycle-Zeilen aus. Bewusst eng gefasst zum Zeitpunkt dieser Phase: kein Ranking, keine lexikalische oder Dense-Suche, keine Golden-Set-Evaluation — das war die Grundlage, auf der die späteren Phasen aufbauen, noch kein fertiges Retrieval-System (Roadmap-Punkte 7 und 8, beide unten separat inzwischen ausgeliefert). Die Docstring warnt ausdrücklich davor, dies ohne explizite tenant_id-Übergabe an einem mandantenfähigen Endpunkt zu exponieren, angesichts der eigenen früheren Evidence-API-Cross-Tenant-Leck-Historie dieses Codebase. 7 neue rollback-isolierte Tests.
Phase 10 — Prompt-/Modell-Registry (Roadmap-Punkt 6). trading/cma/model_registry.py ist eine kleine, code-basierte Registry bekannter (Komponente, Prompt-Version)-Paare, jeder Eintrag mit dem echten Git-Commit und Datum, das ihn eingeführt hat — bewusst keine Datenbanktabelle: GeoScores eigene Versionsdisziplin lebt bereits in der Git-Historie (eine versionierte PROMPT_VERSION-Konstante, vor jedem Rollout gegen ein Golden Set evaluiert), und eine separate mutable Registry-Tabelle könnte selbst von dem Code abdriften, den sie beschreiben soll — das Gegenteil dessen, wofür eine Registry da ist. Der Bau gegen echte Historie deckte eine echte, bisher undokumentierte Lücke auf: Eine frühere Kalibrierungsrunde, die fünf VIP-/Influencer-Golden-Set-Events ergänzte (Commits 880e3e1a/99b35ad8, 7/10 → 14/15), hat PROMPT_VERSION nie angehoben — nach wie vor geoscore-prompt-v2. Ehrlich im Registry-Eintrag vermerkt, statt rückwirkend ein "v2.1" zu erfinden, das dieser Codebase nie genutzt hat. Ein schreibgeschütztes audit_ledger_versions() durchsucht den lebenden Ledger nach jeder model_inferred-Zeile, deren (Komponente, Prompt-Version)-Paar diese Registry nicht kennt; gegen die Produktion ausgeführt fand es null unregistrierte Versionen (die einzigen model_inferred-Zeilen des Ledgers sind die 27 oben erwähnten geleakten Testzeilen, die zufällig eine echt registrierte Version tragen). Nicht als Enforcement-Gate in record_memory_event eingebunden — das wäre eine separate, spätere Entscheidung an einem bereits HIGH-Risk eingestuften, gemeinsam genutzten Writer, nicht Teil der Einführung dieser Registry selbst. 12 neue Tests, darunter einer, der den echten aktuellen Registry-Stand fixiert, sodass ein künftiges geoscore-prompt-v3 ohne passenden Eintrag laut fehlschlägt.
Phase 11 — Golden Set + CI-Non-Regression (Roadmap-Punkt 7). trading/cma/golden/cma_retrieval_golden_set.json friert 5 retrieve()-/retrieve_latest_per_stream()-Abfragen gegen echte, unveränderliche Zeilen aus dem AAS-Spiegelungs-Nachweislauf aus Phase 1 ein (die 5 Submodelle der TXN-Research-Shell, IDs 1276–1280), jede mit einer exakt erwarteten Evidenz-ID-Menge — keine Bereiche wie bei GeoScores LLM-bewertetem Golden Set, weil Retrieval über einen Append-only-Ledger bei fester Evidenz genau eine richtige Antwort hat. tests/test_cma_golden_set_unittest.py spielt jeden Fall gegen die lebende Datenbank als normalen Teil der pytest-Suite ab: echte CI-Non-Regression, kein separates Eval-Skript nötig. Der Bau des "aktueller Zustand je Stream"-Falls deckte einen echten Bug auf, bevor er je fixiert wurde: Alle 5 Zeilen der TXN-Shell teilen sich ein event_time (in einem Market-Watch-Zyklus gespiegelt), und der bis dahin nicht existierende Tiebreak von retrieve_latest_per_stream() gab still Postgres' Scan-Reihenfolge zurück, die beobachtbar die erst-eingefügte Zeile der Gruppe lieferte — die falsche Richtung für "aktueller Zustand". Behoben durch ein explizites id DESC als Tiebreak (die zuletzt in den Ledger gelangte Zeile gewinnt jetzt); der Tiebreak-Fall des Golden Sets fixiert das korrigierte Verhalten gegen dieselben echten Daten, die den Bug aufgedeckt haben, sodass eine Regression sofort auffiele statt neu entdeckt zu werden.
Phase 12 — Hybrides Retrieval (Roadmap-Punkt 8). Dieser Codebase hatte vor dieser Phase keine Vektorsuch-Infrastruktur: kein pgvector, kein Embedding-Generierungscode irgendwo, keine Embeddings-Oberfläche in der AION-MCP-Integration (direkt geprüft, nicht angenommen). Was bereits lief, war nomic-embed-text (768-dim, ein dediziertes Embedding-Modell, bestätigt vorhanden) auf derselben GPU-Ollama-Instanz, von der GeoScores LLM-Aufrufe bereits abhängen (100.98.188.22:11434) — der Bau brauchte also eine neue Postgres-Extension und einen neuen Python-Client, kein neues Modell und keinen neuen Server. Installiert wurde pgvector 0.8.1 (bestätigt von der bestehenden Rolle zentrader_researcher ohne Superuser installierbar — eine "trusted" Extension), plus eine nullable vector(768)-Spalte und ein HNSW-Cosine-Distance-Index auf cma_memory_events. Weil die Tabelle append-only ist, können Embeddings nicht wie eine normale "reservierte Spalte" nachträglich per UPDATE befüllt werden — trading/cma/embeddings.pys apply_embedding() läuft nur beim Insert, neben Hash-Kette und Signierung, und berechnet einen Vektor aus search_text, wenn vorhanden. Anders als bei diesen beiden wird ein fehlgeschlagener Embedding-Aufruf abgefangen und geloggt, nie geworfen: Es ist ein Netzwerkaufruf an eine entfernte GPU, der auch bei korrekter Konfiguration transient fehlschlagen kann, und der Evidenz-Vertrag des Ledgers darf nicht von der Erreichbarkeit dieser GPU abhängen. lexical_search() (Postgres ts_rank über den GIN-Index, den diese Tabelle seit Phase 1 trägt), dense_search() (pgvector Cosine Distance) und hybrid_search() (Min-Max-normalisierte gewichtete Fusion beider) sind drei unabhängig austauschbare Bausteine — die vom Roadmap-Punkt geforderte "austauschbare Schnittstelle". Einmal echt gegen die GPU verifiziert, Ende-zu-Ende, außerhalb der dauerhaften Test-Suite (in allen committeten Tests gemockt, passend dazu, dass auch GeoScores eigene Tests nie die echte Ollama-Instanz aufrufen): Eine Anfrage nach "Zentralbank Geldpolitik Zinsentscheidung" rankte über das Dense-Signal allein korrekt eine Zeile über "Fed signalisiert Zinssenkungen" ganz oben (lexikalischer Score 0 — kein gemeinsames Wort), ein echter semantischer Treffer, nicht nur Keyword-Überlappung. Beide neuen Flags (CMA_LEDGER_EMBED, gated die Insert-Zeit-Berechnung) default-OFF; kein Embedding wurde je in eine echte Produktionszeile geschrieben. 22 neue Tests über drei Dateien; komplette cma/geoscore/gate_decision/aas-Suite grün (263 bestanden), zusätzlich ein voller 1.826-Test-Gesamtlauf ohne Regressionen anderswo (2 vorbestehende, unabhängige Fehlschläge in einem unverwandten API-Bereich, von dieser Arbeit unberührt).
Phase 13 — die Model-Registry fängt ihre eigene Art von Drift ein zweites Mal. Phase 10 vermerkte ehrlich, dass GeoScores Prompt-Konstante trotz einer undokumentierten Kalibrierungsänderung noch geoscore-prompt-v2 war. Inzwischen ist geoscore-prompt-v3 ausgeliefert: eine neue, gegen das Golden Set evaluierte Änderung (eine TRACKED_ASSETS-Präferenzliste für Asset-Benennung, Golden Set 13/15 mit n=3 Self-Consistency-Läufen) hat die Version diesmal korrekt angehoben — geoscore-prompt-v2 ist in trading/cma/model_registry.py jetzt als deprecated markiert, geoscore-prompt-v3 ist der neue active-Eintrag mit den echten einführenden Commits. Die zwei Golden-Set-Fehlschläge, die unter v3 bleiben (ein Memecoin-Post-Score-Bereich, Exchange-Hack-Faktor-Vorzeichen), sind vorbestehende, von dieser Änderung unabhängige Kalibrierungslücken, keine neue Regression. Ein echter, kleiner Beleg für den eigentlichen Zweck der Registry: Eine reale Versionsänderung ist passiert, und sie landete in der Registry statt ein zweites Mal still zu verdriften.
GeoScore, die qualitative Narrativ-Scoring-Pipeline der Plattform, ist die reifste Vorlage im Repository für die von CMA benötigte Evaluations-Disziplin: Jede Prompt- oder Modelländerung wird vor dem Rollout gegen ein versioniertes, bandbasiert bewertetes Golden Set evaluiert, das Scoring selbst ist eine deterministische, unit-getestete Funktion der strukturierten (nie numerischen) LLM-Ausgabe, und ein erneutes Scoring überschreibt nie eine Zeile — es fügt eine neue ein, verkettet über superseded_by. Genau dieses Append-and-Chain-Muster soll der vorgeschlagene CMA-Event-Ledger über alle Memory-Klassen hinweg verallgemeinern, nicht nur für Narrativ-Scores.
4. Forschungsfragen und Hypothesen
| Frage | Hypothese |
| RQ-A — Zeitliches Retrieval. Ruft CMA Informationen, die zum angefragten Entscheidungszeitpunkt gültig waren, zuverlässiger ab als Recency, lexikalisches oder rein dichtes Retrieval? | Hybrides CMA-Retrieval verbessert die zeitliche Gültigkeitsgenauigkeit und nDCG@k gegenüber Recency-only-, BM25-only- und Dense-only-Baselines. |
| RQ-B — Evidenz-Rekonstruktion. Lässt sich eine vergangene Entscheidung aus ihren exakten Daten-, Memory-, Modell-, Prompt-, Strategie- und Policy-Zuständen rekonstruieren? | CMA erreicht eine höhere vollständige Rekonstruktionsrate und eine niedrigere Rate unbelegter Behauptungen als Freitext-Journale oder unversioniertes RAG. |
| RQ-C — Umgang mit Widersprüchen. Reduzieren explizite Gültigkeit, Supersession und Quellenautorität den Abruf veralteter oder widersprüchlicher Memories? | Gültigkeitsbewusstes Retrieval reduziert veraltete Memory-Einbindung und Widerspruchsfehler gegenüber reinem Zeitstempel-Retrieval. |
| RQ-D — Kontrollierte Konsolidierung. Verbessern abgeleitete Reflexionen Multi-Hop-Reasoning, ohne mit Primärevidenz verwechselt zu werden? | Evidenzgebundene Reflexionen verbessern Multi-Hop-Retrieval bei erhaltener Evidenz-Präzision. |
| RQ-E — Memory-Ökonomie. Reduziert gerankter, komprimierter Speicher Kontextgröße und Latenz, ohne die Entscheidungsqualität wesentlich zu verschlechtern? | CMA verwendet weniger Prompt-Tokens als Full-Context-Baselines bei nicht-unterlegener Aufgabengenauigkeit. |
| RQ-F — Manipulationssicherheit. Können Kanonisierung, Hashing und Signaturen unautorisierte Änderung oder Auslassung gespeicherter Evidenz erkennen? | Eingeschleuste Datensatz-Mutationen werden erkannt, und Auslassungsangriffe sind gegen unabhängig gehaltene Checkpoints erkennbar. |
Vorläufige technische Zielwerte — nach einem gelabelten Pilotlauf und vor Öffnung eines Holdouts festzulegen — umfassen eine absolute Verbesserung der zeitlichen Gültigkeitsgenauigkeit um fünf Prozentpunkte, mindestens 95 % vollständige Entscheidungsrekonstruktion, null unentdeckte Mutationen in einer adversariellen Testsuite und mindestens 30 % weniger Prompt-Tokens als Full-Context-Retrieval bei nicht-unterlegener Genauigkeit. Dies sind zu testende Validierungsschwellen, keine aktuellen Produktbehauptungen.
5. Design-Prinzipien
Die formale CMA wird von sechs Invarianten geleitet:
- Evidenz ist unveränderlich. Beobachtungen, Entscheidungen, Ausführungen und Outcomes werden angehängt, nie überschrieben.
- Der aktuelle Zustand ist eine Projektion. Der "aktuell bekannte Zustand" kann neu aufgebaut werden, ist aber immer aus unveränderlichen Events abgeleitet.
- Zeit hat mehr als eine Bedeutung. Beobachtungszeit, Ereigniszeit, Erfassungszeit und Gültigkeitsintervall werden getrennt gespeichert.
- Autorität ist explizit. Broker-Fakten, deterministische Berechnungen, menschliche Aussagen und LLM-Inferenzen sind eigene Memory-Klassen mit eigenen Vertrauensstufen.
- Agenten schlagen vor; deterministische Dienste committen. Ein Agent kann einen Memory-Write anfragen, aber Schema-, Mandanten-, Policy-, Provenienz- und Autoritätsprüfungen entscheiden über die Annahme.
- Vergessen darf die Auditierbarkeit nicht zerstören. Decay, Zusammenfassung und Archivierung betreffen Retrieval und Kosten, nie den zugrunde liegenden Evidenz-Ledger.
6. Memory-Taxonomie (Auszug)
| Klasse | Definition | Veränderbarkeit |
| Observation | Direkt von einer definierten Quelle erhaltene Daten | Append-only |
| Assertion | Eine aus Beobachtungen abgeleitete Behauptung | Superseded, nie überschrieben |
| Decision | Deterministisches oder menschliches Gate-Ergebnis | Append-only |
| Execution | Broker-seitige Aktion und gemeldeter Zustand | Append-only Event-Stream |
| Reconciliation | Abgleich zwischen internen und Broker-Zuständen | Append-only |
| Outcome | Spätere Evidenz zur Bewertung einer früheren Assertion/Decision | Append-only |
| Projection | Materialisierte aktuelle Sicht (z. B. heutige aas_shells) | Neu aufbaubar und veränderlich |
7. Bezug zu verwandten Arbeiten
Die gesichtete Literatur liefert einzeln starke Lösungen für Langzeit-Retrieval, Reflexion, Graph-Memory, Finanz-Memory und Provenienz. ZenTraders Design ist insofern ungewöhnlich, als es diese mit AAS-inspirierten semantischen Zwillingen, deterministischer Policy-Evidenz und Multi-Broker-Reconciliation kombiniert — das ist jedoch eine Forschungsvermutung, keine belegte Alleinstellungsbehauptung; eine systematische Literaturrecherche steht vor einer Veröffentlichung noch aus.
| Feld | Implikation für CMA |
| AAS & digitale Zwillinge (IDTA-Metamodell) | AAS-Identitäts-/Shell-/Submodell-Prinzipien nutzen; ein dokumentiertes ZenTrader-Kompatibilitätsprofil pflegen statt Konformität zu behaupten. |
| Retrieval-Augmented Generation | Externe, abfragbare Evidenz behalten statt Modellgewichte als Systemgedächtnis zu behandeln. |
| Generative Agents (Park et al.) | Gerankte Retrieval- und Reflexionsmuster übernehmen, Reflexionen aber an Evidenz binden, damit sie nicht stillschweigend zu Fakten werden. |
| MemGPT | Explizite Retrieval-Schnittstellen bereitstellen; ein LLM darf die deterministische Write-Policy nie umgehen. |
| MemoryBank | Decay nur auf die Retrieval-Sichtbarkeit anwenden, nie auf unveränderliche Finanz-Evidenz. |
| HippoRAG | Graph-/PageRank-Erweiterung erst nach stabiler relational-zeitlicher Baseline erwägen. |
| FinMem | CMA gegen eine geschichtete Finanz-Memory-Baseline vergleichen; über Evidenz-Governance und zeitliche Provenienz differenzieren, nicht nur über Schichtung. |
| LoCoMo | Task-Taxonomie als allgemeinen Memory-Sanity-Check nutzen; separat einen finanzspezifischen zeitlichen Benchmark aufbauen. |
| W3C PROV | Datensätze, Prompts, Modelle, Policies, Agenten und Entscheidungen auf ein explizites Provenienz-Vokabular abbilden. |
8. Validierungsprogramm
Fünf Eigenschaften werden unabhängig getestet statt auf Trading-Profitabilität reduziert, die von Strategiequalität, Regime und Kosten abhängt und allein nicht belegen kann, dass die Memory-Architektur besser ist:
- Retrieval-Qualität — findet CMA die korrekte Evidenz?
- Zeitliche Korrektheit — ruft es nur ab, was zum angefragten Zeitpunkt bekannt und gültig war?
- Entscheidungsrekonstruktion — kann ein unabhängiger Prüfer reproduzieren, was das System wusste und warum es handelte?
- Operative Effizienz — welche Latenz-, Token- und Speicherkosten verursacht das Memory?
- Integritätsprüfung — lassen sich Veränderung, Kürzung und inkonsistente Historie erkennen?
Baselines reichen von No-Memory- und Full-Context-Extremen über Recency/BM25/Dense-RAG, Generative-Agents-artiges Scoring, eine FinMem-artige geschichtete Baseline bis zu drei CMA-Konfigurationen (relational, hybrid, Graph+Reflexion). Die finale konfirmatorische Evaluation soll — im OSF-Sinn eines zeitgestempelten, schreibgeschützten, vor Zugriff auf das Holdout eingefrorenen Plans — präregistriert werden, bevor ein Kernergebnis veröffentlicht wird.
Konkrete Validierungs-Meilensteine
| Meilenstein | Abschlusskriterium |
| Memory-Event-Schema | JSON-Schema-Validierung und Datenbank-Constraints stimmen bei gültigen/ungültigen Fixtures überein |
| Zeitliche Abfragen | Alle synthetischen bitemporalen Testfälle bestehen, inklusive verspäteter Korrekturen |
| Evidenz-Rekonstruktion | Mindestens 95 % der gelabelten Entscheidungen rekonstruieren mit vollständiger Pflicht-Evidenz |
| Golden Set | Versionierter Query-Satz, Evaluator und Non-Regression-CI sind operativ |
| Hashing & Signaturen | Mutation-, Reorder- und Wrong-Predecessor-Tests scheitern erwartungsgemäß an der Verifikation |
| Präregistrierte Evaluation | Gesperrtes Holdout wird einmalig nach dem registrierten Plan analysiert |
9. Limitationen
- Standard-Umfang. ZenTrader entlehnt AAS-Konzepte, verwendet aber eine domänenspezifische JSON-Form und relationale Normalisierung. Volle AAS-Konformität kann erst behauptet werden, wenn Serialisierung und Schnittstellen gegen die offiziellen IDTA-Spezifikationen getestet sind.
- Aktuelle Event-Unveränderlichkeit; unbegrenztes Wachstum gelöst. Gate-Decisions sind im Anwendungscode append-only und, in einer späteren Phase, zusätzlich durch einen Trigger datenbankseitig erzwungen, wie
cma_memory_events; AAS-Shell- und Submodell-Writes sind technisch Upserts, wobei eine direkte Zählung ergab, dass der Konflikt-Pfad in der Praxis fast nie feuert (2 von 907.164 Zeilen), weil die task_id jedes Zyklus die IDs eindeutig macht — das historische reale Risiko war unbegrenztes, unkomprimiertes Wachstum (~14 GB über vier AAS-Tabellen und wachsend), nicht stilles Überschreiben, und dieses Wachstumsproblem ist inzwischen gelöst: Alle vier AAS-Tabellen (aas_shells, aas_submodels, aas_submodel_elements, aas_data_statements) sind jetzt komprimierte TimescaleDB-Hypertables ohne Retention-/Lösch-Policy, abgeschlossen über vier inkrementelle Migrationen in einer Phase dieses Programms — und es hält: seither erneut gemessen sind die kombinierten Zeilenzahlen bei drei der vier Tabellen um 20-30% gewachsen (jetzt 1,15 Mio. / 5,80 Mio. / 21,0 Mio. / 10,97 Mio. Zeilen), doch der kombinierte komprimierte Speicherbedarf liegt bei ~8,3 GB, gegenüber der ~14-GB-Basis vor der Kompression. Ein dedizierter, datenbankseitig erzwungener Event-Ledger (cma_memory_events) existiert ebenfalls bereits, mit drei angebundenen Producern (AAS-Submodell-Spiegelung, gate_decisions, GeoScore), jeweils hinter eigenem default-OFF-Flag — eine separate, engere Lücke (Überschreib-Schutz und zeitliche/Autoritäts-Semantik) als das Wachstumsproblem, und weiterhin offen bis zur Produktivaktivierung.
- Quellenwahrheit. Eine künftige Hash-Kette würde beweisen, dass Inhalte sich gegenüber einem Checkpoint nicht verändert haben — nicht, dass ein Broker, eine Nachrichtenquelle, ein Modell oder eine menschliche Aussage korrekt war.
- Nicht-Stationarität. Finanzregime, Broker-Verhalten und Modelle ändern sich über die Zeit; Ergebnisse aus einem festen historischen Fenster generalisieren möglicherweise nicht, daher ist zeitliche Kreuzvalidierung zwingend.
- Private Reproduzierbarkeit. Proprietäre Daten und Code begrenzen die vollständige externe Replikation; ein synthetischer Benchmark, öffentliche Schemas und eingefrorene Evaluationsartefakte sind geplant, um dies zu mildern, ohne Trading-IP zu veröffentlichen.
10. Roadmap
Die Roadmap priorisiert Schema-Stabilität sowie zeitliche und Evidenz-Korrektheit vor Embeddings, Graphdatenbanken oder autonomer Reflexion:
- Terminologie- und ADR-Freeze (Memory-Taxonomie, Autoritätsklassen, zeitliche Semantik)
- JSON-Schema-Paket mit gültigen/ungültigen Fixtures
- Erledigt Unveränderlicher Event-Ledger (
cma_memory_events; nur-einfügend, DB-Trigger-erzwungen — drei Producer angebunden: AAS-Submodelle, gate_decisions, GeoScore, jeweils hinter eigenem default-OFF-Flag; der AAS-Producer live in Produktion nachgewiesen, die anderen beiden bisher nur testverifiziert)
- Erledigt Projektions-Brücke von Events in die bestehenden AAS-Tabellen (schreibgeschützte Rekonstruktion + Verifikation; 100% Treffer auf dem bisher einzigen gemessenen Datensatz)
- Teilweise Schreibgeschützte, zeitlich gefilterte Retrieval-API — Point-in-Time-Filterung (
as_of) + Scope-Filter, eine "letzter Zustand je Stream"-Abfrage und inzwischen hybrides lexikalisches/dichtes Ranking gebaut (trading/cma/retrieval.py, Punkt 8 unten); noch kein mandantenfähiger Endpunkt und kein präregistriertes Evaluations-Harness (Punkt 11)
- Erledigt Prompt-/Modell-Registry, die GeoScores Versionsdisziplin verallgemeinert — Code-Level-Registry (
trading/cma/model_registry.py), keine DB-Tabelle, bewusst passend dazu, wie GeoScore selbst Versionen bereits nachverfolgt (Git-Historie, keine mutable Registry, die selbst driften könnte)
- Erledigt Golden Set mit erwarteten Evidenz-IDs und CI-Non-Regression — 5 Fälle gegen echte, unveränderliche Produktionszeilen eingefroren (
trading/cma/golden/cma_retrieval_golden_set.json), läuft als normaler Teil der pytest-Suite; deckte beim Bau einen echten Sortierungsfehler auf
- Erledigt Hybrides (lexikalisch + dicht) Retrieval hinter austauschbarer Schnittstelle — pgvector installiert, echte GPU-Embedding-Aufrufe Ende-zu-Ende verifiziert; standardmäßig nicht aktiviert
- Erledigt Hash-Kette und Signaturen (JCS-Kanonisierung, SHA-256, Ed25519) — beide gebaut (praktisches kanonisches JSON, kein zertifiziertes JCS); keines in Produktion aktiviert
- Externe Checkpoints (Merkle-Batches, unabhängig gehaltene Roots)
- Präregistrierte Holdout-Evaluation und öffentliches Forschungspaket
Das erste umsetzbare Release ist als CMA v1: unveränderliche Events, zeitliches Retrieval und Evidenz-Rekonstruktion geplant. Graph-Memory, autonome Reflexionen und externe Transparenz-Logs sind spätere Ausbaustufen — so sequenziert, dass anspruchsvolles Retrieval niemals schwache zeitliche oder Provenienz-Semantik darunter verdeckt.
Referenzen
- Park et al., Generative Agents: Interactive Simulacra of Human Behavior — DOI: 10.1145/3586183.3606763
- Packer et al., MemGPT: Towards LLMs as Operating Systems — arXiv: 2310.08560
- Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — NeurIPS 2020
- Gutiérrez et al., HippoRAG — DOI: 10.52202/079017-1902
- Zhong et al., MemoryBank — arXiv: 2305.10250
- Chhikara et al., Mem0 — arXiv: 2504.19413
- Yu et al., FinMem — DOI: 10.1109/TBDATA.2025.3593370
- Maharana et al., Evaluating Very Long-Term Conversational Memory of LLM Agents (LoCoMo) — DOI: 10.18653/v1/2024.acl-long.747
- IDTA, Asset Administration Shell Metamodel, IDTA-01001 — offizielles Metamodell und normative Schemas
- W3C, PROV-O — W3C Recommendation
- RFC 8785, JSON Canonicalization Scheme (JCS) — rfc-editor.org/rfc/rfc8785
- RFC 9162, Certificate Transparency Version 2.0 — rfc-editor.org/rfc/rfc9162
- OSF, Registrations and Preregistrations — offizielle OSF-Leitlinie
Dieses Dossier begleitet das ZenTrader-Whitepaper und ersetzt es nicht. Es ist ein internes Forschungsprotokoll zur technischen und Förder-Prüfung; Forschungsfragen, Meilensteine und Termine sind Planungsartefakte, keine Zusagen auf ein festes Lieferdatum. Der Implementierungsstatus wurde gegen Quellcode und produktives Datenbankschema verifiziert und wird sich mit der Weiterentwicklung der Codebasis verändern — jede konkrete Aussage ist zeitgestempelt zu lesen, nicht als dauerhaft gültig.