Understanding TIER
TIER links recorded AI spend to merged software changes. This guide explains the number in plain language, shows where its inputs come from, and takes you from installation to a first report.
TIER (Token Impact & Efficiency Ratio) is explained here in three layers. Each layer stands on its own, so read only as far as you need.
- The short answer — what TIER is and why a team would want it, in plain words.
- How the meter works — where the numbers come from. Technical terms are defined where they first appear.
- The full method, page by page — how to run it on real data, then each rule in brief with a link to the page that defines it.
Layer 1 — The short answer
TIER reports recorded outcome points per dollar of captured AI use. It associates spend and finished work observed in the same period; it does not establish that the AI spending caused that work.
The number is outcome points per $1,000. Higher means more finished work for the same money.
- The top of the fraction is finished work. Pull requests count once merged, which means accepted into the team's main code. Optional direct-commit capture and the outcomes API also supply outcomes. Bigger pieces earn more points. With GitHub's webhook connected, work that later fails its GitHub Actions run or has to be undone earns fewer; without the webhook, TIER sees neither.
- The bottom is what the AI use costs at the AI vendors' published prices, in US dollars, taken from a price table built into TIER. It is deliberately not your invoice. Discounts and credits differ between companies and change over time. A fixed price list means the same work always costs the same, so this month can be compared with last month.
Compare a team with its own history, not with other teams. The kind of work a team takes on moves the number, and the number cannot tell the kind of work apart from the skill of the people doing it.
What it is for. TIER is built for coaching, not for evaluating developers. Per-person figures are not accurate enough to judge an individual. The positioning is grade the work, not the worker, by policy, not by mechanism. Points follow the size of the finished work, not how hard it was: someone who spends a lot of AI effort on a small fix to a hard problem scores lower than someone making routine changes of the same size. A low number describes the work, not the developer's ability.
Current access and retention: Real servers always require an issued key.
Root reads everyone, node keys read their dated branch and personal keys read
their holder. Named access follows names_visibility; personal keys retain self access.
Named cards audit before construction and need no declaration or
positive verified spend. Shared/static credentials and server reporting modes
are retired. Team, division and company reports expand to their people;
name-free monthly comparisons retain the k floor. Writable servers run raw
retention at startup and daily (90 days by default, 60–365 days); pruning is
permanent. Read-only servers and the synthetic demo do not initiate pruning.
See identity access for current setup and trust limits.
Solo users can read their own local Claude Code, Codex CLI, Opencode (Z.ai coding plan) and Muse Code cost table and issue-attributed spend share with tierd score. tierd score --outcomes joins that spend to only the GitHub token owner's merged PRs for a personal TIER; it persists no report data and shows no team band. tierd demo provides the dashboard on invented data.
Who sees what. Real servers always require issued keys. Root sees everyone,
node keys see their dated branch and personal keys see self. Team, division and
company reports expand to their people. Named reads audit before construction;
the person can inspect their own view log. Named branch access follows
names_visibility; personal keys retain self access. Declarations and static/shared
credentials are removed. Name-free monthly comparisons use the k floor (default
five, minimum three), complementary suppression. The synthetic
demo uses invented data. See identity access for setup and
legal and privacy for policy considerations.
One caveat. The number is an estimate built from real records, not an exact reading. Spend is recorded when it happens, but work only counts when it merges, which comes later. So a period that ended very recently reads too low, and a period that starts before TIER began recording spend reads too high. Layer 2 explains both.
Historical self-measurement; original inputs and run settings are not publicly reproducible. The maintainer reported 221 points per $1,000 across 152 merged PRs, trailing 30 days to 2026-07-21, and 72.1% of spend unlinked. It was computed from backfilled history; no quality events were recorded for it, so it is size-weighted only. It illustrates the dashboard, not independent validation. Unlinked spend remains in the denominator.
The maintainer has exercised TIER's CI and revert rules in manual test runs; the project's automated webhook tests exercise the same rules. The inspected historical 221 figure has no recorded quality-event receipt.
Claude costs are derived from deduplicated Claude Code usage logs. Their completeness against independent provider accounting remains unvalidated, including for the subscription routes used here. Missing usage would understate those costs. Codex costs use logged cumulative counters; those counters do not independently establish complete capture. If the logs undercount, costs are understated and TIER scores read high. If Claude's logs undercount more than Codex's, Claude looks relatively cheaper.
Try it. Install TIER with Go 1.27.3 or newer
(go install github.com/tiermetric/tier/cmd/tierd@v0.7.0, once published), or download a
release; quickstart.md §1 covers both. Then run
tierd demo and open http://127.0.0.1:8080 in a browser. The demo fills the
dashboard with invented developers and spend. To measure your own work, see
From install to a first real score.
Next: How the meter works.
Layer 2 — How the meter works
The score is a ratio:
TIER = outcome points ÷ (list-price cost of the AI use / 1,000)
Read it as "outcome points per $1,000." The list-price cost is what the
AI use would cost at the vendors' published per-token prices, not what you
paid. TIER computes the ratio per developer. A team's or division's score is
its members' points added together, divided by their costs added together. It
is not an average of individual scores. Named reports use issued-key scope
and can read live date windows. Name-free comparisons read one closed UTC
calendar month, the latest by default on /api/v1/scores; pick another with
?period=YYYY-MM. The synthetic demo defaults to 90 days in the API and
30 days in the dashboard.
Both halves come from records that already exist: AI session logs, and merged pull requests. Neither comes from surveys or timesheets. The main human judgment in the formula is the size label on a pull request, covered below (a revert's reason is also read from keywords in its human-written message).
The bottom half: dollars
TIER reads the session files your AI coding tool already writes to disk. For
Claude Code, these are JSONL files (one JSON record per line) under
~/.claude/projects/. Each AI reply in them records its token counts and the
model's name. A token is a fragment of text a few characters long, and it is
the unit AI vendors bill by. Codex CLI, Opencode and Meta's Muse Code have
their own local readers, each switched on by a flag. Other tools can be captured through an
optional proxy. README § Capturing tokens
lists which tools are supported and how well tested each one is.
Tokens become dollars through a reference price table built into the program. It holds the vendors' published prices in US dollars per million tokens, under one version number for the whole table. That choice is deliberate. An invoice bundles discounts, credits and negotiated rates, so identical work would cost different amounts at different discount levels. A list price makes the same work cost the same. The table changes only when you install a new TIER release or supply your own table. On a flat-rate subscription, the figure is what your usage would have cost at list price, not what you paid. If you record what you actually paid, TIER reports the ratio between the two as a separate number. See pricing-philosophy.md for why, and reference-price-table.md for the table itself.
Spend is linked to a piece of work through the branch the AI session was on.
TIER looks for the issue number (the ticket number in your tracker) in the
branch name, such as feature/42-login or fix/TIER-99-crash (only with TIER
configured as a tracker key, for example --tracker-keys TIER), or in a commit
on that branch made around the same time. Spend it cannot link lands in an
unattributed bucket. It stays in the bottom half of the fraction, so it
still lowers the number. Local cost reports and the synthetic demo break out these buckets; coaching
cards use their own attribution fields. Name-free monthly comparisons do not
publish this breakdown. The bucket's label says why the link failed:
| Bucket | What happened |
|---|---|
unattributed:main |
recorded on main or master, which carry no issue number |
unattributed:branch-without-issue |
recorded on a named branch with no issue number in its name |
unattributed:detached-head |
no branch was recorded (a detached HEAD, or none at all) |
unattributed |
from a source that never sees a branch: the proxy, or a vendor's billing feed |
unattributed:main can have a technical cause rather than a missing ticket.
Here is one. A developer starts an AI session in the main copy of the
repository, then has it work in a second working copy (a git "worktree")
checked out on a feature branch. In one installation's session files, examined
on 2026-09-26, Claude Code recorded the branch where the session started and
did not record a later cd into another worktree. Other installations and
Claude Code versions have not been checked. Helper agents that Claude Code runs
in worktrees of their own can land on main the same way;
Attribution in Layer 3 explains how.
The remedy is to start the session inside the worktree, on a branch whose name
carries the issue number. A worktree on a branch without one moves the spend to
unattributed:branch-without-issue instead. Starting in the right worktree fixes
future sessions. A later qualifying PR can also link matching previously
unlinked records to its issue in mutable months, including records labelled
unattributed:branch-without-issue; closed-month inputs stay frozen. tierd doctor --repo .
reports how much of your spend it could link, so you can check whether the fix
worked.
The top half: outcome points
GitHub pull requests count only when merged and when they name an issue, either
in the branch name or in a line such as closes #42 in the description. A
merged pull request with no issue reference is skipped, because its work cannot
be joined to its spend. "Merged" means the merge was recorded (by GitHub, or
through TIER's outcomes API for other trackers). It does not mean deployed.
Unmerged work adds cost and no points. With --push-capture, qualifying direct
commits to the default branch also count at weight 0.5, once per issue per UTC
day. Other trackers can send outcomes through the outcomes API.
Each merged pull request earns points from its size label, on a fixed scale of five sizes:
| Label | Weight |
|---|---|
xs |
0.5 |
s |
1 |
m |
3 |
l |
5 |
xl |
8 |
A person, or your own automation, puts the label on the pull request in GitHub. A pull request with no recognised label is sized from its diff instead, on the same five weights.
The weights are locked. You can rename the labels in the config file, but TIER refuses any weight not on this scale. The lock keeps your own history comparable: a weight change would silently rescale every earlier period. Fixed weights do not establish shared calibration; cross-installation comparison is not supported; compare a team with its own history.
Each pull request's weight is then multiplied by a quality multiplier
between 0.1 and 1.0 when it comes from GitHub (an outcome sent through the
outcomes API carries the quality its sender set, from 0 to 1). It is 1.0
unless something goes wrong after the merge and GitHub's webhook reports it;
without the webhook nothing lowers it after the merge.
A failing GitHub Actions run (the automated build and tests) on the merge commit within 48
hours lowers it to 0.7, unless a re-run of the same check soon passes. A revert
within 60 days lowers it to 0.8 when the revert was a business decision, or to
0.1 when it was a code problem. TIER tells the two apart from keywords in the
revert's human-written commit message, and treats a revert as a code problem
unless the message gives only business reasons. The worst of these wins. Other PR-head SHAs are not scored. In v0.6.1 (#1230), only push-triggered runs on the default branch with a recorded merge SHA change quality; matched scheduled and dispatched runs are audit-only, and merge_group runs are dropped. The matcher still enforces no lower event-time bound; a matching push-triggered failure timestamped before merge can count. A revert
can arrive weeks after the merge, so a live historical score can still move.
Monthly closes freeze activity and census; later quality events, aliases,
backfills and repricing do not revise them. Only the paid layer can be revised,
and erasure/retention pooling removes identities while conserving totals. The
numerator is Σ(weight × quality) with corrective-work scoring off (the default).
Three things that will bite you
1. Task mix moves the number, and the number cannot separate it from skill. A quarter spent building new features and a quarter spent chasing production bugs will not score the same. The number cannot say how much of the gap comes from the work and how much from the people. Compare a team to its own history, not to another team's number.
2. Name-free monthly comparisons apply a privacy floor. A closed month's
census counts rostered, non-bot people with both positive qualifying spend and
a positive outcome count on the dated path; a direct push can supply the
outcome. Qualifying spend comes from bound uploads,
--watch-as server watches or root-mapped vendor-attributed events; shared,
legacy and manual spend cannot establish a counted person. Aliases do not lend
another subject's evidence. A person counts once across model rows and paths.
Comparisons use the larger of the close's k and the reading server's k (default
five, minimum three). Small groups can fold into Other; complementary suppression
can withhold siblings or parents to prevent subtraction. One tree decision
covers the additive figures; there is no separate spend/points/paid contributor
floor. Paid and realtime amounts do not decide which groups publish. A shown
group also needs at least two members. See manager-faq.md.
Named branch reports and coaching cards instead follow issued-key access and
names_visibility; personal keys retain their holder's own figures.
For local use, tierd score --repo <path> shows captured cost and its
issue-attributed share; add --outcomes for personal TIER. The dashboard demo
uses invented data. See quickstart for real-server setup.
3. The two halves must cover the same stretch of work. Both halves are counted over the same calendar dates. TIER does not pair each merged pull request with the exact spend that produced it. Spend is recorded when it happens, and points arrive later, at merge. Two things follow:
- A window that ends too recently reads low. Its spend is in, but some of its work has not merged yet.
- A window that starts before TIER began recording spend reads high. That starting point is your installation's cost horizon. Work merged before it is counted, but its spend was never recorded, so it looks free.
On one real multi-repo installation, measured on 2026-07-26, the API's default
90-day window gave a number about twice as high as the trailing 30 days, which
roughly matched the period whose spend had been recorded. TIER warns about this
second case, with a dashboard banner and a tierd doctor check, but it still
computes the number. There is
no fixed safe length. For a live named report, the rule of thumb is a window several
times longer than your usual time from first AI use to merge, starting after the
cost horizon. For a name-free comparison the window is a closed month: read
months that start on or after the cost horizon; reading an earlier one, the
dashboard banner names the first such month.
See interpreting-the-number.md.
Next: The full method, page by page. Before you rely on any score, read interpreting-the-number.md, which covers windows, skew and when a score is too early to trust.
Layer 3 — The full method, page by page
Layer 2 gave the formula, the weights and the multiplier values. For each step, this layer says what the program does, gives each rule's key numbers in brief and links the page that owns it, so each rule has one copy to keep correct. For a code-grounded account of what the tool does and does not do today, read how-it-works.md alongside it.
From install to a first real score
Solo users can stop after step 3 for their own local cost table and the
issue-attributed share of that spend. tierd score --repo . --outcomes also
computes a local personal TIER score by joining that spend to the GitHub token
owner’s merged PRs; it persists nothing and shows no team band. Run tierd demo
for the dashboard on invented data. The remaining
steps load an organization server; name-free comparisons require a closed
month and enough counted contributors. Start in the current UTC month with a
fresh database. Backfill and ship only that month so startup cannot freeze older
outcomes before their matching spend and roster arrive. Writable serve closes
due months at startup and every minute, 24 hours after month end. Finish roster
import, shipping and identity mapping before then; later uploads cannot revise
frozen costs or census. This sequence cannot bootstrap complete historical
reports; use offline score --outcomes for past work. For branch reports, use
the first full month after the roster takes effect.
See the quickstart for the full setup.
-
Install. Go 1.27.3 or newer, or a release download: quickstart.md §1.
-
Check capture. In your repository's folder, run
tierd doctor --repo .. It reports what TIER can read on this machine and how much of your spend it could link to an issue. -
See the cost side.
tierd score --repo .prints cost per issue from your local session files. It needs no server and no GitHub access. It shows cost only by default; add--outcomesfor personal TIER. In v0.7.0 it reads Claude Code, Codex CLI, Opencode (Z.ai coding plan) and Muse Code logs by default. Server capture in steps 5 and 6 still needs the collector flags named in step 6. -
Load merged work.
tierd backfill --repo <owner>/<name> --token @<file> --since "$(date -u +%Y-%m-01)"reads your merged pull requests from GitHub.<owner>/<name>is the repository as it appears in its GitHub URL.<file>is a file holding a GitHub token that can read the repository's pull requests; README § What you need before you start shows how to create one. -
Serve and issue bound keys. Start
tierd serve. Bootstrap root on the host and import your developer into the team map. Issue a personal or upload key for that developer. This walkthrough starts no watcher: repeat step 6 for new activity before the month closes. For a separate live watcher, see bound watcher setup. -
Load this month's spend. In a second terminal, run
tierd ship --server http://127.0.0.1:8080 --repo <path> --developer <login> --bound-token @<key-file> --since "$(date -u +%Y-%m-01)". Use the same current-month start as step 4 so outcomes are not loaded from months that could close before their matching spend arrives.--serveris the address the server from step 5 listens on, and<path>is your checkout folder.<key-file>holds the issued personal or upload key.shipreads Claude Code sessions only, unless you add--codex-rolloutfor Codex,--opencodefor Opencode or--musefor Muse Code. Without it, a run on a repository where you used only one of those tools finds nothing and stops with an error that blames the--repopath. -
Check identity. Use the same developer identifier for a separate watcher's
--watch-as,ship --developerand the issued key's subject, preferably your GitHub login from step 4. Bound uploads use the key's subject; the identity is not necessarily your OS login. If historical spend uses a different identifier, root can join it with an alias after checking that both identifiers belong to the same person. See README § Identity mapping. An alias corrects live reads and future closes; it does not rewrite closed months or turn legacy spend into qualifying bound evidence. Check before you join historical records. If that historical identifier is your current OS login ($USER), inspect it withprintf 'Authorization: Bearer %s\n' "$(cut -f4 ~/.tier/root-credential.tsv)" | curl --fail-with-body -H @- "http://127.0.0.1:8080/api/v1/developer/$USER/export"The sum of
cost_microintoken_eventsmust be above 0, andoutcomesmust benullor empty (no merged work). If you havejq, add| jq '{spend: ([.token_events[]?.cost_micro] | add), outcomes: (.outcomes // [] | length)}'to the command to print both. If the export fails, spend is absent, or any outcome is present, stop here. Merged work may belong to somebody whose GitHub login matches your computer login. The join moves both spend and merged work, so it would put that person's work into your score. The check covers only merged work loaded so far. After the join, the same export also lists your own merged work, so before any laterbackfill, check that every pull request in itsoutcomesis yours. If one is not, undo the join withprintf 'Authorization: Bearer %s\n' "$(cut -f4 ~/.tier/root-credential.tsv)" | curl --fail-with-body -H @- -X DELETE "http://127.0.0.1:8080/api/v1/developer_alias/$USER"If the check passes, tell the server they are one person:
printf 'Authorization: Bearer %s\n' "$(cut -f4 ~/.tier/root-credential.tsv)" | curl -f -H @- -X POST http://127.0.0.1:8080/api/v1/developer_alias \ -H "Content-Type: application/json" \ -d '{"alias":"<login-name>","canonical":"<github-login>"}'<login-name>is the historical identifier checked above and<github-login>is your GitHub login. Use the issued root key for these setup requests, saved in~/.tier/root-credential.tsvby the root bootstrap. The server answers201 Createdwith an empty body, so the command prints nothing when it works. The join also applies to spend and work already loaded in live reads and future closes; closed monthly figures stay frozen. The team-server form is in README § Identity mapping. -
Open the dashboard. Open
http://127.0.0.1:8080and sign in with your issued key. To read the latest closed monthly comparison as JSON, use root:printf 'Authorization: Bearer %s\n' "$(cut -f4 ~/.tier/root-credential.tsv)" | curl -f -H @- http://127.0.0.1:8080/api/v1/scoresA monthly comparison requires a completed close; without one it returns 404.
Everything is stored in one SQLite database file on the machine running the
server, ~/.tier/tier.db by default. For a shared team server, with tokens,
the GitHub webhook, and spend sent in from each developer's laptop, see
README § Run it for a team.
Capture — how spend gets measured
TIER is JSONL-first. The primary path reads the session files the tool
already writes locally. On that path no proxy sits in front of your model
provider and no request is intercepted. An optional reverse proxy exists for
tools that write no usable local log, and open-weights and self-hosted models
have their own capture path. On a team, each developer runs tierd ship on
their own machine. It reads the local session files and sends the cost
records to the team's server; this is the laptop-shipper setup.
- Capture paths and the laptop-shipper topology — README § Capturing tokens
- Self-hosted and open-weights models — open-weights-capture.md
- What is read, stored, and never touched — privacy.md
Pricing — how tokens become dollars
ComputeCost, the function that turns an event's token counts into dollars,
prices each event against the table in internal/store/prices.yaml. That file
is compiled into the program and is the single source of truth. It is
versioned as one unit: any price change bumps the table's single version
number. Each cost is fixed when it is recorded and stamped with the version
that priced it, so upgrading TIER does not reprice history. tierd reprice is
the explicit, audited way to reprice raw history; it does not revise monthly
closes. A window whose costs span several versions is flagged.
Before lookup, a model name is lowercased and a trailing date stamp (plus
-preview or -latest) is removed. Dated snapshots of one model therefore
share a price, while differently named versions keep their own. A model not in
the table is priced by a guess. Names containing nemotron-ultra or
deepseek-r1-full select the large self-hosted class; names containing
phi-4-mini, embeddings or reranker select the small class. Otherwise, a
parameter count in the name (such as 70b) selects a self-hosted size-class
rate. If neither rule matches, it gets the flat self-hosted-medium rate of
$0.50 per million tokens. For either guess path, the server
writes a one-time warning per model name to its log and counts the event in the
tier_unknown_model_events_total metric. Open-weights models are priced by
model and by the host serving them, because the cost belongs to the host,
not the weights.
- Why list prices, not invoices — pricing-philosophy.md
- The table, and §4's list of corrections to older copies of it — reference-price-table.md
- Normalization rules and the target governance model — cost-normalization-spec.md
Attribution — how spend is tied to work
Spend is joined to an issue through the issue reference carried by the
session's branch. Merged work is joined through the pull request's branch name
or a closes #N line in its body. Bound uploads use the issued key's subject;
--watch-as sets the Claude Code watcher's subject. Other local capture can
use the computer login or a configured developer identifier. Outcomes use the
PR author's GitHub login. Root can map identifiers belonging to one person
through the alias API so cost and outcomes join in live reads and future
closes. Monthly closes retain their frozen identities, activity and census;
aliases do not rewrite them. The monthly quality block reports whole-company
cost-only and outcome-only counts when that population is published; it does
not list unjoined names. Named reports remain scoped by the holder's issued key.
Claude Code can run helper agents in worktrees of their own, on branch names
it makes up (worktree-agent- followed by a code). Those names carry no issue
number, so TIER uses the last branch a person named earlier in the same session
file. If that branch was main, the helper's spend lands on main too.
- Branch, label, and issue-reference conventions — conventions.md
- Identity mapping — README § Identity mapping. Real-server alias administration requires an issued root key, including on loopback.
Scoring — how outcomes become points
The canonical rubric defines the fixed {0.5, 1, 3, 5, 8} size scale, the
label taxonomy, the fallback for a pull request with no recognised label, and
the quality multiplier derived from quality events. The fallback sizes a pull
request from its diff: lines changed plus ten for each file changed, bucketed
onto the same five weights.
Two checks decide whether a score has enough behind it to read. A row is only
treated as sound once it has at least 3 outcomes and at least $5 of list-price
spend; below that it is still shown, marked as below the evidence floor. A
merged pull request is flagged when its developer recorded fewer than 1,000
tokens against its repository and issue in a 14-day window ending at the latest
merge that reuses that issue among the outcomes being scored. Reused issues share
that window, so an older merge can be flagged too. Its points still count, but its developer's row is
marked as not sound, because TIER cannot tell whether the work used AI it
never saw, was badly attributed, or was genuinely done without AI. Direct commits to the main branch, with no
pull request, count only if the operator turns on --push-capture, and then at
the smallest weight, 0.5.
- The canonical rubric, and why it defines no absolute good/bad band — rubric.md
- The quality multiplier's degradation rules — quality-degradation-spec.md
- Outcome ingest for teams not on GitHub — outcomes-api.md
- GitHub webhook wiring — webhook-setup.md
Reading the result
Use your first settled window as your baseline, and read later windows against it. The rubric deliberately defines no absolute good or bad band.
GET /api/v1/scores?period=YYYY-MM returns a monthly comparison manifest.
Read disclosures.horizon.window_predates_cost_capture and
disclosures.horizon.cost_coverage_safe_since for the frozen cost horizon;
choose a closed UTC month beginning at or after the safe date. An unknown or
unrecorded horizon does not establish complete capture. disclosures.partial_input
and origin_evidence disclose retention and capture loss.
Shown rows are in comparison.Nodes and comparison.Other, with figures only
when Disposition is shown; comparison_withheld signals that some figures were withheld or folded.
Hidden rows are omitted from the public comparison. Monthly comparison routes reject arbitrary since/until windows.
A month without a close returns 404. Named reports and coaching cards have
their own response shapes; the synthetic demo retains its data_quality block.
- Honest reading, windowing skew, and when a score is too early to trust — interpreting-the-number.md
- Where TIER sits alongside DORA (the DevOps Research and Assessment delivery metrics), SPACE (a developer-productivity framework) and DX Core 4 (which folds DORA, SPACE and DevEx into four dimensions) — how-tier-relates.md
- Moving practices between people without ranking them — peer-learning.md
The limits, stated plainly
TIER can be gamed. The known ways are documented: label inflation, splitting pull requests, picking cheap work, and several failure modes that are structural rather than deliberate. Read adversarial-analysis.md before the score is used anywhere it could affect how people are treated.
Measuring developers individually is regulated in some jurisdictions. Two separate kinds of rule apply. Works-council co-determination rules, such as Germany's §87 BetrVG, can require the works council's agreement before a monitoring tool is introduced. GDPR Article 22 restricts decisions about a person made solely by automated processing. Read legal-and-privacy.md before introducing named or group reporting; it covers works-council consultation and data protection impact assessments (DPIAs).
On real data, root reads everyone and node keys read their dated branch when
names_visibility permits; personal keys retain their own figures and card.
Each card read is audited before construction. Shared/static credentials and
tokenless real-server access are retired. Host/database owners remain trusted
with retained data. The synthetic demo exposes invented rows only.
Interfaces
/api/v1compatibility contract — what is pinned and what may change — api-compatibility.md- Operator security model — security.md
- Full documentation index — docs/README.md