Repository navigation
Change Cost
The change-cost advisor answers the question every refactor argument really comes down to: what does it cost us to change this value, and what would make it cheaper? For every fact and entity, starchart cost runs the same impact walk as starchart impact, weights each impacted item by class into estimated person-hours, and suggests the changes that would cut the cost most (codegen, templates, bindings, write access). This page covers the algorithm, the default hours table, how suggestions are built, real output from the demo, and how to use it to pick your next refactor. Source: analysis/cost.ts.
starchart cost # top 15 facts/entities by hours
starchart cost -n 5 # top 5
starchart cost addon:pro.price.usd # specific ids
starchart cost -f json # CostReport[] (also limited by --top)With no ids, it costs every entity plus every leaf fact (facts with no child facts), except the generated <entity>.status facts. Ids that don't exist are skipped silently, and the command exits 0. -f accepts only text or json; -f markdown is rejected by the argument parser (exit 1).
flowchart LR
F[fact or entity] --> I[computeImpact<br>same walk as starchart impact]
I --> C[count items per class]
C --> H["hours = Σ count × rate"]
I --> S[suggestions + savings]
For each id:
- Run
computeImpact(graph, [id], { canWrite }).canWritecomes from your config, so an adapter withwrite: trueturns itsmanualitems intoauto, but only for artifacts the adapter'scanApply(node)accepts (App Store screenshots and IAPs staymanual). See Impact Analysis for how items are classified. - Count items per class (
byClass).impactedis the total, includinginfoitems. -
hours = Σ byClass[class] × rate[class], rounded to two decimals. -
hardcoded= the number ofcodeitems (non-generated code literals that anchor the fact). -
mediaBurnIns= the number ofmanualitems reached throughembedswhose node is aschema:ImageObjectorschema:VideoObject. - Build suggestions (below).
Reports are sorted by hours (highest first), then id.
| Class | Hours per item | Meaning |
|---|---|---|
auto |
0.05 | STARCHART applies it. Someone glances at the diff. |
code |
0.25 | A hardcoded literal to update by hand. |
test |
0.1 | A test to run. |
review |
0.5 | Someone reads it and decides (describes, promotes, derivedFrom, …). |
manual |
1.5 | A human updates an external system, re-shoots a screenshot, or re-edits a video. |
retire |
0.5 | Take down an expired or retired-dependent artifact. |
break |
1 | Something will break (for example, code referencing an archived Stripe price). |
info |
0 | Informational only. |
These are rough, deliberately round numbers for ranking, not estimates for invoices. Library callers can override them: changeCost(graph, ids, { hours: { manual: 3 } }). There is no CLI flag for custom rates.
Suggestions are built in this order. Each one that applies also adds its savings to a running total:
| Condition | Suggestion | Savings |
|---|---|---|
code items reached directly from a fact > 0 |
N hardcoded code anchor(s): generate constants with \starchart codegen` to make these auto` |
N × (code − auto) |
| media burn-ins > 0 | N image(s)/video(s)/media asset(s) embed(s) this value: bind it/them to a template (renders) to regenerate automatically |
N × (manual − auto) |
other manual items with no binding (not media, not captures) |
N artifact(s) has/have no binding: bind it/them so STARCHART can audit and update it/them |
none |
other manual items whose adapter can write that artifact
|
N manual update(s) in <adapters>: enable write access for this adapter/these adapters to sync automatically |
N × (manual − auto) |
| savings > 0 and hours > 0 | Doing this cuts the change cost from <hours> to <hours − savings> |
In the summary line, costs under an hour print as minutes (45 min), otherwise as hours with up to two decimals (1.75 h).
A few details:
-
capturesitems ("screen changed; re-capture") never get a suggestion. There's no automation for re-shooting screens yet. - The bind suggestion adds no savings. Binding makes an artifact auditable, but it still needs an adapter that can write.
- The codegen suggestion only counts
codeitems whose last hop starts at a fact. Codegen emits fact constants, so a symbol reached through an artifact (like a Stripe price-id constant thatanchorsa Stripe price) can't be generated and isn't counted.hardcodedin the JSON still counts everycodeitem. - The write-access suggestion only counts items whose adapter is registered, declares
capabilities.write, implementsapply(), and (if it has one) returns true fromcanApply(node). Sourlartifacts, unregistered adapters (like the demo'syoutube), and App Store screenshots and IAPs (App Store bindings without afield) are never listed. Those stay manual no matter what you set.
From a temp copy of examples/pro-universe, where Stripe and App Store are read-only (the default for external adapters):
$ starchart cost
████████████████████ 9.4h addon:pro.price.usd (21 impacted)
→ 1 hardcoded code anchor: generate constants with `starchart codegen` to make these auto
→ 1 image embeds this value: bind it to a template (renders) to regenerate automatically
→ 2 manual updates in appstore, stripe: enable write access for these adapters to sync automatically
→ Doing this cuts the change cost from 9.4 h to 4.85 h
████████████ 5.7h addon:pro.name (16 impacted)
→ 1 hardcoded code anchor: generate constants with `starchart codegen` to make these auto
→ 2 manual updates in appstore, stripe: enable write access for these adapters to sync automatically
→ Doing this cuts the change cost from 5.7 h to 2.6 h
███████████ 5.0h addon:pro.productId (12 impacted)
→ 1 hardcoded code anchor: generate constants with `starchart codegen` to make these auto
→ Doing this cuts the change cost from 4.95 h to 4.75 h
█████████ 4.5h addon:pro.features (13 impacted)
→ 1 hardcoded code anchor: generate constants with `starchart codegen` to make these auto
→ Doing this cuts the change cost from 4.45 h to 4.25 h
███████ 3.1h addon:pro.price.eur (9 impacted)
███ 1.6h addon:pro.billing (7 impacted)
███ 1.5h addon:pro (4 impacted)
█ 0.0h app:nebula (0 impacted)
…
The bar is scaled to the most expensive row (20 blocks). The hours column is rounded to one decimal, and the summary line uses two, which is why addon:pro.productId shows 5.0h next to 4.95 h.
The JSON for the top fact (starchart cost addon:pro.price.usd -f json, trimmed to the object) shows the math:
{
"id": "addon:pro.price.usd",
"impacted": 21,
"byClass": { "auto": 6, "code": 2, "test": 1, "review": 1, "manual": 5, "retire": 1, "break": 0, "info": 5 },
"hours": 9.4,
"hardcoded": 2,
"mediaBurnIns": 1,
"suggestions": [
"1 hardcoded code anchor: generate constants with `starchart codegen` to make these auto",
"1 image embeds this value: bind it to a template (renders) to regenerate automatically",
"2 manual updates in appstore, stripe: enable write access for these adapters to sync automatically",
"Doing this cuts the change cost from 9.4 h to 4.85 h"
]
}Hours: 6 × 0.05 + 2 × 0.25 + 1 × 0.1 + 1 × 0.5 + 5 × 1.5 + 1 × 0.5 = 9.4. Savings: 1 × 0.2 (codegen) + 1 × 1.45 (template) + 2 × 1.45 (write access) = 4.55, so 9.4 → 4.85 h.
What those items are (from starchart impact addon:pro.price.usd):
-
2 code:
symbol:ios/Pricing.proUSDhardcodes the price in Swift.symbol:web/lib/stripe#PRICE_PRO_MONTHLYis the Stripe price-id constant, reached because it anchorsstripe:price/pro-monthly, which mirrors the price ("holds this artifact's external id; update it if the id changes"). The generatedStarchartFactsconstants are alreadyauto. OnlyPricing.proUSDcounts toward the codegen suggestion: codegen emits fact constants, so the Stripe id constant would need its own fact (for example astripePriceIdfact) before codegen could own it. -
1 media burn-in: App Store screenshot
appstore:screenshots/6.9/03has the price burned in. -
4 other manual: the Stripe price and the App Store description can be written once you enable writes, so they're the 2 in the write-access suggestion. The App Store IAP (
appstore:iap/pro-monthly, nofield) and the live pricing URL (urladapter) can't be written by any adapter, so they're left out. -
1 retire: the expired
reel:spring-2026.
Read the top of the list as a refactor backlog, ranked by pain:
-
Hardcoded anchors → codegen. Each
codeitem is a literal a human must find and edit. Add acodegen:target for the entity, replace the literal with the generated constant, and those items becomeauto(0.25 → 0.05 h each). They also stop trippinganchor-matches. See Codegen. -
Burned-in media → templates. Every image that embeds a value costs a designer 1.5 h per change. Turn it into a template artifact with
renders: { template: …, with: [facts] }, like the demo'sweb:og-pro, andstarchart applyregenerates it. For a store screenshot that captures a real screen, the honest fix is often to keep the price out of the screenshot. - Unbound artifacts → bind them. No binding means no audit and no updates. This saves no hours by itself, but it's the prerequisite for step 4.
-
Read-only adapters → enable writes, deliberately. External adapters are read-only unless you opt in with
adapters.stripe.write: true(orappstore). Once enabled, thosemanualitems becomeauto, andstarchart applysyncs them with a journal you can revert. This is a trust decision, not a free win. Read Apply, Revert and Journals first, STARCHART only suggests adapters that can actually write the artifact, sourlchecks and App Store IAPs never show up here. -
Re-run
starchart costafter each step. The demo's price goes from 9.4 h to 4.85 h with steps 1, 2 and 4. What's left is mostly work no adapter can do: the IAP, the live-page check, the review item, and the expired reel.
Facts with many review items (lots of describes) are a copy-sprawl signal. Consider whether all those pages need to talk about the value at all.
★ 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