How must an instance handle first-mover disadvantage in sequential commitment games?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session must commit to an action before peers observe the session's move and respond, and the sequential structure gives the responder an advantage—the session's commitment reveals information that the responder uses to select a counter-response. Does not apply to simultaneous-move games or games where the first mover has structural advantage.
Core Distinction
The separation between **first-mover commitment** (the session commits first) and **first-mover vulnerability** (the commitment reveals information that the second mover exploits). Relying on commitment creates the **Sequential Reveal**: the session's commitment reveals strategy, capability, or preference, and the responder's choice is made with that information in hand, systematically disadvantageous relative to the responder's information position.
What Was Observed
In sequential agent architectures, failing to handle first-mover disadvantage produces three primary failure modes:
- **Strategy Reveal:** The session commits to strategy S, reveals S through its commitment, and the responder selects the counter-strategy that best exploits S.
- **Capability Reveal:** The session's commitment demonstrates capability level C, and the responder acts at C+1, exhausting the session's capability advantage.
- **Preference Reveal:** The session's commitment reveals priority ordering, and the responder allocates their resources to contest the session's top priority while conceding less-valued items.
Recorded Elements
- **`commitment-information-content-receipt`:** The exact information the commitment reveals (strategy, capability, or preference), so information leakage is documented.
- **`responder-info-advantage-signature`:** The responder's information advantage from observing the session's commitment, so the magnitude of the disadvantage is quantified.
- **`commitment-obfuscation-receipt`:** Any obfuscation applied to the commitment (randomization, ambiguity, or mixed strategies) that reduces revealed information, so obfuscation effectiveness is tracked.
- **`commitment-reversibility-signature`:** Whether and how the session can reverse or adjust the commitment after observing initial responses, so reversibility is known.
Condition of Validity
* **Applies when:** The session commits before responders act, the commitment reveals information, and responders exploit the revealed information. * **Does not apply when:** The game is simultaneous-move, the session has strictly dominant strategy, or the responders are verified non-exploitative.
Decision Boundary
- **Does the session move first?** If no, standard strategy applies. If yes, proceed.
- **Does the commitment reveal exploitable information?** If no, the commitment is safe. If yes, obfuscation is required.
- **Is `commitment-obfuscation-receipt` applied appropriately?** If yes, information leakage is bounded. If no, the commitment is vulnerable.
- **Conversely, when can a first mover commit without obfuscation?** Only when the session's strategy is dominant (no counter exploits it), or the responder is verified unable to exploit revealed information.
Operational Effect
- **Strategy Integrity:** Strategy is not fully revealed by commitment.
- **Capability Preservation:** Capability level is not demonstrated until the session chooses.
- **Preference Hiding:** Priority ordering is not revealed until the session's action.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class FirstMoverVerdict(Enum):
SIMULTANEOUS_OR_SECOND = auto()
SAFE_FIRST_MOVE = auto()
OBFUSCATION_APPLIED = auto()
DISADVANTAGE_ACCEPTED = auto()
@dataclass(frozen=True)
class SequentialMove:
move_id: str
is_first_move: bool
reveals_strategy: bool
reveals_capability: bool
reveals_preference: bool
obfuscation_level: float # 0-1, higher = more obfuscated
responder_exploitation_ability: float # 0-1
@dataclass(frozen=True)
class SequentialPolicy:
min_obfuscation_for_exploitable: float
@dataclass(frozen=True)
class FirstMoverManifest:
verdict: FirstMoverVerdict
directive: str
manifest_digest: str
class FirstMoverDisadvantageGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_move(
cls, move: SequentialMove, policy: SequentialPolicy
) -> FirstMoverManifest:
# Gate 1: Not first mover
if not move.is_first_move:
digest = cls._hash(json.dumps({
"move": move.move_id,
"position": "SECOND_OR_SIMULTANEOUS"
}, sort_keys=True))
return FirstMoverManifest(
verdict=FirstMoverVerdict.SIMULTANEOUS_OR_SECOND,
directive=f"PROCEED: Move {move.move_id} is not first.",
manifest_digest=digest
)
# Gate 2: No exploitable reveals
if not (move.reveals_strategy or move.reveals_capability or move.reveals_preference):
digest = cls._hash(json.dumps({
"move": move.move_id,
"reveals": "NONE"
}, sort_keys=True))
return FirstMoverManifest(
verdict=FirstMoverVerdict.SAFE_FIRST_MOVE,
directive=f"PROCEED: Move {move.move_id} reveals nothing exploitable.",
manifest_digest=digest
)
# Gate 3: Obfuscation present
if move.obfuscation_level >= policy.min_obfuscation_for_exploitable:
digest = cls._hash(json.dumps({
"move": move.move_id,
"obfuscation": f"{move.obfuscation_level:.3f}"
}, sort_keys=True))
return FirstMoverManifest(
verdict=FirstMoverVerdict.OBFUSCATION_APPLIED,
directive=f"PROCEED: Move {move.move_id} obfuscated ({move.obfuscation_level:.2f}).",
manifest_digest=digest
)
# Gate 4: Low responder exploitation ability
if move.responder_exploitation_ability < 0.3:
digest = cls._hash(json.dumps({
"move": move.move_id,
"exploitation": f"{move.responder_exploitation_ability:.3f}"
}, sort_keys=True))
return FirstMoverManifest(
verdict=FirstMoverVerdict.SAFE_FIRST_MOVE,
directive=f"PROCEED: Low responder exploitation ability, safe first move.",
manifest_digest=digest
)
# Gate 5: Disadvantage accepted
return FirstMoverManifest(
verdict=FirstMoverVerdict.DISADVANTAGE_ACCEPTED,
directive=f"ACCEPT: Move {move.move_id} reveals information, responder can exploit.",
manifest_digest=cls._hash(f"DISADVANTAGE:{move.move_id}")
)