Skip to content

Default-on issue intent metadata for set_issue_type, set_issue_field, and add_labels#46207

Merged
pelikhan merged 6 commits into
mainfrom
copilot/preserve-issue-intent-metadata
Jul 18, 2026
Merged

Default-on issue intent metadata for set_issue_type, set_issue_field, and add_labels#46207
pelikhan merged 6 commits into
mainfrom
copilot/preserve-issue-intent-metadata

Conversation

Copilot AI commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Three handlers (set_issue_type, set_issue_field, add_labels) gated intent metadata on config.issue_intent === true, silently discarding agent-supplied rationale/confidence when frontmatter was omitted — inconsistent with close_issue and assign_to_agent which default-on with !== false.

Handler changes

  • set_issue_type / set_issue_field / add_labels: Change gate from config.issue_intent === trueconfig.issue_intent !== false. Omitted frontmatter now forwards metadata through the GraphQL/intent-aware path by default.

  • add_labels strict mode: Introduce issueIntentStrict = config.issue_intent === true. When explicitly true, plain-string label names are rejected — agents must supply structured objects with intent fields. Default (omitted) accepts both strings and objects.

// Before: metadata silently dropped with omitted config
const issueIntentEnabled = config.issue_intent === true;  // false when omitted

// After: default-on, consistent with close_issue / assign_to_agent
const issueIntentEnabled = config.issue_intent !== false;  // true when omitted
const issueIntentStrict = config.issue_intent === true;    // add_labels strict mode

Schema

Added issue-intent: boolean property to add-labels, set-issue-type, and set-issue-field in main_workflow_schema.json. Previously the compiler rejected issue-intent frontmatter for these handlers, making opt-out (issue_intent: false) impossible via valid workflow syntax.

Tests

Added focused tests covering: omitted-config selects the intent path and forwards metadata; strict mode (true) rejects plain string labels; plain strings remain compatible in default mode; explicit disable (false) still selects the legacy REST path.

… omitted

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- Change `set_issue_type`, `set_issue_field`, `add_labels` handlers from
  `config.issue_intent === true` to `config.issue_intent !== false` so
  intent metadata is forwarded by default, consistent with `close_issue`
  and `assign_to_agent` semantics.
- Add strict-mode enforcement in `add_labels`: when `issue_intent: true`
  is explicitly set, plain string label names are rejected.
- Add `issue-intent` boolean to JSON schema for `add-labels`,
  `set-issue-type`, and `set-issue-field` (compiler previously rejected
  the frontmatter for these handlers).
- Add focused tests covering omitted config, strict mode, metadata
  forwarding, and plain-string compatibility.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix issue intent metadata handling when frontmatter is omitted Default-on issue intent metadata for set_issue_type, set_issue_field, and add_labels Jul 17, 2026
Copilot AI requested a review from pelikhan July 17, 2026 11:49
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the clear PR description and for calling out the consistency issue with close_issue and assign_to_agent specifically. The change looks focused, the schema update is well-scoped, and the added handler tests make the behavioral intent easy to verify.

This PR looks ready for review — nice work tightening the default-on issue_intent behavior while preserving explicit opt-out semantics.

Generated by ✅ Contribution Check · 80.9 AIC · ⌖ 8.97 AIC · ⊞ 6.2K ·

@pelikhan
pelikhan marked this pull request as ready for review July 18, 2026 05:34
Copilot AI review requested due to automatic review settings July 18, 2026 05:34

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

Defaults issue-intent metadata forwarding on while preserving explicit opt-out and adding strict label handling.

Changes:

  • Default-enable intent metadata for three issue handlers.
  • Add strict structured-label validation.
  • Extend schema support and focused tests.
Show a summary per file
File Description
pkg/parser/schemas/main_workflow_schema.json Adds issue-intent configuration fields.
actions/setup/js/set_issue_type.cjs Defaults to the intent-aware GraphQL path.
actions/setup/js/set_issue_type.test.cjs Tests default intent behavior.
actions/setup/js/set_issue_field.cjs Defaults metadata forwarding on.
actions/setup/js/set_issue_field.test.cjs Tests default metadata forwarding.
actions/setup/js/add_labels.cjs Defaults metadata forwarding and adds strict mode.
actions/setup/js/add_labels.test.cjs Tests default, disabled, and strict modes.

Review details

Tip

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

  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment on lines +104 to +107
if (issueIntentStrict) {
const plainStringLabels = requestedLabelInputs.filter(label => typeof label === "string");
if (plainStringLabels.length > 0) {
const error = `Plain string label names are not permitted when issue_intent is explicitly enabled. Provide label objects with a "name" field and intent metadata (rationale, confidence). Plain labels: ${plainStringLabels.map(l => JSON.stringify(l)).join(", ")}`;
@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

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

The default-on change (!== false) is correct and consistent with close_issue/assign_to_agent. The one-liner fixes for set_issue_type and set_issue_field are clean and well-tested.

Blocking issue: add_labels strict mode gap

See the existing inline comment at add_labels.cjs:107. The strict-mode check rejects plain strings but silently passes objects lacking intent metadata (e.g. { name: "bug" }). Such objects are then downgraded to plain strings at line 206, so an agent can bypass the strict-mode intent requirement. The check should additionally reject label objects missing all of rationale/confidence/suggest.

Minor

  • Schema description fields for issue-intent should mention the behavioural difference: true = metadata required on every label; omitted = plain strings still accepted.
  • Add a test for strict mode with { name: "bug" } (bare object, no metadata) to document expected rejection once the gap is fixed.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 28.1 AIC · ⌖ 4.34 AIC · ⊞ 5K

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

❌ Request Changes

Two blocking issues before merge.

🔍 Findings summary

Critical: Implicit breaking behavior change (3 files)
The === true!== false flip is silently backwards-incompatible. Every existing deployment that omits issue_intent frontmatter will silently switch from REST to the GraphQL/intent path. This can change API call shapes, required permissions, and data formats without any user signal. See inline comment on add_labels.cjs:10.

High: Schema key mismatch renders opt-out non-functional
The schema adds "issue-intent" (kebab-case) but handlers read config.issue_intent (snake_case). Unless the compiler normalizes keys, issue_intent: false opt-out is unreachable from frontmatter. See inline comment on main_workflow_schema.json:239.

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

Comments that could not be inline-anchored

actions/setup/js/add_labels.cjs:10

Silent breaking change: flipping the gate from === true to !== false is a backwards-incompatible behavior change for any existing workflow that omits issue_intent.

<details>
<summary>💡 Why this is risky</summary>

Before this PR, omitting issue_intent meant issueIntentEnabled = false — the REST path was taken. After this PR, omitting it means issueIntentEnabled = true — the GraphQL/intent path is taken silently.

Any deployed workflow relying on the old REST behavior (no front…

pkg/parser/schemas/main_workflow_schema.json:239

Schema key mismatch: schema uses issue-intent (kebab-case) but runtime code reads config.issue_intent (snake_case) — opt-out via frontmatter will silently have no effect.

<details>
<summary>💡 Details</summary>

The schema adds the property as &quot;issue-intent&quot; (lines 236–239, 247–250, 258–261). JavaScript reads it as config.issue_intent (the underscore form). Unless the workflow compiler or YAML loader transparently normalizes kebab-case keys to snake_case, setting `issue-intent: fal…

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (114 new lines across actions/setup/js/ and pkg/parser/schemas/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/46207-default-on-issue-intent-metadata.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch at docs/adr/46207-default-on-issue-intent-metadata.md
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-46207: Default-On Issue Intent Metadata

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 46207-default-on-issue-intent-metadata.md for PR #46207).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 54.8 AIC · ⌖ 10.1 AIC · ⊞ 8.5K ·
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.

Skills-Based Review 🧠

Applied /codebase-design and /tdd — requesting changes on a strict-mode enforcement gap.

📋 Key Themes & Highlights

Key Issue

Strict-mode contract is partially enforced. issueIntentStrict correctly rejects plain strings but silently allows label objects without metadata (e.g. { name: "bug" }), which then get downgraded to plain strings at line 206. The behaviour contradicts the stated contract that strict mode requires metadata. This needs both a code fix and a companion test.

Positive Highlights

  • ✅ Clean default-on alignment with close_issue / assign_to_agent — consistent and well-explained in the PR body.
  • ✅ Good test coverage for the omitted-config and explicit-false cases.
  • ✅ Schema additions are minimal and correctly placed.

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

Comments that could not be inline-anchored

actions/setup/js/add_labels.cjs:206
actions/setup/js/add_labels.cjs:206

[/codebase-design] In strict mode (issue_intent: true), label objects without any intent metadata (e.g. { name: &quot;bug&quot; }) pass the string-rejection guard on line 104 but are silently downgraded to plain strings here, defeating the contract strict mode promises.

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

Extend the strict-mode guard to also reject metadata-free objects:

if (issueIntentStrict) {
  const withoutMetadata = requestedLabelInputs.filter(
    label =&gt; typeof label !==

</details>

<details><summary>actions/setup/js/add_labels.test.cjs:606</summary>

**[/tdd]** The strict-mode test only covers plain string inputs. A `{ name: &quot;bug&quot; }` object (no metadata) also violates the strict-mode contract but is not tested  this is the same gap flagged on the implementation side.

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

```js
it(&#39;should reject object labels without metadata in strict mode&#39;, async () =&gt; {
  const handler = await main({ max: 10, issue_intent: true });
  const result = await handler({ item_number: 1, labels: [{ name: &#39;bug&#39; }] }, {

</details>

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

⚠️ Test Quality Score: 72/100 — Acceptable

Analyzed 50 test(s) (sampled): 42 design, 8 implementation, 0 violation(s).

📊 Metrics (50 tests analyzed, sampled from ~100)
Metric Value
Analyzed 50 sampled (Go: 0, JS: 50)
✅ Design 42 (84%)
⚠️ Implementation 8 (16%)
Edge/error coverage 30 (60%)
Duplicate clusters 0
Inflation YES (add_labels.test.cjs 4.5:1 vs prod)
🚨 Violations 0
Test File Classification Issues
should include intent metadata by default when issue_intent is omitted set_issue_field.test.cjs:558 design_test None
should omit intent metadata when issue_intent is disabled set_issue_field.test.cjs:532 design_test None
should include issue intent metadata without requiring a runtime feature set_issue_field.test.cjs:498 design_test None
should use GraphQL intent path by default when issue_intent is omitted set_issue_type.test.cjs:499 design_test None
should forward intent metadata by default when issue_intent is omitted set_issue_type.test.cjs:523 design_test None
should use legacy REST issue type update when issue_intent is disabled set_issue_type.test.cjs:474 design_test None
should forward per-label intent metadata by default when issue_intent is omitted add_labels.test.cjs:562 design_test None
should strip structured intent metadata when issue_intent is disabled add_labels.test.cjs:540 design_test None
should accept plain string labels by default when issue_intent is omitted add_labels.test.cjs:584 design_test None
should reject plain string labels when issue_intent is explicitly true add_labels.test.cjs:606 design_test Includes error path ✅
should return a function from main() set_issue_field.test.cjs:96 implementation_test Happy-path only
should return a function from main() set_issue_type.test.cjs:83 implementation_test Happy-path only
should create a handler function with default configuration add_labels.test.cjs:70 implementation_test Happy-path only

⚠️ Sampling note: 50 of ~100 total tests analyzed. Newly added intent-metadata tests were prioritized.

⚠️ Flagged Tests (1 pattern)

should return a function from main() (×3 files)implementation_test. These tests only assert typeof result === "function", providing no behavioral coverage. They would not detect regressions in initialization logic or config validation. Low-value but not harmful; consider folding into the first substantive test.

add_labels.test.cjs inflation (4.5:1) — Test file is 1,181 lines vs 264 prod lines. The large suite is comprehensive and covers many edge cases. Not a violation — add_labels is a complex handler and the breadth of coverage justifies the size.

Verdict

Passed. 16% implementation tests (threshold: 30%). The core PR additions — default-on issue_intent tests for set_issue_type, set_issue_field, and add_labels — are all design_test with clear behavioral assertions on API payload shape and flag-controlled branching. Error paths and edge cases (disabled flag, omitted flag, strict mode) are covered. No guideline violations.

References:

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 37.2 AIC · ⌖ 8.25 AIC · ⊞ 6.8K ·
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: 72/100. 16% implementation tests (threshold: 30%). Core intent-metadata tests are design-quality with clear behavioral assertions.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Copilot AI and others added 2 commits July 18, 2026 08:37
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…labels schema

- add_labels.cjs: strict mode (issue_intent: true) now rejects label objects
  missing rationale or confidence, not just plain strings
- generate_safe_outputs_tools.cjs: when issue-intent: true, labels items schema
  becomes object-only with name/rationale/confidence required
- Tests: added coverage for missing-metadata rejection and schema change;
  moved deduplication test to default mode (omitted issue_intent) since
  mixed metadata quality is invalid in strict mode

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

Copilot AI commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

@copilot run pr-finisher skill

Done in b46ac20. Two concrete fixes:

  1. Runtime (add_labels.cjs) — strict mode now also rejects label objects missing rationale or confidence. Previously only plain strings were caught; { name: "bug" } would silently pass and get downgraded to a plain-string call.

  2. Schema generator (generate_safe_outputs_tools.cjs) — when issue-intent: true, the labels items schema is rewritten from oneOf [string, {name required}] to a plain object with name, rationale, and confidence all in required. This makes the tool contract consistent with what the runtime now enforces.

The deduplication test (should prefer the metadata-bearing entry when a duplicate label name appears) was moved from issue_intent: true to the default (omitted) mode, since mixed metadata quality (one { name: "bug" } + one { name: "bug", rationale, confidence }) is a schema violation in strict mode.

@pelikhan
pelikhan merged commit 991f7d4 into main Jul 18, 2026
@pelikhan
pelikhan deleted the copilot/preserve-issue-intent-metadata branch July 18, 2026 08:55
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preserve issue intent metadata when frontmatter is omitted

3 participants