Skip to main content

Questline + NPC Progression (The Bonds and the Board)

Questline + NPC Progression (The Bonds and the Board)

Status: Part 1 Q1 BUILT — quest scaffold + quest log shipped; Part 2 Q2 BUILT — NPC relationship scores, the five tiers and their one-time payoffs, the NPC SIDE quest chains, and the Arc One ending su

Last updated: September 8, 2026

Dark Tower — Questline + NPC Progression (The Bonds and the Board)

Status: Part 1 Q1 BUILT — quest scaffold + quest log shipped; Part 2 Q2 BUILT — NPC relationship scores, the five tiers and their one-time payoffs, the NPC SIDE quest chains, and the Arc One ending survival branch shipped; Q3 (post-story integration) BUILT — the forward-compatible post-story quest/NPC integration shipped; the literal Ascension carry-over WIRING is deferred to the post-story-loop build PS1-PS4, which is not yet built (see Q3 build status). Originating design: DESIGN (game-design audit gd-02 — process-reports report 3, finding 11. Owner chose "full questline + NPC system buildout, the larger path"). No engine code in this task — this doc is the spec; the build epics are flagged at the end and filed to the queue. Companion to the post-story-loop.md (the activity loop); together they close gd-02.

Parent: index.md. Sibling: post-story-loop.md (the deep activity loop this dovetails with). Reuses: narrative.md (the quest stub, the NPC relationship stub, the clue system, the Arc One ending router 35877), economy.md (the [NAME]_RELATIONSHIP_IMPROVE reward + [NAME]_RELATIONSHIP_HURT punishment types, the pending-reward pipeline, the Title Shop, premium-currency audit discipline, permanent-buff caps), combat.md

Thesis (the original problem -- RESOLVED by Q1-Q3 below; kept for rationale)

This section describes the pre-2026-06-17 state that motivated this doc. Q1-Q3 (below) shipped the fix; narrative.md § Quest System now reflects the live system, not this stub. gd-02 named two intertwined gaps in Dark Tower: a stubbed quest system and stubbed NPC payoffs. At the time, narrative.md documented both precisely as:

  • Quests — DARK_TOWER_QUEST_LOOKUP routes to , which only collects auction winnings. There is no quest log, no quest data model, no quest tracking, no quest-card linking, and no quest types. The word "quests" in the handler is aspirational.
  • NPC relationships — eight named NPCs (William, Isabel, Trinity, Cuthbert, Chelsea, Nigel, Lucas, Rylee) already have BOTH a [NAME]_RELATIONSHIP_IMPROVE reward type (economy.md Standard Rewards) and a [NAME]_RELATIONSHIP_HURT punishment type (economy.md Punishment System). Nothing reads or writes a relationship score, nothing tiers it, nothing pays it off, and nothing feeds it back into the story. The reward/punishment types fire into the void.

This doc designs the system that closes both: a real quest layer that gives the player a structured "what should I do, where am I, what next" anchor, and a real NPC relationship layer where the eight named characters become people the player invests in and gets paid off by — culminating in who survives the ending. The two are one system: NPC arcs ARE quest chains, and quest completion is a primary mover of relationship score. Both are built almost entirely on systems and counters Dark Tower already has (clues, counters, the companion system, the Title Shop, the ending router, the pending-reward pipeline), so they add structure, goals, and payoff — not net-new gameplay telemetry.

How this complements the post-story loop (the hard boundary)

post-story-loop.md (The Ascendant's Path) is the deep activity loop — Ascension (NG+), Hunter's Contracts, Trial of the Week — the repeatable things a finished player DOES. This doc is the goal + relationship layer — the quests that frame those activities and the NPC bonds that give them emotional stakes. They are non-overlapping by construction:

Concern Owner What it is
The small daily ritual daily.md (E5, SHIPPED) One same-day kill/clue bounty
The deep repeatable activities post-story-loop.md Ascension / Contracts / Trial
The goal index + progress anchor THIS doc, Part 1 (Quests) The quest log: "what should I do, where am I, what next" across all cadences
The relationships + their payoff THIS doc, Part 2 (NPCs) Eight named NPCs become tiered bonds with tangible + narrative payoff (who survives)

The quest log surfaces and references the daily, contracts, and trial — it does NOT re-implement them. It is the single voice-first hub that answers "what should I do?" by listing the active goals from every cadence. The contracts/trial/daily remain their own systems; the quest log is the index over them, plus the home of the MAIN-story, SIDE (NPC + exploration), and ACHIEVEMENT quests this doc adds.


Part 1 — The Quest System (turning the stub into a real layer)

Design principle: quests OBSERVE existing state, they don't re-instrument the game

The single most important decision: a quest is an overlay on the clue/counter/flag state the game already maintains, not a new per-card data structure. Dark Tower has 612,042+ cards; adding quest-reference fields to cards (the gap narrative.md § Quest System lists) would be a massive, brittle content migration. Instead, a quest's objective is a small declarative observer that reads an EXISTING signal:

  • a clue in cluesDiscovered (e.g. CLUE_UNLOCKED_CHAPTER_THIRTEEN, an NPC arc clue),
  • a counter on (enemyKills total or per-type, cluesDiscovered size, level, god devotionLevels, towerStats, dungeon/wave/raid completion flags),
  • or an NPC relationship score (Part 2).

Progress for cumulative objectives uses the DELTA-since-snapshot pattern already proven by the daily framework (DELTA_SINCE_DAY_START) and re-used by Hunter's Contracts (DELTA_SINCE_CONTRACT_START): the quest snapshots the lifetime counter when the quest becomes ACTIVE, and progress = current − snapshot. No new per-kill or per-card event plumbing. This is the same trick three shipped systems already use; quests are the fourth consumer of it.

Quest model

DarkTowerQuest                                  (a definition — static catalog, code-resident)
├── questKey: DarkTowerQuestTypes               (new enum)
├── category: MAIN | SIDE | ACHIEVEMENT | POST_STORY
├── title: String                               (stable, hermetic-assertable, e.g. "William's Trust")
├── spokenDescription: String                   (voice-first objective text)
├── unlockPredicate: observer                    (LOCKED → AVAILABLE gate: a clue / level / prior-quest-done)
├── objectives: List<QuestObjective>
│   ├── signal: CLUE | COUNTER_TOTAL | COUNTER_TYPED | RELATIONSHIP | ACTIVITY_FLAG
│   ├── key: String                              (the clue / counter / enemy type / NPC / flag)
│   ├── target: long                             (e.g. 1 clue, 100 kills, relationship tier 3)
│   └── mode: ABSOLUTE | DELTA_SINCE_ACTIVE       (ABSOLUTE for "have you ever", DELTA for "since accepting")
├── chain: questKey | null                        (the next quest in this chain, unlocked on CLAIMED)
└── reward: DarkTowerReward                       (paid through the EXISTING pending-reward pipeline)
 (new minimal state)
├── questStates: Map<DarkTowerQuestTypes, QuestState>   (LOCKED/AVAILABLE/ACTIVE/COMPLETE/CLAIMED + snapshot)

QuestState carries the per-quest status enum and the DELTA snapshot value captured when the quest went ACTIVE. That single map is the only new persisted field the quest layer needs; everything an objective reads already lives on the cache. (The build epic MAY instead persist the quest ledger in a claude.* table, mirroring the daily's claude.daily_challenge decision — decided at build time per .claude/rules/data-catalog.md. Default: the on-cache map, smallest blast (repository root) radius.)

Quest state machine

LOCKED  ──unlockPredicate true──►  AVAILABLE  ──player accepts (or auto for MAIN)──►  ACTIVE
ACTIVE  ──all objectives met──►  COMPLETE  ──player claims──►  CLAIMED  ──chain set──►  unlock next quest
  • MAIN quests auto-accept (they track the player's actual story position — there is nothing to "accept").
  • SIDE / ACHIEVEMENT / POST_STORY quests surface as AVAILABLE and the player accepts them (accept quest), which captures the DELTA snapshot so "kill 100 cultists" counts from acceptance, not retroactively. (A build-time tuning call may let some ACHIEVEMENT quests use ABSOLUTE/"have you ever" mode so a veteran's lifetime total counts — decided per quest in the catalog.)
  • COMPLETE → CLAIMED is the reward gate. Claiming an incomplete quest is a graceful no-op that re-states progress (never a dead-end, never an error).

The four quest categories

Category What it tracks Signal source Example
MAIN Story-chapter progression — the "where am I / what next" anchor chapter milestone clues + meta_chapters "Reach the Lich's Bargain" (clue CLUE_UNLOCKED_CHAPTER_THIRTEEN)
SIDE NPC arcs (Part 2) + exploration milestones NPC relationship tier, location/activity clues, devotionLevels "William's Trust" (NPC arc); "Pilgrim" (pray at all 8 god points)
ACHIEVEMENT Lifetime mastery milestones enemyKills totals, level, towerStats, dungeon clears "Demon Hunter" (1000 DEMON kills); "Tower Conqueror" (waves round 50)
POST_STORY The Ascendant's Path goals, surfaced as quests references contracts/trial/ascension state "Take a Hunt" (→ Hunter's Contracts); "This Week's Trial" (→ Trial of the Week)

MAIN quests directly answer the "stuck on chapter 12" confusion class

The recurring "I'm stuck / the story is repeating / I can't reach chapter 14" reports (narrative.md Design Decisions) are partly a navigation problem and partly a "the player has no in-game sense of their own progress or next goal" problem. A MAIN quest line ("Chapter 13: Reach the Lich's Bargain") read off the existing chapter-unlock clues gives the player an explicit, voice-first answer to "what chapter am I on and what's next" — complementing the DARK_TOWER_WHAT_CHAPTER handler with a goal, not just a status. MAIN quests never gate progress (the story auto-advances regardless); they narrate it.

The quest log (the surface)

A real quests / quest log voice surface, reached by quests, quest log, my quests, active quests, what should I do, what next. It reads the player's questStates and speaks, voice-first (philosophy/player-experience.md):

"You have three active quests. William's Trust — earn William's loyalty, you are at tier two of four. Demon Hunter — slay one thousand demons, you are at six hundred forty. This week's Trial is the Lich Lair. Say a quest name to focus it, or say daily for today's Bounty Board."

The quest log is the unified "what should I do" hub: it lists the player's MAIN next-step, accepted SIDE/ ACHIEVEMENT quests, and a one-line reference to each post-story cadence (daily / contract / trial) without re-implementing them.

NLU — repurpose the stub, don't strand the auction collect (mandatory)

DARK_TOWER_QUEST_LOOKUP today routes to , which calls . That auction-collect behavior must NOT be lost — it is a real feature players use. The build epic:

  • Routes the quests / quest log family to the NEW quest-log readout.
  • Preserves the auction collect as collect winnings / collect rewards (and keeps it reachable from the quest-log readout as a "you have winnings to collect" line when the auction service has items). The collect-winnings path stays wired; it just stops masquerading as the entire quest system.
  • Collision check (mandatory, both directions): verify no shadowing against the daily daily / bounty board surface (daily.md § NLU) and the post-story contracts / trial of the week surfaces (post-story-loop.md Pillars B/C). quest phrases must not steal those, and vice-versa — with scenario_tests in both directions, exactly as did for daily vs bounty board. Note the synonym mapper getSynonymsToCompareTo does NOT honor the enabled flag (a shadowing synonym must be DELETED, not disabled) — the lesson from the daily shadow fix.

Quest rewards (every grant rides an existing audited path)

Quest completion pays through the existing pending-reward pipeline (pendingRewards → finalizeRewardsExternal(), economy.md). No new faucet, no new currency:

Quest tier Reward Path Audit
MAIN milestone Gold (soft) + occasional gear/item roll pendingRewards standard rewards Soft-currency carve-out, money-cap aware
SIDE (NPC arc) Relationship improve + a tier payoff (Part 2) [NAME]_RELATIONSHIP_IMPROVE reward type Part 2
ACHIEVEMENT Gold + a Title Shop eligibility unlock (cosmetic) pendingRewards + Title gate predicate Title gold-tax unchanged
POST_STORY references contracts/trial rewards — paid by THOSE systems — Owned by post-story-loop.md

Premium (diamond) quest rewards, where used at all, are milestone-only and ride with a mandatory game_log.purchase_transactions audit row in the same call (the discipline economy.md + daily.md enforce). Quests never invent a currency and never grant raw combat stats.


Part 2 — NPC Relationships + Payoff Arcs (wiring the stubbed types into real bonds)

Design principle: the reward/punishment types already exist — make them MOVE a real score

The eight NPCs already have live reward AND punishment types. The whole gap is that they move nothing. The fix is literal: a numeric per-NPC relationship score that [NAME]_RELATIONSHIP_IMPROVE raises and [NAME]_RELATIONSHIP_HURT lowers, with thresholds that fire payoffs. The design intent narrative.md already records — "personal investment in specific characters rather than an abstract reputation meter" — is honored: eight individual scores, eight individual arcs, not one global reputation bar.

The eight NPCs and their roles

NPC Existing role (narrative.md) Arc theme (build-epic authors the beats)
William Primary ally; dies in the Pyrrhic Victory ending Loyalty / brotherhood — the headline survival payoff
Isabel Secondary companion Trust earned through the orc-alliance arc (existing cards 30605–30647)
Trinity Secondary character —
Cuthbert Supporting —
Chelsea Supporting —
Nigel Supporting —
Lucas Supporting —
Rylee Supporting —

(The arc beats — the spoken NPC lines and the side-quest cards — are narrative authoring delivered by the build epic + the storyline writers; this doc specifies the SYSTEM, not the prose.)

Relationship score + tiers

  • New state: npcRelationships: Map<DarkTowerNpc, Integer> on (new DarkTowerNpc enum of the eight names). Absent key = 0 (Stranger). One small map — the minimal new field.

  • The score is moved ONLY by the existing reward/punishment types (and, downstream, by completing an NPC's SIDE quest chain, which grants the improve reward):

    Mover Effect
    [NAME]_RELATIONSHIP_IMPROVE reward +N to that NPC's score (N tunable per grant; default small)
    [NAME]_RELATIONSHIP_HURT punishment −N to that NPC's score, floored at the Stranger tier (never below 0)
    Completing an NPC SIDE quest chain step grants the improve reward (the quest layer's main relationship driver)
  • Tiers (thresholds tunable in the build; named here for the voice copy + payoff gates):

    Tier Name Payoff fired on FIRST crossing
    0 Stranger —
    1 Acquaintance A spoken acknowledgement beat; the NPC's SIDE arc quest becomes AVAILABLE
    2 Ally A tangible non-combat payoff (see below)
    3 Confidant The NPC becomes a recruitable companion (reuses the 6-slot companion system)
    4 Sworn The narrative payoff: the NPC's fate in the ending improves (see "Who survives") + a unique Title
  • Each tier crossing is idempotent and one-time (mirror hasClue / ensureRaidBossClueUnlocked — exploration.md): a per-NPC "highest tier paid" cursor guards the payoff so a score that oscillates across a threshold pays the tier exactly once.

What the tier payoffs ARE (economy walls respected — NEVER raw combat stats)

The relationship payoffs obey the same wall the post-story loop does: the combat-stat lane is paragon-only (economy.md § Permanent Non-Combat Buffs). NPC payoffs are prestige, narrative, utility, and companionship — never a flat damage/HP/AC number:

  • Spoken bond beats (Acquaintance) — the NPC speaks to the player by name, acknowledging the growing relationship. Pure narrative payoff, zero economy cost.
  • Tangible non-combat boon (Ally) — one of: a one-time gold/item reward via the pending-reward pipeline, a unique clue that unlocks side content / a fast-travel node, or a QoL tick that shares the existing permanent-buff caps so it can never exceed them (economy.md § Permanent Non-Combat Buffs).
  • Companion unlock (Confidant) — the NPC becomes recruitable into one of the existing 6 companion slots (index.md Character System; progression.md). The companion's combat contribution comes entirely through the existing companion-bonus system (no new stat path) — so a beloved NPC literally fights at your side, using machinery that already exists. This is the strongest "I invested in this character and got them back" payoff and it costs no new combat math.
  • Ending survival + unique Title (Sworn) — see below + a "Sworn of {NPC}" / "{NPC}'s Champion" entry in the existing Title Shop rotation (economy.md § Title Shop), gated by the Sworn tier, bought with gold like every other title (tier = eligibility, gold = tax). Reuses the title gate + voice plumbing wholesale.

The headline payoff — "Who survives the ending" (relationship as a SECOND input to the existing router)

The Arc One ending router (card 35877) is today a pure function of clue count (narrative.md: 12+ Total, 8–11 Pyrrhic [William dies], 4–7 Tragic [multiple deaths], 0–3 Defeat). The NPC system adds a second input without rewriting the router's clue-count spine:

  • William's survival in a Pyrrhic ending. A player at the Pyrrhic clue band (8–11) whose William relationship is Sworn (tier 4) sees William survive — the ending narration branches on the relationship flag. The clue count still sets the macro ending; the relationship decides who you saved within it. This is the concrete, emotionally-loaded replay/engagement goal: "I got the Pyrrhic ending and William died — this run I'll earn his trust and save him." It reuses the existing ending router (one new branch read off a flag), not a new ending system.
  • Generalize across the named NPCs (build-epic, with the storyline writers): each "death" in the Tragic band (4–7 clues, "multiple character deaths") is gated on that NPC's relationship — a Sworn NPC survives even a Tragic ending. The macro ending stays clue-gated; the survivor list is the relationship payoff.
  • Track a per-storyline best-ending + survivors high-water mark so the player sees their own target (pairs with the post-story-loop "better ending" pull — post-story-loop.md).

NPC arcs ARE quest chains (the unification)

Each NPC's relationship is climbed through a SIDE quest chain (Part 1): e.g. William's Trust → William's Burden → William's Oath, each step unlocked by the prior (chain), each completion granting WILLIAM_RELATIONSHIP_IMPROVE and advancing the tier. So the two halves of gd-02 are one mechanism:

  • The quest log shows the player which NPC arcs are open and how far along each is.
  • Completing the arc quests is the primary, player-driven way to raise relationship (alongside the in-story reward/punishment grants that already fire from card content).
  • Reaching Sworn delivers the survival + title payoff.

A player always has a legible answer to "how do I save William?": open his quest chain in the quest log and complete it.

Post-story continuation (the NPC half of the activity loop)

After the main story, NPC arcs do not evaporate — this is the NPC contribution to the "post-story activity loop" the task asks for, complementing post-story-loop.md:

  • Relationships carry across Ascension. Ascension (NG+) preserves the character intact (post-story-loop.md Pillar A carry-over) — npcRelationships, recruited companions, and Sworn titles persist. A bond earned once is permanent across every re-run; the NPC who survived stays at your side.
  • The quest log spans the cadences. Post-story, the quest log's POST_STORY category surfaces the active Hunter's Contract and the week's Trial as quests, so the same "what should I do" hub keeps working when the authored story is exhausted.
  • High-relationship NPCs frame post-story activity (build-epic, light): a Sworn NPC can deliver the Ascendant's Path hub readout in their voice / offer a contract hand-in beat — pure narrative dressing over the existing contract/trial systems, no new mechanics.

This gives a max-progressed player both a reason to keep playing (the Ascendant's Path activities) AND someone to keep playing with/for (the persistent NPC bonds) — the retention pairing gd-02 was missing.


Reward-economy safety (summary)

Per economy.md and the daily/post-story precedent, every grant rides an existing audited path:

Grant Currency Path Audit
MAIN/ACHIEVEMENT quest gold Gold (soft) pendingRewards / Soft-currency carve-out, money-cap aware
Quest gear/item roll item pendingRewards standard reward Existing loot pipeline
NPC Ally tangible boon gold / item / capped QoL pendingRewards (shares permanent-buff caps for QoL) Never exceeds existing caps
NPC Confidant companion — (companion slot) existing 6-slot companion + companion-bonus system No new stat path
NPC Sworn title Gold (the tax) existing Title Shop gate + catalog row Title gold-tax unchanged
Any milestone diamonds Diamonds (premium) (existing/POST_STORY source) Mandatory purchase_transactions row
Ending survival branch — (narrative flag) existing 35877 ending router + one relationship-flag read No currency write

No grant invents a currency or hands out raw combat stats. The combat-stat lane stays paragon-only.

Voice-first / never-dead-end (mandatory)

Every quest-log and NPC surface obeys philosophy/player-experience.md: state what happened, where they are, and a clear next action, with no parens / brackets / slashes / abbreviations. Canonical shapes (starting copy, tune in build):

  • Quest log: "You have two active quests. William's Trust, earn his loyalty, you are at tier two of four. Demon Hunter, slay one thousand demons, you are at six hundred forty. Say a quest name to focus it, or say what next for your story goal."
  • NPC tier-up beat: "William claps you on the shoulder. You have earned his trust. He will fight at your side now. Say companions to bring him along."
  • Ending survival payoff (Pyrrhic, William Sworn): "The citadel falls, but William stands beside you, breathing. The bond you forged held when it mattered."
  • Claim-an-incomplete-quest no-op: "That quest is not finished yet. Slay one thousand demons, you are at six hundred forty. Come back when it is done."

Regression shape (hermetic — for the build epics)

Per .claude/rules/hermetic-scenario-tests.md — every test seeds its own precondition and asserts the date/RNG/order-independent surface only. Author scenario_tests via the canonical MCP tool add_scenario_test (raw INSERT prohibited); pure service/objective math goes in JUnit.

  • Quest progression → JUnit + scenario_test: seed a known counter snapshot, advance the underlying counter (e.g. enemyKills), assert the quest reads the correct "N of M" DELTA progress and transitions ACTIVE → COMPLETE. claim on an incomplete quest is a graceful no-op that re-states progress. Assert the stable quest key/title + progress shape, NEVER a rotating objective's prose. (Quest progression scenario_test.)
  • NPC payoff → JUnit + scenario_test: seed an NPC relationship score one point below the Ally (or Confidant) threshold, apply a [NAME]_RELATIONSHIP_IMPROVE grant, assert the tier crosses, the payoff fires exactly once (companion-unlock flag set / title eligibility set / survival flag set), and a second identical grant does NOT re-pay (idempotent cursor). For the survival payoff: seed a Pyrrhic clue count + William at Sworn, assert the ending branch reports William alive; seed Pyrrhic + William below Sworn, assert he dies (the existing behavior, now a control). (NPC-payoff scenario_test.)
  • Post-story loop tie-in → scenario_test: seed a completed-story character (CLUE_PATH_OF_ASCENSION_OPEN via the existing setStoryClues seeder, narrative.md / post-story-loop.md), assert the quest log's POST_STORY category surfaces the contracts/trial reference and that an NPC arc still reads its tier. Structural assertion only — never the rotating trial activity's text. (Post-story-loop scenario_test.)
  • NLU → process_tests: every new phrase (quests, quest log, my quests, what next, accept quest, collect winnings, NPC-focus phrases), PLUS explicit anti-shadow assertions that the daily daily / bounty board and the post-story contracts / trial of the week still resolve to their own surfaces (the task-22369 lesson, both directions).

What this does NOT do (scope guards)

  • Does not re-spec the daily (daily.md) or the post-story activity loop (post-story-loop.md). The quest log references them; it never re-implements selection, rewards, or rotation.
  • Does not add quest-reference fields to the 612K cards. Quests observe existing clue/counter/flag state.
  • Does not grant raw combat stats (paragon's lane). NPC payoffs are narrative, prestige, companionship, and capped QoL.
  • Does not rewrite the Arc One ending router's clue-count spine. It adds ONE relationship-flag branch read for who-survives; the clue count still sets the macro ending.
  • Does not write new authored story prose here — the NPC arc beats + side-quest cards are narrative authoring delivered by the build epics + storyline writers. This doc is the SYSTEM spec.
  • Does not add a cron/scheduler. Quest progress is computed on read from existing counters (the daily/ contract/trial deterministic model).

Build epics (flagged + filed — NO engine code in this design task)

This task is design-only; the Java build is filed to the queue as a sequenced chain (each game-engine epic carries the per-commit game_test.scenario_tests obligation .claude/rules/deploy-gating.md and a same-change update to this doc): (repository root)

# Epic Scope Depends on
Q1 Quest system scaffold + quest log — BUILT DarkTowerQuestTypes enum + quest catalog; the QuestObjective observer model (CLUE / COUNTER / RELATIONSHIP / FLAG signals, ABSOLUTE + DELTA_SINCE_ACTIVE modes reusing the daily snapshot trick); questStates state + state machine; the quests / quest log / what next NLU surface repurposing DARK_TOWER_QUEST_LOOKUP while preserving the auction collect winnings path; MAIN-quest auto-tracking of chapter milestones; the anti-shadow NLU guard vs daily/contracts/trial. Scenario_tests: quest progress DELTA read, claim no-op, MAIN chapter track, anti-shadow NLU. post-story PS1 scaffold (shares PremiumCurrencySource/hub) — coordinate, not blocking
Q2 NPC relationship + payoff arcs DarkTowerNpc enum + npcRelationships map; wire [NAME]_RELATIONSHIP_IMPROVE / [NAME]_RELATIONSHIP_HURT into score mutation (floored at Stranger); the 5 tiers + one-time idempotent tier payoffs (spoken beat, Ally boon, Confidant companion unlock via the existing 6-slot system, Sworn title + survival flag); the NPC SIDE quest chains on top of Q1; the ending-router second input (35877 who-survives branch on the relationship flag, William first). Scenario_tests: tier-cross pays once + idempotent, companion-unlock flag, Pyrrhic+Sworn→survive vs below-Sworn→die. Q1
Q3 Post-story quest/NPC integration — BUILT (forward-compatible portion; Ascension-command carry-over deferred to PS2) The quest log's POST_STORY category surfacing Hunter's Contracts + Trial of the Week as referenced quests; NPC arcs continue post-story; Ascension carry-over of npcRelationships + recruited companions + Sworn titles; Sworn-NPC framing of the Ascendant's Path hub (light narrative dressing). Scenario_tests: post-story quest-log surfaces the cadences, relationship survives an Ascension. Q1, Q2, and post-story-loop PS1–PS4

Sequence: Q1 → Q2 → Q3 (Q3 also waits on the post-story-loop build PS1–PS4). Each epic updates this doc's status table for its part in the same change.

Q1 build status

Part 1's quest scaffold + quest log shipped as game-engine Java (build green; JUnit ; hermetic scenario_tests 2206-2210). What landed and the deliberate Part-1 scoping:

  • Model (model/darktower/quest/): DarkTowerQuestTypes, DarkTowerQuestCategory, DarkTowerQuestStatus, QuestSignal (CLUE / COUNTER_TOTAL / COUNTER_TYPED / RELATIONSHIP / ACTIVITY_FLAG), QuestObjectiveMode (ABSOLUTE / DELTA_SINCE_ACTIVE), and QuestState (the one new persisted field, on ).
  • Logic (engines/handlers/darktower/quest/): QuestObjective, DarkTowerQuest, DarkTowerQuestCatalog (MAIN chapter chain 2 to 13 off the existing CLUE_UNLOCKED_CHAPTER_* clues, ACHIEVEMENT kill/clue milestones, a SIDE devotion quest plus a DELTA "Reckoning", a POST_STORY signpost), (the LOCKED to CLAIMED state machine, the observer progress math, and claim), and (the voice-first readout).
  • NLU repurpose without a risky DB repoint: the quest log is reached through the EXISTING DARK_TOWER_QUEST_LOOKUP action, branched in-code by firing action inside . "quests" / "my quests" reach the quest log; "collect" / "collect rewards" gather auction winnings AND claim finished quests, so the auction collect-winnings path stays reachable. No process_action_handlers row was repointed (avoids the row-precedes-jar INTERNAL_ERROR trap), so the surface is hermetic on the existing routing.

Deliberate Part-1 simplifications (revisited in Q2/Q3):

  • No "accept quest" command yet — SIDE/ACHIEVEMENT quests auto-accept (the AVAILABLE pause is a no-op in Part 1). The explicit accept and the AVAILABLE surface land with the quest-accept NLU bundle.
  • RELATIONSHIP signal is modeled but reads zero until Q2 wires npcRelationships; no relationship quest is in the Q1 catalog, so nothing stalls.
  • POST_STORY unlock is proxied on CLUE_UNLOCKED_CHAPTER_THIRTEEN; Q3 repoints it to the real story-complete clue when the post-story loop ships.
  • Claim rides the "collect" action rather than a dedicated "claim quest" command — keeps the surface hermetic with no new prod NLU row. MAIN milestones and achievements pay soft gold via on collect.

Follow-on prod NLU bundle (safe, additive, post-deploy — each phrase routes to an already-handled action, so there is no row-precedes-jar risk): add process_one_shot_values rows in DARK_TOWER context for quest log, active quests, what next, what should i do to DARK_TOWER_QUEST_LOOKUP, and collect winnings to COLLECT. The phrases quest / quests / my quests / collect rewards already route today.

Q2 build status

Part 2's NPC relationship + payoff system shipped as game-engine Java (build green; JUnit , ; hermetic scenario_tests 2218-2221). What landed:

  • Model (model/darktower/npc/): DarkTowerNpc (the eight named NPCs, with a fromRelationshipConstant resolver that maps a [NAME]_RELATIONSHIP_IMPROVE / _HURT enum to its NPC) and DarkTowerNpcTier (the five tiers with their tunable score thresholds — Stranger 0, Acquaintance 10, Ally 25, Confidant 50, Sworn 100). Two new persisted cache maps: npcRelationships (the live score) and npcTierPaid (the permanent, never-decreasing paid-tier cursor that backs idempotency, the Sworn survival flag, and Title eligibility).
  • Logic (utils/darktower/details/): improve / hurt move the score (floored at Stranger), reconcileTierPayoffs pays each newly-crossed tier exactly once (spoken Acquaintance beat; Ally soft-gold boon via the money path; Confidant companion unlock by granting the companion's own gating clue so it becomes recruitable in the existing 6-slot upgrade picker; Sworn beat — the Title and survival flag both derive from the paid cursor, so no extra write).
  • Wiring: handles the *_RELATIONSHIP_IMPROVE reward as an immediate effect (like the recovery rewards, never queued); applies the *_RELATIONSHIP_HURT decrement (and is now null-row hardened). No raw combat stat is ever granted — payoffs are narrative, prestige, companionship, and capped QoL.
  • Title Shop: eight TITLE_SWORN_OF_<NPC> entries added to DarkTowerTitleTypes + the catalog, each gated by isSworn on that NPC and bought with gold like every other title (tier = eligibility, gold = tax).
  • NPC SIDE arcs (DarkTowerQuestCatalog): William's three-step chain (Trust -> Burden -> Oath, Acquaintance to Sworn) and Isabel's two-step orc-alliance chain. Each step observes a kill-DELTA so it is completable through normal play, and grants the NPC improve on claim (advancing the tier and firing its payoff). DarkTowerQuest gained unlockNpc / unlockNpcTier / npcReward / npcRewardAmount; the quest RELATIONSHIP signal now reads the live tier; the quest log surfaces earned bonds and reconciles tier payoffs on read as a safety net. The remaining six NPCs onboard the same way as the storyline writers author their beats — no core change needed.
  • Ending router ( + ): on card 35877 the clue-gated option still picks the macro ending (Total/Pyrrhic/Tragic/Defeat, untouched); the new branch reads the relationship flag and emits a survivor epilogue for any Sworn NPC who would die in the Pyrrhic (William) or Tragic (William, Isabel, Trinity) band. A per-storyline best-ending high-water mark is recorded. Below Sworn, the existing authored death outcome stands.
  • Test seeder: setNpcRelationships (PlayRequest + ) seeds a score and reconciles the paid cursor exactly as a live grant would; the bond maps are wiped per scenario run in for hermeticity.

Deliberate Part-2 scoping (storyline-writer / Q3 follow-on):

  • NPC arc prose + side-quest cards are authored later by the storyline writers; the Part-2 spokenDescriptions are starter copy and the arc objectives observe the existing kill counter rather than authored arc clues. William's and Isabel's arcs are wired; the other six onboard with no core change.
  • The bonds NLU phrase is deferred as a safe additive process_one_shot_values row (like the Q1 follow-on bundle). NPC bonds are reachable today through the existing DARK_TOWER_QUEST_LOOKUP quest-log surface, so no risky prod NLU repoint ships with Q2.
  • Ascension carry-over of npcRelationships / companions / Sworn titles is Q3 (waits on the post-story loop).

Q3 build status

Part 2's post-story-continuation section shipped the forward-compatible Q3 integration that does NOT require the post-story loop's Java to exist yet (PS1-PS4 — Ascension, Hunter's Contracts, Trial of the Week — are still DESIGN, unbuilt at the time of this change). What landed as game-engine Java (build green; hermetic scenario_tests 2227-2228):

  • POST_STORY quest log surfaces both cadences. DarkTowerQuestCatalog's single POST_STORY signpost (DT_POST_STORY_ASCENDANT) now names BOTH Hunter's Contracts and the weekly Trial as descriptive forward references. It is reference-only and deliberately NOT an actionable command — the contracts / trial surfaces ship with PS3/PS4, so the readout never tells the player to say a phrase that does not route yet (no dead-end). Unlock stays proxied on CLUE_UNLOCKED_CHAPTER_THIRTEEN until PS1 grants the real CLUE_PATH_OF_ASCENSION_OPEN.
  • Sworn-NPC framing of the hub readout. now prefixes the post-story line with a one-line beat in the voice of the first Sworn NPC the player has earned (swornFraming), reading the permanent paid-tier cursor (isSworn). Pure narrative dressing over the existing reference — the "high-relationship NPCs frame post-story activity" line from post-story-loop.md — with no new mechanic or surface.
  • NPC bonds continue post-story. The eight bonds live on character-global cache maps (npcRelationships, npcTierPaid) that are not story-gated, so they persist and read in the quest log after the story is finished — verified by scenario_test 2227 (a Sworn bond still reads alongside the post-story cadences).
  • Companion carry-over guarantee (forward-defense for Ascension). A Confidant-tier companion is recruitable via a granted clue; Ascension (PS2) will CLEAR the storyline's clues on replay, which would otherwise drop a recruited companion. now RE-ASSERTS the companion's gating clue from the permanent npcTierPaid cursor on every reconcile (idempotent addClue), so a bond once earned keeps its companion across ANY clue reset. This makes the "recruited companions persist across Ascension" guarantee real and derived from cursor state the reset never touches.

Deferred to the post-story-loop build (the hard PS1-PS4 dependency)

Q3's remaining items cannot be wired until the post-story loop exists in code (this task's guidance: "coordinate so this lands after Ascension/Contracts/Trial exist"). As of this change none of PS1-PS4 is built — there is no ascend command, no ascensionLevel, no CLUE_PATH_OF_ASCENSION_OPEN, no Contracts/Trial system, no PremiumCurrencySource.ASCENSION. The carry-over GUARANTEE is in place and proven via the path Ascension reuses, but the literal Ascension wiring is PS2's:

  • PS1 repoints the POST_STORY unlock from the CLUE_UNLOCKED_CHAPTER_THIRTEEN proxy to the real story-complete clue CLUE_PATH_OF_ASCENSION_OPEN, and replaces the descriptive cadence copy with live contracts / trial references once those surfaces route.
  • PS2 (Ascension) MUST honor the carry-over contract when it clears the active storyline's clues: npcRelationships, npcTierPaid (the Sworn title eligibility + the ending-survival flag), and ownedTitles are character-global cache fields the existing story-switch carry-over (, the path PS2 reuses) already preserves untouched; the recruited-companion clue is the one fragile point, and PS2's clue-clear MUST be followed by reconcileTierPayoffs (which now re-asserts the companion clue from the cursor) so no companion is lost. The reassert added here IS that contract, enforced now as a self-healing safety net.
  • post-story-loop.md — the deep activity loop this pairs with (Ascension / Contracts / Trial); together they close gd-02.
  • narrative.md — the quest stub + NPC-relationship stub this replaces; the Arc One ending router (35877), clue system, setStoryClues seeder.
  • economy.md — the [NAME]_RELATIONSHIP_IMPROVE / _HURT types, pending-reward pipeline, Title Shop, permanent-buff caps, premium-audit discipline.
  • index.md — the 6-slot companion system, the clue/ending overview, character state.
  • progression.md — companions, level/devotion milestones (quest + tier gates).
  • combat.md — the enemyKills counter quests + achievements read.
  • exploration.md — the activeBounties system + deep activities the POST_STORY quests reference.
  • daily.md + engine/daily-framework.md — the DELTA-snapshot objective pattern + the daily / bounty board surface the quest log references and must not shadow.
  • philosophy/player-experience.md — voice-first, never-dead-end.
  • .claude/rules/hermetic-scenario-tests.md / .claude/rules/deploy-gating.md — the regression discipline for (repository root) the build epics.