docs: FA6 — ledger row + gate script §FA6 (fellowship PASSED live, allegiance deferred)
Plan ledger: fellowship two-session automated gate PASSED live 2026-08-12 (five of six runs reproduced the decisive cross-session assertion); the allegiance bot gate is DEFERRED behind AllegianceGateEnabled=false pending docs/ISSUES.md #384, with commit citations for every fix this slice landed (confirmation relay, name-matched proximity, the fellowship-only finalization). Gate script §FA6: the fellowship automated-gate recipe + actual PASSED result (the two-session config, the six proof points per stage, the literal decisive-assertion log lines), the allegiance deferral writeup, and a new [TWO-CLIENT] manual step (25) the user's own connected gate can run to help disambiguate #384 (ACE-side rule vs wire-builder defect vs harness-specific drop) using two real graphical clients instead of the testaccount/testaccount2 pair. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
022b1844e1
commit
01fafe7b37
2 changed files with 164 additions and 2 deletions
File diff suppressed because one or more lines are too long
|
|
@ -4,7 +4,10 @@
|
|||
with `ACDREAM_LIVE=1` against the local ACE server (`testaccount` /
|
||||
`+Acdream`). Anything marked **INERT** is authored and clickable but
|
||||
deliberately does nothing yet — that is the correct, contracted behavior
|
||||
for this slice (D1), not a bug.
|
||||
for this slice (D1), not a bug. **FA6's bot-vs-ACE fellowship gate PASSED
|
||||
live 2026-08-12 (§FA6 below) and needs no connected re-gate; its
|
||||
allegiance half is DEFERRED (`docs/ISSUES.md` #384) with one
|
||||
`[TWO-CLIENT]` manual step in §FA6 that can help settle it.**
|
||||
|
||||
FA3 is the panel SHELL only: mount, F3/F4 open paths, tab switching, all
|
||||
four pages' empty states, and Friends/Squelch read-only lists. Fellowship
|
||||
|
|
@ -750,3 +753,162 @@ from the steps above, or a pre-existing allegiance)
|
|||
AD-86).
|
||||
- Swear's missing "target is a player" enable-rule check (register row
|
||||
AD-84) — a cosmetic superset-of-retail gap, not a wire-behavior bug.
|
||||
|
||||
---
|
||||
|
||||
## FA6 — the bot-vs-ACE two-session gate
|
||||
|
||||
Unlike FA3-FA5, this is not a graphical-client gate: no window is
|
||||
launched. The coordinator runs `acdream-headless run` with a config
|
||||
declaring TWO sessions — `testaccount`/`+Acdream` as the fellowship
|
||||
LEADER/allegiance PATRON, `testaccount2` as the fellowship RECRUIT/
|
||||
allegiance VASSAL — both selecting policy id `fellowship-allegiance-gate`
|
||||
with `role: "leader"`/`role: "recruit"`. Both sessions run in the SAME
|
||||
process, ticked sequentially on one dedicated update thread.
|
||||
|
||||
### Automated fellowship gate — the shipped, passing part
|
||||
|
||||
**Recipe:**
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"sessions": [
|
||||
{
|
||||
"id": "fa6-bot-a-leader",
|
||||
"endpoint": { "host": "127.0.0.1", "port": 9000 },
|
||||
"account": "testaccount",
|
||||
"character": { "name": "+Acdream" },
|
||||
"policy": { "id": "fellowship-allegiance-gate", "role": "leader" },
|
||||
"credential": { "provider": "environment", "reference": "FA6_BOT_A_PASSWORD" }
|
||||
},
|
||||
{
|
||||
"id": "fa6-bot-b-recruit",
|
||||
"endpoint": { "host": "127.0.0.1", "port": 9000 },
|
||||
"account": "testaccount2",
|
||||
"character": { "index": 0 },
|
||||
"policy": { "id": "fellowship-allegiance-gate", "role": "recruit" },
|
||||
"credential": { "provider": "environment", "reference": "FA6_BOT_B_PASSWORD" },
|
||||
"characterOptions": { "FellowshipAutoAcceptRequests": true }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The Recruit session's `character` selector deliberately does NOT hard-code
|
||||
a name — `{"index": 0}` picks the first available character on
|
||||
`testaccount2`, and the Leader bot discovers that character's real name
|
||||
live (`FellowshipAllegianceGateCoordinator.RecruitCharacterName`, set by
|
||||
the Recruit bot's own `HeadlessSessionHost` the instant CharacterList
|
||||
selection resolves it) rather than trusting a config-file guess. Run it:
|
||||
`acdream-headless run --config fa6-gate.json` with `FA6_BOT_A_PASSWORD`/
|
||||
`FA6_BOT_B_PASSWORD` set in the environment. The process is
|
||||
self-terminating — every policy stage carries its own timeout, and the
|
||||
run ends (gracefully, with ACE-confirmed per-character logout) on its own
|
||||
once both bots reach `Done` or fault. Do not `timeout`/Ctrl+C the process
|
||||
mid-run: an external kill during an in-world session leaves ACE holding a
|
||||
stale session for ~3 minutes (CLAUDE.md's documented logout-before-
|
||||
reconnect discipline; one of this slice's OWN runs discovered this
|
||||
firsthand from wrapping a probe run in bash's `timeout`, not from the
|
||||
gate's own code path).
|
||||
|
||||
**What the fellowship gate proves, per stage:**
|
||||
|
||||
1. **Proximity.** The Leader sends retail's admin `@teleallto` (no target
|
||||
= "teleport everyone online to me") on a 5 s retry, then polls
|
||||
`RuntimeFriendlyTargetQuery.FindPlayerByName` for the Recruit bot's
|
||||
discovered name specifically — NOT the ambiguous "nearest any player"
|
||||
query, which a live run found picks up a stray third character on a
|
||||
shared ACE dev instance if one happens to be online nearby.
|
||||
2. **Create + recruit.** `Fellowship.Create` then `Fellowship.Recruit`
|
||||
against the name-matched guid.
|
||||
3. **The decisive assertion.** The Recruit bot's OWN
|
||||
`RuntimeFellowshipState` — a completely separate process's canonical
|
||||
Runtime owner, not the Leader's local echo — flips
|
||||
`IsInFellowship=true`, `MemberCount=2`, `LeaderGuid=<Leader's guid>`.
|
||||
This is the proof that `0x02BE`/`0x02C0` inbound reached a real second
|
||||
client, not just that the Leader's own send succeeded.
|
||||
4. **D4 panel-open + vitals.** The Leader declares `SetPanelOpen(true)`
|
||||
(`0x00A6`) and asserts the Recruit's own fellowship member row already
|
||||
carries nonzero vitals (`MaxHealth`) — headless bots have no panel to
|
||||
freeze/unfreeze, so this proves the declaration sends and that vitals
|
||||
data is present, not the freeze-while-closed half of D4 (that remains
|
||||
a graphical-client-only observation, FA4's own owed connected gate).
|
||||
5. **Mid-flow reconnect.** Both bots reconnect
|
||||
(`commands.Session.Reconnect`) after establishing, then assert the
|
||||
fellowship state re-seeds from scratch (a fresh generation clears
|
||||
`RuntimeFellowshipState` per FA2 D2) — proving reconnect-idempotence
|
||||
over the real wire, with a genuine second account watching.
|
||||
6. **Teardown.** The Leader disbands (`Fellowship.Quit(disband: true)`);
|
||||
both bots assert their own `IsInFellowship` clears.
|
||||
|
||||
**Result — PASSED, 2026-08-12 (five of six live runs; the sixth, run 2,
|
||||
hit a since-fixed wrong-target bug before the decisive stage was even
|
||||
reached):**
|
||||
|
||||
```
|
||||
[fa6-recruit] DECISIVE ASSERTION PASSED: own RuntimeFellowshipState
|
||||
flipped IsInFellowship=true, MemberCount=2, LeaderGuid=0x5000000A —
|
||||
recruit inbound path reached THIS process's own Runtime owner
|
||||
[fa6-leader] panel-open declared; recruit vitals name='+Horan'
|
||||
maxHealth=201
|
||||
```
|
||||
|
||||
Two real defects surfaced and were fixed IN this slice, both now covered
|
||||
by conformance tests: headless hosts silently dropped every server-driven
|
||||
confirmation (`HeadlessSessionHost.OnConfirmationRequest` was `null`); and
|
||||
`RuntimeFriendlyTargetQuery.FindClosestOtherPlayer`'s "nearest any player"
|
||||
query picked up a stray third character (`+Je`, `0x50000001`) instead of
|
||||
the actual Recruit bot after `@teleallto`, fixed by the name-matched
|
||||
`FindPlayerByName`.
|
||||
|
||||
### Allegiance bot gate — DEFERRED (docs/ISSUES.md #384)
|
||||
|
||||
**Status: not shipped as an automated gate.** The allegiance half of the
|
||||
SAME policy classes (Leader's `WaitForVassal`; Recruit's `Swear`/
|
||||
`WaitSwornSeed`/`Break`/`WaitBrokenSeed`) is fully written and wired —
|
||||
proximity, the `0x001D` swear send, a confirmation-relay seam on the
|
||||
Leader (the would-be patron, per `docs/research/2026-08-11-fa-allegiance-
|
||||
wire.md` §1.3's "Target (would-be patron)" steps 4-7), the decisive
|
||||
`TotalVassals`/`TryGetPatron` assertions, break, and reconnect-idempotence
|
||||
— but is gated OFF by default (`AllegianceGateEnabled = false` in both
|
||||
policy classes) because it has never actually completed over the wire.
|
||||
Six live runs against local ACE all showed the same symptom: ACE returns
|
||||
**nothing** to the swear — no `0x0274` confirmation, no `0x0020` tree
|
||||
update, no WeenieError — confirmed at 0.005 m separation between the two
|
||||
bots (ruling out retail's 2.0 m swear-distance gate). See `docs/ISSUES.md`
|
||||
#384 for the full evidence trail and register row AD-87 for the
|
||||
divergence this creates (the allegiance wire/state code is unit-tested
|
||||
and locally-echoed but not wire-verified end-to-end).
|
||||
|
||||
**[TWO-CLIENT] Manual counterpart for the user's connected gate** — this
|
||||
is the step that can settle #384 outside the headless harness:
|
||||
|
||||
25. With TWO graphical clients logged into different characters near each
|
||||
other (the existing FA5 `[TWO-CLIENT]` swear steps 14-16 already
|
||||
exercise this UI path), have character A select character B and click
|
||||
Swear. **Report specifically:** does B's client show the incoming
|
||||
"accept swear" confirmation dialog at all? If B accepts, does A's
|
||||
Allegiance page then show B in A's vassal list, and does B's page show
|
||||
A as patron? If the SAME silent non-response reproduces in the
|
||||
graphical client (no dialog ever appears on B's side, no error on
|
||||
A's), that points at an ACE-side rule or a genuine defect in acdream's
|
||||
`0x001D` wire builder rather than anything specific to the headless
|
||||
harness — the two clients are real user accounts, not `testaccount`/
|
||||
`testaccount2`, which also rules out any GM-flag-specific explanation.
|
||||
If it works normally in the graphical client, the symptom is scoped
|
||||
to `testaccount`/`testaccount2` specifically (a GM flag, a rank/self-
|
||||
allegiance precondition, or state left over from this session's
|
||||
testing) — re-run the headless gate with a different account pair
|
||||
before reopening #384 as a real wire bug.
|
||||
|
||||
### Explicitly NOT in scope for this gate
|
||||
|
||||
- A fully verified allegiance bot gate — deferred to #384; do not report
|
||||
its absence as a regression, and do not re-run the headless allegiance
|
||||
path repeatedly hoping for a different result without new information
|
||||
(six identical live results is enough evidence, not bad luck).
|
||||
- Kick — no test exercises it (would need a THIRD account to have a
|
||||
vassal to kick that isn't also the tester).
|
||||
- Kick/kick-confirmation UI — FA5's own `[TWO-CLIENT]` scope, unrelated
|
||||
to this bot gate.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue