Repository navigation
task 8 context
Xopher edited this page Oct 28, 2026
·
1 revision
Earlier tasks you consume (all on this branch, read them with chemx read <file> --outline / --symbol=<name>):
- T3
src/lib/services/projects/projectSchedule.ts:PhaseWindow,ROOF_PHASE_ID("roof"),daysBetween,extendWindows(windows, shares, clearedIds, today, newEndOn)(re-spreads uncleared phases from today by their renormalised shares; refuses a range too short). - T3
src/lib/services/projects/floorBonus.ts:floorMultiplier(window, clearedOn YYYY-MM-DD),floorBonusPool(quests {xp,gp}[], multiplier),splitFloorBonus(pool, workerIds, lastWorkerId). Use these; do not re-derive the math. - T1
src/lib/engine/quests/QuestSchedule.ts:isProjectQuest, the quest'sproject: { projectId, floor, dueOn, wokenAt? }link. - T6
src/lib/services/projects/projectQuests.ts:ProjectTowerInput(hasprojectId,heroes?),projectStartsOn(opensOn)(local midnight ISO),windowOfPhase,projectQuestId;src/lib/services/projects/projectTower.ts:buildProjectTower(input);src/lib/services/projects/towerRecord.ts:roofFloorKey. - T7
src/lib/services/projects/projectRecord.ts(ProjectRecord,ProjectFloor,newProjectRecord) andsrc/lib/databases/ProjectDb.ts(getProjectDb,getActive,getAll,save,lastOfType). - Rewards are paid by
applyQuestRewards(see howsrc/lib/services/quests/QuestCompletionService.tscalls it at ~L166 and ~L230: plain label strings likeQuest: <name>, so "Floor bonus: " follows that pattern).
Rulings (follow them; they are decided):
- The roof's floor key is
roofFloorKey=${phaseCount + 1}F(e.g. "4F" for three phases), NOT "RF"; itsphaseIdis "roof". The brief's "settling RF" test means the roof floor key. The roof's window is the last phase's window (already stored on its ProjectFloor). - A floor's clear day (
clearedOn) = the local calendar day (dayKey, or dateKey ofcompletedAtin local time) of the LATESTcompletedAtamong the floor's paid entries, neverreviewedAt. The hero of that entry islastWorkerIdfor the remainder. - A "paid" entry is a quest-log entry for one of the floor's quest ids whose rewards were applied (
rewardsApplied === true); a pending or rejected one does not count. A floor quest id with no quest record (deleted by the GM) does not count and does not block the clear. - The bonus pool is
(m - 1)x the XP and GP of every existing chore on the floor, each chore counted ONCE (a team chore paid to three heroes counts once), throughfloorBonusPool; the workers are the distinctuserIds of the floor's paid entries, split throughsplitFloorBonus. AP is never multiplied: grants pay{ xp, gp, ap: 0 }. A grant whose xp and gp are both 0 (a floor cleared late, x1) is not paid (no empty reward lines). - "Already settled" = the floor has
clearedAt. Settling twice (a second approval, two phones) returns null: bonus paid once, next floor woken once. Setmultiplier,clearedAtandbonusPaidAton the floor at settlement. - Empty floors (owner rule: a deleted chore no longer counts): a floor whose quests no longer exist reads cleared. When a settlement wakes the next floor and that floor is itself already cleared (no live chores), it settles in the same pass with no grants and wakes the one above, and so on; an empty roof finishes the project. Put this cascade in the pure module with a test ("wakes past an empty floor"); keep the brief's exported signatures (you may add a pure helper).
FloorSettlement.wakenames the floor that ends up woken and open (the highest one woken). -
startProject(input, rewardText): refuse whilegetActive()returns a record;input.projectIdis${typeId}-${startOn}(earlier ruling R4); build withbuildProjectTower(input)(input must carryheroes, which drive approvals: pass them through, never drop them); save the tower's temple record the way the Moving House pack saves its generated temple (find it withchemx qinsrc/lib/services/core/packs/movingPack.ts; temple idgen-project-<typeId>, a re-run replaces it), save its quests the way that pack saves quests (merge, never wipe), then savenewProjectRecord(...). -
extendProject(newEndOn, today): refusenewEndOnbeforetoday(and letextendWindowsrefuse a range too short for the uncleared phases). Shares come from the project type's phases (src/lib/services/core/packs/projects/projectTypes.ts). Rewrite every UNCLEARED floor'swindow, its quests'startsOnwithprojectStartsOn(window.opensOn)and theirproject.dueOnwith the window'sdueOn; the roof takes the last phase's new window; setendOn. Cleared floors keep their window, multiplier and bonus. -
abandonProject(): delete the active project's quests that have no paid entry, delete its temple record, keep paid chores (their quest records and log entries stay), setstatus: "abandoned"; no trophy (abandoned runs never count as cleared,lastOfTypealready reads onlycleared). -
markRewardGiven()setsreward.givenAton the newest cleared record whose reward was earned and not given;markSeen(heroId, what)adds the hero once toreward.seenBy("reward") orcreditsSeenBy("credits") of the newest cleared record. Both are no-ops when there is none. - In
QuestCompletionService, the hook runs only forisProjectQuest(quest), after rewards are applied, incompleteQuest's paid branch and inapproveCompletionwhenshouldPay; any failure is caught and logged withdebug.warnand never blocks the payment. Keep the hook a one-line call intoprojectService(screens and services stay thin; the rules live inprojectProgress.ts). - Out of scope here (T10 owns the tower in play): the arrival wake from TempleGrounds and the Boss Key drop when the key-guard chore was deleted. Do not touch temple screens or room interactions.
Known parked notes in this area (ledger, for your awareness only): isQuestActiveOn ignores date for a woken project quest (T1, deferred); a malformed project.dueOn parses as today, so always write a valid YYYY-MM-DD dueOn.
13. One small extra (the board gate on T7 flags it): in src/lib/services/projects/projectRecord.ts:75, name the inline compound condition before the if (e.g. const hasDates = Boolean(first && last);), as the audit's CONTROL_FLOW_INLINE_BOOLEAN rule asks. Run tests/unit/projectRecord.spec.ts after it. Name your own compound booleans the same way in the new files.
- 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