772. Lesson identity
This lesson establishes a narrow ownership contract for faction relationships. A faction system should answer questions about relationships it owns without becoming an undisclosed authority over currency, quests, dialogue, combat, or the entire game state.
773. Learning objective
After this lesson, you can specify one faction relationship contract by naming its state, accepted inputs, mutation authority, invariant rules, threshold rules, and authorized consumers.
774. Why this matters
Faction systems become difficult to change when they silently control unrelated domains. A reputation value may begin as a relationship measure and later become an accidental source of rewards, quest availability, dialogue text, and difficulty changes. A narrow contract gives collaborators a boundary they can inspect. It also makes disagreements precise: the team can discuss whether a value is relationship state, an input into that state, a classification derived from it, or an output owned by a consumer.
Explicit mutation authority and invariants make the boundary testable. They identify who may change the relationship, how that change is applied, and which conditions must remain true after every update.
775. Prior knowledge
You should already be able to:
- Separate a design choice from the system that owns its consequence.
- Identify hidden global writes and replace them with explicit state changes.
- Describe a choice using a contract that distinguishes selection from consequence.
These capabilities come from Module 2.8 — Design choices without hidden global writes.
776. Core concept
A faction owns the relationship state between an actor and that faction. It does not automatically own every system affected by that relationship.
A useful faction relationship contract names the boundary at each step:
- State: What relationship value or category does the faction own?
- Approved input: Which explicit events or commands may request a change?
- Mutation authority: Which system applies the change, and through which named operation?
- Invariant check: Which conditions must remain true after the mutation?
- Classification: Which thresholds convert the resulting relationship state into a documented label?
- Consumers: Which named systems may read that result, and what response does each own?
The complete flow is:
approved input → mutation authority → relationship state → invariant check → threshold classification → authorized consumer response
A threshold only converts the resulting relationship state into a documented classification. Crossing a threshold does not transfer ownership of downstream consequences to the faction system.
For example, a faction may own playerRelationship = -20, the approved events that modify that value, and the classification labels hostile, wary, and trusted. The faction relationship system may be the only authority permitted to call adjustRelationship(input), while an invariant keeps the value between -100 and 100. A quest system may consume the resulting label to decide whether a quest is available. The faction system should not silently create the quest, award currency, rewrite dialogue, or alter enemy health merely because the relationship crossed a threshold.
Keep these responsibilities distinct:
| Responsibility | Faction relationship system | Another system may own it |
|---|---|---|
| Store relationship state | Yes | No, unless explicitly delegated |
| Apply approved relationship inputs | Yes | No hidden direct writes |
| Authorize the mutation operation | Yes | No direct assignment to the relationship field |
| Preserve relationship invariants | Yes | No duplicated clamping or conflicting rules |
| Classify state using documented thresholds | Yes | No duplicate interpretation without a contract |
| Decide whether a quest is available | No | Quest system |
| Grant a reward | No | Reward or economy system |
| Present relationship text | No | Dialogue or UI system |
| Change combat challenge | No | Difficulty or combat system |
A mutation-authority decision answers: “Who can change this state?” For a narrow contract, the faction relationship system changes it through an explicit operation that accepts approved inputs. An event producer may request a change, but it should not directly write the relationship value.
An invariant decision answers: “What must always be true after the change?” Examples include a bounded numeric range, exactly one current classification derived from the current value, and rejection of unknown input types. Invariants protect the relationship contract; they do not grant ownership of downstream consequences.
777. Mental model
Use the Inputs → Mutation authority → State → Invariants → Thresholds → Consumers model.
approved input request
|
v
[mutation authority]
|
v
[relationship state]
|
[invariant check]
|
v
[threshold classification]
/ | \
quest system dialogue UI reward system
decides presents grants
For each faction relationship, complete this contract:
| Field | Question | Example |
|---|---|---|
| State | What relationship value is owned? | harborLeagueStanding from -100 to 100 |
| Inputs | What may request a change? | returnedCargo, attackedCourier |
| Mutation authority | Who applies the change, and how? | Faction system via adjustRelationship(input) |
| Invariants | What must remain true? | Value stays between -100 and 100; unknown inputs are rejected |
| Thresholds | How is the resulting state classified? | below -25 hostile; -25 to 24 wary; 25+ trusted |
| Consumers | Who may read the result, and why? | quests check access; UI presents the label |
| Exclusions | What does the faction not do? | does not grant currency or edit quest state |
The authority and invariant rows are essential. Without authority, multiple systems may mutate the same relationship through hidden writes. Without invariants, a contract may name a range or classification set without defining how the system protects it. Explicit exclusions prevent the faction system from expanding into a global controller.
778. Concrete example
Suppose the game has a faction called the Harbor League. Its relationship contract could be:
- State:
harborLeagueStanding, an integer from-100to100. - Inputs: completing a delivery for the League adds
+10; stealing League cargo adds-15. - Mutation authority: the faction relationship system alone applies these changes through
adjustRelationship(input); event producers do not assign the standing directly. - Invariants: the standing remains within
-100through100; an unknown input is rejected; exactly one relationship label is derived from the current standing. - Thresholds: below
-25ishostile;-25through24iswary;25or higher istrusted. - Consumers: the quest system checks the classification before offering a League contract; the dialogue system chooses an explicitly authored relationship variant; the UI displays the current label.
- Exclusions: the faction system does not pay the delivery reward, create the quest, select dialogue lines, or modify enemy statistics.
When a delivery is completed, the event submits an approved input. The faction relationship system validates the input, applies the mutation through its named operation, and checks the invariants. It then classifies the resulting standing using the documented thresholds. Authorized consumers read the state or classification and perform only their own responsibilities.
This design supports different responses to the same relationship result. The quest system may deny a mission to a hostile player while the dialogue system presents a warning. Neither response needs to be embedded in the faction update.
779. Common mistake
A common mistake is treating a threshold crossing as permission for the faction system to execute every consequence. For example: “When standing reaches 25, unlock the quest, give 100 credits, replace the dialogue tree, and reduce guard damage.” That combines relationship classification with quest, economy, dialogue, and combat responsibilities.
Another mistake is allowing any event handler to assign the relationship field directly. That bypasses mutation authority and may skip validation, bounds, or other invariants.
A better design exposes a clear result, such as the underlying standing and its trusted classification, and lets each authorized consumer decide how that result matters within its own domain. Required consequences should be documented as consumer contracts rather than hidden inside the faction update.
780. Guided practice
Write a one-page contract for one invented faction. Do not implement it. Complete the following table:
| Field | Your decision |
|---|---|
| Faction name | |
| Relationship state and range | |
| Two valid inputs | |
| One invalid or unauthorized input | |
| Mutation authority and named operation | |
| Invariants that must hold after mutation | |
| Threshold classifications | |
| Two authorized consumers | |
| Responsibility of each consumer | |
| Three explicit exclusions |
Then test the contract with this scenario:
The player's relationship crosses from
warytotrustedafter one event.
Write six sentences:
- What approved input is accepted?
- Which authority applies the mutation?
- What underlying relationship state changes?
- Which invariant is checked or preserved?
- Which threshold classification is derived, and which consumer reads it first?
- What does that consumer decide, and which tempting consequence remains outside the faction's responsibility?
Your required design decisions are the mutation authority, the invariant list, and the exclusion list. Choose at least one consequence that would be convenient to place in the faction system and deliberately assign it elsewhere.
781. Validation and evidence
Your evidence is the completed faction relationship contract and threshold scenario. It passes when:
- The underlying relationship state has a clear owner and valid range or category set.
- Every state-changing input is explicit and named.
- One mutation authority and one named mutation operation are specified.
- The contract states at least two invariants and explains how the authority preserves them or rejects invalid input.
- Thresholds are ordered, non-overlapping, and produce documented classifications.
- Each consumer has a stated purpose rather than unrestricted access.
- At least three unrelated consequences are excluded from faction responsibility.
- The scenario can be followed from input through mutation authority, relationship state, invariant check, classification, and consumer response without an undisclosed global write.
If a reader cannot distinguish the underlying relationship value from its threshold classification, cannot identify who may mutate it, or cannot tell which system owns a consequence, revise the contract before moving on.
782. Key takeaways
- A faction owns relationship state and the rules for changing and classifying it.
- Inputs must be explicit, and mutation authority should be concentrated in a named operation.
- Invariants protect the relationship contract after every mutation.
- Thresholds derive documented classifications; they do not transfer ownership of downstream consequences.
- Consumers read faction results and own their domain-specific responses.
- Explicit exclusions prevent a faction system from becoming a hidden global controller.
783. Next lesson
Next: Keep faction consequences thin and explicit, the next lesson in Module 2.9 — Faction systems.
784. Knowledge check
Answer these items for yourself before reading the answers.
What should a faction relationship system primarily own?
Show answer and feedback
Answer: The relationship state, its approved inputs, mutation authority, invariants, and threshold classification
Why: The faction system owns the relationship state and the controlled rules for changing, validating, and classifying it. Other domains retain responsibility for their own responses.
What is the role of a consumer of faction relationship state?
Show answer and feedback
Answer: To read the relationship result and make a decision within its own domain
Why: A consumer uses the relationship result for a specific responsibility, such as checking quest access or presenting a dialogue variant. It does not gain authority to rewrite the relationship or control unrelated domains.
Why should a faction relationship contract include explicit exclusions?
Show answer and feedback
Answer: To prevent the faction system from becoming an undisclosed global controller
Why: Exclusions state what the faction system does not do. They expose responsibility boundaries and limit accidental coupling to quests, economy, dialogue, combat, or world state.
Which sequence best describes a narrow relationship contract?
Show answer and feedback
Answer: Approved input → mutation authority → relationship state → invariant check → threshold classification → authorized consumer response
Why: The complete sequence identifies who applies the mutation, validates the resulting state against its invariants, derives a classification, and leaves each downstream response to an authorized consumer.
Which value is underlying relationship state rather than a threshold classification, economy value, or world-state output?
Show answer and feedback
Answer: Harbor League standing: -20
Why: Harbor League standing: -20 is the underlying relationship value. A label such as wary would be a classification derived from that value by documented thresholds. Prices and credits belong to economy systems, while an open checkpoint is a world-state output.