Skip to content

Audit extension settings and item JSON updates; repair Bun merge drivers - #1348

Merged
unbraind merged 2 commits into
mainfrom
fix/audited-workspace-mutations-bun-merge
Sep 29, 2026
Merged

unbraind merged 2 commits into
mainfrom
fix/audited-workspace-mutations-bun-merge

Conversation

@unbraind

@unbraind unbraind commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Add a typed host-bound SDK operation for extension commands to preview and update project settings under the workspace history lock, with validation, author attribution, command-scoped replay identity, standard serialization, and write hooks.
  • Reject full-item JSON updates that alter persisted comments, notes, or learnings, including annotation-only edits that previously returned success without a write.
  • Install and audit a stable absolute Bun merge-driver launcher, with Node and Bun contract documentation.
  • Carry PM closeout, linked evidence, SDK and error contracts, tests, documentation, and the package-generated changelog in this PR.

PM items

Review follow-up

  • Completed replay returns without invoking the extension mutation callback. Two commands may use the same operation ID independently.
  • Settings writes use the normal serializer and notify active onWrite hooks after a changed write. Installed-extension tests cover both behaviors.
  • Malformed full-item annotation arrays already pass through a typed facet validator before snapshot filtering. Regression tests now prove the usage refusal for comments, notes, and learnings.
  • The SDK surface snapshot records the explicit replay receipt type and optional invocation context with an acknowledgement of its conservative signature classification.

Verification

  • Full V8 suite: 9,414 passed, exact statements/branches/functions/lines 100/100/100/100, zero uncovered counts.
  • pnpm quality:static, pnpm typecheck, linked pm test --run --progress, changelog --check, and pnpm security:scan passed.
  • Fresh temporary package install: npx and bunx both report 2026.9.29; Bun strict health returned zero findings. Separate temporary Git merge acceptance exercised the Bun item/history drivers and verified history.
  • pm validate --check-resolution --check-history-drift found zero drift across 2,839 items. Its sole warning is the previously documented 170-item historical resolution evidence residual owned by pm-e9zh.

Expose a host-bound settings mutation primitive to extension commands. Apply
validated changes under the workspace-history lock, support dry-run and
idempotent retries, and attribute events to the invoking actor.

Reject full-item JSON updates that modify persisted comments, notes, or
learnings. Check the submitted snapshot under the item lock so annotation-only
edits cannot return a successful no-op.

Install and audit an absolute Bun merge-driver launcher alongside Node. Cover
packed Bun and copied-extension workflows, record the three issue resolutions
in pm, and regenerate the SDK contracts and changelog.
@sourcery-ai

sourcery-ai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

This PR adds an audited, replay-safe host SDK mutation for project settings, enforces annotation integrity for full-item JSON updates, repairs Bun merge-driver installation and validation, and updates the associated contracts, tests, documentation, and PM/changelog artifacts.

Sequence diagram for audited extension settings mutation

sequenceDiagram
    participant Extension as ExtensionCommand
    participant SDK as HostBoundSDK
    participant History as WorkspaceHistory
    participant Settings as settings.json

    Extension->>SDK: mutateWorkspaceSettings(operationId, mutate, dryRun)
    SDK->>History: mutateWorkspaceJsonWithHistory(operationId, author, dryRun)
    History->>History: acquireLock(workspace-history)
    History->>History: verifyHistoryChain()
    History->>SDK: locked current settings
    SDK->>SDK: validateSettings(current)
    SDK->>Extension: mutate(current)
    Extension-->>SDK: next settings
    SDK->>SDK: validateSettings(next)
    alt dryRun
        SDK-->>Extension: changed, dry_run, replayed
    else new operation
        History->>Settings: write validated settings
        History->>History: append audited history event
        History-->>SDK: mutation result
        SDK-->>Extension: changed, dry_run, replayed
    else recorded operation
        History-->>SDK: replayed result
        SDK-->>Extension: changed: false, replayed: true
    end
Loading

Flow diagram for full-item JSON annotation integrity

flowchart TD
    A[Full-item --stdin-json update] --> B[itemDocumentToMutationOptions]
    B --> C[documentAnnotationSnapshot]
    C --> D[mutateUpdateDocument]
    D --> E[assertPersistedAnnotationSnapshot]
    E -->|Existing comments, notes, or learnings changed| F[Reject with stdin_json_persisted_annotation_changed]
    E -->|Persisted annotations unchanged| G[Append new annotations and write item fields]
    F --> H[Use pm comments, notes, or learnings --edit]
Loading

File-Level Changes

Change Details Files
Add a host-bound, audited settings mutation API for extension commands.
  • Expose a typed SDK method accepting an operation ID, preview mode, and complete-tree mutator.
  • Execute mutations under the workspace-history lock with author attribution, settings validation, history consistency checks, idempotent replay handling, and rollback on append failure.
  • Inject the extension author into the host-created SDK and document the extension contract.
src/core/extensions/extension-types.ts
src/core/history/workspace-history.ts
src/sdk/extension-command-context.ts
src/sdk/runtime.ts
sdk/public-surface.json
docs/SDK_AUDITED_MUTATIONS.md
docs/README.md
tests/integration/extension-host-contracts.integration.spec.ts
tests/unit/core/history/workspace-history.spec.ts
tests/unit/sdk/sdk-extension-mutation-platform.spec.ts
Prevent full-item JSON updates from modifying persisted annotations.
  • Capture persisted comments, notes, and learnings during structured document conversion.
  • Reject changed or removed existing annotations before writing any item fields with a dedicated error contract.
  • Continue allowing new annotations through normal mutation paths and direct corrections through annotation commands; add round-trip integration coverage.
src/sdk/lifecycle/update.ts
src/sdk/structured-mutations.ts
src/sdk/generated/generated-error-code-catalog-part-2.ts
tests/integration/structured-mutation-io.integration.spec.ts
tests/fixtures/contracts/full.json
docs/SDK_AUDITED_MUTATIONS.md
Repair Bun merge-driver installation and broaden merge-driver auditing for Node and Bun runtimes.
  • Resolve a stable absolute Bun executable by scanning absolute PATH entries and matching its reported version to the active runtime.
  • Accept Bun launcher commands in portability and health validation while retaining Node behavior and runtime/path checks.
  • Document the Node/Bun launcher contract and test selection plus audit behavior.
src/sdk/merge/install.ts
docs/MERGE_SAFETY.md
tests/unit/sdk/merge/worktree-config.spec.ts
Record PM closeout metadata and generated release/documentation artifacts.
  • Update managed extension state, issue records, and workspace history for the three completed PM items.
  • Add the unreleased changelog entries and regenerate affected contract and census documentation.
.agents/pm/extensions/.managed-extensions.json
.agents/pm/history/pm-2589e6.jsonl
.agents/pm/history/pm-vks66s.jsonl
.agents/pm/history/pm-wtqltn.jsonl
.agents/pm/issues/pm-2589e6.toon
CHANGELOG.md
docs/generated/REFUSAL_CLOSURE_CENSUS.md

Assessment against linked issues

Issue Objective Addressed Explanation
#1343 Prevent full-item pm update <id> --stdin-json from silently ignoring edits to persisted notes, comments, or learnings. ✅
#1343 Ensure edited persisted annotations are either handled through an appropriate audited mutation path or rejected atomically with a nonzero, field-specific error directing the user to the corresponding annotation edit command. ✅
#1345 Expose a typed, host-bound extension SDK operation for atomically mutating validated workspace settings without requiring extensions to import or resolve the host CLI SDK. ✅
#1345 Perform workspace settings mutations under the workspace history lock, deriving the complete next value from the locked snapshot, attributing the invocation actor, recording the settings change in verified workspace history, and compensating if persistence of the file or history fails. ✅
#1345 Support dry-run and replay-safe/idempotent operations, and provide regression coverage demonstrating that a packed extension with no local CLI dependency can update settings while strict health and workspace-history verification succeed without changing state on previews or failures. ✅
#1346 Install Bun merge drivers using a stable absolute Bun executable path so drivers remain usable when invoked through bunx --bun. ✅
#1346 Make strict health auditing recognize the repaired Bun merge-driver configuration as valid, eliminating false merge_driver_configuration_drift findings. ✅
#1346 Ensure repeated merge-driver installation is idempotent and that the registered Bun driver can execute real item/history merges through the stable runtime path. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 8a5a7f70-cdf0-4c8c-a857-806f50ac02b2


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/core/history/workspace-history.ts" line_range="539-542" />
<code_context>
+          { code: "workspace_history_state_conflict" },
+        );
+      }
+      if (params.idempotencyKey !== undefined && entries.some(
+        (entry) => entry.op === `${params.op}:${params.idempotencyKey}`,
+      )) {
+        return { changed: false, result: (await params.mutate(beforeRaw)).result, replayed: true };
+      }
+    }
</code_context>
<issue_to_address>
**issue (bug_risk):** A replayed idempotent mutation invokes `params.mutate(beforeRaw)` again before returning instead of returning the recorded result without executing the mutation callback. Retried extension commands therefore rerun arbitrary callback side effects and can fail or perform expensive work even though no settings or history write occurs.

**Triggers:** When an extension retries an operation ID that already has a history entry.

**Suggested fix:** Detect the replay before invoking the callback and return a stored or otherwise replay-safe result without executing the mutation function.
</issue_to_address>

### Comment 2
<location path="src/sdk/structured-mutations.ts" line_range="848-855" />
<code_context>
   appendFacetOptions(documentOptions, item, mode === "update");
   if (linked !== undefined) appendFacetOptions(documentOptions, linked);
+  if (mode === "update") {
+    const annotations = Object.fromEntries(
+      (["comments", "notes", "learnings"] as const)
+        .filter((key) => Object.hasOwn(item, key))
+        .map((key) => [
+          key,
+          (item[key] as unknown[]).filter(
+            (entry) => isPlainObject(entry) && entry.created_at !== undefined,
+          ),
+        ]),
+    );
</code_context>
<issue_to_address>
**issue (bug_risk):** The full-item JSON conversion calls `.filter` on each supplied `comments`, `notes`, or `learnings` value without first checking that it is an array. A malformed but parseable document such as `{"notes": null}` therefore raises a raw TypeError instead of producing the command's normal usage validation error.

**Triggers:** When `--stdin-json` contains a non-array value for one of the annotation fields.

**Suggested fix:** Validate each annotation field is an array before filtering, and raise the appropriate `PmCliError` for invalid full-item JSON.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and this changes several persisted mutation paths: an extension can write settings and workspace history, full-item updates now reject annotation edits, and Bun merge-driver configuration affects local Git merges. A wrong settings or merge result can outlive a code revert, but the affected files and history are bounded and can be repaired or regenerated.

Blocking findings: src/core/history/workspace-history.ts:542, src/sdk/structured-mutations.ts:855


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/core/history/workspace-history.ts Resolved
Comment thread src/sdk/structured-mutations.ts Resolved
@codspeed

codspeed Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 11 untouched benchmarks


Comparing fix/audited-workspace-mutations-bun-merge (78bd206) with main (db52e3f)

Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[High risk] Adds audited settings mutations and fixes item JSON update logic.

The PR appears safe to merge based on the reviewed changes.

Summary

The PR adds audited host-bound extension settings mutations, rejects edits to persisted annotations in full-item JSON updates, and repairs Bun merge-driver installation.

  • The updated head scopes replay IDs by command and returns completed replays without rerunning extension callbacks.
  • Settings writes now use the standard serializer and notify active onWrite hooks after changed writes.
  • The four earlier Greptile findings are addressed in the current code; their threads are resolved.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Command[Extension command] --> SDK[Host-bound settings SDK]
  SDK --> Lock[Workspace history lock]
  Lock --> Replay{Recorded command and operation ID?}
  Replay -- Yes --> Receipt[Inert replay receipt]
  Replay -- No --> Mutate[Validate and serialize mutation]
  Mutate --> Write[Write settings and history]
  Write --> Hooks[Notify onWrite hooks]
Loading

Reviews (2) · Last reviewed commit: "Harden audited settings mutations after ..."

Comment thread src/core/history/workspace-history.ts Resolved
Comment thread src/sdk/extension-command-context.ts Resolved
Comment thread src/sdk/extension-command-context.ts Resolved
Comment thread src/sdk/extension-command-context.ts Resolved
@codecov

codecov Bot commented Sep 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

Keep replay callbacks inert, scope extension operation IDs to their command, serialize settings through the canonical writer, and notify write hooks for changed state. Record the public SDK receipt contract and regression acceptance for copied extensions and malformed annotation input.

Complete the linked PM defect gate evidence, exact coverage and static verification, and refreshed reviewed documentation.
@unbraind

Copy link
Copy Markdown
Owner Author

@greptileai Please review the updated head, including the replay, command identity, serializer, and hook fixes.
@coderabbitai full review
@sourcery-ai Please review the updated head.

@coderabbitai

coderabbitai Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
❌ Action failed

Review failed.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed Sourcery guide #1348 (comment). The replay finding was fixed and the annotation validation path was proven with regression tests; both inline threads are resolved.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed CodeRabbit automatic review notice #1348 (comment). A manual full review was requested for head 78bd206; the provider returned a failed invocation without findings. Required checks and other reviews completed.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed Greptile review #1348 (review). Its four inline findings were addressed in 78bd206, each thread has a response, and the updated summary reports no remaining issue.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed Codecov report #1348 (comment). The hosted patch check passed; local exact V8 statements, branches, functions, and lines are all 100 percent.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed CodeRabbit manual invocation response #1348 (comment). The provider reported review failure without actionable findings after the explicit full-review request. Required checks and the Greptile and Sourcery review surfaces are complete.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed Sourcery review #1348 (review). Callback replay is fixed; the malformed annotation claim is refuted by the existing typed validator and new regression assertions. Both findings have inline dispositions.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed CodSpeed report #1348 (comment). It reports 11 untouched benchmarks on the current head; no performance change is requested.

@unbraind

Copy link
Copy Markdown
Owner Author

Reviewed updated Greptile summary #1348 (comment). Its four original findings are fixed and resolved in their inline threads; the exact-head summary reports safe to merge.

@unbraind
unbraind merged commit bbfa428 into main Sep 29, 2026
41 checks passed
@unbraind
unbraind deleted the fix/audited-workspace-mutations-bun-merge branch September 30, 2026 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant