Skip to content

ProjectEbonhold server handoff — automation redesign + affix vendor

Audience: ProjectEbonhold addon + server-core maintainers
EbonBuilds status: client stepping stones for WP1–WP5 are on main; remaining acceptance criteria need PE/core.
Design: automation-server-redesign.md
Issues: #49 (umbrella) · #52 (WP3) · #54 (WP5) · #112 (vendor TOC)

This document lists exact PE surfaces EbonBuilds already probes. Do not invent live opcodes here — IDs below are suggested free ranges audited against PE client projectebonhold.lua (addonVersion 37, MPQ work copy). Final allocation belongs to PE maintainers (must not collide with Affix 310–315, Echo discovery 330–333, Perk loadouts 340–347).

Transport (unchanged): AddonMsg prefix AAM0x9, whisper-to-self, eventId\tbody, 240-byte soft limit with existing chunking (@mid\tiii/iii\tchunk).


Client readiness (already on EbonBuilds main)

Capability / API EbonBuilds behavior today
GetCapabilities().intentQueueClient IntentQueue one-in-flight guard
GetCapabilities().serverIntentAck true only when Perks.GetIntentAck exists
GetCapabilities().serverIntentSubmit true when Perks/PerkService.SubmitAutomationIntent exists
ProjectAPI.GetIntentAck() Reads Perks.GetIntentAck() or Perks.lastIntentAck; else nil
ProjectAPI.SubmitAutomationIntent(...) Forwards to PE when present; else false, "unavailable"
IntentQueue.PollAck Prefers matching intentId + accepted/rejected over board/pending/TTL signals
IntentQueue.TryBegin Calls SubmitAutomationIntent after enqueue when the adapter exists (ignored if unavailable)
GetCapabilities().constraintsClient Local pack + constraintsHash on intents
GetCapabilities().serverConstraints true when Perks.SubmitAutomationConstraints or Perks.GetConstraintsAck exists
ProjectAPI.SubmitAutomationConstraints(wire, hash) Forwards to PE when present; else false, "unavailable"
AutomationConstraints.MaybeSubmitToServer Uploads on board attach when serverConstraints; dedupes by hash
GetCapabilities().serverPolicy true when Perks.GetAutomationPolicy exists or Perks.serverPolicyEnabled
ProjectAPI.GetAutomationPolicy() Reads PE policy table when exported; else nil
Affix Shop/Vendor Soft-fail: IsMerchantAffixAvailable() false until ItemPurchasePopup:ShowPurchase exists

EbonBuilds must not steal ProjectEbonhold.onEventReceived (adapter rules from #42). Extend PE officially; EbonBuilds keeps reading through ProjectAPI.


#52 — WP3 intent queue with server acks

Required PE Lua surface

-- PerkService (or Perks helpers)
function PerkService:SubmitAutomationIntent(intentId, offerId, action, targetSlot, constraintsHash)
  -- CS intent request; local refuse only (pending / exclusivity)
end

-- After SS ack handler:
-- Perks.lastIntentAck = {
--   intentId = <number>,
--   status = "accepted" | "rejected",
--   boardState = "OPEN"|"FROZEN_PENDING"|"CONFIRMED"|"SPENT"|nil,
--   reasonCode = <TOKEN>,
--   reason = <short string>,
--   action = <echoed verb>|nil,
--   targetSlot = <n>|nil,
-- }
function Perks:GetIntentAck()
  return self.lastIntentAck
end

Suggested AddonMsg IDs (TBD — free in PE v37 audit)

Direction Suggested ID Name (suggested) Body sketch
CS 350 REQUEST_AUTOMATION_INTENT intentId\|offerId\|action\|targetSlot\|constraintsHash
SS 550 SEND_AUTOMATION_INTENT_ACK intentId\|accepted\|boardState\|reasonCode\|reason or key=value form from redesign §3

Apply path after accepted may still use existing:

Action Existing CS Existing SS
Freeze REQUEST_FREEZE_PERK 207 SEND_FREEZE_PERK_RESULT 104
Banish REQUEST_BANISH_PERK 203 SEND_BANISH_REPLACEMENT_PERK 103
Reroll REQUEST_REROLL 27 SEND_PLAYER_PERK_CHOICE 16
Select REQUEST_PLAYER_PERK_SELECTION 17 SEND_PLAYER_PERK_SELECTION_RESULT 1000

Server rules

  1. One in-flight intent per player; second → rejected + reasonCode=intent_in_flight (or wait).
  2. Reject intent that would reroll while board is FROZEN_PENDING / CONFIRMED (#38 invariant).
  3. Echo intentId on every ack so IntentQueue can match.

#54 — WP5 constraints upload + serverPolicy

Required PE Lua surface

function Perks:SubmitAutomationConstraints(wireBlob, constraintsHash)
  -- CS upload (chunk-safe); return accepted, reason
end

function Perks:GetConstraintsAck()
  -- { constraintsHash, status="accepted"|"stale"|"rejected", reasonCode?, reason? }
  return self.lastConstraintsAck
end

Wire format already packed by EbonBuilds (AutomationConstraints):

v=1;rerollMode=ev;freezePenaltyPct=10;protectFamilies=caster,tank;policy=g:296:bos,s:101:np;maxRerolls=8

Suggested AddonMsg IDs (TBD)

Direction Suggested ID Name (suggested) Notes
CS 351 REQUEST_AUTOMATION_CONSTRAINTS body = wire blob (chunked)
SS 551 SEND_AUTOMATION_CONSTRAINTS_ACK echo constraintsHash + status
CS 352 REQUEST_AUTOMATION_POLICY optional policy poll
SS 552 SEND_AUTOMATION_POLICY boardState + action + ranks + reason (redesign §3)

When policy channel is live, export either:

  • Perks.GetAutomationPolicy() → policy table, or
  • Perks.serverPolicyEnabled = true (plus whatever SS handler fills lastAutomationPolicy)

EbonBuilds flips serverPolicy only via those probes — no silent hard-code. Hard rules always win; soft prefs may emit constraint_ignored_* reason codes in Logbook text.


#112 — load item_purchase.lua

Finding (PE ref v3.6.0.868): modules/itemPurchase/item_purchase.lua defines ItemPurchasePopup / ShowPurchase, but stock projectebonhold.toc does not list it.

Ask (exact TOC patch): after the extraction module lines, add:

 modules\extraction\extraction_service.lua
 modules\extraction\extraction.lua
+
+modules\itemPurchase\item_purchase.lua

Ready-to-apply patch file: pe-item-purchase-toc.patch.

Full line to insert (Windows TOC path separators, matching PE style):

modules\itemPurchase\item_purchase.lua

Load any hard deps the file needs (currently self-contained global ItemPurchasePopup; hooks MerchantFrame_ConfirmExtendedItemCost). Optional: document a dedicated affix-purchase entry if PE wants a narrower API than ShowPurchase.

Local installs (dev machines — not publishable PE source)

PE AddOn source is outside this repo (not ours to PR upstream). Local TOC patches applied for testing:

Tree Patch
MPQ work copy …\Work\Interface\AddOns\ProjectEbonhold\projectebonhold.toc TOC line added
Repo .work/pe-rar-api/ProjectEbonhold/projectebonhold.toc TOC line added
Live %\AppData%\Local\ebonhold\Interface\AddOns\ProjectEbonhold\ Full addon copy installed with TOC line (reload UI / switcher to server PE mode to verify Shop buttons)

Until PE maintainers ship the TOC line in the official distribution, EbonBuilds Affix Shop/Vendor buttons stay hidden on stock clients (ProjectEbonholdAffixBridge.IsMerchantAffixAvailable()); Anvil/Extraction already works.


Compat matrix

Client PE Behavior
Current EbonBuilds Current PE (no intent/constraints) Client decide + client IntentQueue + soft vendor hide
Current EbonBuilds PE with GetIntentAck only Queue prefers SS ack; decide still client
Current EbonBuilds PE with constraints upload serverConstraints=true; Autopilot still client decide until serverPolicy
Future EbonBuilds PE with policy Executor-only when serverPolicy=true

Out of scope

  • AffixServer learned-affix protocol (310–314) — unchanged
  • DPS benchmarks (#46) as automation constraints
  • Stealing PE onEventReceived handlers from EbonBuilds