--- language: - en license: apache-2.0 library_name: holo-metacognitive tags: - memory - metacognition - self-model - provenance - introspection - anomaly-detection - associative-memory - hyperdimensional-computing - vector-symbolic-architecture - numpy - educational - research datasets: [] metrics: - self-verification-accuracy - anomaly-detection - trajectory-tracking pipeline_tag: feature-extraction --- # holo-metacognitive **A memory that holds facts about itself, verifies them, and reports its own trajectory.** Standard memory tools report their state through a side channel — a `stats()` method, a log file, a dashboard. The state exists but is not addressable through the same interface as the content. This substrate closes that gap. Three kinds of facts are stored and queried the same way: - **Content** — labels and weights for external items - **Provenance** — which source contributed which weight - **Self-facts** — counts, magnitudes, trends, self-verification Every one of the three is retrievable through the same `ask()` primitive. The caller does not specify which kind they are asking for. The substrate reports what it has. ## What it does ```python from holo_metacognitive import MetaMemory mem = MetaMemory(d=2048) mem.store("apple", weight=1.0, source="book") mem.store("apple", weight=0.5, source="witness") mem.query("apple") # Same interface, three layers mem.ask("apple") # [item] apple: verdict=YES, conf=+0.988 mem.ask("n_items") # [meta] n_items = 1.0 mem.ask("book") # [source] book: total_weight=1.0 # Provenance mem.sources_of("apple") # {"book": 1.0, "witness": 0.5} mem.consensus("apple") # {"consensus": 0.92, "shares": {...}} # Trajectory mem.trajectory("apple") # [{"tick": 1, "verdict": "YES", ...}] mem.confidence_trend() # slope of recent query confidence # Self-verification mem.verify_meta() # 5/5 checks passed # Anomalies mem.anomalies() # unusual items # Full report mem.health() # stats + meta + verification + anomalies ``` ## Why self-reference Standard memory tools are flat. A vector database accepts an embedding and returns neighbors. A KV cache accepts a key and returns a value. A dashboard shows the state but does not let the user query it. The metacognitive layer makes the substrate's own state addressable through the same primitive as its content. A query for `"n_items"` returns the item count; a query for `"apple"` returns the item. There is no separate reporting interface for the two. The self-verification layer goes one step further: the substrate can be asked whether it trusts its own facts, and the answer comes from the same substrate that holds those facts. The anomalies layer does the same for individual items. ## Installation ```bash pip install numpy ``` No other dependencies. Single file, approximately 700 lines. ## Usage ### CLI ```bash python holo_metacognitive.py python holo_metacognitive.py --output results/ ``` Runs ten demonstrations and writes a JSON state file. ### Python ```python from holo_metacognitive import MetaMemory mem = MetaMemory(d=2048, threshold=0.05) # Storage with provenance mem.store("earth_round", weight=1.0, source="textbook") mem.store("moon_cheese", weight=0.4, source="folklore") # Queries log themselves mem.query("earth_round") mem.query("moon_cheese") mem.query("jupiter_capital") # UNKNOWN, logged as doubt # The three layers under one interface hits = mem.ask("earth_round") # item hits = mem.ask("n_items") # meta hits = mem.ask("textbook") # source # Provenance analysis mem.sources_of("earth_round") # {"textbook": 1.0} mem.consensus("earth_round") # consensus score # Trajectory mem.trajectory("earth_round") # list of query records mem.confidence_trend(window=10) # slope of recent confidence # Self-verification report = mem.verify_meta() print(report["n_ok"], "/", report["n_checks"], "checks passed") # Anomaly detection for a in mem.anomalies(): print(a["kind"], a["label"]) # Full state health = mem.health() mem.save_json("state.json") ``` ## Results All results at D=2048, threshold=0.05. ### Self-test Four checks before any demonstration: | Check | Result | |---|---| | bind/unbind identity | PASS | | raw projection | PASS | | meta-fact round-trip (n_items = 7) | PASS | | forget decrements count (n_items = 5) | PASS | ### Demo 1 — Basic storage with provenance Two items stored with two sources each. | Label | Weight | Sources | |---|---|---| | apple | 1.50 | book=1.0, witness=0.5 | | orange | 1.00 | book=1.0 | Source totals: `book: 2.00`, `witness: 0.50`. ### Demo 2 — Query log and trajectory Query sequence: `apple, pear, apple, pear, orange`. Trajectory for `apple` shows two queries at ticks 1 and 3, both with confidence +1.496. Trajectory for `pear` shows ticks 2 and 4 at +0.279. Query summary: ``` n_queries: 5 by_verdict: {'YES': 4, 'UNKNOWN': 1} mean_confidence: 0.710 n_doubt: 1 confidence_trend: -0.299 ``` The trend is negative because the sequence ends with an UNKNOWN verdict (orange is not stored), pulling the slope down. ### Demo 3 — Introspection The introspect() method returns the full meta snapshot as a dict: | Key | Value | |---|---| | confidence_trend | 0.0 | | dimension | 2048.0 | | magnitude | 2.22 | | mean_confidence | 1.48 | | n_doubt | 0.0 | | n_items | 2.0 | | n_queries | 2.0 | | n_sources | 2.0 | | source_book_weight | 2.0 | | source_witness_weight | 1.0 | | threshold | 0.05 | Dimension is stored exactly (2048.0). Magnitude is quantized to two decimal places. Counts are exact. ### Demo 4 — Self-query through `ask()` Seven example queries, each returning heterogeneous hits. | Query | Result | |---|---| | apple | `[item]` verdict=YES, conf=+0.988 | | n_items | `[meta]` n_items = 2.0 | | book | `[source]` total_weight=1.00 | | n_queries | `[meta]` n_queries = 1.0 | | source_book_weight | `[meta]` = 1.0 | | dimension | `[meta]` = 2048.0 | | unknown_label | (no hits) | The same primitive answered "what is apple?" and "how many items do I have?" and "what is my dimension?" ### Demo 5 — Consensus across sources Three items with different source distributions. | Label | Sources | Consensus | Shares | |---|---|---|---| | well_attested | 2 | 0.561 | book=0.91, forum=0.09 | | disputed | 2 | 0.000 | book=0.50, forum=0.50 | | controversial | 3 | 0.000 | book=0.33, forum=0.33, witness=0.33 | Consensus is `1 - H/log(N)`. A dominant source gives 0.561. Balanced sources give 0.000. ### Demo 6 — Meta-facts grow with the store Six steps, five items added per step. | Step | n_items | n_sources | n_queries | magnitude | trend | |---|---|---|---|---|---| | 0 | 5 | 3 | 1 | 2.170 | n/a | | 1 | 10 | 3 | 2 | 3.160 | 1.090 | | 2 | 15 | 3 | 3 | 3.890 | 1.040 | | 3 | 20 | 3 | 4 | 4.480 | 1.030 | | 4 | 25 | 3 | 5 | 4.990 | 1.000 | | 5 | 30 | 3 | 6 | 5.530 | 1.020 | Magnitude grows sublinearly (√N). Trend stabilizes near 1.0 as the sequence progresses. ### Demo 7 — Forgetting updates all layers Store 10 items, then forget two. | | After store | After forget | |---|---|---| | n_items | 10 | 8 | | magnitude | 3.190 | 2.840 | | source_book_weight | 10.000 | 8.000 | The count, magnitude, and source total all update. This is the fix from the previous version, where `n_items` was wrong after forgetting. ### Demo 8 — Self-verification Five meta-checks against source-of-truth state. | Key | Expected | Stored | Tolerance | Diff | ok | |---|---|---|---|---|---| | n_items | 2.000 | 2.0000 | 1.0000 | 0.0000 | Y | | n_sources | 2.000 | 2.0000 | 1.0000 | 0.0000 | Y | | n_queries | 3.000 | 3.0000 | 1.0000 | 0.0000 | Y | | magnitude | 1.403 | 1.4000 | 0.0100 | 0.0032 | Y | | dimension | 2048.000 | 2048.0000 | 4.0000 | 0.0000 | Y | All 5 checks pass. The `magnitude` check has a diff of 0.0032, within the 0.01 tolerance set by the quantization scale (100 buckets per unit). ### Demo 9 — Anomaly detection Two anomalies detected in a hand-crafted store: | Kind | Label | Details | |---|---|---| | high_doubt | never_stored | unknown_count=5 | | split_sources | split | consensus=2.9e-12, n_sources=2 | The `high_doubt` anomaly fires because a query was issued 5 times for a label that was never stored. The `split_sources` anomaly fires because two sources contributed equal weight (consensus ≈ 0). ### Demo 10 — Full health snapshot The `health()` method combines everything: - stats (counts, magnitudes) - verification (5/5 checks passed) - anomalies (empty in this run) - query summary (mean confidence, trend, doubt count) The output is the substrate's full self-report. ### JSON export `save_json` writes a complete state file including: ```json { "d": 2048, "n_items": 3, "n_queries": 2, "trace_magnitude": 1.7427, "meta_magnitude": 3.3444, "items": { ... }, "meta_snapshot": { "confidence_trend": 0.99, "dimension": 2048.0, "magnitude": 1.74, "n_doubt": 0.0, "n_items": 3.0, "n_queries": 2.0, "n_sources": 2.0, "threshold": 0.05 }, "query_log": [ ... ], "anomalies": [], "verification": { "n_checks": 5, "n_ok": 5, "all_ok": true, "checks": [ ... ] } } ``` The `meta_magnitude` is non-zero in the saved file (fix from the previous version, where `save_json` did not refresh the meta-trace). ## API reference ### `MetaMemory` ```python MetaMemory(d=2048, threshold=0.05, key=None, meta_buckets=4096) ``` **Storage** - `store(label, weight=1.0, source="user")` — add weight for label. - `forget(label)` — remove all trace of label. **Query** - `query(label, log=True) -> dict` — verdict, confidence, raw, weight. **Provenance** - `sources_of(label) -> dict` — per-source weights for label. - `consensus(label) -> dict` — n_sources, consensus score, shares. **Trajectory** - `trajectory(label, limit=None) -> list` — query records for label. - `confidence_trend(window=20) -> float | None` — slope of recent queries. - `query_summary() -> dict` — aggregated query statistics. **Meta** - `refresh_meta()` — rebuild the meta-trace from current state. - `query_meta(key) -> float | None` — retrieve a meta-fact by key. - `meta_keys() -> list` — all available meta keys. - `introspect() -> dict` — full meta snapshot as a dict. **Self-verification** - `verify_meta() -> dict` — re-derive meta-facts and compare. **Anomalies** - `anomalies() -> list` — unusual items with kind and details. **Unified interface** - `ask(query) -> dict` — heterogeneous search across all layers. - `health() -> dict` — full snapshot (stats + meta + verification + anomalies). **Diagnostics** - `stats() -> dict` — counts and magnitudes. - `save_json(path)` — full state with meta snapshot, query log, anomalies, and verification report. ### Query result ```python { "label": str, "verdict": "YES" | "UNKNOWN", "confidence": float, "raw": float, "weight": float, } ``` ### `ask()` result ```python { "query": str, "hits": [ {"type": "item", "label": str, "verdict": str, "confidence": float, "weight": float}, {"type": "meta", "key": str, "value": float}, {"type": "source", "name": str, "total_weight": float}, ] } ``` ## Design notes ### Meta-facts are quantized Meta-values are stored as bucket indices in a codebook of 4096 vectors. The value `n_items = 7` is stored as `bind(meta_key_vector("n_items"), meta_value_vector(7))`. Retrieval unbinds the key and classifies the result against the bucket codebook. The bucket index divided by the scale gives the value. This means meta-facts are approximate to one bucket. The tolerance for each key is `1/scale`, set at refresh time. Counts have scale 1.0 (tolerance 1). Magnitude has scale 100.0 (tolerance 0.01). Dimension has scale 0.25 (tolerance 4, exact for D=2048). ### Why ticks, not wall-clock Query timestamps use a monotonic counter instead of `time.time()`. Wall-clock timestamps in a fast loop are indistinguishable; the previous version logged five queries with `t=1791494125.885` and `t=1791494125.886`. Ticks distinguish them cleanly. ### Self-verification `verify_meta()` re-derives a set of meta-facts from the store's actual state and compares against the stored values. The check uses the per-key tolerance from the meta storage. A mismatch means the meta-trace and the state have diverged — a signal that the substrate has become inconsistent with itself. ### Anomalies Three anomaly types: - **low_confidence**: verdict YES but confidence below twice the threshold. - **high_doubt**: label queried 3+ times, always UNKNOWN. - **split_sources**: item with 2+ sources, consensus below 0.5. Each is a heuristic. The substrate reports what it finds; the user decides whether the anomaly matters. ## Limitations **Meta-facts are approximate.** Quantization to 4096 buckets limits resolution. Counts are exact up to ~4000. Magnitudes are exact to 0.01. Values beyond the bucket range are clamped. **No meta-of-meta.** Facts about the meta-trace itself (its magnitude, its bucket usage) are not stored as meta-facts. Adding them is straightforward but not implemented. **Anomaly thresholds are fixed.** The heuristic thresholds (`confidence < 2 * threshold`, `unknown_count >= 3`, `consensus < 0.5`) are not learned from the store's history. A user who wants different sensitivity changes the constants. **No cross-meta inference.** The substrate cannot answer "which source contributes most to my confidence?" because confidence is a scalar per query and sources are per item. Extending the meta layer to infer attribution across items is a separate project. **Keys are still per-store.** The keyed codebook layer from `holo-program` is available but the metacognitive layer does not use it. A keyed store would need to re-derive meta-vectors under the same key. **No consolidation integration.** The four-axis consolidation layer would decay items over time. Here, `forget()` is explicit. A combined store would need to decide whether consolidation updates the meta-facts of its own accord. ## Citation ```bibtex @misc{holo-metacognitive2026, title = {holo-metacognitive: A memory that holds facts about itself}, author = {zeechimp}, year = {2026}, note = {Three-layer memory with content, provenance, and self-facts under one interface.} } ``` ## References - Plate, T. A. "Holographic Reduced Representations." *IEEE Transactions on Neural Networks* 6:3 (1995), 623–641. - Kanerva, P. "Hyperdimensional Computing." *Cognitive Computation* 1:2 (2009), 139–159. - Gayler, R. W. "Vector Symbolic Architectures Answer Jackendoff's Challenges." *ICCS/ASCS* (2003). ## License Apache 2.0