Chemenu 2.1.0 - deterministischer Wissenskompiler
CI / verify (push) Failing after 32s
Release / release (push) Successful in 38s

Chemenu kompiliert Rohnotizen zu einem verlinkten, quellengebundenen Wiki:
raw/ -> types/ + tools/ -> kb/ -> reports/. Was mechanisch ist, macht
tools/wikitool; was Urteil braucht, macht ein Agent unter Contracts, deren
Grenzen in Code durchgesetzt sind statt im Prompt.

Dieser Commit ist der Startpunkt der oeffentlichen Historie. Die vorherige
Entwicklung fand in einer privaten Instanz statt und ist nicht Teil dieses
Repositorys; ihre Erzaehlung steht vollstaendig in CHANGES.md, das mit 44
Eintraegen von 0.1.0 bis 2.1.0 erhalten geblieben ist.

Der mitgelieferte Korpus ist ein Testbett und eine Demo: 170 Seiten ueber den
Stack selbst - Gates, Lint, Versionierung, Suche, das Wiki-Muster. Er
dokumentiert das Werkzeug mit den eigenen Mitteln des Werkzeugs.

Lizenz: AGPL-3.0 fuer den Stack (tools/, types/), CC-BY-4.0 fuer die Inhalte.
Die Grenze zwischen beiden ist der Dateiplan, den dist export berechnet -
siehe NOTICE.
This commit is contained in:
2026-09-01 16:24:34 +02:00
commit 18ae28f918
368 changed files with 50628 additions and 0 deletions
@@ -0,0 +1,70 @@
import datetime
import pytest
from chemenu import config
from chemenu.commands import confidence_decay
from chemenu.commands.confidence_decay import FLOOR, compute_decay
from chemenu.frontmatter_io import read_page
def test_no_decay_at_zero_months():
today = datetime.date(2026, 8, 2)
assert compute_decay(0.9, today, today) == 0.9
def test_decay_after_ten_months():
today = datetime.date(2026, 8, 2)
last_confirmed = datetime.date(2025, 10, 2) # ~10 months earlier
result = compute_decay(0.9, last_confirmed, today)
# 0.9 * (1 - 0.01 * ~10) ~= 0.9 * 0.90 = 0.81
assert 0.80 <= result <= 0.82
def test_decay_floors_at_0_2():
today = datetime.date(2026, 8, 2)
long_ago = datetime.date(2015, 1, 1)
result = compute_decay(0.5, long_ago, today)
assert result == FLOOR
@pytest.fixture
def decay_wiki(kb_dir, monkeypatch):
monkeypatch.setattr(config, "KB_DIR", kb_dir)
return kb_dir
def test_init_base_backfills_from_current_confidence(decay_wiki):
confidence_decay.confidence_init_base(apply=True)
frontmatter, _ = read_page(decay_wiki / "entities/systems/aurora.md")
assert frontmatter["confidence_base"] == 0.9
# Written next to `confidence`, keeping the schema's field order.
keys = list(frontmatter)
assert keys.index("confidence_base") == keys.index("confidence") + 1
def test_init_base_is_idempotent(decay_wiki):
confidence_decay.confidence_init_base(apply=True)
before = (decay_wiki / "entities/systems/aurora.md").read_text(encoding="utf-8")
confidence_decay.confidence_init_base(apply=True)
assert (decay_wiki / "entities/systems/aurora.md").read_text(encoding="utf-8") == before
def test_decay_is_idempotent_across_runs(decay_wiki):
"""The regression that motivated `confidence_base`: decaying the stored
`confidence` in place compounded on every run, because the elapsed-months
factor kept growing while the multiplicand had already shrunk."""
confidence_decay.confidence_init_base(apply=True)
confidence_decay.confidence_decay(apply=True)
after_first = (decay_wiki / "entities/systems/aurora.md").read_text(encoding="utf-8")
confidence_decay.confidence_decay(apply=True)
confidence_decay.confidence_decay(apply=True)
assert (decay_wiki / "entities/systems/aurora.md").read_text(encoding="utf-8") == after_first
def test_decay_skips_pages_without_a_base(decay_wiki):
"""Falling back to the stored `confidence` would silently reintroduce the
compounding bug, so pages without a base are skipped instead."""
confidence_decay.confidence_decay(apply=True)
frontmatter, _ = read_page(decay_wiki / "entities/systems/aurora.md")
assert frontmatter["confidence"] == 0.9