Write the play agent target (plan step 16)

The operator redirected the playtest gate on 2026-09-22. Ghostlight's
controller machinery suits offline simulation, not interactive role-play.
One operational agent now runs the table; the Projector and Persona passes
stay exactly as they are.

The target records the rulings (the play authority, actor acts through the
actor's affordances, deferral of L2-L4, D1-D3 and the L1 follow-ups), eight
invariants, the redefined playtest gate, and eleven open questions for the
cut map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-22 00:49:02 +02:00
commit cb0b604ae3

View file

@ -0,0 +1,249 @@
# Ghostlight Dungeon play agent (plan step 16)
## Status
Target, adopted 2026-09-22. Not implemented. The means will be in
`ghostlight-play-agent-cut.md`. This target is the playtest gate. It replaces
library passes L2–L4 and Dungeon passes D1–D3 on the gate's path; those are
deferred by ruling, not dropped (see "Deferred").
## Why
Ghostlight's controller machinery was built for offline narrative generation
and world simulation. It includes the cover partition, grouped cells,
grant-filtered action catalogs per subject, a separate Interpreter pass, and
the elaborator swarm. Those are the wrong compromises for interactive
role-play: today a reply takes minutes, and a player's whole vocabulary is
`world.speak`.
The operator, 2026-09-22:
> the way Ghostlight previously ran is great for offline narrative generation
> and world simulation, but it's the wrong set of compromises for an efficient
> role-playing experience. The Persona stuff is good, we want actors to think
> narratively. All the rest of it can be operated by a single operational
> agent, from dispatching and interpreting Persona turns to prompting the
> player and negotiating the result.
What makes this worth building is where consistency lives. In AI Dungeon it
lives in the context window, so it decays as the story grows. In Ghostlight it
lives in the kernel: typed state, one reducer, affordance preconditions,
outcome bands, and a digest-chained journal. None of that spends a token. A
small local model therefore does only what it is good at, which is judgment
and prose over a bounded context, while the kernel keeps the books.
## Target
A player on one local machine plays a world seeded from a Vault, turn by turn.
The reference machine is Raven's, running Bonsai 2, a Qwen 3.8 quant tuned for
agentic use, with several concurrent slots. One operational agent (the **play
agent**) runs the table: it reads the world, interprets what the player and
the Personas do, commits the consequences through the kernel, dispatches
Personas, and asks the player questions when an outcome needs negotiating.
Personas keep thinking narratively. For each Persona, the existing Projector
renders that subject's own slice of the world into lived prose. The Persona
reads only that prose and writes prose back. Neither the Projector nor the
Persona changes.
### Ownership
- **Dungeon** owns the play agent: its loop, its prompt, its tool catalog, the
turn lifecycle, and the Eve surface. None of it enters the library
vocabulary.
- **The library** gains only consumer-neutral pieces. These are one author
capability for a play authority, a retire primitive, and a callable Persona
turn (Projector then Persona) that does not require the controller runner. A
consumer other than Dungeon could run its own table on them.
- The library keeps everything the play path stops using: cover, grouped
cells, action catalogs, the controller runner, the Interpreter, the elaborator
sweep, and lenses. Offline consumers and simulation still own them.
### One turn
1. The player types. Their text is prose from an actor, exactly as a Persona's
is.
2. The play agent reads a projection of world state rebuilt for this turn. It
interprets the player's prose. Speech commits verbatim through the player
subject's speaking affordance, and acts commit by exercising the player
subject's affordances. The agent may instead **ask the player** something
("what are you offering him?"). A question commits nothing and holds the
turn open.
3. The agent dispatches the Personas who react. They run concurrently, each
through Projector then Persona, reading what they perceived from world
state.
4. The agent interprets each Persona's prose under the same rules as the
player's, and commits its own rulings for anything no actor's affordance
covers.
5. The player sees their projection: their place, who is present, and what
they perceived this turn, with speaker and visible acts, plus any question
the agent is asking.
## Invariants
1. **The kernel is the only writer, and the agent carries no world.** Every
consequence is a library command. The agent's context each turn is built
from world state and the current turn; no transcript is carried across
turns. Test: restart the daemon between two turns, and the second turn's
agent input is byte-identical to the input it would have received without
the restart.
2. **Personas never see structured state or the agent's context.** A Persona's
input is Projector prose. The Projector's input is that subject's own typed
slice (`controllers.rs` `projector_context`). The agent never writes a
Persona's input, so a secret in the agent's context cannot reach a Persona
except through world state that subject holds.
3. **An actor's act goes through that actor's affordance.** An act attributed
to a subject, whether a Persona or the player, commits only as that
subject's `ExerciseDecision`, with preconditions checked and the outcome
band drawn by the kernel. The agent's raw ops are its own rulings: they are
journaled with the play authority as author and never attributed to an
actor. (Operator ruling, decision 1.)
4. **Speech is verbatim.** Speech committed for an actor is a literal span of
that actor's prose, checked in code, not by prompt. This holds for the
player's typed text and for a Persona's output. It keeps the agent from
paraphrasing every actor into its own voice.
5. **One play authority, and only one thing holds it.** The library defines one
consumer-neutral author capability. Its holder may:
- declare in Active without answering elaboration demand;
- reach the whole world, unconfined to a ground;
- advance time.
The elaborator gate is unchanged: elaborator sessions still answer a
boundary or deficit. The agent is Dungeon's detail demand: when the player
walks into the tavern, the agent fills it. (Operator ruling, decision 1.)
6. **Removal is retirement.** A retired subject stays in history, holds no
opportunity, cannot be the actor of a decision, and is never dispatched.
Replay reproduces retirement. A body that matters afterwards is declared as
a resource.
7. **One loop, many backends.** Rust drives every tool round, as it already
does. A local OpenAI-compatible backend returns tool calls inert, as the
connector lane does, and adds no second loop. Routing stays per model
name, so each lane (agent, Projector, Persona, seed) is pointed at a backend
independently.
8. **The player's view is a projection.** Nothing the player is shown is world
truth unless it was committed. The agent's questions are the one thing
shown that is not derived from state.
## Playtest gate
Passes when a human, on a local daemon with every play lane on a local model,
does all of the following:
1. creates a world and seeds it from a Vault;
2. activates it;
3. plays at least these:
- speaks to a Persona and gets a reply in the Persona's own words;
- does something physical that a precondition refuses, and sees why;
- moves to another place;
- is asked a question by the agent and answers it;
- kills or removes a subject, who then never acts again;
4. restarts the daemon mid-session and continues with the world intact.
It proves one player. Hosted play, multiple players, Session Zero's Vault
choice and sliders, and detail rules are not in this gate. Seconds per turn
are **measured and recorded** on Raven's machine. The gate does not set that
number in advance, because nobody has measured Bonsai 2 on this workload yet.
The current baseline is minutes.
## Cut line
Dungeon's play path stops using:
- the owner-only "Let X act" controls and `world.controller.act`;
- automatic tick dispatch through cover cells on the play path;
- the Interpreter pass;
- the per-subject action catalogs;
- elaboration while Active.
Whether these are deleted from Dungeon or merely go unused is for the cut map
to establish, one surface at a time. Deletion is the default where nothing
else consumes the surface.
The library keeps them.
The Claude SDK sidecar stays as the cloud fallback until the local lane has
carried the playtest. It is the only live cloud provider (there is no Codex
subscription and no API budget), so "cloud fallback" means the sidecar. The
decision to delete it comes after the gate. This corrects the 2026-09-22 chat
default, which named the connector lane as the fallback.
## Deferred, by ruling (2026-09-22, decision 3)
Deferred until a consumer that still runs the offline machinery needs them:
- L1.f16, configurable lens sets (operator: yes);
- L1.f1, quarantine-class errors never quarantine;
- L1.f13, seed lane orphans rows;
- L1.f14, controller-work rows never retired;
- L2, per-world evidence binding;
- L3, detail rules;
- L4;
- Session Zero D1–D3.
After the gate, decide whether anything still consumes the controller runner,
cover and lenses. If nothing does, park them at a tag.
Exception: if the cut map finds that L1.f13 bites seeding on the playtest
path, it is in scope, because seeding is on the path.
## Open questions for the cut map
Imagination establishes each of these by probing the Body, and returns forks
with a recommendation.
1. **Where the local backend lives.** It could be a third `InferencePort` in
`ghostlight` following the connector posture (~150 lines), or a connector
behind the shared CultNet connector contract that `state/map.yaml` says
every backend uses. The map also records "a generic OpenAI-compatible
connector is required before third parties use the deployment", so this
pass may be that connector. The handoff says nothing goes into
CodexConnector itself.
2. **What a Persona perceived.** Does the Projector's context already carry
what the subject perceived since its last turn (speech heard, acts seen,
`Seen { by }` knowledge)? If not, what is the smallest addition?
3. **A callable Persona turn.** Projector then Persona currently runs inside
the narrative lane of `ControllerRunner`, with checkpointing. What is the
smallest library surface the play agent can call per subject, and does it
keep resumability?
4. **Exercising on an actor's behalf.** `ExerciseDecision` is admitted for the
subject's controller principal. How does the play authority exercise an
affordance for an actor it dispatched without weakening sealed admission,
given that opportunities and digests are kernel-issued?
5. **The play authority's shape.** Name the capability, where it is granted,
and how the clock capability's precedent maps onto it.
6. **Retirement's shape.** Is it a component op, a declaration, or a subject
state? What do preconditions, opportunity derivation and the Projector read?
7. **The agent's catalog.** The kernel's component ops plus light declarations
(not `declare_affordance`), plus exercise-for-actor, dispatch-Persona,
ask-player and end-turn. Measure the strict-schema size, and say whether a
small model plausibly handles it.
8. **The turn lifecycle.** Where does an open turn (a question outstanding, or
Personas in flight) live, and what survives a restart (invariant 1)?
9. **The Eve play surface.** Place, co-presence, perceived speech with speaker,
displays, the agent's question, and the player's input.
10. **The player's subject.** Does the genesis human subject at the commons
serve, with the agent placing it after seeding?
11. **The player's prose.** Does the player see perceived events as they are,
or rendered into prose by the same Projector a Persona gets? The Projector
renders only committed state, so it satisfies invariant 8, and it gives
the player the narration the play agent does not write. It also costs one
more serial call per turn. Recommend with that cost measured.
## Verification sketch
The cut map owns exact tests. Each invariant gets a check that fails under its
own mutation.
- **Invariant 1:** restart equivalence of the agent's turn input.
- **Invariant 2:** the Persona's request contains no field of structured state
and none of the agent's context.
- **Invariant 3:** an act for a subject not present is refused, and a raw op
never carries an actor attribution.
- **Invariant 4:** a paraphrased quote is refused.
- **Invariant 5:** an elaborator's declaration in Active without an answer is
still refused, and the play authority's is admitted.
- **Invariant 6:** a retired subject gets no opportunity and no dispatch
across a replay.
- **Invariant 7:** a scripted local backend drives a full tool round through
the existing evaluator.
- **Road:** the playtest gate itself, on Raven's machine.