Skip to content

fix: scope ambient events + destructive approvals to the session run; init --fresh (#98, #99)#100

Merged
richard-devbot merged 4 commits into
richard-devbot:mainfrom
richardsongunde:fix/session-run-scoping-98-99
Jun 12, 2026
Merged

fix: scope ambient events + destructive approvals to the session run; init --fresh (#98, #99)#100
richard-devbot merged 4 commits into
richard-devbot:mainfrom
richardsongunde:fix/session-run-scoping-98-99

Conversation

@richardsongunde

@richardsongunde richardsongunde commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Changes

  • src/integrations/pi/rstack-sdlc.ts: new module-scoped sessionRunId set by sdlc_start. Ambient hooks, destructiveApprovalExists(), and delegate model-escalation now use sessionRun() instead of latestRun(). With no session-owned run they stay silent rather than polluting an old run. Explicit run_id parameters on user-facing tools (sdlc_status, sdlc_rollback, …) are unchanged.
  • src/integrations/init.js: prior-run count in the init report; --fresh archival (non-destructive, rename into .rstack/archive/<ts>/).
  • bin/rstack-agents.js: --fresh CLI flag.
  • tests/integrations-init.test.js: 3 new subtests (prior-run reporting, --fresh archival preserves everything, --fresh on a clean project).
  • README.md: documents adoption behavior + --fresh.

Design note

Session adoption happens only on sdlc_start. A session that resumes an old run via explicit run_id params still writes its stage events (those use explicit appendEvent calls), but ambient hook logging stays off — accurate attribution was preferred over completeness. Follow-up could add an explicit sdlc_resume-style adoption.

Validation

  • npx tsx --test tests/integrations-init.test.js — 18 pass, 0 fail (3 new)
  • npm test — same 7 pre-existing Windows-environment failures as unmodified main (ESM file:// dynamic-import in tests, operator-bridge spawn, memory path); zero new failures
  • npm run lint — clean
  • npm run validate — all 196 agents pass
  • node bin/rstack-agents.js init --help shows --fresh

Real-world repro this fixes

On a workspace with a run from 2026-06-01 (manifest stuck STARTED), a session on 2026-06-09 appended its bash tool calls and even its own sdlc_start invocation into the June 1 run's events.jsonl before the new run folder existed — polluting Run Analytics and the Business Hub timeline for both runs.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added --fresh option to init to archive prior state and start clean.
    • Introduced session-scoped run tracking to ensure operations target the current session.
  • Bug Fixes

    • Normalized line endings for consistent frontmatter parsing and cross-platform behavior.
  • Documentation

    • Added README guidance for --fresh behavior.
  • Tests

    • Added integration and frontmatter tests covering init-with-prior-state and newline normalization.

richardsongunde and others added 3 commits June 9, 2026 15:36
parseFrontmatter (CLI + tests) split on \n and matched lines with a
line-anchored regex; '.' does not match \r and '$' does not precede a
trailing \r, so on CRLF checkouts every field line failed to parse and
all 196 agents reported missing name/description. Normalize CRLF/CR
before parsing. Add .gitattributes to keep text assets LF on checkout.

Fixes: validate (196/196 pass), test 'valid frontmatter' + 'valid unique
Pi skill names' now pass.

Closes #1
…n; add init --fresh

Fixes richard-devbot#98: tool_call/tool_result/session_shutdown hooks and
destructiveApprovalExists resolved the target run via latestRun(),
which returns whatever run directory sorts last — so a new session
appended its events into a stale run from days earlier, and a
destructive-action approval granted in an old run silently authorized
destructive commands in a new session. Ambient hooks, approval checks,
and model escalation now use a session-scoped run set by sdlc_start;
with no session run they stay silent instead of polluting old runs.

Fixes richard-devbot#99: init on an existing .rstack/ now reports how many prior
runs it adopted, and a new --fresh flag archives runs, approvals,
memory, registry, and config to .rstack/archive/<timestamp>/ (nothing
deleted) before initializing clean. Documented in README.

Tests: 3 new init subtests (prior-run reporting, --fresh archival,
--fresh on clean project). npm test shows the same 7 pre-existing
Windows-environment failures as unmodified main; lint and validate
pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ec6c2431-4c2c-4450-9641-02de14a80b60

📥 Commits

Reviewing files that changed from the base of the PR and between 9e24304 and c412426.

📒 Files selected for processing (3)
  • README.md
  • src/commands/list.js
  • src/integrations/pi/rstack-sdlc.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • README.md

📝 Walkthrough

Walkthrough

The PR extends SDLC reliability through cross-platform line-ending normalization in validation, adds a --fresh flag to init for non-destructive state archiving, wires the feature through the CLI and tests, and introduces session-scoped run tracking in SDLC to prevent event routing from using stale runs.

Changes

SDLC Reliability and Init Workflow

Layer / File(s) Summary
Line-ending normalization in validation
.gitattributes, src/commands/validate.js, src/commands/list.js, src/integrations/pi/rstack-sdlc.ts, tests/validate-agents.test.js, tests/validate-markdown-frontmatter.test.js
Git attributes and validation code normalize Windows/macOS line endings (CRLF, CR) to LF before parsing frontmatter and detecting delimiters, ensuring consistent behavior across checkout environments.
Init fresh feature with archiving
bin/rstack-agents.js, src/integrations/init.js, README.md, tests/integrations-init.test.js
Adds --fresh flag to init command, extends initFramework(..., { fresh }) to archive selected .rstack state into .rstack/archive/<timestamp>/, recreate .rstack/runs/, and report prior run count when state already exists; includes CLI wiring, tests, and README docs.
Session-scoped run tracking in SDLC
src/integrations/pi/rstack-sdlc.ts
Introduces sessionRunId module variable and sessionRun(projectRoot) helper; routes SDLC events, approval checks, tool_call/tool_result logs, and delegated-agent escalation counting to the session's run instead of the latest run on disk.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

🐰 I hop through line breaks, neat and swift,
Archive corners kept as a gentle gift,
Fresh starts without a single tear,
Session runs tracked, events land near,
A rabbit's init—tidy, quick, and clear.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and accurately summarizes the main changes: it identifies the two core fixes (session run scoping for ambient events/destructive approvals, and the init --fresh feature) and references the related issues (#98, #99), which aligns with the primary objectives of the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/integrations-init.test.js (1)

176-201: ⚡ Quick win

Consider expanding test coverage to validate archival of all ARCHIVABLE_STATE entries.

The test currently verifies archival of runs, approvals.jsonl, and rstack.config.json, but ARCHIVABLE_STATE also includes memory, registry, and budget.json. While not critical for the current PR (the core archival mechanism is validated), adding assertions for these entries would strengthen confidence that the feature works comprehensively.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integrations-init.test.js` around lines 176 - 201, The test "init
--fresh archives prior state non-destructively and starts clean" currently
checks runs, approvals.jsonl, and rstack.config.json but misses other
ARCHIVABLE_STATE entries; update the test (the async function with tmpProject
root and call to initFramework(root, 'custom', { profile: 'lean-mvp', fresh:
true })) to create representative files for memory, registry, and budget.json
under root/.rstack before init, then after init assert those files no longer
exist in root and assert they exist under join(archiveRoot, stamp, ...) (use the
same archiveRoot and stamp variables already in the test) to validate archival
of each ARCHIVABLE_STATE entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 22-26: Update the README snippet to accurately list all items
moved during a fresh init by matching the implementation constant
ARCHIVABLE_STATE in src/integrations/init.js: include "runs, approvals,
registry, config, memory, budget.json" (or "memory and budget.json") in the
archival description so the docs reflect the actual archived state.

In `@src/commands/validate.js`:
- Around line 27-33: Both other frontmatter parsers must apply the same CRLF/CR
normalization as validate.js: in the parseFrontmatter function in
src/commands/list.js replace direct uses of content.indexOf and content.slice
with a normalized string (e.g., const normalized = content.replace(/\r\n?/g,
'\n')) and then use normalized.startsWith, normalized.indexOf('\n---', 3) and
normalized.slice(...) so fences with \r\n are detected; likewise in
src/integrations/pi/rstack-sdlc.ts normalize the raw input before calling
raw.indexOf("\n---", 3) (use a normalized variable and use
normalized.indexOf(...) and normalized.slice(...)) so all frontmatter searches
consistently operate on CRLF-normalized text.

---

Nitpick comments:
In `@tests/integrations-init.test.js`:
- Around line 176-201: The test "init --fresh archives prior state
non-destructively and starts clean" currently checks runs, approvals.jsonl, and
rstack.config.json but misses other ARCHIVABLE_STATE entries; update the test
(the async function with tmpProject root and call to initFramework(root,
'custom', { profile: 'lean-mvp', fresh: true })) to create representative files
for memory, registry, and budget.json under root/.rstack before init, then after
init assert those files no longer exist in root and assert they exist under
join(archiveRoot, stamp, ...) (use the same archiveRoot and stamp variables
already in the test) to validate archival of each ARCHIVABLE_STATE entry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a21547e9-53b1-43d7-a226-5a2d3b09c07a

📥 Commits

Reviewing files that changed from the base of the PR and between b339ec6 and 9e24304.

📒 Files selected for processing (9)
  • .gitattributes
  • README.md
  • bin/rstack-agents.js
  • src/commands/validate.js
  • src/integrations/init.js
  • src/integrations/pi/rstack-sdlc.ts
  • tests/integrations-init.test.js
  • tests/validate-agents.test.js
  • tests/validate-markdown-frontmatter.test.js

Comment thread README.md
Comment thread src/commands/validate.js
…ct --fresh doc

Addresses CodeRabbit review on richard-devbot#100: normalize \r\n / \r in
parseFrontmatter (src/commands/list.js, src/integrations/pi/rstack-sdlc.ts)
and stripFrontmatter so the \n--- fence search works on Windows
checkouts, and list all archived items (memory, budget) in the README
--fresh comment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@richard-devbot richard-devbot merged commit 19dc26f into richard-devbot:main Jun 12, 2026
6 checks passed
richard-devbot pushed a commit that referenced this pull request Jun 12, 2026
…test stage

Review follow-ups on #101:
- withDecisionLock now steals locks orphaned by a crashed holder (mtime
  older than 30s) instead of timing out forever, and the EEXIST retry is
  scoped to the lock acquire so errors from the locked operation are not
  swallowed or re-executed.
- resolveRunId rejects run ids containing path separators or traversal
  so --run-id cannot write state outside .rstack.
- sdlc_build_next gates on the latest stage of a bundled task via
  latestStageId() instead of the first, so decisions required before a
  mid-bundle stage actually block.
- Tests for all three; merged main (CRLF frontmatter fixes from #100).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
richard-devbot added a commit that referenced this pull request Jun 12, 2026
* feat: add decision readiness gate

Closes #70

* fix: address decision readiness review feedback

- Serialize Decision Queue writes with a per-run filesystem lock\n- Fail closed on unknown readiness stages\n- Surface readiness load failures as warnings\n- Recompute scoped dashboard decision totals\n\nAddresses CodeRabbit comments on #101

* fix: harden decision lock, validate run ids, gate bundled tasks on latest stage

Review follow-ups on #101:
- withDecisionLock now steals locks orphaned by a crashed holder (mtime
  older than 30s) instead of timing out forever, and the EEXIST retry is
  scoped to the lock acquire so errors from the locked operation are not
  swallowed or re-executed.
- resolveRunId rejects run ids containing path separators or traversal
  so --run-id cannot write state outside .rstack.
- sdlc_build_next gates on the latest stage of a bundled task via
  latestStageId() instead of the first, so decisions required before a
  mid-bundle stage actually block.
- Tests for all three; merged main (CRLF frontmatter fixes from #100).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: remove accidentally committed local operator config example

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Richardson Gunde <rgunde@evoketechnologies.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants