Skip to content

The Sharing Tab - #8406

Closed
keithharvey wants to merge 21 commits into
fmt-llmfrom
sharing_tab
Closed

The Sharing Tab#8406
keithharvey wants to merge 21 commits into
fmt-llmfrom
sharing_tab

Conversation

@keithharvey

Copy link
Copy Markdown
Collaborator

📚 Reviewed via the file-partitioned split — bottom-up

Important

This PR is the merge vehicle for the whole feature — review happens in the split PRs above. Its tree is byte-identical to the assembled split tip. Merge order: the type-migration stack (#8235) lands first; then this PR's base flips to master (the diff doesn't change — the stack is already built on the migrated base) and it merges through the GitHub UI. The split PRs are closed afterwards; their content is contained here.

Each PR is file-partitioned: every file appears in exactly one PR in its final sharing_tab form, so each PR's diff is byte-identical to that branch. Regenerated deterministically by just bar::sharing-split.


Related work

📚 Stacked split— review bottom-up

Each PR merges into the one below it; together they reproduce the sharing_tab branch (bar one intentional change — index.lua lazy-loads the mode helpers).

The idea

Full architecture & rationale — controllers, policies, the Waterfill solver, and the policy DSL it unlocks — is written up in Beyond-All-Reason#8018: Game Controllers & Policies. Short version:

The engine stops being the economy authority and becomes the economy data plane for team redistribution. It keeps measuring (income, pull, expense, per-frame excess) and exposes that state through an API. A registered synced-Lua controller pulls a snapshot on its own cadence, runs redistribution, and writes back its own economy stats directly. Unit transfers, team giveaways (GiveEverythingTo), and /take are replaced by game-side gadgets; native overflow sharing is the one piece behind a flag — nativeExcessSharing = false hands it to the Lua controller.

On top of that boundary, sharing is configured by modes — named presets that set, lock, and hide the individual modoptions. The lobby (Chobby) presents them; the game enforces them. Each modoption stays cardinal (one knob, one behavior) so modes compose them freely.

Modes

Enabled (default) — all sharing on, no tax. Today's game, unchanged.
image

Disabled — no unit or resource sharing
image

Easy Tax — anti-co-op preset. Taxes resource sharing, assist, and resurrection; gifted eco buildings are stunned and mobile constructors build-delayed, so you can't dodge the tax by handing over production. /take runs on a stun delay.
image

Tech Core — tech levels gate what you can build; you raise your level by constructing Keystone buildings. Unit sharing and resource tax both scale with tier (e.g. constructors become shareable at T2; tax eases as you climb). /take runs on a 60s delay for Resource buildings (the Take Delay Category in the screenshot below).
image

Customize — every knob editable; roll your own policy.

Note: This is the one mode that preserves the previous mode's values when switching to it, so you can switch from tech core to customize and customize will behave exactly like tech core.

For players and mode developers, Customize provides a lot of benefits for this design:

  1. Removes a lot of complexity from the other modes, allowing us to hide/lock the opinionated mode without impacting customization of any new capabilities those modes may bring to the table.
  2. Lets people roll their own fully customizable mode, if they want.
  3. Gives us all the knobs needed to prove that each diverse mod option is actually orthogonal during testing.
  4. Lets users intuitively understand how this works under the covers and that the individual mod options are the implementation details for each top-level mode.
image

Other changes

  • Geo/Mex upgrades fixed (credit Hobo): the unit-sharing filter now lets "Utility" (resource) buildings transfer, so you can upgrade an ally's mex. Could become its own toggle later (Try to merge master into gl4cus #1040), out of scope here.
  • /take moved into the game (was engine-native), which is what enables the delay/category take modes above.
  • Invalid-unit feedback: units a mode disallows show in tooltips and highlight when you hover an ally in the player list.

Demos

LLM usage

Tons of AI usage, but this started on much earlier models so I really had to beat it into shape and the code is clearly my style of decompositional functional programming, and that doesn't happen accidentally.

keithharvey and others added 21 commits July 17, 2026 01:14
…ring

Renames spec/builders/{spring->engine}_{,un}synced_builder.lua + their
builder_specs, Builders.Spring->Builders.EngineSynced,
Builders.SpringUnsynced->Builders.EngineUnsynced, @Class names, and all
call sites. The renamed builders own every Engine-related test edit so no
two prereqs touch one file:
  - engine_synced_builder.lua: gamedata/system.lua defs mock aliases
    Engine.{Shared,Synced,Unsynced} + BAR to the _G.Spring/_G.BAR mocks
  - engine_unsynced_builder.lua: widget sandbox gets env.Engine; capture
    spies install on Engine.Shared.*

Prefix branch -> lands in fmt once, every leaf+mig inherits it.

Recovered from origin/mig-spring-split@4e25bfe82a (branch lost in a rename);
files transplanted verbatim (formatting is normalized by run_fmt).
Add Utilities, I18N, Debug, Lava, and GetModOptionsCopy to the
System tables in luaui/system.lua and luarules/system.lua so that
widgets and gadgets can access them after detach-bar-modules moves
them off the Spring table.

Also create .emmyrc.json (the EmmyLua analyzer config) with the
detached modules in the globals list, plus type stubs for LSP/CLI
support. The .emmyrc.json content matches what
vscode-recommended-extensions ships, with 5 extra globals
(Utilities/Debug/Lava/GetModOptionsCopy/I18N) that only become
real top-level identifiers after detach-bar-modules runs. When
vscode-recommended-extensions has already merged, -Xtheirs in the
cherry-pick keeps this version (the superset).

# Conflicts:
#	.emmyrc.json
Restructures the 20 files under luaui/Tests/, luaui/TestsExamples/,
plus the headless-only common/testing/infologtest.lua, from bare-
global hook declarations to a return-table shape. Updates the
dbg_test_runner widget to read test hooks from the returned table.

Motivation: the pre-existing shape required the test files to run
under setfenv(chunk, testEnvironment) and define `function test()`,
`function setup()`, etc. as bare module-level globals that setfenv
redirected into the environment. That works at runtime but emmylua
can't model the sandboxing — it sees 20+ files declaring project-
wide globals like `test`, `setup`, `skip`, `cleanup`. To keep
emmylua happy, .emmyrc.json had to blacklist both test directories
under workspace.ignoreDir — a kludge on clearly-ours code. Lives on
its own leaf so the convention change can be discussed in isolation.

Minimal shape change per file — just prepend `local` to each top-
level `function` declaration, and append a final `return { ... }`
block listing whichever lifecycle hooks (skip/setup/test/cleanup)
that file actually defines. Original indentation and formatting
preserved (no stylua reformatting noise — the fmt transform runs
after this one in the mig pipeline).

Runner patch — luaui/Widgets/dbg_test_runner.lua, loadTestFromFile:
  - capture the return value of pcall(chunk)
  - require it to be a table
  - merge its keys into testEnvironment so runTestInternal still
    reads bare `skip`/`setup`/`test`/`cleanup` under setfenv
Vendored LuaCATS annotations for busted/luassert to provide
IntelliSense for the unit-test surface. Lives on its own leaf so the
discussion around 'vendoring LuaCATS types' can happen in isolation —
prior pushback on the same direction in an earlier unit-testing PR
makes this the right place to litigate it rather than burying it in a
broader env commit.

Why vendored instead of declared as a Lux dep: Lux does not yet
support pulling LuaCATS annotations from library deps, and quick
attempts to wire this up in Lux failed. Upstream tracking issue:
lumen-oss/lux#953 — once that lands, these
directories should be deleted in favor of declaring busted as a
normal Lux dev-dep.

Sources (pinned SHAs):
  - types/busted/   https://github.com/LuaCATS/busted
                    @ 5ed85d0e016a5eb5eca097aa52905eedf1b180f1
  - types/luassert/ https://github.com/LuaCATS/luassert
                    @ d3528bb679302cbfdedefabb37064515ab95f7b9

See types/busted/provenance.md and types/luassert/provenance.md for
per-directory upstream refs + license status.
…ixes

Human-curated environment that, together with the LLM type-triage pass
(fmt-llm), drives emmylua_check to zero on the migrated tree. Per-change
rationale lives in PR #7447 review comments.

- .emmyrc.json globals + diagnostics; types/* stubs; busted mock; CI gate
- forward-decl / assertEqual declarations; reverted orphaned kikito loader
- rationale-comment strip; types/IntegrationTests rename
- deterministic pins for type-triage leftovers the LLM mishandles on big
  files (multi_attack opts, HighlightUnit forward-decl, ripairs suppress,
  gui_pip gameFrame use-before-declare)
- json.lua forward-decl tidy (relocate null, drop dead decode_scan*)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
IsDevModeCached (upstream #6918) references `utilities` inside its own
table constructor, where the local is not yet in scope — Lua resolves
those reads as GLOBALS, so the first real call would index nil. Dormant
today only because nothing calls it. Forward-declare the local so the
closure captures it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0.22.0's analyzer resolves a local inside its own table constructor, so
constructor-self-reference globals — a real dormant-crash class (see the
springFunctions.lua fix) — passed CI silently. 0.24.0 catches them; the
whole workspace surfaces exactly the four occurrences of that one bug,
fixed in the previous commit, so the stricter gate lands green. Also
tracks the upstream release asset rename (arm64 -> aarch64).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gui_flowui.lua: Draw.Button uses `opaque` — Draw.Element's 17th
parameter, which Button never had; the global read was always nil.
Pinned false (behavior-identical) until upstream decides whether Button
should expose an opaque mode.

snd_notifications.lua: `customNotifications` is persisted by
GetConfigData but never declared or assigned anywhere. Declared nil so
the round-trip is explicit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generated by parallel claude-sonnet-4-6 workers dispatched by
scripts/codemod/llm-type-triage.sh, applying fixes per SKILL.md categories.
Single pass, no iteration — categories that don't shrink the count
are a signal that SKILL.md needs a new rule.
@keithharvey keithharvey mentioned this pull request Jul 22, 2026
@keithharvey

Copy link
Copy Markdown
Collaborator Author

Closing: the sharing_tab branch head is the identical commit to sharing/05-game-modes-export — this monolithic PR is fully covered by the sharing stack (#8411): #8125#8126#8407#8062#8063#8064#8095, with #8408 (The Modules Format) stacked on top. Review proceeds on the stack.

@keithharvey

Copy link
Copy Markdown
Collaborator Author

Feature tracking moved to #8412; review and merge proceed on stack #8411.

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