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` /
|
with `ACDREAM_LIVE=1` against the local ACE server (`testaccount` /
|
||||||
`+Acdream`). Anything marked **INERT** is authored and clickable but
|
`+Acdream`). Anything marked **INERT** is authored and clickable but
|
||||||
deliberately does nothing yet — that is the correct, contracted behavior
|
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
|
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
|
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).
|
AD-86).
|
||||||
- Swear's missing "target is a player" enable-rule check (register row
|
- 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.
|
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