Skip to content

collect_directions reads order, which is a doc index and not the direction value #83

Description

@wormeyman

The claim, and why it is wrong

tools/trim-factorio-oracle.py:139-151 says this:

def collect_directions(doc_dir):
    """defines.direction is the authoritative answer to 'what number means east'.
    Factorio 2.0 widened this from 8 to 16 values, which silently reinterpreted every
    direction in every blueprint."""
    ...
            return {v["name"]: v["order"] for v in define.get("values", [])}

runtime-api.json does not publish the numeric value of any define. The fixture's
directions table is built from a documentation ordering index, not from the
game's actual numbers.

Verified against the installed 2.1.14 file

Measured directly on
.../Factorio/factorio.app/Contents/doc-html/runtime-api.json, application_version
2.1.14:

  • 0 of 1,408 define values carry a value key. The only keys present on a
    define value are name, order and description. There is no value field
    anywhere in the file.
  • order is always a dense 0..n-1 index. Checked across all 137 define
    tables in the file: every one has orders that are exactly range(len(values)).
    Not one has a gap, a duplicate or a non-zero start.
  • Values are stored alphabetically by name. defines.direction is stored as
    east, eastnortheast, eastsoutheast, ... So order exists to restore
    declaration order for display, which is what a documentation index is for.
  • The HTML docs do not publish values either. doc-html/defines.html contains
    no numeric assignments for defines.inventory or anything else.

So there is no shipped file, JSON or HTML, that answers "what number is east".

Why the fixture is still correct today

Factorio declares directions clockwise starting at north = 0, and there are
exactly 16 of them with no gaps. For an enum like that, declaration order and
runtime value are the same number. The committed fixture holds exactly 0 through
15 with north=0, east=4, south=8, west=12, which is right.

So this is not a live defect in output. Nothing is currently wrong in a
blueprint. It is a wrong method that currently produces a right answer.

Why it is still worth fixing

Because order provably cannot represent a non-sequential enum. It is a dense
0..n-1 index by construction, so any define whose real values have a gap, a
duplicate, or a start other than zero would be read wrong and nothing here would
notice. Directions happen to be the friendly case.

Because the docstring makes a claim the file does not support. It says
defines.direction is "the authoritative answer". The authority is the running
game. What we read is a documentation artifact that agrees with the game by
coincidence of declaration order. Anyone extending collect_directions to a second
define - which is the obvious next step, and something the shared oracle CLI
proposal explicitly wants - would inherit a method that looks proven and is not.

Because of what this constant is. Direction encoding is the exact thing that
silently broke in 2.0, when 8-way widened to 16-way and every blueprint direction
was reinterpreted. #77 exists because of it. The oracle was built so that constant
would never again be taken on trust - and it is the one value in the fixture that
is inferred rather than read.

How to fix it

Read the values from the running game rather than from the docs. A probe mod dumps
them directly:

local out = {}
for name, value in pairs(defines.direction) do out[name] = value end
helpers.write_file("defines-dump.json", helpers.table_to_json(out))

That is the same throwaway-mod technique already used in this repo to establish the
direction table, the mirror field and the Version bit layout - see 975e344 and
the notes in CLAUDE.md. The catch is that the mod was written, run and thrown away,
so there is nothing to re-run. Rebuilding it from the prose in CLAUDE.md is the
work here.

Two smaller changes go with it:

  1. Correct the docstring. Say what the source actually is and what it can and
    cannot answer.
  2. Add a guard while the current method stands. If collect_directions keeps
    reading order, assert that the resulting values are contiguous from zero and
    that the count matches what the planner expects. That turns a silent wrong
    answer into a failed capture for any future define that is not sequential.

Relationship to the shared oracle work

This is the strongest single argument for the probe-mod capability described in
#82, and it stands on its own regardless of whether that tool gets built. Filed
separately so it does not get lost inside a larger issue.

While in this file, CLAUDE.md also says the capture pulls four sources and lists
data/changelog.txt as one of them. It pulls three. There is no changelog handling
anywhere in tools/. Worth correcting in the same pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions