nodeGo header size seenGameInfo = do
    [hasGameInfo, hasRoot, hasSetup, hasMove] <- mapM (hasAny . properties Go) [GameInfo, Root, Setup, Move]
    let setGameInfo       = hasGameInfo && not seenGameInfo
        duplicateGameInfo = hasGameInfo && seenGameInfo
    when (hasSetup && hasMove) dieSetupAndMove
    when duplicateGameInfo warnGameInfo
    when hasRoot           warnRoot

    mGameInfo       <- liftM (\x -> guard setGameInfo >> Just x) (gameInfo header)
    otherGameInfo   <- gameInfoGo
    ruleSet_        <- ruleSet ruleSetGo Nothing header
    action_         <- if hasMove then liftM Right $ move (moveGo size) else liftM Left $ setupPoint pointGo
    annotation_     <- annotation header
    otherAnnotation <- annotationGo
    markup_         <- markup header pointGo
    unknown_        <- unknownProperties
    children        <- gets subForest >>= mapM (\s -> put s >> nodeGo header size (seenGameInfo || hasGameInfo))

    return (Node (GameNode (fmap (\gi -> gi { T.ruleSet = ruleSet_, T.otherGameInfo = otherGameInfo }) mGameInfo) action_ annotation_ { T.otherAnnotation = otherAnnotation } markup_ unknown_) children)
    where
    dieSetupAndMove    = dieEarliest ConcurrentMoveAndSetup    (properties Go =<< [Setup, Move])
    warnGameInfo       = warnAll     ExtraGameInfoOmitted      (properties Go GameInfo)
    warnRoot           = warnAll     NestedRootPropertyOmitted (properties Go Root)
nodeGo header size seenGameInfo = do
    [hasGameInfo, hasRoot, hasSetup, hasMove] <- mapM (hasAny . properties Go) [GameInfo, Root, Setup, Move]
    let setGameInfo       = hasGameInfo && not seenGameInfo
        duplicateGameInfo = hasGameInfo && seenGameInfo
    when (hasSetup && hasMove) dieSetupAndMove
    when duplicateGameInfo warnGameInfo
    when hasRoot           warnRoot

    mGameInfo       <- liftM (\x -> guard setGameInfo >> Just x) (gameInfo header)
    otherGameInfo   <- gameInfoGo
    ruleSet_        <- ruleSet ruleSetGo Nothing header
    action_         <- if hasMove then liftM Right $ move (moveGo size) else liftM Left $ setupPoint pointGo
    annotation_     <- annotation header
    otherAnnotation <- annotationGo
    markup_         <- markup header pointGo
    unknown_        <- unknownProperties
    children        <- gets subForest >>= mapM (\s -> put s >> nodeGo header size (seenGameInfo || hasGameInfo))

    return (Node (GameNode (fmap (\gi -> gi { T.ruleSet = ruleSet_, T.otherGameInfo = otherGameInfo }) mGameInfo) action_ annotation_ { T.otherAnnotation = otherAnnotation } markup_ unknown_) children)
    where
    dieSetupAndMove    = dieEarliest ConcurrentMoveAndSetup    (properties Go =<< [Setup, Move])
    warnGameInfo       = warnAll     ExtraGameInfoOmitted      (properties Go GameInfo)
    warnRoot           = warnAll     NestedRootPropertyOmitted (properties Go Root)
nodeGo header size seenGameInfo = do
    [hasGameInfo, hasRoot, hasSetup, hasMove] <- mapM (hasAny . properties Go) [GameInfo, Root, Setup, Move]
    let setGameInfo       = hasGameInfo && not seenGameInfo
        duplicateGameInfo = hasGameInfo && seenGameInfo
    when (hasSetup && hasMove) dieSetupAndMove
    when duplicateGameInfo warnGameInfo
    when hasRoot           warnRoot

    mGameInfo       <- liftM (\x -> guard setGameInfo >> Just x) (gameInfo header)
    otherGameInfo   <- gameInfoGo
    ruleSet_        <- ruleSet ruleSetGo Nothing header
    action_         <- if hasMove then liftM Right $ move (moveGo size) else liftM Left $ setupPoint pointGo
    annotation_     <- annotation header
    otherAnnotation <- annotationGo
    markup_         <- markup header pointGo
    unknown_        <- unknownProperties
    children        <- gets subForest >>= mapM (\s -> put s >> nodeGo header size (seenGameInfo || hasGameInfo))

    return (Node (GameNode (fmap (\gi -> gi { T.ruleSet = ruleSet_, T.otherGameInfo = otherGameInfo }) mGameInfo) action_ annotation_ { T.otherAnnotation = otherAnnotation } markup_ unknown_) children)
    where
    dieSetupAndMove    = dieEarliest ConcurrentMoveAndSetup    (properties Go =<< [Setup, Move])
    warnGameInfo       = warnAll     ExtraGameInfoOmitted      (properties Go GameInfo)
    warnRoot           = warnAll     NestedRootPropertyOmitted (properties Go Root)