Repository navigation
Code Authority Facts
Some facts are born in code. The list of features Pro unlocks is decided by an Entitlements enum, not by a YAML file, and copying it into YAML would just create a second thing to drift. authority: code flips the direction: the fact reads its value from a code symbol on every run. This page covers the syntax, the short symbol form, how resolution works after ingest, the anchors bridge it creates, what happens when the symbol can't be found, and what a code PR that edits the symbol looks like. Source: compileProject, normalizeSymbol and resolveCodeFacts in compiler/compile.ts, and buildProject in project.ts.
A code-authority fact is a fact spec with authority: code and source.symbol:
id: addon:pro
facts:
features: { authority: code, source: { symbol: ios/Entitlements.proFeatures } }-
source.symbolis required. Without it the load fails:fact addon:pro.features has authority "code" but no source.symbol(exit code 2). -
valueis optional and gets overwritten once the symbol resolves. You can leave it out.
normalizeSymbol adds the symbol: prefix if it's missing, so these are equivalent:
source: { symbol: ios/Entitlements.proFeatures }
source: { symbol: "symbol:ios/Entitlements.proFeatures" }The rest of the id follows the normal per-language format (Node IDs): ios/Pricing.proUSD (Swift), web/lib/pricing#PRO_FEATURES (TS), android/Pricing.PRO_USD (Kotlin), api/internal/pricing.ProUSD (Go). The scope name comes first.
buildProject runs these steps in order:
-
Compile the YAML. The fact node is created with
authority: "code", the givensource, andvaluefrom YAML (usuallyundefined). A pending entry{ factId, symbol }is recorded. - Import design tokens, if configured.
- Ingest code and merge the code layer into the graph.
-
resolveCodeFacts, for each pending fact:- look up the symbol node by id;
- if found, copy the symbol's literal
valueinto the fact and addsymbol --anchors--> factwithorigin: "declared"; - if not found, record it as unresolved.
-
recomputeContainersrebuilds every container fact from its leaves, so a container over a code fact gets the right value. - Warn about unresolved facts.
The value comes from the symbol's extracted literal. The ingestor reads string, number and boolean literals, arrays of them and simple object literals. A symbol whose initialiser isn't a literal (a function call, a computed expression) has no value. The anchors edge is still added, but the fact keeps its YAML value (or stays empty).
After resolution, the demo's fact looks like this (starchart node addon:pro.features):
{
"id": "addon:pro.features",
"kind": "fact",
"authority": "code",
"source": {
"symbol": "ios/Entitlements.proFeatures"
},
…
"value": [
"Themes",
"iCloud sync"
]
}
--partOf--> addon:pro
<--describes-- appstore:listing/description
<--describes-- web:pricing-page
<--anchors-- symbol:ios/StarchartFacts.AddonPro.features
<--anchors-- symbol:web/lib/starchart-facts#ADDON_PRO_FEATURES
<--anchors-- symbol:ios/Entitlements.proFeatures
source.symbol keeps whatever you wrote (the short form here). The edge uses the normalised id.
The resolved fact gets symbol:ios/Entitlements.proFeatures --anchors--> addon:pro.features. anchors propagates in both directions, so:
- editing the Swift array changes the symbol hash → impact flows into the fact → out to everything that embeds, describes or mirrors it;
- the lockfile's dependency walk crosses the same edge, so artifacts that depend on
addon:pro.featuresalso pinsymbol:ios/Entitlements.proFeatures's hash.
flowchart LR
S["symbol:ios/Entitlements.proFeatures<br/>(Swift literal)"] -- anchors --> F["addon:pro.features<br/>authority: code"]
F -- partOf --> E["addon:pro"]
P["web:pricing-page"] -- describes --> F
L["web:landing-hero"] -- describes --> E
If the symbol isn't in the code layer (typo, renamed, file excluded, scope misnamed), the fact keeps its YAML value (usually none) and every command warns on stderr:
warn fact addon:pro.features: code symbol symbol:ios/Entitlements.proFeatures not found
The warning doesn't change exit codes. It does change hashes: the fact's value goes from the array to undefined (hashed like null), so starchart check reports every dependent as stale. Renaming the Swift constant to allFeatures without updating the YAML gives:
warn fact addon:pro.features: code symbol symbol:ios/Entitlements.proFeatures not found
✗ stale appstore:listing/description
changed: addon:pro.features
…
When ingestion is skipped (journals, history, adapters), code facts are never resolved and there's no warning. Their value stays whatever the YAML says. emit jsonld always ingests code, so code-authority facts like addon:pro.features export with their sc:value; --code only decides whether code nodes themselves go into the full export (JSON-LD and SEO).
A teammate adds a feature in Swift:
enum Entitlements {
static let proFeatures = ["Themes", "iCloud sync", "Widgets"]
}Nobody touched .starchart/. starchart plan still sees the change, from two sides: the symbol's hash moved (it's pinned in lock.code), and the fact's value moved (pinned in lock.facts):
Change: addon:pro.features ["Themes","iCloud sync"] → ["Themes","iCloud sync","Widgets"]
Change: symbol:ios/Entitlements.proFeatures "67931739280ac34c" → "3043a3a49728dca7"
! manual appstore:screenshots/6.9/03 captures screen changed; re-capture
~ auto symbol:ios/StarchartFacts.AddonPro.features anchors regenerate fact constants (codegen)
~ auto symbol:web/lib/starchart-facts#ADDON_PRO_FEATURES anchors regenerate fact constants (codegen)
? review appstore:listing/description describes describes this semantically
? review web:pricing-page describes describes this semantically
? review email:onboarding-day-3 describes describes this semantically
? review web:landing-hero describes describes this semantically
✗ retire reel:spring-2026 promotes expired 2026-06-30
✓ tests test:ios/Tests/PaywallTests.swift tests run these tests
Order: appstore:listing/description → appstore:screenshots/6.9/03 → symbol:ios/StarchartFacts.AddonPro.features → symbol:web/lib/starchart-facts#ADDON_PRO_FEATURES → email:onboarding-day-3 → web:landing-hero → web:pricing-page → reel:spring-2026
Plan: 1 manual · 2 auto · 4 review · 1 retire · 1 tests
(3 informational items hidden; use --verbose)
And starchart check fails CI (exit 1) until someone handles it:
…
✗ stale web:landing-hero
changed: addon:pro.features
changed: symbol:ios/Entitlements.proFeatures
✗ stale web:pricing-page
changed: addon:pro.features
changed: symbol:ios/Entitlements.proFeatures
Check: 6 stale
The fix loop:
-
starchart applyregenerates the web and iOS fact constants (the twoautoitems) in one codegen pass, and pushes anyautoartifacts:✓ symbol:ios/StarchartFacts.AddonPro.features [codegen] regenerated apps/web/lib/starchart-facts.ts; regenerated apps/ios/Sources/Core/StarchartFacts.swift ✓ symbol:web/lib/starchart-facts#ADDON_PRO_FEATURES [codegen] regenerated apps/web/lib/starchart-facts.ts; regenerated apps/ios/Sources/Core/StarchartFacts.swift … -
Update the App Store listing copy and the pricing page wording (
review), re-shoot screenshot 3 (manual), retire the reel, thenstarchart ack <ids…>. Until thenplankeeps listing them. -
Commit the updated
starchart.lockwith the PR.
With the GitHub Action, the same blast radius lands as a PR comment via impact --diff.
authority: code |
@starchart anchors annotation |
|
|---|---|---|
| Where the truth lives | the code symbol | the YAML fact |
| Fact value | read from code on every run | written in YAML |
| Edge created |
symbol --anchors--> fact, origin declared
|
symbol --anchors--> fact, origin annotation
|
| Code symbol in a plan | the thing that changed | classed code: update the literal or switch to codegen |
Use code authority when engineers own the value (entitlements, feature lists, limits). Use annotations when marketing or product owns it and code just has to keep up.
★ STARCHART
☠ a Space Pirate Zero joint
STARCHART Every dependency. Code to cosmos.
Guides
Concepts
- Three-Layer Model
- Facts and Entities
- Artifacts and Bindings
- Edge Types
- Node IDs
- Impact Analysis
- Lockfile and Drift
- Rollout Ordering
Authoring
Code layer
Commands & API
Adapters & engine
- Adapters Overview
- Adapter: fs
- Adapter: url
- Adapter: Stripe
- Adapter: App Store Connect
- Writing an Adapter
- Audit and Break Detection
- Apply, Revert and Journals
- Future Universe Preview
- Viewer and Serve
- Reality X-Ray
Rules & analysis
Integrations
Project