developer-profile undercounts office-hours tenure: Phase-4.5-only logging + no timeline.jsonl reconciliation (4 logged vs 14 real runs)
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
`/office-hours` greets a user who has run gstack daily since April with "this is your third session." The relationship-tier feature understates the relationship for exactly the long-tenure users it exists to reward. Found on v1.67.2.0, still present in v1.68.2.0.
## Real-user numbers (my machine)
| Source | Count |
|---|---|
| `~/.gstack/developer-profile.json` `sessions[]` | 4 (3 startup + 1 resources) |
| `office-hours` events in `~/.gstack/projects/*/timeline.jsonl` | 14 runs across 5 project slugs |
| `office-hours` lines in `~/.gstack/analytics/skill-usage.jsonl` | 20 |
| Total skill runs logged since 2026-04-30 | 269 |
`gstack-builder-profile` reports `SESSION_COUNT: 3`, `TIER: welcome_back`. The real history says this user should be `inner_circle`.
## Why
`sessions[]` has exactly one writer: the `--log-session` call in office-hours **Phase 4.5**, which runs only after the diagnostic conversation, premise agreement, and approach selection. Two structural losses follow:
1. **Early-exit sessions never count.** Any office-hours run that ends before Phase 4.5 (user interrupt, escape hatch, context death, host crash) is invisible to the tier system, even though the timeline logged its `started` event.
2. **No reconciliation with history that predates the feature.** `do_migrate()` in `bin/gstack-developer-profile` migrates the legacy `builder-profile.jsonl` (the #1677 writer/reader split), but nothing ever backfills from `timeline.jsonl`, where the complete per-run history (`started`/`completed` events per skill, per project) already exists. Sessions from before the `--log-session` era, and sessions lost to the #1677 window, are permanently uncounted.
#1677 closed its stranded-entries question with "loss is aesthetic." With 4 months of usage the loss compounds into the greeting being factually wrong by ~3x, and `welcome_back`/`regular`/`inner_circle` copy ("This is session N", accumulated-signal reflections, the session-5 journey summary) asserts the wrong history as fact.
Related: #1677 (writer/reader split, the original stranding), #2067 (resources rows double-counted, closed).
## Proposed fix (two independent parts)
**(a) Log a stub at Phase 1, upgrade it at Phase 4.5.** Office-hours appends a minimal session entry (`{date, mode: "started", project_slug}`) right after mode selection, and Phase 4.5 upgrades that entry in place with signals/design_doc/assignment. Early exits then still count toward tenure; signal aggregates stay truthful because stubs carry `signal_count: 0`.
**(b) Add `--reconcile` (or extend `--migrate`) to backfill count-only entries from `timeline.jsonl`.** For each `{"skill":"office-hours","event":"completed"}` timeline event with no matching `sessions[]` entry within the same hour, append `{date, mode, project_slug, signal_count: 0, signals: [], backfilled: true}`. Never fabricate signals; `backfilled: true` lets the reader exclude these from signal reflections while counting them for tenure. Idempotent, and it also heals the #1677 stranded window retroactively.
Happy to send a PR for either or both; (b) is self-contained in `bin/gstack-developer-profile`, (a) touches the office-hours SKILL template. Flagging first in case you would rather define tenure as "completed design-doc sessions only" on purpose; if so, the greeting copy should stop claiming "this is session N".
Contributor guide
Research direction
Start with bin/gstack-developer-profile, its do_migrate() path, and the office-hours SKILL template around Phase 1 and Phase 4.5. Trace how sessions and timeline.jsonl events are currently written and read. Done means early exits count without fabricated signals, timeline entries can be reconciled idempotently, and tenure and greeting values reflect the recovered history.
Written by the indexing model from the issue text.
Assessment
- Domain
- developer-experience, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 70/100