Skip to content

autosetup: pick the build system and the artifact directory from artifacts on disk - #169

Draft
shellygr wants to merge 2 commits into
masterfrom
shelly/build-system-artifact-pick
Draft

autosetup: pick the build system and the artifact directory from artifacts on disk#169
shellygr wants to merge 2 commits into
masterfrom
shelly/build-system-artifact-pick

Conversation

@shellygr

Copy link
Copy Markdown
Contributor

Draft — the tie-break half needs a paired builder change before it earns its keep; see What this
actually fixes today
.

Two defects, both surfacing as "no contracts"

A. The Foundry/Hardhat tie is broken by config order, not by evidence. When a directory holds both
a foundry.toml and a Hardhat config, detection always answered Foundry and logged
Both Foundry and Hardhat detected, defaulting to Foundry. If Hardhat is what built the tree, its
output is under artifacts/ while out/ is empty or absent, so the extractor reads nothing and the
run dies with No project-local logic contracts found in FoundryManager build output — 12 contract
rows across 6 projects in the last corpus sweep. Detection now prefers the build system whose artifact
directory actually holds artifacts. Foundry keeps the tie when it has artifacts of its own and when
neither side has any (an unbuilt tree offers nothing to rank by), and --build-system still wins
outright.

B. A configured artifact directory was ignored when the default name existed as a parent. The
extractor tested out/ for existence, so a project with out = "out/foundry" found the (empty)
parent and reported that the build produced nothing. It now takes the default only while it holds
artifacts, else the directory the config names.

Evidence is one predicate per build system — holds_artifacts — and all of it requires a file, not
a directory: a *.sol/ dir for Foundry, a *.json under contracts/or build-info/ for Hardhat, a
flat *.json for Truffle. A configured-but-never-run build leaves the directories behind, so
directory existence is not evidence that a build happened.

What this actually fixes today

Measured in the fleet image against the real clones:

  • B fixes 2 of the 12 rows (reconcopy-mitosis: rc=1 No project-local logic contracts
    rc=0, 39 contracts found in out/foundry).
  • A fixes 0 of them by itself — in all six projects Foundry does have artifacts, because the
    builder only ever runs forge build there, so Hardhat never gets a chance to leave any. A is the
    precondition for fixing that on the builder side; on its own it changes no corpus project's answer
    (measured across all 314 clones: 87 hold both configs, 0 flip).
  • One project (sales-compound-multiplier) fails for an unrelated reason — its node_modules/ is
    empty, so forge build produced a single interface with no bytecode. No detection change can
    recover that.

Known limits, deliberately not fixed here

  • The tie-break reads Foundry's out from [profile.default], so a tree built under a non-default
    FOUNDRY_PROFILE with a different out reads as having no artifacts. Documented in the docstring.
  • A Hardhat project whose foundry.toml governs a forge test harness looks like Foundry the moment
    that harness is compiled. Also documented.
  • find_build_config_dir still ranks Foundry first for a directory holding both configs, so it can
    disagree with detect() on a monorepo package that only Hardhat built. Worth closing, separately.

Tests

tests/test_build_system_choice.py — 15 cases: every single-build-system path unchanged (built and
unbuilt), both-configs-with-Foundry-artifacts unchanged, both-unbuilt unchanged, the tie-break itself,
empty artifact directories rejected on both sides, evidence read from a configured out,
--build-system still authoritative, plus the extractor's resolution and error-message cases.

pytest -m "not expensive": 759 passed, 9 skipped. pyright: 0 errors.

shellygr and others added 2 commits August 16, 2026 21:24
A project shipping both a foundry.toml and a Hardhat config gave no say to which
one built the tree: detection always answered Foundry, so a Hardhat project whose
foundry.toml only governs a forge test harness had its empty out/ read and yielded
no contracts. Detection now breaks that tie on the artifacts present, with Foundry
keeping it whenever it has artifacts of its own and when neither side has any.

The extractor had the same shape of problem one level down: it read the build
system's default artifact directory whenever that directory existed, so a project
configuring out = "out/foundry" had its bare out/ read — a directory that exists
only as the parent of the real one. The default now counts only while it holds
artifacts, and the config's own answer decides otherwise.

Both rules ask the same question, "does this directory hold artifacts", which each
manager answers from its own layout, and the per-build-system artifact directory
helpers in project_dir are now shared with the detector instead of copied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Hardhat's evidence test accepted a bare `artifacts/contracts` or `artifacts/build-info`
directory, which a configured-but-never-run build also leaves behind, while Foundry and
Truffle both require a file. That asymmetry could hand the tie to Hardhat for a tree only
Foundry had built.

The unreadable-artifacts error now names the directory the config declares rather than the
build system's default, and distinguishes a path that is absent from one that is present
but not a directory.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant