feat(config): T-1281 — canvas-version, and typer's other rich path
All five gates now live in the check domain. canvas-version produces byte-identical output to the original on the live tree. It is the first real consumer of core/process.run. The git calls pass check=False deliberately: a git failure here is not an error to report but a signal that there is nothing to compare, since a fresh clone with no remote is a legitimate state rather than a broken one. The argv-list and missing-binary guards still apply. Its two skips are kept distinct from its pass. NO_BASE and DIFF_FAILED exit 0, as does CLEAN — but only CLEAN means the gate actually looked at something. Collapsing them would hide a gate that had silently stopped running, which for this check in particular is the exact failure it exists to prevent. Found a second rich path while a NameError was rendering as a full-width box-drawn traceback: typer's pretty-exception handler is a different mechanism from rich_markup_mode, and setting one does nothing about the other. Same log pollution T-1259 thought it had closed, arriving through another door and landing in the worst place — a hook log at the moment something has already gone wrong. pretty_exceptions_enable=False now on the root and on every domain built by cli.domain(). test_canvas_version_check.py moves with the code it guards. It had been loading the extensionless script through a SourceFileLoader and reaching canvas_sources by sys.path insert, both only because tooling/ was not importable. Second instance of that debt evaporating on contact. What it asserts is unchanged, which is the point: diff_has_version_bump was kept pure in the port so its six properties still hold without constructing git history. Also restores an import the check router dropped in T-1267 when it moved to cli.domain() — caught by running the command rather than by reading it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,11 +17,13 @@ nothing left to defer. Laziness lives one level up, in `main.py`.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typer
|
||||
|
||||
from tooling.core import cli, console
|
||||
from tooling.core.command import command
|
||||
from tooling.core.errors import ReachError
|
||||
from tooling.domains.check import service
|
||||
from tooling.domains.check.schemas import StampState
|
||||
from tooling.domains.check.schemas import CanvasState, StampState
|
||||
|
||||
app = cli.domain("check", "Consistency gates — the checks the push hook runs.")
|
||||
|
||||
@@ -67,6 +69,63 @@ def client_version() -> None:
|
||||
console.verdict(f"check-client-version: OK — {result.yaml_version}")
|
||||
|
||||
|
||||
@app.command("canvas-version")
|
||||
@command
|
||||
def canvas_version(
|
||||
base: str = typer.Option(
|
||||
service.DEFAULT_BASE, "--base", help="Base ref to compare against."
|
||||
),
|
||||
head: str = typer.Option("HEAD", "--head", help="Head ref to compare."),
|
||||
) -> None:
|
||||
"""Fail if canvas generation changed without project.yaml's version moving."""
|
||||
result = service.canvas_version(base, head)
|
||||
|
||||
if result.state is CanvasState.NO_BASE:
|
||||
console.verdict(
|
||||
f"check-canvas-version: {result.base} not found — skipping (nothing to compare)"
|
||||
)
|
||||
return
|
||||
if result.state is CanvasState.DIFF_FAILED:
|
||||
console.verdict(
|
||||
f"check-canvas-version: could not diff {result.commit_range} — skipping"
|
||||
)
|
||||
return
|
||||
if result.state is CanvasState.CLEAN:
|
||||
console.verdict("check-canvas-version: no canvas-generation changes in range — OK")
|
||||
return
|
||||
if result.state is CanvasState.BUMPED:
|
||||
console.verdict(
|
||||
f"check-canvas-version: OK — {len(result.touched)} canvas-generation "
|
||||
"file(s) changed and project.yaml's version moved with them"
|
||||
)
|
||||
return
|
||||
|
||||
shown = result.touched[:10]
|
||||
remainder = len(result.touched) - len(shown)
|
||||
listing = "".join(f" {path}\n" for path in shown)
|
||||
if remainder:
|
||||
listing += f" ... and {remainder} more\n"
|
||||
|
||||
raise ReachError(
|
||||
"check-canvas-version: canvas generation changed without a version bump\n"
|
||||
"\n"
|
||||
f" Range: {result.commit_range}\n"
|
||||
" Changed canvas-generation files:\n" + listing + "\n"
|
||||
"project.yaml's `version:` is the Atlas disk cache's ONLY invalidation\n"
|
||||
"signal. Without a bump, every warm cache keeps serving canvases built by\n"
|
||||
"the code you just changed — silently, and only on machines that have a\n"
|
||||
"warm cache, so you will not see it on a cold checkout.",
|
||||
fix=(
|
||||
"bump `version:` in project.yaml (scheme 0.{phase}.{n}), note it in the "
|
||||
"comment block above, and mirror the value into client/project.godot's "
|
||||
"config/version. If you are certain the change cannot alter canvas bytes, "
|
||||
"bump it anyway — the cost is one round of cache misses, and this has "
|
||||
"shipped broken five times, most recently T-1239, which took eight days "
|
||||
"to find."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
_STAMP_REMEDY = {
|
||||
StampState.UNSTAMPED: "make regen-db — systems.db carries no stamp to verify",
|
||||
StampState.BAD_VERSION: "make regen-db — the recorded schema_version predates semver",
|
||||
|
||||
Reference in New Issue
Block a user