Skip to content

Module #6 — DA active forgetting + decay-path correctness, with honest falsification - #69

Merged
cdeust merged 18 commits into
mainfrom
wip/da-active-forgetting
Jun 30, 2026
Merged

Module #6 — DA active forgetting + decay-path correctness, with honest falsification#69
cdeust merged 18 commits into
mainfrom
wip/da-active-forgetting

Conversation

@cdeust

@cdeust cdeust commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Module #6 — DA active forgetting + decay-path correctness, with honest falsification

This branch lands the active-forgetting mechanism (two Drosophila dopaminergic
circuits) and a campaign of correctness and provenance fixes around the
memory decay path. It is shipped with a falsification harness that we let
fail where the model genuinely diverges from biology rather than tuning the
test to pass.

What landed

Feature — active forgetting (a5bef4e8, c264af95)

  • core/active_forgetting.py + handlers/consolidation/forgetting.py: two
    independent dopaminergic forgetting circuits — permanent Rac1 trace erosion
    (chronic interference × stage vulnerability) and transient DAMB retrieval
    block (Davis & Zhong 2017; Sabandal et al. 2021).
  • Benchmark + ablation gates: benchmarks/active_forgetting/ (9/9 pass) and
    LME on/off gate snapshots.

Decay-path correctness

  • 42e6ff19 — backfill/import use the single A3 decay path: removed the
    age_decayed_heat override that double-decayed heat (created_at → A3 decay
    only). Deleted dead backfill_helpers.py and test_backfill_heat.py.
  • acfc948ceffective_heat made monotone via a piecewise α-integral.
  • 382f3948 — consolidation stage derived lazily on the read path.

Provenance corrections (zetetic source discipline)

  • f8b5472d, ee201ff1 — corrected false paper attributions
    (Shannon / Tse / Zettelkasten / Platt Eq.7) across 5 core modules.
  • eaca9636 — constant disclaimers on predictive_coding_flat (engineering
    defaults, not paper-derived).
  • ca545438 — real PC algorithm (G² CI test + v-structures) replacing the
    placeholder.
  • 9c7cc373 — faithful SR spectral embedding for the cognitive map; dead code
    dropped.

Transparency — falsification preserved, not papered over

The forgetting-curve harness (benchmarks/forgetting_curve/, criteria C1–C4)
is falsifiable by construction and we report its verdict honestly:

  • C1 (pure power-law) — FALSE (ΔAIC −124). The decay law is exponential
    Ebbinghaus with a floor
    , not a power law.
  • C2, C3 — TRUE.
  • C4 (Benna & Fusi √t law-family) — FALSE (b = 0.235). C4 fits the
    transient regime, not a permastore √t plateau (12f6637b, 04357868).
  • Net: partially falsified by design — the implementation is an
    exponential+floor model, and the harness says so out loud rather than being
    retuned to confirm a law the system does not implement.

This matches the thermodynamic paper, whose decay axis is exponential
Ebbinghaus (R(t)=e^{-t/S}); the paper's "power law" refers to the
cross-sectional steady-state item distribution, not a retention curve.

Independent paper audits

Both arXiv companion papers were audited against the implementation on all 7
campaign axes (exp-not-power-law; Adcock 1.5×; reconsolidation 0.15/0.65;
Yonelinas forgetting-rate-not-gain; no fixed prior; neurogenesis≠DG;
engineering-default constants):

  • docs/arxiv-thermodynamic/main.texFAITHFUL, zero HIGH/MEDIUM
    contradictions.
  • docs/arxiv-context-assembly/main.texFAITHFUL, zero contradictions.

Benchmarks — no regression on the heat gate

The retrieval heat gate is byte-identical between main and this branch
(the effective_heat prefilter appears 5× in pg_schema.py, unchanged on both
sides; the changed code is the backfill/import path, off the benchmark
ingestion route). So retrieval scores are governed by the same code on both
branches.

Consolidation is required for headline retrieval. The benchmark runners
default to consolidation OFF; in that mode every loaded memory keeps
heat_base_set_at/stage_entered_at at ingest-time (hours_elapsed ≈ 0), so
the stage never advances past labile, effective_heat sits at the labile
floor (≈1e-4), and the read-path gate (min_heat = 0.01) prefilters every
candidate → retrieval collapses to ≈0%. This is a harness artifact of the
OFF default
, not a property of the branch: it reproduces identically on
main. Reported headline numbers (CLAUDE.md) are measured --with-consolidation.

Reconfirmation on an isolated cortex_bench DB, --with-consolidation (50-Q /
10-Q subsets — smaller than the full-suite headline, so not directly comparable
to the 500-Q/full LoCoMo numbers):

Benchmark (subset) --with-consolidation consolidation OFF
LongMemEval-s R@10 (n=50) 94.0% 0%
LongMemEval-s MRR (n=50) 0.854
LoCoMo R@10 (n=10, 1982 Qs) 93.8% 9.3%
LoCoMo MRR (n=10, 1982 Qs) 0.821

Decay-law benchmarks re-ran with identical verdicts to committed snapshots
(forgetting_curve C1 FALSE / C2 TRUE / C3 TRUE / C4 FALSE; active_forgetting
9/9). 970 tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au

cdeust and others added 18 commits June 29, 2026 19:45
…undle

Two independent dopaminergic forgetting circuits (Davis & Zhong 2017;
Sabandal et al. 2021), step 1 of the resume contract — GREEN on all DB-free
checks, NOT yet verified against live PostgreSQL, NOT for merge.

- core/active_forgetting.py: pure two-circuit decisions (permanent Rac1
  pressure >= Tp; transient DAMB overlap >= X AND age <= W).
- handlers/consolidation/forgetting.py: chronic noisy-OR 1-prod(1-sim_i) over
  newer overlapping neighbors, acute interferer, pin/sleep gates; permanent ->
  mark_memory_stale(True), transient -> heat*(1-acute_overlap) (magnitude rides
  measured salience, no invented constant).
- pg_store.search_newer_neighbors: created_at>target KNN (I/O half; noisy-OR
  aggregation stays in the handler, SRP).
- sleep.run_deep_sleep returns replayed_ids (sleep-protection signal);
  consolidate runs the forgetting cycle AFTER replay.
- ablation: ACTIVE_FORGETTING unit (28 -> 29).
- tests_py/handlers/test_forgetting_cycle.py: 17 DB-free tests (noisy-OR maths
  + fake-store wiring), all pass; active_forgetting benchmark PASSED.

docs/handoff/da-active-forgetting/ carries the resume checkpoint + verified
paper findings (normally outside the repo) for cross-machine continuation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…its) + benchmark gates

Replace the saturating noisy-OR (46% over-fire on 384-dim embeddings) with two
independent dopaminergic circuits faithful to the Drosophila literature:
permanent Rac1 trace erosion (chronic interference x stage vulnerability, leaky
integrator requiring sustained pressure) and transient DAMB retrieval block
(recency AND overlap). Constants traced to benchmark, no invented values:
PRESSURE_LEAK_LAMBDA=0.85, PERMANENT_ACCUM_THRESHOLD=1.25662,
ACUTE_OVERLAP_THRESHOLD=0.575, ACUTE_RECENCY_WINDOW_HOURS=13.0
(source: benchmarks/active_forgetting/run_benchmark.py grid search).

Schema: forgetting_pressure_accum REAL column (PG migration + SQLite parity) +
store.update_forgetting_pressure_accum; handler persists the leaky accumulator.

Benchmark gates (isolated cortex_bench, paired OFF=--ablate vs ON, both
--with-consolidation so the forgetting cycle actually fires) — no regression:
- LME-S  --limit 50:  R@10 94.0%->94.0%, MRR 0.857->0.856 (delta 0.0pp/-0.001)
- LoCoMo --limit 10:  R@10 94.8%->95.0%, MRR 0.832->0.836 (delta +0.2pp/+0.004)
- BEAM 100K: no consolidation path, MRR 0.501 no crash (schema/store change safe)

Davis & Zhong 2017 (Neuron 95:490-503), Sabandal et al. 2021. 30 tests GREEN,
benchmark PASSED (9 falsifiers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
… 5 core modules

Wave-3 provenance audit of 5 modules outside the original 33. Full suite GREEN
(3620 passed). One real functional bug, four sets of false paper attributions.

- platt_calibration.py: FUNCTIONAL BUG. _smoothed_target swapped class counts
  (positive used n_neg, negative used n_pos), inverting Platt 1999 Eq.7 /
  Lin-Lin-Weng 2007 Eq.2. Fixed + regression test. CONVERGENCE_TOL 1e-6->1e-5
  and MAX_ITERATIONS=100 sourced to Lin-Lin-Weng Algorithm 1; MIN_SAMPLES
  relabeled engineering default.
- reconsolidation.py: 4 false attributions removed (no values changed). 0.15/
  0.65 not from Osan-Tort-Amaral 2011; PE 0.5 and 30d/0.15 age window are
  engineering (Lee 2009, Milekic & Alberini 2002 = direction only). Emotional
  multiplier no longer attributed to Yonelinas & Ritchey 2015 (forgetting-rate
  effect, not reconsolidation gain - category error documented).
- hierarchical_predictive_coding.py: DEEP FIX. Removed ungrounded fixed prior
  [0.30,0.35,0.35] + duplicate ACh transform (triple-counted ACh). Total free
  energy now F = sum(pi_i * F_i) derived from neuromodulated precision (Friston
  2005 eq.7). Logistic squash relabeled engineering. No prod impact
  (WRITE_GATE_HIERARCHICAL defaults False).
- neurogenesis.py: docstring rescoped (temporal-context heuristic, NOT DG
  pattern separation); Aimone 2011 demoted to motivation-only; 5 constants
  relabeled engineering defaults. No behavior change.
- memory_ingest.py: importance_boost=1.5 relabeled engineering default;
  Adcock 2006 demoted to motivation-only (paper reports no ratio).

docs/provenance/paper-implementation-audit.md: Wave-3 changelog entry added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…kasten)

Faithfulness fixes for citation-level misattributions found in the Wave-4
provenance audit. Behaviour-preserving (labels/docstrings only):

- write_gate_calibration: the 50% acceptance target is the maximum of the
  Bernoulli (binary) entropy H(p), i.e. Shannon (1948) — not Jaynes'
  maximum-entropy principle (Ch.11). The value 0.5 was already faithful;
  only the citation was imprecise.
- condensers: drop the Tse 2007 "schema-congruent consolidation" citation
  for timeline slot-extraction — a cross-domain category error (Tse is rat
  hippocampus systems consolidation, no computational result for text slots).
- wiki_classifier: the 200–3000 char "atomic note" band is an unsourced
  engineering default, NOT Luhmann's Zettelkasten (which prescribes no char
  range); Alexander P2/P4 relabelled "inspired by" (framing only); the
  score threshold marked unsourced/calibration-pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
project_to_2d claimed "spectral embedding of the SR graph" (Stachenfeld
2017) but ran a purely-attractive force-directed relaxation with no
eigendecomposition. Replace with the real SR spectral embedding: the
eigenvectors of the symmetric normalised adjacency S = D^(-1/2) W D^(-1/2)
(which shares the eigenvectors of the SR matrix M = (I-γT)⁻¹, T = D⁻¹W —
Belkin & Niyogi 2003), using the two subdominant eigenvectors as the
grid-cell-like (x, y) axes. Isolated nodes embed at the origin.

Also remove dead code that carried false-attribution defects:
- build_co_access_graph (zero importers) held a γ^(dist-1) off-by-one vs the
  SR definition and a non-SR symmetric back-link (SR is directional).
- _SR_DISCOUNT became unused — the spectral embedding is γ-independent (the
  eigenvectors of M are a function of T alone for any γ∈(0,1)).

Adds test_cognitive_map.py (was untested): SR scoring, BFS navigation, and
the spectral-embedding faithfulness property (the Fiedler vector separates
weakly-bridged co-access clusters). Not in the retrieval ranking path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
causal_graph claimed the PC algorithm (Spirtes & Glymour 1991) but built a
PMI-threshold skeleton with single-variable conditioning and temporal-only
orientation — not PC. Replace with a faithful PC in new core module
causal_pc:

- G² (likelihood-ratio) conditional-independence test over binary
  entity-presence data; chi-square survival via the regularised upper
  incomplete gamma (Numerical Recipes §6.2) — no SciPy dep; validated
  against textbook critical values and scipy to ~1e-14.
- PC skeleton with growing conditioning sets and separating-set recording.
- v-structure (unshielded collider) orientation; temporal precedence only
  orients edges PC leaves undirected (background knowledge, never overriding
  a collider).

PC now determines graph structure; PMI is demoted to an effect-size
annotation for ranking only. discover_causal_edges takes a per-memory
presence matrix (build_presence); the cls consolidation handler is updated.
Removes dead PMI helpers (compute_conditional_independence,
compute_co_occurrence_matrix). Tests rewritten with product/grid designs
that make conditional independence exact. Not in the retrieval ranking path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
Zetetic warning cleanup — each is a real unverified behaviour, not noise:

- FutureWarning (production): embedding_engine used the deprecated
  get_sentence_embedding_dimension; prefer get_embedding_dimension with a
  getattr fallback for sentence-transformers <5 (cleared ~15 occurrences).
- un-awaited coroutine: test_pipeline_impact_bump patched asyncio.run but
  still evaluated the real _pipeline_detect_changes coroutine as its arg;
  also patch the coroutine factory (was GC-misattributed to other tests).
- leaked psycopg connections: tests constructed MemoryStore(...) directly
  instead of get_shared_store() (the documented rule — closed by conftest's
  reset_shared_store teardown). Converted spell/codebase-alteration,
  pg_store_delete_by_tag, seed_project, remember; closed the schema_integrity
  bootstrap store.
- leaked asyncio subprocess transports: the mcp_client deadlock-regression
  tests spawn real children; close() (sync) sends SIGTERM but cannot await
  exit, so reap the child (await proc.wait() + transport.close()) within the
  test loop before it tears down.

Remaining 6 are GC-misattributed psycopg ResourceWarnings to trace later.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
A3 made HEAT lazy (effective_heat decays from heat_base_set_at on every
read) but left STAGE eager — consolidation_stage advances only in the
consolidation handler, never on the recall/read path. Between consolidation
passes a trace stayed frozen at its insert stage 'labile' (alpha=2.0,
floor=0.0) while its heat decayed under the labile law, collapsing to ~0.
Benchmark and import runs trigger no consolidation pass, so the forgetting
law could never shape ranking: everything old read as ~0 uniformly.

Fix: make STAGE as lazy as HEAT. New PL/pgSQL effective_stage() re-derives
the stage at read time from elapsed dwell + stored signal columns, mirroring
cascade_advancement.compute_advancement_readiness applied cumulatively
(DA gate disabled — encoding-time, unavailable on read; monotonic
forward-only; stage_hours consumed as a dwell budget stage-by-stage;
reconsolidating/unknown pass through unchanged). effective_heat() now keys
BOTH alpha (Kandel 2001) AND the permastore floor (Bahrick 1984, Benna &
Fusi 2016) on the derived stage instead of the static column.

Also includes the step-1 decay-clock anchor: insert_memory sets
heat_base_set_at = COALESCE(provided, created_at, now()) in both pg_store
and sqlite_store, so imported/backfilled rows decay from their true age
rather than from insert time.

Verified on cortex_test (rolled-back probe):
  fresh/imp0.5            -> 1.00  (early_ltp)
  365d/imp0.5/0acc        -> 0.05  (late_ltp floor)
  365d/imp0.5/5acc        -> 0.10  (consolidated floor)
  365d/imp0.2/0acc        -> ~0    (labile, forgetting preserved)

test_pg_effective_stage_parity.py pins the SQL ladder against the Python
oracle (grid + monotonicity + off-chain passthrough). I2 allow-list line
numbers updated for the heat_base_set_at shift (fix confined to pg_schema,
no writer added). Suites: infrastructure+invariants 415 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
Result snapshot from the active_forgetting benchmark run on 2026-06-29,
joining its already-tracked siblings in benchmarks/results/active_forgetting/.
Predates the lazy-stage read-path fix; recorded for the reproducibility trail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
effective_heat decayed with exponent α(eff_stage)·hours_elapsed: the
final-stage α was applied to ALL elapsed hours. At a stage boundary α
drops (e.g. 0.8→0.5), retroactively shrinking the exponent so heat RISES
with age — non-monotonic. Latent in every multi-stage trace; the
forgetting-curve grid exposed it at the 7h late→consolidated boundary
(6h 0.98982 → 8h 0.99151).

Replace the α-CASE with a new SQL fn alpha_integral(stage,τ,imp,acc,
schema) = ∫₀^τ α(stage(s))ds, walking the SAME chain/gates/dwells as
effective_stage. effective_heat now decays over
  alpha_integral(stage_hours) - alpha_integral(max(0, stage_hours-elapsed)).
Since α>0 ⇒ ∫α strictly increasing ⇒ POWER strictly decreasing, heat is
monotone non-increasing BY CONSTRUCTION. Single-stage traces reduce
exactly to α·hours_elapsed (max|Δ|=0.0 vs the old path, verified).

Also fix emergence_metrics.compute_forgetting_curve docstring: it claimed
a power-law R=a·t^-b fit, but the code fits ln(heat) on linear age — an
EXPONENTIAL. curve_type was already correctly "exponential"; the real
power-law fit lives in benchmarks/forgetting_curve/curve_fit.py.

Verified: new test_pg_alpha_integral.py (SQL==Python oracle, ∫α
non-decreasing, single-stage==α·τ, effective_heat monotone for all 4
profiles); full tests_py/infrastructure/ 380 PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…ix snapshot

New honest falsification instrument for the forgetting law: criteria.py
(power-over-exponential AIC, permastore floor, exponent plausibility),
curve_fit.py (real power-law fit R=a·t^-b), run_benchmark.py. It does NOT
fake a power law — it fits both families and reports which wins.

Post-fix snapshot (20260630T102251Z): all 4 stage profiles monotone;
C2 permastore PASS (B@365d holds floor, A collapses); C1 still correctly
FAILS (ΔAIC favours exponential) — the monotonicity fix removes the
stage-boundary bump without manufacturing a power law. Verdict:
PARTIALLY FALSIFIED, preserved honestly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
Post-fix run (20260630T102401Z) confirms no regression from the
effective_heat α-integral monotonicity fix: all active-forgetting
falsifiers still PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…(C4)

The forgetting-curve harness had a descriptive-only ensemble_diagnostic.
Promote it to a falsifiable criterion (C4) that tests the specific
Benna&Fusi 2016 prediction: a cascade / continuum of timescales decays
as h ∝ 1/√t (power law, exponent ≈ 0.5).

C4 is evaluated on the population MIXTURE (mean over the 4 stage
profiles), not a single trace — a single stage is a pure exponential by
construction, so superposition of separated timescales is the only route
to a power law in this architecture. PASSES iff the mixture is fit better
by a power law than a single exponential (ΔAIC>2) AND the fitted exponent
lies in the √t band [0.4, 0.6]. The double gate matters: in the full run
the mixture's fitted b lands at 0.39-0.44 — near 0.5 — yet the power law
LOSES to the exponential (winner=exponential, power r²(h)=0.0 because the
permastore floor is a plateau no power law can fit). Gating on the
exponent alone would have been a false positive.

Honest result (20260630T110048Z): C4 PASS=False. The 4-level α-ladder
(rates 2.0→0.5, a single decade) is far coarser than Benna&Fusi's
many-decade continuum and does NOT reproduce 1/√t. C4 does not gate
overall_passed (still C1+C2); it appends an explicit law-family clause to
the verdict. C1/C2/C3 unchanged from the prior snapshot (C1 ΔAIC=-124.37)
— purely additive, no regression.

New unit tests (test_forgetting_curve_criteria.py) lock the falsifier:
a planted 1/√t mixture passes, a single exponential fails, and an
out-of-band power law (b≈1.5) fails despite winning over exponential.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…teau

The Benna&Fusi √t criterion (C4) fit the mixture over ALL ages via a
`1e-3 < h` filter, which included the permastore floor plateau (mean
0.0375 for t≥90d). A power law a·t^-b can represent neither a ceiling at
1.0 nor a floor, so its h-space r² went negative and clamped to 0.0 — a
degenerate result that read like a bug and masked the real finding.

Fix: restrict C4's fit to the strictly-decaying transient regime via the
same transient_points filter C1/C3 already use, with the mixture floor =
equal-weight mean of the per-profile permastore floors. The plateau is a
separate phenomenon (Bahrick, tested by C2), not part of the decay law.

Result is now non-degenerate and cleaner: the transient mixture is an
almost-perfect single exponential (exp r²=0.9915) and decisively NOT a
power law (power r²=0.230, ΔAIC=-58.5, fit b=0.235 outside the √t band
[0.4,0.6]). Verdict unchanged: the 4-level α-ladder does not reproduce
the 1/√t continuum. Output now reports n_transient_points + mixture_floor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…(Wave 3 sibling)

predictive_coding_flat.py had the same zetetic violation Wave 3 fixed in
its hierarchical sibling: invented constants under the Friston 2005 label
with no provenance disclaimer (the honesty discriminator is the
disclaimer, not the citation). The flat path was missed in the first Wave
3 pass; surfaced during the forgetting-law campaign.

No values changed (behavior-preserving). Every constant now carries a
source/disclaimer: the 4-signal blend weights (0.40/0.25/0.20/0.15), the
24h temporal saturation timescale, the order-of-magnitude length buckets,
and the no-data fallback priors (0.5/0.7/0.8) are relabeled engineering
defaults; Friston 2005 demoted to concept-only (prediction-error gating).
The blend is validated end-to-end — ROC-AUC=0.9998 separating novel from
duplicate content (flat mode, benchmarks/gate_precision, 2026-06-11; the
hierarchical alternative scored only 0.5514, which is why flat is the
default path). Audit doc Wave 3 changelog updated with this entry.

Verified: 156 write-gate/predictive-coding/novelty/gate tests PASS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…-decayed heat

Remove the age_decayed_heat pre-decay override from backfill_memories and
import_sessions. Post-A3 (382f394), insert_memory anchors heat_base_set_at
to created_at, so effective_heat() already decays the baseline by the
memory's real age at read time. Pre-decaying initial_heat on top double-
counted the same age — verified on cortex_test as a 1.05x-1.83x effective_heat
suppression in the 3-60 day window (masked by the late_ltp floor beyond ~90d).

Keep created_at; drop the now-dead age_decayed_heat/compute_age_days helpers
and their unit test. The original #14 bimodality motive is subsumed by A3's
read-time decay; the homeostatic cohort correction (#14 Fix 2) is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
…ine retrieval

The benchmark table's retrieval scores are measured with consolidation enabled.
The runners default to consolidation OFF, where every loaded memory keeps its
ingest-time heat timestamps (hours_elapsed≈0), so the stage never advances past
labile, effective_heat sits at the labile floor (≈1e-4), and the read-path heat
gate (min_heat=0.01) prefilters every candidate — retrieval collapses to ≈0%.
This is a harness artifact of the OFF default that reproduces across branches,
not a property of the stored memories or of this branch.

Subset reconfirmation on cortex_bench (2026-06-30, --with-consolidation vs OFF):
LongMemEval-s n=50 R@10 94.0% / MRR 0.854 vs 0%; LoCoMo n=10 (1982 Qs)
R@10 93.8% / MRR 0.821 vs 9.3%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
The branch's new/changed Python files were committed without running
`ruff format`; CI's Lint job (`ruff format --check .` + `ruff check .`) failed.
Apply ruff formatting to the 17 affected files (formatting-only, AST-preserving)
and remove the unused `forgetting_pressure` import in the active_forgetting
benchmark (F401). `ruff format --check` and `ruff check` both pass locally.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au
@cdeust
cdeust merged commit 8a5f31f into main Jun 30, 2026
13 checks passed
@cdeust
cdeust deleted the wip/da-active-forgetting branch June 30, 2026 15:10
@cdeust cdeust mentioned this pull request Jun 30, 2026
cdeust added a commit that referenced this pull request Jun 30, 2026
…forgetting (#73)

Bumps version across pyproject/server/manifest/marketplace/plugin manifests and
records the 3.25.0 CHANGELOG section covering #67#72:
- feat: active forgetting module (#69), safe headless drain (#70), full zetetic
  agent roster for wiki authoring (#72)
- fix: Windows portability (#68), subscription-default billing (#71),
  variadic --add-dir prompt-swallow root cause (#72)
- deps: pydantic-settings 2.14.0→2.14.2 security patch (#67)


Claude-Session: https://claude.ai/code/session_019o58McF4LRfvGNNXaqG2Au

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant