Skip to content

chore(metadata): tighten issue and pr governance#974

Merged
ashleyshaw merged 6 commits into
developfrom
chore/metadata-governance-automation
Jun 18, 2026
Merged

chore(metadata): tighten issue and pr governance#974
ashleyshaw merged 6 commits into
developfrom
chore/metadata-governance-automation

Conversation

@ashleyshaw

@ashleyshaw ashleyshaw commented Jun 18, 2026

Copy link
Copy Markdown
Member

Linked issues

Relates to #968

Summary

  • Add automated metadata governance for issues and PRs.
  • Split project field sync from assignee/milestone/relationship handling.
  • Update label, workflow, and project docs to match the live contract.

Changelog

Added

  • Automated issue and PR metadata governance with assignee, milestone, and relationship handling.

Changed

  • Tightened project field derivation so kickoff dates stay empty until status:ready or status:in-progress.
  • Reworked the legacy project-meta-sync entrypoint into a compatibility shim.
  • Updated label and workflow documentation to match the live automation contract.

Fixed

Removed

Risk Assessment

Risk Level: Medium

Potential Impact:

This change touches metadata automation and the supporting docs, but keeps the scope to governance and project-field sync.

Mitigation Steps:

  • Added targeted Jest coverage for the new metadata helper and project-field derivation.
  • Ran workflow, label, issue-field, and template validation locally.
  • Kept the legacy project-meta-sync entrypoint as a compatibility shim.

How to Test

Prerequisites

  • GitHub Actions enabled on the repository.

Test Steps

  1. Open or edit an issue body with linked issue refs and verify metadata governance adds assignee, milestone, and relationship context.
  2. Open a PR with a linked issue reference and verify the project sync keeps kickoff dates empty until the item is ready or in progress.
  3. Run the local validation commands listed below.

Expected Results

  • Issues and PRs are added to the project automatically.
  • Assignee, milestone, and relationship metadata are applied.
  • Start date and Target date remain empty until kickoff.

Edge Cases to Verify

  • Empty issue body still keeps the item open
  • Linked issues and PR references are captured when present
  • Template enforcement labels incomplete issues instead of closing them

Checklist (Global DoD / PR)

  • All AC met and demonstrated
  • Tests added/updated (unit/E2E as appropriate)
  • Docs/readme/changelog updated (if user-facing)
  • Risk assessment completed above
  • Testing instructions provided above

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

✅ Template check passed after update. Thanks for fixing the PR description.

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ashleyshaw, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 29 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: cb79e8e7-4f76-4152-abf7-152e5fefb487

📥 Commits

Reviewing files that changed from the base of the PR and between 71efd64 and 3aa0b0d.

📒 Files selected for processing (36)
  • .github/issue-fields.yml
  • .github/labels.yml
  • .github/prompts/update-mermaid-diagrams.prompt.md
  • .github/reports/mermaid-validation-report.md
  • .github/workflows/README.md
  • .github/workflows/labeling.yml
  • .github/workflows/metadata-governance.yml
  • .github/workflows/project-meta-sync.yml
  • .github/workflows/template-enforcement.yml
  • CHANGELOG.md
  • agents/agent.md
  • agents/project-meta-sync.agent.md
  • docs/AUTOMATION.md
  • docs/GITHUB_PROJECT_OPERATIONS_SPEC.md
  • docs/ISSUE_CREATION_GUIDE.md
  • docs/ISSUE_FIELDS.md
  • docs/LABELING.md
  • docs/LABEL_COLOR_STRATEGY.md
  • docs/LABEL_INVENTORY.md
  • docs/LABEL_STRATEGY.md
  • docs/PR_CREATION_PROCESS.md
  • docs/WORKFLOW_COORDINATION.md
  • docs/agents/PLANNER_RUNBOOK.md
  • instructions/automation.instructions.md
  • instructions/project-meta-sync.instructions.md
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/derive-project-fields.cjs
  • scripts/agents/includes/issue-pr-metadata.cjs
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/labeling.agent.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/run-labeling-agent.cjs
📝 Walkthrough

Walkthrough

Introduces a new metadata-governance workflow backed by a new issue-pr-metadata.cjs script to sync assignee, milestone, and relationship metadata for issues and PRs. Refactors derive-project-fields.cjs with kickoff-aware date gating. Deprecates the legacy project-meta-sync agent. Renames priority labels and splits the labeling agent CLI entrypoint.

Changes

Metadata Governance & Label Taxonomy Overhaul

Layer / File(s) Summary
Label taxonomy and status:needs-more-info config
.github/issue-fields.yml, scripts/agents/includes/label-heuristics.js, docs/LABELING.md, docs/LABEL_COLOR_STRATEGY.md, docs/ISSUE_FIELDS.md, docs/agents/PLANNER_RUNBOOK.md, scripts/agents/includes/__tests__/label-utils.test.js
Priority labels renamed from urgent/high/low to critical/important/minor; type:docs renamed to type:documentation; status:needs-more-info mapped to Triage in the field config; label-utils tests updated to match.
New issue-pr-metadata.cjs metadata sync script
scripts/agents/includes/issue-pr-metadata.cjs
Introduces a 484-line Node.js CLI script with helpers for relationship-hint parsing, milestone lookup/creation, assignee candidate resolution, sub-issue GraphQL mutation, and a syncItemMetadata orchestrator that upserts a marker-identified governance comment.
metadata-governance.yml workflow wiring
.github/workflows/metadata-governance.yml, .github/workflows/README.md
Adds the new workflow with issues/pull_request_target triggers, content-read + issues/PR-write permissions, non-cancelling concurrency, and a GITHUB_STEP_SUMMARY report step; README trigger matrix updated.
derive-project-fields.cjs refactor + project-meta-sync.yml updates
scripts/agents/includes/derive-project-fields.cjs, .github/workflows/project-meta-sync.yml
Extracts deriveProjectFieldValues as an exported function gating startDate/targetDate behind status:ready or status:in-progress; guards main() with require.main; workflow gains ITEM_MILESTONE_DUE_ON env var and splits field updates into two conditional steps.
project-meta-sync agent deprecation + labeling agent CLI split
scripts/agents/project-meta-sync.agent.js, scripts/agents/labeling.agent.js, scripts/agents/run-labeling-agent.cjs, .github/workflows/labeling.yml
project-meta-sync.agent.js stripped to a deprecation shim; labeling.agent.js self-execution removed and imports switched to namespace style; new run-labeling-agent.cjs CJS entrypoint added; labeling.yml updated to invoke it.
Template enforcement status:needs-more-info handling
.github/workflows/template-enforcement.yml
On template pass: removes status:needs-more-info if present. On fail: strips other status:* labels, applies status:needs-more-info, updates messaging to drop auto-close wording, and calls core.setFailed instead of closing the issue.
Tests for new and refactored scripts
scripts/agents/includes/__tests__/derive-project-fields.test.js, scripts/agents/includes/__tests__/issue-pr-metadata.test.js, scripts/agents/__tests__/labeling.agent.test.js, scripts/agents/__tests__/project-meta-sync.agent.test.js
Adds kickoff-date tests for deriveProjectFieldValues; 277-line suite for all issue-pr-metadata.cjs helpers and two async syncItemMetadata integration flows; labeling agent tests converted from file-existence to behaviour assertions; project-meta-sync tests updated for the deprecation shim contract.
Docs, agent specs, and instructions alignment
docs/AUTOMATION.md, docs/GITHUB_PROJECT_OPERATIONS_SPEC.md, docs/ISSUE_CREATION_GUIDE.md, docs/WORKFLOW_COORDINATION.md, docs/PR_CREATION_PROCESS.md, agents/agent.md, agents/project-meta-sync.agent.md, instructions/automation.instructions.md, instructions/project-meta-sync.instructions.md
All documentation updated to reflect the new workflow split, kickoff-aware date rules, label taxonomy changes, and agent deprecations.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Event (issues / pull_request_target)
    participant WF as metadata-governance.yml
    participant script as issue-pr-metadata.cjs
    participant REST as GitHub REST API
    participant GQL as GitHub GraphQL API
    participant OUT as GITHUB_OUTPUT / STEP_SUMMARY

    GH->>WF: trigger (opened / labeled / edited / …)
    WF->>script: node scripts/agents/includes/issue-pr-metadata.cjs
    script->>script: getItemFromEvent → parseRelationshipHints
    script->>REST: assignIssue (candidate usernames)
    script->>REST: listMilestones / createMilestone
    script->>REST: updateMilestone on item
    script->>GQL: addSubIssueRelationship (issues only)
    script->>REST: upsertComment (marker-based governance comment)
    script->>OUT: write assignee, milestone, linkedRefs, …
    WF->>OUT: append Metadata governance report to STEP_SUMMARY
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

lang:yaml, meta:needs-changelog, type:maintenance

Suggested reviewers

  • krugazul
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: tightening metadata governance for issues and PRs through automation and improved field synchronisation.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering the new metadata governance, split project field sync, and documentation updates.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/metadata-governance-automation

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 and usage tips.

@ashleyshaw ashleyshaw force-pushed the chore/metadata-governance-automation branch from d66acb7 to 5e0e9df Compare June 18, 2026 11:37
@github-actions github-actions Bot added status:needs-review Awaiting code review type:chore Chore / small hygiene change priority:normal Default priority area:ci Build and CI pipelines area:labels Label governance and routing area:documentation Docs & guides area:tests Test suites & harnesses area:scripts Scripts & tooling lang:js JavaScript/TypeScript lang:md Markdown content/docs type:bug Bug or defect meta:needs-changelog Requires a changelog entry before merge labels Jun 18, 2026
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

🔍 Reviewer Summary for PR #974

CI Status:success
Files changed: 36
Risk Distribution: 5 critical, 4 high, 5 medium, 22 low

Recommendations

  • ⚠️ 5 critical-risk file(s) modified (workflows, secrets)
  • ⚠️ Security-sensitive files modified (review carefully)
  • ⚠️ Large deletion detected (>500 lines removed)

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request deprecates the legacy project-meta-sync.agent.js script in favor of a new metadata governance model driven by metadata-governance.yml and project-meta-sync.yml workflows, supported by helper scripts issue-pr-metadata.cjs and derive-project-fields.cjs. It also updates extensive documentation, refactors label priorities and types, and adds robust unit tests. Feedback on the new implementation suggests improving robustness by handling missing event payloads in getItemFromEvent, combining sequential GraphQL queries to reduce network roundtrips, relaxing the bot-user check when identifying existing comments, and wrapping milestone operations in a try-catch block to prevent workflow failures.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +42 to +68
function getItemFromEvent(event) {
if (event.pull_request) {
return {
kind: "pull_request",
number: event.pull_request.number,
nodeId: event.pull_request.node_id,
title: event.pull_request.title || "",
body: event.pull_request.body || "",
labels: Array.isArray(event.pull_request.labels)
? event.pull_request.labels
: [],
milestone: event.pull_request.milestone || null,
author: event.pull_request.user?.login || "",
};
}

return {
kind: "issue",
number: event.issue.number,
nodeId: event.issue.node_id,
title: event.issue.title || "",
body: event.issue.body || "",
labels: Array.isArray(event.issue.labels) ? event.issue.labels : [],
milestone: event.issue.milestone || null,
author: event.issue.user?.login || "",
};
}

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.

medium

If the workflow is triggered by an event other than issues or pull_request_target (for example, during manual dispatch or push events), both event.pull_request and event.issue will be undefined. Accessing event.issue.number directly in the fallback block will throw a TypeError. Adding an explicit check for event.issue and throwing a descriptive error makes the code more robust and easier to debug.

function getItemFromEvent(event) {
  if (event.pull_request) {
    return {
      kind: "pull_request",
      number: event.pull_request.number,
      nodeId: event.pull_request.node_id,
      title: event.pull_request.title || "",
      body: event.pull_request.body || "",
      labels: Array.isArray(event.pull_request.labels)
        ? event.pull_request.labels
        : [],
      milestone: event.pull_request.milestone || null,
      author: event.pull_request.user?.login || "",
    };
  }

  if (event.issue) {
    return {
      kind: "issue",
      number: event.issue.number,
      nodeId: event.issue.node_id,
      title: event.issue.title || "",
      body: event.issue.body || "",
      labels: Array.isArray(event.issue.labels) ? event.issue.labels : [],
      milestone: event.issue.milestone || null,
      author: event.issue.user?.login || "",
    };
  }

  throw new Error("Event payload does not contain a pull_request or issue");
}

Comment on lines +273 to +302
async function addSubIssueRelationship(github, owner, repo, parentNumber, childNumber) {
const parent = await github.graphql(
`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $number) {
id
}
}
}
`,
{ owner, repo, number: parentNumber },
);

const child = await github.graphql(
`
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $number) {
id
}
}
}
`,
{ owner, repo, number: childNumber },
);

const parentId = parent?.repository?.issue?.id;
const childId = child?.repository?.issue?.id;
if (!parentId || !childId) return false;

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.

medium

The sequential GraphQL queries to fetch the parent and child issue IDs can be combined into a single GraphQL query. This reduces the number of network roundtrips to the GitHub API from two to one, improving the efficiency of the metadata sync process.

async function addSubIssueRelationship(github, owner, repo, parentNumber, childNumber) {
  const response = await github.graphql(
    `
      query($owner: String!, $repo: String!, $parentNumber: Int!, $childNumber: Int!) {
        repository(owner: $owner, name: $repo) {
          parent: issue(number: $parentNumber) {
            id
          }
          child: issue(number: $childNumber) {
            id
          }
        }
      }
    `,
    { owner, repo, parentNumber, childNumber },
  );

  const parentId = response?.repository?.parent?.id;
  const childId = response?.repository?.child?.id;
  if (!parentId || !childId) return false;

Comment on lines +328 to +330
const existing = comments.find(
(comment) => comment.user?.type === "Bot" && comment.body?.includes(COMMENT_MARKER),
);

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.

medium

Relying on comment.user?.type === "Bot" to identify the existing comment can be fragile. If the workflow is executed using a Personal Access Token (PAT) or a custom GitHub App, the comment author's type might be "User" or another value instead of "Bot". Since the COMMENT_MARKER (<!-- metadata-governance -->) is highly unique, it is safer and more robust to find the comment solely by checking if the body includes the marker.

  const existing = comments.find(
    (comment) => comment.body?.includes(COMMENT_MARKER),
  );

Comment on lines +363 to +378
let milestoneSummary = item.milestone?.title || "";
if (!milestoneSummary) {
const linkedMilestone =
item.kind === "pull_request"
? await resolveLinkedIssueMilestone(
github,
owner,
repo,
[...new Set([...hints.linkedRefs, ...extractIssueRefs(item.body)])],
)
: null;
const milestoneTitle = linkedMilestone?.title || deriveMilestoneTitle(item.title);
const milestone = linkedMilestone || (await ensureMilestone(github, owner, repo, milestoneTitle));
await updateIssueMilestone(github, owner, repo, item.number, milestone.number);
milestoneSummary = milestone.title;
}

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.

medium

If any of the milestone API calls (such as ensureMilestone or updateIssueMilestone) fail due to secondary rate limits, validation errors, or permission issues, the entire metadata governance workflow will crash. Wrapping this block in a try-catch block ensures that milestone assignment failures are handled gracefully and logged, matching the robust error-handling strategy used for other optional metadata operations in this file (like assignees and sub-issue relationships).

  let milestoneSummary = item.milestone?.title || "";
  if (!milestoneSummary) {
    try {
      const linkedMilestone =
        item.kind === "pull_request"
          ? await resolveLinkedIssueMilestone(
              github,
              owner,
              repo,
              [...new Set([...hints.linkedRefs, ...extractIssueRefs(item.body)])],
            )
          : null;
      const milestoneTitle = linkedMilestone?.title || deriveMilestoneTitle(item.title);
      const milestone = linkedMilestone || (await ensureMilestone(github, owner, repo, milestoneTitle));
      if (milestone?.number) {
        await updateIssueMilestone(github, owner, repo, item.number, milestone.number);
        milestoneSummary = milestone.title;
      }
    } catch (error) {
      console.info(`Milestone governance failed for #${item.number}: ${error.message}`);
    }
  }

@github-actions github-actions Bot added type:chore Chore / small hygiene change and removed type:chore Chore / small hygiene change labels Jun 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

- run: node ../scripts/agents/labeling.agent.js

P2 Badge Keep the documented labelling entrypoint runnable

This canonical workflow snippet still tells users to run node ../scripts/agents/labeling.agent.js, but this change removed the direct-run guard from labeling.agent.js and moved execution to run-labeling-agent.cjs. In environments with dependencies installed, following this instruction now imports the module and exits without running runLabelingAgent, so manual or dry-run labelling checks silently do nothing; update the command to the wrapper or preserve the direct entrypoint.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

function extractIssueRefs(text) {
const refs = new Set();
const source = String(text || "");
const matches = source.matchAll(/#(\d+)/g);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Ignore non-local qualified issue references

When a body contains a qualified GitHub shorthand reference such as other-repo#123, this regex still extracts 123, and downstream milestone inheritance or sub-issue creation treats it as an issue in the current repository. That can copy metadata from, comment about, or create relationships to the wrong local issue whenever contributors link cross-repository work; parse the owner/repo and ignore non-local refs, or only accept unqualified local #123 references.

Useful? React with 👍 / 👎.

@github-actions github-actions Bot removed the type:chore Chore / small hygiene change label Jun 18, 2026
@ashleyshaw ashleyshaw added meta:no-changelog No changelog needed type:chore Chore / small hygiene change and removed meta:needs-changelog Requires a changelog entry before merge type:bug Bug or defect labels Jun 18, 2026
@coderabbitai coderabbitai Bot requested a review from krugazul June 18, 2026 11:50
@coderabbitai coderabbitai Bot added lang:yaml YAML config meta:needs-changelog Requires a changelog entry before merge type:maintenance Maintenance labels Jun 18, 2026
@github-actions github-actions Bot removed the type:chore Chore / small hygiene change label Jun 18, 2026
@ashleyshaw ashleyshaw removed the meta:no-changelog No changelog needed label Jun 18, 2026
@github-actions github-actions Bot added the type:chore Chore / small hygiene change label Jun 18, 2026
coderabbitai[bot]
coderabbitai Bot previously requested changes Jun 18, 2026

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

Actionable comments posted: 7

🧹 Nitpick comments (5)
scripts/agents/includes/issue-pr-metadata.cjs (1)

273-318: ⚡ Quick win

Consider consolidating the two GraphQL queries into one to halve API calls.

The addSubIssueRelationship function makes two separate GraphQL queries to fetch the parent and child issue IDs, then a third for the mutation. You could fetch both in a single query, which would be kinder to the rate limits and a tad snappier!

♻️ Proposed single-query approach
 async function addSubIssueRelationship(github, owner, repo, parentNumber, childNumber) {
-  const parent = await github.graphql(
+  const result = await github.graphql(
     `
-      query($owner: String!, $repo: String!, $number: Int!) {
+      query($owner: String!, $repo: String!, $parentNumber: Int!, $childNumber: Int!) {
         repository(owner: $owner, name: $repo) {
-          issue(number: $number) {
+          parent: issue(number: $parentNumber) {
             id
           }
+          child: issue(number: $childNumber) {
+            id
+          }
         }
       }
     `,
-    { owner, repo, number: parentNumber },
+    { owner, repo, parentNumber, childNumber },
   );

-  const child = await github.graphql(
-    `
-      query($owner: String!, $repo: String!, $number: Int!) {
-        repository(owner: $owner, name: $repo) {
-          issue(number: $number) {
-            id
-          }
-        }
-      }
-    `,
-    { owner, repo, number: childNumber },
-  );
-
-  const parentId = parent?.repository?.issue?.id;
-  const childId = child?.repository?.issue?.id;
+  const parentId = result?.repository?.parent?.id;
+  const childId = result?.repository?.child?.id;
   if (!parentId || !childId) return false;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/agents/includes/issue-pr-metadata.cjs` around lines 273 - 318, The
addSubIssueRelationship function currently makes two separate GraphQL queries to
fetch the parent and child issue IDs sequentially. Consolidate these into a
single GraphQL query that fetches both issue IDs at once by modifying the query
structure to accept both parentNumber and childNumber as parameters and retrieve
both parent.repository.issue.id and child.repository.issue.id in the same query
call. This will reduce the total API calls from three to two, improving
efficiency and reducing rate limit consumption.
.github/workflows/metadata-governance.yml (1)

23-23: ⚖️ Poor tradeoff

Consider SHA-pinning actions for stronger supply-chain security.

The coding guidelines note that @v4 tags are acceptable, but SHA pins are better. For a workflow with write permissions, pinning to specific commit SHAs reduces the risk of a compromised upstream action.

This is optional but recommended for high-privilege workflows.

Also applies to: 26-26

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/metadata-governance.yml at line 23, Replace the version
tag reference in the actions/checkout action with a SHA pin for stronger
supply-chain security. Instead of using `actions/checkout@v4`, pin the action to
a specific commit SHA (e.g., `actions/checkout@<FULL_SHA>`). This should be done
at both occurrences mentioned in the comment to ensure consistent security
practices throughout the workflow, particularly since this workflow has write
permissions.

Source: Coding guidelines

scripts/agents/includes/derive-project-fields.cjs (1)

22-33: ⚡ Quick win

Quick safety net: default cfg to avoid a faceplant.

Line 31 dereferences cfg immediately. If this helper is called without cfg (or config load returns null), it throws before fallback logic can run.

Suggested tweak
 function deriveProjectFieldValues({
-  cfg,
+  cfg = {},
   labels = [],
   eventName = "",
   eventAction = "",
   prMerged = false,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/agents/includes/derive-project-fields.cjs` around lines 22 - 33, The
deriveProjectFieldValues function immediately dereferences cfg on line 31 when
accessing cfg.project_field_mappings without any null or undefined check. If cfg
is not provided or is null, this will throw an error before any fallback logic
can run. Add a default value for cfg in the destructuring assignment of the
deriveProjectFieldValues function parameters to ensure cfg has a safe fallback
value (such as an empty object) when it is not provided.
scripts/agents/includes/__tests__/derive-project-fields.test.js (1)

33-50: ⚡ Quick win

Add one more guardrail test for status:in-progress.

Nice coverage for the “not started” and “ready” states. Adding the second positive kickoff state (status:in-progress) would lock the full contract and prevent sneaky regressions.

Proposed test addition
   test("populates kickoff dates when the item is ready to start", () => {
@@
   });
+
+  test("populates kickoff dates when the item is already in progress", () => {
+    const result = deriveProjectFieldValues({
+      cfg: issueFieldsConfig,
+      labels: ["status:in-progress", "priority:important", "type:feature"],
+      eventName: "issues",
+      eventAction: "edited",
+      itemCreatedAt: "2026-06-18T10:15:00Z",
+      milestoneDueOn: "2026-07-18T00:00:00Z",
+    });
+
+    expect(result).toMatchObject({
+      status: "In Progress",
+      priority: "Important",
+      type: "Feature",
+      startDate: "2026-06-18",
+      targetDate: "2026-07-18",
+    });
+  });
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/agents/includes/__tests__/derive-project-fields.test.js` around lines
33 - 50, Add a new test case for the `status:in-progress` state to match the
existing test structure. Create a test that calls deriveProjectFieldValues with
the same configuration and fields as the current test ("populates kickoff dates
when the item is ready to start"), but replace the "status:ready" label with
"status:in-progress". Verify that the result properly populates the startDate
and targetDate fields to ensure the deriveProjectFieldValues function correctly
handles both the ready and in-progress states, preventing regressions in this
critical path.
scripts/agents/run-labeling-agent.cjs (1)

3-7: ⚡ Quick win

Add JSDoc on main() to keep JS docs/lint standards tidy.

A short JSDoc block here keeps the new entrypoint aligned with the repo’s JS documentation rules.

As per coding guidelines, "JavaScript and TypeScript files must follow linting standards defined in instructions/languages.instructions.md, including JSDoc documentation."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/agents/run-labeling-agent.cjs` around lines 3 - 7, The main()
function is missing JSDoc documentation which violates the repository's
JavaScript documentation standards. Add a JSDoc block above the main() function
definition that describes its purpose as the entrypoint for running the labeling
agent. The JSDoc should be brief and clearly explain what the function does,
using standard JSDoc syntax with description tags as appropriate.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/metadata-governance.yml:
- Around line 22-23: Add the persist-credentials parameter set to false in the
checkout action to enhance security. Locate the step with uses:
actions/checkout@v4 and add persist-credentials: false as a parameter under the
with section. This ensures that the GitHub token is not persisted for subsequent
steps, following security best practices when the workflow uses
pull_request_target with write permissions.

In @.github/workflows/project-meta-sync.yml:
- Line 136: The `titoportas/update-project-fields` action is pinned to a mutable
version tag (v0.1.0) which creates supply-chain risk. Replace the version tag
with the full commit SHA `421a54430b3cdc9eefd8f14f9ce0142ab7678751` for all
occurrences of the `titoportas/update-project-fields` action in the workflow
file to ensure only the specific, immutable commit is used.

In `@docs/ISSUE_FIELDS.md`:
- Around line 5-7: The frontmatter metadata at the top of the ISSUE_FIELDS.md
file has been updated with version v1.0.5, created_date 2026-05-31, and
last_updated 2026-06-18, but the visible "Version" and "Last Updated" fields
displayed within the document body still contain older values. Locate the
in-document "Version" and "Last Updated" fields (typically in a metadata or
header section within the visible content) and update them to match the
frontmatter values to maintain consistency across the documentation.

In `@docs/LABEL_COLOR_STRATEGY.md`:
- Around line 5-7: The frontmatter metadata in LABEL_COLOR_STRATEGY.md has been
updated to version v1.0.1 with created_date 2026-05-31 and last_updated
2026-06-18, but there is a visible metadata block elsewhere in the document that
still contains older version and date values. Locate the visible metadata block
in the document body and update its version and date fields to match the
frontmatter values (v1.0.1, created_date 2026-05-31, last_updated 2026-06-18) to
ensure consistency across the entire document.

In `@docs/LABELING.md`:
- Around line 5-6: The frontmatter metadata has been updated with version
'v1.0.2' and last_updated '2026-06-18', but the visible "Version" and "Last
Updated" sections elsewhere in the LABELING.md document still contain outdated
values. Find and update any "Version" or "Last Updated" section headers and
their corresponding values in the document body to match the frontmatter values
(v1.0.2 and 2026-06-18) to ensure consistency and prevent reader confusion.

In `@scripts/agents/includes/issue-pr-metadata.cjs`:
- Around line 58-68: The getItemFromEvent function lacks a defensive check to
validate that event.issue exists before attempting to access its properties
(number, node_id, title, body, etc.). If the event object lacks both
pull_request and issue properties, this code will throw a TypeError when trying
to access event.issue.number. Add a guard clause at the beginning of the
function or before the return statement that validates event.issue exists, and
either return a safe default value or throw a descriptive error if the required
event.issue data is missing.

In `@scripts/agents/run-labeling-agent.cjs`:
- Around line 3-7: The `main()` function is calling `runLabelingAgent()` without
passing any options, but the function expects an options object with a `dryRun`
property that should be populated from the `DRY_RUN` environment variable.
Modify the `main()` function to read the `DRY_RUN` environment variable and pass
it to `runLabelingAgent()` as an options object with the shape `{ dryRun:
<boolean-value> }`, ensuring the environment variable is properly converted to a
boolean since `runLabelingAgent()` expects `opts.dryRun` to determine the
workflow behavior.

---

Nitpick comments:
In @.github/workflows/metadata-governance.yml:
- Line 23: Replace the version tag reference in the actions/checkout action with
a SHA pin for stronger supply-chain security. Instead of using
`actions/checkout@v4`, pin the action to a specific commit SHA (e.g.,
`actions/checkout@<FULL_SHA>`). This should be done at both occurrences
mentioned in the comment to ensure consistent security practices throughout the
workflow, particularly since this workflow has write permissions.

In `@scripts/agents/includes/__tests__/derive-project-fields.test.js`:
- Around line 33-50: Add a new test case for the `status:in-progress` state to
match the existing test structure. Create a test that calls
deriveProjectFieldValues with the same configuration and fields as the current
test ("populates kickoff dates when the item is ready to start"), but replace
the "status:ready" label with "status:in-progress". Verify that the result
properly populates the startDate and targetDate fields to ensure the
deriveProjectFieldValues function correctly handles both the ready and
in-progress states, preventing regressions in this critical path.

In `@scripts/agents/includes/derive-project-fields.cjs`:
- Around line 22-33: The deriveProjectFieldValues function immediately
dereferences cfg on line 31 when accessing cfg.project_field_mappings without
any null or undefined check. If cfg is not provided or is null, this will throw
an error before any fallback logic can run. Add a default value for cfg in the
destructuring assignment of the deriveProjectFieldValues function parameters to
ensure cfg has a safe fallback value (such as an empty object) when it is not
provided.

In `@scripts/agents/includes/issue-pr-metadata.cjs`:
- Around line 273-318: The addSubIssueRelationship function currently makes two
separate GraphQL queries to fetch the parent and child issue IDs sequentially.
Consolidate these into a single GraphQL query that fetches both issue IDs at
once by modifying the query structure to accept both parentNumber and
childNumber as parameters and retrieve both parent.repository.issue.id and
child.repository.issue.id in the same query call. This will reduce the total API
calls from three to two, improving efficiency and reducing rate limit
consumption.

In `@scripts/agents/run-labeling-agent.cjs`:
- Around line 3-7: The main() function is missing JSDoc documentation which
violates the repository's JavaScript documentation standards. Add a JSDoc block
above the main() function definition that describes its purpose as the
entrypoint for running the labeling agent. The JSDoc should be brief and clearly
explain what the function does, using standard JSDoc syntax with description
tags as appropriate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Pro

Run ID: 1aeb1833-d4c3-4ad0-9957-4b0a1c4d417a

📥 Commits

Reviewing files that changed from the base of the PR and between 37c2327 and 71efd64.

📒 Files selected for processing (30)
  • .github/issue-fields.yml
  • .github/workflows/README.md
  • .github/workflows/labeling.yml
  • .github/workflows/metadata-governance.yml
  • .github/workflows/project-meta-sync.yml
  • .github/workflows/template-enforcement.yml
  • agents/agent.md
  • agents/project-meta-sync.agent.md
  • docs/AUTOMATION.md
  • docs/GITHUB_PROJECT_OPERATIONS_SPEC.md
  • docs/ISSUE_CREATION_GUIDE.md
  • docs/ISSUE_FIELDS.md
  • docs/LABELING.md
  • docs/LABEL_COLOR_STRATEGY.md
  • docs/PR_CREATION_PROCESS.md
  • docs/WORKFLOW_COORDINATION.md
  • docs/agents/PLANNER_RUNBOOK.md
  • instructions/automation.instructions.md
  • instructions/project-meta-sync.instructions.md
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/derive-project-fields.cjs
  • scripts/agents/includes/issue-pr-metadata.cjs
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/labeling.agent.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/run-labeling-agent.cjs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: coderabbit-gate
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{php,js,ts,jsx,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{php,js,ts,jsx,tsx}: Follow WordPress Coding Standards for PHP files, ESLint/Prettier for JS/TS files, and PHPCS/WPCS for PHP files.
Security: Validate all input, escape all output, use nonces, never commit secrets.

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/labeling.agent.js
**/*.{js,ts,jsx,tsx,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Performance: Avoid unnecessary JS, defer/lazy-load where possible, prefer native blocks.

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/labeling.agent.js
**/*.{php,js,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not enqueue editor-only WordPress assets on the front end (and vice versa).

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/labeling.agent.js
**/*.{php,js,css,html}

📄 CodeRabbit inference engine (AGENTS.md)

Follow WordPress Coding Standards (CSS, HTML, JavaScript, PHP) and inline-documentation standards at all times

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/labeling.agent.js
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

JavaScript and TypeScript files must follow linting standards defined in instructions/languages.instructions.md, including JSDoc documentation

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/labeling.agent.js
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

All test files must follow Jest testing standards and maintain minimum coverage thresholds as defined in instructions/quality-assurance.instructions.md

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
**/*.{js,ts}

⚙️ CodeRabbit configuration file

**/*.{js,ts}: Review JavaScript/TypeScript:

  • Ensure code is linted and follows project style guides.
  • Check for dead code, unused variables, and clear function naming.
  • Validate accessibility and performance optimisations.
  • Ensure tests are isolated and do not depend on external state.
  • Check for descriptive test names and clear test structure.

Files:

  • scripts/agents/includes/__tests__/derive-project-fields.test.js
  • scripts/agents/includes/__tests__/label-utils.test.js
  • scripts/agents/includes/label-heuristics.js
  • scripts/agents/__tests__/project-meta-sync.agent.test.js
  • scripts/agents/project-meta-sync.agent.js
  • scripts/agents/includes/__tests__/issue-pr-metadata.test.js
  • scripts/agents/__tests__/labeling.agent.test.js
  • scripts/agents/labeling.agent.js
**/*.{md,markdown,txt,instructions.md}

📄 CodeRabbit inference engine (CLAUDE.md)

Language: Use UK English throughout (optimise, organisation, colour, behaviour).

Files:

  • docs/agents/PLANNER_RUNBOOK.md
  • instructions/project-meta-sync.instructions.md
  • agents/project-meta-sync.agent.md
  • agents/agent.md
  • docs/LABELING.md
  • docs/LABEL_COLOR_STRATEGY.md
  • docs/GITHUB_PROJECT_OPERATIONS_SPEC.md
  • docs/ISSUE_FIELDS.md
  • docs/AUTOMATION.md
  • docs/PR_CREATION_PROCESS.md
  • docs/ISSUE_CREATION_GUIDE.md
  • docs/WORKFLOW_COORDINATION.md
  • instructions/automation.instructions.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

All documentation must follow Markdown formatting standards and include YAML frontmatter as specified in instructions/documentation-formats.instructions.md

Files:

  • docs/agents/PLANNER_RUNBOOK.md
  • instructions/project-meta-sync.instructions.md
  • agents/project-meta-sync.agent.md
  • agents/agent.md
  • docs/LABELING.md
  • docs/LABEL_COLOR_STRATEGY.md
  • docs/GITHUB_PROJECT_OPERATIONS_SPEC.md
  • docs/ISSUE_FIELDS.md
  • docs/AUTOMATION.md
  • docs/PR_CREATION_PROCESS.md
  • docs/ISSUE_CREATION_GUIDE.md
  • docs/WORKFLOW_COORDINATION.md
  • instructions/automation.instructions.md
**/docs/**/*.md

⚙️ CodeRabbit configuration file

**/docs/**/*.md: Review documentation files:

  • Ensure markdown is linted and formatted per project style guides.
  • Flag illogical folder structures, file naming, or misplaced content.
  • Confirm documentation is up to date, accurate, and cross-referenced.
  • Ensure accessibility (heading hierarchy, alt text for images, UK English).

Files:

  • docs/agents/PLANNER_RUNBOOK.md
  • docs/LABELING.md
  • docs/LABEL_COLOR_STRATEGY.md
  • docs/GITHUB_PROJECT_OPERATIONS_SPEC.md
  • docs/ISSUE_FIELDS.md
  • docs/AUTOMATION.md
  • docs/PR_CREATION_PROCESS.md
  • docs/ISSUE_CREATION_GUIDE.md
  • docs/WORKFLOW_COORDINATION.md
**/*.instructions.md

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.instructions.md: Do not create instruction files with a 'references' frontmatter field; use inline links or footer sections instead.
Instruction files must follow the pattern: frontmatter + role declaration + Overview + General Rules + Detailed Guidance + Examples + Validation + References.

Files:

  • instructions/project-meta-sync.instructions.md
  • instructions/automation.instructions.md
instructions/**

⚙️ CodeRabbit configuration file

instructions/**: Review portable instruction files:

  • Verify frontmatter follows the canonical pattern (file_type, version, last_updated, owners, tags, status, domain, stability).
  • Flag any references: frontmatter field — prohibited by CLAUDE.md.
  • Confirm the file has: Overview, General Rules, Detailed Guidance, Examples, Validation, and Cross-References sections.
  • Check that language is UK English throughout.

Files:

  • instructions/project-meta-sync.instructions.md
  • instructions/automation.instructions.md
**/.github/workflows/*.yml

⚙️ CodeRabbit configuration file

**/.github/workflows/*.yml: Review GitHub Actions workflows for this governance repo:

  • Security: check for least-privilege permissions (use permissions: at job level, default to read-only).
  • Secret handling: ensure secrets are passed via env vars, not interpolated directly into run: steps to prevent injection.
  • Action pinning: prefer SHA-pinned actions over mutable tags (e.g. actions/checkout@v4 is acceptable; SHA pins are better).
  • No pull_request_target with untrusted code execution unless explicitly justified.
  • Avoid storing sensitive outputs as unmasked step outputs.
  • Check for reusable workflow patterns and matrix strategies where appropriate.
  • Validate on: triggers: ensure branch/path filters are present to avoid unnecessary runs.
  • Confirm workflows are documented, DRY, and maintainable.
  • Ensure agent-triggered workflows use workflow_dispatch with defined inputs.

Files:

  • .github/workflows/labeling.yml
  • .github/workflows/metadata-governance.yml
  • .github/workflows/project-meta-sync.yml
  • .github/workflows/template-enforcement.yml
🪛 ESLint
scripts/agents/includes/__tests__/derive-project-fields.test.js

[error] 1-1: 'require' is not defined.

(no-undef)


[error] 2-2: 'require' is not defined.

(no-undef)


[error] 3-3: 'require' is not defined.

(no-undef)


[error] 4-4: 'require' is not defined.

(no-undef)

scripts/agents/__tests__/project-meta-sync.agent.test.js

[error] 5-5: 'require' is not defined.

(no-undef)

scripts/agents/run-labeling-agent.cjs

[error] 11-11: 'console' is not defined.

(no-undef)


[error] 12-12: 'console' is not defined.

(no-undef)


[error] 13-13: 'process' is not defined.

(no-undef)

scripts/agents/project-meta-sync.agent.js

[error] 32-32: 'require' is not defined.

(no-undef)


[error] 32-32: 'module' is not defined.

(no-undef)


[error] 39-39: 'module' is not defined.

(no-undef)


[error] 40-40: 'module' is not defined.

(no-undef)


[error] 41-41: 'module' is not defined.

(no-undef)

scripts/agents/includes/__tests__/issue-pr-metadata.test.js

[error] 8-8: 'require' is not defined.

(no-undef)

scripts/agents/includes/derive-project-fields.cjs

[error] 80-80: 'process' is not defined.

(no-undef)


[error] 81-81: 'process' is not defined.

(no-undef)


[error] 85-85: 'process' is not defined.

(no-undef)


[error] 93-93: 'process' is not defined.

(no-undef)


[error] 94-94: 'process' is not defined.

(no-undef)


[error] 95-95: 'process' is not defined.

(no-undef)


[error] 96-96: 'process' is not defined.

(no-undef)


[error] 97-97: 'process' is not defined.

(no-undef)


[error] 100-100: 'process' is not defined.

(no-undef)

scripts/agents/includes/issue-pr-metadata.cjs

[error] 235-235: 'console' is not defined.

(no-undef)


[error] 266-266: 'console' is not defined.

(no-undef)


[error] 394-394: 'console' is not defined.

(no-undef)


[error] 402-402: 'console' is not defined.

(no-undef)


[error] 421-421: 'process' is not defined.

(no-undef)


[error] 422-422: 'process' is not defined.

(no-undef)


[error] 423-423: 'process' is not defined.

(no-undef)


[error] 431-431: 'process' is not defined.

(no-undef)


[error] 432-432: 'process' is not defined.

(no-undef)


[error] 445-445: 'process' is not defined.

(no-undef)


[error] 447-447: 'process' is not defined.

(no-undef)


[error] 466-466: 'console' is not defined.

(no-undef)


[error] 467-467: 'process' is not defined.

(no-undef)

🪛 LanguageTool
docs/LABELING.md

[style] ~65-~65: Would you like to use the Oxford spelling “prioritized”? The spelling ‘prioritised’ is also correct.
Context: ...tant— High-impact work that should be prioritised soon -priority:normal` — Standard fea...

(OXFORD_SPELLING_Z_NOT_S)

docs/GITHUB_PROJECT_OPERATIONS_SPEC.md

[uncategorized] ~88-~88: Loose punctuation mark.
Context: ...nt Derivation source notes: - Status, Priority, and Type are mapped from ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~88-~88: The official name of this software platform is spelled with a capital “H”.
Context: ..., and Type are mapped from labels via .github/issue-fields.yml mappings. - Effort ...

(GITHUB)


[uncategorized] ~91-~91: The official name of this software platform is spelled with a capital “H”.
Context: ... relationships is handled separately by .github/workflows/metadata-governance.yml. Cu...

(GITHUB)


[grammar] ~101-~101: There seems to be a noun/verb agreement error. Did you mean “writes” or “wrote”?
Context: ...Y` Safe automation boundary: - Active write path is limited to the five core derive...

(SINGULAR_NOUN_VERB_AGREEMENT)

docs/ISSUE_FIELDS.md

[style] ~457-~457: Consider using a more formal alternative.
Context: ...ocked - On hold: status:on-hold - Needs more info: status:needs-more-info - Closed: statu...

(MORE_INFO)

docs/ISSUE_CREATION_GUIDE.md

[uncategorized] ~130-~130: Do not mix variants of the same word (‘labelled’ and ‘labeled’) within a single text.
Context: ... - Incomplete templates are flagged and labelled for correction rather than closed. - Me...

(EN_EXACT_COHERENCY_RULE)

docs/WORKFLOW_COORDINATION.md

[uncategorized] ~447-~447: The official name of this software platform is spelled with a capital “H”.
Context: ...eferences - [Next Issues Execution Plan](../.github/projects/active/next-issues-execution-p...

(GITHUB)

🪛 zizmor (1.25.2)
.github/workflows/metadata-governance.yml

[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 3-7: use of fundamentally insecure workflow trigger (dangerous-triggers): pull_request_target is almost always used insecurely

(dangerous-triggers)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 26-26: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

.github/workflows/project-meta-sync.yml

[error] 136-136: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🔇 Additional comments (46)
.github/issue-fields.yml (1)

29-29: LGTM!

scripts/agents/includes/label-heuristics.js (1)

34-37: LGTM!

docs/agents/PLANNER_RUNBOOK.md (1)

218-218: LGTM!

scripts/agents/includes/__tests__/label-utils.test.js (1)

56-57: LGTM!

Also applies to: 61-61, 333-334

.github/workflows/template-enforcement.yml (1)

59-71: LGTM!

Also applies to: 73-95, 113-151

scripts/agents/includes/issue-pr-metadata.cjs (12)

1-8: LGTM!

Also applies to: 471-484


13-19: LGTM!


21-40: LGTM!


70-88: LGTM!


90-150: LGTM!


152-193: LGTM!


195-271: LGTM!


351-418: LGTM!


420-443: LGTM!


464-469: LGTM!


320-349: Bot comment detection is correctly implemented using the standard GitHub API approach.

The filter comment.user?.type === "Bot" is the recommended way to identify bot comments in the GitHub API, and github-actions[bot] correctly returns user.type === "Bot". This approach is more robust than checking the login name for a [bot] suffix, as documented in GitHub's REST API guidance.


445-458: GitHub Actions output format cannot handle multi-line values in the current implementation.

The code joins output lines with \n and adds trailing newlines, which works perfectly for single-line values. However, GitHub Actions' standard key=value\n format is inherently newline-delimited and cannot safely handle values containing embedded newlines (e.g., milestone titles, assignee names, or linked reference descriptions with line breaks).

If any of these values might contain newlines, switch to the heredoc syntax with a unique delimiter to ensure reliable parsing:

if (process.env.GITHUB_OUTPUT) {
  const delimiter = `EOF_${Date.now()}`;
  fs.appendFileSync(
    process.env.GITHUB_OUTPUT,
    `metadata_assignee<<${delimiter}\n${result.assignee || ""}\n${delimiter}\n` +
    `metadata_milestone<<${delimiter}\n${result.milestone || ""}\n${delimiter}\n` +
    // ... repeat for other fields
  );
}

This approach guarantees correct parsing regardless of special characters or line breaks in the output values.

.github/workflows/metadata-governance.yml (4)

1-17: LGTM!


25-38: LGTM!


40-61: LGTM!


6-7: pull_request_target trigger requires developer verification of script safety.

The pull_request_target trigger runs with write permissions in the base branch context, which can be risky if untrusted code from the PR gets executed. This workflow appears to check out the base branch (default behaviour) and runs a script from the trusted codebase—not from the PR itself. However, I couldn't directly inspect the script to confirm it never dynamically requires or evaluates anything from the PR's source tree.

Please verify that scripts/agents/includes/issue-pr-metadata.cjs doesn't use require(), eval(), or similar patterns with paths or inputs controlled by the PR. If it only reads the event payload for metadata and makes API calls, the usage should be safe.

Bonus notes:

  • Consider setting persist-credentials: false in any checkout steps as a best practice with write permissions.
  • Action pinning to SHA is optional but would be a nice hardening step for future improvements.
.github/workflows/README.md (3)

5-5: LGTM!


48-48: LGTM!


84-88: LGTM!

docs/AUTOMATION.md (1)

75-78: Excellent alignment with the new metadata governance split!

The table correctly reflects the separation of concerns: metadata-governance.yml handles assignees/milestones/relationships, whilst project-meta-sync.yml syncs project fields. The new "Metadata Governance" section (lines 156–161) clearly articulates the automation contract, including the kickoff-aware date gating. Spot on!

docs/GITHUB_PROJECT_OPERATIONS_SPEC.md (1)

86-91: 💤 Low value

Tight kickoff-aware date-gating logic — perfectly aligned with the refactored derive-project-fields.cjs.

Lines 84–91 clearly articulate that Start date and Target date remain empty until an item reaches status:ready or status:in-progress. This mirrors the PR's refactored project-field derivation and prevents premature date population. Excellent contract clarity!

A minor note: the linting tool flagged a loose punctuation mark around line ~88 (likely a whitespace artifact before the bullet dash). If you spot errant spacing, a quick trim will keep the markup tidy.

docs/PR_CREATION_PROCESS.md (1)

130-140: Brilliant addition of the linked development requirement!

Line 139's requirement for linked development references (Closes #, Fixes #, Related to #) is spot on — it's essential for the new issue-pr-metadata.cjs script to capture and parse relationship hints correctly. Similarly, line 138 correctly notes that the PR author is auto-assigned unless a local rule overrides, which aligns perfectly with the new metadata-governance workflow. The label example update to type:documentation (line 131) is also consistent with the label taxonomy overhaul. Nice cohesion!

docs/WORKFLOW_COORDINATION.md (1)

51-52: Perfect placement of the new metadata workflows in the Always-Run registry!

Lines 51–52 correctly document metadata-governance.yml (issues/pull_request_target triggers) and project-meta-sync.yml (push/issues/pull_request triggers) as always-run, metadata-only workflows. This aligns beautifully with the PR's separation of concerns: metadata governance runs on issue/PR events, whilst project-meta-sync runs on code/issue/PR events to keep the project board in sync. The registry now clearly reflects the split that was implemented. Excellent clarity!

agents/agent.md (1)

3-4: Spot-on deprecation marking for the legacy project-meta-sync agent!

The version bump (v2.1 → v2.1.1) and updated description at line 62 clearly signal that project-meta-sync.agent.md is now a deprecated compatibility spec, not the active contract. This is exactly the right tone for guiding maintainers away from the old path and towards the new metadata-governance and derive-project-fields workflows. Crystal clear!

Also applies to: 62-62

agents/project-meta-sync.agent.md (1)

1-5: Exemplary deprecation guidance — crystal clear and unambiguous!

The updated description (lines 3–5) and guardrails (lines 70–71) leave zero room for misinterpretation: this spec is deprecated, compatibility-only, and the active automation lives in project-meta-sync.yml, metadata-governance.yml, and their helper scripts. This kind of explicit guardrailing prevents future confusion and guides maintainers straight to the current truth. Top-tier deprecation practice!

Also applies to: 70-71

instructions/automation.instructions.md (1)

284-284: Excellent alignment of priority taxonomy and script invocation!

Lines 284 and 548–551 correctly update the priority label examples and field mappings to reflect the new four-level taxonomy: critical, important, normal, minor. This is consistent with the label taxonomy overhaul across the PR.

More critically, line 570 updates the project sync script invocation from the deprecated project-meta-sync.agent.js to the refactored includes/derive-project-fields.cjs. This is the heart of the metadata governance split: derive-project-fields now handles the project-field syncing logic with kickoff-aware date gating, whilst metadata-governance handles the assignee/milestone/relationship metadata.

Top-notch alignment of documentation with the implementation refactor!

Also applies to: 548-551, 570-570

docs/ISSUE_CREATION_GUIDE.md (1)

102-132: No action needed—UK English is correctly applied in prose.

The file correctly uses British spelling ("labelled") in the documentation text. The American spellings present (labeling.yml, labeled/unlabeled events) are references to actual GitHub Actions workflow file names and API event types, which are fixed artefacts that cannot be changed for style consistency. Conflating code references with prose style is a category error. The documentation already complies with the UK English requirement for markdown files.

			> Likely an incorrect or invalid review comment.
instructions/project-meta-sync.instructions.md (2)

4-6: ⚡ Quick win

Verify apply_to targets align with the deprecation narrative.

The description states this is "deprecated compatibility guidance," yet .github/workflows/project-meta-sync.yml (line 22) remains in the apply_to list without being marked as removed. The AI summary claims it should be removed, but it's still present.

If project-meta-sync.yml is truly deprecated, should it be:

  • Removed from apply_to entirely, or
  • Kept as a target because the instruction still governs its legacy contract?

Please clarify the intent — either way, the apply_to list should be consistent with the deprecation narrative once the file body is added.

Also applies to: 23-25


1-26: Confirm whether instruction file body sections are present beyond the frontmatter.

The frontmatter is properly structured with all required metadata fields, and no prohibited references field is present. However, the code snippet shows only the frontmatter ending at line 26. Per coding guidelines, instruction files must follow this structure:

frontmatter + role declaration + Overview + General Rules + Detailed Guidance + Examples + Validation + References

If the body sections (Overview, General Rules, Detailed Guidance, Examples, Validation, and References) are truly missing or incomplete, this constitutes a structural violation of the required instruction file format. Given that the file is marked as deprecated guidance, the Overview section should at minimum redirect readers to the active project-meta-sync and metadata-governance workflows.

scripts/agents/includes/derive-project-fields.cjs (1)

79-100: ESLint configuration for process global in CommonJS scripts needs verification.

This file uses process globally (lines 80–100), which may trigger ESLint's no-undef rule if Node globals aren't declared. Please verify your project's ESLint setup:

  • Check whether .cjs files or scripts/** have an environment override that declares Node globals
  • If not already configured, add /* eslint-env node */ as a file header or configure an ESLint override for CommonJS scripts
scripts/agents/includes/__tests__/issue-pr-metadata.test.js (2)

8-8: Same lint/env snag here at Line 8 (require).


10-277: LGTM!

scripts/agents/__tests__/project-meta-sync.agent.test.js (2)

5-5: Duplicate of the require lint/env issue (Line 5).


7-27: LGTM!

scripts/agents/__tests__/labeling.agent.test.js (1)

1-78: LGTM!

scripts/agents/includes/__tests__/derive-project-fields.test.js (1)

1-4: ESLint gets twitchy with CommonJS require statements in this Jest test file.

When using CommonJS require() in Jest tests without explicit ESLint configuration, the no-undef linter will rightfully complain about require, module, and Jest globals not being defined. The fix is straightforward—add an ESLint environment directive at the top of the file to inform the linter that Node and Jest globals are available:

Quick fix for this file
+/* eslint-env node, jest */
 const fs = require("fs");
 const path = require("path");
 const yaml = require("js-yaml");
 const { deriveProjectFieldValues } = require("../derive-project-fields.cjs");

Alternatively, ensure your project's ESLint configuration properly defines the Node and Jest environments via .eslintrc or eslint.config.js to avoid duplicating this comment across all test files.

Per the coding guidelines, JavaScript files must follow linting standards—this blocks the pipeline unless addressed.

scripts/agents/project-meta-sync.agent.js (2)

3-30: LGTM!


32-41: A sneaky module-format gremlin: CJS globals in this .js shim can break execution.

Lines 32 and 39–41 use require/module.exports, while static analysis already flags no-undef here. If this file is treated as ESM (as in sibling agent .js files), the shim can fail before returning the deprecation descriptor.

scripts/agents/labeling.agent.js (1)

23-24: LGTM!

.github/workflows/labeling.yml (1)

93-93: LGTM!

scripts/agents/run-labeling-agent.cjs (1)

11-13: Ensure ESLint configuration applies Node globals to .cjs files.

Static analysis is flagging console and process as undefined on these lines. Verify that your ESLint config properly handles .cjs files with Node environment settings—otherwise, this shiny new entrypoint might hit lint gate troubles.

Comment thread .github/workflows/metadata-governance.yml
Comment thread .github/workflows/project-meta-sync.yml
Comment thread docs/ISSUE_FIELDS.md
Comment thread docs/LABEL_COLOR_STRATEGY.md Outdated
Comment thread docs/LABELING.md
Comment on lines +58 to +68
return {
kind: "issue",
number: event.issue.number,
nodeId: event.issue.node_id,
title: event.issue.title || "",
body: event.issue.body || "",
labels: Array.isArray(event.issue.labels) ? event.issue.labels : [],
milestone: event.issue.milestone || null,
author: event.issue.user?.login || "",
};
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Potential crash when neither pull_request nor issue exists in event.

If getItemFromEvent is called with an event that lacks both pull_request and issue (e.g., a malformed or unexpected event type), this will throw a TypeError when accessing event.issue.number.

A defensive check would make this more resilient:

🛡️ Proposed defensive guard
   }

+  if (!event.issue) {
+    throw new Error("Event payload contains neither pull_request nor issue");
+  }
+
   return {
     kind: "issue",
     number: event.issue.number,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return {
kind: "issue",
number: event.issue.number,
nodeId: event.issue.node_id,
title: event.issue.title || "",
body: event.issue.body || "",
labels: Array.isArray(event.issue.labels) ? event.issue.labels : [],
milestone: event.issue.milestone || null,
author: event.issue.user?.login || "",
};
}
if (!event.issue) {
throw new Error("Event payload contains neither pull_request nor issue");
}
return {
kind: "issue",
number: event.issue.number,
nodeId: event.issue.node_id,
title: event.issue.title || "",
body: event.issue.body || "",
labels: Array.isArray(event.issue.labels) ? event.issue.labels : [],
milestone: event.issue.milestone || null,
author: event.issue.user?.login || "",
};
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/agents/includes/issue-pr-metadata.cjs` around lines 58 - 68, The
getItemFromEvent function lacks a defensive check to validate that event.issue
exists before attempting to access its properties (number, node_id, title, body,
etc.). If the event object lacks both pull_request and issue properties, this
code will throw a TypeError when trying to access event.issue.number. Add a
guard clause at the beginning of the function or before the return statement
that validates event.issue exists, and either return a safe default value or
throw a descriptive error if the required event.issue data is missing.

Comment thread scripts/agents/run-labeling-agent.cjs
@ashleyshaw ashleyshaw removed the request for review from krugazul June 18, 2026 12:27
@ashleyshaw ashleyshaw enabled auto-merge (squash) June 18, 2026 12:28
@github-actions github-actions Bot added type:chore Chore / small hygiene change and removed type:chore Chore / small hygiene change labels Jun 18, 2026
@ashleyshaw

Copy link
Copy Markdown
Member Author

@Mergifyio queue

@mergify

mergify Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • 🟠 Waiting for queue conditions
  • ⏳ Enter queue
  • ⏳ Run checks
  • ⏳ Merge
Waiting for
  • -closed [📌 queue requirement]
  • any of: [🔀 queue conditions]
    • all of: [📌 queue conditions of queue rule Merge queue]
      • any of: [🛡 GitHub branch protection]
        • check-neutral = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-skipped = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-success = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
      • any of: [🛡 GitHub branch protection]
        • check-neutral = Validate PR Template / validate-pr-template
        • check-skipped = Validate PR Template / validate-pr-template
        • check-success = Validate PR Template / validate-pr-template
    • all of: [📌 queue conditions of queue rule dependabot]
      • label=area:dependencies
      • any of: [🛡 GitHub branch protection]
        • check-neutral = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-skipped = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-success = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
      • any of: [🛡 GitHub branch protection]
        • check-neutral = Validate PR Template / validate-pr-template
        • check-skipped = Validate PR Template / validate-pr-template
        • check-success = Validate PR Template / validate-pr-template
All conditions
  • -closed [📌 queue requirement]
  • any of [🔀 queue conditions]:
    • all of [📌 queue conditions of queue rule Merge queue]:
      • any of [🛡 GitHub branch protection]:
        • check-neutral = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-skipped = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-success = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
      • any of [🛡 GitHub branch protection]:
        • check-neutral = Validate PR Template / validate-pr-template
        • check-skipped = Validate PR Template / validate-pr-template
        • check-success = Validate PR Template / validate-pr-template
    • all of [📌 queue conditions of queue rule dependabot]:
      • author~=^(dependabot\[bot\]|app/dependabot)$
      • label=area:dependencies
      • any of [🛡 GitHub branch protection]:
        • check-neutral = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-skipped = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
        • check-success = CI • Unified Checks (Lint, Test, Validate) / All Checks Passed
      • any of [🛡 GitHub branch protection]:
        • check-neutral = Validate PR Template / validate-pr-template
        • check-skipped = Validate PR Template / validate-pr-template
        • check-success = Validate PR Template / validate-pr-template
      • -conflict
      • -draft
      • base=develop
  • -conflict [📌 queue requirement]
  • -draft [📌 queue requirement]
  • any of [📌 queue -> configuration change requirements]:
    • -mergify-configuration-changed
    • check-success = Configuration changed
  • any of [📌 queue requirement]:
    • check-neutral = Mergify Merge Protections
    • check-skipped = Mergify Merge Protections
    • check-success = Mergify Merge Protections

@ashleyshaw

Copy link
Copy Markdown
Member Author

@Mergifyio queue

@mergify

mergify Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

queue

☑️ Command queue ignored because it is already running from a previous command.

@ashleyshaw ashleyshaw self-assigned this Jun 18, 2026
@ashleyshaw ashleyshaw requested a review from krugazul June 18, 2026 13:48
@ashleyshaw ashleyshaw force-pushed the chore/metadata-governance-automation branch from 2d20ab6 to c5a37c7 Compare June 18, 2026 14:36
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

🎨 Mermaid Diagram Validation

✅ All Mermaid diagram checks passed.

Check Result
✅ Syntax (diagram type, direction, bracket matching) Passed
✅ Accessibility (accTitle / accDescr present) Passed
✅ Colour contrast (WCAG 2.2 AA ≥ 4.5:1) Passed

@github-actions github-actions Bot removed the type:chore Chore / small hygiene change label Jun 18, 2026
@ashleyshaw ashleyshaw dismissed coderabbitai[bot]’s stale review June 18, 2026 14:43

Superseded by follow-up commits and passing validation on the current head.

@ashleyshaw ashleyshaw merged commit ec159b9 into develop Jun 18, 2026
28 checks passed
@ashleyshaw ashleyshaw deleted the chore/metadata-governance-automation branch June 18, 2026 14:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ci Build and CI pipelines area:documentation Docs & guides area:labels Label governance and routing area:scripts Scripts & tooling area:tests Test suites & harnesses lang:js JavaScript/TypeScript lang:md Markdown content/docs lang:yaml YAML config meta:needs-changelog Requires a changelog entry before merge priority:normal Default priority status:needs-review Awaiting code review type:maintenance Maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants