The migration spec only asserted SQL substrings against a mocked
QueryRunner and had no getMetadataArgsStorage() check that ShopOffer's
column options and partial unique indexes actually match the new
schema. Since ts-jest does not type-check in this package
(isolatedModules: true), this is the only automated guard against
entity/migration drift -- matches the house convention in
npc-system.migration.spec.ts and loot-bags.migration.spec.ts.
Adds a second, mutually exclusive target column (loot_bag_definition_id)
and a bypass_conditions column to shop_offers, so a later slice's quest
referral can open one offer that reputation alone would not. Keeps
shop.service.ts compiling against the now-nullable itemDefinition with
temporary non-null assertions; Task 4 replaces them with a real branch
on offer kind.
Fixes 5 residual findings from the re-review of Playable Slice 0.6.6's
whole-branch review: two twice-hit spec files still carried invented
or seeded German fixture values (reputation-display faction name,
inventory-detail-panel item description and item name), a world store
fixture still used a German location description, and a dev comment
in reputation-content.ts referenced a faction name that no longer
exists in the code. All are literal string substitutions using
already-translated canon English text; no keys, ids, or logic changed.
- TRAVELLING spelling: fix TRAVELING -> TRAVELLING in travel-panel.component.html
to match UK spelling used everywhere else (world/hunting/combat stores + API
error messages)
- Grenzwacht -> Border Watch: fix stale German faction display name in
reputation-display, reputation.service/controller, turn-in.service specs,
and the vertical-slice seed spec test title
- Suedtor von Graufurt -> Graufurt South Gate: fix stale ASCII-transliterated
German location name in hunting.service.spec.ts
- Aschenfelder(n) -> Ashen Fields: fix stale German location name/description
in top-bar.component.spec.ts and context-panel.component.spec.ts (key
identifiers left untouched)
- Fix 7 test titles still describing translated error messages as "German"
across world/hunting/inventory/combat store specs
- README: update demo location names from German to their current English
names (Graufurt South Gate, Burned Road)
- item-rarity.enum.ts: fix now-false comment claiming rarity labels are
German; the frontend RARITY_LABELS map is English
Pure literal-string/comment substitutions; no keys, ids, or logic changed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACkMEDYiwtcfchqKkiUJNX
visible-slice.e2e-spec.ts still asserted the German monster names
'Aschenratte'/'Straßenräuber' that Task 1 already translated in the
seed data. Update the assertion to the actual English seeded values
'Ash Rat'/'Road Bandit'. This file lives outside the *.spec.ts glob
(it's matched by jest-e2e.json's *.e2e-spec.ts pattern instead), so it
was missed by prior sweeps scoped to the unit-test glob.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACkMEDYiwtcfchqKkiUJNX
Task 10 review sweep found two German strings the closing sweep missed:
'Abgenutztes Kurzschwert' (8 occurrences across 5 spec files, the real
seeded worn-short-sword item) and 'Gepolsterter Helm' (1 occurrence, a
synthetic test-only bonus-hp-helm fixture). Translated both to their
English equivalents per the item-content.ts glossary and slice style.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACkMEDYiwtcfchqKkiUJNX
Repo-wide grep sweep (apps/web/src, apps/api/src) for leftover German
content strings missed by Tasks 1-9, mostly in spec fixtures/assertions
that mirror already-translated seed content (monster/item names, POI
titles and action labels, location names/descriptions) plus a few real
source-file gaps:
- inventory-detail-panel.component.ts: STAT_LABELS (Waffenschaden,
Angriff, Leben, Rüstung) were never translated by Task 6; now match
the identical English labels already used in inventory-page.component.html.
- app-shell.component.html: aria-label="Spielinhalt" -> "Game content"
(this file was outside every prior task's file list).
- location-interaction-panel.component.spec.ts: dead NPC-quote fixture
translated to match the real wounded-scout POI text.
Code comments referencing German source-spec section titles or
not-yet-seeded faction names, and inline calculation-documentation
comments, are left as-is per the source spec's scope (dev-facing
comments may stay German).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ACkMEDYiwtcfchqKkiUJNX
Translates the six REPUTATION_RANKS labels in reputation-rank.ts
(Geachtet/Vertraut/Anerkannt/Bekannt/Geduldet/Fremder -> Esteemed/
Trusted/Recognized/Known/Tolerated/Stranger), per the glossary in
docs/superpowers/specs/2026-08-21-english-game-content-foundation-design.md
section 4. Keys and thresholds are unchanged.
Also updates reputation.service.spec.ts and reputation.controller.spec.ts,
which asserted the German rankLabel value returned by
resolveReputationRank() via the service/controller layer.
Converts all German player-facing content in the API's seed files to
English per the English Game Content Foundation glossary: item
name/description, monster name, location name/description, all
local-location POI/action content, and the border-guard reputation
faction. Technical keys are unchanged.
Reconciles Slice 0.6.5 (Renown & Reputation Foundation) against master's
persistent-HP-and-regeneration slice, which landed independently and
touches several of the same files (Character entity, CombatService,
EquipmentService, the inventory detail panel).
Conflict resolutions:
- CharacterStatsService/EquipmentService constructor wiring: kept
master's CharacterVitalsService injection, which this branch's
version of the same files didn't have yet.
- CombatService.performAction: kept master's HP-guard logic
(characterTooWounded, vitals pause-on-enter) alongside this branch's
multi-line calculate() call style.
- Inventory detail panel (.html/.ts/.scss/.spec.ts): master had
redesigned the panel (wrapping section, rarity styling, flavour
text, a shared inventory.labels.ts) on top of the OLD level-gated
component, since this branch's removal of the level gate (R4, Task
8/14) hadn't reached master yet. Kept master's visual redesign in
full, but with the level-gate concept removed throughout: no
requiredLevel stat block, no meetsLevelRequirement() branch in the
equip button, no now-dead .detail__value--unmet SCSS rule. Kept both
branches' independent tests (non-equippable-item, flavour-text).
- inventory-page.component.ts: dropped master's dead characterLevel
computed (nothing in the template read it, and the level concept is
gone); kept its independent bagCells/bagUsed/bagCapacity grid
feature, which has nothing to do with renown or level.
Post-merge fixture repairs (three files failed the Angular bundle
compile because they predate master's hpRegenPerSecond/hpRegenSince
fields or master's item description field, neither conflict-marked
since git considered them non-overlapping edits):
- app.spec.ts: a 'renders loaded character values' test added on
master after this branch forked still used the abolished level/
experience fields on its decoy fixture -- retargeted to renown.
- inventory-detail-panel.component.spec.ts: the ashPelt fixture added
by this branch's final-review follow-up predates master's required
description field.
- top-bar.component.spec.ts: this branch's fixture predates master's
required hpRegenPerSecond/hpRegenSince fields.
No database migration touches the same column: master's
1792000000000-AddHpRegeneration only adds characters.hp_regen_since,
independent of this slice's 1791000000000-CreateRenownAndReputation.
Timestamp ordering between the two was already correct with no rename
needed.
Verified: API 288/288 (267 from this slice + 21 from master), API
build zero errors, web 237/237 (230 from this slice + 7 from master).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The branch review approved the slice with no blocking findings. These
are the substantive non-blocking ones.
N1, the one no per-task review could see: every seeded monster rolls
silverMin/silverMax = 0 (R7), so the victory screen showed "Silber +0"
after every fight in the shipped game. Three tasks were each correct in
isolation -- the mechanism stays, the values are zero, the field still
exists -- and the composite was wrong. Now conditional, with a test.
This does not contradict R16: R16 deleted the XP block because the
field ceased to exist, leaving nothing to hide. Silver still exists and
can be non-zero, so a conditional is the right tool.
N2: world.store.ts still said a combat "granted XP and silver". Same
false-fact-in-a-comment defect fixed in b5bcd50, one file over.
N4: resolveReputationRank threw a TypeError on negative input, since
findIndex returns -1 and REPUTATION_RANKS[-1] is undefined. Unreachable
today, but grantReputation is public and accepts any number.
N5/N6: grantReputation resolved factions without the enabled filter the
read path applies, so a disabled faction could accumulate invisible
reputation -- "disabled" was not actually a kill switch. The dense read
also had no ORDER BY, so the list could reorder between requests.
N8: design 13 requires silver stay 0 for every seeded monster; only two
of four were pinned. Re-adding silver to the others would have shipped
silently.
N9: spec 36's "a normal kill grants no Renown" had no test. It was
structurally guaranteed but unasserted -- now locked down against a
later slice wiring renown into combat.
N10: an impossible renown: 0 fixture, and RENOWN_MIN exported but never
used to clamp the floor.
API 268/268, web 230/230, API build zero errors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
When I dropped Silber and Erfahrung from the burned road's seeded
reward preview (e5752c7, because R7 zeroed every monster's silver on
that road), I updated the server content but not the web fixture that
mirrors it. burnedRoadFixture() still advertised Silber, and the
sidebar spec still asserted it rendered -- so the web tests were
proving the UI shows a category the API no longer sends.
Also clears dead level/experience fixture fields and an experience key
in a reward-service mock from combat-equipment-integration.spec.ts.
They were inert (nothing read them) but they date from after the
API-side sweep and describe fields the entity and DTO no longer have.
API 267/267, web 229/229.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The re-anchor test in equipment.service.spec.ts anchored hpRegenSince
at null, which meant currentHp already equaled the old maxHp and
nothing in equip() could change it whether settle() ran correctly, was
a no-op, or read the wrong (post-change) maxHp. Anchor currentHp at 90
with hpRegenSince 600s before the harness's fixed clock so settle()
must actually cap accumulated regen at the OLD maxHp for the assertion
to hold, catching both failure modes the original fixture missed.
- Update CharacterStatsService constructor to accept CharacterVitalsService
- Compute currentHp via CharacterVitalsService.effectiveHp() instead of raw pass-through
- Add hpRegenPerSecond and hpRegenSince fields to EffectiveCharacterStats return type
- Update spec with new test cases for regeneration calculation and field pass-through
- Equipment and combat tests now fail as expected (separate tasks will fix constructor calls)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The location view's "Mögliche Belohnungen" preview listed Silber and
Erfahrung. This slice made both false:
- Experience no longer exists as a concept (spec 1).
- Every monster seeded on this road now rolls silverMin/silverMax = 0
(design R7), so a kill yields no silver. Silver reaches the player
through turn-ins instead.
The list's own comment states the rule it was breaking: the view may not
promise a drop the roll does not guarantee (spec 8). Equipment and
material stay -- the loot tables still back both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
combat.service.spec.ts mocked CombatRewardService, so it never noticed
that design R8 removed CombatRewardDto.experience. Its mocks returned
{ experience, silver, items } and one assertion required experience: 8
back out -- encoding a contract the production DTO no longer has. A mock
lying about the real shape is worse than no test: it would keep passing
if the real DTO drifted further.
The rollback test deliberately wrote two independent fields so its
assertions could not pass vacuously ("rolled back" vs "never written").
Swapped the abolished experience for renown rather than dropping to a
single field, preserving that intent.
Monster level is untouched -- it is a monster stat this slice keeps, not
the abolished character level.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Design ruling R7 abolishes XP as a concept and says the column goes with
it, but no task in the plan actually dropped it -- the plan only dropped
characters.experience and combat_rewards.experience_granted. Task 9
removed experienceReward from the seed literals, leaving
monster_definitions.experience_reward as a NOT NULL column with no
default that nothing supplies. The first monster insert against a real
database would have failed on a constraint violation.
No suite here could have caught it: none of them connect to Postgres.
Drops the column in the slice migration (which has never been run, so
amending it in place is correct rather than stacking a second one),
removes the entity field, and clears the three test fixtures that still
set it. silver_min/silver_max deliberately stay -- spec 15 keeps a
direct currency drop available as a lore-valid exception, and XP has no
such carve-out.
Also retargets the seed idempotency test off renown: 1, which is the
seed's own default and so could not distinguish "preserved" from
"reset to default".
NOTE ON SCOPE: this commit also absorbs a Prettier reformatting pass
that was already sitting uncommitted in the working tree, which is why
it touches ~59 files. That churn is purely cosmetic line-rewrapping --
verified by inspection, and the suite is green at 267/267 with the build
at exactly the 3 expected errors owned by Tasks 10 and 11. The repo is
not Prettier-clean at baseline (119 files still flagged), so this was a
partial run by an earlier step, not a deliberate repo-wide format.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The comment sat two lines above the deleted experience computation and
still named XP as something the guard protects. Only silver survives.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TurnInService locks and validates the character row before touching
inventory, silver, or reputation, but no test exercised that branch.
Both sibling services in this slice (renown, reputation) have the
equivalent test; this closes the gap.
`characterNotFound` is shared from travel.errors and so is not a
TurnInDomainError -- assert on the wire contract (code + status) the
way reputation.service.spec.ts does for the same shared error.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>