Skip to content

fix: roll saved template results and refuse outputs that failed their checks - #22

Merged
XxFran10xX merged 6 commits into
mainfrom
fix/template-results-and-broken-outputs
Nov 13, 2026
Merged

XxFran10xX merged 6 commits into
mainfrom
fix/template-results-and-broken-outputs

Conversation

@XxFran10xX

@XxFran10xX XxFran10xX commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Status record

  • Reviewed: Fable 5.2 APPROVE at e7bde2a (round 2); off-hand fix APPROVE at 6554591 (2 rounds; wording-only after at 0a902ab)
  • Second opinion: CodeRabbit APPROVE at 0a902ab (no findings)
  • Dev-tested: passed at 0a902ab (TFMCDev01, 2026-11-13 21:59 UTC, off-hand retest: one real click with an empty main hand and a start item in the off hand finished the seeded station (saved t.minor_runestone rolled), started no new project, kept the off-hand item and deleted the station file; a click 2 s later started a project normally; no Research errors in the log). Earlier, at b825e24, parts 1 and 2: alias warning and reload, alias projects start and complete, unbuildable reward keeps the project and the reopen tells the player, broken output refused with one log line, seeded literal t.minor_runestone result finished on an empty-main-hand reopen; the off-hand fall-through found there is fixed in 2ff3ff3/6554591
  • Local tests: passed at 0a902ab (ResearchManagerTest 138; full mvn verify last run at 6554591: 343 tests). The only full-suite failures are the same 31 Windows-only directory-fsync failures in ResearchPersistenceTest, StationBackfillTest and StationEstateTest that also fail on unmodified origin/main; they leave 16 estate lines in ResearchManager uncovered locally. Every changed line is covered. Linux CI enforces the 100% line gate.

The bug

OutputDef.ResultSpec reads result.item and result.template as separate keys. An output written as result.item: t.greater_runestone therefore had an item ref that isn't an item:

  1. OutputLoader logged has invalid result item 't.greater_runestone' but still registered the output, so players could start it.
  2. ResultResolver.resolve returned the item ref as given, so the station saved the literal t.greater_runestone as resolved_result_ref.
  3. On completion, ItemRef.build("t.greater_runestone") returned null. checkProjectCompletion logged Could not build result item and returned. The project never completes; it stays on the lectern for good.

Tutorial impact

Tutorial's outputs/minor_runestone.yml, lesser_runestone.yml, greater_runestone.yml and ascendant_runestone.yml all use result.item: t.<template>, and every Tutorial start logs the four "invalid result item" errors. Two Tutorial stations have saved t.greater_runestone: data/stations/TFMC_S2_142_19_347.json and TFMC_S2_146_19_347.json. Both are mid-research (magic confirmed, other aspects still testing), so they will hit the failure when they finish. Main and Dev use their own a_*_runestone outputs and have no t.* saved results.

The fix

  • a. Saved templates roll at completion. When a project completes and its saved result is still a t.* template ref, the template is rolled at that point (nested templates too). The rolled item ref is saved to the station, built and granted, and ResearchCompleteEvent carries the rolled item. The console logs Resolved saved result template .... If the template no longer exists, the project stays and the warning names the template, output and station. A project whose recipe was already complete when its reward failed now also finishes when its owner opens the lectern again, so it doesn't need another experiment. The two Tutorial stations therefore finish on their own, with no manual edit. The roll is saved only after its item builds, so a roll that can't be built leaves the template saved and rolls again next time; a failed save is logged. The reopen finish runs only for the main hand, skips outputs that failed their checks or have an empty recipe, and tells the player (station.output_unavailable) if the reward still can't be given.

  • b. result.item: t.* is read as result.template. At load, staff get a warning: Output 'x' sets result.item: t.y, which is a template. It is read as result.template; write it as result.template in <file>. Setting both item: t.* and template is still the existing "not both" error.

  • c. Outputs that failed a load check can't be started. An output with no aspects and no aspect_pool.pick now also fails its checks, because it would be complete as soon as it started. No live Main (62), Dev (57) or Tutorial (54) output has an empty recipe. OutputLoader now records outputs that fail any check (OutputLoader.passedChecks). Starting one refuses before the research paper is taken. The player sees the new station.output_unavailable message, "This research is not working right now. Please tell a staff member.", instead of "Research reload failed. Check console for errors." The console gets a warning such as <player> could not start research '<input>': it rolled output '<id>', which failed its load checks .... Unknown, disabled and unresolvable outputs and inputs without outputs use the same message, each with its own log reason. Each input and output pair is logged once per load, not on every right-click. messages.yml gets the new key. Live messages.yml files are never overwritten, so the code has a built-in fallback until the key is added.

  • Off-hand half of a finishing click. A real client sends a second, off-hand interact in the same tick when the main hand did nothing on its side. After a main-hand reopen finishes a project, the manager remembers that lectern and tick (one entry per player; it expires after that tick window and is removed on the next station click, quit or unload) and cancels only that player's off-hand interact on the same lectern in that tick or the next (the two packets can straddle a tick boundary), so a research paper in the off hand no longer starts a new project there. Off-hand starts on other ticks or lecterns work as before.

Not in this PR

The Tutorial config fix (move the four runestone outputs from result.item: t.<template> to result.template: t.<template>) is a separate live config change. With this PR those outputs already load and work, with a warning.

No version bump: Research sets the version from the release tag.

🤖 Generated with Claude Code

… checks

An output written as result.item: t.<template> was not read as a template:
the loader logged it as an invalid item but kept the output, players could
start it, the station saved the literal t.<template> as its result, and on
completion the item could not be built, so the station stayed stuck.

- A saved result that is still a t.* template is rolled when the project
  completes; the rolled item is saved and granted. A project whose recipe is
  already complete also finishes when its owner opens it again.
- result.item: t.<template> is read as result.template, with a load warning
  telling staff to move it to result.template.
- Outputs that fail their load checks stay listed but cannot be started:
  the player gets station.output_unavailable (with a built-in fallback for
  older messages.yml files) and the console gets a warning naming the
  input and the problem, instead of "Research reload failed".

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

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • New Features

    • Completed projects can now be finished when reopened at a station, provided their recipe and output are valid.
    • Missing message entries now display a fallback message.
  • Bug Fixes

    • Invalid or unavailable outputs are rejected before a project’s starting item is consumed, with a clear message shown.
    • Template references in result items are recognised correctly, and outputs without required aspects are flagged.
    • Duplicate refusal notices are reduced, and station interactions no longer trigger an unintended second action.

Output loading now records validation failures and recognises template references in result.item. ResearchManager uses output checks when starting projects, resolves template results, and can complete eligible projects when a station is reopened.

Changes: Research output flow

Layer / File(s) Summary
Output validation and result definitions
src/main/java/net/tfminecraft/research/loader/OutputLoader.java, src/main/java/net/tfminecraft/research/model/OutputDef.java, src/test/java/net/tfminecraft/research/loader/*, src/test/java/net/tfminecraft/research/ResearchTestState.java, src/test/java/net/tfminecraft/research/util/ResearchUtilitiesTest.java
OutputLoader tracks failed output checks and rejects definitions with no fixed aspects or selected pool aspects. OutputDef recognises a template reference in result.item when result.template is blank. Tests cover validation, aliases, and check-state reset.
Unavailable-output start handling
src/main/java/net/tfminecraft/research/Messages.java, src/main/java/net/tfminecraft/research/manager/ResearchManager.java, src/main/resources/messages.yml, src/test/java/net/tfminecraft/research/ResearchTextAndModelTest.java, src/test/java/net/tfminecraft/research/manager/ResearchManagerTest.java
ResearchManager refuses starts for missing, unloaded, disabled, invalid, or unresolvable outputs before consuming the start item. It sends the configured unavailable message or a fallback and logs each input/output pair once per load.
Template result resolution
src/main/java/net/tfminecraft/research/util/ResultResolver.java, src/main/java/net/tfminecraft/research/model/ActiveProject.java, src/main/java/net/tfminecraft/research/manager/ResearchManager.java, src/test/java/net/tfminecraft/research/manager/ResearchManagerTest.java
ResearchManager resolves saved template references into item references. When the result builds, it updates and saves the project reference before granting the reward. Tests cover unresolved templates, unbuildable results, and save failures.
Station-reopen completion and click handling
src/main/java/net/tfminecraft/research/manager/ResearchManager.java, src/test/java/net/tfminecraft/research/manager/ResearchManagerTest.java
Reopening a station can complete an eligible project with a complete recipe. The manager suppresses the corresponding off-hand click and clears click tracking when the player quits or stations unload.

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Player
  participant ResearchManager
  participant ResultResolver
  participant ActiveProject
  Player->>ResearchManager: Reopen station
  ResearchManager->>ResultResolver: Resolve saved template reference
  ResultResolver-->>ResearchManager: Return item reference
  ResearchManager->>ActiveProject: Update resolved result reference
  ResearchManager->>Player: Deliver built reward
Loading

Suggested reviewers: ryanbarlow97, drefvelin

Merge Risk: Minimal · up to 0a902

This change rolls saved template results at completion, refuses to start outputs that failed their load checks, and lets owners finish already-complete projects by reopening the lectern. No concrete defect was found in the reviewed code. The earlier concern about template cycles is ruled out by load-time validation. The risk of merging is minimal.

- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6edcee74-527e-4ee5-9d62-ab673126d187
Commits

Reviewing files that changed from the base of the PR and between 5de5a7c and 0a902ab.

Files selected for processing: 13

  • src/main/java/net/tfminecraft/research/Messages.java
  • src/main/java/net/tfminecraft/research/loader/OutputLoader.java
  • src/main/java/net/tfminecraft/research/manager/ResearchManager.java
  • src/main/java/net/tfminecraft/research/model/ActiveProject.java
  • src/main/java/net/tfminecraft/research/model/OutputDef.java
  • src/main/java/net/tfminecraft/research/util/ResultResolver.java
  • src/main/resources/messages.yml
  • src/test/java/net/tfminecraft/research/ResearchTestState.java
  • src/test/java/net/tfminecraft/research/ResearchTextAndModelTest.java
  • src/test/java/net/tfminecraft/research/loader/OutputChecks.java
  • src/test/java/net/tfminecraft/research/loader/ResearchLoadersTest.java
  • src/test/java/net/tfminecraft/research/manager/ResearchManagerTest.java
  • src/test/java/net/tfminecraft/research/util/ResearchUtilitiesTest.java

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

@github-actions github-actions Bot added the size:L 100-499 effective changed lines (tests excluded in mixed PRs). label Nov 13, 2026
XxFran10xX and others added 5 commits November 13, 2026 16:53
- Roll a saved template, build the reward, and only then save the rolled
  ref, so a roll that cannot be built never pins the station; warn when
  that save fails.
- Outputs with no aspects and no aspect_pool.pick now fail their load
  checks (no live Main, Dev or Tutorial output has one), and the reopen
  finish skips outputs that failed their checks or have an empty recipe.
- The reopen finish runs for the main hand only and tells the player when
  the reward still cannot be given.
- Refused starts are logged once per input and output until the next
  load, with no second log for an unresolved result.
- OutputLoader.failedChecks() is read-only; tests use a package hook.
- station.output_unavailable now reads "This research is not working
  right now", since it also covers a reward that cannot be given.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wording only: a failed save of a rolled result still gives the reward,
and OutputLoader notes that the refusal-log set is the manager's state,
main thread only and reset on each load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A real client sends an off-hand interact in the same tick when the main
hand did nothing client-side. After a main-hand reopen finished a project,
that off-hand half found the lectern free and started a new project from
a research paper held in the off hand (seen on Dev).

The manager now remembers the lectern and server tick of each player's
last main-hand reopen finish (one entry per player, dropped on the next
tick, on quit and on unload) and cancels only that player's off-hand
interact on the same lectern in the same tick. Off-hand starts on other
ticks or other lecterns work as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The main-hand and off-hand packets of one click can straddle a tick
boundary, so the off-hand half is ignored in the finishing tick and the
next one; the entry expires beyond that. Tests cover the +1 tick case,
a +2 tick start, and a main-hand click in the same tick that still starts
normally. The field comment now says how entries expire.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wording only: the field comment says when entries are removed, and the
parameterized start test is now startsStillWorkOutsideTheFinishingClick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@XxFran10xX
XxFran10xX marked this pull request as ready for review November 13, 2026 23:01
@XxFran10xX

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@XxFran10xX
XxFran10xX merged commit 401a51e into main Nov 13, 2026
4 checks passed
@XxFran10xX
XxFran10xX deleted the fix/template-results-and-broken-outputs branch November 13, 2026 23:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 effective changed lines (tests excluded in mixed PRs).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant