Skip to content

fix: mode-specific intent guidance for all intent-aware safe-output mutations - #46876

Merged
pelikhan merged 8 commits into
mainfrom
copilot/update-intent-aware-mutation-descriptions-again
Jul 20, 2026
Merged

fix: mode-specific intent guidance for all intent-aware safe-output mutations#46876
pelikhan merged 8 commits into
mainfrom
copilot/update-intent-aware-mutation-descriptions-again

Conversation

Copilot AI commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Generated tool descriptions for intent-aware mutations (add_labels, set_issue_type, set_issue_field, close_issue, assign_to_user, assign_to_agent) were inconsistent with their runtime schemas. Most critically, add_labels in strict mode still described plain strings as valid and rationale/confidence as optional — causing agents to emit payloads the safe-output processor would reject entirely.

Behavior by mode

Mode Before After
issue_intent: true Generic "INTENT: Include…" suffix; field descriptions still said "Optional" "INTENT REQUIRED: …are required for each call."; rationale/confidence descriptions updated to say "Required"; add_labels labels description is object-only with example
issue_intent omitted No guidance at all "INTENT ENCOURAGED: …optional but strongly encouraged…"; add_labels prefers structured objects while keeping plain strings valid
issue_intent: false Intent fields stripped Unchanged

Changes

generate_safe_outputs_tools.cjs

  • Replaced ISSUE_INTENT_SUFFIX with two mode-specific constants: ISSUE_INTENT_REQUIRED_SUFFIX and ISSUE_INTENT_OPTIONAL_SUFFIX
  • Added ADD_LABELS_STRICT_FIELD_DESC / ADD_LABELS_OPTIONAL_FIELD_DESC constants for the labels property description in each mode
  • Added isIssueIntentOmittedForTool() helper to detect the default/omitted case
  • Added makeIntentFieldDescriptionsRequired() to rewrite top-level rationale/confidence property descriptions from "Optional…" to "Required…" in strict mode
  • In strict mode: applies required suffix, calls makeIntentFieldDescriptionsRequired(), replaces add_labels labels description and updates nested rationale/confidence item descriptions
  • In omitted mode: applies encouraged suffix, updates add_labels labels description to prefer structured objects

generate_safe_outputs_tools.test.cjs

  • Updated existing tests to use new INTENT REQUIRED: suffix text
  • Added 4 new regression tests covering all three modes for all 6 tools; strict add_labels assertions verify the description contains no "plain strings accepted" language and no "optional" for required fields

Example: strict mode add_labels schema + description (was conflicting, now consistent)

{
  "labels": {
    "description": "Labels to add. Each label must be an object with required fields: name (string), rationale (string, max 280 chars), and confidence (exactly one of: LOW, MEDIUM, HIGH). Plain string label names are not permitted. Example: [{\"name\": \"bug\", \"rationale\": \"The report describes reproducible incorrect behavior.\", \"confidence\": \"HIGH\"}].",
    "type": "array",
    "items": {
      "type": "object",
      "required": ["name", "rationale", "confidence"],
      "properties": { ... }
    }
  }
}

pr-sous-chef run https://github.com/github/gh-aw/actions/runs/29761732160

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · 31.2 AIC · ⌖ 6.13 AIC · ⊞ 6.9K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 20, 2026 15:48
- Add ISSUE_INTENT_REQUIRED_SUFFIX constant for issue_intent: true mode
- Add ISSUE_INTENT_OPTIONAL_SUFFIX constant for omitted issue_intent mode
- Add ADD_LABELS_STRICT_FIELD_DESC / ADD_LABELS_OPTIONAL_FIELD_DESC constants
- Add isIssueIntentOmittedForTool() helper
- Add makeIntentFieldDescriptionsRequired() helper to update rationale/confidence
  property descriptions from "Optional" to "Required" in strict mode
- In strict mode: use required suffix, update rationale/confidence descriptions,
  update add_labels labels description and nested items descriptions
- In omitted mode: use encouraged suffix, update add_labels labels description
  to prefer structured objects while keeping plain strings valid
- Update existing tests to use new suffix strings
- Add new tests covering omitted, required, and disabled modes for all 6 tools

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…spread, clarify test name and regex comment

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Update intent-aware mutation descriptions for metadata requirements fix: mode-specific intent guidance for all intent-aware safe-output mutations Jul 20, 2026
Copilot AI requested a review from pelikhan July 20, 2026 15:58
@pelikhan
pelikhan marked this pull request as ready for review July 20, 2026 15:59
Copilot AI review requested due to automatic review settings July 20, 2026 15:59
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

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

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

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

Copilot AI 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.

Pull request overview

Aligns intent-aware safe-output descriptions with strict, optional, and disabled runtime schemas.

Changes:

  • Adds mode-specific intent guidance and label examples.
  • Updates required field descriptions.
  • Expands regression coverage across six mutation tools.
Show a summary per file
File Description
actions/setup/js/generate_safe_outputs_tools.cjs Generates mode-specific intent guidance.
actions/setup/js/generate_safe_outputs_tools.test.cjs Tests intent behavior across modes.

Review details

Tip

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

Comments suppressed due to low confidence (1)

actions/setup/js/generate_safe_outputs_tools.cjs:47

  • The example shows a bare object even though labels has type: "array". An agent copying this example would produce a schema-invalid payload; wrap the structured label in an array.
  'Labels to add. Prefer structured label objects: {"name": "bug", "rationale": "The report describes reproducible incorrect behavior.", "confidence": "HIGH"}. Plain strings are also accepted for compatibility. Include rationale (string, max 280 chars) and confidence (LOW, MEDIUM, or HIGH) to improve transparency. Labels must exist in the repository.';
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Medium

const ISSUE_INTENT_SUFFIX = "INTENT: Include rationale (string, max 280 chars) and confidence (string, exactly one of: LOW, MEDIUM, HIGH) with each call.";
const ISSUE_INTENT_REQUIRED_SUFFIX = "INTENT REQUIRED: rationale (string, max 280 chars) and confidence (exactly one of: LOW, MEDIUM, HIGH) are required for each call.";
const ISSUE_INTENT_OPTIONAL_SUFFIX =
"INTENT ENCOURAGED: Include rationale (string, max 280 chars) and confidence (exactly one of: LOW, MEDIUM, HIGH) with each call. These fields are optional but strongly encouraged — they improve transparency and should normally be included. Use suggest: true to route for human review.";
}
if (isIssueIntentEnabledForTool(tool.name, config[tool.name])) {
enhancedTool.description = `${enhancedTool.description || ""} ${ISSUE_INTENT_SUFFIX}`.trim();
enhancedTool.description = `${enhancedTool.description || ""} ${ISSUE_INTENT_REQUIRED_SUFFIX}`.trim();

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

Review: LGTM

The three-mode intent split (REQUIRED / ENCOURAGED / disabled) is correctly implemented and fully tested.

  • isIssueIntentOmittedForTool cleanly detects the default case without branch overlap with enabled/disabled paths.
  • makeIntentFieldDescriptionsRequired patches top-level rationale/confidence descriptions; nested item descriptions for add_labels are separately handled with dedicated constants.
  • Old combined omitted+disabled test properly split into focused negative assertion (disabled) and new positive coverage test (omitted, all 6 tools).
  • Strict add_labels now consistently forbids plain strings in both description text and schema.

No correctness, security, or reliability issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 22.9 AIC · ⌖ 7.68 AIC · ⊞ 5K

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100 — Excellent

Analyzed 10 test(s): 10 design, 0 implementation, 0 violation(s).

📊 Metrics (10 tests)
Metric Value
Analyzed 10 (Go: 0, JS: 10)
✅ Design 10 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 10 (100%)
Duplicate clusters 0
Inflation Borderline (total file ratio 2.01:1)
🚨 Violations 0
Test File Classification Issues
adds issue intent suffix for issue tools when explicitly enabled generate_safe_outputs_tools.test.cjs:310 design_test None
adds issue intent suffix even when unrelated runtime features are present generate_safe_outputs_tools.test.cjs:350 design_test None
omits issue intent guidance when explicitly disabled per tool generate_safe_outputs_tools.test.cjs:371 design_test None
makes add_labels label items object-only with required name/rationale/confidence when issue_intent is true generate_safe_outputs_tools.test.cjs:384 design_test None
does not modify add_labels label items schema when issue_intent is omitted or false generate_safe_outputs_tools.test.cjs:431 design_test None
reflects required/optional/absent intent fields per tool configuration generate_safe_outputs_tools.test.cjs:468 design_test None
adds encouraged intent guidance for all intent-aware tools when issue_intent is omitted generate_safe_outputs_tools.test.cjs:542 design_test None
strict mode add_labels description does not permit plain strings and marks fields as required generate_safe_outputs_tools.test.cjs:593 design_test None
omitted mode add_labels description prefers structured label objects and permits plain strings generate_safe_outputs_tools.test.cjs:653 design_test None
strict mode updates rationale and confidence property descriptions to say required generate_safe_outputs_tools.test.cjs:689 design_test None

Verdict

Passed. 0% implementation tests (threshold: 30%). All 10 new tests verify user-visible behavioral contracts for the three intent modes (required/encouraged/absent). The test suite covers the full mode matrix across all 6 intent-aware tools, includes negative assertions, and uses no forbidden mocks. Borderline file-level inflation (2.01:1) did not affect scoring as actual added-line data was unavailable.

References:

🧪 Test quality analysis by Test Quality Sentinel · 42 AIC · ⌖ 7.66 AIC · ⊞ 7K ·
Comment /review to run again

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

✅ Test Quality Sentinel: 90/100. 0% implementation tests (threshold: 30%). All 10 new tests are behavioral design tests covering the full intent-mode matrix (required/encouraged/absent) across all intent-aware safe-output tools.

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

Verdict: two issues require fixes before merge

Blocking: makeIntentFieldDescriptionsRequired marks fields as required in text but never updates inputSchema.required, creating a schema/description mismatch that validators and strict consumers will not catch (see line 56 comment). Blocking: the omitted-mode add_labels description says "Plain strings are also accepted" unconditionally, even when the source schema has no oneOf allowing strings — agents that trust the description will emit payloads the validator rejects (see line 113 comment).

Non-blocking
  • Line 102: delete labelsSchema.items.oneOf is dead code after the full object replacement — remove to avoid misleading future readers.

🔎 Code quality review by PR Code Quality Reviewer · 57.1 AIC · ⌖ 4.67 AIC · ⊞ 5.6K
Comment /review to run again

Comments that could not be inline-anchored

actions/setup/js/generate_safe_outputs_tools.cjs:56

makeIntentFieldDescriptionsRequired never updates inputSchema.required: The function rewrites description text to say "Required" but never adds rationale/confidence to inputSchema.required, so JSON Schema validators will not enforce them.

<details>
<summary>💡 Suggested fix</summary>

Add the fields to required inside the function:

const required = new Set(schema.required ?? []);
required.add(&#39;rationale&#39;);
required.add(&#39;confidence&#39;);
schema.required = [...required];

actions/setup/js/generate_safe_outputs_tools.cjs:113

ADD_LABELS_OPTIONAL_FIELD_DESC applied unconditionally even when items.oneOf is absent: The omitted-mode branch replaces the labels description with text saying "Plain strings are also accepted", but never checks whether the source schema actually supports plain strings via items.oneOf.

<details>
<summary>💡 Detail</summary>

If the source tool's labels.items is already a plain {type: &#39;object&#39;} (no oneOf), the description will incorrectly advertise plain string support that t…

actions/setup/js/generate_safe_outputs_tools.cjs:102

delete labelsSchema.items.oneOf is a no-op: After labelsSchema.items = strictItems (line 101), strictItems was spread from objectSchema which never had oneOf — that property lived on the old items wrapper. The delete deletes a non-existent property on the new object and does nothing.

<details>
<summary>💡 Detail</summary>

The old code needed the delete because it mutated the existing items object. Here, a new object is assigned, so oneOf is never present on it. The `delete…

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

Skills-Based Review

Applied /tdd and /codebase-design — two targeted observations, no blocking issues.

Key themes:

  • Test coverage gap (omitted mode): omitted-mode test does not assert rationale/confidence descriptions remain Optional.
  • Control flow: isIssueIntentDisabled is a separate if rather than fused into the else if chain.

Highlights:

  • Clean split of ISSUE_INTENT_SUFFIX into two well-named constants
  • makeIntentFieldDescriptionsRequired is a focused helper
  • Four new regression tests cover all three modes thoroughly
  • PR description table clearly articulates before/after per mode

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 37.4 AIC · ⌖ 4.63 AIC · ⊞ 6.7K
Comment /matt to run again

name: "add_labels",
description: "Adds labels.",
inputSchema: {
type: "object",

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.

[/tdd] The omitted-mode test verifies that rationale/confidence are not in inputSchema.required, but doesn't assert that their descriptions still say "Optional" — so a future accidental call to makeIntentFieldDescriptionsRequired in the omitted path would go undetected.

💡 Suggested assertion

Add these assertions inside the loop over toolNames.filter(n => n !== 'add_labels'):

const props = tool.inputSchema.properties;
if (props?.rationale?.description) {
  expect(props.rationale.description, `${name} rationale description should remain optional`).toMatch(/optional/i);
}
if (props?.confidence?.description) {
  expect(props.confidence.description, `${name} confidence description should remain optional`).toMatch(/optional/i);
}

This guards the invariant that omitted mode does not promote field descriptions to required.

@copilot please address this.

}
}
}
if (isIssueIntentDisabledForTool(tool.name, config[tool.name])) {

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.

[/codebase-design] The isIssueIntentDisabled branch at line 297 runs as an independent if after the if/else if chain for enabled/omitted. This means a tool explicitly configured with issue_intent: false will still enter isIssueIntentOmittedForTool — it won't, because isIssueIntentOmittedForTool returns false when disabled — but the structure is brittle: it's easy for a future reader to add another else if that inadvertently runs for disabled tools, or to add logic before the stripIssueIntentSchemaFields call that applies to all non-enabled tools.

💡 Suggestion

Merge the disabled branch into the else chain to make the three modes mutually exclusive at the structural level:

if (isIssueIntentEnabledForTool(...)) {
  // strict
} else if (isIssueIntentDisabledForTool(...)) {
  stripIssueIntentSchemaFields(enhancedTool);
} else if (isIssueIntentOmittedForTool(...)) {
  // encouraged
}

This makes it immediately obvious the modes are exhaustive and mutually exclusive.

@copilot please address this.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback, and rerun checks once the branch is up to date.

Unresolved review threads:

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · 8.75 AIC · ⌖ 14.8 AIC · ⊞ 6.9K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 20, 2026 16:32
… examples

- Update ISSUE_INTENT_OPTIONAL_SUFFIX to say 'alongside rationale and
  confidence' so agents know suggest goes with those fields (inside each
  label object for add_labels, not at the top level)
- Update ADD_LABELS_OPTIONAL_FIELD_DESC to include suggest: true in the
  example object, making its per-label placement unambiguous
- In strict mode for assign_to_agent, replace inline example calls with
  versions that include rationale and confidence so examples match the
  generated schema
- Add regression test for strict-mode assign_to_agent example update
- Add assertion that omitted-mode add_labels description shows suggest
  inside the label object example

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…les and pre-condition

- Capture source description in variable and assert it lacks rationale/confidence
  before transformation, proving the replacement is non-trivial
- Replace simple regex matches with matchAll iteration: verifies that EVERY
  assign_to_agent() call in the output includes both rationale= and confidence=,
  rather than just checking anywhere in the description

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Done. Two commits address the review feedback:

suggest placement guidance (reviewer lines 43 & 47):

  • ISSUE_INTENT_OPTIONAL_SUFFIX now says "Use suggest: true alongside rationale and confidence to route for human review" — valid for both schema shapes (top-level for most tools, per-label-object for add_labels)
  • ADD_LABELS_OPTIONAL_FIELD_DESC example now includes "suggest": true inside the label object, making per-label placement explicit

Strict-mode assign_to_agent examples (reviewer line 256):

  • Added ASSIGN_TO_AGENT_EXAMPLE_USAGE_REGEX + ASSIGN_TO_AGENT_STRICT_EXAMPLE_USAGE constants
  • When strict mode is applied, the two inline assign_to_agent(...) example calls are replaced with versions that include rationale= and confidence=, aligning examples with the generated schema

Regression tests verify: pre-condition (source has no rationale/confidence in examples), post-condition (every example call includes both fields), and the INTENT REQUIRED suffix is still present.

…hain, guards, test assertions

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback, and rerun checks once the branch is up to date.

Unresolved review threads:...

Addressed all 4 unresolved review threads in c61d246:

github-actions thread (line 304 — else-chain structure): Merged the disabled branch into the else-if chain so the three modes are now mutually exclusive at the structural level: enabled → disabled → omitted.

github-actions thread (line 598 — omitted-mode description assertions): Added "Optional …" descriptions to the omitted-mode test source tools and added assertions inside the loop to verify rationale/confidence descriptions remain matching /optional/i — guards against any future accidental call to makeIntentFieldDescriptionsRequired in the omitted path.

PR Code Quality Reviewer BLOCKING (makeIntentFieldDescriptionsRequired never updates required): makeIntentFieldDescriptionsRequired now also adds rationale and confidence to inputSchema.required, so JSON Schema validators enforce them. Pre-existing required fields are preserved. A new assertion in the strict-mode descriptions test verifies this.

PR Code Quality Reviewer BLOCKING (ADD_LABELS_OPTIONAL_FIELD_DESC unconditional): Omitted-mode add_labels now only applies ADD_LABELS_OPTIONAL_FIELD_DESC (which advertises plain string support) when the source schema actually has items.oneOf — guarded by Array.isArray(labelsSchema.items?.oneOf).

Non-blocking cleanup: Removed the dead delete labelsSchema.items.oneOf line (the property never exists on the newly-assigned strictItems object).

Copilot AI requested a review from gh-aw-bot July 20, 2026 16:56
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any remaining review feedback, and rerun checks once the branch is up to date.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · 31.2 AIC · ⌖ 6.13 AIC · ⊞ 6.9K ·
Comment /souschef to run again

@pelikhan
pelikhan merged commit bd3f5d9 into main Jul 20, 2026
8 checks passed
@pelikhan
pelikhan deleted the copilot/update-intent-aware-mutation-descriptions-again branch July 20, 2026 17:20
Copilot stopped work on behalf of gh-aw-bot due to an error July 20, 2026 17:20
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.14

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.

Intent-aware mutation descriptions should encourage optional metadata and clearly require strict metadata

4 participants