# Council Rank
Documentation: next (source: develop).

Install the preview: `pnpm add @aephia/atlas-kit@next`. These docs follow develop and may include changes not yet published to npm.

> Read Character XP, stored levels, career research points, Council Rank Renown, and acquired research nodes, and plan one research node unlock.

Markdown source of https://develop.atlas-kit-docs.pages.dev/guides/council-rank/ — see https://develop.atlas-kit-docs.pages.dev/ai/ for the full machine-readable surface.

Progression belongs to a **Character**, not a wallet-wide balance pooled across
Profiles. Activities earn career XP; career levels provide career research
points and contribute toward Council Rank Renown. Research turns those points
into capabilities.

:::game[Progress belongs to your Character]
Pilot, Data Runner, Mining, Building, Crafting and Combat each have XP and levels.
Each career level grants a research point in that career. Career level gains also
contribute toward Council Rank Renown, a separate research currency: the current
PTR setting is one Renown per six levels. Research can unlock larger ships,
Fleet capacity, additional Fleets, buildings and other capabilities.
:::

## XP, career research points, and Renown

These are different units:

| Value                  | Meaning                                                                              |
| ---------------------- | ------------------------------------------------------------------------------------ |
| Career XP              | Activity experience recorded in that career's `earned` field.                        |
| Career level           | The level stored on the Character, governed by the Game's XP thresholds.             |
| Career research points | One per career level; available points are `level - spent`, clamped to zero.         |
| Council Rank Renown    | A separate research currency; available Renown is `earned - spent`, clamped to zero. |

The six careers are Pilot, Data Runner, Mining, Building, Crafting, and Combat.
The current PTR configuration awards one Renown per six career level gains
across those careers. This counts levels gained, not unspent career points:
spending a career point is not an exchange into Renown. For example, three
Pilot and three Mining levels provide three research points in each career
and one Renown before spending. Daily XP is a separate category, not one of
these six careers.

Do not hardcode six for another deployment or future release. The Game exposes
`xpDefinitions.renown.divisor` and `feederCategories`. The Character's
`xp.councilRankLevelCarry` records career-level progress toward the next Renown.
Stored Council Rank `level` and available Renown are distinct values.

## Fetch balances and acquired nodes quickly

All Character-local inputs are already available from **one Character account
read**, with no Game or research catalog required. Repeated reads use the
context cache; use `{ refresh: true }` when you need current state.

Requires an existing `ctx` and a known `profileAddress` (verified by the guide
snippet gates):

```ts
import {
  getCharacterForProfile,
  deriveCharacterResearchState,
} from '@aephia/atlas-kit/identity';

const character = await getCharacterForProfile(ctx, profileAddress);
const research = deriveCharacterResearchState(character);

research.careers.pilot.earnedXp;
research.careers.pilot.level;
research.careers.pilot.researchPointsAvailable;
research.renown.available;
research.nodes; // acquired { nodeId, level } rows
JSON.stringify(research); // bigint values become decimal strings
```

Do **not** calculate career points as `earned - spent`: career `earned` is raw
XP while career `spent` counts research points. Keep the arithmetic in bigint.
The helper returns an immutable, JSON-serializable projection without any extra
reads or cache. `careers` contains all six careers, with `earnedXp`, `level`,
`researchPointsSpent` and `researchPointsAvailable`. `renown` separately exposes
`earned`, `spent`, `available`, `level` and `careerLevelCarry`. Daily XP is not
included in the career balances; it remains available on `character.xp.dailyXp`.

`nodes` includes acquired nodes only, not a historical receipt of purchases.
An unlocked node without a stored `nodeLevels` entry defaults to level 1; a node
absent from `unlockedNodes` is not acquired. Stored levels are reported as-is, including 0; only a missing entry defaults
to 1. This preserves observed state rather than the official client's minimum-1
normalization for synchronization estimates. The original stored rows remain on
`character.modifiers.nodeLevels`.

Catalog costs use category labels that map to projection fields as follows:

| `xpCosts[].category`                                | Balance source                                                        |
| --------------------------------------------------- | --------------------------------------------------------------------- |
| `pilot`, `mining`, `building`, `crafting`, `combat` | `careers.<same>.researchPointsAvailable`                              |
| `data-runner`                                       | `careers.dataRunner.researchPointsAvailable`                          |
| `council-rank`                                      | `renown.available`                                                    |
| `daily`                                             | Not projected; `character.xp.dailyXp.earned - spent`, clamped to zero |

This mapping identifies balances; it does not check all node prerequisites or
authorize a purchase.

The projection reports `xpSequenceId`, `researchSequenceId` and
`pendingNodeUpdates` from the input. It does not fetch definitions or assert that
the Character is synchronized. Refresh through `getCharacterForProfile` and
project again when the underlying read needs updating.

## Add thresholds and node descriptions when needed

Requires the same context and Profile address (verified by the guide snippet
gates):

```ts
import {
  getCharacterProgressionForProfile,
  getResearchCatalog,
} from '@aephia/atlas-kit/identity';

const progression = await getCharacterProgressionForProfile(
  ctx,
  profileAddress,
);
const renownRules = progression.xpDefinitions.renown;
const thresholds = progression.xpDefinitions.levelThresholds;
const catalog = await getResearchCatalog(ctx);
```

The progression read joins Character XP to **sequence-matched** Game XP rules;
it does not invent levels. These optional definition reads load the large Game
account through the shared lazy registry. Reuse the context so definitions and
Character reads can be cached/deduplicated; do not fetch a Game per career or
per node. Separate Character/catalog reads are not an atomic chain snapshot.

Stored levels reflect the rules at `character.xp.seqId`. If that sequence differs
from the Game XP definitions, the progression read throws
`RegistryOutOfSyncError`. The Character must be synchronized with the current
game rules before relying on its levels; refreshing a read alone does not
synchronize on-chain state.

> **Runnable example — Read Council Rank and research.** Character rank and career levels, plus the research catalog. Run it in the browser at https://develop.atlas-kit-docs.pages.dev/guides/council-rank/.

Catalog nodes expose `xpCosts` with `category`, `minimumLevel`, and `costRaw`.
Despite the field name, a career-category cost is career research points;
`council-rank` costs are Renown. Daily XP is a separate currency. Minimum level
is an eligibility threshold, not a deduction. Nodes also expose ATLAS and cargo
costs, prerequisite `requiredTagIds`, `maxLevel`, cost growth and `modifier`.
Node IDs and prerequisite tags must not be treated as interchangeable.

For context, these **dated PTR definitions** were read on October 11, 2026;
they are not an eligibility or successful-purchase claim:

| Node                          | Points                       | Other requirements/costs                                                 |
| ----------------------------- | ---------------------------- | ------------------------------------------------------------------------ |
| Fleet Size - Tier 1 (1)       | 1 Renown                     | 0 ATLAS; prerequisite tag                                                |
| X-Small Ships (31)            | 1 Pilot research point       | 350 ATLAS; prerequisite tag                                              |
| Contested Space Scanning (18) | 1 Data Runner research point | Data Runner level 5; 350 ATLAS; cargo; prerequisite tag                  |
| Enemy Faction Scanning (19)   | 1 Data Runner research point | Data Runner level 22; Combat level 5; 350 ATLAS; cargo; prerequisite tag |

The Points column lists only nonzero point costs. Zero-cost category entries
carry level requirements only (including Council Rank level 0 for X-Small Ships
and Combat level 5 for Enemy Faction Scanning).

The catalog had 243 definitions, not necessarily 243 visible nodes or 243 total
spendable points. The game client can hide or disable nodes. Read current costs
instead of assuming a universal 350 ATLAS fee or a fixed total tree price.

:::game[Research turns progression into capabilities]
A node can require career levels and prerequisite tags, and spend career research
points or Council Rank Renown, ATLAS and cargo. A required level is not itself a
spend. Acquired nodes and their levels live on the Character; applied modifiers
describe its current perks. `planUnlockResearchNode` plans one explicit unlock;
no respec or refund guarantee is established here.
:::

Join acquired node IDs to catalog `id` values for names and descriptions; retain
IDs that do not resolve rather than silently discarding acquired state. Applied
perks live in `character.modifiers.values`. `fleetSize` limits ship capacity
within a Fleet; `fleetConcurrency` limits Fleet count. Compare the latter with
`character.counts.fleets` when displaying remaining Fleet slots. That comparison
alone is not a complete action-eligibility check.

Treat these applied perks as current only when `character.modifiers.seqId`
matches `catalog.sequenceId` and `character.modifiers.unupdatedCount === 0`.
After a research-definition update, synchronization rebuilds the modifiers;
until it finishes, values such as Fleet concurrency may lag current rules.
Synchronize the Character in the game, then refresh it and the relevant
definitions before presenting those limits as current.

## Unlock a research node

Use `planUnlockResearchNode` to raise one node to its next level for your
Profile's Character. Name the node and the level it will reach: a node you have
not unlocked reaches level 1, and a repeatable node (`maxLevel` 0) at level 3
reaches level 4. The planner never picks a level or unlocks prerequisites for
you.

This example is illustrative. Supply your application's context, the System of
a Starbase where your Character has a Starbase Player, and explicit
authorization; it only prepares an inspectable Plan.

```ts
import { planUnlockResearchNode } from '@aephia/atlas-kit/identity/actions';
import type { Address, SageContext } from '@aephia/atlas-kit/client';

declare const ctx: SageContext;
declare const profile: Address, authority: Address, system: Address;

const plan = await planUnlockResearchNode(ctx, 62, {
  authorization: { profile, authority, keyIndex: 0 },
  system,
  level: 1,
});
console.log(plan.describe());
```

The unlock spends, all at once:

- the listed research points from each career, or Renown for Council Rank;
- the node's ATLAS cost from the Character, grown by `costGrowthBasisPoints`
  for each level already held and rounded down (350 ATLAS at 10% growth costs
  385 ATLAS from level 1 to 2);
- any cargo cost from that Starbase Player's cargo, grown and rounded the same
  way;
- lamports from the Profile for the Character's extra storage. The unlock pays
  them as a locked rent deposit, separate from transaction fees.

The Character grows when the unlock adds entries it did not hold: a newly
unlocked node, a stored level, and any research tag, cargo category or rare
mineral the node grants. A repeated level whose grants the Character already
holds adds nothing. The program takes the growth's rent from the Profile vault
with the signing key, and returns any surplus storage lamports on the Character
to the Profile. The Plan states the conservative Profile debit. A positive debit
needs a Profile AUTH key or a key that also holds `drainSolVault`, and Profile
lamports above the Profile's own rent reserve.

Every required tag must already be on the Character, and each listed category
must be at its minimum level, even when it costs nothing. Any Starbase where the
Character has a current Starbase Player works, including another faction's.
Use a direct Profile AUTH key or a `doResearch` key scoped to SAGE or the Game.

When something is missing, planning fails with the exact shortfall, such as the
missing tags or how many research points the Character has. Daily XP costs are
refused as unqualified.

A Character whose research or XP predates the current Game definitions is also
refused, because the resynchronized Character decides eligibility. The program
resynchronizes it itself at the start of the unlock, as it does for any action
that validates the Character, when at most 8 node levels are pending. Run such
an action and replan. With more pending levels, run the permissionless
`syncCharacter` instruction until no nodes remain.

Execution rechecks every requirement, both definition sequences, the ATLAS cost
and the Profile storage debit before signing. The program adds the node's tags and modifier to the
Character, so read the Character after confirmed execution for the resulting
limits. One unlock per Character fits in a transaction.

## Limits of the current evidence

The bindings contain per-career XP allowance banks, regeneration rates and bank
ceilings. These support a refillable allowance model; they do not establish
mainnet progression times or guarantee a particular activity's awarded XP.

Research time is not a field in the current node definition. Locker-based fee
waivers, Starbased XP migration, respec/refund rules and mainnet progression
targets are not established here as active contracts. Do not infer them from
older announcements.

The point arithmetic above matches `researchPointsEarned` and
`spendableResearchPoints` in the
[retained official-client evidence](https://github.com/Aephia/atlas-kit/blob/develop/docs/evidence/character-progression.md)
(excerpts and bundle SHA-256, inspected October 11, 2026).
The read-only PTR observations were at slots 59,198,431–59,198,438, Game XP
sequence 26 and research sequence 0. They establish stored configuration.
Unsigned simulations on October 19, 2026 verified the unlock's deductions,
growth and failures
([research unlock evidence](https://github.com/Aephia/atlas-kit/blob/develop/docs/evidence/research-unlock-808.md));
no research transaction was signed or submitted.

## Reference

- [`identity`](/reference/identity/) — public progression and Character reads
- [You](/guides/identity/) — Profile and Character relationships
- [Crafting habs](/guides/crafting-habs/) and [claim stakes](/guides/claim-stakes/)
