From 13b565d03f7a548dfab0191a27718592e483c15e Mon Sep 17 00:00:00 2001 From: Mark Schaller Date: Sat, 26 Sep 2026 02:29:58 -0400 Subject: [PATCH 1/2] Make a clean, reproducible build part of done The definition of done was parity of the action graph. Parity is unaffected by whether a TU compiles: the diff compares commands, and the command for a TU that fails compares as well as one that succeeds. So an agent could converge, truthfully report 0 discrepancies, and hand back a workspace where `bazel build //...` fails. Measured in any2bazel-lab: across ten larger projects, the skill-guided migration failed `bazel build //...` on three, and the unguided one on none. On Kodi the agent converged over 1,789 TUs while ten TUs could not compile, reasoning that FFmpeg and two other libraries were missing from the host and that "the parity diff is unaffected". The unguided run in the same environment vendored FFmpeg and SWIG through rules_foreign_cc and built crossguid and libdvdcss from pinned sources. - The "what converged does not cover" list gains the build itself, and the Repeat step says: repeat until converged, then, once, `bazel build //...` from a fresh output base must succeed, and so must `bazel test` over the tests the migration declares, with the files they read declared as data. Any target left out is named and explained. - "Create initial BUILD.bazel files" says a missing host dependency can be vendored (a pinned module or http_archive, or rules_foreign_cc), that a TU left uncompiled for a missing dependency is a gap in the migration, and not to install the dependency into the host instead (make install, /usr/local, /opt), since the build then passes only on the machine that was prepared. - The report includes the clean-build result. In the lab's later runs with this change: - The next Kodi migration built every target from a fresh output base for the first time, by vendoring FFmpeg, SWIG and four smaller libraries. Its ported kodi-test, though, aborted under `bazel test` with its data files undeclared, which is what the test clause addresses. - With the test clause, a later Kodi migration ran kodi-test under `bazel test`, and 1,686 of the 1,689 reference-passing tests passed. That agent had compiled FFmpeg 9 into its container's /usr/local instead of vendoring it, so on a fresh machine with the distribution's FFmpeg 6.1 the tree does not compile. The host-install clause was written after that run and has not yet been tested. Lab-Proposal: P23 Co-Authored-By: Claude Opus 5.5 --- SKILL.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/SKILL.md b/SKILL.md index 8fdaa3b..6c6f9dd 100644 --- a/SKILL.md +++ b/SKILL.md @@ -70,6 +70,12 @@ Bazel aquery jsonproto ──extract_bazel.py───────┘ - **How shared libraries link.** A shared library is compared by its TUs only; its link flags and the libraries it links are not checked (the external-dep check is project-wide). Run a binary that loads each one. + - **That it builds.** A command for a TU that fails to compile compares as + well as one that works. Done also requires `bazel build //...` to succeed + from a fresh output base; name any target you leave out, and why. Every + test target you declare must also pass under `bazel test`, with the files + it reads declared as `data`: a test that passes only when run from the + reference's build directory has not been migrated. ### How targets are matched @@ -270,7 +276,12 @@ versions, read here, why some were hand-written instead, and why a version must be resolved rather than recalled). Put `common --check_direct_dependencies=error` in the generated `.bazelrc` so a declared version that MVS overrides fails the build -instead of being a warning nobody reads. +instead of being a warning nobody reads. A dependency the host lacks can be +vendored (a pinned module or `http_archive`, or `rules_foreign_cc` for a +non-Bazel build); a TU left uncompiled for a missing dependency is a gap in the +migration, not a property of the machine. Don't install it into the host +instead (`make install`, `/usr/local`, `/opt`): the build then passes only on +the machine you prepared, and a clean checkout on a fresh one fails. **Values read from the repository** (`git describe`, a commit hash) are lost silently: a genrule cannot see `.git` from the sandbox, and the binary reports @@ -410,8 +421,10 @@ Kinds specific to a reference build system are listed in its reference guide. If you edited `BUILD.bazel`/`MODULE.bazel`/`.bzl`, re-run from [Extract the Bazel action graph](#extract-bazel-graph) (re-extract the Bazel side); if you only edited `any2bazel.json`, re-run from -[Diff against reference build](#diff). Repeat until `converged: true`. Report -remaining `warn` items and the `excluded` roles. +[Diff against reference build](#diff). Repeat until `converged: true`; then, +once, run `bazel build //...` from a fresh output base: it must succeed, and so +must `bazel test` over the tests you declared. Report remaining `warn` items and +the `excluded` roles. ### (Optional) Diff tests {#diff-tests} @@ -432,7 +445,8 @@ Once production parity is reached, opt into test diffing: ### Report results -Summarize: production targets reconciled, rounds taken, suppressions recorded in +Summarize: production targets reconciled, the clean-build result (and any +target left out, with the reason), rounds taken, suppressions recorded in `any2bazel.json` (with rationale), excluded roles (dashboard/codegen) for human follow-up, and — if `include_tests` was on — test-source parity and any test-binary count gap. From 28fe7fc6fa040b786a7eabc1570af8e6113c23c0 Mon Sep 17 00:00:00 2001 From: Mark Schaller Date: Fri, 16 Oct 2026 01:45:57 -0400 Subject: [PATCH 2/2] Say to check that the project's .gitignore does not hide the migration's files Before reporting, the agent now checks `git status --short --ignored` for files it wrote that the project's .gitignore hides, and renames them or adds an exception. A file git ignores is left out of the migration anyone commits, and nothing in the parity loop or the build notices: both read the working tree. Found in any2bazel-lab: QGIS's `/build*` rule matched an agent's `build_defs/`, dropping from a plain `git add` the ten .bzl and .py files every BUILD file loads. Blender's .gitignore hid an unguided run's `.bazelrc`, YugabyteDB's its four `bazel/thirdparty` files, and GDAL's an agent's `cpl_config.h`. In each case the build passed in the agent's tree and fails from a commit of it. In the lab's six runs with this change, no migration had a file the project's .gitignore hides, and the QGIS agent ran the check and kept its rules out of `/build*`. Lab-Proposal: P27 Co-Authored-By: Claude Opus 5.5 --- SKILL.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/SKILL.md b/SKILL.md index 6c6f9dd..f9c755b 100644 --- a/SKILL.md +++ b/SKILL.md @@ -423,8 +423,12 @@ If you edited `BUILD.bazel`/`MODULE.bazel`/`.bzl`, re-run from side); if you only edited `any2bazel.json`, re-run from [Diff against reference build](#diff). Repeat until `converged: true`; then, once, run `bazel build //...` from a fresh output base: it must succeed, and so -must `bazel test` over the tests you declared. Report remaining `warn` items and -the `excluded` roles. +must `bazel test` over the tests you declared. Then check +`git status --short --ignored` for files you wrote that the project's +`.gitignore` hides (a `/build*` rule also matches `build_defs/`): a file git +ignores is not in the migration anyone commits. Rename it, or add a `!` +exception to `.gitignore`, and say which. Report remaining `warn` items and the +`excluded` roles. ### (Optional) Diff tests {#diff-tests}