Skip to content

Scope preflight override to owned commands - #36

Merged
unbraind merged 1 commit into
mainfrom
scope-preflight-override-to-owned-commands
Aug 14, 2026
Merged

Scope preflight override to owned commands#36
unbraind merged 1 commit into
mainfrom
scope-preflight-override-to-owned-commands

Conversation

@unbraind

@unbraind unbraind commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Problem

registerPreflight used the bare-function form:

api.registerPreflight((ctx) => { ... });

The SDK types this as PreflightOverride | ScopedPreflightOverrideDefinition and documents the scoped form as "a preflight handler invoked only for a declared command, or globally when unscoped." So the bare form registers a global override. Every pair of globally-scoped overrides genuinely contends, and pm health reports:

extension_preflight_override_collision:project:pm-github:project:pm-gantt-chart

With all six fleet packages installed together that is 15 pairwise warnings and ok: false. None of them actually contend — each only guards its own credentials for its own commands.

Fix

Use the scoped object form, declaring the command paths pm-github owns:

api.registerPreflight({
  commands: ["github sync", "github export", "github import", "gh-issues import", "github project import", "github project sync"],
  run: (ctx) => { ... },
});

Why full command paths, not top-level names

The runtime matches a command against the commands array by exact normalized path (entry.commands.includes(baseContext.command)), not by prefix. A bare top-level name like github never matches the real command github sync, so it would silently disable the early warning while still resolving the collision. The array therefore lists the full mutating command paths pm-github's isMutatingGithubCommand already recognizes.

The authoritative credential gate stays in the command handlers; this only narrows the override's scope so it no longer contends with other packages' overrides.

Verified before/after

  • Before (two globally-scoped packages installed): pm health reported ok: false with one extension_preflight_override_collision warning.
  • After (both scoped): pm health reported ok: true with zero collision warnings, and the guarded command still runs.

Also tested and rejected: adding contributions.commands to the manifest does not resolve the collision — only the scoped registerPreflight form does.

Checklist

  • npm run release:check exits 0
  • npm run changelog:check passes
  • npx pm health --strict-exit exits 0
  • Coverage did not decrease
  • New test asserts the override is a scoped object with the exact owned command paths

pm item

Summary by Sourcery

Scope the pm-github preflight override to its own mutating command paths to avoid collisions with other extensions.

Bug Fixes:

  • Prevent global preflight override collisions reported by pm health by restricting pm-github's override to its owned commands.

Enhancements:

  • Document the scoped preflight behavior and rationale in the extension source comments.
  • Record the fix in the changelog and pm agent history/issue tracking files.

Tests:

  • Add a smoke test that asserts the preflight override is registered as a scoped object with exactly the expected command paths.

Summary by cubic

Scopes pm-github’s registerPreflight override to its own mutating command paths to eliminate global collisions. Previously the bare-function form registered a global override that made pm health report extension_preflight_override_collision; now a scoped object lists exact command paths, preserving the early warning without contending with other packages.

  • Uses exact normalized paths: "github sync", "github export", "github import", "gh-issues import", "github project import", "github project sync". Matching is exact; a top-level "github" would not match and would disable the warning. Adding contributions.commands does not resolve collisions.
  • Behavior is otherwise unchanged: no network calls, no hard-blocking; authoritative validation remains in handlers. Health output goes from collision warnings to none.
  • Test asserts the override is scoped with the expected commands.

Written for commit ef107a5. Summary will update on new commits.

Review in cubic

registerPreflight used the bare-function form, which the pm runtime treats as a
global override. Two globally-scoped overrides genuinely contend: pm health
reports extension_preflight_override_collision for every installed pair, so all
six fleet packages installed together produce 15 warnings and ok: false.

Rewrite the registration to the scoped object form, declaring exactly the
mutating github/gh-issues command paths the override guards. The runtime matches
a command against the commands array by exact normalized path, so the array must
list the full command paths (github sync, github export, github import,
gh-issues import, github project import, github project sync) rather than a bare
top-level name: a bare 'github' never matches 'github sync' and would silently
disable the early warning. The authoritative credential gate stays in the
command handlers; this only narrows the override's scope so it no longer
contends with other packages' overrides.

Verified: with two of these packages installed, pm health reported ok: false
with one collision warning; after scoping both, ok: true with zero warnings and
the guarded command still runs.

@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.

Sorry @unbraind, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 15d35a83-980a-4d61-8aa1-b3dc21a0c363

📥 Commits

Reviewing files that changed from the base of the PR and between b6b8076 and ef107a5.

📒 Files selected for processing (5)
  • .agents/pm/history/pm-github-yhhz.jsonl
  • .agents/pm/issues/pm-github-yhhz.toon
  • CHANGELOG.md
  • index.ts
  • test/smoke.test.ts

Summary by CodeRabbit

  • Bug Fixes

    • Limited GitHub preflight checks to the relevant mutating commands.
    • Preserved credential warnings for operations that modify GitHub data.
    • Prevented unrelated commands from triggering GitHub-specific preflight behavior.
  • Tests

    • Added coverage confirming the expected command scope and preflight behavior.
  • Documentation

    • Added an Unreleased changelog entry describing the fix.

Walkthrough

The GitHub preflight registration now uses a scoped object for six pm-github mutating command paths. The smoke test verifies the scope and callable runner. The changelog and project records document the completed fix.

Changes

Scoped pm-github preflight

Layer / File(s) Summary
Scoped registration and validation
index.ts, test/smoke.test.ts, CHANGELOG.md, .agents/pm/issues/pm-github-yhhz.toon, .agents/pm/history/pm-github-yhhz.jsonl
registerPreflight now lists six owned command paths. The token warning and empty override result remain unchanged. The smoke test verifies the exact scope and callable run function. Project records and the changelog document the completed fix.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to ef107

The change narrows the preflight override to the commands it owns, preventing false collision warnings without changing the authoritative credential checks; no actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

  • unbraind/pm-github#28: Both PRs modify the index.ts preflight registration. This PR refines the command scope.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: limiting the preflight override to pm-github's owned commands.
Description check ✅ Passed The description directly explains the collision problem, scoped command paths, retained credential checks, tests, and validation results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 scope-preflight-override-to-owned-commands

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 commented Aug 14, 2026

Copy link
Copy Markdown

Reviewer's Guide

Scopes the pm-github extension’s preflight override to the exact mutating commands it owns, converting the global bare-function preflight into a scoped object form and adding tests and changelog entries to ensure and document the new behavior.

Sequence diagram for scoped pm-github preflight override

sequenceDiagram
  actor User
  participant pm_core
  participant pm_github_extension
  participant Console

  pm_github_extension->>pm_core: api.registerPreflight(commands, run)

  User->>pm_core: runCommand(github sync)
  pm_core->>pm_github_extension: run(ctx) [command in commands]
  pm_github_extension->>pm_github_extension: isMutatingGithubCommand(ctx.command, ctx.options)
  alt [isMutatingGithubCommand && no token]
    pm_github_extension->>pm_github_extension: resolveGitHubToken()
    pm_github_extension->>Console: console.error()
  end
  pm_core->>User: execute github sync handler (authoritative validation)
Loading

File-Level Changes

Change Details Files
Convert global preflight override into a scoped object tied to specific mutating GitHub commands.
  • Replaces bare-function api.registerPreflight handler with an object containing a commands array and run function.
  • Limits the preflight override to the exact normalized command paths for mutating GitHub and gh-issues commands.
  • Keeps the existing token resolution and warning behavior but confines it to owned commands to avoid cross-package collisions.
index.ts
Add tests ensuring the preflight override is scoped exactly to pm-github’s owned mutating commands.
  • Introduces a smoke test that asserts the preflight override registers as a scoped object with a non-empty commands array.
  • Verifies that the override exposes a run function and that commands matches the expected list of mutating GitHub command paths.
test/smoke.test.ts
Document the scoping fix and track the associated pm item in project metadata.
  • Adds an Unreleased changelog entry describing the preflight scoping fix and linking to the pm-github-yhhz item.
  • Adds new pm agent history and issue tracking files for the pm-github-yhhz item.
CHANGELOG.md
.agents/pm/history/pm-github-yhhz.jsonl
.agents/pm/issues/pm-github-yhhz.toon

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

@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown

Greptile Summary

The PR scopes pm-github’s preflight warning to the six mutating command paths it owns, preventing unrelated extensions’ preflight overrides from colliding.

  • Replaces the global preflight callback with a scoped { commands, run } definition.
  • Adds an activation-harness assertion for the scoped registration and exact command list.
  • Records the completed PM item and adds the corresponding changelog entry.

Confidence Score: 5/5

The PR appears safe to merge with no concrete blocking or non-blocking defects identified.

The scoped command list matches every path recognized by the existing mutation predicate, preserves the authoritative handler-level credential checks, and is pinned by the activation-harness test.

Important Files Changed

Filename Overview
index.ts Scopes the existing non-blocking credential preflight to all six command paths recognized by the mutation predicate.
test/smoke.test.ts Verifies through the activation harness that the preflight is registered as a scoped object with the exact intended paths.
CHANGELOG.md Adds an Unreleased fix entry linked to the completed PM issue.
.agents/pm/issues/pm-github-yhhz.toon Records the completed issue, affected files, and verification metadata.
.agents/pm/history/pm-github-yhhz.jsonl Adds the corresponding append-only lifecycle history for the PM issue.

Reviews (1): Last reviewed commit: "Scope preflight override to owned comman..." | Re-trigger Greptile

@unbraind
unbraind merged commit 36e66f6 into main Aug 14, 2026
7 checks passed
@unbraind
unbraind deleted the scope-preflight-override-to-owned-commands branch August 14, 2026 06:46
unbraind added a commit that referenced this pull request Aug 15, 2026
* Bind the preflight scope to pm-github's declared command set

PR #36 scoped registerPreflight to a fixed six-entry commands array, but
nothing binds that array to isMutatingGithubCommand or to the commands the
package declares: if a command is added or reclassified as mutating on one
side only, the override silently stops running for it (the runtime matches
by exact normalized path) and it executes with no early credential warning.

Extend the scoping smoke test into a drift guard: every scoped path must be
one isMutatingGithubCommand treats as mutating — the apply-gated github
export and github project sync are checked under their apply configuration
rather than skipped — and every declared-but-omitted path (github validate,
github project list, github project fields) must be read-only, proving the
omission is justified rather than an accidental gap.

Manifest-vs-scope audit: every scoped path is a declared command; the three
omitted commands are read-only diagnostics that were never gated under the
old global registration either. No gate lost; the legacy gh-issues import
alias was already in scope.

Verified: npm test 251/251; coverage 92.04 lines / 81.34 branches / 91.49
functions (thresholds 88/79/89); release:check exit 0; npx pm health
--strict-exit ok: true.

* Derive the preflight drift guard from real activation instead of a hand-maintained list

Greptile (P2) and CodeRabbit (Major) independently raised the same objection to
the guard added in the previous commit, and both were right.

The test compared the override scope against DECLARED_READ_ONLY_COMMANDS, a
second hand-maintained literal, and only checked that each CURRENT scope entry
was mutating. So declaring a new mutating command while omitting it from both
the scope and that literal left every assertion green - the guard could not
detect the drift it was written for, which is worse than no guard because it
reads as coverage.

This matters more than a typical test-quality note. The whole point of the
change is to NARROW a preflight scope, and narrowing is precisely the operation
that can drop a command's credential gate silently: the runtime matches by exact
normalized path, swallows preflight throws, and the authoritative handler gate
only fires once the command has already run and failed.

The test now derives the declared set from the real activation registrations -
registerCommand, registerImporter and registerExporter - asserts the dispatch
handler paths equal that derived set, partitions it with the same
isMutatingGithubCommand predicate production uses rather than a second copy of
the knowledge, and asserts the mutating and read-only classes reconstruct the
declared set EXACTLY. That last assertion is the one that closes the finding:
without it the hand-maintained list has merely moved.

Verified non-vacuous rather than assumed. A scratch mutating command
'github scratch drift' was declared through registerCommand and added to
isMutatingGithubCommand without touching the override scope; the suite failed
1 of 251 with 'preflight override scope must equal the mutating class of the
declared command set exactly' and the diff named the command. The scratch
command has been removed; 251 of 251 green.

---------

Co-authored-by: SteveBot <1153461+unbraind@users.noreply.github.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

Development

Successfully merging this pull request may close these issues.

1 participant