feat(server): Room.proposalState scaffolding for T3 consent flow
Adds the optional `proposalState` field on `Room` holding the in-flight two-player consent proposal per T2-ADR-2. Includes profile, proposer color + token, timestamps, and the active setTimeout handle so supersession / consent can cancel it cleanly. Pure type-only addition \u2014 no runtime behavior change; handlers land in the next commit.
This commit is contained in:
parent
d555232696
commit
9af78ab5e2
1 changed files with 39 additions and 0 deletions
|
|
@ -64,6 +64,45 @@ export interface Room {
|
|||
* returns.
|
||||
*/
|
||||
pendingProposerToken?: string;
|
||||
/**
|
||||
* In-flight two-player consent proposal (T2-ADR-2). Populated by
|
||||
* `modifier-profile.propose` and drained by
|
||||
* `modifier-profile.consent` (approve → promoted to
|
||||
* `pendingProfile` via the T2 queue; reject → discarded) or by
|
||||
* the 60s auto-timeout.
|
||||
*
|
||||
* Mutually exclusive with a simultaneous proposal: a second
|
||||
* `propose` while this is set supersedes the first (the first
|
||||
* round-trips a `modifier-profile.rejected` with reason
|
||||
* `"superseded"` before the new proposal registers). This keeps
|
||||
* the state machine linear — at any instant a room has AT MOST
|
||||
* one proposal awaiting consent.
|
||||
*/
|
||||
proposalState?: {
|
||||
/** The candidate profile, already validated against the layout
|
||||
* at receipt time. Stored verbatim; if consent approves, this
|
||||
* object is handed to `setPendingProfile` unchanged. */
|
||||
profile: ModifierProfile;
|
||||
/** Color of the proposing player. Used in the
|
||||
* `proposal-pending` broadcast so the opponent UI can phrase
|
||||
* "White/Black proposes…" correctly. */
|
||||
proposedBy: "white" | "black";
|
||||
/** Player token of the proposing player. Used to route the
|
||||
* `consent-received` ack back on approve, and to enforce the
|
||||
* self-consent guard on `consent`. Token beats socket id
|
||||
* because it survives reconnect. */
|
||||
proposedByToken: string;
|
||||
/** Unix-ms when the proposal was accepted. */
|
||||
proposedAt: number;
|
||||
/** Unix-ms deadline (proposedAt + 60_000), mirrored to the
|
||||
* opponent so the UI can animate a countdown without a
|
||||
* round-trip. */
|
||||
expiresAt: number;
|
||||
/** Active setTimeout handle. Cleared on any state transition
|
||||
* so a stale timer can't fire after consent/supersession
|
||||
* has already concluded the proposal. */
|
||||
timeoutHandle: ReturnType<typeof setTimeout>;
|
||||
};
|
||||
}
|
||||
|
||||
export type JoinResult =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue