diff --git a/REFERENCE.md b/REFERENCE.md index 62ed857..a89ce1f 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -106,7 +106,9 @@ writes nothing. The science body map. **Code, not ledger** — `sync_cli` and `local_path` are paths a conductor executes under. Real YAML read with `yaml.safe_load`; the -shape is validated by `cortex.py`: +shape is validated by `cortex.py`. A project key may appear only once — since +`yaml.safe_load` silently keeps the last of a repeated key, `cortex.py check` +scans the raw column-0 keys and reports every duplicate with its line numbers: | Field | Value | Notes | |---|---|---| diff --git a/projects.yaml b/projects.yaml index 3d0d535..9a6ab51 100644 --- a/projects.yaml +++ b/projects.yaml @@ -288,323 +288,3 @@ euclid_sersics: partition: ral status: retired note: "retired 2026-09-25: retire euclid_sersics as well" - -analytic_gaussian: - remote: none - local_path: /mnt/c/Users/Jammy/Science/analytic_gaussian - ral_root: /mnt/ral/jnightin/analytic_gaussian - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, logs, sync, status, submit, push-submit, jobs, sacct, cancel, tail, du, check] - ledger: wiki/project/state.md - assistant: autofit_assistant - witness_file: results/**/*.json - partition: ral - status: active - note: "born 2026-09-09 as the graphical-ep campaign's phase-1 keystone at ensemble scale; benchmark model with a closed-form posterior, borrowed from autofit_workspace_test scripts/graphical (PR #92 lineage); CPU-only, no dataset (every draw is simulated in memory from its seed); remote none until the human runs gh repo create PyAutoLabs/analytic_gaussian --private" - -ep_toy_gaussian: - remote: PyAutoLabs/ep_toy_gaussian - local_path: /mnt/c/Users/Jammy/Science/ep_toy_gaussian - ral_root: /mnt/ral/jnightin/ep_toy_gaussian - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, logs, sync, status, submit, push-submit, jobs, sacct, cancel, tail, du, check] - ledger: wiki/project/state.md - assistant: autofit_assistant - witness_file: results/**/*.json - partition: ral - status: active - note: "born 2026-09-10 as the graphical-ep campaign's confidence test on the PyAutoFit#1405 collapse toy at N=50: joint BlackJAX NUTS vs EP x3 on identical data; model and EP settings verbatim from complete/2026/07 ep_toy_diagnostic; CPU-only, data simulated in memory from its seed; remote PyAutoLabs/ep_toy_gaussian (private) created 2026-09-10" - -# --------------------------------------------------------------------------- # -# dormant — git repos only. The non-git trees (subhalo, euclid_group, z_*) are -# storage, not projects, and aris_PJ011646 is an assistant clone; none get a -# row. `ral_root` is the planned path and `sync_verbs` is unverified on every -# row below — each note says so. -# --------------------------------------------------------------------------- # -profiling: - remote: none - local_path: /mnt/c/Users/Jammy/Science/profiling - ral_root: /mnt/ral/jnightin/profiling - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "2026-05 checkpointed sweep harness, PyAutoNSS venv; name collides with autolens_profiling; ral_root planned, sync_verbs unverified" - -cowls_diana: - remote: none - local_path: /mnt/c/Users/Jammy/Science/cowls_diana - ral_root: /mnt/ral/jnightin/cowls_diana - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "local git, no remote; ral_root planned, sync_verbs unverified" - -subhalo_simulations: - remote: none - local_path: /mnt/c/Users/Jammy/Science/subhalo_simulations - ral_root: /mnt/ral/jnightin/subhalo_simulations - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "git init, zero commits, 21 GB; ral_root planned, sync_verbs unverified" - -slope_hierarchy: - remote: Jammy2211/slope_hierarchy - local_path: /mnt/c/Users/Jammy/Science/z_projects_complete/slope_hierarchy - ral_root: /mnt/ral/jnightin/slope_hierarchy - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: retired - note: "retired 2026-09-08: wrapped up 2026-07-22 at N=5; succeeded by slope_hierarchy_scale; tree vaulted under z_projects_complete/" - -slope_hierarchy_scale: - remote: PyAutoLabs/slope_hierarchy_scale - local_path: /mnt/c/Users/Jammy/Science/slope_hierarchy_scale - ral_root: /mnt/ral/jnightin/slope_hierarchy_scale - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, sync, status, submit, push-submit, jobs, tail, check] - ledger: wiki/project/state.md - assistant: autolens_assistant - witness_file: results/**/*.json - partition: both - status: active - note: "born 2026-09-08 as graphical-ep phase 3, code borrowed from slope_hierarchy (vaulted under z_projects_complete/); private remote created 2026-09-08" - -pj011646: - remote: Jammy2211/PJ011646 - local_path: /mnt/c/Users/Jammy/Science/PJ011646 - ral_root: /mnt/ral/jnightin/PJ011646 - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "personal remote, recorded as a fact — not a PyAutoLabs repo; ral_root planned, sync_verbs unverified" - -concr: - remote: Jammy2211/cosmology_and_cancer - local_path: /mnt/c/Users/Jammy/Science/concr - ral_root: /mnt/ral/jnightin/concr - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "personal remote Jammy2211/cosmology_and_cancer, recorded as a fact; ral_root planned, sync_verbs unverified" - -ic50_workspace: - remote: Jammy2211/ic50_workspace - local_path: /mnt/c/Users/Jammy/Science/ic50_workspace - ral_root: /mnt/ral/jnightin/ic50_workspace - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, logs, sync, push-data-init, pull-full, status, submit, push-submit, jobs, sacct, cancel, wait-and-pull, tail, du, check, clear-logs] - ledger: NOTES.md - assistant: none - witness_file: results/**/*.json - partition: ral - status: active - note: "personal remote, recorded as a fact — not a PyAutoLabs repo; activated 2026-09-09 for graphical-ep phase 4, ral_root created and first runs submitted; NOTES.md predates the graphical/HPC work and needs a refresh" - -autolens_inference: - remote: PyAutoLabs/autolens_inference - local_path: /home/jammy/Code/PyAutoLabs/lens/autolens_inference - ral_root: /mnt/ral/jnightin/autolens_inference - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull, logs, status, submit, jobs, sacct, cancel, tail, du, check] - ledger: wiki/project/state.md - assistant: autolens_assistant - witness_file: results/**/*.json - partition: both - status: active - note: "born 2026-09-10 as the from-scratch restart of inference_programme (retired PyAutoCortex#22); nothing inherited; phase 1 = birth (PyAutoMind#399), first task slam_hst_base" - -analytic_gaussian: - remote: none - local_path: /mnt/c/Users/Jammy/Science/analytic_gaussian - ral_root: /mnt/ral/jnightin/analytic_gaussian - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, logs, sync, status, submit, push-submit, jobs, sacct, cancel, tail, du, check] - ledger: wiki/project/state.md - assistant: autofit_assistant - witness_file: results/**/*.json - partition: ral - status: active - note: "born 2026-09-09 as the graphical-ep campaign's phase-1 keystone at ensemble scale; benchmark model with a closed-form posterior, borrowed from autofit_workspace_test scripts/graphical (PR #92 lineage); CPU-only, no dataset (every draw is simulated in memory from its seed); remote none until the human runs gh repo create PyAutoLabs/analytic_gaussian --private" - -ep_toy_gaussian: - remote: PyAutoLabs/ep_toy_gaussian - local_path: /mnt/c/Users/Jammy/Science/ep_toy_gaussian - ral_root: /mnt/ral/jnightin/ep_toy_gaussian - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, logs, sync, status, submit, push-submit, jobs, sacct, cancel, tail, du, check] - ledger: wiki/project/state.md - assistant: autofit_assistant - witness_file: results/**/*.json - partition: ral - status: active - note: "born 2026-09-10 as the graphical-ep campaign's confidence test on the PyAutoFit#1405 collapse toy at N=50: joint BlackJAX NUTS vs EP x3 on identical data; model and EP settings verbatim from complete/2026/07 ep_toy_diagnostic; CPU-only, data simulated in memory from its seed; remote PyAutoLabs/ep_toy_gaussian (private) created 2026-09-10" - -# --------------------------------------------------------------------------- # -# dormant — git repos only. The non-git trees (subhalo, euclid_group, z_*) are -# storage, not projects, and aris_PJ011646 is an assistant clone; none get a -# row. `ral_root` is the planned path and `sync_verbs` is unverified on every -# row below — each note says so. -# --------------------------------------------------------------------------- # -profiling: - remote: none - local_path: /mnt/c/Users/Jammy/Science/profiling - ral_root: /mnt/ral/jnightin/profiling - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "2026-05 checkpointed sweep harness, PyAutoNSS venv; name collides with autolens_profiling; ral_root planned, sync_verbs unverified" - -cowls_diana: - remote: none - local_path: /mnt/c/Users/Jammy/Science/cowls_diana - ral_root: /mnt/ral/jnightin/cowls_diana - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "local git, no remote; ral_root planned, sync_verbs unverified" - -subhalo_simulations: - remote: none - local_path: /mnt/c/Users/Jammy/Science/subhalo_simulations - ral_root: /mnt/ral/jnightin/subhalo_simulations - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "git init, zero commits, 21 GB; ral_root planned, sync_verbs unverified" - -slope_hierarchy: - remote: Jammy2211/slope_hierarchy - local_path: /mnt/c/Users/Jammy/Science/z_projects_complete/slope_hierarchy - ral_root: /mnt/ral/jnightin/slope_hierarchy - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: retired - note: "retired 2026-09-08: wrapped up 2026-07-22 at N=5; succeeded by slope_hierarchy_scale; tree vaulted under z_projects_complete/" - -slope_hierarchy_scale: - remote: PyAutoLabs/slope_hierarchy_scale - local_path: /mnt/c/Users/Jammy/Science/slope_hierarchy_scale - ral_root: /mnt/ral/jnightin/slope_hierarchy_scale - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, sync, status, submit, push-submit, jobs, tail, check] - ledger: wiki/project/state.md - assistant: autolens_assistant - witness_file: results/**/*.json - partition: both - status: active - note: "born 2026-09-08 as graphical-ep phase 3, code borrowed from slope_hierarchy (vaulted under z_projects_complete/); private remote created 2026-09-08" - -pj011646: - remote: Jammy2211/PJ011646 - local_path: /mnt/c/Users/Jammy/Science/PJ011646 - ral_root: /mnt/ral/jnightin/PJ011646 - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "personal remote, recorded as a fact — not a PyAutoLabs repo; ral_root planned, sync_verbs unverified" - -concr: - remote: Jammy2211/cosmology_and_cancer - local_path: /mnt/c/Users/Jammy/Science/concr - ral_root: /mnt/ral/jnightin/concr - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull] - ledger: README.md - assistant: none - witness_file: results/**/*.json - partition: both - status: dormant - note: "personal remote Jammy2211/cosmology_and_cancer, recorded as a fact; ral_root planned, sync_verbs unverified" - -ic50_workspace: - remote: Jammy2211/ic50_workspace - local_path: /mnt/c/Users/Jammy/Science/ic50_workspace - ral_root: /mnt/ral/jnightin/ic50_workspace - mirror: none - sync_cli: hpc/sync - sync_verbs: [push, pull, logs, sync, push-data-init, pull-full, status, submit, push-submit, jobs, sacct, cancel, wait-and-pull, tail, du, check, clear-logs] - ledger: NOTES.md - assistant: none - witness_file: results/**/*.json - partition: ral - status: active - note: "personal remote, recorded as a fact — not a PyAutoLabs repo; activated 2026-09-09 for graphical-ep phase 4, ral_root created and first runs submitted; NOTES.md predates the graphical/HPC work and needs a refresh" - -autolens_inference: - remote: PyAutoLabs/autolens_inference - local_path: /home/jammy/Code/PyAutoLabs/lens/autolens_inference - ral_root: /mnt/ral/jnightin/autolens_inference - mirror: none - sync_cli: hpc/sync - sync_verbs: [pull, logs, status, submit, jobs, sacct, cancel, tail, du, check] - ledger: wiki/project/state.md - assistant: autolens_assistant - witness_file: results/**/*.json - partition: both - status: active - note: "born 2026-09-10 as the from-scratch restart of inference_programme (retired PyAutoCortex#22); nothing inherited; phase 1 = birth (PyAutoMind#399), first task slam_hst_base" diff --git a/scripts/cortex.py b/scripts/cortex.py index 02a2f00..9001393 100644 --- a/scripts/cortex.py +++ b/scripts/cortex.py @@ -77,6 +77,7 @@ # grammars # --------------------------------------------------------------------------- # PROJECT_KEY_RE = re.compile(r"^[a-z][a-z0-9_]*$") +PROJECT_KEY_LINE_RE = re.compile(r"^([a-z][a-z0-9_]*):\s*(#.*)?$") LEDGER_FILE_RE = re.compile(r"^projects/([a-z][a-z0-9_]*)\.md$") DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$") WALL_RE = re.compile(r"^\d+:\d{2}$") @@ -185,8 +186,22 @@ def _replace_section(text: str, name: str, body: "list[str]") -> str: # --------------------------------------------------------------------------- # # projects.yaml # --------------------------------------------------------------------------- # +def _duplicate_key_problems(text: str) -> "list[str]": + """`yaml.safe_load` silently keeps the last of a repeated mapping key, so a + project row pasted twice would vanish from view: scan the raw column-0 + keys first and name every repeat with its line numbers.""" + seen: "dict[str, list[int]]" = {} + for n, line in enumerate(text.split("\n"), 1): + m = PROJECT_KEY_LINE_RE.match(line) + if m: + seen.setdefault(m.group(1), []).append(n) + return [f"projects.yaml: duplicate project key {key!r} " + f"(lines {', '.join(map(str, lines))})" + for key, lines in seen.items() if len(lines) > 1] + + def parse_projects(text: str) -> "tuple[dict[str, dict], list[str]]": - problems: "list[str]" = [] + problems: "list[str]" = _duplicate_key_problems(text) try: doc = yaml.safe_load(text) except yaml.YAMLError as e: diff --git a/tests/test_cortex.py b/tests/test_cortex.py index 78bda7a..84ac0b2 100644 --- a/tests/test_cortex.py +++ b/tests/test_cortex.py @@ -222,6 +222,24 @@ def test_projects_yaml_is_validated(tmp_path): assert any("unknown field `colour` on example" in p for p in _problems(root)) +def test_projects_yaml_rejects_duplicate_project_keys(tmp_path): + # yaml.safe_load keeps the last of a repeated key silently; the raw-line + # guard must name the repeat (25e0168 tripled 11 rows this way). + root = _copy(tmp_path) + path = root / "projects.yaml" + text = path.read_text() + lines = text.split("\n") + first = lines.index("example:") + 1 + start = text.index("example:\n") + row = text[start:text.index("\n\n", start) + 1] + path.write_text(text.rstrip("\n") + "\n\n" + row) + second = len(text.rstrip("\n").split("\n")) + 2 + problems = _problems(root) + assert f"projects.yaml: duplicate project key 'example' (lines {first}, {second})" in problems + assert not any("duplicate project key 'single'" in p for p in problems) + assert _problems(SKELETON) == [] + + # --------------------------------------------------------------------------- # # the writing verbs # --------------------------------------------------------------------------- #