Skip to content

feat(autoplay): always farm the farming analyzer's top spot - #47

Merged
zoeyrose merged 9 commits into
mainfrom
feat/analyzer-driven-autoplay
Oct 17, 2026
Merged

zoeyrose merged 9 commits into
mainfrom
feat/analyzer-driven-autoplay

Conversation

@zoeyrose

@zoeyrose zoeyrose commented Oct 17, 2026 •

Copy link
Copy Markdown
Member

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 Deliver an unattended start-to-finish Atrinik playthrough #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

zoeyrose and others added 2 commits October 16, 2026 22:34
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>
Replace the hard-coded level ladder, readiness gates, catch-up legs,
per-map safety switches and the curated farm-spot catalog with the
farming analyzer's #1 spot for the preferred objective. Only live
failures (death, emergency recall, ten minutes without XP, or an
unroutable spot) exclude a spot for six hours.

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:14:20.024286Z 3668d62 Manual request
🔒 Security Review ✅ Completed 2026-10-17T04:20:25.711861Z 3668d62 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: a56dc5072a

ℹ️ 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 navigation.py Resolved
Comment thread compatibility.py Resolved
Comment thread farm_analyzer.py Resolved
Comment thread web_static/app.js Resolved
zoeyrose and others added 3 commits October 16, 2026 22:57
…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>
…autoplay

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

Serve the Farm picker's legs in the shape farm_circuit accepts, rebuild
a manually started analyzer spot from the server's ranking with its
analyzer-derived margins and pulls, and finish the circuit instead of
farming on when its spot is quarantined and nothing usable is ranked.

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 Security Review · Automatically triggered

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

Reviewed commit: f1e637e3a3

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.

@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: f1e637e3a3

ℹ️ 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 navigation.py Resolved
Comment thread navigation.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 and others added 2 commits October 16, 2026 23:10
…autoplay

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ignore death and emergency-recall records from before the circuit
started, so a replayed ledger cannot extend an expired quarantine, and
restart the no-XP clock after time away from the farm.

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. Swish!

Reviewed commit: 3668d62d00

ℹ️ 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: 3668d62d00

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 added a commit that referenced this pull request Oct 17, 2026
## 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
atrinik/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 #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](https://claude.com/claude-code)

---------

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

# Conflicts:
#	README.md
#	test_bot.py
#	web_server.py
#	web_static/index.html
@zoeyrose
zoeyrose merged commit 0f2b8eb into main Oct 17, 2026
11 checks passed
@zoeyrose
zoeyrose deleted the feat/analyzer-driven-autoplay branch October 17, 2026 13:35
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.22.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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