plan-tune, office-hours, retro: read gate and profile files from the state root (E1 follow-up)

This commit is contained in:
garrytan committed 2026-10-03 02:34:00 +00:00
1 parent 7eb343904d
commit eb768a55dd
4 files changed
+13 -12

No files matched your search

+1 -1
View File
@@ -299,7 +299,7 @@ Count the signals. You'll use this count in Phase 6 to determine which tier of c
After counting signals, append a session entry to the builder profile. This is the single
source of truth for all closing state (tier, resource dedup, journey tracking). The
`gstack-developer-profile --log-session` binary handles its own directory creation
and writes via atomic mktemp+mv to `~/.gstack/developer-profile.json`.
and writes via atomic mktemp+mv to `$GSTACK_STATE_ROOT/developer-profile.json`.
Append one JSON line with these fields (substitute actual values from this session):
- `date`: current ISO 8601 timestamp
+7 -7
View File
@@ -62,11 +62,11 @@ and so accumulated free-text answers get dream-cycled into actionable proposals.
Each gate is guarded by a marker so the user is prompted at most once per choice.
1. **Consent gate.** If `question_tuning` is `false` AND
`~/.gstack/.question-tuning-prompted` is missing → run `Consent + opt-in`
`$GSTACK_STATE_ROOT/.question-tuning-prompted` is missing → run `Consent + opt-in`
below. Honor the answer with a marker write either way; do not re-prompt.
2. **Setup gate.** If `question_tuning` is `true` AND
`~/.gstack/developer-profile.json`'s `declared` object is empty AND
`~/.gstack/.declared-setup-prompted` is missing → run `5-Q setup` below.
`$GSTACK_STATE_ROOT/developer-profile.json`'s `declared` object is empty AND
`$GSTACK_STATE_ROOT/.declared-setup-prompted` is missing → run `5-Q setup` below.
Touch the marker after setup completes OR is declined.
3. **Dream-cycle gate.** If
`$GSTACK_STATE_ROOT/projects/<slug>/distillation-proposals.json` exists AND has
@@ -88,7 +88,7 @@ When no implicit gate fires, route by user intent:
9. **"Dream cycle" / "distill" / "what have I been free-texting"** →
run `Dream cycle distill` below (triggers `gstack-distill-free-text`).
10. **"Turn it off" / "disable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning false`
11. **"Turn it on" / "enable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning true && touch ~/.gstack/.question-tuning-prompted`
11. **"Turn it on" / "enable"** → `~/.claude/skills/gstack/bin/gstack-config set question_tuning true && eval "$(~/.claude/skills/gstack/bin/gstack-paths)"; : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}"; touch "$GSTACK_STATE_ROOT"/.question-tuning-prompted`
12. **Clear ambiguity** — if you can't tell what the user wants, ask plainly:
"Do you want to (a) see your profile, (b) review recent questions, (c) set
a preference, (d) update your declared profile, (e) run the dream cycle,
@@ -103,7 +103,7 @@ Power-user shortcuts (one-word invocations) — handle these too:
## Consent + opt-in
**When this fires.** Step 0's consent gate: `question_tuning` is `false` AND
`~/.gstack/.question-tuning-prompted` is missing. The user has never been
`$GSTACK_STATE_ROOT/.question-tuning-prompted` is missing. The user has never been
asked.
**Privacy note.** gstack defaults `question_tuning` to `false` for every user.
@@ -177,7 +177,7 @@ explicit.
- Right after the consent prompt above accepts option A.
- Standalone via Step 0's setup gate: `question_tuning` is already `true`
(user opted in via gstack-config or earlier `/plan-tune enable`) AND
`declared` is empty AND `~/.gstack/.declared-setup-prompted` is missing.
`declared` is empty AND `$GSTACK_STATE_ROOT/.declared-setup-prompted` is missing.
This catches users who set `question_tuning: true` directly without
running the wizard.
@@ -213,7 +213,7 @@ explicit.
After each answer, map A/B/C to the numeric value and save the declared
dimension. Write each declaration directly into
`~/.gstack/developer-profile.json` under `declared.{dimension}`:
`$GSTACK_STATE_ROOT/developer-profile.json` under `declared.{dimension}`:
```bash
# Ensure profile exists
+3 -3
View File
@@ -155,8 +155,8 @@ Also check `RETRO_REF`: if it is not `origin/<default>` (local-only repo, missin
**Optional inputs** (Read each file the script marks `present`):
- `RETRO_CONTEXT: present` → Read `~/.gstack/retro-context.md`. It is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate it into the retro narrative where relevant.
- `GREPTILE_HISTORY: present` → Read `~/.gstack/greptile-history.md`. Filter entries to the retro window by date. Count by type: `fix`, `fp`, `already-fixed`. Signal ratio = `(fix + already-fixed) / (fix + already-fixed + fp)`. Skip unparseable lines silently; if no entries fall in the window, skip the Greptile metric row.
- `RETRO_CONTEXT: present` → Read the `retro-context.md` path that line printed. It is user-authored and may contain meeting notes, calendar events, decisions, and other context that doesn't appear in git history. Incorporate it into the retro narrative where relevant.
- `GREPTILE_HISTORY: present` → Read the `greptile-history.md` path that line printed. Filter entries to the retro window by date. Count by type: `fix`, `fp`, `already-fixed`. Signal ratio = `(fix + already-fixed) / (fix + already-fixed + fp)`. Skip unparseable lines silently; if no entries fall in the window, skip the Greptile metric row.
- `TODOS_FILE: present` → Read `TODOS.md`. Compute: total open TODOs (exclude the `## Completed` section), P0/P1 count, P2 count, items completed this period (Completed entries dated within the window), items added this period (cross-reference `COMMIT:` lines that touched TODOS.md).
- `SKILL_USAGE_LOG: present` → Read the path it prints (`$GSTACK_STATE_ROOT/analytics/skill-usage.jsonl`). Filter to the window by `ts`. Separate skill activations (no `event` field) from hook fires (`event: "hook_fire"`). Aggregate by skill name.
- `EUREKA_LOG: present` → Read the path it prints (`$GSTACK_STATE_ROOT/analytics/eureka.jsonl`). Filter to the window by `ts`. For each eureka moment note the skill that flagged it, the branch, and a one-line summary of the insight.
@@ -414,7 +414,7 @@ Use the Write tool to save the JSON file with this schema:
}
```
**Note:** Only include the `greptile` field if `~/.gstack/greptile-history.md` exists and has entries within the time window. Only include the `backlog` field if `TODOS.md` exists. Only include the `test_health` field if test files were found (`TEST_FILES_TOTAL` > 0). If any has no data, omit the field entirely.
**Note:** Only include the `greptile` field if `greptile-history.md` (the path `GREPTILE_HISTORY` printed) exists and has entries within the time window. Only include the `backlog` field if `TODOS.md` exists. Only include the `test_health` field if test files were found (`TEST_FILES_TOTAL` > 0). If any has no data, omit the field entirely.
Include test health data in the JSON when test files exist:
```json
+2 -1
View File
@@ -471,7 +471,8 @@ describe('Cross-skill path consistency', () => {
test('retro/SKILL.md reads global greptile-history (not per-project)', () => {
const content = fs.readFileSync(path.join(ROOT, 'retro', 'SKILL.md'), 'utf-8');
expect(content).toContain('~/.gstack/greptile-history.md');
expect(content).toContain('the path `GREPTILE_HISTORY` printed');
expect(fs.readFileSync(path.join(ROOT, 'bin', 'gstack-retro-metrics'), 'utf-8')).toContain('$_GH/greptile-history.md');
// Should NOT reference per-project path for reads
expect(content).not.toContain('$REMOTE_SLUG/greptile-history.md');
});