Skip to content
Next — unreleased

Players enroll in MUD, ONI or Ustur. Read the faction that an existing Profile joined with getFactionForProfile:

import { getFactionForProfile } from '@aephia/atlas-kit/factions';
const enrollment = await getFactionForProfile(ctx, profileAddress);
console.log(enrollment.faction, enrollment.factionId);

A Profile’s enrollment and a Game’s dynamic faction registry are different things. Enrollment records the player’s MUD/ONI/Ustur choice. The dynamic registry describes factions used by other game systems, including NPCs such as Jorvik (ID 4). Inspecting an NPC faction does not make it a player-enrollment option.

  • getFactionForProfile(ctx, profileAddress) reads a player’s enrollment.
  • getFaction(ctx, factionId) reads a Game-scoped dynamic faction record.
  • getFleetCombatStatus(ctx, fleetAddress) from the combat entry exposes participant.kind; an NPC participant retains its numeric factionId. This remains useful even when its dynamic registry record is unavailable.

Keep the NPC ID when inspecting Fleet state and combat activity. Do not infer player membership from a Fleet’s owner Profile, treat every faction ID as a playable choice, or require a registry record merely to recognize an NPC. NPC action planning remains subject to each action’s documented authority and preconditions; faction inspection grants no authority to act for that NPC.

Use maybeGetFactionForProfile(ctx, profileAddress) when the Profile may not have enrolled yet. It returns undefined only when its canonical enrollment is absent. A present record exposes profile, faction, and factionId; faction is unaligned, mud, oni, or ustur. Invalid owners, malformed bytes, and wrong Profile relationships are errors, not missing enrollment.

Use getFactionForProfile when enrollment must already exist. After a confirmed write, read it with { refresh: true } and verify both the Profile and selected faction. Reads never choose a faction or create an account.

The faction entry also covers dynamic faction identity, economics, diplomacy, standing, treasuries, asset ownership and King-system ownership. These reads do not replace player enrollment. maybeGetFactionStanding returns undefined when no standing is recorded; getFaction asserts that a registry record exists and reports ACCOUNT_NOT_FOUND if it does not.

Recorded example — z.ink PTR, 2026-08-30. The example below remains runnable against the documentation’s isolated historical faction scenario, using dynamic faction ID 4. Its registry record was removed on 2026-09-09. It is not a current PTR availability promise or a player-enrollment example. Live documentation checks still execute this example as archived replay, separately from current player reads. For your own deployment, provide an existing dynamic faction ID.

import {
getFaction,
getFactionRelations,
maybeGetFactionStanding,
} from '@aephia/atlas-kit/factions';
const faction = await getFaction(ctx, factionId);
const relations = await getFactionRelations(ctx);
const standing = await maybeGetFactionStanding(ctx, profileAddress, factionId);
console.log(faction.factionId, relations, standing);

planChooseFaction from @aephia/atlas-kit/factions/actions plans first enrollment into mud, oni, or ustur. It rejects an existing enrollment account, including an existing unaligned account. Reuse a valid enrollment; faction switching and repair of existing accounts are outside this planner.

Illustrative: supply a configured context, an existing Profile address, and its authorized wallet address. Use the actual Profile key index (shown as zero here). The result is an inert Plan; this snippet does not sign or submit.

import { planChooseFaction } from '@aephia/atlas-kit/factions/actions';
import type { PlanAuthorization } from '@aephia/atlas-kit/factions/actions';
const authorization: PlanAuthorization = {
profile: profileAddress,
authority: walletAddress,
keyIndex: 0,
};
const plan = await planChooseFaction(ctx, {
faction: 'ustur',
authorization,
});
console.log(plan.describe());

The Profile authority signs this instruction. There is no separate payer: the program funds the new account from the Profile account’s own on-chain balance, preserving the Profile’s rent reserve. A funded authority wallet does not replace that balance. The planner validates the current Rent account and observed Profile funding; it does not transfer funds or top up the Profile. Transaction fees remain separate and execution requires an explicit fee payer.

Inspect the Plan’s signers, writable accounts, funding description, and preconditions, then simulate before requesting signatures. The account must remain absent and validated prerequisite state must remain unchanged. Profile permissions and certificate authorization ultimately remain chain-authoritative; local validation is not proof that every delegated certificate path is accepted. When delegation requires a certificate, its account must exist before the planner returns a Plan. A missing account produces a remedy to select an existing certificate or a matching direct Profile key. An unused certificate supplied with valid direct authority remains ignored. Profile authority, Rent pricing and certificate guards identify their respective roles and explain how to replan.

After confirmed execution, load the enrollment again with a refresh read. A simulation or submitted signature alone does not establish enrollment. The PTR evidence uses unsigned simulations, without live account creation or token movement.

Classification: off-chain/editor-authored color is editor-local; live Region presentation is chain-derived from owner and safety. The official map editor’s inspected 2026-09-13 createNewRegion producer reads a color picker and stores its value as color in regionDefinitions. The export code serializes those definitions alongside the systems in mapData. This directly establishes an editor source, not a canonical C4 palette or a chain-addressed payload. The reported 69 Regions in the dated 2026-06-09 export are consumer evidence, not a schema or a verified deployment mapping.

The checked @staratlas/[email protected] generated Region type and RegionTracker account codecs contain ownership, safety/risk, XP, geometry, connections, systems and research requirements, but no color or Region content reference. Region is nested in RegionTracker, not a separately addressable account. Faction.contentUriHash belongs to FactionAccount, whose generated comment describes an off-chain manifest hash for cosmetics, blueprints and dialogue; neither that hash nor its homeRegion field proves a Region palette relationship. The checked @staratlas/[email protected] Faction type is an alignment enum, not another metadata account.

The deployed C4 client inspected 2026-09-13 uses drawRegions and getFactionColorFromOwner to choose Region fill/stroke color from chain Region.owner, using a fixed faction palette. Safety/risk status governs baseline opacity; hover, selection and zoom add client-side styling. It draws borders from the chain Region geometry, not the editor’s authored palette.

For live-game-style presentation, use TerritoryRegionSummary.owner and TerritoryRegionSummary.safety, which already project the governing chain fields. Also use TerritoryRegionSummary.risk when matching the client’s low-risk styling: low-risk Regions, or safe aligned Regions, receive that style. Choose presentation styles in your application; do not join editor IDs to chain Region IDs to reproduce the live renderer. Editor timestamp string IDs and chain u16 IDs are different namespaces. Custom editor palettes remain application-owned authoring data, not SDK-owned canonical Region metadata.

There is no proven Region-scoped content reference supplying authored color. The checked schema does not prove universal on-chain absence; it does expose the owner/safety inputs used by the inspected live renderer. No separate implementation issue is needed: those inputs are already exposed, and no new stored color or canonical payload was discovered. TerritoryRegionSummary gains no color/content fields, and the SDK does not fetch or vendor editor exports.

The dated provenance record contains the deployed bundle URL, SHA-256, renderer anchors, editor-source hashes and codec boundaries. See also the #436 chain-audit correction: editor-only evidence previously missed chain-derived visual semantics. Star and Celestial Body findings remain separate from this Region conclusion.

Keep player alignment and NPC identity separate. Enrollment ID 0 means unaligned. For a Fleet, inspect its explicit participant kind and retain an NPC participant’s numeric faction ID; do not infer NPC identity from a player alignment value or its owner Profile.

Standing is per profile, not per character. It belongs to the wider Star Atlas identity rather than to the SAGE character.

Relations are between factions, not players. Diplomacy describes the factions’ stances toward each other.