fix(office-hours): session writer was writing to legacy file#1676
Open
pryow wants to merge 2 commits into
Open
fix(office-hours): session writer was writing to legacy file#1676pryow wants to merge 2 commits into
pryow wants to merge 2 commits into
Conversation
…legacy file User-visible symptom: returning /office-hours users get the same closing pitch every visit, no matter how many times they've run the skill. The welcome_back tier (which exists specifically to skip the pitch for returning users) was unreachable. Live since 2026-04-18 / v1.0.0.0 on every fresh-$HOME user. Root cause: the v1.0.0.0 migration moved the read path to ~/.gstack/developer-profile.json but left the writer in office-hours/SKILL.md.tmpl writing to the legacy ~/.gstack/builder-profile.jsonl. Reader and writer disagreed on storage, so SESSION_COUNT never incremented and /office-hours always treated the user as a first-timer. Fix: - bin/gstack-developer-profile: new --log-session subcommand that read-modify-writes developer-profile.json's sessions[] array (atomic mktemp+mv, signals/resources/topics aggregation, gbrain-enqueue mirror of gstack-timeline-log:40). Naming matches the gstack-*-log family verb. - bin/gstack-developer-profile: do_read filters mode:"resources" entries when picking LAST_PROJECT/LAST_ASSIGNMENT/LAST_DESIGN_TITLE so the Phase 6 resources auto-append doesn't clobber real-session state. Latent bug that was masked by the broken writer; activated by the fix. - office-hours/SKILL.md.tmpl: lines 490 + 893 swap echo >> for --log-session. - test/gstack-developer-profile.test.ts: +8 tests covering --log-session contract (regression, aggregation, dedup, validation, ts handling) plus the mode-filter regression. All 8 fail on main, all 8 pass with this fix. - test/static-no-legacy-writes.test.ts: new static-grep invariant walking every skill dir to prevent future regressions onto the legacy file. Affected users: stranded builder-profile.jsonl entries are not recovered automatically by this PR. On their next /office-hours run, the first new session lands in welcome_back; past data stays in the legacy file (still readable by other tools during deprecation). Most pre-existing users have only a handful of stranded sessions. See docs/designs/FIX_1671_PROFILE_MIGRATION.md for scope decisions (RC2/RC3 follow-ups, what was intentionally left out, and why). Issue: garrytan#1671
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1677.
What users get
Returning
/office-hoursusers now hit thewelcome_backtier on their second visit instead of being pitched as first-timers every time. Live on every fresh-$HOMEuser since v1.0.0.0 (~5 weeks).Root cause
v1.0.0.0 moved the read path to
~/.gstack/developer-profile.jsonbut left the writer inoffice-hours/SKILL.md.tmplechoing to the legacy~/.gstack/builder-profile.jsonl.ensure_profilecreates a stub withsessions: []; subsequent writes went to a file the reader never re-reads. Reader and writer disagreed on storage.SESSION_COUNTstayed at 0 forever,welcome_back(which exists specifically to skip the closing pitch for returning users) was unreachable on fresh-$HOMEinstalls.Fix
bin/gstack-developer-profile --log-session '<json>'— read-modify-writesdeveloper-profile.json'ssessions[]. Atomic mktemp+mv. Silent skip on invalid JSON (matchesgstack-timeline-log:22-26). Aggregatessignals_accumulated,resources_shown,topics. Callsgstack-brain-enqueueafter write, mirroringgstack-timeline-log:40. Verb joins thegstack-*-logfamily.office-hours/SKILL.md.tmplwriter calls at lines 490 + 893 to use the new subcommand. Regenerateoffice-hours/SKILL.md.do_readbug: filtermode:"resources"entries when pickingLAST_PROJECT/LAST_ASSIGNMENT/LAST_DESIGN_TITLE/CROSS_PROJECT. Phase 6 resources auto-append runs after the real session in the same invocation; without the filter, it clobbers real-session state next visit. Masked by the broken writer; activated by this fix.Affected users
Stranded entries in
~/.gstack/builder-profile.jsonlfrom the broken-writer period (v1.0.0.0 → v1.43.4.0) are not auto-recovered. Affected users' next/office-hourssession lands fresh inwelcome_back; past data stays in the legacy file (still readable by other tools during deprecation). Most pre-existing users have only a handful of stranded sessions; the loss is mostly aesthetic.Tests
+8 behavioral tests in
test/gstack-developer-profile.test.ts: regression (read-write-read promotes to welcome_back), aggregation (signals, resources_shown, topics dedup), validation (silent skip on invalid input),tsinjection/preservation,do_readmode filter. +3 static-grep invariants intest/static-no-legacy-writes.test.ts(new) that prevent future writers from regressing onto the legacy file. All 62 pass in 5.17s.What's intentionally NOT in this fix
--log-sessionbelongs on the owner ofdeveloper-profile.json, not thegstack-*-logevent family. Joins--migrate/--deriveas a write-side subcommand on the same binary.developer-profile.json.gstack-configaccepts the same race on YAML; not introduced here.schema_version: 1.Full rationale:
docs/designs/FIX_1671_PROFILE_MIGRATION.md.Related
#1139 — Voice prompt: "apply to YC" suggestion triggers too frequently across sessions. This PR unblocks proposed fix #3 (suppress-on-prior-session detection). Without correct
SESSION_COUNT, that detection couldn't have worked even if implemented; YC-apply suppression itself is separate work.🤖 Generated with Claude Code