docs: handoff for the VTank-class plugin automation milestone

The requirements research from 2026-07-29 was nearly lost: it lives in a
session titled "graphics" because it was one strand of a session about
something else, and could not be found again by any search. The research
itself was committed (6077ce4d) and survived; this makes it findable and
usable by a session picking the work up cold.

Contents: reading order, the architectural conclusion not to relitigate
(VTank's meta FSM, expressions and loot engine are plugin-land, not
host-land; the K2 headless triad is already the right substrate), the
five dependency-ordered steps, every relevant file path, and the project
rules that bind the work.

Two things the handoff adds beyond relaying the research. First, a
changed-since section: three of the research's "gap" rows have closed —
vendor landed 2026-08-08, fellowship 2026-08-12, secure trade 2026-08-14 —
so step 4's substrate is materially stronger than when the plan was
written, and §3's gap table is the part that has aged. Second, every path
is verified against the live tree as of today rather than copied forward:
WorldEntitySnapshot is still exactly four fields, IPluginHost is unchanged,
there is still no enchantment-enumerating view and no point-goal movement
primitive, and IHeadlessBotPolicy is internal to AcDream.Headless so step 1
mirrors its shape rather than re-exporting the type.

All 30 path references were checked programmatically. Also records that
claude-memory/ is a junction that resolves in the main checkout but not
inside a worktree, which would otherwise read as a broken pointer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-20 15:50:58 +02:00
parent c254fea83d
commit 690f21889e

View file

@ -0,0 +1,211 @@
# Handoff — VTank-class plugin automation milestone
**Written 2026-08-20 for a fresh session picking this up cold.**
You are inheriting a completed requirements-research phase and an unstarted
implementation. Nothing has been built yet. The research is thorough and was
done at `xhigh` effort against primary sources — **read it before designing
anything, and do not re-derive it.** This document tells you where everything
is, what has changed since the research was written, and what to do first.
---
## 1. Start here, in this order
| # | Path | Why |
|---|---|---|
| 1 | [`docs/research/2026-07-29-vtank-plugin-automation-requirements.md`](2026-07-29-vtank-plugin-automation-requirements.md) | **The research.** 384 lines. Full VTank capability inventory, the implied host-API surface, mapping to acdream, and the 5-step milestone. |
| 2 | [`docs/plans/2026-07-29-post-vulkan-work-intake.md`](../plans/2026-07-29-post-vulkan-work-intake.md) | Where the milestone is filed (C-bucket candidate), line 35. |
| 3 | `claude-memory/project_plugin_requirement.md` (see note below) | Why plugins are a day-1 architectural constraint, not a nice-to-have. |
| 4 | `CLAUDE.md` § "Code Structure Rules" rule 3, and § "UI strategy" | The binding constraints on this work (see §6 below). |
Rows 12 are committed to the repo. Paths verified 2026-08-20.
> **`claude-memory/` is a junction, not tracked content.** It resolves in the
> main checkout (`C:\Users\erikn\source\repos\acdream`) but **not inside a git
> worktree**, and `git ls-files claude-memory/` returns nothing. The files
> really live under
> `C:\Users\erikn\.claude\projects\C--Users-erikn-source-repos-acdream\memory\`.
> If you are working in a worktree and a `claude-memory/...` path does not
> resolve, that is why — read it from the main checkout or the real path.
---
## 2. The architectural conclusion — do not relitigate
VTank's meta state machine, expression language and loot-rule engine are
**plugin-land, not host-land.** VTank itself was built on Decal's primitives;
acdream ships the equivalent primitive layer and a VTank-like engine then
becomes an acdream plugin — potentially file-compatible with `.met` / `.nav` /
`.utl`, whose encodings the research already decodes.
The second conclusion: **the K2 headless-bot triad is already the right
substrate.** Synchronous borrowed reads, generation-gated typed commands with
attempt semantics, and an ordered delta stream are exactly what a VTank-class
engine needs, and VTank's 293 ms meta tick maps cleanly onto `Tick`. So this
milestone is largely a bridging and query-surface exercise, not new
architecture.
---
## 3. The five steps (dependency-ordered)
1. **Plugin↔Runtime bridge — the enabler, gates everything else.** Mirror the
K2 triad into BCL-only `Plugin.Abstractions`: per-plugin
`Tick(view, commands)`, generation-gated command groups, ordered event
observer. This upgrades plugins to headless-bot parity.
2. **Entity/property query surface.** Names, classification, weenie type,
physics position on entity snapshots; query verbs; per-object property bags
in the retail key space; ID-request command + ID-arrived event.
3. **Spell/enchantment surface.** Enumerable active enchantments (spell id,
layer, seconds remaining), can-cast prediction, explicit cast-on-target,
cast-outcome events.
4. **Interaction/transaction commands.** use-by-id, apply-on, give, container
take-specific, salvage, vendor buy/sell — over the existing
one-transaction gate, with receipts as events.
5. **Nav/move-to layer.** Point-goal movement with arrival/stuck/off-course
events plus a server-confirmed-arrival variant, follow-entity, jump.
(1) gates all. (2) and (3) are independent once (1) lands. (5) is last and is
**the only genuinely new machinery** — everything else is exposure of state
that already exists Runtime-side.
---
## 4. What changed since the research was written
The research is dated 2026-07-29. Three weeks and several campaigns have
landed since, and **three of its "gap" rows have closed**. Verified today:
| Research said | Reality on 2026-08-20 |
|---|---|
| "vendor = M4 Slices 56 in flight" | **Landed**, user-accepted 2026-08-08. `RuntimeVendorRangeQuery`, `VendorShopItemMaterializer`. The six-slice world-interaction program is COMPLETE. |
| "Fellowship state: not in Runtime views yet" | **Landed.** Campaign FA code-complete 2026-08-12: `RuntimeFellowshipState`, `RuntimeAllegianceState`. |
| (not mentioned — postdates it) | Secure trade shipped 2026-08-14: `RuntimeTradeState`. |
**Net effect: step 4's substrate is materially stronger than when the plan was
written.** Re-read §3 of the research against the live tree before scoping —
its gap table is the one part that has aged.
Still true, verified today:
- `WorldEntitySnapshot` is still exactly four fields —
`(uint Id, uint SourceId, Vector3 Position, Quaternion Rotation)`. The
step-2 gap is real and unchanged.
- `IPluginHost` still exposes only `{ HasUi, Log, State, Events, Selection, Ui }`.
- There is **no** enchantment-enumerating view; the state lives in
`RuntimeCharacterState` / `GameRuntimeGameplayViews`.
- There is **no** point-goal movement primitive. Movement is WASD-intent-shaped.
---
## 5. Every file you will need, verified 2026-08-20
**The plugin API you are extending** (BCL-only — see §6):
```
src/AcDream.Plugin.Abstractions/IPluginHost.cs <- the surface to grow
src/AcDream.Plugin.Abstractions/IGameState.cs
src/AcDream.Plugin.Abstractions/IEvents.cs
src/AcDream.Plugin.Abstractions/ISelectionService.cs
src/AcDream.Plugin.Abstractions/IUiRegistry.cs <- AddMarkupPanel; already a better-typed "Meta Views"
src/AcDream.Plugin.Abstractions/IAcDreamPlugin.cs
src/AcDream.Plugin.Abstractions/IPluginLogger.cs
src/AcDream.Plugin.Abstractions/WorldEntitySnapshot.cs <- the 4-field snapshot to enrich
```
**The Runtime surface you are mirroring** (all three interfaces are `public`):
```
src/AcDream.Runtime/GameRuntimeViews.cs :259 public interface IGameRuntimeView
src/AcDream.Runtime/GameRuntimeCommands.cs :489 public interface IGameRuntimeCommands
src/AcDream.Runtime/GameRuntimeEvents.cs :100 public interface IRuntimeEventObserver
src/AcDream.Runtime/GameRuntimeGameplayViews.cs gameplay projections incl. enchantments
```
**The pattern to copy** — note `IHeadlessBotPolicy` is `internal` to
`AcDream.Headless`, so you are mirroring the *shape*, not re-exporting the type:
```
src/AcDream.Headless/Policies/HeadlessBotPolicy.cs :8 internal interface IHeadlessBotPolicy
:12 void Tick(IGameRuntimeView, IGameRuntimeCommands)
```
**Runtime gameplay state owners** (what step 24 will expose):
```
src/AcDream.Runtime/Gameplay/RuntimeCharacterState.cs vitals/skills/spellbook/enchantments
src/AcDream.Runtime/Gameplay/RuntimeInventoryState.cs
src/AcDream.Runtime/Gameplay/RuntimeActionState.cs selection/combat/cast intent, transaction gate
src/AcDream.Runtime/Gameplay/RuntimeFellowshipState.cs (new since research)
src/AcDream.Runtime/Gameplay/RuntimeAllegianceState.cs (new since research)
src/AcDream.Runtime/Gameplay/RuntimeTradeState.cs (new since research)
src/AcDream.Runtime/Gameplay/RuntimeVendorRangeQuery.cs
src/AcDream.Runtime/Gameplay/VendorShopItemMaterializer.cs
```
**Plugin loading/hosting**:
```
src/AcDream.Core/Plugins/PluginLoader.cs
src/AcDream.Core/Plugins/LoadedPlugin.cs
src/AcDream.Core/Plugins/PluginAssemblyLoadContext.cs
src/AcDream.Plugins.Smoke/SmokePlugin.cs <- the worked example
```
**Domain background** (read on demand — junction, see the note in §1):
```
claude-memory/project_modern_runtime_architecture.md Slice-J ownership truth
claude-memory/project_linux_headless_bots.md Slice K; the BINDING #368 contract
claude-memory/project_interaction_pipeline.md use / pickup / appraisal flow
```
---
## 6. Constraints that bind this work
1. **`AcDream.Plugin.Abstractions` is BCL-only.** No App namespaces, no
Runtime types leaking through, no third-party packages. Plugin gameplay UI
goes through `IUiRegistry.AddMarkupPanel` and nothing else. This is what
keeps plugins insulated from presentation churn — see CLAUDE.md rule 3.
2. **Hosts give Runtime ONE of everything** — the BINDING #368 contract in
`claude-memory/project_linux_headless_bots.md`. Read it before adding a
second anything.
3. **Every C-bucket item gets a brainstormed spec before code** — the intake
doc's own sequencing note, and the roadmap rules in CLAUDE.md. Use
`superpowers:brainstorming`, then `superpowers:writing-plans`.
4. **This is not the active milestone.** M4 "Live in the world" is current.
This is filed as a post-M4 C-bucket candidate. Confirm with the user that
they want it started before doing anything beyond the spec — CLAUDE.md's
one-active-milestone rule exists specifically to prevent this kind of drift.
5. **No workarounds without explicit approval**, and any retail deviation
introduced gets its row in
`docs/architecture/retail-divergence-register.md` in the same commit.
---
## 7. First action
Read the research end to end, then re-verify its §3 gap table against the live
tree (three rows are already stale — see §4). Then bring the user a
brainstormed spec for **step 1 only**. Step 1 gates everything else, it is the
smallest coherent slice, and getting the bridge shape wrong is the one mistake
that would be expensive to undo.
Do not start with the nav layer, however tempting — it is step 5 for a reason.
Route automation needs combat and loot reads to decide when to move.
---
## 8. Provenance
- Research commit: `6077ce4d` — *"docs: VTank requirements research — the
plugin-automation milestone model"*, 2026-07-29, authored Fable 5, `xhigh`.
- Originating session: `local_dce33067-349e-45dd-916f-479bfae6cbc6`, titled
**"graphics"**, branch `claude/git-sync-status-5fb1d2`, worktree
`peaceful-blackburn-5333f0`. The misleading title is why it could not be
found by search — the VTank research was one strand of a session about
something else entirely.
- Related sessions, if the VTank *content* is ever needed rather than the
acdream plan: `local_79a15007` (`repos/metas` — authoring VTank `.af` metaf
scripts) and `local_19297181` (`dereth-workspace` — code consuming
`ILootRuleProcessor` / VirindiTank loot rules).
- The research's own source list — Wayback wiki snapshots plus `metaf`,
`virindi-public-clone`, `ACE.BaseMod`, `vtank-routes`, `vtank-loot-profiles`
— is at the end of the research doc. The live virindi.net wiki is
**unreachable** (self-signed TLS; the HTTP wiki returns a database error),
so use the Wayback snapshots cited there rather than trying the live site.