Skip to content

Fix two stale doc claims from the positional-pop move, and stop treating semver as a review concern - #786

Merged
tobyhede merged 2 commits into
mainfrom
784-positional-pop-review-corrections
Aug 17, 2026
Merged

Fix two stale doc claims from the positional-pop move, and stop treating semver as a review concern#786
tobyhede merged 2 commits into
mainfrom
784-positional-pop-review-corrections

Conversation

@tobyhede

@tobyhede tobyhede commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Follow-up to #784, whose review findings arrived after it merged.

What this does NOT do anymore

The first revision of this PR raised the positional-pop-to-fixtures changeset from patch to major, on the reasoning that removing SessionService.popRunbook is a breaking public-API change. That was wrong to spend a PR on. Rundown is unreleased and has no downstream consumers, so there is nothing for a bump level to protect. That commit is dropped; the changeset is untouched and still reads patch.

The last commit here exists so the same finding stops being generated.

1. releaseFromSession doc rationale (session-service.ts)

Justified its in-place shape with "composite operations — releaseRunbooks, popRunbookIfActive — can release several runbooks against one session snapshot". popRunbookIfActive releases exactly one run, so the substituted name did not support the argument the sentence exists to make. Now attributes the multi-release case to releaseRunbooks, and states the conditional pop's own reason separately: its single release folds into the transaction that decides whether the run is still the top.

2. popTopOfStackUnverified @returns (session-fixtures.ts)

Promised null "when the stack was empty or the release removed nothing". The second arm is unreachable, as the comment inside the body already argues — topId is read off defaultStack, so projectRunbookRelease always removes it.

Deleting that arm alone would have left a second inaccuracy: null is also correct when the popped run was the last stack entry (the wf3 → wf2 → wf1 unwind in session-service.test.ts hits exactly that). The replacement names both real cases.

3. Write down that versions do not matter here

CLAUDE.md already says this for persisted state — "compatibility code for consumers that do not exist" — but never for package versions, so review kept generating semver findings.

  • CLAUDE.md gains a Versioning and changesets section: the bump field does not matter, the changeset prose does, and a finding whose only consequence lands on a hypothetical consumer is out of scope.
  • .coderabbit.yaml gets the same rule in tone_instructions (global) and as a .changeset/**/*.md path instruction that splits the two halves — never comment on the bump level, do review the prose for accuracy against the diff.

Verification

Full verify chain passes apart from check:md, which fails on 44 files under the untracked .agents/ and .claude/ skill directories — pre-existing and unrelated. test exits 0: parser 630, cli 5780, core 2836. .coderabbit.yaml parses and is schema-shaped (22 path_instructions entries); it is not Prettier-managed in this repo (.prettierignore line 1).

`SessionService.popRunbook` was removed from the public surface of
`@rundown-org/core`, which the changeset's own text already called out as
"a breaking change only for a consumer calling `SessionService.popRunbook`
directly". A `patch` bump does not describe that.

The repo's precedent for this exact shape — removing public core API whose
in-repo callers were already retired — is `major`:
`.changeset/delete-completion-and-delegation-locks.md` ("the modules were
dead code with a live public export ... the public API does change, and
that is the breaking part of this major") and
`.changeset/single-store-public-api-cutover.md`.

No release impact either way: five core majors are already queued, so the
next release resolves to 2.0.0 regardless. This is accuracy of the release
record, not a fix to a reachable break.
Both are doc-only; no behaviour changes.

`releaseFromSession` justified its in-place shape with "composite
operations — releaseRunbooks, popRunbookIfActive — can release several
runbooks against one session snapshot". `popRunbookIfActive` releases
exactly one run, so the substituted name did not support the sentence's
own argument. Attribute the multi-release case to `releaseRunbooks`, and
state separately why the conditional pop wants the same primitive: its
release folds into the transaction that decides whether the run is still
the top.

`popTopOfStackUnverified`'s `@returns` promised null "when the stack was
empty or the release removed nothing". The second arm is unreachable, as
the comment inside the body already argues — `topId` is read off
`defaultStack`, so `projectRunbookRelease` always removes it. Dropping
that arm alone would leave a second inaccuracy, because null is also the
answer when the popped run was the last entry (the wf3/wf2/wf1 unwind in
session-service.test.ts covers exactly that), so name both real cases.
@coderabbitai

coderabbitai Bot commented Aug 17, 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a3f33ecb-ad5e-4211-a1e2-f6a6c4a26d4d

📥 Commits

Reviewing files that changed from the base of the PR and between 557df71 and 3336f24.

📒 Files selected for processing (3)
  • .changeset/positional-pop-to-fixtures.md
  • packages/core/src/runbook/session-service.ts
  • packages/core/src/testing/session-fixtures.ts

Included review availability: 0 reviews are currently available. Based on recent review activity, included reviews refill at 1 per hour.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (16)
  • GitHub Check: coverage-mcp
  • GitHub Check: test-isolation-cli
  • GitHub Check: scenarios
  • GitHub Check: playwright
  • GitHub Check: lint-typed
  • GitHub Check: stryker-dry
  • GitHub Check: coverage-core
  • GitHub Check: coverage-plugin
  • GitHub Check: coverage-parser
  • GitHub Check: coverage-cli
  • GitHub Check: perf
  • GitHub Check: mutation-gate (source, dedicated, core, packages/core, core, 1, 2, src/runbook/session-service.ts...
  • GitHub Check: mutation-gate (source, dedicated, core, packages/core, core, 2, 2, src/testing/session-fixtures.t...
  • GitHub Check: rd-landlock-build
  • GitHub Check: analyze
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,ts,jsx,tsx}: Use clear, descriptive variable and function names that convey intent
Add comments for complex logic and non-obvious code sections
Use async/await over callbacks and promise chains
Use const by default, let for variables that need reassignment, avoid var
Use template literals instead of string concatenation

Files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript for type safety; define explicit types instead of relying on inference

**/*.{ts,tsx}: Never migrate persisted runbook state between versions. Reject incompatible schema versions or structures and require explicit finish, stop, prune, or restart rather than silently adapting or hydrating legacy state.
Use isError(), isNodeError(), or getErrorMessage() from the approved modules; never call Error.isError() directly. Retain instanceof only for same-realm custom error classes.
All exported symbols require TSDoc: exported functions need descriptions, parameter and applicable return/throw tags; exported types need descriptions and non-obvious property comments; exported classes need class, constructor, and public-method documentation; deprecated items need migration guidance.
Prefer discriminated unions, typed guards, and narrowing so invalid states are unrepresentable; do not branch on raw action-type strings when a purpose-built type can encode the discriminant.
Actions such as STOP, COMPLETE, and BREAK must propagate unchanged; never silently map one action type to another, and do not create synthetic state identifiers such as ~channel.

Files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (CLAUDE.md)

Use Biome for JavaScript, TypeScript, JSON, and CSS formatting; never run Prettier on TypeScript. Prettier is reserved for Markdown.

Files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
packages/core/src/runbook/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Persisted context must contain data only; runtime references and dependencies must flow through invoke.input closures, with compile-time-bound dependencies captured by the builder closure and event-time dependencies read from context at invocation time.

Files:

  • packages/core/src/runbook/session-service.ts

⚙️ CodeRabbit configuration file

packages/core/src/runbook/**/*.ts: This is the XState runbook state machine compiler and runtime. Focus on:

  • Type-driven dispatch: types and events should drive logic, not raw string checks.
  • No silent mapping: STOP, COMPLETE, BREAK, DEFER, GOTO, NEXT, CONTINUE, and RETRY must preserve their distinct semantics.
  • No synthetic IDs: use XState native event system and state graph structure.
  • Guard functions must express domain conditions only.
  • Persisted state no-migration: this project is pre-release. Do not request
    migrations, compatibility shims, fallback reconstruction, or legacy identity
    derivation for RunbookState, snapshots, lifecycle, variables, delegation state,
    or schemaVersion changes. Flag explicit or implicit migration/adaptation; stale
    state should be rejected and require complete, stop, prune, or restart.

Files:

  • packages/core/src/runbook/session-service.ts
packages/core/src/runbook/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

packages/core/src/runbook/**/*.{ts,tsx}: Handle concurrent_modification as a reachable result on concurrently driven paths, and ensure mutateState build callbacks are free of external side effects because they may run once per retry attempt.
Acquire file or domain locks and scope release with await using; do not release domain locks from a bare finally. Lock release must be best-effort, idempotent, and unable to mask the protected result.
For manifest writes, lock the sequence consisting of findEquivalentManifestRow followed by append, using a lock derived from manifestPath(cwd) plus .lock.

Files:

  • packages/core/src/runbook/session-service.ts
🧠 Learnings (7)
📚 Learning: 2026-02-26T06:27:17.519Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 51
File: packages/core/src/schemas.ts:438-487
Timestamp: 2026-02-26T06:27:17.519Z
Learning: In the rundown codebase, when evolving persisted state schemas in the core package, do not perform automatic migrations. Instead, implement a roll-forward approach: detect stale or incompatible state and prompt the user to take action (e.g., restart the session with a fresh state). This guideline is documented in CLAUDE.md. During code reviews of TypeScript files under packages/core/src, ensure changes are staged as non-destructive, include clear user prompts or upgrade paths, and avoid migrations that modify existing persisted data automatically.

Applied to files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
📚 Learning: 2026-03-13T07:37:13.038Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 102
File: packages/cli/__tests__/commands/fail.test.ts:134-141
Timestamp: 2026-03-13T07:37:13.038Z
Learning: In the tobyhede/rundown repository, ensure that ErrorResponseSchema in packages/core/src/output/zod-schemas.ts uses command: z.string().optional() (renamed from action) to reflect NoActiveRunbookOutput.action → command across the codebase. Update and verify all references to this field, including related code paths such as OutputEmitter.noActiveRunbook() and json-renderer.ts. During reviews, check that tests (e.g., packages/cli/__tests__/commands/fail.test.ts) align with the new field name and that any expectations or mocks reference command rather than action.

Applied to files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
📚 Learning: 2026-04-06T04:20:01.297Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 177
File: packages/claude-code-plugin/runbooks/planning/write-plan.runbook.md:24-24
Timestamp: 2026-04-06T04:20:01.297Z
Learning: In this repository (tobyhede/rundown), `CLAUDE_PLUGIN_ROOT` is part of a published contract and is guaranteed to already include a trailing `/` (enforced since PR `#174`). Therefore, when reviewing code, do not flag path concatenations that join the variable directly to the next path segment (e.g., `{{ CLAUDE_PLUGIN_ROOT }}schemas/plan.schema.json`) as missing a separator—this resolves correctly because the trailing slash is included in the variable value.

Applied to files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
📚 Learning: 2026-05-03T01:45:03.732Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 255
File: packages/cli/__tests__/commands/status.test.ts:239-249
Timestamp: 2026-05-03T01:45:03.732Z
Learning: In tobyhede/rundown’s status output logic (notably `buildStashedStatus` in `packages/cli`/`packages/core`), when a stashed runbook has `parentLinkage.kind === 'delegation'`, the generated status must omit the `vars` key for delegation-claimed children. Specifically, `rd status` (without `--claim-id`) must not expose inherited variable contents for these delegation-claimed descendants (e.g., ensure output does not contain sensitive values). Only callers using `rd status --claim-id <claimId>` (the capability-holder) are allowed to see the `vars` field for stashed delegated children. This guards against production data leaks; preserve/test this isolation behavior (as fixed in PR `#255`, commit dfba8464).

Applied to files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
📚 Learning: 2026-05-15T01:37:58.087Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 307
File: packages/core/__tests__/runbook/state.test.ts:718-718
Timestamp: 2026-05-15T01:37:58.087Z
Learning: In this repo’s TypeScript code, do not flag unannotated local `const` declarations as missing explicit type annotations. Type inference for local `const` is intentional and consistent; the lint rules enforced here cover `typescript-eslint/explicit-function-return-type` and `typescript-eslint/explicit-module-boundary-types` (and there is no `typescript-eslint/typedef`), and Biome likewise does not require explicit types for local `const`. For example, `const foo = process.platform !== 'win32'` should be accepted without adding a manual type annotation.

Applied to files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
📚 Learning: 2026-07-25T01:57:23.567Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 650
File: packages/core/__tests__/helpers/lease-wait-clock.ts:53-73
Timestamp: 2026-07-25T01:57:23.567Z
Learning: In this repository’s TypeScript code, follow the established convention for formatted interpolated numeric values and long error messages: use `String(<number>)` when interpolating numeric values, and when building lengthy error-message strings, concatenate fragments rather than switching to a single template literal if the resulting line(s) would exceed Biome’s configured line-width limit. Do not request/encourage converting such concatenated messages into a template literal when it would violate the width constraint.

Applied to files:

  • packages/core/src/testing/session-fixtures.ts
  • packages/core/src/runbook/session-service.ts
📚 Learning: 2026-04-24T01:48:14.441Z
Learnt from: tobyhede
Repo: tobyhede/rundown PR: 227
File: packages/core/src/runbook/retry-hook.ts:43-57
Timestamp: 2026-04-24T01:48:14.441Z
Learning: In tobyhede/rundown, `asTemplateVars` should intentionally drop `boolean` and `null` template variable values at the `retry-hook` boundary (after upstream stringification). This behavior is consistent with `TemplateVarValue` / `TemplateVarValueSchema` and the upstream resolution contract, so do NOT treat this filtering as data loss or a type-contract violation in future code reviews—if `boolean`/`null` are present here, they should be excluded with a warning rather than passed through.

Applied to files:

  • packages/core/src/runbook/session-service.ts
🔇 Additional comments (3)
packages/core/src/runbook/session-service.ts (1)

1956-1960: LGTM!

packages/core/src/testing/session-fixtures.ts (1)

311-315: LGTM!

.changeset/positional-pop-to-fixtures.md (1)

2-2: LGTM!


📝 Walkthrough

Walkthrough

This PR clarifies session release and stack-pop documentation. It also changes the @rundown-org/core release classification from patch to major.

Changes

Session contract updates

Layer / File(s) Summary
Document session release and stack-pop contracts
packages/core/src/runbook/session-service.ts, packages/core/src/testing/session-fixtures.ts, .changeset/positional-pop-to-fixtures.md
The documentation clarifies transactional release behavior and the null return cases for popTopOfStackUnverified. The changeset classifies @rundown-org/core as a major release.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to 3336f

This PR only corrects release metadata and documentation without changing runtime behavior. The listed checks and full test suite pass, and no actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
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.
Persisted State No-Migration ✅ Passed The PR changes only changeset metadata and documentation; no persisted-state, schema, migration, snapshot, or stale-data handling behavior changed.
Cli Schema Coverage ✅ Passed The PR-only diff changes one changeset and two documentation blocks. It does not change CLI commands, JSON output, --schema behavior, OutputEmitter usage, schema mappings, or tests.
Sha-Pinned Workflow Actions ✅ Passed The PR diff from commit 557df71 to HEAD changes only the changeset and two core documentation files; no .github/workflows or .github/actions files changed.
Security Policy Review ✅ Passed The PR diff changes only changeset release metadata and documentation; it does not change policy, sandbox, command, path, data-source, symlink, or environment handling.
Title check ✅ Passed The title clearly identifies the two stale documentation fixes and the change to stop treating semver as a review concern.
Description check ✅ Passed The description explains the changes and verification results in detail, but it omits the template's explicit Review Notes checklist.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 784-positional-pop-review-corrections

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

@github-actions

Copy link
Copy Markdown

🧬 Mutation score (advisory)

Hybrid mutation analysis: source changes use changed-line scopes (dedicated tests by default; mutation:related opts into related tests), while test-only changes use native incremental comparison with the main baseline. This check is advisory and never blocks merge. Trend & full reports: the Stryker Dashboard. See issue #485.

ℹ️ Mutation scope plan

Source test selection: dedicated.

core — changed-scope mutants (floor 70% shown as score context)

File Score Status
src/runbook/session-service.ts ⏭️ not mutated

core — changed-scope mutants (floor 70% shown as score context)

File Score Status
src/testing/session-fixtures.ts ⏭️ not mutated

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying rundown with  Cloudflare Pages  Cloudflare Pages

Latest commit: 3336f24
Status: ✅  Deploy successful!
Preview URL: https://e6afac62.rundown-7hl.pages.dev
Branch Preview URL: https://784-positional-pop-review-co.rundown-7hl.pages.dev

View logs

@tobyhede tobyhede changed the title Correct the positional-pop changeset bump and two stale doc claims Fix two stale doc claims from the positional-pop move, and stop treating semver as a review concern Aug 17, 2026
@tobyhede
tobyhede merged commit c403c95 into main Aug 17, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant