Repository navigation
task 10 report
Implementer @sonnet-pt10. Status: DONE_WITH_CONCERNS (see Concerns).
Pure rules (all with specs):
-
src/lib/services/projects/floorClock.ts:floorClockLine,bonusOfferLine(brief signatures), plusfloorClockState,floorClockView(project, floorKey, today, voice)(what the header shows),phaseNameOf(phase name, "The Roof", or the floor key). "due today" on the due day, "late" after, "cleared" for a settled floor whatever its dates say (ruling 7); the offer isfloorMultiplier(window, today).toFixed(1)with the multiplication sign, null when cleared or x1. -
src/lib/services/projects/towerView.ts(new, not in the brief):currentFloorOf,clearedFloorKeys,floorRowsOf,unseenClearedFloors,withFloorSeen,endDateProblem. Kept apart from projectProgress.ts (364 lines) so the settle rules file stays small. -
src/lib/services/projects/towerPrompts.ts(new):floorClearedPrompt,abandonPrompt(reveal-prompt options, in-world, three voices). -
projectProgress.ts:wakeOnArrival(project, floorKey, quests, now)(ruling 1, pure part; null when the project is not running, the floor is unknown or already awake). -
projectIds.ts:freshProjectId(projectId, taken)(ruling 11). -
projectRecord.ts:ProjectFloor.seenBy?: string[]. -
projectService.ts:onFloorReached(floorKey, now)(wake for the family, then the settleReady pass, in the service's turn queue),readTower()(running project + floors that read cleared),markFloorSeen(heroId, floorKey);startProjectbuilds under a fresh id and forgets the heroes' saved walks;abandonProjectforgets them too.ProjectStoresgainedprogress(TempleProgressDb) andengine(forgetTempleRun, lazily imported so the service does not load the temple engine until a project starts or ends). The privatefloorNameOfnow usesphaseNameOf(one "The Roof"). - Copy:
src/lib/services/copy/catalog/projectTower.tsregistered in the catalogue index (clock, offer, floor-cleared, abandon question, sheet lines, spot cue; simple/adventure/classic; no em dashes).
Screens (thin wiring):
-
templeGrounds/useProjectTower.ts(new composable) +TempleFloorClock.vue+TempleGrounds.ts/.vue. Inert for every temple that does not start withgen-project-(no read, no watch,isFloorClearedanswers undefined). For a tower: on eachionViewDidEnterand on each floor change it takes its turn to (1)onFloorReached(level), (2)templeSystem.refreshQuestRooms(always: the run read the board when it opened, and the next floor's chores woke after that, so without it 2F's rooms would still read asleep), (3)readTower(), (4) tell each unseen cleared floor. The header clock sits in a slim row under the toolbar (not inside the toolbar, whose title is absolutely laid out), withdata-cy="temple-floor-clock",temple-floor-clock-line,temple-floor-offerhooks for Task 12's walk. -
useRoomOutcomes.ts: new optional depisFloorCleared;getLiveContextaddsfloorClearedto the context only when it is defined (other temples' context object is byte-identical). -
HomeTown.ts/.vue:project-towerspot (default x 50, y 46: the free middle of the plaza, above the Old House at 50/72),towerSpot.ts(pure: name, cue "Now on 2F: Deep Clean", scene id),ProjectTowerSheet.vue+_ProjectTowerSheet.scss. -
ProjectTowerSheet.vue: tower name, current floor, its clock and offer, every floor with a state (cleared / open / asleep), "Enter the tower"; Game Master (canAccessGameMaster()) also "Move the end date" (native date inputmin= today,endDateProblemrefuses before today and not-a-day, thenextendProject(newEnd, today); a service refusal shows the "too soon" line) and "Abandon project" (reveal-prompt confirm, thenabandonProject). Actions sit in the bottom bar (thumb reach). It callssettleReadyFloors()when it opens. Empty state is a named slotempty(default a plain line): Task 11 puts the trophy there (and HomeTown must also show the spot for a cleared project; today it hides it with no active project, ruling 7/R5). - Voxel:
buildingShapes.tsproject-tower(plain id = 4 floors, wind) andproject-tower-<floors>-<element>ids viaprojectTowerSceneId;PROJECT_TOWER_THEMESfor the nine elements; one wall band per floor (1 to 8, band height shrinks so 8 still fit the camera: top <= 16, width +-3.5), stepped roof and pennant on top.XpBuildingModel.vueknows tower scene ids (no shop sublabel, the click is left to the caller). BGM untouched.
On the project record: ProjectFloor.seenBy (hero ids), written by markFloorSeen before the prompt shows (so a second refresh cannot show it twice). It is family data like reward.seenBy, so it travels in a backup and in Family Sync; a hero on a second device is not shown it twice. The roof is never listed (its clear is the project's finish; T11's reveal tells it, and a cleared project is no longer getActive() anyway).
A sealed mini-boss room whose questIds all point to deleted quests: resolveRoomQuest -> resolvePicks finds no live pick (questRooms.ts ~L267-279), no template, so the resolution is emptyLair (L333). syncQuestRooms (engine/core/dungeons/templeSystem/questRooms.ts) puts every non-lurking quest room (empty lairs included) into clearedRooms, so the room does not seal. roomActions (RoomInteractions.ts L242-258) builds the quest sheet with fight: false and isDropWaiting(room, ctx, false) (roomInteractions/treasure.ts L140) is true while the Boss Key drop is not taken, so the sheet offers "Take it" (takeDrop -> showDropReveal -> claimDropItems, which hands out the key). No production change. tests/unit/TowerKeyGuard.spec.ts (new, passes against unchanged code) pins: the empty lair offers only "Take it" with drop: "waiting", it counts as cleared after the board sync, and a key guard with one live chore keeps its Fight and offers no key. (I tried the case inside QuestRoomSheet.spec.ts first and moved it out: that file would have crossed the 500-line budget.)
- 3:
Floor cleared!is a reveal prompt (floorClearedPrompt, title "Floor cleared!", the phase name, the early bonus line with the multiplier when above x1, one Onward), shown once per hero per floor; remembered inProjectFloor.seenBy. - 4: no code needed, see above.
- 1: arrival wake through the project (
onFloorReached), family-wide, never the per-hero wake map;settleReadyFloors()runs on tower load (insideonFloorReached) and when the Hometown sheet opens. - 2:
floorClearedin the live context = the tower's answer for the live level: true when every chore of the floor was paid (an empty floor reads true), false until the tower is read (and when it cannot be read), true when no project is running any more (so a hero is never trapped in a finished tower), undefined for other temples. - 5:
startProjectandabandonProjectclear every hero's saved walk in the tower's temple (getProgressForTemplethenclearProgress, so no hero list is needed) and drop the engine's in-memory run; a failure is warned and never stops the project. - 11:
startProjectsuffixes~2,~3when the id is held by any record in ProjectDb, and builds the tower and the record under it.
RED (specs written first; every one failed to run because the modules/exports did not exist, ts-jest diagnostics):
-
chemx test tests/unit/floorClock.spec.ts->Test suite failed to run ... floorClock.spec.ts:6:94 import { bonusOfferLine, ... } from "@/lib/services/projects/floorClock" -
towerView.spec.ts-> failed to run (towerViewmissing;Property 'seenBy' does not exist on type 'ProjectFloor') -
towerPrompts.spec.ts,projectIds.spec.ts-> failed to run (modules/exports missing) -
projectProgress.spec.ts->Test suite failed to run(wakeOnArrivalmissing) -
projectService.spec.ts->TS2305 ... has no exported member 'onFloorReached' -
buildingVoxel.spec.ts->TS2305 ... no exported member 'projectTowerSceneId' -
TempleGroundsModules.spec.ts->TS2305 ... no exported member 'markFloorSeen' -
ProjectTowerSheet.spec.ts->Test suite failed to run(component missing) -
TowerFloorLock.spec.ts: written after the 3-lineuseRoomOutcomesedit; I proved it by disabling the edit:2 failed out of 4 ... Expected: true / Received: undefined, then restored it. -
TowerKeyGuard.spec.ts: characterization of existing behaviour, green on first run against unchanged production code (ruling 4). -
towerSpot.spec.ts: written together withtowerSpot.ts(no RED captured; it is a 20-line pure function).
GREEN: one combined run, all 14 specs below:
NODE_PATH=$PWD/node_modules/.pnpm/node_modules chemx test tests/unit/floorClock.spec.ts tests/unit/ProjectTowerSheet.spec.ts tests/unit/TempleGroundsModules.spec.ts tests/unit/projectProgress.spec.ts tests/unit/projectService.spec.ts src/components/organisms/BuildingModel/__tests__/buildingVoxel.spec.ts tests/unit/voices.spec.ts tests/unit/HexLiteralRatchet.spec.ts tests/unit/towerView.spec.ts tests/unit/towerPrompts.spec.ts tests/unit/projectIds.spec.ts tests/unit/towerSpot.spec.ts tests/unit/TowerKeyGuard.spec.ts tests/unit/TowerFloorLock.spec.ts
-> All tests passed (303 passed in 77870ms).
Also green (existing specs that load files I changed): HomeTown.spec, RoomOutcomesApply.spec, TempleBattleReturnDrop.spec, TempleSystemCleared.spec (74 passed, run before the last small edits) and a final rerun of those plus XpProjectWizardModal.spec and QuestCompletion.spec after the last edits: All tests passed (153 passed).
New: src/lib/services/projects/{floorClock,towerView,towerPrompts}.ts, src/lib/services/copy/catalog/projectTower.ts, src/app/Console/TempleGrounds/components/TempleFloorClock.vue, src/app/Console/TempleGrounds/templeGrounds/useProjectTower.ts, src/app/Console/MyPortal/HomeTown/components/{ProjectTowerSheet.vue,_ProjectTowerSheet.scss,towerSpot.ts}; specs tests/unit/{floorClock,towerView,towerPrompts,projectIds,towerSpot,ProjectTowerSheet,TowerKeyGuard,TowerFloorLock}.spec.ts.
Modified: projectProgress.ts, projectService.ts, projectIds.ts, projectRecord.ts, copy/catalog/index.ts, TempleGrounds.ts/.vue, useRoomOutcomes.ts, HomeTown.ts/.vue, buildingShapes.ts, XpBuildingModel.vue; specs projectProgress.spec.ts, projectService.spec.ts, TempleGroundsModules.spec.ts, buildingVoxel.spec.ts.
- Every new/changed source file passes
chemx checkwith no introduced hazards (named compound conditions; no inline anonymous types; the sheet's emits are the runtime array form). - No hex literals in the new .vue/.scss (kit
--xp-app-*and--gs-*tokens only); HexLiteralRatchet green. Copy has no em dashes (spec asserts it for the lines it builds; also grepped). - I could not run
chemx typecheck(rule). I read the.vuescripts for types by hand (jest does not type-check.vue): the clock prop is typed at runtime (PropType) so the SFC compiler never has to resolve an aliased import type;TempleGrounds.tspassesRef<string>/Promise<boolean>exactly asuseTempleEntryalready gets them. - The bottom nav is untouched. Controls sit in the bottom bar of the sheet.
-
TempleGrounds.tswas exactly 500 lines and is now 507 (7 lines of wiring: 2 imports, 1 component, 2 call, 1 dep, 1 spread). The audit flags files over 500 (LINE_BUDGET_FILEinchemx-ratchet.json, currently 39): if the gate counts it as a new file, the cheapest fix is moving the equipment-hand block (itemCatalogtry/catch +useHand, ~22 lines) into a small composable. I did not split it myself, as asked. -
projectService.spec.ts(703 lines),projectProgress.spec.ts(574) andbuildingShapes.ts(906) were already over 500; they grew but were already counted. The new service cases could move to their own spec if the owner wants the spec back under budget. -
buildingShapes.tscarries the tower shape (+72 lines) as the brief says; a sibling file would be tidier. - The header clock is a row under the toolbar, not inside it beside the room name: the toolbar's title is laid out absolutely (the map and key buttons on both sides), and a second element there would overlap it.
- Task 11 must also change HomeTown so the tower spot shows for a cleared project (it hides today with no active project, per R5) and fill the sheet's
emptyslot. - The
FloorArrival.settledpass pays floor bonuses withnew Date()as the log time; same assettleReadyFloors. - Not verified in a browser (no dev server run, per the rules); the sheet and clock were exercised through specs only.
Status: DONE. Base: 60cce69c. Five items, all fixed; no git writes.
Moved the three route-param helpers (isBlankParam, toStartPosition, toStartLevel, byte for byte) from the top of TempleGrounds.ts into src/app/Console/TempleGrounds/templeGrounds/routeStart.ts and import the two it uses. No behaviour change (a move). New characterization cases for both helpers in tests/unit/TempleGroundsModules.spec.ts (RED first: routeStart missing, Test suite failed to run; GREEN after the move).
-
wc -l src/app/Console/TempleGrounds/TempleGrounds.ts: 490 (was 507; 500 before Task 10). -
chemx audit src/app/Console/TempleGrounds --no-triage --unroll:Line Budgets & Monolith Decomposition PASS 0,Largest File: TempleGrounds.ts (490 lines),Line Budgets & Monolith Decomposition (0 violations). The one hazard it lists for TempleGrounds.ts is the existing HOOK_SATURATION at line 84.
-
projectService.onFloorReached(templeId, floorKey, now, stores): returns null, wakes and settles nothing, when no project runs orproject.templeId !== templeId. -
useProjectTower: passes its temple id; afterreadTower()it keeps the snapshot only whenread.project.templeId === temple, otherwise treats it as no project running: no clock, no offer, no prompt,markFloorSeennever called, andisFloorClearedanswersundefined(nofloorClearedin the live context, so the stairs behave as in any temple). - Decision to flag: the lead's text equates "another temple's project" with "no project running" and says
floorClearedundefined. My first version answeredtruewhen no project ran at all (so a hero could climb a finished tower). I made both casesundefined, so a finished tower's stairs-up stay shut. No UI route re-enters a finished tower today, and the roof (the only place a hero stands when a project finishes) has no stairs up; if the owner wants finished towers climbable, the place to say so isisFloorClearedinuseProjectTower.ts(one line). - Specs:
projectService.spec.ts"is quiet for a hero in another project's tower" (Spring Cleaning runs with its 1F paid and ready;onFloorReached("gen-project-moving-out", "2F", ...)is null, the record is untouched, 2F still asleep, 1F not settled, no bonus paid).TempleGroundsModules.spec.ts"takes the running project of another tower for no project" (floorClock null,isFloorClearedundefined on both floors, no prompt although a cleared floor is unseen,markFloorSeennot called, the service asked asgen-project-moving-out), and the "project is over" case now expectsundefined. All existing call sites moved to the new signature.
src/lib/services/copy/catalog/projectTower.ts gained projectTower.roofName, .keeper ("Tower Keeper"), .onward, .abandon.yes (simple "Give up", else "Abandon"), .abandon.no (simple "Keep going", else "Keep it"), .spot.fallbackName ("Project tower"), each with simple, adventure and classic. Used by floorClock.phaseNameOf(typeId, floor, voice = FALLBACK_VOICE) (the ROOF_NAME constant is gone; the wallet label in projectService keeps the adventure default, "Floor bonus: The Roof", as before), towerView.floorRowsOf(project, voice), towerPrompts (speaker, Onward, the two buttons), towerSpot (fallback name, and the roof in the cue in the hero's voice), the sheet (rows named in the hero's voice) and useProjectTower (the cleared-floor prompt names the phase in the hero's voice). Specs: floorClock.spec (roof name in each voice and by default), towerPrompts.spec (speaker and labels from the catalogue, simple "Give up"), towerSpot.spec (fallback name per voice, roof cue in classic), towerView.spec (roof row in classic). Voices spec green (simple lines <= 10 words, no duplicate key).
background: var(--gs-window, rgba(0, 0, 0, 0.7)) is now background: var(--gs-window). Searched the three new style sources (TempleFloorClock.vue, ProjectTowerSheet.vue, _ProjectTowerSheet.scss) for rgba( and #: none left. HexLiteralRatchet green.
The "arrival and a payment together settle the floor once" case now asserts paidBonus called exactly heroes.size times, the paid heroes equal the workers, and floor 1F has clearedAt and bonusPaidAt set (it passed vacuously before).
NODE_PATH=$PWD/node_modules/.pnpm/node_modules CHEMX_AGENT_ID=@sonnet-pt10 chemx test tests/unit/TempleGroundsModules.spec.ts tests/unit/projectService.spec.ts tests/unit/projectProgress.spec.ts tests/unit/towerSpot.spec.ts tests/unit/towerPrompts.spec.ts tests/unit/floorClock.spec.ts tests/unit/ProjectTowerSheet.spec.ts tests/unit/TowerFloorLock.spec.ts tests/unit/voices.spec.ts tests/unit/towerView.spec.ts tests/unit/HexLiteralRatchet.spec.ts
-> All tests passed (266 passed in 72883ms).
chemx check on every changed source file: 0 hazards.
New: src/app/Console/TempleGrounds/templeGrounds/routeStart.ts.
Modified: TempleGrounds.ts, templeGrounds/useProjectTower.ts, projectService.ts, floorClock.ts, towerView.ts, towerPrompts.ts, HomeTown/components/towerSpot.ts, HomeTown/components/ProjectTowerSheet.vue, TempleGrounds/components/TempleFloorClock.vue, copy/catalog/projectTower.ts; specs TempleGroundsModules, projectService, floorClock, towerView, towerPrompts, towerSpot.
- Architecture
- Component-Library
- Hooks-Reference
- Temple-System
- Battle-Field-Architecture
- current_context - For AI/Human Handoff
- User Menu
- General Settings
- Family Settings
- Sound Settings
- Notification Settings
- Reward Settings
- Party Settings
- Theme Settings
- Chore Settings