Repository navigation
Conversation
…t generation A regeneration started from the reply before the regenerated one and excluded that reply, but a Tracker Panel edit lives only on the edited reply's own row. Regenerating or swiping the corrected reply therefore brought back the wrong value the user had just fixed. - Record every tracker value a manual edit changes (scene text by value, lists and playerStats keys by fingerprint) in the existing manualOverrides column. - getForGeneration lays the edits still visible on any swipe of the regenerated reply over its base, so the prompt, lorebook scan, tracker agents and Peek Prompt start from them. A tracker run that changes the value retires the edit. - Values the trackers leave out keep the edit, the GM tool base keeps it, and a regenerated swipe no tracker wrote gets a row with it. - A tracker run that rewrites its own row keeps that row's edit record. Closes Pasta-Devs#7286 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-edit-base Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
🎭 Dottore Review — ConcludedTip Review posted. The specimen has left the observation table.
|
🎭 Dottore ReviewDottore Verdict: Repair RequiredWarning REPAIR REQUIRED
Note Mode: 🧭 Specimen Summary
🔎 Isolated Defects
🧹 Minor Imperfections
🤖 Copy prompt for isolated Dottore findings🧪 Observations
📝 Lab Notes
|
| .select() | ||
| .from(gameStateSnapshots) | ||
| .where(and(eq(gameStateSnapshots.chatId, chatId), eq(gameStateSnapshots.messageId, messageId))) | ||
| .orderBy(asc(gameStateSnapshots.swipeIndex)); |
There was a problem hiding this comment.
⚠️ MEDIUM: Swipe order defeats the latest manual correction
Location: packages/server/src/services/storage/game-state.storage.ts:325 (RIGHT)
A swipe index has been promoted to a clock, with predictable results. Edit swipe 2's location, return to swipe 0 and correct it again, then regenerate: the ascending scan applies swipe 2 last, replacing the newer correction with the older one. The regeneration prompt and fallback state consequently start from the stale edit.
Tip
Suggested fix: Record per-field edit order and resolve competing corrections by that order, rather than by the swipe's position.
| // is taken whole from the edited swipe. A per-row diff would carry only the edited rows. | ||
| for (const row of rows) { | ||
| for (const [key, value] of Object.entries(parseStoredManualOverrides(row.manualOverrides) ?? {})) { | ||
| if (manualEditValue(row, key) !== value) continue; |
There was a problem hiding this comment.
⚠️ MEDIUM: Retired edits revive when automatic values return
Location: packages/server/src/services/storage/game-state.storage.ts:333 (RIGHT)
The equality check confuses present value with uninterrupted manual provenance. On the same swipe, a manual value A followed by automatic writes B and A leaves A's record intact throughout; regeneration then treats the final automatic A as a live correction again. Both replacement through create and automatic _applyUpdate writes preserve the record that the B write supposedly retired.
Tip
Suggested fix: Invalidate affected edit records when an automatic write changes their persisted values, while retaining records for values actually left unchanged.
| [statKey]: storedPlayerStats(row)[statKey], | ||
| }); | ||
| } else { | ||
| Object.assign(edited, { [key]: row[key as keyof GameStateRow] }); |
There was a problem hiding this comment.
⚠️ MEDIUM: Whole-tracker overlays carry unrelated automatic changes
Location: packages/server/src/services/storage/game-state.storage.ts:342 (RIGHT)
The edit record identifies an entire collection, then generously carries every member across the regeneration boundary. With a preceding snapshot X=0/Y=0, an automatic change to X=1 and a manual correction only to Y=2 cause regeneration to start from X=1/Y=2 rather than X=0/Y=2. The same whole-value transfer affects characters, persona stats, and lists inside playerStats.
Tip
Suggested fix: Persist and replay the actual manual differences within structured trackers, leaving unrelated automatic changes on the regenerated reply's side of the boundary.
| // stay on screen and carry into the next message. | ||
| if ( | ||
| input.regenerateMessageId && | ||
| chatMode !== "game" && |
There was a problem hiding this comment.
⚠️ MEDIUM: Preserve edited tracker baselines on Game regenerations
Location: packages/server/src/routes/generate.routes.ts:13704 (RIGHT)
The fallback preserves manual edits, then exempts Game from the treatment. In a ruleset-free Game chat with manual trackers and no state-tool or map writes, regenerating the edited reply creates no snapshot for the new swipe. If an earlier reply has a committed snapshot, the HUD falls back to that row and displays its old date instead of the correction, contrary to the promised no-tracker regeneration behavior.
Tip
Suggested fix: Extend no-row materialization to Game through a mode-aware service path, retaining authoritative spatial and ruleset state rather than overwriting them.
Dottore replay shadow (fork only) of upstream PR 7288 at 5263dee, the first head CodeRabbit reviewed.
Original title: fix(trackers): use manual Tracker Panel edits as the base for the next generation