Repository navigation
Meta linter in typed python; pyright gate (#220 stage 2, #256) - #258
Merged
Merged
Conversation
lint_unity_meta.py is the implementation; lint-unity-meta.ps1 becomes a delegator so the pre-commit hook and the Unity Meta Lint workflow keep their command. The port adds the meta linter's first test suite (19 red-green cases over the three rule classes, the folder-asset rule, the Unity-ignoration exemptions, and the CLI surface); the old ps1 and the port print identical reports on this repo (1403 paths checked).
pyright 1.1.414 (basic mode) type-checks the two typed-python linters and their suites. The pin lives in pyproject.toml's non-default typing group, so plain uv run - every delegator's path - never installs it; the CI step requests it and caches uv's packages keyed on the manifest. Two linters now live in python, the gate #256 asked for is landed. Also pins the interpreter the Unity Meta Lint workflow runs on and widens the llm lint trigger to tooling~/**/*.py so the gate sees every python edit.
The review caught two undisclosed rule divergences in the port: the ps1's -match family was case-insensitive (the port now keeps that with re.IGNORECASE - a GUID:/folderAsset: YES meta parses like the ps1) and .NET's ReadAllLines replaced invalid bytes instead of throwing (the port now decodes with errors=replace, so a stray latin-1 byte cannot move a file into the guid bucket). Verified old-ps1 vs port on fixtures for both. The suite gains the BOM/CRLF, non-UTF-8, non-ASCII path, and middle-segment pins and asserts exit 0 on the passing folder-asset branches. The report stream seam is typed (a Stream protocol) in both linters, sweeping stage 1's getattr, and the ps1 docstrings claim python 3.11+ (the manifest floor) instead of 3.9+. The Unity Meta Lint workflow runs both OS legs so the delegator's Windows wiring is enforced in CI. Also rewrites the preflight lane test whose fixed 300ms overlap window failed on a loaded windows runner (spawn lag past the window while the checks really overlapped): the lead check now polls up to 5s for the follower's start, and a serialized run still fails the pin.
Round-2 review: str.splitlines also split \x0b-\x1e and the U+2028/2029 family, so a folderAsset line holding a vertical tab read as two lines and the port passed where the ps1 errored. The split is now exactly .NET's CR/LF/CRLF set and both of the review's fixtures agree with the old ps1. Two deltas stay and are stated in the module docstring with their direction: python's Unicode casefold (a 'guıd:' key parses where the invariant culture did not) and python's \s matching \x1c-\x1f. git_tracked_paths also maps a missing repo root or missing git to the ps1's controlled failure message (was a raw traceback), with a test.
Round-3 review: .NET's ReadAllLines BOM-sniffed UTF-16/32, which the port does not - the docstring now names that as a third read limit instead of claiming full decode parity; a UTF-16 meta fails closed as an unparsable guid. And a tracked filename whose bytes are not UTF-8 printed surrogates that crashed the report with a UnicodeEncodeError traceback after its first line: the CLI now reconfigures the console streams to backslashreplace, so the report survives the way the ps1's lossy print did, pinned by a git-backed CLI test.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 02e76ca. Configure here.
os.fsdecode is strict UTF-8 on Windows (PEP 529), so the fixture raise before the CLI ran and the windows llm-lint leg went red. A byte-invalid tracked name cannot exist on an NTFS checkout anyway: the pinned console behavior is the POSIX checkout's, and the test says so.
The mergeWrite marker was one file both children rewrote, so a follower write landing between the lead's read and write could erase the sawSibling record the assert reads (found adjudicating the Bugbot finding round 5 carried). Each child now owns its marker file: no read-modify-write, no lost update; the mutation check still fails a serialized run. Children that crash fail the assert with their output instead of costing a silent 5s poll, and the markers are absolute so nothing leaks into the repo root (the first draft leaked one). The BOM fixture's re-write dropped the BOM it existed to pin (the utf-8 write-back stripped it); the bytes are now written once with utf-8-sig and the fixture asserts the BOM is really there.
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.

DISCLOSURE: LLM-GENERATED TEXT
Why:
The meta linter was the last Unity-free gate still on PowerShell and the only one with no test suite; landing it in python brings the typed-python surface to two linters, which is the trigger #256 set for the typing gate.
What:
typinggroup, souv run- every delegator's path - never installs it, and CI requests it explicitly with uv's package cache keyed on the manifest.tooling~/**/*.pyso the gate sees every python edit.How we know:
The old ps1 and the port print identical reports on this repo (1407 paths checked, sorted-diff empty) and agree on adversarial fixtures (uppercase keys, exotic separators, invalid bytes); both python suites green (24 + 9) under uv; pyright 0 errors; preflight 19/19. Three adversarial review rounds drove the parity fixes (re.IGNORECASE, errors=replace, the ReadAllLines split), the decode hardening, and the flake rewrite.
Closes #256. Part of #220 (stage 2).
Note
Low Risk
Changes are confined to tooling scripts, CI, and docs; linter behavior is parity-tested against the former PowerShell implementation with no runtime or auth impact.
Overview
Ports the Unity
.metahygiene linter from PowerShell to typed Python (lint_unity_meta.py, issue #220 stage 2).lint-unity-meta.ps1is now a thin uv/python delegator so pre-commit and CI keep the same entry points;test_lint_unity_meta.py(plustest-lint-unity-meta.ps1) adds the first contract tests and runs in the LLM instructions workflow.Adds the #256 typing gate: pinned pyright in a non-default
typingdependency group,pyrightconfig.json, and a Linux-only CI step (uv run --group typing pyright) with uv cache; workflow path filters widen totooling~/**/*.py. The Unity Meta Lint job mirrors the LLM job (Python 3.12, uv) and runs on ubuntu + windows.lint_skill_sizes.pygains aStreamprotocol for cleaner annotations. Docs (context.md, create-unity-meta skill, pre-commit description) name the Python implementation and pyright gate. Preflight’s concurrent-check test drops a flaky 300ms window for a 5s sibling-start poll with per-child marker files.Reviewed by Cursor Bugbot for commit 832297e. Bugbot is set up for automated code reviews on this repo. Configure here.