Skip to content

Read factorio-data at a tag, without ever moving its HEAD (step 7) - #10

Merged
wormeyman merged 17 commits into
mainfrom
refs
Aug 18, 2026
Merged

Read factorio-data at a tag, without ever moving its HEAD (step 7)#10
wormeyman merged 17 commits into
mainfrom
refs

Conversation

@wormeyman

Copy link
Copy Markdown
Contributor

Build-order step 7. Adds a refs subcommand so the four consumer repos can read
Factorio's shipped Lua and its Lua API docs at any version.

Why

~/GitHub/factorio-data is one clone with one working tree, and at least three
repos read it at different versions. It sits on master right now, not detached
at a tag, so FactorioMapWebUI's refs:sync --check reports "in sync" only
because master happens to equal the newest tag. That is a coincidence, and a
git checkout there breaks whatever else is reading it, silently.

So this reads at a tag and never moves HEAD. tests/refs.rs records the
clone's branch, commit and status before a real run and asserts all three are
unchanged after.

What it does

factorio-oracle refs show 2.0.77 base/info.json
factorio-oracle refs grep support_range --tag 2.0.73 --tag 2.1.12
cd "$(factorio-oracle refs worktree 2.0.77)"
factorio-oracle refs docs 2.1.14 runtime-api.json --which
factorio-oracle refs sync 2.0.73 --check

The multi-tag verdict is the part that earns the command. This is
factorio-blueprint-editor's hand-written versionCaveat sentence, checked:

2.0.73  elevated-rails/prototypes/entity/elevated-rails.lua:309:    support_range = 11,
2.1.12  elevated-rails/prototypes/entity/elevated-rails.lua:309:    support_range = 11,

identical across 2.0.73 and 2.1.12

Three places measurement overruled the design

No archive cache, and no zip dependency. The installed game ships its whole
docs tree, and ships the published archive too: doc-html/static/archive.zip is
byte-identical to the one at lua-api.factorio.com, same 45,547,463 bytes and
same sha256. For a version you have installed there is nothing to download. For
one you do not, single files are published, and the archive never wins on bytes
even in the worst case - fetching all 1,613 HTML pages costs about 17 MB against
43 MB for the archive. The accepted cost is that you cannot search a version
nobody has installed, and that limit is stated in the code, the README and
CLAUDE.md rather than hidden.

sync reports availability, not pinned state. Since nothing checks anything
out, there is no working tree to pin, so there is no lock file to go stale.
--check never fetches and never writes.

refs grep takes several tags and says whether the answer moved between
them, because that is the question the consumer repos answer by hand today.

Reviewing this

Ten corrections came out of building it, and they are recorded in the plan at
FactorioTools/docs/superpowers/plans/2026-08-17-factorio-oracle-refs.md. Half
the commit subjects here name a defect found in review rather than a feature.

Six of the ten were one defect class: a value reaching a Path::join or a
command argument, guarded where it looked dangerous and left unguarded one
argument over. Each was caught in isolation. The whole-branch review found a
seventh only because it was asked to enumerate every such value as a set rather
than per call site. The lesson, if you read one thing: a guard is a property of
a value, not of a call site.

Nine tests were found vacuous - passing for reasons unrelated to their
names. The most effective method was mutation rather than reading: one pass
broke ok() and watched all 14 tests stay green. Reading finds a test that
asserts nothing; only mutation finds a test that asserts the wrong thing.

One known limit, documented rather than fixed

install::read_version runs a raw Command with no timeout, the only
subprocess in the crate not behind the Spawner trait. So a hung binary hangs
any command that selects an install, and refs sync --check does launch the
game binary despite being documented "never fetches, never writes". That is
pre-existing code which installs list, run and provenance report already
reach, so fixing it earns its own branch.

Also here

provenance report's NewerThanBinary arm now has a real gated test. It needs
a Factorio older than the fixtures, which used to mean a machine kept free of a
Rust toolchain, so it had only ever been unit-tested. A full 2.0.77 now sits in
the repo, gitignored and outside every discovery root, so the arm runs for real.
Its control step points the same test at 2.1.14 and requires it to fail.

Checks

260 tests pass, up from 167: 247 unit and 13 integration. cargo fmt --check
and clippy -D warnings are clean. The install-gated and clone-gated tests ran
rather than skipping. No new dependency; the crate still holds at five.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QDh77pcfxE3Y65CrcKgtvi

wormeyman and others added 17 commits August 17, 2026 20:36
…oundary

Fix round 1 review findings on refs grep:
- Two tags that both matched nothing now read as NothingMatched, not
  Identical - absence agreeing with absence is not a measurement.
- render's verdict match names every variant instead of falling through
  a wildcard, so a future variant fails to compile silently.
- search and show validate every tag with valid_tag before calling git,
  since both are pub and grep_args places a tag as a bare positional.
- one_tag_renders_without_a_tag_column now asserts the whole rendered
  string instead of three contains checks that could not fail.
Standing::NewerThanBinary fired only in unit tests until now, because it
needs a Factorio older than the 2.1.14 fixtures and the only one used to
live on a machine kept free of a Rust toolchain. A full 2.0.77 now sits
in installs/, so a_binary_older_than_the_fixtures_reports_them_as_newer
exercises the arm for real when FACTORIO_ORACLE_OLD_FACTORIO points at
it, and skips everywhere else.

.gitignore rides along because the /installs/ rule and this test arrived
for the same reason: the rule is what lets the 5.1 GB bundle sit in the
tree without git descending into it, and this test is the only thing
that reads it.
…ct docs

Whole-branch review fix wave, covering every finding at once.

Important:
- worktree::ensure and worktree::remove were the seventh unguarded
  path/argv boundary this branch produced. Both now reject an invalid
  tag with anyhow::ensure! as their first line, before git is ever
  reached, matching grep::search, grep::show and docs::fetch. Fixes
  worktree_path's doc comment, which had stated the opposite - that
  callers already validated - and adds a RED-then-GREEN test for each
  function proving rejection happens before the fake spawner is called.
- sync::docs_standing reported Cached for a version with zero docs
  files on disk, because docs::fetch creates a nested file's parent
  directory before curl runs, and a failed fetch leaves that empty
  subdirectory behind. Walks into subdirectories for an actual file now,
  with a RED-then-GREEN test for the nested-empty-directory case.
- CLAUDE.md's test counts were wrong: measured 247 unit tests (not 244,
  after the 3 tests this wave added) and 13 integration tests (not 12),
  including a third tests/provenance.rs test the paragraph never
  mentioned. Names both FACTORIO_ORACLE_PROVENANCE_DIR and
  FACTORIO_ORACLE_OLD_FACTORIO and what each points at.
- Documented, rather than fixed, that install::read_version has no
  timeout and is the one subprocess not behind Spawner, so refs sync
  --check still launches the game binary despite being "report only."
  Also notes that no test exercises src/main.rs, which is why the
  worktree gap went unnoticed this long.

Minors: worktree --remove now says whether it removed anything; the
sync arm's bad-version message and guard style now match its siblings;
the 267,489,280-byte uncompressed-HTML figure is labelled as such in
both CLAUDE.md and docs.rs; "two worktrees at one tag coexist" restores
the dropped noun; --which's help text says it still fetches on a miss.

Verified after: cargo fmt --all -- --check, cargo clippy --all-targets
-- -D warnings, and cargo test --all-targets all pass (260 tests). The
shared ~/GitHub/factorio-data clone is unchanged: still on master, a
clean working tree, and exactly one worktree entry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QDh77pcfxE3Y65CrcKgtvi
@wormeyman
wormeyman merged commit 6a6ddce into main Aug 18, 2026
1 check passed
@wormeyman
wormeyman deleted the refs branch August 18, 2026 06:17
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