V2's online-fighting backbone is the part of the project that has to be frame-
perfect under loss and latency, not just plausible. A 1v1 ranked match between
two players 80 ms apart cannot wait for the opponent's input to arrive before
drawing a frame, so V2 predicts the missing input, draws immediately, and — when
the real input arrives and disagrees — rewinds the world to the last agreed
frame and re-simulates everything in between, in a single tick, before the
player ever sees it. That whole mechanism lives in the V2Netcode Unreal
C++ module (V2/ue/Source/V2Netcode/, ten .cpp/ten .h plus
V2Netcode.Build.cs, which depends on Unreal's ReplicationGraph and NetCore
modules and on V2Combat / V2Core / V2Input). The module is real and
compiles on the on-box engine — the build tree carries sixteen V2Netcode/*.o
objects under
V2/ue/Intermediate/Build/Linux/x64/UnrealEditor/Development/V2Netcode/. This
page is the architecture-side companion for the rollback session, the transport,
the network-quality fallback ladder, the client-server backbone, and tag-team;
the section hub is ../V2_ARCHITECTURE.md.
The design rests on a deliberate split. A deterministic, integer-frame, side-
effect-free simulator — FV2SimWorld (V2RollbackSimWorld.h:6) — holds the
only state that ever rolls back, and a separate FV2PresentWorld
(V2RollbackSimWorld.h:117) interpolates that state to the display refresh rate
without ever feeding back into the sim. The combat layer that decides what a
hit does lives next door in V2Combat/V2Gameplay and is documented in
./combat-system-gas-frame-data-and-determinism.md;
this page owns the layer that decides which frames to simulate, in what order,
under what network conditions. The orchestrator that ties them together is
FV2RollbackSession (V2RollbackSession.cpp), and almost everything below is a
method on it or a type it consumes.
What ships, honestly#
The rollback core is real and tested. FV2RollbackSession::TickFrame,
prediction, correction detection, rewind-and-resimulate, the "Recovering
Connection…" freeze, the one-time delay-fallback offer, snapshot capture/restore
under an 8 KB budget, the deterministic state hash, and the network-quality
handshake/fallback analyzer are all substantive C++ exercised by the automation
suite. Netcode.Module.spec.cpp is a single large automation test
(V2.Netcode.Module plus V2.Rollback.CustomSocket) with 604 assertions
that drive FV2SimWorld::StepFrame directly, run a live FV2RollbackSession
through resimulation and the frozen-overlay path (Netcode.Module.spec.cpp
around lines 4672 and 4733), and round-trip the packet codec. A second test,
V2Tests/Private/Netcode/GoldenReplayCorpus.spec.cpp, backs the determinism
claim with a golden-replay corpus.
Three honest qualifications matter. First, the transport is a wire-format
codec, not a live socket. FV2RollbackPacketCodec (V2RollbackTransport.cpp)
builds, encodes, decodes, ACK-bitfields and XOR-parity-protects packets into
TArray<uint8>, and produces a FV2RollbackUdpDatagram carrying UDP/DTLS
flags — but there is no FSocket, ISocketSubsystem, SendTo, RecvFrom,
or DTLS handshake anywhere in the module. The byte format and the adaptive-send
policy are implemented and tested; pushing those bytes over a real wire is not
yet wired. Second, FEC parity is generated and preserved but not
reconstructed — BuildXorParity and AttachFecParity exist and survive an
encode/decode round-trip, but there is no function that rebuilds a dropped
packet from parity. Third, several "server" surfaces are data contracts with
validators, not live services: the dedicated-server remote-admin (RCON-style)
and server-replay recording types expose Evaluate()/IsValid…() and
default-builders, not a running socket or recorder. Where the source monolith
claims more than the code delivers, this page says so — the most consequential
case is tag-team, below.
The two worlds: deterministic sim vs. interpolated present#
FV2SimWorld is the authority. It advances on a fixed integer step
(FV2RollbackConfig::SimulationHz = 60, GetFixedDeltaSeconds()), stores
fighter state as integers — fixed-point position (FixedX/FixedY), integer
Health (default 1000), integer Meter, frame counters, a RngCursor — and
exposes exactly the primitives rollback needs: Reset(MatchSeed, FighterCount),
CaptureSnapshot(), RestoreSnapshot(),
StepFrame(FrameInputs, SideEffectPolicy), and ComputeStateHash(). Crucially
it is side-effect-free on demand: StepFrame takes an
EV2RollbackSideEffectPolicy (Emit, SuppressCosmetics, TelemetryOnly), so
the same code path that plays audio and spawns particles on a live frame can be
told to stay silent during a resimulation.
FV2PresentWorld never decides anything. It receives sim snapshots via
SubmitSimSnapshot, keeps the previous and current snapshot, and
TickPresentation(DisplayDeltaSeconds) interpolates between them at the display
refresh rate — so a 60 Hz sim can be presented at 120 Hz or 144 Hz without
touching the simulation clock. It also owns the recovery overlay
(ShowRecoveryOverlay/ClearRecoveryOverlay). The automation suite asserts the
contract that keeps these honest: "present interpolation leaves sim hash
unchanged" — drawing a frame must never perturb the rolled-back state. The two
classes are aliased FV2_SimWorld / FV2_PresentWorld for readers coming from
the monolith's naming.
The rollback session loop#
FV2RollbackSession::TickFrame(LocalInput, LocalPlayerIndex, NewlyConfirmedRemoteInputs)
is the per-frame entry point. The sequence is:
Concretely (V2RollbackSession.cpp:18): each newly-confirmed remote input is
handed to the predictor, which returns a FV2RollbackCorrection. Corrections
that RequiresRollback() are collected; ApplyCorrections picks the
earliest corrected frame and calls ResimulateFromCorrection. That method
computes RestoreFrame = CorrectedFrame − 1 and
RollbackFrames = CurrentFrame − RestoreFrame, restores the snapshot for
RestoreFrame, then replays every frame from CorrectedFrame to CurrentFrame
through StepFrame — using SuppressCosmetics when
bSuppressCosmeticsDuringResim is set, so the rewind is silent. Each replayed
frame is re-snapshotted and re-submitted to the present world, and a
FV2RollbackTelemetryEvent is emitted carrying the before/after state hashes,
the resimulated frame range, and a per-frame ReplayedFrames array for
postmortem. If no correction is pending, the session simply advances one frame
with Emit.
A worked example: at CurrentFrame = 100 the session has been predicting player
1's input as "hold forward" since frame 96. Player 1's real frame-97 input
("crouch") arrives. The predictor flags a correction at frame 97;
RestoreFrame = 96; the session restores the frame-96 snapshot and re-steps 97,
98, 99, 100 with the corrected input and SuppressCosmetics, producing a new
frame-100 state hash — four frames of rewind, resolved inside one tick, with no
audio or VFX replayed. The returned FV2RollbackTickResult reports
RollbackFrames = 4, bRecovered = true, and the new StateHash.
Input prediction and the rollback trigger#
Prediction is last-confirmed repetition, the classic GGPO-style choice.
FV2RollbackInputPredictor::PredictInput(Frame, Player)
(V2RollbackInputPredictor.cpp) returns the confirmed input if one exists for
that (frame, player); otherwise it repeats LastConfirmedByPlayer[Player] —
re-stamped to the new frame via BuildPredictionSample and flagged
bPredicted = true. Frame 0 predicts neutral. Inputs are keyed by a packed
(FrameNumber << 16) | PlayerIndex.
The rollback trigger is deliberately narrow.
FV2RollbackCorrection:: RequiresRollback() (V2NetcodeTypes.cpp:2033) returns
true only when
CorrectedFrame != INDEX_NONE && !PredictedInput.IsSameInput(ConfirmedInput) —
i.e., a confirmed input only forces a rewind when the prediction was actually
wrong. A correctly-predicted "hold forward" that turns out to be "hold forward"
costs nothing; this is what keeps a clean connection at zero rewinds despite
predicting every frame. The net-graph's frame advantage is computed as
GetLastConfirmedFrame(0) − GetLastConfirmedFrame(1)
(V2RollbackSession.cpp:79), the standard "who is ahead" diagnostic.
Snapshots and the 8 KB budget#
A FV2SimSnapshot (V2NetcodeTypes.h:1157) is the complete rollback state for
a frame: the fighter array, the frame inputs, and explicit sub-snapshots for
every system that must survive a rewind — ASCStateHashes,
AttributeSetValues, AbilityActivations, AnimationTimers, HitboxStates,
InputBufferFrames, RngStreams, and the Tekken-family state (movement,
air-juggle, Heat, Rage, Ki Charge, Power Crush, stance). The automation suite
checks each of these individually ("sim snapshot serializes ability activation
state," "…animation timer state," "…hitbox state," "…RNG streams,"
"…input buffer").
The budget is enforced, not aspirational. SnapshotBudgetBytesPerFighter
defaults to 8192 and is clamped [512, 8192] in the config.
IsWithinBudget computes
EstimateSerializedBytesPerFighter() <= BudgetBytesPerFighter, where the
per-fighter figure is the total estimate divided (rounded up) by fighter count
(V2NetcodeTypes.cpp:1090). The suite asserts both directions — "initial
snapshot is within 8KB per fighter" and "oversized snapshot fails budget."
For tag-team this is what gives the monolith's "≤ 24 KB per side" figure: three
fighters × 8 KB, computed rather than stored. The session keeps
SnapshotHistoryFrames = 90 frames of history (TrimSnapshotHistory evicts
anything older than CurrentFrame − 90), so the rewind depth is bounded by
memory as well as by MaxRollbackFrames.
Determinism: hashing, fixed-point, strict floating point#
Rollback is only correct if two machines re-simulating the same inputs reach
byte-identical state. FV2SimWorld::ComputeStateHash()
(V2RollbackSimWorld.cpp:1833) folds MatchSeed, CurrentFrame, and each
fighter's RefreshStateHash() with HashCombineFast. The subtle part is FName
hashing: GetTypeHash(FName) hashes the process-local name-table index, which
differs between processes, so the module defines V2StableNameHash
(V2NetcodeTypes.h:13) as FCrc::StrCrc32 over the name string and uses it for
the stance tags inside RefreshStateHash (V2NetcodeTypes.cpp:921). That makes
the hash content-based and stable across the client, the server's re-simulation
check, and golden-replay playback.
Determinism is also a build property. V2Server.Target.cs sets
DETERMINISM=1, V2_DETERMINISM=1, and V2_STRICT_FP=1, and injects strict
floating-point compiler arguments — /fp:strict /fp:except- on MSVC,
-fno-fast-math -ffp-contract=off on Clang — so the compiler cannot reorder
floats or fuse multiply-adds differently on two platforms. Combined with the
integer-fixed-point sim state, this is what lets the golden-replay corpus assert
bit-identical re-simulation rather than "close enough." The deeper treatment of
StepFrame, the per-tick order, and the golden corpus lives in the combat page
(./combat-system-gas-frame-data-and-determinism.md);
the input-encoding side is in
./animation-and-input-pipeline.md.
Transport: the wire-format codec#
FV2RollbackPacketCodec (V2RollbackTransport.cpp) is a complete, tested
packet format and adaptive-send policy. EncodePacket writes a V2RB magic, a
version, sequence/ACK/ACK-bits, the frame range, a payload CRC, FEC
group/index/size, a flags byte, then the encoded input bytes and parity bytes;
DecodePacket reverses it and rejects anything malformed. Inputs are encoded
through FV2InputReplayEncoder::EncodeSamples (reused from V2Input), so the
netcode payload and the replay format share one encoder. Three pieces give the
source's "adaptive send" promise teeth:
- ACK piggyback.
BuildAckBits(LastAck, ReceivedSequences)packs the last 32 acknowledgements into a bitfield carried on every outbound packet — no separate ACK traffic. - Adaptive resend window.
BuildAdaptiveFramePacketcallsBuildResendWindowto attach the current frame plus the lastResendInputFrames(default 8) frames of input, so a single lost datagram is covered by the next one. The header flagsbEveryFrameInputSendandbBatchResendForLossRecoveryare set precisely when the window is contiguous and current. - FEC parity.
BuildXorParityXORs a group of packets into parity bytes;AttachFecParityrides them along. As noted above, parity is generated and round-tripped but not yet used to reconstruct a dropped packet — an honest gap.
BuildUdpDatagram wraps an encoded packet in a FV2RollbackUdpDatagram with
SocketProfile = "V2.Rollback.UDP.DTLS" and bUsesUdp / bUsesDtls /
bSequenceNumbered / bAckPiggybacked / bFecProtected flags. The channel
topology (BuildDefaultReplicationChannels, in V2NetworkQuality.cpp:236)
confirms the monolith's "custom socket for rollback, Iris for everything else":
| Channel | Transport profile | Iris | Reliable | Max Hz | Notes |
|---|---|---|---|---|---|
| RollbackInputs | V2.Rollback.CustomSocket |
no | no | 60 | deterministic, custom socket |
| MatchState | UE.Iris.MatchState |
yes | yes | 30 | out-of-rollback state |
| ChatPresence | UE.Iris.ChatPresence |
yes | yes | 10 | social |
| Spectator | UE.Iris.Spectator |
yes | no | 20 | read-only viewers |
| Telemetry | UE.Iris.RollbackTelemetry |
yes | yes | 5 | postmortem feed |
| Lobby | UE.Iris.Lobby |
yes | yes | 15 | pre-match |
The suite asserts the load-bearing invariant directly: "rollback input channel does not use Iris" and "non-rollback Iris channels stay off rollback socket."
Network quality, handshake, and graceful fallback#
FV2NetworkQualityAnalyzer (V2NetworkQuality.cpp) turns measured samples into
a mode recommendation. EvaluateHandshake averages RTT and packet loss and
takes the max jitter across the pre-match samples, then grades:
| Grade | Condition (defaults) | Recommended mode | Ranked |
|---|---|---|---|
| Poor | avg RTT > 150 ms or avg loss ≥ 8 % | Delay | not eligible |
| Borderline | avg RTT > 100 ms or max jitter > 18 ms or loss ≥ 4 % | Hybrid | eligible |
| Good | otherwise | Rollback | eligible (Wi-Fi warned) |
The thresholds are the real config fields — DelayFallbackRttThresholdMs = 150,
HybridRttThresholdMs = 100, PoorPacketLossPercent = 8. A Wi-Fi or mobile
sample sets a non-blocking "wired recommended" warning. Mid-match, the system
does not silently downgrade: EvaluateDelayFallbackDecision only offers the
delay fallback after sustained pressure — ShouldOfferDelayFallback
requires SustainedRollbackPressureFrames (1800 frames = 30 s at 60 Hz) of
consecutive samples whose RollbackFrames exceed MaxRollbackFrames (8).
When that fires in a ranked match, the decision sets bRankedSuspended and, if
the player declines, bRankedNoContest — the source's "one-time fallback offer
→ ranked no-contest." Extreme RTT (> 150 ms) defaults straight to delay without
an offer.
ComputeReliabilityScore produces a per-account 0–100 figure — 100 minus an
average penalty of
RTT/200·25 + jitter/40·25 + loss/10·40 + (10 if rollback > 8), clamped — and
BuildDiagnosticsStamp writes RTT/jitter/loss/grade/reliability into a
FV2NetworkDiagnosticsStamp bound to a match record and an ops endpoint
Ops.NetworkHealth.V2. That stamp is the data behind the monolith's "results
stamped in match record" and "ops dashboard"; the dashboard consumer itself is
outside this module — see
./online-backbone-and-competitive-integrity.md
and
./telemetry-performance-testing-and-release-gates.md.
Client-server netcode#
Not every mode rolls back. Free-for-all, Royal Rumble's full ring, open-world
co-op, hubs, and tooling-heavy training use Unreal's authoritative client-server
path. The dedicated-server build target is real: V2Server.Target.cs
(Type = Server, [SupportedPlatforms(Server)]) with the deterministic build
flags above and a gRPC generation step.
The replication graph is UV2ReplicationGraph : UReplicationGraph
(V2ReplicationGraph.h). BuildDefaultPriorityBands and
RouteActorForConnection encode exactly the four priority bands the monolith
promises, and the suite asserts each weight:
| Band | Priority | Relevance |
|---|---|---|
| OwnPawn | 1.0 | always relevant, not spatialized |
| NearbyFighter | 0.8 | spatialized, within max distance |
| DistantFighter | 0.3 | spatialized |
| AmbientProp | 0.1 | spatialized |
Server tickrate adapts via FV2AdaptiveServerTickratePolicy: default 60 Hz, 128
Hz for ≤ 2-player high-frequency sessions, 30 Hz under load (downshift at 85 %
CPU, recover at 65 %), allowed set {30, 60, 128} — but
bRollbackModesAlways60Hz, bRankedOneVsOneMandatory60Hz, and
bTournamentMandatory60Hz pin the competitive paths to 60 Hz regardless. For
the client-server hit path,
FV2ClientServerHitConfirmationRequest::ResolveHostConfirmation implements
client-side prediction with host authority and a 2-frame confirmation grace,
resolving to ConfirmedByHost / RejectedByHost / LateHostConfirmation. This
is the other authority model: rollback uses SharedDeterministicLoop (both
peers run the same sim, no arbiter — the suite asserts "rollback hit authority
does not use server arbitration"), while client-server uses host arbitration.
Two further server surfaces are data contracts with validators, not running
services, and should be read that way: server-replay recording
(FV2ServerReplayRecordingConfig/InputFrame/Manifest — authoritative input
capture, deterministic input hashing, dispute-evidence metadata, server
signature, PII redaction, 30-day retention, 54000-frame cap) and the RCON-style
remote admin (FV2ServerRemoteAdminPolicy/CommandEnvelope/Result —
token-hash auth, loopback-only by default, an allow-list of
Status/ListPlayers/Kick/Broadcast/ SetTickRate/GracefulShutdown, audit). Their
Evaluate() and IsValid…() methods are real and validated; the live socket
and on-disk recorder are not in this module.
Tag-team architecture — honest correction#
The monolith states that "Snapback / DHC / X-Factor / Cross Assault are
abilities in V2Gameplay with their own GAS subclass." In the current code
they are not. There are no UGameplayAbility subclasses for these mechanics —
a search of V2Gameplay finds none, and the names resolve instead to a
deterministic data-contract catalog in V2Modes:
FV2TagTeamMechanicsCatalog (V2ModeTypes.h:4514), validated by
TagTeamMechanics.spec.cpp (V2.Modes.TagTeamMechanics.AssetContract). Treat
the GAS-subclass language as aspirational until those abilities ship; what
exists today is the spec layer that describes them.
That spec layer is, however, genuine and tested. The catalog carries:
- 3 formats (
EV2TagTeamFormatKind): 2v2 (two fighters/team, one active, switchable mid-combo via tag button), 3v3 (assist calls enabled), and Trinity (three fighters, once-per-match anchor assist). - 7 mechanics (
EV2TagTeamMechanicKind): TagCancel (designer-curated launcher animation, combo extender), Snapback (forces opponent tag-out; snapped-out fighter regenerates HP off-screen), DelayedHyperCombo (partner-super cancel, spends meter), AssistCall (single-move assist with a 360-frame cooldown), CrossAssault (one player controls two fighters), XFactorPandora (trades HP for damage/speed), and BaroqueDuoCancel (partner-call cost, combo extender). The suite asserts each is discoverable and that the assist cooldown is exactly 360. - Team HP (
FV2TagTeamTeamHpSpec): per-fighter bars, partner HP on the HUD, off-screen regen at0.35 %/s, team KO only when the entire roster is at 0 HP. - Net/sim (
FV2TagTeamNetSimSpec): 60 Hz rollback, 2 active sim fighters/side, deterministic tag transition, frame-accurate tag animation, replay encoder records tag actions — i.e. tag-team rides the sameFV2RollbackSessionloop, just with more fighters perFV2SimSnapshot. - Authoring (
FV2TagTeamAuthoringSpec): real CSVs on disk —V2/balance/tag/tag_cancel_dhc_matrix.csv(per-fighter pairing rows with cross-IP and cinematic restriction columns) andV2/balance/tag/team_theme_music.csv. - 3 online queues: RankedTagTeam (4 players, role-preference balancing), TagCoop (two players per team), CrewBattle (best-of-five single-elimination, 6 players).
The registry round-trip is verified too: UV2ModeRegistrySubsystem accepts the
catalog and CaptureRegistrySnapshot reports counts (3 formats / 7 mechanics /
3 queues) and readiness flags. The broader mode lifecycle is in
./game-modes-training-and-replay.md.
Edge cases and failure modes#
- Rollback budget exceeded. When
RollbackFrames > MaxRollbackFrames(8),EnterRecoveringConnectionfreezes the sim, setsbSimulationFrozen, shows theNetcode.RecoveringConnectionoverlay with "Recovering Connection…", and reports the state asRecovering. The session stays frozen until corrections stop arriving, then clears. - Missing or un-restorable snapshot. If the snapshot for
RestoreFrameis absent (evicted past the 90-frame history) orRestoreSnapshotfails, the session transitions toFallbackOfferedrather than corrupting state — a fail-loud seam, not a silent guess. - Cosmetic double-fire. Resimulation always runs under
SuppressCosmetics(when configured), so a hit that already played its sound on the predicted frame does not replay it on rewind; only the final, reconciled frame emits. - Empty handshake.
EvaluateHandshakewith zero samples grades Poor and recommends Delay — absence of data is treated as bad, not good. - Cross-process hash drift. Mitigated by
V2StableNameHash; a regression here surfaces as a golden-replay mismatch in CI, not as a desync in the wild.
Configuration reference#
FV2RollbackConfig (V2NetcodeTypes.h:114) is the single tuning surface, with
clamped UPROPERTYs and an IsValidConfig() guard:
| Field | Default | Meaning |
|---|---|---|
SimulationHz |
60 | fixed sim step |
MaxRollbackFrames |
8 | rewind cap before "Recovering Connection" |
PredictionWindowFrames |
8 | how far ahead inputs are predicted |
SnapshotBudgetBytesPerFighter |
8192 | per-fighter snapshot cap (clamped 512–8192) |
SnapshotHistoryFrames |
90 | rewind-able history depth |
ResendInputFrames |
8 | adaptive resend-window size |
FecGroupSize |
4 | XOR parity group |
AckWindowBits |
32 | ACK bitfield width |
HybridRttThresholdMs |
100 | Good→Borderline boundary |
DelayFallbackRttThresholdMs |
150 | Borderline→Poor / extreme-RTT boundary |
PoorPacketLossPercent |
8 | loss threshold for Poor |
SustainedRollbackPressureFrames |
1800 | 30 s of pressure before a fallback offer |
bRequireEncryptedTransport |
true | sets DTLS flags on packets |
bSuppressCosmeticsDuringResim |
true | silence rewinds |
UV2NetcodeBlueprintLibrary exposes 27 UFUNCTIONs over this surface
(BuildDefaultRollbackConfig, EvaluateNetworkHandshake,
EvaluateDelayFallbackDecision, EncodeRollbackPacket/DecodeRollbackPacket,
ConfirmClientServerPredictedHit, the adaptive-tickrate and server-admin
builders, …), which is how designers and tests reach the C++ without owning a
session object.
How it connects#
The rollback session consumes combat: FV2SimWorld::ResolveRollbackHits and
StepFrame apply the frame-data and hit geometry owned by
./combat-system-gas-frame-data-and-determinism.md,
and the input samples it predicts come from
./animation-and-input-pipeline.md (whose
FV2InputReplayEncoder is the same encoder the transport reuses). It feeds
the replay and training systems in
./game-modes-training-and-replay.md — the
sim/present split is exactly why training runs on the live sim while lab
overlays attach to the present world. Its diagnostics flow into
./online-backbone-and-competitive-integrity.md
and
./telemetry-performance-testing-and-release-gates.md;
the net-graph overlay surfaces through
./ui-hud-vr-ar-and-accessibility.md. The
module vocabulary (FV2SimWorld, snapshot, state hash, priority band) is
indexed in
./glossary-and-module-topology.md, and the
"netcode that respects the player's connection" promise is set in
./v2-product-promise.md. The racing and special-mode
backbones reuse the same client-server primitives —
./racing-and-vehicle-architecture.md and
./open-world-coop-and-special-modes.md
— while store/progression, esports services, build/cook, and compliance sit at
./live-ops-store-progression-and-community.md,
./esports-companion-and-ai-services.md,
./build-cook-assets-data-and-production.md,
and
./security-compliance-and-sister-monorepo-integration.md.
Related#
- Combat System: GAS, Frame Data & Determinism — the sim-world step, hit resolution, and golden-replay corpus
- Animation & Input Pipeline — the input samples and the shared replay encoder
- Game Modes, Training & Replay — tag-team mode lifecycle and the replay/training takeover
- Online Backbone & Competitive Integrity and Telemetry, Performance, Testing & Release Gates — reliability scores, diagnostics stamps, and CI determinism gates
- Glossary & Module Topology and V2 Product Promise — vocabulary and intent
- The section hub: ../V2_ARCHITECTURE.md