Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/nerves_board.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ name: Nerves Board
# * dashboard.md (the markdown mirror).
#
# Read-only: the board edits nothing. Truth is a sparse checkout of each
# source's config folder (blobless clone, only `<config dir>/**` checked out)
# taken fresh on every run; slugs come from the Mind's body map.
# source's config folder (blobless clone, only `<config dir>/**` checked out;
# for a library also `<package>/**/*.py`, scanned for the config keys its
# code reads) taken fresh on every run; slugs come from the Mind's body map.

on:
schedule:
Expand Down Expand Up @@ -63,7 +64,7 @@ jobs:
# and the board can never disagree about what is collected. A source
# that fails to clone is simply absent — the board reports it under
# "unavailable this render" rather than pretending it was read.
- name: Sparse-clone every config folder
- name: Sparse-clone every config folder (and library package code)
run: |
python3 - <<'PY'
import importlib.util, subprocess, yaml
Expand All @@ -74,6 +75,10 @@ jobs:
repos = yaml.safe_load(Path("PyAutoMind/repos.yaml").read_text())["repos"]
for src in board.SOURCES:
name, cfg = src["repo"], src["config"]
# a library's package .py files too: the board scans them for
# the config keys the code reads ("possibly unused keys")
patterns = [f"{cfg}/**"] + (
[f"{src['package']}/**/*.py"] if src.get("package") else [])
home = (repos.get(name) or {}).get("github")
if not home:
print(f"::warning::{name}: no github slug in repos.yaml")
Expand All @@ -85,7 +90,7 @@ jobs:
f"https://github.com/{home}", str(dest)],
check=True, timeout=300)
subprocess.run(["git", "-C", str(dest), "sparse-checkout",
"set", "--no-cone", f"{cfg}/**"],
"set", "--no-cone", *patterns],
check=True, timeout=60)
subprocess.run(["git", "-C", str(dest), "checkout", "--quiet"],
check=True, timeout=300)
Expand Down
22 changes: 18 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,24 @@ NUMBA_CACHE_DIR=/tmp/numba_cache MPLCONFIGDIR=/tmp/matplotlib python -m pytest t
(<https://pyautolabs.github.io/PyAutoNerves/>): every YAML file under each
library's `<package>/config/` and each workspace's `config/`, with keys,
comments, source, prior tables, the workspace → library override map, the
`PYAUTO_*` env vars, and a `state.json` cockpit feed (contract owned by
`PyAutoBrain/board/_state.py`). The config sources are the `SOURCES` table at
the top of the script (repo, config dir, kind, library lookup stack) — add a
new library or workspace there. It is stdlib + PyYAML, is **not** packaged
`PYAUTO_*` env vars, the "possibly unused config keys" scan, and a
`state.json` cockpit feed (contract owned by `PyAutoBrain/board/_state.py`).
The config sources are the `SOURCES` table at the top of the script (repo,
config dir, kind, library package dir, library lookup stack) — add a new
library or workspace there.

**Unused-key classification** (`scan_lookups` → `classify_files`): an AST
scan of every library package's `.py` (and `autonerves/`) collects the config
paths the code reads — literal `conf.instance[...]` / `instance[...]` chains
(`.get("k")` counts; a non-literal subscript ends the chain as a wildcard),
sections bound to a local and indexed later in the function or a closure,
and `should_output("name")` (`HELPER_READS`); `logging.yaml` is loaded whole
(`WHOLESALE_FILES`). Each library settings key (priors exempt) is `used`,
`section-read` or `unused` against the reads of the *whole* stack. It is
skipped entirely if any library's config or package dir is missing (a partial
scan would call that library's reads unused). It is static and untrusted:
unused keys are one `info` item per library in `state.json`, never yellow —
add a new lookup style to `lookups_from` rather than colouring the feed. It is stdlib + PyYAML, is **not** packaged
(`scripts/` is excluded in `pyproject.toml` / `MANIFEST.in`), and is tested by
`test_autonerves/test_board.py`. Published by
`.github/workflows/nerves_board.yml` (daily + dispatch). Local run:
Expand Down
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,31 @@ workspace's `config/` that overrides them.
array → fit). Keys whose value differs, keys no library defines (*orphans*)
and keys that fall through to the libraries are listed per file.
`build/*.yaml` is workspace tooling and is grouped apart.
- **Possibly unused config keys**: each library's Python (and autonerves'
own) is scanned for `conf.instance[...]` lookups, and every key of a
library settings file is classed *used* (a lookup reads it, or reads a key
under it — PyAutoLens reading a PyAutoFit key counts, since autonerves
merges every layer), *section-read* (a lookup reads an ancestor section
whole, or a non-literal subscript such as `["plots"][section][name]` ends
the chain above it) or *unused* (nothing references it). Unused keys get a
chip on the repo page, per-file counts and an index section grouped by
library with GitHub links. Prior files are exempt (looked up by class name).
**Limits:** the scan is static — it follows literal subscript chains
(including multi-line ones and `.get("k")`), sections bound to a local and
indexed later in the same function or a closure, and the `should_output`
helper; a key read any other way (built key strings, `getattr`, a section
passed to another function and indexed there) shows as section-read at
best and may show as unused. Treat the list as candidates, not a verdict.
- **Environment variables**: the `PYAUTO_*` switches autonerves reads.
- **Cockpit feed** (`state.json`): green when every file parses and no
workspace key is orphaned; yellow with one item per unparseable file or
orphan-carrying workspace file; grey when nothing was collected. Never red.
Possibly unused keys add one *info* item per library — never yellow, until
the scan is trusted.

Rendered daily by [`.github/workflows/nerves_board.yml`](.github/workflows/nerves_board.yml)
from sparse checkouts of the config folders; the renderer is
from sparse checkouts of the config folders (plus each library's package
`.py` files, for the lookup scan); the renderer is
[`scripts/board.py`](scripts/board.py) (not part of the `autonerves` package).
Nothing on the board edits config.

Expand Down
Loading
Loading