Skip to content

Satisfactory: rate order and parts mix beside OEE, last-played window - #214

Merged
kalwei merged 1 commit into
mainfrom
feat/satisfactory-parts-mix
Oct 30, 2026
Merged

kalwei merged 1 commit into
mainfrom
feat/satisfactory-parts-mix

Conversation

@kalwei

@kalwei kalwei commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

What

  • Rate order. A plant can hold one standing rate order: a name, and for each item a target rate in units a minute. It has no quantity and no due date.
    • New tables rate_orders and rate_order_lines, with an alembic migration chained to a9c4e1f7b2d3.
    • GET/PUT/DELETE /rate-order: any role reads it; writing needs masterdata.write.
    • A rate_orders kind in the master-data pack. The Satisfactory lab's starter, labs/satisfactory/masterdata/rate_orders.json, is seeded once and then left alone.
    • No order means no target, never a target of zero.
  • Parts mix panel under Energy on /dashboard/analysis.
    • Columns: item, target /min, actual /min, target share %, actual share %, gap /min, and the game's own figure (getProdStats) /min as the check.
    • Rows with a target come first, shortest first. Items with no target come after and say "no target".
    • The panel is absent when the plant has no order and no PARTS.* readings.
    • The machine OEE tab gets one line: what the building makes, its rate, the plant's rate and the target.
    • oee_breakdown carries parts_mix, so the assistant sees it.
    • The rate order never enters an OEE figure. OEE and Energy are unchanged.
  • "Last played" window. The reader writes FEED.Stretch on each watched poll. On a plant that has those readings, the analysis page now opens on the latest unbroken stretch, shown as "last played 04:41–05:23 today". The hours choices are still there, and ?hours= and ?shift= still win. The 80 % rule is unchanged.
  • Reader fixes.
    • A building missing from 5 consecutive unpaused polls is retired as torn down. The count is configurable as satisfactory_torn_down_polls, and the building is un-retired when it is listed again.
    • A line that arrives within 5 s after its poll is folded into that poll instead of being skipped. A genuinely empty poll is still skipped.

Why

The handoff satisfactory-parts-mix: Scott wants to see whether the factory made the mix he asked for the last time he played, beside the OEE figure, without the OEE figure changing.

How verified

  • Tests.
    • New: tests/test_the_parts_mix_stands_beside_oee_against_a_standing_rate_order.py (18 prose-named tests, one or more per DoD case) and tests/test_the_parts_mix_panel_and_the_last_play_window_in_a_browser.py.
    • The full fast tier and the whole -m browser tier pass locally, and ruff is clean.
    • The browser test holds /analysis/oee back by 1.5 s with a Playwright route and waits on the panel's rows with wait_for_function.
  • Replay on a scratch plant (loopback, port 8197) of the 2026-10-30 fixture: 43 polls, 0 skipped (the late getProdStats lines are now absorbed), 11,580 units booked, 5 buildings retired as torn down. The page opened on "last played 04:41–05:23 today · 41 min", and 41.1 min were watched.

What the screenshots showed

  • Parts mix panel, with the starter order "60.0 units/min over 3 items":

    Item target /min actual /min target share actual share gap /min game /min
    Screws 24 22.8 40 % 36 % −1.2 26.9
    Iron Rod 12 13.1 20 % 21 % +1.1 13.7
    Iron Plate 24 27.6 40 % 44 % +3.6 29.5

    Below those, the items with no target: Wire, Iron Ingot, Concrete, Copper Ingot, Biomass, Cable. The note line lists the ores the game made that the MES books none of.

  • Window picker: "last played" is selected by default, and the hours choices are below it.

  • Machine OEE tab for a constructor: "Parts: makes Screws · 22.3 units/min here over 42.13 min watched (938 units) · the plant 22.8 units/min · rate order 24.0 units/min".

Arithmetic hand-checked against the raw feed and getProdStats:

  • Units booked match a recount from the raw file: Screws 938, Plate 1,137, Rod 538, Concrete 1,232, Wire 3,544. The MES's figures differ by under one unit, because it books whole units.
  • Concrete runs steady on 2 × 15/min: the MES says 29.96/min and the game 29.99/min.
  • The game figure for Screws is 1,101.3 summed over 41 polls with statistics, which is 26.86/min, matching the panel.
  • The MES is lower than the game on Screws because the game's CurrentProd is a rolling figure. It decays for about 8 minutes after a building stops (IsProducing 0, e.g. 04:54–04:58 and 05:12–05:22). The MES books only producing intervals (Satisfactory: book only while running; one save on the floor #212's rule), so the gap is the game's smoothing, not lost units.

Notes

  • The design's "60 reinforced plates/min, mix 40/40/20" is read as 24 Iron Plate, 24 Screws and 12 Iron Rod a minute.
  • Line coverage in the last-play window is about 61 % on the constructors, because several buildings were placed at 05:19–05:22. That is the unchanged coverage rule, not the feed: the feed was watched for all 41 min.
  • Out of scope, as the handoff says: anything predictive, writing to the game, charts, the 80 % rule, and the energy figures.

🤖 Generated with Claude Code

A plant can hold one standing rate order: a name and a target per item in
units a minute, set by API or the master-data pack (starter for the
Satisfactory lab: 24/24/12 Iron Plate/Screws/Iron Rod). The analysis page
gets a Parts mix panel under Energy: target and actual /min, target and
actual share, gap, shortest first, the game's own getProdStats figure as the
check. No order means no target, never zero; no order and no PARTS readings
means no panel. The machine OEE tab gets one line, and oee_breakdown carries
parts_mix for the assistant. The rate order never feeds OEE.

The analysis window defaults to "last played" on a plant whose reader
writes FEED.Stretch; the hours choices stay and the 80 % rule is unchanged.

The reader retires a building after 5 unpaused polls without it
(satisfactory_torn_down_polls) and brings it back when listed again, and
absorbs a line arriving within seconds of its poll instead of skipping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: scottkalw <scottkalwei@gmail.com>
@github-actions

Copy link
Copy Markdown

Thanks for the first pull request. Checks: every commit signed off (git commit -s), ruff and pytest green, and the house-rules checklist in the template. The maintainer reviews within a few days.

@kalwei
kalwei merged commit 8e6c4c0 into main Oct 30, 2026
28 checks passed
@kalwei
kalwei deleted the feat/satisfactory-parts-mix branch October 30, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant