FACTION_STANDING_WIRING_SPEC.md

systems/FACTION_STANDING_WIRING_SPEC.md

Faction standing — the wiring spec

Status: ACTIVE (2026-08-04). The engine-consumable half of the faction-standing mint. The

executable half is harness/emit_faction_registry.py and harness/apply_ladder_rewards.py; the data

is four tables. This doc is what an engine lane reads to wire readers and writers off real rows.

0. What this closes

The fun-gap wave-2 audit found the nine-band standing ladder ruled and its struct generated, and then

found nothing underneath it: the ladder registry held two rows with a blank reward reference, 160 of

164 cast rows carried 176 distinct free-text faction tokens with no table to point at, the two

worldstate rows named consumers that resolve to nothing, and **only the negative direction of

community memory was specced** — the corpus could record being hurt and could not record being

helped.

Josh's bar, verbatim: *"trades and skills and reputations and factions and exploration like World of

Warcraft."* A world that only remembers harm is not that world. So the grammar below carries both

signs, and the positive side is the larger one: twenty-four positive classes against sixteen harm

classes, every one of them lifted from a line canon had already written and nobody had wired.

1. Derivation (SUBAGENT_CONTRACT §1 clause 5)

DERIVED FROM:

— the *Five-Factors faction table* on all twelve slice region pages. Every faction row is minted

from one bullet and cites its line: flores_island.md:L812-L821, bali.md:L1854-L1870,

sumatra_java.md:L1787-L1794, angkor_khmer.md:L622-L625, sri_lanka.md:L838-L858,

south_india.md:L713-L732, swahili_coast.md:L735-L755, ethiopia.md:L655-L672,

rift_valley.md:L576-L590, central_africa_congo.md:L939-L958, west_africa.md:L2162-L2193,

south_africa.md:L63,L67,L573.

nine ruled bands and the STANDING label list), §8.11.4 (write discipline: qualitative

class-and-direction tokens, never point values), §8.7 (faction standing never hard-gates

progression; relationships are locally real and not symmetrically modeled), §4.9 (accumulation),

L192 (a kill ripples through the community and is remembered).

live CSV on every run, never hand-typed.

*standing*: FST_0003, FST_0004, FST_0005, FST_0008, FST_0010, FST_0011, FST_0013, FST_0014,

FST_0016. Derived by reading the registry, with a positive control that fails the emit if the set

drifts from the routing table.

the eight standing writes the slice already authored in prose.

§ The engine — the harm side's

existing doctrine (witness, memory, community resilience, the escalation ladder), which the

negative half of the grammar references rather than re-invents.

NOT DERIVED (authored judgment, and why it had no canon home):

"closed but courteous"); the nine bands are numeric. Something had to map one onto the other. The

rule is stated, deterministic, unit-tested, and every row carries the page's own phrase beside the

derived band so the mapping is auditable against source rather than trusted.

enumerate reward classes. The table only re-expresses cited improve classes as offers and adds

nothing that no page named.

2. T0_Faction_Registry — the table the 176 tokens now point at

67 rows, 22 columns. registries/T0_Faction_Registry [DRAFT v0.1]/Sheet1.csv.

2.1 Shape

columnUE typenotes
faction_idFNameFAC_\d{4}, RowName
faction_nameFTextplayer-facing; localization-bearing
kindUENUM + FString mirrorcommunity · institution · order · network · apparatus
region_refFDataTableRowHandleT0_Region_Index.region_id
chapter_refFNameCH_NN
relationship_typeFStringthe page's own token, carried verbatim
standing_on_arrivalUENUM + mirrora STANDING label, or NOT_APPLICABLE
arrival_noteFStringthe region page's own phrase — the evidence for the derived band
web_ally_refs / web_rival_refs / web_trade_refsFString + parse helper;-joined FAC_ ids
improve_event_classes / degrade_event_classesFString + parse helper;-joined SE_ ids
never_targetUENUM + mirrorTRUE (inviolate individual and collective) · COLLECTIVE (the culture is protected; individual members are Tier-2 attackable) · FALSE
joinablebool
questline_refFStringdesigner prose, the page's own
cast_token_countint32how many T0_Character_Index rows re-point here
ladder_refFNameGLOBAL_DEFAULT_9BAND
reveal_gated / reveal_gate_anchorbool / FName
source_refFStringfile:line
notesFStringdesigner prose

2.2 The arrival-band derivation rule

Applied by derive_band(); unit-tested with must-fire and must-not-fire controls.

Stranger (Neutral band).

No region page states an arrival above Friendly, and the emitter asserts it: **Honored, Revered and

Exalted are earned, never granted.** That is the whole shape of the WoW ladder Josh named.

2.3 Two things the table deliberately does not contain

Ch 38, and T0_Faction_Registry is read by slice surfaces. T0_Reputation_Ladder_Registry

FR_0002 is reveal_gated post-Ch-38 and its faction_ref is therefore **blank by the firewall,

not by omission** — the row says so on its own face.

else; the cross-chapter join lives in the antagonist registries where the gating already exists.

3. T0_Standing_Event_Grammar — one vocabulary, both signs

40 rows, 12 columns: 24 positive, 16 negative.

registries/T0_Standing_Event_Grammar [DRAFT v0.1]/Sheet1.csv.

columnUE typenotes
event_class_idFNameSE_\d{4}, RowName
event_classFNameinternal routing vocabulary; never rendered
signUENUMpositive · negative
directionUENUMthe ratified fork vocabulary: generative · neutral · corrosive
familyUENUM + mirrorsolidarity protection provision gift healing rite festival labor knowledge trade restraint restitution record bearing coercion allocation corruption theft extraction harm desecration
player_verbFTextwhat the player does, in a person's words
world_readsFTextwhat the world does back — a person treating you differently, never a bar filling
magnitude_classFStringBLANK on every row. §8.11.4 rules relational movement writes to be qualitative class-and-direction tokens; per-beat rates are runtime clamps. Phase-5M fills this or nothing does
applies_to_kindFString + parsewhich faction kinds the class can fire on
first_wired_writersFString + parsethe rows that fire it *today*
authority_refFStringthe cited canon line the class was lifted from

3.1 The positive side — what the world can finally notice

Every class below cites a clause canon had already written. Josh's four named examples are the first

four checked by the emitter's self-test, so they cannot silently rot out:

SE_0003 freed_the_held (freeing the captives raises standing *because the community is the

refuge that receives them*), SE_0022 exposed_the_apparatus_cleanly.

rite, the Batak sacrifice — the shared table as a standing surface).

and reciprocity matter in a way the ethnography is explicit about*.

(the caci circuit, the kalari pit — climb for community standing, offered never forced).

And the ones the corpus had written and never wired: SE_0006 held_the_ward_through_the_night,

SE_0010 completed_the_work (a terrace block through a full cycle; a forge shift), `SE_0011

took_the_place_assigned (the net line and the division of the kill), SE_0013

returned_what_belongs_to_the_keepers, SE_0014 restrained_from_reaching` — the Baka Jengi gate,

where the region's most protected content is opened by not reaching for it, which is the single

best positive-standing mechanic already sitting in canon.

3.2 The negative side

The harm classes were already doctrine and are now rows on the same ladder rather than a separate

system: SE_0040 read_need_as_leverage, SE_0041 took_more_than_the_share, `SE_0043

stepped_the_line_for_a_private_take (the band's own documented offence), SE_0044

treated_knowledge_as_inventory, SE_0051 participated_in_the_extraction, SE_0052

killed_a_community_member, SE_0054 attempted_systematic_slaughter` — which routes to the escalation

ladder (settlement → region → hunted-across-the-world) and to the Nemesis band's display label,

Hunted. The culture endures and is never erasable; the player becomes the hunted party. That is

the ladder and the anti-genocide floor meeting at one row.

Two rows carry an empty degrade column *by canon, not by omission*: FAC_0059 (the Agojie — no degrade

path routes through violence, HL_0003) and FAC_0044/FAC_0049, where canon stages no beat at all.

4. T0_Standing_Reward_Band and the ladder

4.1 The nine rungs

9 rows. Rewards are classes, and every one is an OFFER: vendor access, escort, teaching, shelter,

festival roles, work contracts, introductions, kit and lore at Exalted. Every row carries the §8.7

no-dead-end clause in its own non_gating_clause column — **standing shapes what you are handed,

never what you can reach.** Nothing on this ladder gates a route; a closed opportunity re-routes to an

equivalent-class alternative.

4.2 T0_Reputation_Ladder_Registry, 2 rows → 52

band_reward_ref, offer_classes, non_gating_note and notes. FR_0001's pre-faction-table

label ("Swahili coast trade-guild") now resolves onto the collective the region page itself names,

the ocean web (FAC_0037). Its trade_off_pair_partner and asymmetric_bridge_ref stay blank on

purpose and say why on the row: §8.7 rules faction relationships locally real and **not

symmetrically modeled**, and no Section 8 bullet declares an opposed pair — an authored one would

be invention.

FR_0001 at runtime, never retyped**, so a per-faction override (a deliberate act under §8.11.4)

cannot happen by accident. offer_classes is derived from that faction's own cited improve

classes through the family → offer table: knowledge → teaching, labor → work_contract, trade →

vendor_access, festival/rite → festival_role, solidarity → escort, protection/healing → shelter,

gift/restraint/restitution → lore, record/bearing → introduction. A community offers what the

region page says you earn from it.

5. The slice writer roster — where standing is written, Prologue → Ch 13

This is the section an engine lane wires off. Left column is the beat or surface; right is the event

class that fires.

5.1 Already authored in the spine (8 writes, now pointing at real ids)

beat / fork optionold free-text tokennowclass
CH_05 FORK_CH05_A generative (CH_05.md:L194)temple_household +FAC_0018SE_0001
CH_05 FORK_CH05_A corrosive (L196)court −FAC_0020SE_0040
CH_05 FORK_CH05_B generative (L206-L207)samosir_community +FAC_0010SE_0001
CH_08 CH08_B## reef (CH_08.md:L131)+waganga_warding_trustFAC_0038SE_0002
CH_08 FORK_CH08_B generative (L185)kilwa_sufi_community standing risesFAC_0033SE_0003
CH_12 FORK_CH12_A generative (CH_12.md:L190)ogboni_resistance +FAC_0061SE_0021
CH_12 FORK_CH12_A corrosive (L193)community −FAC_0064SE_0040
CH_13 FORK_CH13_A both directions (CH_13.md:L267)the mine labour-record markFAC_0066 / FAC_0067SE_0021 / SE_0051

5.2 The nine festival rows — the first wired POSITIVE writers

These are already-authored, already-standing-bearing content that had nothing to write into. They are

the cheapest positive surface in the slice and they are all opt-in.

festivalregion · chapterclass
FST_0003 uma randang, the field-openingflores · CH_03SE_0008, SE_0012
FST_0004 the caci contest seasonflores · CH_03SE_0009
FST_0005 nado mere, feast precedenceflores · CH_02-03SE_0007, SE_0004, and SE_0050 when the claim sours the room
FST_0008 the banten-tegeh temple festivalbali · CH_04SE_0007
FST_0010 canang sari, the daily offeringbali · CH_04SE_0007
FST_0011 Galunganbali · CH_04SE_0008, SE_0004
FST_0013 the bius ritesumatra_java · CH_05SE_0007
FST_0014 the buffalo sacrifice and porbuhitan augurysumatra_java · CH_05SE_0004, SE_0007
FST_0016 the Thap Ba Po Nagar festivalangkor_khmer · CH_05SE_0008, SE_0015

The routing carries a positive control: the emitter re-derives the standing-bearing set from the

festival registry's own text on every run and refuses to emit if it no longer matches this table.

5.3 Where the slice is still silent, named rather than left implicit

Chapters 2, 3, 4, 6, 7, 9, 10 and 11 author zero faction-standing writes today. Their factions,

improve classes and ladder rows now exist, so the writes are authorable rather than blocked — this is

a worklist for the quest and dialogue lanes, not a defect in this mint. The highest-value four, each

already sitting in canon and needing only a beat to fire from:

is a written mechanic with no write.

6. The two worldstate rows now have consumers

Both cells were replaced under an old-value guard in harness/apply_ladder_rewards.py.

T0_Standing_Event_Grammar (the write vocabulary, both signs), T0_Standing_Reward_Band (the read

side), T0_Reputation_Ladder_Registry.faction_ref, and §5 of this doc.

T0_Standing_Reward_Band.reward_band_id, and §5 of this doc.

7. What is declared open, and why nothing was guessed

docs/faction_token_map.csv carries all 176 tokens with a disposition and a reason. 87 tokens across

88 cast rows RESOLVED. The rest are declared:

a director call, not a lane guess: manggarai_adjacent_hunter_lineage_corrupted_individual and

batak_ritual_corrupted_lineage_pustaha_dark_practice both name a lineage *and* mark their bearer

as a corrupt departure from it, so resolving them seats a chapter antagonist inside a protected-host

community, and minting a corrupted-lineage faction asserts the lineage carries the corruption —

which sumatra_java.md:L1790 denies in terms ("the office is honored and the corrupt individual

does not define it"). Two are Ch-47/48 living-institution rows awaiting their region page and a

§17.1 care read. Two are fairy-realm rows the ruled slice order designs last.

Solange Diallo); south_india.md:L732 rules the Siddha tradition out by name; sri_lanka.md:L858

states the counterfeit "is not a community, has no faction, no summoner and no apparatus".

destination is named on every row: that region's page Section 8 faction table, at which point

re-running the emitter re-points them.

Magnitudes stay blank behind Phase-5M by rule, not by omission. The grammar names classes and

directions; the numbers are runtime clamps.

8. Rebuild

python harness/emit_faction_registry.py --selftest   # 23 checks incl. 3 negative controls
python harness/apply_ladder_rewards.py --selftest    # 7 checks
python harness/emit_faction_registry.py --apply
python harness/apply_ladder_rewards.py --apply       # idempotent; re-running is a no-op
python harness/registry_fidelity.py --reference _source/00_Tier_0_Master_Indices \
    --candidate registries --fk-spec docs/fk_spec.json \
    --baseline docs/fidelity_baseline.json --out harness/scorecard \
    --emit-baseline docs/fidelity_baseline.json
python harness/rag/index.py --scope canon     # the canon hash moved; index_freshness reads it
python harness/run_gates.py                   # UNPIPED

Idempotency is proven, not asserted. Re-running the emitter after the re-point has landed

produces a byte-identical docs/faction_token_map.csv. The first cut did not: the census read

the cells it had itself rewritten, saw 132 FAC_ ids where 176 tokens had been, and would have

rewritten the map to nonsense while reporting a clean run. The census now skips already-canonical

cells and merges the prior map — which is the only surviving record of what a re-pointed cell used

to say — and an accounting control fails loudly if a FAC_ cell exists that no RESOLVED row

claims.

Gate state at landing. 46 gates PASS. Two fail and neither is this lane's, both introduced

by commit 604a6624 and reproducible on an untouched checkout: scan reports a

lowercase_bullet at _source/01_Tier_1_Foundation/T1_Personal_Dimension_Spec [ACTIVE v1.1].md:277

in a file this lane never opened (git diff HEAD -- _source/ is empty), and pillar10_vocab names

harness/check_pillar10_vocab.py, which git cat-file -e HEAD:harness/check_pillar10_vocab.py

proves does not exist at HEAD — a committed gate config pointing at an uncommitted script.

Generated by harness/site/structure_site.py — the URL path is the repo path. review root