Commit graph

26 commits

Author SHA1 Message Date
acamilo
3d9a08d0be infra: flyedge.service, off by default, and the feed bus through build, deploy and watchdog
flyedge.service runs /opt/fly/current/fly-edge After= and Requires=
flysim.service, with its metrics on loopback :9102 and a
ConditionPathExists so a release without the binary leaves it inactive. It is
in no target and 07-enable.sh does not enable it; the header has the switch
and the way back.

build-flysim.sh also builds fly-edge beside the flysim binary and
package-release.sh ships it when present. 05-deploy.sh writes
FLY_FEED_VIA (default direct) into fly.env, flysim.service names
FLY_BUS_DIR=/run/fly/bus and tmpfiles creates it. Watchdog check 2 reads the
feed counters from whoever serves the feed: flyedge when fly.env says bus.
lint.sh holds all of that, and drives check 2's choice against a fixture.
2026-09-23 11:41:28 +00:00
flybrain
6c7ee5476c docs: macros.md 12.21 and the row 57 audit 2026-09-23 10:10:03 +00:00
flybrain
b8a5c8fc52 watchdog: check 10 counts outcomes, not only starts
Row 57's pad was one button refused every hold for two hours: one start
and one name in ten brain minutes, so neither the sequence rule nor the
dominance rule could fire, and the coordinator's own watcher saw it
first. Check 10 now reads every macro outcome in the window. The fly's
decisions are its starts and its refusals; `stalled` flags 90% of 20+
decisions ending refused, blocked or timed out, and `zero-progress`
flags decisions with no `done` among them on two probes in a row. Both
sit behind the same no-new-ground gate as the old rules.

fly_loop_refused, fly_loop_blocked and fly_loop_done are exported, and
loop.json carries window.decisions and window.outcomes. It still never
acts: the lint fixture asserts no unit is restarted across six cases,
two of them new (the row-57 log, and a zero-progress log).
2026-09-23 05:48:01 +00:00
flybrain
a22edacbc8 docs: macros.md 12.20, macros-wram.md section 11, the row 56 audit
The survey whole, both arms of the trap hunt, the ROM run, and the residuals --
including the two this row does not work: neither arm reaches rung 11 from this
checkpoint, and the watchdog's check 10 cannot see a loop of exactly four
distinct macros.
2026-09-23 01:17:33 +00:00
acamilo
6342adba39 docs: row 55 gates, as run on the merged tree 2026-09-22 22:48:11 +00:00
acamilo
e5fe6c46ac Merge main into fix/loop-row55: row 50's battle seam beside row 55's counter
Three conflicts, all of them two reviews appending in the same place, all
resolved by keeping both sides: `macros.md` (row 50 keeps section 12.18, row 55
becomes 12.19), `macros-traps.md` (both trap rows, both residual pairs, both arm
sections) and `scene_probe.rs` (both survey modes, `accept` and `shop`). Every
source file auto-merged.

The two rows compose on the cartridge: from the mart checkpoint the fly leaves
the counter, walks the town, and no `MOVE n` blocks any more, so the longest
chain of one macro blocked on an unchanged frame is 1 in any scene.
2026-09-22 22:38:10 +00:00
acamilo
549df6c323 docs: row 55, and the two claims about a mart the survey narrowed
`macros.md` section 12.18 is the review; `macros-wram.md` section 7.1 corrects
the address table, where `wListMenuID` was said to be cleared by every text
display and an item's position in the stock was said to be its cursor index;
`macros-traps.md` carries row 55, its two arms and its ROM run, and two new
residuals -- `wListScrollOffset` is not a pinned address, and a mart that has
never drawn a buy list reads `Unknown` rather than `Shop`.
2026-09-22 22:29:07 +00:00
acamilo
349a1fd28c Merge fix/loop-row50: a battle turn is the fly's only while the move list is drawn 2026-09-22 22:13:08 +00:00
dev
e307b7dde4 docs: row 50's survey, its two trap hunts and its ROM run
The press survey, twenty brain minutes before and after on both checkpoints,
and the ROM-gated forest run.

The ethos check's 'fewer flagged windows, more distinct tiles' holds on the
tiles on both arms (296 to 430, 163 to 184) and does NOT hold on the windows
(33/73 to 70/73, 68/73 to 73/73). After the fix the fly spends three quarters
of each run inside battles it is actually fighting, and the hunt's tile rule
flags a fighting fly exactly as hard as a stuck one. Reported rather than
smoothed.
2026-09-22 22:11:01 +00:00
dev
6588897ab3 docs: a menu is up while its box is on screen (section 12.18, row 50)
macros.md gains 12.18 and macros-wram.md a section 10 for the accessor and the
survey that found it: press at every battle frame with a rollback pulse, and
ask every byte of WRAM and HRAM which of them separates a honoured press from
a refused one.

The half of row 50 that was wrong is where the fix is. The move list was not
drawn: MoveSelectionMenu's cursor bytes are never cleared and SelectMenuItem
decrements wCurrentMenuItem back into the one-based range on its way out, so a
turn's whole text and animation read as an open list with a placeable cursor.

The battle bag is the same trap on wListMenuID and is named rather than fixed,
because the figure that tells its list from the frame after it closes has not
been surveyed yet.
2026-09-22 18:43:05 +00:00
acamilo
a8afd8f448 Merge feat/catch-reward: a catch reward, adapter v6 with a v5 migration, and a rung restart 2026-09-22 18:41:15 +00:00
acamilo
f223702085 Merge fix/chat-ring-persist: the on-screen chat ring survives a sim restart via a hot-dir sidecar 2026-09-22 17:45:59 +00:00
alex
23a4d7379b rewards: a catch reward, adapter v6 with a v5 migration, and a rung restart
The operator's decision of 2026-09-22: pay the fly for keeping a wild Pokemon,
bump the adapter properly, and restart the live run from an early checkpoint
rather than from scratch.

The rule. `catch` is the catalog's ninth kind, appended so the key order
`counts` serializes in does not move. 0.30 for a species this run had never
owned, 0.10 for a repeat, three payouts per species for the lifetime of the
ledger; the `species` rule is untouched, so a first catch of a new species pays
0.80 across two kinds. The catch is read from `wCapturedMonSpecies` ($d11c),
whose comment in ram/wram.asm is "0 if no mon was captured": ItemUseBall zeroes
it before every throw and writes wEnemyMonSpecies into it only on the branch
that keeps the Pokemon, and UseBagItem's `.returnAfterCapturingMon` zeroes it
again and sets wBattleResult to 2 -- a value written on exactly two paths in
the game, that one and a link battle whose opponent ran. Both are required, so
a byte read out of a half-initialised battle cannot pay. Not wPartyCount: a
catch with a full party raises wBoxCount instead, and wPartyCount also rises
for a gift, a trade and a PC withdrawal.

"Never owned this run" is the `species` payout inside the same battle, because
nothing else can set a Pokedex bit during one. It is not read off the captured
species byte: that is the cartridge's internal index while the owned bitset is
by Pokedex number, and nothing in WRAM converts between them.

The address was resolved by tools/resolve_wram.py, not written by hand. The
tool needed NUM_TMS and NUM_HMS, which the decomp defines through its `const`
enumeration, so it now counts them from the file's own add_tm/add_hm
definitions and cross-checks NUM_TMS against the literal the same file
declares.

The feed's kinds are closed, so `catch` publishes on `wildwin` and nothing in
packages/feed or apps/stage changed. Deliberately not `pokedex`: the `species`
rule already pays for the bit the same catch sets. The stage's ticker copy is
keyed on the feed kind, so a catch row reads "wild win" -- stated in
docs/rewards-learning.md rather than left to be discovered.

v5 -> v6. STATE_VERSION stays 4: the rule adds one counter, `catchCounts`, and
changes nothing else, so a v5 state restores with it empty. That migration is
opt-in and needs all three of: the adapter segment being the only difference
between the two compatibility strings, the running adapter listing the
checkpoint's adapter in `migrates_from()`, and the deploy naming it in
FLY_ACCEPT_ADAPTERS. flysim applies the rule at restore and 05-deploy's gate
applies the same rule before it flips the symlink, writing the variable into
fly.env so the two cannot disagree.

The restart. infra/bin/fly-reset-to-milestone <N> archives both stores to a
dated directory, rewrites milestone-<N>.checkpoint with the ratchet's attempts
and recoveries at zero, installs it as the newest generation of both stores,
clears the milestone archives above N and the event log, and prints what it
did. It refuses while flysim is running and refuses a rung the run never
reached. The envelope work is in flysim::reset (`flysim
--reset-to-milestone N`); the shell script is the operator's wrapper.

Tests: catalog values and order; a synthetic WRAM trace of a catch (new,
repeat, cap, already-owned species, trainer/Safari/old-man/missed-ball
negatives, rollback replay); a v5 state restoring with the counter at zero; a
v5 checkpoint fixture accepted with the opt-in and refused without it; the
reset tool against copies of a state dir in temp directories; and a ROM-gated
catch from a rung-9 forest checkpoint, driven by the shipping THROW BALL macro.

The compatibility string differs from main's in exactly one segment, checked by
splitting both on `/`: pokered-unique8-v5 -> pokered-unique8-v6.
2026-09-22 17:30:00 +00:00
acamilo
95d3d56d3f docs: the rung-eleven ROM run, measured 2026-09-22 17:24:27 +00:00
acamilo
bffbaca394 docs: row 54, the mid-step survey and both arms of the hunt
macros.md gains section 12.17; macros-wram.md section 9 gains the frame-by-frame trace of a step,
the three readings that come out of it and the one byte that tracks a step exactly and is recorded
unused; macros-traps.md closes rows 54 and 54b, strikes the two residuals they worked, and prints
both checkpoints' before and after whole -- including the arm where the ethos check's "fewer
flagged windows, more distinct tiles" does not hold, and why.
2026-09-22 17:19:25 +00:00
acamilo
533cf82ac8 infra(05-deploy): FLY_RESET_STATE=1 clears the chat ring too
The deliberate reset already clears the tmpfs hot ring; the on-screen chat
ring's sidecar lives there now, so it goes with it.
2026-09-22 16:26:29 +00:00
acamilo
de0eed7da9 traps: both hunt arms, and row 54 -- the cycle that replaced the one this branch closed
BACK in a text box goes 291 to 0 and the museum is left in the first window and never returned
to, which is rows 51 to 53. The hunt's own two measures do not improve: 193 distinct tiles become
175 and 59 flagged windows become 69, because a new three-macro cycle takes the old one's five
tiles for seven and a half brain minutes and then the fly spends four minutes inside one battle,
which the tile rule flags as hard as a stall. Battle frames go 6,948 to 20,894.

Row 54 names the new cycle with the two readings that fit it, and the residual under both is the
whole-map grid being refused on every frame the fly is mid-step. Reported rather than smoothed:
the ethos check's 'the trap hunt improves' does not hold for this branch.
2026-09-22 14:23:00 +00:00
acamilo
93925673eb tests: print the rank the ROM run ends on
It ends on rank 10 with no badges: the fly reaches the gym on 15 macros and presses TALK fifteen
times inside it, and 55 brain minutes of the stub rotation do not beat the leader. The road is
what this branch is about; winning the fight is the fly's.
2026-09-22 13:18:24 +00:00
acamilo
d5a21e9a5d traps: rows 51 to 53, the museum's missing rows and a BACK with no box under it
The reproduction, the three surveys and the before/after for the rung-10 Pewter stall, with the
ROM-gated run's table. Rows 51 (UNKNOWN's two states), 52 (a building with no row on the map
graph) and 53 (a frontier excluded by a window that lapses) each with their tests.
2026-09-22 13:14:47 +00:00
acamilo
e1b4819ebe docs: row 41 worked, with the survey and the before/after
Where the fly was standing, the conversation press by press, why TALK
retired nothing, the four rows this branch closes and the one it leaves,
the ROM-gated run, and the hunt: 1 distinct tile to 437, 73/73 flagged
windows to 54/73, YES in a text box on map 0x3a 1424 to 4, dialog frames
69,469 to 5,492.

The 54 that still flag are a different trap on ground the before arm
never reached -- GO FRONTIER runs and a GO OBJECTIVE/BACK/GO FRONTIER
cycle in Pewter City -- and that is the next brief.
2026-09-22 11:16:18 +00:00
acamilo
c06d3206e2 docs: section 12.11, and rows 44 to 47 of the trap audit
The rung-10 loop whole: which building the fly was in, why every candidate list
on that map emptied, the byte dump that named the battle menu's swapped entries,
the ROM-gated before and after, and the two arms of the trap hunt being identical
because a restore clears the ledgers the loop was built out of.

Section 13.1's tables follow: MENU off both overworld rows and off the narrow
counter row, the move list's conditional BACK, the start menu reachable only by
the raw START button, and two new rows in the pad-empty audit - the room whose
one door the ledger rests, and the map with no way out at all, which is the one
empty pad left and is asserted rather than covered.
2026-09-22 09:07:00 +00:00
acamilo
4bd0a4b3fa Merge fix/loop-20260922T0459: NEXT never on a pad with an input-accepting cursor; MOVE 1 is the main menu backstop; the bag is the fly's turn 2026-09-22 06:18:34 +00:00
acamilo
f0cebd2574 docs: section 12.10, and rows 42 and 43 of the trap audit
The contract: no pair of buttons on any battle pad may undo each other with
nothing else changing, which is section 12.2's rule stated at the pad instead
of at one macro. Section 13.1's table takes NEXT off the own-turn main menu,
gives the bag a row of its own on the own turn, and records MOVE 1 as the
backstop that row keeps.

The audit carries the reproduction -- 71,673 frames in one battle, 73 of 73
windows flagged, BACK 739 starts on the move list against NEXT 739 on the main
menu -- the ROM-gated run before and after, the trap hunt before and after
(1 distinct tile to 260, 73 of 73 flagged windows to 68 of 73, 0 overworld
frames to 20,394), and the residuals: NEXT on a move list whose cursor the seam
cannot place is now the largest source of it, which is row 30b and wants a WRAM
reading rather than a pad change.
2026-09-22 06:15:09 +00:00
claude
4b93f9dc7f docs: the trap hunt for section 15, before and after
286 distinct tiles become 489 over twenty brain minutes from the rung-9
checkpoint, the median flagged window holds 55 tiles instead of 16, GO FRONTIER
runs 64 walks worth up to twelve net tiles instead of four worth one, and one
walk spends its cap where six did.

The cost is named rather than buried: flagged windows go 61 to 70 and windows
under four tiles 5 to 14, and every one of those is a window spent inside a
battle -- a fly that covers more ground walks into more grass, 48,756 battle
frames becoming 50,413 with the longest battle 9,549 frames becoming 13,411.
This is the first measurement in that file where more ground and fewer flags do
not both hold, and it is stated as such.
2026-09-22 05:15:30 +00:00
acamilo
18e16819ca docs: section 12.9, and rows 38 to 41 of the trap audit
The rung-9 forest review: what was live, the mechanism of all three
observations, the audit rows, and the trap hunt before and after from the
release container's own checkpoint.

The hunt is brain-driven rather than stubbed, which is legitimate here and
was not for sections 13 and 14: this branch adds no macro type, so no
population is re-dealt and the two arms differ in the macro code alone.
Distinct tiles 216 to 286, windows flagged 70 of 73 to 61, windows under
four tiles 21 to 5, BACK starts with no list open 175 to 0, MOVE n starts
36 to 68.

Four residuals are named rather than buried: BACK is still 359 starts of
830 over open lists, which is row 34's contract; a NEXT/BACK two-cycle
closes the run inside one battle, from a move list whose cursor the seam
cannot place on its opening frames; a window spent in a battle is flagged
by the tile rule whatever happens in it; and the THROW BALL precondition
is inert in this run because the save carries a party of one.

Row 41 is the loop behind this one: in the before arm the fly answered the
nurse's box YES 474 times on one tile of a Pokemon Center for the last
eight brain minutes of the run. The after arm never enters it, so it is
neither reproduced nor fixed here. It is the next thing to measure.
2026-09-22 04:09:05 +00:00
acamilo
660c3cf00d flybrain v0.4.0: public tree (history retained privately)
Some checks failed
ci / node 22 (test + typecheck) (push) Has been cancelled
ci / rust stable (cargo test --workspace --release) (push) Has been cancelled
ci / infra/tests/lint.sh (push) Has been cancelled
ci / playwright apps/stage (allowed to fail) (push) Has been cancelled
2026-09-21 15:09:46 +00:00