Skip to content

feat(farming): rank farm spots with the locked farming analyzer - #46

Merged
zoeyrose merged 3 commits into
mainfrom
feat/farming-analyzer-spots
Oct 17, 2026
Merged

zoeyrose merged 3 commits into
mainfrom
feat/farming-analyzer-spots

Conversation

@zoeyrose

@zoeyrose zoeyrose commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

Summary

Merge together with the stacked #47. On its own, this PR's objective toggle only reorders the dashboard ranking; #47 makes autoplay farm the selected objective's #1 spot.

First step of making the farming analyzer the source of truth for farm spots. This PR pins the analyzer, runs it in the background from Sera's live stats, and adds a dashboard Farming tab with the objective toggle. Autoplay doesn't follow it yet: the follow-up PR switches autoplay to always farm the selected objective's #1 and deletes the hard-coded tiers and farm_spots.py.

Locked inputs

dependencies.lock.json gains two archive inputs. They use the same fail-closed path as content: digest-pinned HTTPS download, member, size and path limits, required paths, a tree digest in the bundle marker, and a read-only cache generation.

  • farming_analyzer: atrinik/tools v3.8.0 (c624e500), atrinik-tools-farming-analyzer-3.8.0.tar.gz, sha256:3adcce51…, MIT. This is the deterministic asset added in feat(release): publish the farming analyzer as a release asset tools#32; the published bytes match a local rebuild of the tag. It unpacks to analyzer/.
  • classic_server: atrinik/classic v5.99.0 (adcab310, the release MAIN runs), atrinik-classic-server-5.99.0.tar.gz, sha256:ea3fd518…, GPL-2.0-or-later. The analyzer reads src/server/exp.c and skill_util.c from it as text. Nothing from it is compiled, linked, executed or distributed. It unpacks to classic-server/.

compatibility.py validates both inputs through one shared _validate_archive_spec, which content now uses too. _release_specs includes them, so preflight verifies their tags, commits and asset digests on GitHub. install_bundle and inspect_bundle extract and verify them, and doctor gains a farming-analyzer check. For air-gapped installs, dependencies also accepts --analyzer-archive and --server-archive alongside --source-archive and --runtime-archive. THIRD_PARTY_NOTICES.md, PROVENANCE.md, the README and AGENTS.md record the inputs and the out-of-process boundary.

Background analyzer (farm_analyzer.py)

  • Inputs: combat_profile() reads the killing weapon school (from the equipped weapon's required skill) and its level, plus the player doll: DAM, WC, weapon speed, character level, max HP, speed, AC and protections. These map to the analyzer's server-formula melee options (--melee-damage, --weapon-class, --weapon-speed, --melee-attack slash=100, --player-ac, --player-protection TYPE=PERCENT, …). Only melee weapon schools are simulated for now; other loadouts report unsupported.
  • Process: FarmAnalyzer owns at most one analyzer process: nice -n 10 python -E -s with the cached analyzer on sys.path, --content-root and --server-root from the bundle, and --ranking all --top 10 --json. One run ranks every objective, so switching objective never needs a new run.
  • When it runs: after a material profile change (school or level, at least 10% DAM or max HP, at least 5% weapon or movement speed, at least 2 WC or AC, at least 5 points of any protection) or after six hours, at most every ten minutes. A failure keeps the previous ranking and retries after fifteen minutes, independent of that ranking's age; a 15-minute timeout kills a stuck run.
  • Wiring: in web and autoplay modes, the CLI builds the analyzer from the installed bundle and polls it every 30 s while the character is in game.

Dashboard

  • The new Farming tab shows the run status (running, updated N ago with its duration, or the failure) and the simulated profile. Below that is a segmented toggle for XP per hour, Money per hour, Loot per hour, Balanced, Safety, then the top five spots for the selected objective: name, region, location, estimated XP/money/loot per hour, danger, and monsters.
  • The choice is saved per character (farm_objective in the character state record) through the new farm_objective action, which rejects unknown objectives.

Live analyzer check

With Sera's real stats (slash weapons 22, DAM 44, WC 31, 2.25 s, HP 188, AC 37, slash 49 / pierce 48 / impact 43 / cleave 54 / acid 12), a run through the service took 11.0 s. The event loop kept ticking throughout. The #1 picks:

Objective #1
XP, loot, balanced, safety Strakewood Island circuit (est. 4.4M XP/h)
Money Eld Woods Island circuit

Two things to act on before autoplay follows these picks:

  • Strakewood: the analyzer scores Strakewood as the safest spot, but live play there previously killed Sera (crocodile and frog packs joining across map seams). The follow-up keeps one exception: a spot where she dies or has to make an emergency retreat is excluded from the analyzer's next runs for a while, so she moves to the next Deliver an unattended start-to-finish Atrinik playthrough #1. The analyzer's danger model should also learn about those packs.
  • XP estimates: the estimates are about 30 times her live rate (she earns 80–150k XP/h), so they're for ranking, not for display as truth.

Validation

  • Full suite on a fresh CMake build: 456 tests OK. New coverage:
    • profile extraction, including weapon_magic becoming weaponmagic and unsupported loadouts;
    • the material-change thresholds;
    • a background run against a fake analyzer: non-blocking, one process at a time, every objective ranked, no re-run for an unchanged profile, re-run after a level-up, and the last ranking kept for an unsupported loadout;
    • a failed run backing off;
    • the isolated, low-priority command line;
    • the dashboard farming_analysis slice, the farm_objective action and persistence, and the new tab.
  • test_compatibility: 19 OK, with fixtures and checks extended to both new inputs (validation failures, extraction, marker identities, doctor).
  • Real lock, fresh cache: dependencies downloaded and verified both new artifacts; doctor passed all five checks, including farming-analyzer; preflight against GitHub passed all seven.
  • node --check web_static/app.js, compileall and git diff --check: clean.

🤖 Generated with Claude Code

Pin the atrinik/tools farming analyzer and the Classic server source it
reads, run it in the background from the character's live combat
profile, and add a dashboard Farming tab with a saved objective toggle
(XP, money or loot per hour, balanced, safety).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T04:15:08.488723Z 8c50003 Manual request
🔒 Security Review ✅ Completed 2026-10-17T04:16:31.903831Z 8c50003 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f3ea3cf47

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread compatibility.py Resolved
Comment thread farm_analyzer.py Resolved
…hanges

Let `dependencies` take pre-downloaded --analyzer-archive and
--server-archive files for air-gapped installs, and treat a 5% change
in character speed as a material profile change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f73336f4b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web_server.py Resolved
Comment thread farm_analyzer.py Resolved
Track when the current report was produced separately from the last
attempt, so a failed six-hour refresh is retried after fifteen minutes
instead of waiting almost another six hours.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zoeyrose

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

Reviewed commit: 8c50003b65

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 8c50003b65

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@zoeyrose
zoeyrose merged commit 586af3d into main Oct 17, 2026
11 checks passed
@zoeyrose
zoeyrose deleted the feat/farming-analyzer-spots branch October 17, 2026 13:29
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.21.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

zoeyrose added a commit that referenced this pull request Oct 17, 2026
## Summary

Follows #46 (merged), which
pins and runs the farming analyzer.

Autoplay now always farms the farming analyzer's #1 spot for the
dashboard's preferred objective (XP, money or loot per hour, balanced,
or safety). The hard-coded level ladder and every curated spot are gone:

- **Removed:** all 38 `FarmCircuitTask` tier tables (`EARLY_*`,
`TREE_*`, `UNDERGROUND_CITY_*`, `ZECHNA_*`, deer, Strakewood, Fort
Sether, wizardry catch-up, …), together with:
- `_progression_legs`, `_safe_progression_legs`,
`_catchup_progression_legs`;
  - the deer and Strakewood readiness gates and guarded trials;
- the level-specific leg exceptions (killer bees, ogres, early lost
souls);
  - the per-map safety switch;
  - `farm_spots.py`.

  In all, 1,491 lines removed.
- **`analyzer_farm_selection(client, graph)`:** returns the preferred
objective's highest-ranked spot whose maps all exist in the world graph
and none of which is quarantined. `analyzer_spot_legs` turns its
`map_paths` into legs (a multi-map circuit rotates through every map, as
before) and its monster labels (`giant frog L20×3`) into the target
pattern.
- **Autoplay:** waits safely, recording one `awaiting-farm-ranking`
decision, until a spot exists. Then it starts an `analyzer_driven`
circuit, which re-selects whenever the ranking, the objective or a
quarantine changes, between fights and loot. Each switch records a
`farm-spot-selected` decision.
- **Safety from analyzer data:** spots with aggressive residents get
flee 0.80 and heal 0.95, plus the isolated-radius pull planner (one
resident at a time, from squares outside the others' detection radii).
Before, only `world_1_50` had it. Other spots use 0.75 and 0.90. The
lost-soul margin stays as a floor. Explicit, non-analyzer circuits keep
their previous behaviour.
- **Dashboard:** the Tasks tab's **Farm** picker lists the same ranked
spots. Starting one sends its `analyzer_spot` id; the server rebuilds
the circuit from its own ranking (rejecting a spot that's no longer
ranked) with that spot's analyzer-derived margins and pulls. A manual
pick stays on its spot instead of following later rankings.
- **Nothing usable left:** if every ranked spot is quarantined or
unusable while the current spot is excluded, the circuit records
`farm-spots-exhausted` and finishes. Autoplay then holds position safely
until a usable spot is ranked again; it never keeps farming a spot that
was just excluded.

### The only exceptions: live failures

As agreed, the analyzer is the source of truth. A spot is excluded for
six hours, and autoplay moves to the next-ranked one, only after
something it couldn't model goes wrong there:

- **Agreed:** a death there, including on the way there; an emergency
recall there.
- **Beyond what was agreed (flagging for your review):**
- ten minutes on the spot without any character XP. This watchdog used
to apply only at level 30+, which is how Sera stalled at 0 XP on
world_14_77. Time away from the farm (maintenance, travel, reconnects)
restarts the clock instead of counting against the spot;
- a route the world graph cannot plan. Otherwise an unreachable #1 would
fail autoplay repeatedly.

Only failures recorded after the circuit started count, so a decision
ledger replayed after a restart can't extend an expired quarantine.

### What she'll do live

With Sera's real stats (slash weapons 22, DAM 44, WC 31, HP 188, AC 37),
the real analyzer and world graph pick the following. Every ranked spot
maps onto the graph.

| Objective | Spot | Margins | Pulls |
| --- | --- | --- | --- |
| XP, loot, balanced, safety | Strakewood Island circuit: world_0_50,
0_51, 1_50, 1_51, targeting crocodile, giant frog and mud hand | 0.80 /
0.95 | isolated |
| Money | Eld Woods Island circuit: world_13_73 and 14_73, targeting
giant slug and red ant | 0.75 / 0.90 | adjacent |

The Strakewood circuit is where crocodile and frog packs killed Sera
before. The cautious margins, isolated pulls and the
death/emergency-recall quarantine are the safety net. If she dies there
again, the analyzer's danger model needs to learn about those joins.

## Validation

- Full suite on a fresh CMake build: 444 tests OK.
- **Removed:** 19 tier-policy tests (ladders, readiness, catch-up,
guarded trials, hand-audited exclusions, the Old Outpost per-map margin,
the spot catalog).
- **Converted:** mechanics tests now use literal legs: patrol squares,
the rare-detour cooldown, unreachable-target cooldown, waiting for an
engaged target, launcher rules, and combat-build review.
- **New tests:**
  - analyzer results mapping to legs and targets;
  - selection following the objective and skipping quarantines;
  - autoplay waiting for a spot;
- death and emergency recall each quarantining the pick and
re-selecting, without blaming a reached pick for a death elsewhere;
  - the ten-minute no-XP watchdog for any analyzer pick;
  - an unreachable pick being excluded instead of failing autoplay;
  - the data-driven margins.
- An end-to-end probe with the real analyzer, cached bundle and world
graph produced the table above.
- `node --check web_static/app.js`, `compileall` and `git diff --check`:
clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant