Repository navigation
One dispatched workflow builds the wheel, uploads it to TestPyPI, checks the install on three legs and uploads it to PyPI, and tests/test_release_workflow.py holds it (#228, PR 3 of 4) - #268
Merged
Conversation
Phases 1-2 of /opsx:propose for #228: the change scaffold and proposal.md. Annotated vX.Y.Z tags and release/vX.Y branches after opensoft/openRepoShape#850; the openrepotools wheel carrying the whole payload for an offline --install, with --install skipping pipx's link; a dispatch-only release.yml adapted from openRepoShape's (#563); a TestPyPI rehearsal now and v1.1.0 from openRepoTools-code after the cutover (#186). Alignment review and council follow. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… answers of 2026-10-17 (#228) Applies the /opsx:propose alignment review (stack architect and QA lead) to proposal.md, each fix checked against the code first, and records Brett Heap's four answers of 2026-10-17T21:51:50Z (#228 comment 6241784787) as a dated addendum under the decisions. - the pipx skip: the exact detection rule (link, resolved target, pipx_metadata.json main_package.package), the exact skip and count lines, 28 receipt rows against 29, and the upgrade, uninstall, pip --user and pipx-home cases; the record's "as #563 did" corrected (#563 refuses) - the stamp gains the source repository; how it reaches --version (five environment variables, bash keeps the one parser) and the exact lines - the digest code is the pinned upstream/openRepoShape/scripts/repo_shape.py with submodules: true; the in-wheel layout and why the offline install holds (payload_select :969-984, assembly_above, wip_shape_ref :3242) - a new standard-library hygiene test; wheel modes checked; which bash runs - the rc upload departs from openRepoShape on Brett's word; no pypi.org publisher for this repository, on his word; the unsourced "Decision 1 accepts that risk" dropped - #852's patch-tag wording, #850's "or a merge of main" and the lanes' side - the openRepoShape pin bump to v1.1.0 before the regenerated plan (#186 comment 6241785035); the code leg's LICENSE from T006's code-0001 - Impact: AGENTS.md's CI paragraph and tests.yml's header comment - the model cited as openRepoShape v1.1.0 (190133d), published by run 39071178232; the decisions header no longer says "20:5xZ" Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ifications.md (#228) Phase 5 of /opsx:propose for #228. The council verdicts of lane openRepoTools-3 (2026-10-17T22:4xZ) go into proposal.md, VALID 1-9, surgically and with the structure kept. NOTED N1-N5 and the three dismissals go into a new clarifications.md. proposal.md: - VALID 1: a new "Coexistence with the other installers" section. It covers the move from the one-line install (pipx install --force), a checkout's --install meeting pipx's link and its count line, and the workBenches condition, stated in one bullet as position (c), pending Brett Heap's word - VALID 2: the three README passages feature 006 corrects (:240, :251-262, :302); the pipx route's text, fixed now; README gains it only once PyPI serves 1.1.0 and the workBenches condition holds; lane 3 owns that PR - VALID 3: a non-goal: --version names the command's release, not the placed files' - VALID 4: a "Release owner" section. Brett decides every tag, cut and upload, and lane 3 carries them out, step 6 included. Per the lead's correction after #186 comment 6242560541 (D3, D4): code-0001 is the code leg's first commit right after execute, LICENSE is checked as blob 261eeb9 before the first package run, and Brett's code-side environments, tag ruleset and both publishers come after execute and before v1.1.0 - VALID 5: the pipx skip as path and existence checks with a bash-3.2 readlink loop, no jq and no JSON, in every mode, before any link refusal; pipx versions corrected (model locks 1.11.1 / 1.17.8, newest 1.18.3) - VALID 6: the model's all-or-nothing stamp rule (standard.py:153-156); bash reads _release.py beside its payload with a fixed grammar; the five OPENREPOTOOLS_PACKAGE_* variables dropped; the entry module execs bash - VALID 7: the cutover invariants (the gate's four job ids in the code leg's tests.yml, no release step reading across legs, no readme in pyproject.toml), and #228's PRs land before lane 1's rehearsal and plan (D1) - VALID 8: the package job fails on skipped package tests; pipx-skip tests use fake venvs; the build asserts TREE_DIGEST_DEFINITION - VALID 9: --install refuses pip's console script in every mode, and a package-mode --install reports a shadowing openRepoTools on PATH clarifications.md: N1 detection, N2 the stamp grammar, N3 the release notes, N4 hatchling's modes (checked: 1.27.0 normalises to 0644/0755 when reproducible, the default), N5 the refusal and report wording. Also D1-D3, each with the reason it was dismissed. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… build's check, not by hatchling (#228) The lead's correction to the council verdicts' VALID 4 (after #186 comment 6242560541, D3) gives the reason for code-0001's order as "license-files = ["LICENSE"] fails without it". Hatchling 1.27.0 does not fail: its published wheel builds the licence list from a glob of each license-files pattern and raises nothing when a pattern matches no file (hatchling/metadata/core.py:757-770; add_licenses, wheel.py:714-719, only writes what matched). A code leg without LICENSE would build a wheel without one. So the proposal now adopts openRepoShape's own check (release.yml:649-655 at v1.1.0): the wheel's .dist-info holds exactly METADATA, WHEEL, RECORD, entry_points.txt and licenses/LICENSE, and that LICENSE is the commit's. The release build and the package job make it. The order (code-0001 first, right after execute), lane 3's blob check before the first package run, and "never tolerate a missing LICENSE" stand as the lead directed. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lities (#228) Phase 6 of /opsx:propose, the first artifact: one ADDED delta per capability the proposal lists, written against the proposal as the council verdicts left it, and clarifications.md. - release-tags-and-branches: annotated vX.Y.Z tags and their message form, release/vX.Y cut at vX.Y.0, back-ports through main (fast-forward or cherry-pick -x), patch tags waiting for the commit's tests.yml runs, the release/v* push trigger, release notes and GitHub Releases after PyPI serves the version, Brett Heap's word for every act with lane 3 carrying them out, and tags staying where they were made at the cutover - pypi-package: the metadata (no dependencies, one script, no readme, the wheel's .dist-info with licenses/LICENSE), the exec'd entry point, the byte-for-byte payload, the offline install, the all-or-nothing stamp read from the package only, the exact --version lines, the pipx skip and every other link refused, upgrade and uninstall, coexistence (pip refused, the PATH report, the checkout count line), README offering only a published package, the package job, the release gates, the reproducible build, trusted-publishing uploads, the install check, rehearsals, and the cutover invariants openspec validate release-tags-pypi --strict: valid. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Phase 6 of /opsx:propose, the second artifact: how the change is built, written from the proposal, the two delta specs and clarifications.md, so that it answers N1-N5 and reopens none of D1-D3. - the package under src/ (the case-insensitive clash with the root's bash file), and a written-out force-include map that a test holds to bash's payload_names; no build hook - the entry module only execs bash, refusing with exit 2 when there is no bash, and reads no stamp: bash is the one reader - package mode decided from $SELF's path; a broken stamp refuses every invocation in package mode - N2: the stamp's fixed grammar, its refusals, writer-reader agreement, and no docstring line that hatch's case-insensitive VERSION pattern could take first (hatchling/version/core.py:6, :31 in 1.27.0); stricter than the model in three named places - N1: pipx's link resolved with a 40-hop readlink loop and cd -P / pwd -P, quoted for macOS's "Application Support" home (pipx/paths.py:14); the jq check stays where it is (R-A9-12's order); a venv-shaped link that fails the rule is refused without rm advice; fixtures for three pipx releases across four homes - the checkout count line, and the foreign stamp read beside pipx's payload - N5: how pip's console script is recognised, and the exact refusal and PATH-report text - the package job (submodules, pip wheel twice, the dist-info and LICENSE check, pipx 1.11.1 on 3.9, a JUnit count that fails on any skip, tomli pinned for 3.9) and the release.yml differences from the model - N3: the notes stay in spec, no release step reads them, and the release owner creates the Release by hand; N4: the installer owns modes - risks, including the LICENSE that hatchling would not miss and .gitattributes on git archive; migration, rollback and open questions Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ff record (#228) Phase 6 of /opsx:propose, the last artifact. As propose.md requires, it is a governance and handoff record only, with no implementation steps. It tracks: - the proposal, the review and the artifacts (done); - Brett Heap's pending word on the workBenches position; - the single Speckit feature, landing (before lane 1's rehearsal, #186 comment 6242560541 D1), and the rehearsals on his word; - the cutover's dependencies (lane 1's plan entries and invariants; code-0001 first after execute, and lane 3's LICENSE blob check); - v1.1.0 after execute, and archive readiness. Speckit Handoff: feature 006-release-pypi, branch 006-release-pypi, tasks specs/006-release-pypi/tasks.md, pending /speckit.specify. That directory is not created here. openspec validate release-tags-pypi --strict: valid. openspec status: 4/4 artifacts complete. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gs of 2026-10-17 (#228) design.md's Open Questions gains a "Resolved by the lead" list, each item marked "Resolved by the lead, 2026-10-17": 1. the .dist-info check (exactly METADATA, WHEEL, RECORD, entry_points.txt and licenses/LICENSE, equal to the commit's) in both the release build and the package job is confirmed, as the way a missing LICENSE is made fatal; code-0001 stays the code leg's first commit after execute 2. workBenches main is noted at bdab3e2, where both of its checks still hold 3. the stricter stamp rules are confirmed: unstamped is VERSION 0.0.0 with an empty REPOSITORY, TAG is v$VERSION, REPOSITORY is a slug, and a broken stamp refuses every package-mode invocation, --help included, naming the stamp file and the fix, pipx reinstall openrepotools. Decision 4's refusal line now names that fix in place of pipx install --force openrepotools 4. the jq check staying put, the venv-looking link refused with no rm advice, the stamp reader's docstring guard and the pipx home with a space are confirmed 5. the checkout's count line is confirmed as the proposal and spec fix it Still open: Brett Heap's choice of (a), (b) or (c) on workBenches; the proposal's one dependent bullet stays pending his word. openspec validate release-tags-pypi --strict: valid. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…228) /speckit.specify for the OpenSpec change release-tags-pypi, its one linked feature, on the existing branch (the before_specify branch hook skipped). Written only from proposal.md, the two delta specs, design.md (with the lead's rulings of 2026-10-17) and clarifications.md: - six prioritised stories: install offline beside pipx (P1), know which release runs (P1), move between installers without being misled (P2), every commit proves it packages (P2), publish only through gates (P2), and the record tells the truth (P3) - FR-001..FR-046 cover all 25 delta-spec requirements (17 pypi-package, 8 release-tags-and-branches); the exact --version, skip and count lines are restated, and the pip refusal and PATH note are design.md Decision 8's - FR-047, the workBenches condition, is the one open item: pending Brett Heap's choice of (a), (b) or (c), not a blocker - edge cases, key entities, ten measurable success criteria, assumptions (Brett Heap's acts outside the repository, the cutover, lane 1's plan, the model at 190133d) and the proposal's non-goals checklists/requirements.md: every item passes in one iteration; no [NEEDS CLARIFICATION] marker remains. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ff (#228) The "Speckit Handoff" section no longer says "pending /speckit.specify". It names feature 006-release-pypi, branch 006-release-pypi, tasks specs/006-release-pypi/tasks.md, specified on 2026-10-17 by /speckit.specify (spec.md at eb12177). No checklist item is ticked here. openspec validate release-tags-pypi --strict: valid. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ts and quickstart (#228) /speckit.plan (before_plan and after_plan commit hooks skipped; no SPECKIT markers in CLAUDE.md or AGENTS.md, so no agent-context edit): - plan.md: technical context for a bash installer, a stdlib entry module, declarative hatchling 1.27.0 and two GitHub Actions workflows; twelve gates from AGENTS.md, the Build Tiers rule and the change (the constitution is the unfilled template), all passing before Phase 0 and after Phase 1; the source tree; fixed fixture-builder and test-name prefixes so that tasks agree; governed files; four pull requests - research.md R1-R18: openrepotools.cli:main; the written-out force-include map; the bash function names; the count line's source and version; pip's rule as design.md writes it (distlib's /bin/sh launcher a recorded gap); the PATH report's prefix; OPENREPOTOOLS_TEST_WHEEL for the built-wheel tests with the package job's JUnit count; workflow YAML read by the pinned repo_shape.load_yaml; the stamp writer a heredoc the suite runs; the model's hash locks re-headed; tomli by hash in the package job; the v1.0.0 notes checked by their task; dated cap entries - data-model.md, quickstart.md, and contracts/ for the CLI's exact lines, the stamp, pipx's link and pip's script and the PATH report, the wheel, and both workflows design.md Decision 8: <prefix> is five levels above payload/, the parent of its lib/, not four; the layout it writes out has five components (research R7, R17). openspec validate release-tags-pypi --strict: valid. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d tier (#228) /speckit.tasks (before_tasks and after_tasks commit hooks skipped). Every task line carries exactly one tier tag, a files: list and a verify: command; no [H], because AGENTS.md has no "## Governed invariants" section. 19 [O] (governed files, the stamp, the release workflow and trusted publishing, contracts, the shared fixture interface, the installer's cross-cutting changes) and 6 [S]. - Phase 1-2: the stamp and __init__, pyproject.toml, and the shared fixture builders tests/package_layout.py - US1-US3 (pull request 1): tests first, then cli.py and the installer's pipx rule, stamp reader, --version, coexistence, pip refusal and PATH report - US4 (pull request 2): the model's two hash locks, tests_workflow tests, tests.yml's release/v* push and package job, AGENTS.md's CI paragraph - US5 (pull request 3): release workflow tests, then release.yml's build job, its upload and install jobs, and its RELEASING header - US6 (pull request 4): the v1.0.0 notes byte for byte, the v1.1.0 draft, README's version paragraph and three corrections - Polish: quickstart.md end to end - a "before Phase 1" note: merge origin/main (2732d59) into the branch first; a table of requirements met by acts the change's tasks.md tracks; FR-047 pending Brett Heap's word Checked: a script finds 25 well-formed task lines with no [P] overlap and every verify passing bash -n; T001's, T002's and T014's verify commands pass on a correct sample and fail on a wrong one. research.md R16 also records that main has moved (AGENTS.md 321/323 at 2732d59). Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… CRITICAL or HIGH left (#228) /speckit.analyze (before_analyze and after_analyze hooks skipped), three passes. Pass 1: 0 CRITICAL, 3 HIGH, 6 MEDIUM, 12 LOW. Pass 2: 1 more HIGH. Pass 3: 0 CRITICAL, 0 HIGH. HIGH, fixed: - FR-029 refused any dispatch not on the annotated tag, against FR-033's branch rehearsal; now the tag and branch-membership checks stand down on a branch, as in the model (release.yml:200-249 at v1.1.0), any other ref is refused, and contracts/workflows.md steps 2-3, T018 and T019 agree - no task ran the wheel check on a bad wheel, though a missing LICENSE is the lead's ruling 1: T015 and T018 now run each workflow's wheel-check heredoc on four synthetic wheels (as built; no licenses/LICENSE; a changed payload byte; a changed mode) - the upload jobs' permissions were "the reads its re-checks need": now exactly id-token: write, actions: read, contents: read (the model's release.yml:691-694, :1133-1136), build contents+actions read, install contents read, held by T018 and T020 - FR-014 let --help behave as in a checkout while FR-012 refuses it on a broken stamp: FR-014 now applies to a stamp that passes FR-010 MEDIUM, fixed: T004's tests run the payload's bash directly, so T007 and T008 stay parallel; FR-024's move is in the v1.1.0 notes (T023) and the coverage table; the PATH note's "none" case has its own ending; a branch rehearsal needs a dispatched tests.yml run first (header, T021); FR-031's "nothing from opensoft/openRepoTools" is listed as met by the absent pypi.org publisher; the 3.9 leg compiles the installed payload's copies. Also: the package job takes tomli's whole entry (39+ hashes) from the build lock instead of copying one digest (research R12); build's outputs name `final`; main is now 83d2690 (lane-start and skills/handoff/SKILL.md changed in content, modes and payload list unchanged). Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n the change and in feature 006 (#228) Documents only. Each ruling is applied in the change first, then in the feature: 1. A repository guard on the uploads, in code (FR-048; design.md Decision 10; research R19): - opensoft/openRepoTools: testpypi takes a pre-release only, and pypi refuses outright; - opensoft/openRepoTools-code: pre-release to TestPyPI only, final to TestPyPI then PyPI; - any other repository: both upload jobs refuse. The build decides it before any approval and records to-testpypi and to-pypi; each upload job's condition reads them and its first step checks again; the missing pypi.org publisher is the second line. The model's release.yml carries no such guard, so it is new here. T018 adds test_release_guard_build_ and _upload_, and T019-T021 build and document it. 2. The proposal and the pypi-package delta spec now state FR-029's rule: on a branch rehearsal the tag and release-branch checks stand down, as in openRepoShape's release.yml:200-249, and every other check runs (one new scenario). 3. main is not merged now: tasks.md makes that merge, as a merge commit, the implementation's first act. 4. pip's /bin/sh trampoline (pip 26.2.1, distlib/scripts.py:180-182) is recognised as pip's console script (FR-020, Decision 8, pipx-link.md, R6), with three refused and five placed fixtures in T012. pip's own template writes the import at column 0 in both forms (PipScriptMaker, wheel.py:417-424), so the import pattern stands. 5. A package-mode run names `openrepotools <its version>` as the count line's source; `<repo> @ <ref>` is only for a checkout or the one-line install (FR-019, Decision 7, R5). 6. Wording: - the unreadable-stamp clause is now "the openrepotools beside pipx's link, whose stamp cannot be read"; - the broken-stamp line takes <why> as "cannot be read", "is partial:" or "is malformed:", one fixture each in T009; - "venv-shaped" is the one term; - the pypi job is "skipped" in an rc rehearsal; - a branch rehearsal builds with the version of the tag it rehearses, 1.1.0rc1 first (R20, after the model's l3-rehearsal-v1.1.0). The change's tasks.md ticks 2.1 (eb12177) and 2.3 (760281b), and item 4.3 now says skipped. design.md records rulings 6-11 as resolved by the lead, 2026-10-18. /speckit.analyze, two passes: - pass 1 found two MEDIUM, both fixed: T019's verify needed guard-test names that T018 had not fixed, and T009 lacked the three causes. It also fixed four LOW: the data model's install row, the exact-spelling guard, the checklist's scenario count (now 49) and FR-032's compile source; - pass 2 found 0 CRITICAL, 0 HIGH and 0 MEDIUM. 25 tasks (19 [O], 6 [S]); every task line is well formed; openspec validate --strict passes. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to main before Phase 1 Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ped stamp src/openrepotools/__init__.py holds a docstring and nothing else (research R1), so loading the package runs no code. src/openrepotools/_release.py is contracts/stamp.md's committed file: a module docstring with no line hatch could read as the version, then the five assignments, VERSION at 0.0.0 and TAG, COMMIT, DIGEST and REPOSITORY empty, LF only, with a final newline (#228). Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…24 carries Brett Heap's option (c) (#228) Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… ruling 2026-10-18) src/openrepotools/__init__.py and src/openrepotools/_release.py now open with `# SPDX-License-Identifier: Apache-2.0`, as every other tracked .py file in this repository does and as openRepoShape v1.1.0's own package files do. As in all of those, the docstring follows on line 2 with no blank line between. Every other byte of both files is unchanged, so the stamp is still the SPDX line, one module docstring and the five assignment lines, LF only, with a final newline (#228). T001's verify still exits 0. Hatchling 1.27.0's version pattern still first matches `VERSION = "0.0.0"`, since a `#` line cannot match it. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ring, five assignments (#228) On the lead's ruling of 2026-10-18, src/openrepotools/_release.py opens with `# SPDX-License-Identifier: Apache-2.0` (b6ff505). The documents now say so. - contracts/stamp.md: the committed file's block and its bullets give the SPDX line first, then one module docstring, then the five assignment lines. Grammar rule 2 already skipped every blank and `#` line. It now says outright that this holds before the docstring, so the SPDX line is skipped. Rule 3 now says the docstring need not be line 1, and only lines rule 2 skips may come before it. The hatch section notes that a `#` line can never match hatch's pattern, and the writer keeps the SPDX line with every other byte. - data-model.md: the file's shape is the SPDX line, one docstring and the five lines, and the reader skips the SPDX line as a comment. - research.md R1: __init__.py holds the SPDX line and a docstring and no code. Both package files open with that line, as every tracked .py file here and openRepoShape v1.1.0's package files do. The stamp is that line, one docstring and the five lines. tasks.md, T001's task line included, is the lead's, and is untouched. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…soft/openBenches#165 (#228) Brett Heap's word of 2026-10-18 was "go with (c)". Lane openRepoTools-3 has filed opensoft/openBenches#165, for workBenches' scripts/setup-estate-commands.sh to accept pipx's openRepoTools link. - spec.md FR-047 is decided, no longer pending. README offers `pipx install openrepotools` only after opensoft/openBenches#165 lands, and PyPI must still serve the version (FR-045). Until #165 lands, README says a workstation uses one install route or the other, never both, and cites it. - proposal.md: the workBenches condition's position (c) bullet is decided and cites opensoft/openBenches#165. It is the only proposal bullet that changed. - design.md: the workBenches question leaves "Still open". It is now item 12, "Resolved by Brett Heap, 2026-10-18: (c)". - the change's tasks.md item 1.4 is ticked, with its evidence. The issue is written in full as opensoft/openBenches#165 throughout, because a bare #165 in this repository names #165. Feature 006's tasks.md is the lead's and is untouched. T024 already carries the README sentence (cf43b07). `openspec validate release-tags-pypi --strict`: Change 'release-tags-pypi' is valid. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…wheel.md The build system is pinned at hatchling==1.27.0. [project] names openrepotools, with a dynamic version read from src/openrepotools/_release.py, requires-python >=3.9, Apache-2.0 with license-files ["LICENSE"], dependencies = [], and no readme. It declares the one script, openRepoTools = openrepotools.cli:main, and the wheel's packages, src/openrepotools. The force-include map has 24 entries. The first 23 are the installer's payload_names, in its own order, and the last is contracts/openreposhape-pin.yaml. Each entry maps P to openrepotools/payload/P. Header comments in openRepoShape v1.1.0's style give three reasons: - src/, because the root's openRepoTools clashes with an openrepotools/ directory on a case-insensitive disk; - no readme, because README.md goes to the assembly root at the cutover; - the hatchling pin, because 1.27.0 is the newest release on Python 3.9, and 1.28.0 and later require 3.10, as read from PyPI. The optional description, authors, classifiers and [project.urls] are left out. contracts/wheel.md allows them, but this task does not ask for them. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…outs The four fixture builders that plan.md's "The test layout" names, for the pipx, stamp and entry-module tests (T004, T005, T009, T012, T018). The module imports only the standard library, never conftest, and finds the repository as Path(__file__).resolve().parent.parent. - package_tree(prefix, python="python3.12", stamp=None) builds <prefix>/lib/<python>/site-packages/openrepotools/ and returns its payload/. It copies every src/openrepotools/*.py that exists, at 0644, with the given stamp text as _release.py when one is given. payload/ holds the 24 files of pyproject.toml's force-include map, in its order, byte for byte, at 0755 or 0644 by the checkout's owner-execute bit. - pipx_venv(pipx_home, release, python=None, stamp=None) builds <pipx_home>/venvs/openrepotools/ around a package_tree for pipx 1.11.1, 1.17.8 or 1.18.3, defaulting to the interpreter of that release's row in contracts/pipx-link.md. It writes bin/openRepoTools as pip's console script naming the venv's bin/python, and pipx_metadata.json and pyvenv.cfg with placeholder content. Under a spaced home, the console script is pip's /bin/sh trampoline, as pip writes it there. - console_script(path, python, form=None) writes pip 26.2.1's PipScriptMaker template for openrepotools.cli:main, at 0755. It writes either form pip writes: form="shebang", form="trampoline", or pip's own choice, with distlib's quoting of a spaced interpreter and Linux's 127-byte limit on every platform. - stamp_text(**fields) gives the committed stamp with the given fields' values. Each committed line must occur exactly once, and every other byte is kept. Values are not checked, so broken stamps can be built. The payload list is read from the force-include table line by line, because Python 3.9 has no tomllib, and it is cross-checked against tomllib where tomllib exists. The list is read when a builder is called, not at import. A malformed map then fails that builder, and test_payload_map_ still runs and names the differences. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes in #232 (tests/run.sh records its lock owner), #233 (the openRepoShape pin at v1.1.0, 190133d) and #229 item 22 (the bench-root host-path hygiene rule). The two sides touch disjoint files, and no file this branch adds names a bench-root path. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…offline package install (US1) The US1 tests of contracts/pipx-link.md and contracts/cli-output.md, written before T008, on tests/package_layout.py's fake venvs: - test_pipx_link_*: the twelve layouts (pipx 1.11.1, 1.17.8 and 1.18.3 under $PIPX_HOME, ~/.local/pipx, ~/.local/share/pipx and a home with a space, absolute and relative links, PIPX_HOME set only in its own column); a 40-link chain at the hop limit; the five negative cases, from a checkout and from a package outside pipx's venv. - test_pipx_skip_*: the exact skip and pipx-own count lines, 28 receipt rows and the link left as it was; a second link refused with today's rm -f for it alone; the venv-shaped entry and paragraph with no rm for the link, alone and beside another link; no jq; a restart retirement; a later --install; RETIRED never holding openRepoTools. - test_pipx_offline_*: a package-mode --install with the sentinel repository and a failing gh and curl places what a checkout's install places, apart from the link, and calls neither. Every run is bash <installer> --install, never the console script. Only the lines the contracts name are asserted, never a whole output or a hook line. Before T008, 27 fail on today's link refusal and 7 pass. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…228) Add test_the_package_imports_only_the_standard_library. It parses every module under src/openrepotools/ with ast and holds each import, at any depth, to an explicit allowlist of top-level names: os and sys, the two modules design.md Decision 3 has the entry module use (os.execvp, sys.argv, sys.stderr). A relative import and an __import__() call are refused. Where sys.stdlib_module_names exists the allowlist is itself checked against it; on Python 3.9, which has none, nothing skips and the allowlist alone decides. Widen test_the_python_files_compile to compile the same set of modules. Lane: openRepoTools-3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the_ref It now says that a checkout and the one-line install name the repository and ref they fetch from, and that a package names its release (contracts/cli-output.md). Every assertion of the three test_version_* tests is unchanged. Lane: openRepoTools-3 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…built wheel and the console script The package's tests come before their implementation (specs/006-release-pypi, tasks.md T005), under plan.md's four prefixes: - test_metadata_*: contracts/wheel.md's pyproject.toml rules, read with tomllib or tomli, skipping by name where neither imports. The build-lock agreement skips until .github/release-build-requirements.txt exists. - test_payload_map_*: the force-include map against payload_names, run from the installer's own text, plus the openRepoShape pin, both ways round. - test_wheel_*: checks 2, 3, 5 and 6 of contracts/wheel.md and the member comparison against HEAD, on the wheel OPENREPOTOOLS_TEST_WHEEL names; skipped by name when it is unset. Check 6 is also held the other way, so a member the list has and the wheel lacks is named. - test_entry_*: pip's console script in a venv --without-pip holding a package_tree: the exec of the first bash on PATH in the script's own process with the payload and the arguments unchanged; a refused argument as the payload's own refusal in both of pip's script forms; a SIGTERM mid-placement leaving no temporary; the exact no-bash refusal, exit 2, nothing run; and wip_shape_ref, cut out with installer_function, reading the pin packaged beside the payload. Before T007 every test_entry_* fails on "No module named 'openrepotools.cli'", and nothing else. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… worktree and cherry-picked here (#228) Built in parallel on Brett Heap's word of 2026-10-18T03:36:47Z, each from 4ae999d, each accepted on model, scope and verify in its own tree, then cherry-picked with an identical patch-id: - T006: d5449c6 (006-release-pypi-t006) -> d57b75d, accepted 05:58:12Z (sonnet-xhigh) - T010: 331e095 (006-release-pypi-t010) -> fa44864, accepted 08:44:12Z (sonnet-xhigh) - T005: c862db2 (006-release-pypi-t005) -> b286953, accepted 08:46:35Z (opus-xhigh) T004 (7921a2e) is marked once its own acceptance has run. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sts.yml's, line for line but for the fingerprint, and release.yml's comment says so (#228) SHOULD 1: the comment above the install check's offline --install said it and tests.yml's package step "cannot drift", and no test tied them. test_release_install_check_the_offline_install_is_the_package_job_s_but_for_the_fingerprint finds, in each job, the one step with no if: that runs --install against offline.invalid/sentinel, requires the same keys beside the two scripts, and requires the scripts' differences to be exactly FINGERPRINT_LINES, the two places each names: tests.yml's GNU stat -c and sha256sum fingerprint of pipx's link, and the release's Python one, which the macOS leg needs. So a count line, a skip line or a receipt count changed in one copy alone fails it (mutants I1 and I2). The comment now says the two scripts are one but for the link's fingerprint, and that tests/test_release_workflow.py holds them so. It is reflowed and nothing else in release.yml changed: every changed line is a comment, and the pinned load_yaml reads the same workflow. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rsion's own tag, and refuses each (#228) U1 and U2: run_upload_guard always passed refs/tags/v$VERSION, so neither upload guard's ref check was tested. It now takes a ref, and test_release_guard_upload_refuses_every_ref_but_the_version_s_own_tag runs each guard, for each repository and version it passes on its own tag (testpypi: the code leg's final and pre-release and this repository's pre-release; pypi: the code leg's final), on a branch, the rehearsal branch, a branch named as the tag, another version's tag, the tag without its v, a pull request's ref and no ref at all. Each case passes on its own tag and is refused on the other ref: 28 cases. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ked, and the whole step stamps the run's own repository (#228) S1: no case paired a good first copy with a bad second one, so a writer that wrote each copy as it checked it passed. test_release_stamp_writer_writes_neither_copy_until_both_are_checked gives the writer the committed stamp first and, second, one already stamped, one with TAG = "" twice or one with no DIGEST = "", and requires the refusal to leave both copies as they were. The bad stamps come from a_stamp_the_writer_refuses, which the existing not-the-committed-stamp test now uses too. S3: the stamp tests ran the heredoc alone, with REPOSITORY handed in, so a line after the step's export that set REPOSITORY again passed. test_release_stamp_writer_step_as_github_runs_it_stamps_the_run_s_repository runs the whole step under the Runner, with VERSION, GITHUB_SHA, GITHUB_REPOSITORY, DIGEST, TREE_A and TREE_B as a run sets them, for each of RELEASES (the code leg, this repository and a fork), and requires both extractions to be the committed stamp with that release's five values. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… check, each refused naming what is wrong (#228) W2 to W7: the wheel check's only cases were the contract's four synthetic wheels. NOT_THE_COMMITS now also holds: licenses/LICENSE with a byte changed (W2); openrepotools/cli.py with a byte changed (W3); openrepotools/payload/lanes-index missing (W4); extra.pth, which nothing puts in the wheel (W5); the wheel as built, checked in a run whose GITHUB_REPOSITORY is opensoft/openRepoTools while the release's REPOSITORY is the code leg (W6); and the stamp with a comment line after its last, its five values still the release's (W7). Each runs through the existing test: the wheel as built passes, this one fails with no traceback, and a line it adds names the file, or for W6 the run's REPOSITORY. Each case's tuple gains the run's values, which run_wheel_check now takes, and a_changed_byte is a_changed_member on a payload path. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…all are held by their steps' names and commands, and the install check's is run (#228) The MUST candidate. test_release_upload_each_upload_job_checks_publishes_and_checks_again counted any step before the upload whose script held "sha256", and the index step's ["sha256"] answered for it, so the dist check's command could go (mutant X4). It now requires the step named "dist holds the wheel the build job verified, and nothing else", holding the command echo "$WHEEL_SHA256 dist/$WHEEL" | sha256sum --strict -c -. test_release_install_check_takes_the_wheel_by_its_digest_on_a_tag_and_a_branch counted any later step whose script held "sha256", and the offline --install's fingerprint answered for it. It now requires the step named "the wheel is the one the build job verified", with no if:, after both ways of taking the wheel and before pipx installs it, and test_release_install_check_the_digest_step_passes_the_recorded_wheel_alone runs that step's heredoc: the recorded wheel passes, and other bytes under its name, another file beside it, another name and an empty directory are refused, with no traceback. So deleting the step (mutant X7) or its digest comparison (mutant I19) fails. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r a tag nor a branch (#228) G4 (NIT): GUARD_ROWS held no such ref, so a guard that passed one as a rehearsal survived. A last row, the code leg's 1.1.0 on refs/pull/1/merge, must be refused with nothing recorded and no forge asked. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eg compiles with compile() (#228) Two NITs of the interim review. The item under "Resolved by the lead, 2026-10-18, on T020" was numbered 13, which the #237 ruling above it already uses; it is now 15, numbered after item 14, and nothing cites it by number. Decision 10 said the 3.9 leg runs py_compile, where the step compiles lanes-index and lane-worktrees with compile(), as contracts/workflows.md's install step 7 says. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a fake index, holding the lead's empty-index ruling and the served check's 20 reads (#228) X1 to X3: no test ran the index checks; only "/json" in their text was read. Both checks of both upload jobs now run under the Runner, as GitHub runs a step, against FakeIndex, a JSON API on 127.0.0.1 that answers read by read and writes down every read. JSON_BASE is the fake's, and each job's own is held to its index; the one other fake is the clock, a sitecustomize on the step's PYTHONPATH whose time.sleep writes down its seconds and returns, so the steps' scripts run as written. test_release_upload_the_empty_index_check_passes_no_file_or_the_verified_wheel_alone (9 cases a job): one read; a 404, a version listed with no file, and the verified wheel at its digest, not yanked, pass (ac2ca2b's ruling, design.md item 15); the wheel yanked, its name at another digest, another file beside it or alone, a 503 and a 403 refuse. test_release_upload_the_served_check_reads_until_the_verified_wheel_is_served (10 cases a job): it reads through a 404, an empty listing or a 503, 15 seconds apart, and passes on the read that serves exactly the verified wheel, the 20th included; served only at the 21st, another file beside it, another digest, the wheel yanked and a 403 refuse, with the reads counted. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on 3.9 step are run (#228) I7 and I8: the --version step was held by "--version", GITHUB_SHA and GITHUB_REPOSITORY in its text. test_release_install_check_the_version_step_passes_this_release_s_five_lines_alone runs it under the Runner over a package_tree whose entry execs bash on its payload, as pipx's console script does: the run's own stamp passes and prints exactly its five lines, and a stamp with another digest, commit, repository or version, or the unstamped one, is refused. I6: the 3.9 step was held by its text. test_release_install_check_the_3_9_step_refuses_a_payload_command_that_does_not_compile runs its heredoc on a pipx 1.11.1 home: the payload as built passes, and a lanes-index that does not compile, a missing lane-worktrees, no payload directory, two of them, and a Python other than 3.9 are refused, each named, with no traceback. The suite runs on a current Python, so this Python runs the heredoc reading as the case's version (AS_ANOTHER_PYTHON sets sys.version_info and sys.version, and nothing else). Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l, naming its ten differences (#228) The macOS rerun under /bin/bash 3.2 is the third copy of the offline --install, the same script on purpose but where it must differ. The SHOULD 1 test, renamed test_release_install_check_the_offline_installs_are_one_script_but_for_named_lines, now also requires the rerun to have the offline --install's keys but its if:, and its script to differ only in MACOS_RERUN_LINES: its own home and offline directory, the BASH_VERSION probe that must say 3.2, /bin first on the --install's PATH, its own output files, and refusals that name that bash. The skip line, the count line, the 28 rows and the fingerprint are the offline --install's own. A rerun that accepts any bash (I4) fails it. The comparison is assert_one_script_but, which the tests.yml tie uses too. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…inned, and both copies of the guard's table are tied to GUARD_ROWS (#228) H1 and H3: HEADER_CARRIES now holds procedure step 4 word for word, the two approvals, and the branch-cut line with its ^{commit} peel: without it the remote rejects a push of the annotated tag's object to a branch ("trying to write non-commit object"). H2: test_release_header_s_guard_table_is_the_guard_s_own_decisions reads every comment row of the guard's table in release.yml, which writes it twice, in the header and above step 1, and requires each copy's rows to give, for every GUARD_ROWS case on a tag or a branch, the decision the guard is run to: TestPyPI, then PyPI; TestPyPI alone; refused; or the rehearsal's nothing. Every row has a case, and every such case has its row. Lane: openRepoTools-3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sorry @brettheap, your pull request is larger than the review limit of 150,000 diff characters |
This was referenced Oct 19, 2026
|
brettheap
added a commit
that referenced
this pull request
Oct 20, 2026
…runs the fetch, pipx, approval, tag, ref, clean, stamp, dist and digest steps instead of reading them, and release.yml changes only in comments (#228, PR 3b) (#284) Part of #228: **pull request 3b** of feature `006-release-pypi`, stacked on #268 (PR 3, head `9682f0b`). It is the fix round for lane openRepoTools-2's verdict on PR 3 (#228 6273189381) and its re-check (6277890612, 6278141437). Those mutants of `release.yml` survived at `9682f0b` because the steps they changed were read as text, not run. **Nothing changes in what the workflow does.** `release.yml` changes in 9 comment lines only, and `spec.md` in 10. `tests/test_release_workflow.py` grows from 66 test functions to 79. The diff against `9682f0b` is 3 files, 1023 insertions and 90 deletions. No tag is pushed and nothing is dispatched (plan.md gate G8). **The nine commits** - `4daaeda` (SH2, mutants I11 and I12): the install check's fetch step is run on a tag with `curl` faked. - It passes the one file TestPyPI's JSON lists under the wheel's name, at the recorded digest, over https from test-files.pythonhosted.org. - It refuses before fetching anything: another host, plain http, a file listed twice, another digest, another file at the digest, and nothing listed. - The pipx step is run with pipx faked. It passes only when pipx's bin directory holds the one link `openRepoTools`. - `2f274c4` (SH3, mutants E2 to E4): a fake `gh` answers the forge's REST reads. Under it are run: - the build's environments step; - each upload job's approval re-check; - each upload job's tag re-check, with the tag moved, deleted, made lightweight, or naming a tag. - `9762479` (SH5, mutants RF1 and RF2): the ref step is run on tags that a forge fake and a `file://` origin hold, so only the step's own comparisons can refuse. - `2a83a61` (SH7, mutants W9 to W12): one synthetic wheel each, made from HEAD's blobs: - METADATA naming a dependency; - a second console script; - a sixth `.dist-info` file; - no `licenses/LICENSE`. Each refusal must name what is wrong. - `0cf8142` (NITs S7, S8, T5, BLD1, H5 and N5): a case for each: - a TAG of another version; - a read-back one character short; - a forge that ignores `head_sha=`; - the build step run with the backend faked; - the "STAYS PUBLIC" bullet; - every job's whole step list, pinned in order (`STEP_ORDER`). - `76dd73c` (SH8, mutant N3): the clean step is run. The test file's header lists which decisive steps are run and which are still read as text. - `5ccd66e`: the doc NITs, in comments only. - One spelling for the rehearsal's row. - FR-029's additions are named in the header and in FR-028. - Step 1's comment is made true. - US5's tenth scenario is numbered. - `7376b34` (SH6, S5 and S5b, and NITs 1 and 3 to 6 of the PR 3 re-check): - the stamp step is run whole with `refs/heads/release/v1.1` and with `refs/tags/v1.1.0`, and both must stamp `TAG v1.1.0`; - each upload job's dist step is run whole, and so is the install check's digest step, on five cases each; - the fake index polls every 0.01 s; - `PYTHONDONTWRITEBYTECODE=1` is set in `run_index_step`; - a served-check case's first read is a connection closed with no response. - `2ff7094` (the fix-up for lane 2's re-check, #228 6284132726: its N1, its question 1 and its NIT 3): - the test file's header names the dist step among the steps run, and says six are read only as text. Two more header sentences, untrue at `7376b34`, are corrected: how the build's record of the wheel is held, and which steps read `GITHUB_SHA` and `GITHUB_REPOSITORY`; - `STEP_ORDER` finds the build's guard by `guard_step()`, each upload job's guard as its first step, and the macOS and 3.9 legs by `condition_kind()`, as HOW A STEP IS FOUND has it. The count and order are unchanged; - W9's naming check reads only a refusal's `::error::` line. **`7376b34`'s subject says "WIP … written and not yet run".** It was pushed at Brett Heap's account swap, before any test ran. Every result below was then taken at that exact head, on a clean tree, with nothing changed. Its message cannot be corrected without a force-push, so the squash at landing carries an accurate one. **Results at `7376b34`** - **Mutants:** all 37 run are killed. They ran in four batches, and each kill is credited to a test that runs only that mutant's step. The 37 are: - I11 and I12; - all 17 of group 4's survivors; - I3, I10, I13, I14, I17, I18, X5, X6, G7 and S4; - seven new ones: S5b, X8 to X12, and I20. - `-k test_release_workflow`: 499 passed. - `-k "test_release_ or test_tests_yml_ or repo_hygiene"`: 733 passed. That is lane 2's 646 at `9682f0b`, plus 87 new tests. - actionlint 1.7.12 is clean. - `git diff 9682f0b 7376b34 -- .github/workflows/release.yml` changes comment lines only. **Results at `2ff7094`.** `-k test_release_workflow` gives 499 passed, 0 failed and 0 skipped. A step inserted after the stamp writer is killed by the pin. The macOS rerun or the build's guard, renamed, passes it. W9's refusal without its `::error::` naming line is killed. `release.yml` is byte-equal to `7376b34`. **Review.** Lane openRepoTools-2's re-check of `9682f0b..7376b34` is LAND, with no MUST and no SHOULD (#228 6284132726): all 113 mutants are killed. Its re-check of the fix-up, `7376b34..2ff7094`, asked for in 6284529659, is LAND (#228 6288385122). **CI record.** `lane3-queue/q7k2-228pr3b-on-q6k` (`4d6581d`, tree `7ad2bbe`) puts this PR on the main that lane 3's queue k leaves: main `677acc0`, then #262 and #267 to #271. Its `tests.yml` run 39378128111 is green. **Left for v1.2.0** (lane 2's NITs, not taken here, filed on Brett Heap's word of 2026-10-20T09:40Z): WX1, the wheel check's bash line (#285); a `URLError` without a status (#286); the `--depth` pin on the ref step's tag fetch (#287); and a test that runs the stamp step followed by an inserted step (#288). **Landing.** It lands after #271 in lane 3's queue, on Brett Heap's word of 2026-10-18T20:37:07Z: "use this as approval to merge when green for all merges thru v1.1.0". When #268 lands, the landing retargets this PR to main. Lane: openRepoTools-3 Landed by lane openRepoTools-3 as queue prefix q7k2 (tree 7ad2bbe, tests.yml run 39378128111 green), on Brett Heap's word of 2026-10-18T20:37:07Z: "use this as approval to merge when green for all merges thru v1.1.0". Lane openRepoTools-2's re-check of 9682f0b..7376b34: LAND (#228 6284132726); its re-check of the fix-up 7376b34..2ff7094: LAND (#228 6288385122). 7376b34's subject says WIP because it was pushed at an account swap before its tests ran; every result above was taken afterwards, at 7376b34 or at 2ff7094. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brettheap
added a commit
that referenced
this pull request
Oct 21, 2026
… 1.1.0 and list, by area and from the squash titles of aaa7bc8..a42946e, what else changed on main since v1.0.0 (#228) (#293) Part of #228. It brings `docs/release-notes/v1.1.0.md` up to date on main: first on `a42946e`, as lane 3 asked on Brett Heap's word (#228 comment 6303608345, the section for lane openRepoTools-2, task 1), then with lane 3's review of `d8a349d` (comments 6314185715 and 6314529807 on this pull request), with the lines for the three changes that landed after `a42946e`, and with the line for #296, which landed right before this pull request. It is one file, changed in two commits (`d8a349d` and `bebb77d`), 59 insertions and 4 deletions against main. Lands last before rehearsal D's freeze; lane 3 reviews and merges it (#228 6303608345) **What changed** - **Lane 3's review is applied,** in the second commit: - **The line on #255 and #271** no longer says that `lane-reconcile` and `lane-handoff` read a dependency nested in a leg, since only the sweep and `lane-end` do. It says that a leg directory this account cannot search is unreadable and never `absent`; that a dependency nested in a leg whose directory, or one above it, it cannot search is unreadable to the sweep and `lane-end` too; and that one known gap remains, #272, where the sweep reads a declared leg beneath such a directory as `absent`, so `lane-end` does not hold on it. It also says NOT POLLED where the tool prints it, and it says that the item closes two gaps in #246, where it said "both gaps" with nothing before it to refer to. - **The line on #280 and #283:** an `awk` exits and does not "return", and the sentence on a status of 0 or 8 is gone, because a reader of the notes cannot act on it. - **The line on #214:** the fence passes a local commit only when it adds or changes a register or handoff file, and never checks whose it is, so the line no longer says "the lane tooling's own". - **The counts in the `<other-changes>` item:** the pin's line (#233) is in the list, so the list carries 44 of the 53, and the other 9 have their lines under "What 1.1.0 adds", not 43 and 10. The item says "the openRepoShape pin" where the runner pin of #296 could be taken for it. - **The milestone item** names #247, so it lists the six entries the milestone held on 2026-10-20. - **#209 is not tests-only.** Its `-e` fixes `lanes`' stderr filter under macOS's BSD `grep`, so it moves from the test suite to the lane area, after #208's, and its one line there also carries its test changes: the `repoG#8` assertion and the count of bash files in prose. It is cited once. - **Lines for the changes after `a42946e`:** #263 (`d9065df`), #289 (`fb2cf36`) and #294 (`acc89ea`, which closes #292) landed on 2026-10-21, from 11:28Z to 11:30Z. Each has a line in its area, worded from its squash commit and its description: #263 and #289 under "The register and `lanes-edit.sh`", and #294 under "`lane`, `lane-start`, `lane-end`, the name guard and their helpers". - **#296 has its line too,** last under "The test suite and its checks": CI and the release workflow run on `ubuntu-24.04`, because `ubuntu-latest` is now Ubuntu 26.04, and `macos-latest` is unchanged. It landed right before this pull request, as `5afba4a`. - **"What 1.1.0 adds" gains two lines,** after the annotated-tags item. They are for the three entries that closed in the v1.1.0 milestone after the draft was written: - **#255,** fixed by #271: the lane tools name what they could not read in a triad's legs. `lane-handoff` names every tree-inventory record that is not a whole schema-1 one, and a leg directory this account cannot search is unreadable and never `absent`. Only the sweep and `lane-end` also see a dependency nested in such a leg, since `lane-reconcile` and `lane-handoff` read declared legs only, and #272 stays open as the known gap. - **#280,** fixed by #283: `lane-handoff` reads the lane's lifecycle whole and parses it afterwards, so an `awk` that exits early can no longer turn `lane-state`'s SIGPIPE into a lifecycle that could not be read. - #283 is #280's pull request, so the three numbers make two lines. Each line cites the issue and its pull request, as the hook-pair line does for #237 and #247. - **"What else changed since v1.0.0" is drafted** from `git log aaa7bc8..a42946e`, which is 53 squash commits, one pull request each and no merge commit. It is grouped by area, one line each, and each line ends with its pull request. It lists 44 of the 53: the pin's line (#233) at its head and 43 by area, as 4 on the estate commands, 10 on the register and `lanes-edit.sh`, 11 on `lane`, `lane-start`, `lane-end` and the name guard, 6 on the handoff and its skill, 1 on the lane tools in a triad's legs (#246), 9 on the test suite and its checks, and 2 on the triad migration's records. - **The other 9 are accounted for elsewhere:** the package series of #228 (#262, #267, #268, #269, #270 and #284) is covered by #228's lines, and #247, #271 and #283 have the lines above. - **The lines added on 2026-10-21** are for the four changes after `a42946e`: #263 and #289 on the register and `lanes-edit.sh`, #294 on `lane`, `lane-start`, `lane-end` and the name guard, and #296 on the test suite and its checks. The areas now hold 47 lines, one for each of 47 pull requests, and #233's line at the head of the list makes 48. - **The list is redone at the tag.** It is drafted from the squash titles only. - **"Before the tag" is updated in three items:** - `<pr-count>` gives the count at `a42946e`, which is 53; - `<other-changes>` says what was drafted, which 9 pull requests have their lines under "What 1.1.0 adds", that the lines for #263, #289, #294 and #296 were added on 2026-10-21, and what is left to do at the tag; the placeholder's own line now stands for the changes after `a42946e` that have no line above; - the milestone item names the six entries the milestone held on 2026-10-20: #228 still open, #237 closed by its pull request #247, #255 closed, and #280 closed by its pull request #283. **Not added:** nothing that has landed. #296 landed right before this pull request and has its line. This pull request itself, and whatever lands after it, is what the `<other-changes>` placeholder stands for. None of #263, #289, #294, #296 and #292 is in the v1.1.0 milestone, which still holds the six entries of 2026-10-20. **How this keeps the draft's rules** - **One-line paragraphs:** every added line is its own list item, and none is wrapped. - **References:** every reference above "Before the tag" is spelled `opensoft/openRepoTools#N`, with no bare `#N`, since the notes are published from another repository after the migration. - **Placeholders:** `<other-changes>` stays as a named placeholder in code font, as the closing line of the list and as its checklist item. `<pr-count>` is unchanged apart from the drafting-time count. - **The file's closing lines are untouched:** the self-naming last line stays last. **Tests** - **T023's verify command** passes: the last line names `openRepoTools-spec` and `docs/release-notes/v1.1.0.md`, `## Before the tag` is there, and so is `pipx install --force openrepotools`. - **Coverage:** a script over `git log aaa7bc8..acc89ea`, 56 commits and no merge, finds each pull request cited above "Before the tag" except the six of #228's package series, which #228's lines cover. That is 46 by area, #233 at the head of the list, and #247, #271 and #283 under "What 1.1.0 adds". #296 is not in that range, and its line cites it. - **Hygiene:** by grep over `tests/`, no test names this file. The two that read its content scan every tracked file, and both are in `tests/test_repo_hygiene.py`. The only other test that names `release-notes` is in `tests/test_release_workflow.py`, and it reads `release.yml`, not the notes. All of `tests/test_repo_hygiene.py` was run on the file, through `tests/run.sh` with every `LANES_*` and `TMUX*` variable unset: ```text -k 'repo_hygiene' -v collected 2933 items / 2696 deselected / 237 selected 237 passed, 2696 deselected in 2.59s ``` - **Not run:** the whole suite. CI's `tests` job is the suite of record. This pull request's own runs on `bebb77d` went red on `ubuntu-latest`, which is Ubuntu 26.04, for the reasons #296 gives, because #296 was not yet on main. The record is lane 3's queue run over main, #296 and `bebb77d`, on `ubuntu-24.04` (below). **Where the draft's rules left room, and lane 3's answers (comment 6314185715)** - **Which section holds #255 and #280:** "What 1.1.0 adds", because the milestone is Brett Heap's scope for the release and #237 with #247 already sit there. - **`<other-changes>` stays** as a closing placeholder after the drafted list, since this pull request itself lands after `a42946e`. - **How much to list:** the tests-only and migration-record lines stay through the tag, because the check that every pull request has a line depends on them. If Brett Heap wants a shorter body, they fold into one line that still lists every pull request number. - **Issues and pull requests:** the milestone lines cite both, and the area lines cite the pull request only. **Lane 3's re-check of `bebb77d`** (#293 6315668503) is MERGE AFTER FIXES. - **What holds:** every line lane 2 listed, the recount behind line 140 (44 of the 53 pull requests in `aaa7bc8..a42946e`, and 56 in `aaa7bc8..acc89ea`), the file's rules, and T023's verify commands. - **One SHOULD and two NITs, all wording:** - line 45's sentence on a dependency nested in a leg, where "one above it" reads as a directory above the leg, which is #272's case. The text was lane 3's own; - "One known gap" in the same line; - line 74's last clause. - **Why they wait:** lane 3 merges the notes as tested and carries the three fixes into the notes' final pass at the tag. A push here would cost another CI round while lane 2 is out of usage until 15:30Z, and the notes are edited again at the tag in any case. Lane: openRepoTools-2 Landed by lane openRepoTools-3, as queue prefix `lane3-queue-u/p2-293` (tree `9b879ca`; tests.yml run 39595166877, green on `ubuntu-24.04`), right after #296. Before the landing, lane 3 merged main into the branch, so that its own checks ran over main with #296; the content is unchanged. Brett Heap's word, of 2026-10-20T22:5xZ: "merge all when green for all merges thru v1.1.0. use this for all lanes" (#228 6303614082). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brettheap
pushed a commit
that referenced
this pull request
Oct 22, 2026
…ntry module's refusals, and the requirements checklist counts the delta specs' 51 scenarios, where it said 49 (#256) This commit completes the spec half's consistency on Brett Heap's word of 2026-10-22, "yes, fix the spec leftovers too". It follows 9f4700c, which named the entry module's second refusal in the CLI-output contract, design.md's Decision 3, FR-004 and the pypi-package delta. It touches only specs/ and openspec/. Each quote of the line below is byte for byte the one cli.py has at db19b65: REFUSED: openRepoTools needs bash, and no bash on this PATH can be run (<why>). Nothing ran. - specs/006-release-pypi/checklists/requirements.md, the Coverage line: "Their 49 scenarios" is now "Their 51 scenarios, 38 in pypi-package and 13 in release-tags-and-branches", and a dated note, "Recounted 2026-10-22, for #256", says why. The recount is below. - specs/006-release-pypi/tasks.md, T007 and T026: each gains an "Amended 2026-10-22, for #256" sub-bullet. T007's says that main() now catches every OSError, that FileNotFoundError and NotADirectoryError keep the no-bash refusal, and that every other one prints the second refusal and returns 2. T026's says the same of the two not-found errors and the others, and that both refusals are printed after the exec has failed and the two signals have gone back to what they were. The openspec change's own tasks.md holds neither task and says nothing of the entry module, so it is unchanged. - specs/006-release-pypi/tasks.md, T005, which the sweep found: its test_entry_* bullet named only the no-bash refusal, and has the same kind of note now. It gives the second refusal, for a bash that cannot be run, and a runnable bash later on PATH that runs instead. The task lines, checkboxes, tiers and every files: and verify: field are byte for byte as they were: 26 tasks, all [X]. - openspec/changes/release-tags-pypi/proposal.md, "Which bash": a nested "Amended 2026-10-22, for #256" bullet, in design.md Decision 3's wording, gives the second refusal, the two errors that keep the no-bash one, and the named limit (a bash that is there but cannot be started). The recount. The 49 counted the delta specs' "#### Scenario:" blocks, and it was right when the line was written (c82578f: 36 in pypi-package and 13 in release-tags-and-branches). It had gone stale by 33ce26d, which holds 50 (37 and 13), because #268's empty-index ruling added "The index already holds the verified wheel". 9f4700c's "A bash that cannot be run" makes 51 (38 and 13). The 25 requirements (17 and 8) are unchanged. The spec's own acceptance scenarios are another count, which the line never held: 44, by story 10, 6, 7, 5, 10 and 6 (43 at 33ce26d, before US1's scenario 10). The sweep of specs/ and openspec/ found no other place that describes only one entry-module refusal. The notes carry the date they were written, 2026-10-22, and cite design.md's amendment of 2026-10-21. `openspec validate release-tags-pypi --strict` calls the change valid and `git diff --check` is clean. The two tests that read every tracked file, the host-absolute-path rule and the adoption act 0 citation, pass over this tree under tests/run.sh, with every LANES_*, TMUX* and WORKBENCHES_* variable unset. Lane: openRepoTools-5 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This was referenced Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Part of #228: pull request 3 of 4 of feature
006-release-pypi, plan.md "Delivery". It holds User Story 5, which is Phase 7 ofspecs/006-release-pypi/tasks.md(T018 to T021).One dispatched workflow now builds the wheel, uploads it to TestPyPI, checks the install on three legs, and uploads it to PyPI.
.github/workflows/release.ymlhas four jobs,build,testpypi,installandpypi, andtests/test_release_workflow.pyholds it.Nothing is published here.
release.yml'son:block holdsworkflow_dispatchand nothing else, with one required string input,version(release.yml:231-241). No push, tag, pull request or schedule starts a run. The two upload jobs also run only on av*tag, so a dispatch on a branch uploads nothing.testpypiruns in the GitHub environmenttestpypi, andpypiin the environmentpypi.id-token: writeis granted to those two jobs and to no other, and the file holds no PyPI token and nosecrets.reference (grep -c 'secrets\.'gives 0).No lane pushes a tag or dispatches the workflow without Brett Heap's word (plan.md gate G8).
What it adds
tests/test_release_workflow.py(T018,7b5167a): the tests come before the workflow, so every test that readsrelease.ymlfails until T019 to T021 write it, naming the file and the tasks. They read it with the pinned openRepoShape's ownload_yaml(research R9), and skip without the submodule.grep -c '^def test_'counts 56 test functions at T018 and 66 at the fix head9682f0b, under ten prefixes:test_release_trigger_,_lock_,_build_,_stamp_writer_,_guard_build_,_guard_upload_,_upload_,_install_check_,_reads_and_header_. The lock tests and the digest-label test read nothing ofrelease.yml, so they pass before it exists.GITHUB_*,RUNNER_*,LANES_*andTMUX*variable removed, andghandcurlfaked.tests.yml's four jobs, and the digest step, which also runs in a copy of the checkout whose standard or pin names another definition.licenses/LICENSE, a changed payload byte, a mode 0755 made 0644, or a mode 0644 made 0755 fails, and a line of its refusal names the file.--versionfrom apackage_tree. It refuses a file already stamped, and a value no release carries.release.yml's shape and itsbuildjob (T019,0de7213): adapted step for step from openRepoShape v1.1.0 (190133d), under the model's step names, with design.md Decision 10's differences.workflow_dispatchwithversion,permissions: {}, thereleaseconcurrency group that never cancels,bashby default, andVERSIONandPYTHONUTF8inenv.build:contents: readandactions: read, 16 steps (counted at29cc1b3), and five outputs:wheel,wheel-sha256,digest,to-testpypiandto-pypi. In order, it:X.Y.ZorX.Y.ZrcNand never0.0.0, and runs the repository guard (FR-048), which recordsto-testpypiandto-pypi;v<version>whose object names the run's commit, read from the forge and from git; on a branch, a rehearsal; any other ref is refused), that the commit is onmainor onrelease/v<major>.<minor>, and that the checkout is that commit and clean;guard-launch-mode,tests,tests-no-submoduleandpackageeach ran in a push or dispatch run oftests.ymlon this commit, none is still running, and the newest to finish succeeded;tree_digestequalstree_digest_from_gh, and itsTREE_DIGEST_DEFINITIONequals the literalsorted-ls-tree-r-v1and the pin'sdigest_definition;git archive, writes the five-field stamp into both (REPOSITORYfromGITHUB_REPOSITORY), builds each withpython -m build --wheel --no-isolation, and requires one file;release.yml'stestpypi,installandpypijobs (T020,fb2249f): TestPyPI, then the install check, then PyPI.testpypiandpypi: each runs in its own environment, on av*tag and where the build's record says so (to-testpypi,to-pypi), sopypiis skipped in an rc rehearsal. Each holds exactlyid-token: write,actions: readandcontents: read.opensoft/openRepoTools-codeand a pre-release alone fromopensoft/openRepoTools. PyPI takes a final fromopensoft/openRepoTools-codeand nothing else.pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33, and the served digest read up to 20 times.install(contents: read): ubuntu and macOS on Python 3.x, and ubuntu on 3.9, with no Windows leg.--versionis checked line for line.--installbeside pipx's link is set up astests.yml'spackagejob sets its own: the skip line and the count line exact, 28 receipt rows, the link unchanged./bin/bash, whoseBASH_VERSIONmust begin3.2. The 3.9 leg compiles the installed payload'slanes-indexandlane-worktrees.release.yml's header, RELEASING (T021,a04b9e2): the header comment alone, in contracts/workflows.md's six sections, in order. The jobs are unchanged.v1.0.0's message form, the dispatch, the two approvals,gh release createonce PyPI serves the version, thenrelease/vX.YatvX.Y.0.1.1.0;1.1.0rc1first), where releases come from (the repository guard's table), and what the workflow never reads (FR-046).ac2ca2b): the lead's ruling of 2026-10-18 on T020's first doubt, written intoopenspec/changes/release-tags-pypi/design.md, thepypi-packagedelta spec,specs/006-release-pypi/contracts/workflows.mdandspecs/006-release-pypi/spec.md. design.md numbers it item 15, as round 1 fixed it (a review NIT).29cc1b3):specs/006-release-pypi/tasks.mdmarks T018 to T021 done.c6cea2aand9682f0b, 11 commits on1b41ce7): they change three files and no other line ofrelease.yml.git diff --stat 1b41ce7 9682f0bgives 3 files, 843 insertions and 56 deletions.tests/test_release_workflow.py; one comment inrelease.yml(:1381-1383, which now says which test holds the install check's offline--installequal totests.yml's, instead of saying the two cannot drift); and design.md's two NITs.c6cea2a, 7 commits):1d5d657: a test holds the install check's offline--installtotests.yml's, line for line but for the fingerprint, andrelease.yml's comment says so;2ed477f: each upload job's guard is run on refs other than the version's own tag, and refuses each;5116295: the stamp writer writes neither copy until both are checked, and the whole step stamps the run's own repository;d0620ab: the wheel check is run on one synthetic wheel per member check, each refused naming what is wrong;34f4239: the sha256 checks before each upload and before the install are held by their steps' names and commands, and the install check's is run (the review's MUST, under Review);5bc35c3: the build's guard is held to refuse a ref that is neither a tag nor a branch;c6cea2a: design.md numbers the T020 ruling 15, and says the 3.9 leg compiles withcompile().9682f0b, 4 commits on round 1, tests only):2a5d56c: both upload jobs' index checks are run against a fake index, holding the empty-index ruling and the served check's 20 reads;7b1c693: the install check's--versionstep and its Python 3.9 step are run;bc454ad: the macOS rerun is tied to the offline--install, naming its ten differences;9682f0b: the header's approval step and branch cut are pinned, and both copies of the guard's table are tied toGUARD_ROWS.The notes and the code leg, named before they exist. PR 4 follows this PR directly, and the migration's cutover follows all four. So five places describe them in the present tense:
.github/workflows/release.yml:108-112: RELEASING step 5 runsgh release create … --notes-file <spec>/docs/release-notes/v<version>.md. PR 4 addsdocs/release-notes/v1.0.0.mdandv1.1.0.md, and<spec>is the spec leg that the cutover makes.tests/test_release_workflow.py:3163(at9682f0b) holds that line of the header..github/workflows/release.yml:142-144: v1.1.0 "is built later, from another commit, in opensoft/openRepoTools-code"..github/workflows/release.yml:171-174: "FROM v1.1.0 ON, release tags are made in opensoft/openRepoTools-code"..github/workflows/release.yml:189-191: the ref step fetches the tag fromopensoft/openRepoTools-codewith no credentials, and the migration creates that repository..github/workflows/release.yml:222-228: after the cutover the workflow runs in the code leg, which holds none ofdocs/,openspec/,specs/,README.md,AGENTS.mdandCLAUDE.md.test_release_reads_nothing_the_code_leg_will_not_holdholds that no step names one.Runs
ba4a3df, branchlane3-queue/q3d-228pr3-on-q2g: q2g43ec2fe+ this head9682f0b, on main00d52ae, treede5db63):tests.ymlrun 39302680250, pending. This is the run of record for the landing.9682f0b: the selection-k "test_release_ or test_tests_yml_ or repo_hygiene"gives 646 passed, and actionlint is clean (Releases: annotated tags, release/vX.Y branches, and openrepotools on TestPyPI and PyPI from v1.1.0 #228 6273049912).Review. An independent review by lane openRepoTools-2, from two reviewers (tests and mutants, and reading and probes), of
85a7b05..29cc1b3, gave LAND after fixes (#228 6273189381). At1b41ce7the merge of PR 2's review fixes leavesrelease.ymland the test file byte-identical to29cc1b3, so that range is this PR's own.release.ymldoing a wrong thing today. Every finding but one false comment and some NITs is about what the tests fail to hold.34f4239holds the checks by their steps' names and exact commands, and runs the install check's. It should kill I10 as well, which the re-check confirms.1b41ce7..9682f0bis pending, and PR 3 lands only after it. Lane 2's three conditions for landing are: M1 fixed, that re-check, and Linux CI green.9682f0b, per lane 3's ruling (Releases: annotated tags, release/vX.Y branches, and openrepotools on TestPyPI and PyPI from v1.1.0 #228 6273289912). Nothing more goes into PR 3 before the re-check. The re-check says which of the NEW survivors rounds 1 and 2 already kill, and whatever survives goes to PR 3b, not to this PR.release.yml:194-199names.29cc1b3unless named:release.ymlandtests.yml, at29cc1b3and at1b41ce7: clean;-k test_release_workflow: 312 passed, at both commits, and again offline (dead proxies andGIT_ALLOW_PROTOCOL=file), where decoys forgh,curl,wget,pipand git's network commands logged nothing;release.yml, 48 killed and 56 survived;v$VERSION, reaches PyPI;ac2ca2b) matches its docs, apart from the item number round 1 fixed./bin/bash3.2, BSD tools, pipx on the three legs); a real hatchling wheel; Python 3.9 itself; and a syscall-level offline proof.Notes for other work
9682f0b) follows PR 3. Lane 3 lands it after PR 3 by cherry-picking it onto main, and lane 2 re-checks it with the same mutant set (Releases: annotated tags, release/vX.Y branches, and openrepotools on TestPyPI and PyPI from v1.1.0 #228 6273289912).main.1.1.0rc1rehearsal to TestPyPI is a later step, on Brett Heap's word.Landing: Brett Heap's decision 4 on #228 ("Yes, merge when green (Recommended)"), and his word of 2026-10-18T20:3xZ, "use this as approval to merge when green for all merges thru v1.1.0".
tests.ymlon lane 3's prefix branch, under Runs.1b41ce7..9682f0b. q3d is q2g plus this head, so PR 2'spackagejob runs on it.9682f0bwith q3d's tree, as a fast-forward, so the tree under review is the tree that was tested.Lane: openRepoTools-3
🤖 Generated with Claude Code