Release 2.1.208 (2026-08-27)¶
Features¶
- add composable base + language fragment data and compose() (#2929)
-
add managed-block render/parse/check (#2930) Add the vergil-managed fence markers and the block operations that build on Task 1's compose():
-
MANAGED_BEGIN_PREFIX / MANAGED_END markers
- render_block(lang) -> full fenced block (descriptor is 'base +
' when the language contributes a fragment, else 'base') - parse(text) -> (repo_local_lines, fence_or_None); a malformed (unterminated) fence is treated as absent
- Compliance dataclass and check(text, lang) -> Compliance flagging a missing/mismatched fence and any managed pattern stranded outside it
Task 2 of epic vergil-project/.github#325.
- sync() with bootstrap/update semantics (#2931)
- feat(gitignore): add sync() with bootstrap/update semantics
Add sync(text, lang) -> SyncResult to lib/gitignore.py. Bootstrap (no fence): replace the loose monolith with render_block(lang) and keep only repo-local lines absent from managed_vocabulary(), dropping the language's own managed lines and any foreign-language managed lines; report dropped managed lines in removed. Update (fence present): rewrite the fence to canonical render_block(lang) and trust the parsed repo-local section as-is. Idempotent by construction.
Task 3 of epic vergil-project/.github#325.
- test(gitignore): satisfy formatter and type narrowing for sync tests
Format the sync test additions with ruff and narrow the parsed fence to str before splitlines() in the base-only bootstrap test.
Task 3 of epic vergil-project/.github#325.
- accept fenced form in _check_gitignore (transitional) (#2932) Make the .gitignore audit transitional: a repo passes if it satisfies EITHER the legacy baseline-superset check OR a correct base+language fenced managed block (gitignore.check). Acceptance is gated by a new _GITIGNORE_FENCED_ONLY module flag, kept False here; Task 10 flips it to True to drop legacy acceptance so only a fence passes. The fenced-only failure-reporting branch is implemented now behind the flag.
Repo language is resolved via declared_primary_language (the source the validation stack trusts), normalized to None for any language without a managed fragment or when the config is absent/unreadable, so shell/no-language repos expect a base-only fence.
Task 5 of epic vergil-project/.github#325.
-
add vrg-gitignore-sync applicator CLI (#2933) Add the one-repo applicator CLI (vrg-gitignore-sync) over lib.gitignore's sync/check. It resolves the repo's fence language from [project].primary-language via the same rule as the .gitignore audit (repo_config._gitignore_language, normalizing non-fragment languages and config errors to base-only), then --check (default) reports compliance and exits 1 on drift, while --write syncs the managed block and logs what it dropped. The CLI owns only the file change; the fleet driver (Task 7) shells out to it. Task 4 of epic vergil-project/.github#325.
-
compose repo-init .gitignore through render_block; fence the flagship (#2934) render_gitignore now emits gitignore.render_block(lang) — the composed base + language managed fence — instead of the loose monolith. Callers pass the repo's resolved fragment language (primary-language normalized to a fragment or None, the same rule the audit uses).
Convert vergil-tooling's own .gitignore to the fenced form (first repo converted, dogfood): the managed block equals render_block(python) and the repo-local extras section is preserved outside the fence.
Update the monolith-coupled tests to the fenced form: TestRenderGitignore re-points at the composed fence and adds a flagship drift guard; test_baseline_has_required_patterns re-expressed against compose()/managed_vocabulary().
Task 6 of epic vergil-project/.github#325. Needs Task 5's transitional audit (merged). No monolith deletion (Task 10).
- add generic fleet-sweep driver + vrg-fleet-sync (#2935)
Add lib/fleet_sweep.py: the generic per-repo work-chain driver (Applicator/SweepSpec/RepoResult + run_sweep). Per repo it creates a detached probe worktree, runs the applicator, and only when the change is real mints a tracking issue, names the feature/
- branch, commits, and hands off via vrg-pr-workflow report-ready; an unchanged repo is skipped with no issue or branch, and one repo's failure is isolated so the sweep continues. dry-run reports intended actions touching no git/gh state.
Add bin/vrg_fleet_sync.py wiring the gitignore applicator (shells out to vrg-gitignore-sync --write) as the sole consumer of the seam; a general change-script CLI is follow-on #328. The driver never runs vrg-submit-pr or merges.
CI Evidence: All gates passed — full audit bundle available. Download →