diff --git a/agents/conductors/bug/_bug.py b/agents/conductors/bug/_bug.py index d9f860c..0aafd06 100755 --- a/agents/conductors/bug/_bug.py +++ b/agents/conductors/bug/_bug.py @@ -377,7 +377,7 @@ def emit_human(mode: str, d: dict): if d["memory_context"]: print("Relevant context (PyAutoMemory — consult, do not invent):") for wiki, kws in d["memory_context"].items(): - print(f" - {wiki}/index.md ({', '.join(kws)})") + print(f" - PyAutoMemory/wiki/{wiki}/index.md ({', '.join(kws)})") else: print("Relevant context: none matched") print(f"Fix locus: {d['fix_locus']['locus']}") diff --git a/agents/conductors/feature/MIND_TAXONOMY.md b/agents/conductors/feature/MIND_TAXONOMY.md index b0d307d..97287dc 100644 --- a/agents/conductors/feature/MIND_TAXONOMY.md +++ b/agents/conductors/feature/MIND_TAXONOMY.md @@ -67,11 +67,11 @@ context when memory has material. Sub-wikis (source: `PyAutoMemory/index.md`): | Sub-wiki | Domain | Triggered by (examples) | |----------|--------|--------------------------| -| `lensing_wiki/` | strong gravitational lensing | lens, deflection, source reconstruction, subhalo, time delay, cosmography, SLACS/TDCOSMO | -| `smbh_wiki/` | supermassive black holes | black hole, SMBH, binary, recoil, NANOGrav | -| `cti_wiki/` | charge-transfer inefficiency | CTI, trap, arctic, VIS calibration | -| `methods_wiki/` | statistical / computational methods | Bayesian, sampler, JAX, NUFFT, SBI, graphical models, deep learning | -| `galaxies_wiki/` | galaxy formation & evolution | bulge/disk, MGE, morphology, IFU, kinematics | +| `wiki/lensing/` | strong gravitational lensing | lens, deflection, source reconstruction, subhalo, time delay, cosmography, SLACS/TDCOSMO | +| `wiki/smbh/` | supermassive black holes | black hole, SMBH, binary, recoil, NANOGrav | +| `wiki/cti/` | charge-transfer inefficiency | CTI, trap, arctic, VIS calibration | +| `wiki/methods/` | statistical / computational methods | Bayesian, sampler, JAX, NUFFT, SBI, graphical models, deep learning | +| `wiki/galaxies/` | galaxy formation & evolution | bulge/disk, MGE, morphology, IFU, kinematics | Library targets also pull a default sub-wiki (`autolens`→lensing, `autogalaxy`→galaxies, `autofit`/`autoarray`/`autoconf`→methods). PyAutoMemory is diff --git a/agents/conductors/feature/_feature.py b/agents/conductors/feature/_feature.py index 0d67195..c15e5fe 100755 --- a/agents/conductors/feature/_feature.py +++ b/agents/conductors/feature/_feature.py @@ -305,7 +305,7 @@ def emit_human(mode: str, decision: dict): if d["memory_context"]: print("Relevant context (PyAutoMemory — consult, do not invent):") for wiki, kws in d["memory_context"].items(): - print(f" - {wiki}/index.md ({', '.join(kws)})") + print(f" - PyAutoMemory/wiki/{wiki}/index.md ({', '.join(kws)})") else: print("Relevant context: none matched (no scientific context required)") print(f"Phase decision: {d['phase_decision']}") diff --git a/agents/faculties/memory/_memory.py b/agents/faculties/memory/_memory.py index b62ed76..6752a8f 100755 --- a/agents/faculties/memory/_memory.py +++ b/agents/faculties/memory/_memory.py @@ -2,11 +2,16 @@ """agents/faculties/memory/_memory.py — the recall substrate. The **memory faculty** is a read-only opinion sink: given a topic/question, it -greps the organism's knowledge surfaces — PyAutoMemory's sub-wikis, -autolens_assistant's skills/wiki pages, and Mind's complete/ records — and -returns a **cited digest**: ranked pages with matching snippets. The consulting -agent reads only the listed pages and synthesises; this script never dumps -content, never writes, and builds no index. +greps the organism's knowledge surfaces — PyAutoMemory's sub-wikis and its +root entry pages (index.md, reading-queue.md, bibliography/README.md, the +wiki schema), autolens_assistant's skills/wiki pages, and Mind's complete/ +records — and returns a **cited digest**: ranked pages with matching +snippets. The consulting agent reads only the listed pages and synthesises; +this script never dumps content, never writes, and builds no index. + +Deliberately NOT a surface: ``bibliography/*.bib`` — the canonical BibTeX +file is far over ``MAX_FILE_BYTES`` and raw entries are metadata, not digest +text; ``bibliography/README.md`` carries the workflow instead. Exit codes: 0 digest · 4 no hits or no surface · 5 usage. """ @@ -32,6 +37,15 @@ def terms_of(query: str) -> list[str]: def surfaces(memory: Path | None, assistant: Path | None, mind: Path | None): """Yield (surface-name, root, md-file) triples, discovered at query time.""" if memory and memory.is_dir(): + # The repo's own entry surfaces: the hand-written index, the reading + # queue, the bibliography workflow, and the wiki schema. Without + # these the front door PyAutoMemory/AGENTS.md points every agent at + # ("index first") was invisible to this faculty (PyAutoBrain#239). + for rel in ("index.md", "reading-queue.md", + "bibliography/README.md", "wiki/CLAUDE.md"): + f = memory / rel + if f.is_file(): + yield "PyAutoMemory/root", memory, f # wiki// is the current layout; root-level *_wiki/ is the # pre-2026-07 layout, kept for older checkouts and forks. wikis = sorted(d for d in memory.glob("wiki/*") if d.is_dir()) diff --git a/agents/faculties/samplers/AGENTS.md b/agents/faculties/samplers/AGENTS.md index 940a0ef..910195d 100644 --- a/agents/faculties/samplers/AGENTS.md +++ b/agents/faculties/samplers/AGENTS.md @@ -140,7 +140,7 @@ not inventoried. (prototypes + `_metrics.py` + `output/comparison.txt`), `autofit_workspace_developer/searches/` (removed-sampler archive), `autofit_workspace_test/scripts/searches/` (integration scripts). -- **The science** — `PyAutoMemory/methods_wiki`: +- **The science** — `PyAutoMemory/wiki/methods`: `concepts/hamiltonian-monte-carlo.md`, `concepts/gpu-nested-sampling.md`, `concepts/initialization-chaining.md`, `concepts/sampler-benchmarks.md` (the campaign record), `concepts/nested-sampling.md`. **Privacy seam:** diff --git a/agents/faculties/samplers/_samplers.py b/agents/faculties/samplers/_samplers.py index 845e8f4..1e2a24a 100755 --- a/agents/faculties/samplers/_samplers.py +++ b/agents/faculties/samplers/_samplers.py @@ -217,7 +217,7 @@ def digest(autofit, developer, test, lens_developer=None, profiling=None) -> dic "instruction": "reason with agents/faculties/samplers/AGENTS.md " "(sampler<->likelihood match, gradients/JAX, " "initialization chaining); the science lives in " - "PyAutoMemory/methods_wiki — internal use only, " + "PyAutoMemory/wiki/methods — internal use only, " "citations never reach public output", } minimal = integration = [] diff --git a/config/policy.yaml b/config/policy.yaml index 3fe5ca3..d3b32d0 100644 --- a/config/policy.yaml +++ b/config/policy.yaml @@ -26,21 +26,22 @@ sizing_categories: extra_workspace_targets: [workspaces] extra_organism_targets: [autohands] -# Keyword -> PyAutoMemory sub-wiki (also the science vocabulary difficulty -# scoring keys off). Source of truth for the wiki list: PyAutoMemory/index.md. +# Keyword -> PyAutoMemory sub-wiki (the wiki// layout; also the science +# vocabulary the difficulty scoring keys off). Source of truth for the wiki +# list: PyAutoMemory/index.md. memory_wikis: - lensing_wiki: [lens, deflection, source reconstruction, caustic, einstein, + lensing: [lens, deflection, source reconstruction, caustic, einstein, subhalo, substructure, time delay, cosmography, shear, multipole, mass sheet, slacs, tdcosmo, h0licow, macromodel] - smbh_wiki: [black hole, smbh, binary, recoil, nanograv, + smbh: [black hole, smbh, binary, recoil, nanograv, gravitational wave background] - cti_wiki: [charge transfer, cti, trap, arctic, vis calibration] - methods_wiki: [bayesian, sampler, nautilus, dynesty, emcee, mcmc, + cti: [charge transfer, cti, trap, arctic, vis calibration] + methods: [bayesian, sampler, nautilus, dynesty, emcee, mcmc, nested sampling, likelihood, jax, nufft, interpolat, graphical model, expectation propagation, deep learning, sbi, simulation based inference, probabilistic, optimis, gradient, regularis] - galaxies_wiki: [galaxy formation, bulge, disk, morphology, mge, stellar halo, + galaxies: [galaxy formation, bulge, disk, morphology, mge, stellar halo, ifu, kinematic, elliptical, cosmos] # Intake keyword -> target repo routing signals. @@ -62,11 +63,13 @@ target_signals: # Feature conductor: target -> the sub-wiki consulted by default. target_default_wiki: - autolens: lensing_wiki - autogalaxy: galaxies_wiki - autofit: methods_wiki - autoarray: methods_wiki - autoconf: methods_wiki + autolens: lensing + autogalaxy: galaxies + autofit: methods + autoarray: methods + autoconf: methods # legacy name — the Nerves repo was PyAutoConf + autonerves: methods + pyautonerves: methods # Refactor conductor: normalised repo -> the test dir that witnesses # behaviour preservation. diff --git a/docs/adoption/config_surfaces.md b/docs/adoption/config_surfaces.md index ff2e5f6..81e0838 100644 --- a/docs/adoption/config_surfaces.md +++ b/docs/adoption/config_surfaces.md @@ -13,7 +13,7 @@ framework organs is domain-free logic you pull from upstream. | `agents/faculties/sizing/_sizing.py` | Brain | The library/workspace repo sets and aliases used to size and route tasks. | | `agents/conductors/intake/_intake.py` — `TARGET_SIGNALS` | Brain | Keyword → target-repo routing for raw ideas. | | `agents/conductors/release/` — the library tuple + `nightly.sh` | Brain | Which libraries the release path drives. | -| `agents/faculties/memory/` — the wiki keyword map | Brain | Topic keywords → your Memory's sub-wikis. | +| `config/policy.yaml` — `memory_wikis` + `target_default_wiki` | Brain | Topic keywords → your Memory's sub-wikis (`wiki//`), consumed by the sizing faculty and the feature/bug conductors. | | `heart/readiness.py` — `DEFAULT_LIBRARIES`; `heart/checks/version_skew.py` — the workspace→(library, package) map | Heart | The release-gate repo sets. | | `autohands/run_all.py`, `autohands/slow_skip_check.py`, navigator maps | Hands | Which workspaces the validation pipeline runs and skips. | diff --git a/skills/sampler_pipeline/SKILL.md b/skills/sampler_pipeline/SKILL.md index de602f1..1b0cfb5 100644 --- a/skills/sampler_pipeline/SKILL.md +++ b/skills/sampler_pipeline/SKILL.md @@ -26,7 +26,7 @@ Read `agents/faculties/samplers/AGENTS.md` for the judgment tables (sampler ↔ likelihood match, gradient/JAX constraints, initialization chaining, promotion criteria). If the candidate is already prototyped or promoted, resume at the right stage instead of starting over. The deeper science is in -`PyAutoMemory/methods_wiki` (`hamiltonian-monte-carlo`, `gpu-nested-sampling`, +`PyAutoMemory/wiki/methods` (`hamiltonian-monte-carlo`, `gpu-nested-sampling`, `initialization-chaining`, `sampler-benchmarks`) — internal use only; its citations never reach public user-facing output. @@ -72,7 +72,7 @@ The prototype contract (what makes its row comparable): - If the candidate targets real likelihoods (lensing MGE / pixelization / interferometer), extend to `autolens_profiling` use-case runs before any promotion argument — the 1D Gaussian alone never justifies promotion. -- Record durable findings in `PyAutoMemory/methods_wiki` (update +- Record durable findings in `PyAutoMemory/wiki/methods` (update `concepts/sampler-benchmarks.md`). ## 3. Promote (or archive) diff --git a/tests/test_memory_surfaces.py b/tests/test_memory_surfaces.py new file mode 100644 index 0000000..09cb38a --- /dev/null +++ b/tests/test_memory_surfaces.py @@ -0,0 +1,87 @@ +"""tests/test_memory_surfaces.py — the memory faculty's corpus (PyAutoBrain#239). + +First regression net for `agents/faculties/memory/_memory.py`. What matters: +the root entry surfaces (index.md, reading-queue.md, bibliography/README.md, +wiki/CLAUDE.md) are part of the corpus — they were invisible before #239 even +though PyAutoMemory/AGENTS.md tells every agent to index them first; surface +labels stay repo-name-first (digest()'s exit-4 logic splits on '/'); ranking +and the no-hits path behave; and the conductors' printed PyAutoMemory pointers +name paths that exist under the wiki// layout. +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] + / "agents" / "faculties" / "memory")) + +import _memory # noqa: E402 + + +def _memory_repo(tmp_path: Path) -> Path: + m = tmp_path / "PyAutoMemory" + (m / "wiki" / "demo" / "concepts").mkdir(parents=True) + (m / "bibliography").mkdir() + (m / "index.md").write_text("# Index\nthe entry surface mentions quasars\n") + (m / "reading-queue.md").write_text("# Reading queue\n\nquasar paper one\n") + (m / "bibliography" / "README.md").write_text("# Bib\nadding a quasar paper\n") + (m / "wiki" / "CLAUDE.md").write_text("# Schema\nstatus flags\n") + (m / "wiki" / "demo" / "concepts" / "quasars.md").write_text( + "---\nstatus: drafted\n---\nquasars lens light\n") + return m + + +def test_root_entry_surfaces_are_in_the_corpus(tmp_path): + m = _memory_repo(tmp_path) + triples = list(_memory.surfaces(m, None, None)) + root_files = {f.name for name, _, f in triples if name == "PyAutoMemory/root"} + assert root_files == {"index.md", "reading-queue.md", "README.md", "CLAUDE.md"} + # the wiki pages still arrive under their sub-wiki label + assert any(name == "PyAutoMemory/demo" for name, _, _ in triples) + + +def test_labels_stay_repo_name_first(tmp_path): + m = _memory_repo(tmp_path) + for name, _, _ in _memory.surfaces(m, None, None): + assert name.split("/")[0] == "PyAutoMemory" + + +def test_digest_ranks_and_cites_the_queue(tmp_path): + m = _memory_repo(tmp_path) + d = _memory.digest("quasar reading queue", m, None, None, limit=8) + assert d["surfaces_present"] == ["PyAutoMemory"] + pages = {p["page"] for p in d["pages"]} + assert "reading-queue.md" in pages + assert all(p["hits"] >= 1 and p["snippets"] for p in d["pages"]) + + +def test_no_hits_yields_empty_pages(tmp_path): + m = _memory_repo(tmp_path) + d = _memory.digest("nonexistent-elephant-topic", m, None, None, limit=8) + assert d["pages"] == [] and d["surfaces_present"] == ["PyAutoMemory"] + + +def test_bib_file_itself_is_not_a_surface(tmp_path): + m = _memory_repo(tmp_path) + (m / "bibliography" / "demo.bib").write_text("@article{Quasar2020}\n") + files = {f.name for _, _, f in _memory.surfaces(m, None, None)} + assert "demo.bib" not in files # metadata, not digest text (by design) + + +def test_conductor_pointers_name_real_layout_paths(tmp_path): + """The feature/bug conductors print `PyAutoMemory/wiki//index.md` + pointers built from the policy wiki names — those names must be the + wiki// layout, and the printed shape must resolve in a real + checkout when one is present.""" + sys.path.insert(0, str(Path(__file__).resolve().parents[1] + / "agents" / "faculties" / "sizing")) + import _sizing + live = Path(__file__).resolve().parents[2] / "PyAutoMemory" + for wiki in _sizing.MEMORY_WIKIS: + assert not wiki.endswith("_wiki") + if live.is_dir(): + assert (live / "wiki" / wiki / "index.md").is_file(), ( + f"policy names sub-wiki '{wiki}' but " + f"PyAutoMemory/wiki/{wiki}/index.md does not exist") diff --git a/tests/test_policy_seams.py b/tests/test_policy_seams.py index 17f3b7c..d0ed0e5 100644 --- a/tests/test_policy_seams.py +++ b/tests/test_policy_seams.py @@ -48,8 +48,10 @@ def test_aliases_normalise_known_mentions(): def test_memory_wikis_route_science_vocabulary(): wikis = _sizing.MEMORY_WIKIS - assert "lens" in wikis["lensing_wiki"] - assert "sampler" in wikis["methods_wiki"] + # Keys are the wiki// names (the *_wiki root layout is retired). + assert "lens" in wikis["lensing"] + assert "sampler" in wikis["methods"] + assert not any(k.endswith("_wiki") for k in wikis) assert _sizing.SCIENCE_KEYWORDS # derived, non-empty @@ -65,7 +67,9 @@ def test_feature_default_wiki_loads(): sys.path.insert(0, str(BRAIN_HOME / "agents" / "conductors" / "feature")) import _feature - assert _feature.TARGET_DEFAULT_WIKI["autolens"] == "lensing_wiki" + assert _feature.TARGET_DEFAULT_WIKI["autolens"] == "lensing" + # The Nerves rename is covered both ways (legacy autoconf + autonerves). + assert _feature.TARGET_DEFAULT_WIKI["autonerves"] == "methods" def test_refactor_test_witness_loads():