Skip to content

chore: drop expired release-notes banner; complete autohands registry #249

Description

@Jammy2211

Overview

Two hygiene leftovers found by the 2026-08-19 release-board census (#239), both in PyAutoHands.

First, autohands/generate_release_notes.py carries a time-boxed ANNOUNCEMENT banner that expired 2026-07-24announcement_banner() now returns "" on every call. It is dead code that reads like live machinery, so it gets deleted rather than documented.

Second, bin/autohands help claims to be "the registry of what is a CLI verb" (AGENTS.md, fixed by #239), but a sweep of autohands/ finds 11 executable modules (if __name__ == "__main__") that help never mentions. Nothing enforces the claim, so it re-rots with the next module added. This task promotes the human-runnable ones to verbs, declares the rest internal, and adds a test that makes the registry an enforced invariant.

Plan

  • Delete the expired ANNOUNCEMENT dict, announcement_banner() and its call site from generate_release_notes.py.
  • Register nine autohands/ entrypoints as real CLI verbs in bin/autohands, each with an accurate help entry stating its actual input contract (they differ — cwd vs --root vs positional path) and where it runs in anger.
  • Declare the remaining modules internal in an explicit INTERNAL_MODULES list, and print them in autohands help so the registry is complete rather than partial.
  • Add tests/test_autohands_registry.py enforcing that every executable module is either a verb or allowlisted, that the allowlist has no ghosts, and that every verb has the SHORT_DESC + cmd_* + help_* trio the file's own header requires.
  • Update the now-false AGENTS.md clause that calls the navigator modules "not CLI verbs".

Out of scope: the ~30 stale remote branches (incl. origin/master, origin/release) — a destructive git sweep, run separately via /repo_cleanup rather than mixed into a PR diff.

Detailed implementation plan

Work Classification

Library — PyAutoHands source only, no workspace follow-up.

Affected Repositories

  • PyAutoHands (primary)

Branch Survey

Repository Current Branch Dirty?
./PyAutoHands main clean (1 commit behind origin/main — pull before branching)

worktree_check_conflict hands-hygiene-leftovers PyAutoHands → exit 0 (no conflict); worktree_list_claimed empty.

Suggested branch: feature/hands-hygiene-leftovers
Worktree root: ~/Code/PyAutoLabs-wt/hands-hygiene-leftovers/

Implementation Steps

1. Delete the expired announcement banner

  • autohands/generate_release_notes.py: delete the ANNOUNCEMENT dict + preceding comment block (lines 23–36) and announcement_banner() (lines 38–46).
  • Delete the call site in generate_notes() (lines 200–204: banner = announcement_banner(repo) and the if banner: append block).
  • Drop from datetime import date only if nothing else in the file uses date (grep first).
  • tests/test_slack_release_notes.py: the LENS_BODY fixture embeds the banner markdown as a literal string and imports only slack_release_notes — deletion does not break it. Keep the blockquote line (it is the fixture's only > → mrkdwn case) but fix the now-stale comment at lines 17–18 describing the body as "what generate_release_notes.py produces (banner + …)".

2. Register the CLI verbs (bin/autohands)

Nine new verbs, each with a SHORT_DESC entry, a help_<name> heredoc and a cmd_<name> calling the existing _python_in_autohands helper (sets PYTHONPATH, inherits cwd unchanged — required by the workspace-root tools):

Verb Section Input contract
generate_markdown Workspace operations <project> [--only SUBSTR], run from workspace root (cwd)
regenerate_navigator Workspace operations [project] or NAVIGATOR_PROJECT env, run from workspace root
check_navigator new Workspace guards --root DIR (default .), --banners warn|fail, --ignore-file
check_search_memory Workspace guards --root DIR (required)
check_dataset_allowlist Workspace guards no args — operates on cwd
validate_env_profiles Workspace guards positional <workspace> path (not --root)
slack_release_notes Release support --version --result --run-url [--repo]
tombstone Release support [--out DIR] [--package NAME]
clone_seed new Assistant seeding <plan.json> [--push] [--out DIR]

New "# "-prefixed section headers: Workspace guards (CI-invoked; runnable locally) and Assistant seeding.

Each help_* body names where the tool runs in anger — navigator_check.yml, PyAutoHeart/.github/workflows/smoke-tests.yml:148, pre_build.sh:162, release.yml:588, publish_tombstone.yml — so a maintainer knows whether running it locally reproduces CI. Keep entries the length of the existing ones; minimal, not maximal.

navigator.py, build_util.py, env_config.py, result_collector.py, generate_autofit.py have no __main__ — libraries, stay internal.

3. Make help complete: declare the internal modules

Add an INTERNAL_MODULES array beside SUBCOMMAND_ORDER holding add_notebook_quotes (docstring→cell transform; __main__ is a debug aid), run_notebook (subprocess worker spawned by run.py), plus the five libraries above, each with a one-line reason. Print them in cmd_help's no-arg output as a trailing Internal modules (not CLI verbs): block.

4. Enforce it: tests/test_autohands_registry.py

New test module (stdlib + regex over the bin/autohands text; no bash execution) asserting:

  1. Completeness — every autohands/*.py containing if __name__ == "__main__" is in SUBCOMMAND_ORDER or INTERNAL_MODULES; the failure message names the module and both options.
  2. No stale allowlist — every INTERNAL_MODULES entry resolves to an existing autohands/<name>.py, so a rename or deletion cannot leave a ghost.
  3. Verb contract — every non-"# " entry in SUBCOMMAND_ORDER has a SHORT_DESC[...], a cmd_<name>() and a help_<name>(). This is the file's own stated rule (bin/autohands lines 19–23) with nothing enforcing it today.
  4. Disjointness — no name appears in both lists.

Shims (verify_install, url_check, watch/status/tick/fix) and bash subcommands (pre_build, bump_colab_urls, tag_and_merge) have no autohands/<name>.py; check 1 walks the filesystem only, so they are unaffected, and check 3 still covers them.

5. Update AGENTS.md

Lines 27–33 describe the navigator modules as "workflow-invoked, not CLI verbs" — false after step 2. One-sentence rewrite pointing at the enforced registry; no duplicated verb list (bin/autohands help stays the single source).

Key Files

  • autohands/generate_release_notes.py — expired banner mechanism + its call site
  • bin/autohandsSUBCOMMAND_ORDER, SHORT_DESC, new INTERNAL_MODULES, per-verb cmd_*/help_*, cmd_help output
  • tests/test_autohands_registry.pynew, the registry-completeness guard
  • tests/test_slack_release_notes.py — stale fixture comment only
  • AGENTS.md — the "not CLI verbs" clause

Verification

python -m pytest tests/ -q
bash -n bin/autohands && bin/autohands help
for v in generate_markdown regenerate_navigator check_navigator check_search_memory \
         check_dataset_allowlist validate_env_profiles slack_release_notes \
         tombstone clone_seed; do bin/autohands help "$v" >/dev/null || echo "FAIL $v"; done
bin/autohands check_navigator --help          # dispatch reaches argparse
grep -rn "ANNOUNCEMENT\|announcement_banner" autohands/ tests/ && echo LEAK || echo clean

Plus a real guard run against a live workspace (autohands check_navigator --root . --banners=warn from autolens_workspace), and a negative test for the new guard: temporarily add an autohands/zzz_probe.py with a __main__ block, confirm test_autohands_registry.py fails, then delete it. A guard that never fires is not a guard.

Original Prompt

Click to expand starting prompt

Hands hygiene: expired announcement dead code, unregistered modules

Type: maintenance
Target: pyautohands
Repos:

  • PyAutoHands
    Difficulty: small
    Autonomy: safe
    Priority: low
    Status: formalised

Found by the 2026-08-19 release-board census (#239):

  • @PyAutoHands/autohands/generate_release_notes.py:23-46 carries an
    ANNOUNCEMENT banner mechanism that expired 2026-07-24 — now dead code.
    Delete it (delete the trap, don't document it).
  • Several modules exist but are not registered in the bin/autohands
    dispatcher (navigator.py, check_navigator.py, regenerate_navigator.py,
    generate_markdown.py, validate_env_profiles.py, check_search_memory.py,
    check_dataset_allowlist.py). AGENTS.md prose was fixed (feat: release board — what shipped, one-tap prompts, Pages twin #239) to call them
    workflow-invoked modules; decide per module whether it should become a CLI
    verb or stay internal, and make bin/autohands help the complete registry.
  • ~30 stale remote branches (incl. origin/master, origin/release,
    near-duplicate feature names) — sweep via /repo_cleanup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions