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

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

pip install numpy

No other dependencies. Single file, approximately 700 lines.

Usage

CLI

python holo_metacognitive.py
python holo_metacognitive.py --output results/

Runs ten demonstrations and writes a JSON state file.

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:

{
  "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

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

{
    "label": str,
    "verdict": "YES" | "UNKNOWN",
    "confidence": float,
    "raw": float,
    "weight": float,
}

ask() result

{
    "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

@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

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support