Skip to content

Add step-summary command visibility to agentic_commands dispatcher#36346

Merged
pelikhan merged 1 commit into
mainfrom
copilot/update-agentic-commands-logging
Jun 1, 2026
Merged

Add step-summary command visibility to agentic_commands dispatcher#36346
pelikhan merged 1 commit into
mainfrom
copilot/update-agentic-commands-logging

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 1, 2026

The centralized agentic_commands dispatcher did not expose which commands were configured or which command was selected for the current event in the workflow step summary. This change adds explicit summary output so routing decisions are visible at-a-glance during triage.

  • Summary instrumentation

    • Added appendRoutingSummary(existingCommands, selectedCommand) in route_slash_command.cjs.
    • Appends a compact section to GITHUB_STEP_SUMMARY with:
      • configured centralized slash commands
      • selected command parsed from payload (or <none> when absent)
    • Uses non-overwrite writes and safely no-ops when summary APIs are unavailable.
  • Dispatcher flow update

    • Resolves payload text/token earlier in main().
    • Computes selected command before routing and logs it to the step summary regardless of match outcome.
    • Keeps dispatch/reaction behavior unchanged.
  • Test coverage

    • Extended route_slash_command.test.cjs to assert step-summary output for:
      • slash-command payloads (e.g. /archie ...)
      • non-slash payloads (Selected command: <none>)
summary
  .addHeading("Agentic Commands Router", 3)
  .addRaw(`- Existing commands: ${existingCommandsText}`, true)
  .addEOL()
  .addRaw(`- Selected command: ${selectedCommandText}`, true)
  .addEOL();

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title Log existing and selected commands in agentic router summary Add step-summary command visibility to agentic_commands dispatcher Jun 1, 2026
Copilot AI requested a review from pelikhan June 1, 2026 22:12
@pelikhan pelikhan marked this pull request as ready for review June 1, 2026 22:13
Copilot AI review requested due to automatic review settings June 1, 2026 22:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves observability of the centralized agentic_commands slash-command dispatcher by appending routing details (configured commands + selected command from the payload) to the GitHub Actions step summary, and extends the unit tests to verify that summary output for slash and non-slash payloads.

Changes:

  • Added appendRoutingSummary(existingCommands, selectedCommand) to write routing context into GITHUB_STEP_SUMMARY.
  • Moved payload token parsing earlier in main() and logs the selected command regardless of routing match outcome.
  • Extended route_slash_command tests to assert step-summary output for both slash and non-slash payloads.
Show a summary per file
File Description
actions/setup/js/route_slash_command.cjs Adds step-summary instrumentation and parses the selected slash command earlier for consistent logging.
actions/setup/js/route_slash_command.test.cjs Adds assertions verifying the step-summary output for slash and non-slash payloads.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

Comment on lines +17 to +19
if (!summary || typeof summary.addHeading !== "function" || typeof summary.addRaw !== "function" || typeof summary.write !== "function") {
return;
}
Comment on lines +26 to +27
const existingCommandsText = normalizedCommands.length ? normalizedCommands.join(", ") : "<none>";
const selectedCommandText = selectedCommand ? `/${selectedCommand}` : "<none>";
Comment on lines +110 to +112
expect(summaryMock.addRaw).toHaveBeenCalledWith("- Existing commands: /archie", true);
expect(summaryMock.addRaw).toHaveBeenCalledWith("- Selected command: <none>", true);
expect(summaryMock.write).toHaveBeenCalledWith({ overwrite: false });
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #36346 does not have the 'implementation' label (has_implementation_label=false) and has 0 new lines of code in business logic directories (well under the 100-line threshold). No custom design-gate config present.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

PR Code Quality Reviewer completed the code quality review.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions github-actions Bot mentioned this pull request Jun 1, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

REQUEST_CHANGES — two correctness bugs and one security-adjacent ordering issue must be fixed before merge.

### Blocking issues
  1. <none> renders invisible in GitHub Markdown (line 27) — <none> is parsed as an HTML tag and disappears in rendered output. Use `<none>` or <none>.

  2. addEOL missing from capability guard (line 19) — the guard checks addHeading/addRaw/write but not addEOL. A missing addEOL throws inside the chained call and falls into catch rather than cleanly no-oping.

  3. Command inventory written before auth checks (line 255, new comment) — appendRoutingSummary fires for every event, exposing the full slash-command list and the actor's attempted command in the step summary before any membership/identity guard runs.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 1.2M

const labelRouteMap = JSON.parse(process.env.GH_AW_LABEL_ROUTING || "{}");
core.info(`Configured centralized slash commands: ${Object.keys(slashRouteMap).length}.`);
core.info(`Configured decentralized label commands: ${Object.keys(labelRouteMap).length}.`);
const text = resolveBodyText();
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.

Command inventory exposed before auth checks: appendRoutingSummary writes all configured slash commands and the actor's attempted command to the step summary before any identity or membership validation runs. Any user who can post a comment will get a step summary showing the full command list, even if they're subsequently rejected.

💡 Suggested fix

Move the appendRoutingSummary call to after all auth/membership guards pass — i.e., just before the command dispatch logic where commandName is already validated:

// After auth checks pass...
const commandName = selectedCommand;
core.info(`Resolved command '/${commandName}'...`);
await appendRoutingSummary(Object.keys(slashRouteMap), commandName);

Alternatively, if visibility of configured commands on unauthorized events is intentional for diagnostics, document that decision explicitly — but the current code gives no indication this is deliberate.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

🧪 Test Quality Sentinel Report

Test Quality Score: 85/100 — Excellent

Analyzed 2 test(s) in route_slash_command.test.cjs: 2 design tests, 0 implementation tests, 0 guideline violations.

📊 Metrics & Test Classification (2 tests analyzed)
Metric Value
New/modified tests analyzed 2
✅ Design tests (behavioral contracts) 2 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 1 (50%)
Duplicate test clusters 0
Test inflation detected No (test: +21 lines, prod: +33 lines, ratio: 0.64)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Issues Detected
(existing /archie routing test) — +3 new assertions actions/setup/js/route_slash_command.test.cjs:97 ✅ Design Verifies summary content for successful slash command dispatch
logs empty selected command in summary when no slash command is present actions/setup/js/route_slash_command.test.cjs:107 ✅ Design Edge case: verifies <none> shown when no slash command present

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 0 tests
  • 🟨 JavaScript (*.test.cjs, *.test.js): 2 tests (vitest)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). Both tests verify observable side effects of the new appendRoutingSummary function against the external GitHub Actions core.summary API — a legitimate and necessary mock target. The edge-case test (<none> label when no slash command is present) adds good behavioral coverage of the non-dispatch path.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 1.4M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 85/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%).

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /tdd and /zoom-out — overall the change is clean and well-motivated, with a few test-coverage gaps worth addressing.

📋 Key Themes & Highlights

Key Themes

  • Untested branches: The core.summary guard path and the summary.write rejection path both have no test coverage — see inline comments.
  • Unconditional summary write: The routing summary fires before isPRClosedAtStart() and label-event guards, which means it also runs for events where slash-command routing is irrelevant. Documenting the intent (or moving the call) would prevent confusion.

Positive Highlights

  • ✅ Non-overwrite write strategy ({ overwrite: false }) is the right choice to avoid clobbering prior summary content.
  • normalizedCommands is sorted before display — consistent ordering makes step summaries easy to compare across runs.
  • selectedCommand = firstWord.startsWith("/") ? firstWord.slice(1) : "" eliminates the duplicated parsing logic that previously existed downstream, and the commandName = selectedCommand reassignment keeps the change surgical.
  • ✅ Two new test cases cover the happy path and the non-slash payload path.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 1.4M

Comments that could not be inline-anchored

actions/setup/js/route_slash_command.cjs:34

[/tdd] The if (!summary || ...) guard branch is never exercised — if core.summary is absent the function silently returns, but this path has no test coverage.

<details>
<summary>💡 Suggested test</summary>

Add a case that omits core.summary and verifies neither an error nor a summary write occurs:

it(&quot;handles missing core.summary gracefully&quot;, async () =&gt; {
  globals.core.summary = undefined;
  await main();
  // dispatch still proceeds
  expect(dispatchCalls).toHaveLength(1);

</details>

<details><summary>actions/setup/js/route_slash_command.cjs:44</summary>

**[/tdd]** The `catch` block (line 44) is reachable when `summary.write()` rejects, but no test covers this path  so the `core.warning` call and the non-throwing contract are untested.

&lt;details&gt;
&lt;summary&gt;💡 Suggested test&lt;/summary&gt;

```js
it(&quot;warns but does not throw when summary.write rejects&quot;, async () =&gt; {
  summaryMock.write = vi.fn(async () =&gt; { throw new Error(&quot;disk full&quot;); });
  await expect(main()).resolves.not.toThrow();
  expect(globals.core.warning).toHaveBeenCalledWith(
    expect…

</details>

<details><summary>actions/setup/js/route_slash_command.cjs:258</summary>

**[/zoom-out]** `appendRoutingSummary` runs unconditionally before the `isPRClosedAtStart()` guard and the `labeled` event branch. For a closed-PR or label event, the summary section will still be written — `selectedCommand` will show `&lt;none&gt;` even though slash-command routing is not applicable for those paths.

If this is intentional (always log what arrived), a brief comment here would make the intent clear. If slash-command summary should only appear for slash-command–eligible events, consid…

</details>

@pelikhan pelikhan merged commit 7ac86cd into main Jun 1, 2026
58 of 64 checks passed
@pelikhan pelikhan deleted the copilot/update-agentic-commands-logging branch June 1, 2026 22:38
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.

3 participants