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
2 changes: 1 addition & 1 deletion docs/host-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This section is the **contract**: which tools a host needs and which repo proced
| Python 3 | `scripts/` and `spec/` (standard library only, no packages to install) | `python3 --version`, or `py -3 --version` on native Windows | **3.13**, target |
| `jq` | the ruleset normalizer in `repo-config/configure.sh`, the ruleset diff in [`AUDIT.md`][audit] section 6, and payload regeneration | `jq --version` | **1.7**, target |
| `docker` | the four linters, which run as pinned images rather than local installs | `docker --version` | none |
| `uv` / `uvx` | coverage runs, and the Python toolchain (`ruff`, `pyright` or `mypy`) in a Python repo | `uv --version` | none |
| `uv` / `uvx` | coverage runs, and the Python toolchain (`ruff`, `pyright` or `mypy`) in a Python repo | `uv --version` | **0.12.2**, target |

The **Floor** column exists because presence and sufficiency are different questions and the answer to the first was being read as the answer to the second. A tool below its floor still answers `--version`, so every other column reports it as fine while `scripts/host_gate.py` fails it. The kind is named beside the number, since a **measured** floor sits above a version known to break a documented procedure and gives a failing host a defect to point at, where a **target** floor names the version the repo's toolchain is configured for and does not. The next section carries the reasoning behind each one.

Expand Down
6 changes: 4 additions & 2 deletions scripts/test_host_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ def test_the_declared_floors_are_the_ones_with_a_stated_reason(self):
one in the data, which is what caught the python3 floor being added without this line.
"""
floors = {t['name'] for t in self.data['tools'] if t['minimum'] is not None}
self.assertEqual(floors, {'gh', 'git-restore-mtime', 'jq', 'python3'})
self.assertEqual(floors, {'gh', 'git-restore-mtime', 'jq', 'python3', 'uv'})

def test_the_contract_table_carries_every_declared_floor(self):
"""docs/host-setup.md restates the floors, so the doc goes stale the moment the data moves.
Expand Down Expand Up @@ -691,7 +691,9 @@ def norm(text):
floor_col = [c.lower() for c in cells].index('floor')
continue
if cells:
rows[norm(cells[0])] = cells
# A compound cell like `uv` / `uvx` names two tools, so each names the row.
for token in cells[0].split('/'):
rows[norm(token)] = cells
self.assertIsNotNone(floor_col, 'docs/host-setup.md has no contract table with a Floor column')
for t in self.data['tools']:
# An optional tool is deliberately outside the table, which lists what a host must provide.
Expand Down
14 changes: 12 additions & 2 deletions spec/host-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,18 @@
"required": true,
"probes": [["uv", "--version"]],
"pattern": "uv (\\d+(?:\\.\\d+)*)",
"minimum": null,
"why": "Used for coverage runs and the Python toolchain in a Python repository, where the pinned tool versions live in that repository rather than in uv itself. No floor has been measured here."
"minimum": "0.12.2",
"why": "Used for coverage runs and the Python toolchain in a Python repository, where the pinned tool versions live in that repository rather than in uv itself, so no uv feature is what a floor here would guard. The floor is a target rather than a measured breakage, and it says so rather than implying a defect nobody found. It is anchored to what two independently set-up hosts already carry rather than to a version anyone has verified good, the same reasoning jq's floor uses. A winget install on Windows carried 0.12.2 while winget already offered 0.12.4, so the winget package can lag upstream by a release, and host-setup/linux/install-tools.sh, which fetches upstream's latest release directly rather than a distribution package, carried 0.12.4 on a separate Linux host. The floor sits at the lower of the two, so a host on either managed install path already clears it, and a host below it is unverified rather than known broken.",
"source": {
"linux": "The upstream release archive at https://github.com/astral-sh/uv, which host-setup/linux/install-tools.sh fetches directly, and no distribution packages it.",
"macos": "Homebrew, which tracks upstream releases.",
"windows": "winget (astral-sh.uv), which can lag upstream by a release rather than tracking it release for release."
},
"remedy": {
"linux": "host-setup/linux/install-tools.sh --upgrade uv",
"macos": "brew upgrade uv",
"windows": "host-setup/windows/install-tools.ps1 -Upgrade uv"
}
}
]
}