docs: restructure the wiki along Diátaxis
Seven pages carried all four modes at once. Anvil-Chunk-Loader opened with
status, ran through usage, architecture, a comparison, measured tables and
error handling in one file; Light-Engine, Benchmarking, Installation,
Instances-And-Chunks and World-Migration had the same shape. Every paragraph
was correct and no reader was ever in all four states at once.
The four quadrants are now separate pages, encoded in the title because that
is the only structure a wiki preserves: 1 tutorial, 10 how-tos, 9 reference
pages, 15 explanation pages. Project-Status and the Research pages stay
outside the four on purpose — they are the operational record, not
documentation of the software — and so does the build documentation.
Three things the split fixed rather than moved:
- There was no tutorial anywhere. Tutorial-Load-your-first-world-with-Falco
is the one guided path: empty Gradle project to a served world with light,
one path, no alternatives.
- Reference existed only as prose embedded in explanation. The nine pages now
carry generator banners naming the source in the code repository, so the
next step is a generator and a CI drift gate rather than proofreading.
Reference-Exceptions-and-faults says outright that it is incomplete: the
two Reason enums declare eleven constants and the wiki ever recorded two.
- The measured tables were published twice. The four charts lived only in
Benchmarking, their tables only in Measured-Results, and _Footer.md carried
a rule about which source wins — the symptom, not the cure. The charts now
sit with their tables on Reference-Measured-results and the duplicate block
is gone; every figure in it was verified present first. Same for the
reproduction command lines, which stood in two pages.
Prose was moved, not rewritten. What is not carried over is the intros and
tables of contents of the dissolved pages, and the duplicated headline
block. All 195 cross-page links, their anchors and their link texts were
rewritten to the new titles; nothing dangles.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs: the migration module, and the counts that had drifted
falco-migration arrived with #48 and #50 and had no page at all — it did not
appear anywhere in this wiki. World Migration is that page: the three modes,
the backup that cannot be switched off, why migration runs before the version
guard, and where the rules' version numbers come from.
Project Status: item 1 of Open resolved by #49, items 2 and 3 renumbered. The
entry is kept in full down to "What was built", the way the #34 entry is,
because its reproduction is what made the defect actionable — and because the
first attempt at fixing it answered too broadly and broke two tests that
assert versionPolicy(null) means the check does not run. That is recorded
rather than tidied away.
The counts in that page had drifted further than the migration module alone.
"What is in the branch" said 14 types for falco-anvil where the tree has 26,
3 for falco-instance where it has 16, and carried no row for falco-migration
or falco-archunit; "Where things live" listed types that predate several
merged pull requests. Every column is now re-derived at cbd74ccb from one
tree and one test run, which the previous table could not claim: its
executed-test counts came from a build whose commit was not recorded, and its
falco-demo cell carried no number because nothing reproduced it.
Architecture Rules said 39 rules in five classes; there are 48 in seven.
ForeignWritePathTest and MigrationBoundaryTest were missing entirely.
Both pages now state the same thing plainly: falco-migration sits outside
ModuleBoundaryTest's PUBLISHED set because it legitimately depends on
falco-anvil, and the other rules of that class therefore do not reach it. A
gap, not a decision.
Installation and Publishing carried three modules at 1.0.0; there are four at
2.1.0, and five artefacts with the BOM.
Anvil Chunk Loader: ChunkMigrator as the third service of that shape, the
truncated-chunk refusal from #49 under the version floor, and one sentence
that #50 made false — "nothing is converted or migrated" — corrected rather
than left standing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jtJ4GUtmyCSHkiGY1CvgR
docs(status): the half of the air hole that #45 did not close
#45 named three decisions that combined to load a pre-21w43a world as air. It closed the first two
and left the third: NbtReads.optionalList still returns an empty list for a missing key, and
decodeSections still reads sections through it. A chunk with Status full and neither sections nor
Level therefore still reaches the caller as air - reproduced during the review, not argued, with
chunksLoaded at 1 and errors at 0.
Entered as item 1 because the list is ordered by consequence: it is a different defect from the one
#45 fixed, but it shares the failure mode that makes both consequential - the caller is handed a
chunk that looks generated. Two smaller items from the same review follow under Smaller items: the
unverified span between DataVersion 2844 and 2860, and the "-1" label a mistyped DataVersion gets in
the diagnostics breakdown.
The cross-reference "item 2 of this list records" was pointing at an entry that had already been
resolved and removed, so renumbering could not fix it. Replaced with the page that actually carries
the two rows.
Bring the instance and chunk pages level with what shipped on 2026-08-03
falco-instance gained its own chunk storage, a facade split, a shared instance
and a lighting chunk that finally sits on the same class as the rest. The wiki
described the state before all four, and in three places it now said the
opposite of the code.
Corrected, each read against the source first:
- Project Status listed "FalcoInstance and FalcoLightingChunk are mutually
exclusive" under things that cannot be used together. That was the limitation
the whole rewrite existed to remove; FalcoLightingChunk extends FalcoChunk now
and the two run together. The section says what it was, what closed it, and
what it cost -- the class is final, which is a deliberate break of binary
compatibility recorded in gradle/api-breaks.properties.
- Rationale: Instances and Chunks explained "why the superclass is DynamicChunk"
and stated that FalcoChunk adds no storage because Minestom's was never the
part that needed replacing. Both were true of the first version. The section
now says what changed the answer, which was a measurement rather than an
opinion.
- Research: Shared Instances asserted FalcoChunk extends DynamicChunk in the
present tense and named two ways out of the batch light gap. It closed by
neither of them, and the paragraph says so.
- Four places across three pages said there is no instance benchmark in the
repository at all, one of them quoting the build file as proof. The build file
declares jmhImplementation(project(":falco-instance")) since 2026-08-03 and
four JMH classes exist. None has been run as a baseline, so the conclusion
those passages drew is unchanged and each now says which half is missing: the
instrument is there, the run is not.
New: a "Counted" section on Measured Results, kept apart from the timings
deliberately. Object counts have no spread and are unaffected by what else the
machine was doing, so they are the only figures on that page that survive being
taken on a busy machine -- 25 objects and 840 bytes against 192 and 6 848, the
62.24 % empty-section census, the materialisation counts per operation, and the
palette break-even. No timing figure was added anywhere, because the instance
suite has still never run.
Two open items added to Project Status: the unlocked tick map, which is
inherited from DynamicChunk rather than introduced, and the macOS hang that
leaves the counted figures proven on two platforms out of three.
Both page headers that claimed their page carries no measurement were corrected
too -- adding a number and leaving that sentence standing is how a page starts
lying about itself.
docs: split the three changes apart, and name the case that got slower
A third run separates them. The first attempt at it was discarded rather
than quoted: it degraded partway through, and what caught that was the
same job measuring minestomFull, a class no commit here touches, at
+64.8 %. The re-run holds that control inside 1 %.
The reordering and the arrival-direction skip carry the section
propagator on their own. The flat column adds nothing there, which is the
expected answer for a change that lives in the other class, and it is
worth recording as a control whose correct result was zero.
On the chunk propagator the flat column adds a further -8 to -15 % on top
of the two free changes, so its buffer is paid for. Except on the sky
pass at four sections, where it costs +11 to +18 %. The earlier pair made
that look like noise; on a clean run both configurations agree and the
tighter one reads +11.4 %.
It is kept for a reason that is arithmetic, not tolerance: +22 us at four
sections against -733 us at twenty-four, and a real overworld chunk is
twenty-four. The entry says so, and says what the targeted fix would be,
so the decision can be revisited by someone who has four-section columns
rather than rediscovered.
docs: the first rebuild figures this suite has actually measured
Three of the entries under Smaller items came from the standalone rebuild
and said so: directions rather than factors, no intervals, none of them
measured here. #36 built all three and they are now measured, with
intervals, on every configuration of two benchmark classes.
The rebuild said -26 % on searching a column. Measured: -27.3 % to
-39.7 % on the chunk propagator and -7.3 % to -22.0 % on the section one.
The direction held and the magnitude was understated, which is worth
recording as plainly as a miss would have been.
Two things are left open rather than rounded off. The split between the
two commits is not established: the run meant to separate them degraded
partway through, and the only reason that is known is that the same job
measured minestomFull, which neither commit touches and which read
+64.8 % there. And propagateSky at four sections shows no clear win in
either direction, which is exactly where the flat column should be
weakest, so it is named instead of averaged into the range.
docs: follow the javadoc corrections through five pages
#37 fixed two javadoc claims. The wiki had documented both as defects, so
fixing them made five sentences here wrong — the fifth time in this round that
a correct change invalidated prose standing beside it, and the first time the
change was one of ours.
Project Status counted three overrides where the table itself went on to name
four; it says five now, and what the last two actually do.
Two TODOs are resolved and removed. The one on Measured Results is replaced
rather than deleted, because the correction surfaced something nobody has
measured: within a trial the chunks are not rebuilt and both methods write
light into them, so every iteration after the first re-lights already lit
chunks. Level.Iteration would settle it and would leave the configuration that
table was measured under, which makes it a decision rather than a fix.
Benchmarking and Rationale: Measurement described the javadoc as claiming a
rebuild that does not exist. It no longer claims it. Both keep the substance —
the conclusion survives because a fourfold to sixfold gap is far outside what
repeated lighting could produce — and now say the third digit is untested
instead of implying the mechanism was the only problem.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzEdy5fN5JKGxJo8gwtNeu
docs: record what #34 built, and a summed row whose assumption expired
The first entry of Open is resolved. It is the one that was closed by
building what it proposed, and it departed from the proposal in one way
worth keeping: the invalidation is per chunk, not per section. Rebuilding
a single section still means reading that section's block states, and the
reading is what a table costs, so a per-section bound would have bought a
fraction of a rebuild for the price of a second index.
The entry keeps its measurement. That table is still exactly what the
recalculating path pays, because compute() keeps nothing by contract and
was not touched. What is added is the count — a steady 3x3 tick built 50
table sets and now builds 1 — and the workflow run behind the timing,
with the note that its two halves ran on different CPU models and that
full() is the control which makes them readable at all.
Two published tables carried figures the change moved. Both now name the
commit they belong to rather than being overwritten: the numbers are
right for the run they describe, and the runs measured after the change
were taken on shared runners and replace no absolute figure here.
One of them is worth more than a correction. The "one tick pays for both
kinds" row is a sum, and the page had written down the assumption behind
it: that such a pass shares no work between the two kinds. #34 made that
false, because an opacity table is not a kind of light and the sky pass
now reuses what the block pass built. The row is an upper bound now, and
it could only be found to have expired because the assumption was stated
instead of left implicit.
Items 2 and 3 are renumbered to 1 and 2, and the two cross-references
into them are pulled along.
docs: record what #28 moved, and repeat the opacity measurement
Four pages carried 31.41 µs for the propagate stage as if it were current.
It is the after-value of one commit, 69381af, and #28 has since taken the
same stage under the same parameters to 27.3 µs — measured, but written
down nowhere. Each of the four now says which commit its figures belong to.
The opacity share in Project-Status was a single three-fork run. A second
one under the same configuration gives 21.8 / 20.2 / 17.0 % against
19.4 / 20.4 / 15.7 %. The range it establishes is the same, and the repeat
lands on the caveat the page already carried: area 16 moved again, and it
is again the widest interval. Neither run was taken on an idle machine and
the page now says so, which is the part the first provenance line omitted.
One sentence in Project-Status is also corrected rather than extended: the
gap between propagate and the per-section table narrowed, from 3.9x to
3.4x. It does not change the ranking that entry exists to correct.
docs: measure the compression level, and find that neither half was one number
Four TODOs across four pages waited on one run of compressFalcoLevel against
compressMinestomLevel. It has been done at two forks over all five
distinctStates levels, and the answer is that the question was wrong: the
trade has no single value on either side.
Time runs from unresolvable at one distinct state — the intervals overlap
there — to 2.96× at 1024. Size runs from 0.08 % to 40.66 % over the same
sweep. They move together, so the cheap size and the flattering factor are
never the same measurement, and "1.83× faster for about 3 % more bytes" was
never one.
Two of the three competing factors survive. 2.4× at 256 distinct states falls
inside the measured bounds 2.07×-2.53×, and 3.1× at 1024 inside 2.74×-3.20×:
they were readings that had lost their conditions, not contradictions. 1.83×,
the one quoted with no distinctStates attached, falls inside no row's bounds
and has been dropped.
The size figures need no interval and get none. Deflate output length at a
fixed level over fixed input is deterministic, so the table states byte counts
rather than estimates. It runs the benchmark's own setup to compress the same
payload, rather than rebuilding a chunk that would silently be a different
measurement.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzEdy5fN5JKGxJo8gwtNeu
docs: three entries leave the open list, and the fourth loses its ranking
The exception hierarchy (#21), the stale-read item (#23) and the missing ring
diagonals (#24) are done. What they have in common is in the section header
now, because it is worth more than the three results: none was closed by
building what the entry proposed. One needed a decision, one needed a sentence
in the javadoc, and only the third was a defect.
The opacity tables stay, reworded. The entry called them "the largest
remaining cost block by a wide margin", which was written before 69381af took
the per-section table from 31.33 to 8.07 us and left propagate dominant at
31.41 - a change the smaller-items entry records while this one was not pulled
along. Measured over a whole pass with its ring, the tables are between a
sixth and a fifth. The mechanism the entry proposes survives that; the ranking
does not, and the entry now says what the cache has to earn against the risk
that a wrongly invalidated table produces light nothing recomputes.
The figures are from three forks. A single-fork run of the same benchmark
suggested a share that falls as the area grows, and that was an artefact: the
three-fork numbers are not monotone and the whole-pass column moved by up to
25 % between runs. Both the range and that correction are in the page, because
a reader who saw the first number should learn why it changed.
Numbering: the two removed entries were 1 and 2, so the rest moved up. The
cross-reference in smaller items that pointed at the diagonals is gone with
them - that gap is closed - and the one pointing at the tables now says item 1.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs: stop claiming every table, and let the research index list all six
Three defects that had been carried as known and open.
Measured Results said it owns every measured table in the wiki, on four pages.
Anvil Chunk Loader refutes that on its own page: it publishes an independent
second run of the loader table and the two-fork four-thread control beside it,
the only published run whose ± covers more than one JVM launch. The claim that
was actually needed is narrower and is now what stands — where a table appears
twice, the copy in Measured Results is the one that is right.
Research listed five documents and omitted Research: Fluent API, which is an
investigation that produced code (#16) rather than a proposal. A group index
that omits one of its own pages misstates its contents, which is the part of
the folding rule that survives now that collapsed sidebar blocks make height a
non-issue. The heading loses its count rather than gaining one, so it cannot
go stale again the way the pull request numbering in CONTRIBUTING.md did.
The #### exception is written down instead of being re-decided every round. It
covers a document that records a completed investigation and no other kind of
page, and it was checked before being granted: no page links a #### anchor on
either of the two, and neither Contents block lists below ##.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzEdy5fN5JKGxJo8gwtNeu
docs: the exception hierarchy is no longer open
It stood at the top of the list, and what it was waiting on was a decision
rather than work: whether the checked root extends IOException. #21 made that
call - it does not - and built the hierarchy, so the entry goes and the five
below it move up one.
The reasoning is kept in the section header rather than dropped, because the
list is ordered by consequence and a reader who knew the old item 1 should
find out where it went. Research: Exception Hierarchy holds the detail,
including the three places where the implementation departed from the design.
The two cross-references inside item 5 move with the numbering: what used to
be item 3 and item 4 are now 2 and 3.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs: split the working record into status, measurements and contributing
Project Status had grown to 1 783 lines and eighteen sections, from Environment
and Conventions through Measured to Defects and Open. A table of contents above
a page that holds three unrelated things does not make it one thing.
Measured Results now holds every measured table and all eleven provenance
lines. Contributing holds Environment, Working on this, Conventions and
Releasing and snapshots, and is what the repository's new CONTRIBUTING.md
points at. Project Status keeps what its name says: facts, decisions, what is
in the branch, defects, what is open.
The text moved word for word. Heading levels are unchanged, so every
subsection anchor still resolves — only the page in front of it differs. The
old file was checked paragraph by paragraph against the three new ones: 257 of
274 identical, the other 17 differing only in a redirected link or a rewrapped
line. ± appears 94 times before and 94 in the moved text, × 106 times in both.
No figure changed.
The split also broke eighteen sentences that no link checker can catch. They
carry no anchor — "the full tables are in Project Status", "the working
record: benchmark results with their conditions" — so they resolve perfectly
and say something that stopped being true. The worst of them was in
_Footer.md, which renders under all thirty pages. Every one of the twenty-eight
references to Project Status has since been read in context and either
redirected or confirmed.
The Gradle group folds to Build Setup, which already listed all six pages
behind it. Five more long pages gained a table of contents. Home no longer
opens with a greeting.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QzEdy5fN5JKGxJo8gwtNeu
docs: add the architecture rules page and count seven modules
falco-archunit landed in the repository and the wiki still described six
modules, with two build tables that did not know the seventh. The stale
counts are corrected in Build Setup, Project Status, Publishing, Dependency
Management and Benchmarks and Demo, and the two tables in Testing and
Javadoc now say what check and javadoc do for a module whose only source
set is test.
The new page covers what the 39 rules enforce, why the module sees only
main sources — which is what lets it catch a public method carrying a
package-private type, a mistake no test inside the modules can see — and
which invariants it deliberately cannot check: synchronized blocks, the
ordering of the seqlock protocol, and the claim that no CPU-bound work
happens while a lock is held.
docs: state every measured claim with its conditions and its limits
Reworks all 21 wiki pages so that no performance claim can be read as
saying more than the measurement supports.
The measurement model is now stated once and authoritatively: JMH's
score error is the half-width of a 99.9 % confidence interval over the
measurement iterations of a single fork, which bounds dispersion within
one JVM and says nothing about run-to-run variance. Every published
comparison was re-graded against a mechanical significance rule and is
labelled supported, indicative-only, or not usable. Ratios whose
intervals overlap no longer carry a factor.
The 8.00x loader figure is withdrawn. The two-thread 1.9x now carries
the independent repeat that did not reproduce it next to the number
rather than two pages away. What those repeats do establish - Falco's
read time repeats at every thread count and Minestom's does not repeat
above one - is stated as the asymmetry it is, not as a factor.
Each page separates what was measured from what is reasoned from the
code and what is judgement, cites the type or method behind every
structural claim, and carries threats-to-validity and reproduction
sections precise enough for a third party to attempt replication.
Environment facts that were never recorded are marked as gaps rather
than filled in.
No measured number was changed.
Migrate the long-form repository documentation to the wiki
Adds Anvil-Chunk-Loader, Light-Engine, Benchmarking (methodology and
headline results), Project-Status, the five Rationale-* pages and the
four Research-* pages, moved verbatim from the Falco repository's
docs/, STATUS.md and README benchmark section. Internal links were
rewritten to wiki page names; links to source files that stayed in the
repository were rewritten to GitHub blob URLs; chart images stayed in
docs/charts/ in the repository and are embedded here via raw GitHub
URLs. Home.md gains Getting started / Background: rationale /
Background: research groups above the existing Gradle build group.