From a09bbe8db220e52236cfd86400e95b6ec7ca81aa Mon Sep 17 00:00:00 2001 From: "Roger D. Winans" Date: Tue, 18 Aug 2026 23:40:56 +0000 Subject: [PATCH 1/7] Fix HA and cluster signing key rotation steps (#62828) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../rotating-the-signing-key-for-upgrade-packages.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/admin/upgrading-your-instance/troubleshooting-upgrades/rotating-the-signing-key-for-upgrade-packages.md b/content/admin/upgrading-your-instance/troubleshooting-upgrades/rotating-the-signing-key-for-upgrade-packages.md index b20f0125bb70..1e7afe658bdf 100644 --- a/content/admin/upgrading-your-instance/troubleshooting-upgrades/rotating-the-signing-key-for-upgrade-packages.md +++ b/content/admin/upgrading-your-instance/troubleshooting-upgrades/rotating-the-signing-key-for-upgrade-packages.md @@ -58,13 +58,13 @@ For help determining the correct upgrade path, use the [{% data variables.enterp For instances configured with high availability or clustering, the key must be rotated on every node. 1. Connect to any node in your HA or cluster installation via SSH. -1. Download the rotation script provided by {% data variables.product.company_short %}. +1. Download the rotation script provided by {% data variables.product.company_short %} on every node. ```shell - curl -fsSL https://enterprise.github.com/security/2026-05-24/rotate-gpg.sh -o rotate-gpg.sh + ghe-cluster-each -- "curl -fsSL https://enterprise.github.com/security/2026-05-24/rotate-gpg.sh -o rotate-gpg.sh" ``` -1. Run the following commands. The `ghe-cluster-each` command copies the script to all nodes and runs it on all nodes. +1. Run the script twice on every node, once as the `admin` user and once with `sudo`. ```shell ghe-cluster-each -- chmod ug+x ./rotate-gpg.sh From 30d7b8d1d779586ccb4d5093639f4933ddfc94ab Mon Sep 17 00:00:00 2001 From: docs-bot <77750099+docs-bot@users.noreply.github.com> Date: Wed, 19 Aug 2026 08:59:49 +0000 Subject: [PATCH 2/7] docs: update copilot-cli content from source docs (#62788) Co-authored-by: github-actions[bot] Co-authored-by: hubwriter --- .../copilot-cli-reference/cli-command-reference.md | 6 ++++++ .../copilot-cli-reference/cli-config-dir-reference.md | 8 ++++++-- src/content-pipelines/state/copilot-cli.sha | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md index dee5df4b0e47..ab93bbdbb90c 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md @@ -394,6 +394,8 @@ These are the slash commands you can use from within an interactive CLI session. For a complete list of available slash commands enter `/help` in the CLI's interactive interface. +In the schedule manager opened by a bare `/every` or `/after`, use / to select an entry and `x` to remove it. Schedules can only be added from the prompt input using `/every` or `/after` with arguments—the dialog itself is read-and-remove only. + ## Command-line options | Option | Purpose | @@ -518,6 +520,7 @@ Use `--model=MODEL` or the `COPILOT_MODEL` environment variable to select the AI | `gemini-3.1-pro-preview` | Google Gemini reasoning | | `gemini-3.5-flash` | Fast Google Gemini responses | | `gemini-3.6-flash` | Fast Google Gemini responses | +| `gemini-3.7-flash` | Fast Google Gemini responses | | `mai-code-1-flash` | Fast, adaptive coding tasks | You can also switch models during an interactive session using the `/model` slash command. @@ -1031,8 +1034,11 @@ Custom agents are specialized AI agents defined in Markdown files. The filename | `mcp-servers` | object | No | MCP servers to connect. Uses the same schema as `~/.copilot/mcp-config.json`. | | `model` | string | No | AI model for this agent. When unset, inherits the outer agent's model. When the session model is set to `Auto` (server-selected), subagents always inherit the resolved session model regardless of this field. | | `name` | string | No | Display name. Defaults to the filename. | +| `reasoningEffort` | string | No | Default reasoning effort for this agent (for example, `"low"`, `"medium"`, or `"high"`). When unset, inherits the outer agent's effort. | | `tools` | string[] | No | Tools available to the agent. Default: `["*"]` (all tools). | +`model` and `reasoningEffort` apply whether the agent is dispatched through the `task` tool or started directly—for example, through the SDK's `session.startSubagent`. They're resolved with this precedence, highest first: an explicit per-call value, the `subagents` override in `~/.copilot/settings.json`, the agent definition's `model`/`reasoningEffort` field, then the parent session's value. A declared model or effort that can't be honored falls back to the session's value instead of failing the dispatch. + ### Custom agent locations | Scope | Location | diff --git a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md index 8714c9018582..ed3a659d264e 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md @@ -497,7 +497,7 @@ These settings apply across all your sessions and repositories. You can use the | `showTimestamps` | `boolean` | `true` | Show dim `HH:mm` timestamps next to user messages in the timeline. | | `showTipsOnStartup` | `boolean` | `true` | Show a random command tip when the CLI starts. | | `skillDirectories` | `string[]` | `[]` | Additional directories to search for custom skill definitions (in addition to `~/.copilot/skills/`). | -| `statusLine` | `object` | — | Custom status line display. `type`: must be `"command"`. `command`: path to an executable script that receives session JSON on stdin and prints status content to stdout. `padding`: optional number of left-padding spaces. `refreshInterval`: optional integer number of seconds (`1`–`2147483`) to re-run the command on a timer instead of only on events; omit it to refresh only when the session state changes. | +| `statusLine` | `object` | — | Custom status line display. `type`: must be `"command"`. `command`: path to an executable script that receives session JSON on stdin and prints status content to stdout. `padding`: optional number of left-padding spaces. `refreshInterval`: optional integer number of seconds (`1`–`2147483`) to re-run the command on a timer instead of only on events; omit it to refresh only when the session state changes. If the command fails to spawn, exits non-zero, or fails to receive the status JSON on stdin, the CLI logs a warning once per continuous failure episode and leaves the status line blank instead of failing silently. Run with `--log-level all` to see the underlying error detail. | | `stayInAutopilot` | `boolean` | `true` | Remain in autopilot mode after each task completes. When enabled, the next prompt you enter after a task completes is also handled in autopilot mode. For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/autopilot#staying-in-autopilot-mode-between-tasks). | | `storeTokenPlaintext` | `boolean` | `false` | Allow authentication tokens to be stored in plain text in `config.json` when no system keychain is available. | | `stream` | `boolean` | `true` | Enable streaming responses. | @@ -518,7 +518,7 @@ These settings apply across all your sessions and repositories. You can use the > [!TIP] > Run `copilot help sandbox` for the full sandbox reference, including supported hosts and all `sandbox` settings keys. -The `/sandbox` dialog groups `git`, `gh`, and keychain access under a dedicated **Auth** tab, and shows the `settings.json` path where the current sandbox configuration is stored. +The `/sandbox` dialog groups `git`, `gh`, and keychain access under a dedicated **Auth** tab, and shows the `settings.json` path where the current sandbox configuration is stored. Press Ctrl+E in the `/sandbox` dialog to save any pending changes and open `settings.json` in your editor (`COPILOT_EDITOR`, `VISUAL`, or `EDITOR`), matching the same shortcut in `/settings`. The dialog reloads its state from disk after you edit and save the file. Sandboxing is powered by [Microsoft eXecution Container (MXC)](https://github.com/microsoft/mxc), which provides platform-specific containment backends. {% data variables.copilot.copilot_cli_short %} uses Seatbelt on macOS, Bubblewrap on Linux, and ProcessContainer on Windows. @@ -636,11 +636,15 @@ Only the following keys are supported in MDM managed settings. | `forceRemoteSettingsRefresh` | Require a fresh server-managed settings fetch on startup, even when a fresh cached policy exists. The cached entry is still kept as a fallback if the fetch fails. The device (MDM) value takes precedence over a cached server value. | | `model` | Set a default model for all users (overridden by the `--model` flag or a resumed-session model) | | `permissions` | Set managed permissions, including `disableBypassPermissionsMode` and `deny` / `ask` / `allow` rule arrays. See [Managed permission rules](#managed-permission-rules). | +| `policyHelper` | Register an executable that supplies the lowest-priority managed-settings layer. Fields: `path` (required), plus optional `args`, `timeoutMs`, and `refreshIntervalMs`. If both a device (MDM) and a server policy register a `policyHelper`, the device registration wins. | | `remoteControl` | Control whether sessions on this device can be controlled from other devices. `mode` is `"enabled"`, `"disabled"`, or `"requireSSO"` (requires `githubDotComOrganizations` when set). | | `shellShortcut` | Force-enable or force-disable the `$` interactive shell shortcut for all users. A managed value always overrides the user's own `shellShortcut` setting. | | `strictKnownMarketplaces` | Restrict plugins to known marketplaces | | `telemetry` | Push baseline OpenTelemetry export configuration: `enabled`, `endpoint`, `protocol`, `headers`, `resourceAttributes`, `captureContent`, `lockCaptureContent`, and `serviceName`. See [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-command-reference#opentelemetry-monitoring). | +> [!NOTE] +> `policyHelper.path` accepts an absolute path, a home-relative path (`~/...`), or a bare program name resolved from `PATH`. Other relative forms are rejected. The registration is accepted and validated, but the runtime doesn't yet invoke the helper—helper execution ships in a future release. + > [!NOTE] > When `remoteControl.mode` is `"requireSSO"`, list the allowed organizations in `remoteControl.githubDotComOrganizations`. The client must be SSO-authorized for at least one listed {% data variables.product.prodname_dotcom_the_website %} organization—it no longer needs to be authorized for all of them. diff --git a/src/content-pipelines/state/copilot-cli.sha b/src/content-pipelines/state/copilot-cli.sha index 6ddc44b56946..999727a34d99 100644 --- a/src/content-pipelines/state/copilot-cli.sha +++ b/src/content-pipelines/state/copilot-cli.sha @@ -1 +1 @@ -7c8e5884fd6d5e7651fcc9605e57adf9dd230174 +7903b3505243ce5ad4a9f40d5134107a081127b6 From 99794300e9f8b671a34d36b7bb3681bc85c46a10 Mon Sep 17 00:00:00 2001 From: Sophie <29382425+sophietheking@users.noreply.github.com> Date: Wed, 19 Aug 2026 09:52:49 +0000 Subject: [PATCH 3/7] Copilot impact dashboard adds a return on investment section (#62701) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../concepts/copilot-usage-metrics/copilot-metrics.md | 10 ++++++++++ .../administer-copilot/view-impact-dashboard.md | 11 ++++++++++- .../interpret-copilot-metrics.md | 10 ++++++++++ .../reconciling-usage-metrics.md | 4 ++-- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md b/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md index 352cba7a4ad0..a4a28c2dbb1c 100644 --- a/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md +++ b/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md @@ -130,6 +130,8 @@ To be grouped into a phase, a user must meet an engagement threshold of at least Phase assignment is recalculated daily from the trailing 28-day window, so a user's phase can shift from one day to the next as their activity within that window changes. This is expected behavior, not a data error. +The impact dashboard counts every user who was active during the trailing 28-day window and groups each user by their current phase. The phase classification rules are the same, but the dashboard population is broader than the `totals_by_ai_adoption_phase.total_engaged_users` field in API and NDJSON reports, which counts users who were active on a specific day. + Users who haven't met any phase's threshold are grouped into **Passive users**, which is not a measure of inactivity, but a signal that a user's engagement hasn't yet reached the level needed to reliably classify their adoption depth. For example, a user with fewer than two active days in the trailing 28-day window, or one who only lightly uses a surface like {% data variables.copilot.copilot_chat_short %} on {% data variables.product.prodname_dotcom_the_website %}, shows as a passive user. Because phase assignment is based on **which surfaces a user engages with**, not simply how many actions they take, a user with high completion volume but no agent usage stays in Phase 1, while a user with lighter but broader usage across agent surfaces progresses to Phase 2 or Phase 3. @@ -142,6 +144,14 @@ This shows the relative impact of deeper adoption, independent of how many users For example, if users in the engaged cohorts averaged 20 pull requests/user/month and the passive cohort averaged 10, then the equation is 20 / 10 = 2x multiplier. +### Estimating potential return on investment + +The impact dashboard's **Potential return on investment** section provides a comparison of cost and pull request output between **Phase 0-1 Passive and Code First Users** and **Phase 2-3 Agent First Users**. + +For each phase group, the dashboard shows the monthly {% data variables.product.prodname_copilot_short %} cost per developer, based on actual {% data variables.product.prodname_ai_credits_short %} consumption, and that cost as a percentage of developer compensation. It also shows average pull requests per developer per month. + +You can select a compensation band to update estimates that depend on developer compensation. These figures are estimates rather than exact financial results, so interpret them alongside the adoption multiplier's code-shipped and time-to-merge comparisons. The return-on-investment estimates are available only in the dashboard and are not included in the {% data variables.product.prodname_copilot_short %} usage metrics API or NDJSON exports. + ### Interpreting pull request lifecycle metrics across scopes Pull request lifecycle metrics are available at both the organization and enterprise level. When comparing reports, keep the following in mind: diff --git a/content/copilot/how-tos/administer-copilot/view-impact-dashboard.md b/content/copilot/how-tos/administer-copilot/view-impact-dashboard.md index e49c155e421f..56fe09ed0aa1 100644 --- a/content/copilot/how-tos/administer-copilot/view-impact-dashboard.md +++ b/content/copilot/how-tos/administer-copilot/view-impact-dashboard.md @@ -15,7 +15,7 @@ category: Instead of a flat active-user count, the impact dashboard groups users into adoption cohorts based on how they engage with {% data variables.product.prodname_copilot_short %}, and connects that engagement to pull request throughput. This gives you a more meaningful signal of adoption depth than daily or weekly active user counts alone. -For a detailed explanation of what the dashboard shows, including adoption cohorts, engagement trends, and recommendations, see [AUTOTITLE](/copilot/concepts/copilot-usage-metrics/copilot-metrics). +For a detailed explanation of what the dashboard shows, including adoption cohorts, engagement trends, potential return on investment, and recommendations, see [AUTOTITLE](/copilot/concepts/copilot-usage-metrics/copilot-metrics). ## Prerequisite @@ -25,3 +25,12 @@ For a detailed explanation of what the dashboard shows, including adoption cohor {% data reusables.copilot.access-copilot-metrics-dashboard %} 1. In the left sidebar, click **{% data variables.product.prodname_copilot_short %} impact**. + +## Estimating potential return on investment + +The "Potential return on investment" section provides a directional comparison of cost and pull request output across adoption phases. + +1. Under "Average developer cost in your organization", select a compensation band. +1. In the "Transition your developers to be agent-first" card, compare the cost, payroll, and pull request estimates for "Phase 0-1 Passive and Code First Users" and "Phase 2-3 Agent First Users". + +Treat the figures as directional estimates rather than exact financial results. Use them with the adoption multiplier metrics for code shipped and time to merge pull requests. diff --git a/content/copilot/reference/copilot-usage-metrics/interpret-copilot-metrics.md b/content/copilot/reference/copilot-usage-metrics/interpret-copilot-metrics.md index a969e29f6c02..e0e614cc09dc 100644 --- a/content/copilot/reference/copilot-usage-metrics/interpret-copilot-metrics.md +++ b/content/copilot/reference/copilot-usage-metrics/interpret-copilot-metrics.md @@ -86,6 +86,16 @@ The adoption multiplier compares engaged users (Phase 1, 2, or 3) against passiv > [!NOTE] > The adoption multiplier compares two different populations of users, not the same users over time. Differences in team composition, project complexity, or seniority between engaged and passive users can influence the comparison as much as {% data variables.product.prodname_copilot_short %} adoption itself. +## Reviewing potential return on investment + +The **Potential return on investment** section compares {% data variables.product.prodname_copilot_short %} cost, estimated percentage of payroll, and pull requests per developer per month across earlier and agent-first adoption phases. Treat these comparisons as directional associations, not proof that a change in adoption caused a change in output. + +| Signal | What it suggests | Suggested action | +|:--|:--|:--| +| Agent-first users merge more pull requests with a similar or lower cost as a percentage of payroll | Agent-first usage is associated with more pull request output relative to the estimated investment. | Compare this signal with the adoption multiplier and trends over multiple periods before using it to inform enablement investment. | +| Agent-first users merge fewer pull requests or have a higher cost as a percentage of payroll | Differences in work type, team composition, or adoption maturity may be affecting the comparison. | Review cohort distribution and team-level context before drawing conclusions about return on investment. | +| The payroll percentage changes after you select a different developer cost | The dashboard is recalculating the estimate using a different compensation assumption, not showing a change in usage. | Use the same compensation band when comparing different periods or organizations. | + ## Acting on your insights Use trends in usage, feature adoption, and language activity to guide enablement and rollout planning. diff --git a/content/copilot/reference/copilot-usage-metrics/reconciling-usage-metrics.md b/content/copilot/reference/copilot-usage-metrics/reconciling-usage-metrics.md index be4cb564f078..040d30f5f422 100644 --- a/content/copilot/reference/copilot-usage-metrics/reconciling-usage-metrics.md +++ b/content/copilot/reference/copilot-usage-metrics/reconciling-usage-metrics.md @@ -43,7 +43,7 @@ The dashboard and APIs use shared definitions for key metrics: | Acceptance rate | Code completion acceptance rate | `code_acceptance_activity_count` ÷ `code_generation_activity_count` | Both sources calculate acceptance rate the same way, though rounding may differ. | | Agent adoption | Agent adoption chart | `totals_by_feature` where feature = “agent” | Reflects users who interacted with the {% data variables.copilot.copilot_agent_short %}. | | Language usage | Language usage charts | `totals_by_language_feature` or `totals_by_language_model` | The dashboard visualizes these aggregated fields. | -| Adoption cohort/phase | Adoption cohort distribution (impact dashboard) | `ai_adoption_phase`, `totals_by_ai_adoption_phase` | The dashboard and API read the same underlying field, so cohort counts should match between them. Users displayed as "Passive users" in the dashboard correspond to the `No Cohort` value in `totals_by_ai_adoption_phase`, and are included in that array like any other phase, so cohort percentages reflect all licensed users, not just those in Phase 1–3. | +| Adoption cohort/phase | Adoption cohort distribution (impact dashboard) | `ai_adoption_phase`, `totals_by_ai_adoption_phase` | The phase definitions are shared, but the populations differ. The dashboard includes every user active during the trailing 28-day window, while the aggregated `totals_by_ai_adoption_phase` field counts users active on the record's specific day. Dashboard and API cohort counts and percentages therefore do not match. Users displayed as "Passive users" in the dashboard correspond to the `No Cohort` API value. | For complete field descriptions, see [AUTOTITLE](/copilot/reference/copilot-usage-metrics). @@ -61,7 +61,7 @@ Each data source aggregates data differently. | APIs | Daily | Each record represents a single day per user, enabling daily trend analysis. | | NDJSON exports | Daily | Mirrors API output for BI tools and long-term reporting. | -Aligning your reporting period with the dashboard’s 28-day window ensures consistent comparisons. +Aligning your reporting period with the dashboard’s 28-day window makes most comparisons more consistent. However, it does not make adoption cohort counts match because the dashboard counts distinct users across the window and the aggregated API fields contain daily counts. ### Delayed telemetry From 5a630d871ec29f3f49b0987a540dd3f9a7825c4e Mon Sep 17 00:00:00 2001 From: John Clement <70238417+jclement136@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:35:03 +0000 Subject: [PATCH 4/7] [Improvement] Update repository security settings reusable for the Security and quality section (#62819) --- .../repositories/navigate-to-code-security-and-analysis.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/reusables/repositories/navigate-to-code-security-and-analysis.md b/data/reusables/repositories/navigate-to-code-security-and-analysis.md index 2f65de1644e1..d0e9cef2cb82 100644 --- a/data/reusables/repositories/navigate-to-code-security-and-analysis.md +++ b/data/reusables/repositories/navigate-to-code-security-and-analysis.md @@ -1 +1 @@ -1. In the "Security" section of the sidebar, click **{% octicon "codescan" aria-hidden="true" aria-label="codescan" %} {% data variables.product.UI_advanced_security %}**. +1. In the "{% ifversion security-and-quality-tab %}Security and quality{% else %}Security{% endif %}" section of the sidebar, click **{% octicon "codescan" aria-hidden="true" aria-label="codescan" %} {% data variables.product.UI_advanced_security %}**. From fa37603d0846d3a8841aa4381e30f5f2ea78d867 Mon Sep 17 00:00:00 2001 From: Sarah Schneider Date: Wed, 19 Aug 2026 13:51:05 +0000 Subject: [PATCH 5/7] Make redirect_from safe when old and new pages coexist (#62757) --- src/redirects/lib/precompile.ts | 10 +++ .../tests/content/redirect-orphans.ts | 23 +----- src/redirects/tests/unit/precompile.ts | 79 +++++++++++++++++++ 3 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 src/redirects/tests/unit/precompile.ts diff --git a/src/redirects/lib/precompile.ts b/src/redirects/lib/precompile.ts index 70df7d923331..93c07a703999 100644 --- a/src/redirects/lib/precompile.ts +++ b/src/redirects/lib/precompile.ts @@ -26,6 +26,16 @@ export async function precompileRedirects(pageList: Page[]): Promise Object.assign(allRedirects, page.buildRedirects()) } + // Remove any redirect whose source URL is also a real page permalink. + // This prevents redirect_from entries from clobbering live pages when a + // new page (versioned broadly) declares a redirect_from that overlaps + // with an older page that still exists in some versions. + for (const page of pageList.filter((xpage) => xpage.languageCode === 'en')) { + for (const permalink of page.permalinks) { + delete allRedirects[permalink.hrefWithoutLanguage] + } + } + // NOTE: Exception redirects **MUST COME AFTER** pageList redirects above in order // to properly override them. Exception redirects are unicorn one-offs that are not // otherwise handled by the versionless redirect fallbacks (see lib/all-versions.ts). diff --git a/src/redirects/tests/content/redirect-orphans.ts b/src/redirects/tests/content/redirect-orphans.ts index 385aa498faf9..5219ede4c86c 100644 --- a/src/redirects/tests/content/redirect-orphans.ts +++ b/src/redirects/tests/content/redirect-orphans.ts @@ -3,39 +3,24 @@ import path from 'path' import { describe, expect, test, vi } from 'vitest' import { loadPages } from '@/frame/lib/page-data' -import Permalink from '@/frame/lib/permalink' describe('redirect orphans', () => { // Because calling `loadPages` will trigger a warmup, this can potentially // be very slow in CI. So we need a timeout. vi.setConfig({ testTimeout: 60 * 1000 }) - test('no page is a redirect in another file', async () => { + test('no redirect_from entry has a trailing slash', async () => { // Only doing English because they're the only files we do PRs for. const pageList = await loadPages(undefined, ['en']) - const redirectFroms = new Map() + const errors = [] for (const page of pageList) { for (const redirectFrom of page.redirect_from || []) { if (redirectFrom.endsWith('/') && redirectFrom.startsWith('/')) { - throw new Error( - `In ${path.join( - 'content', - page.relativePath, - )} redirect entry (${redirectFrom}) has a trailing slash`, + errors.push( + `In ${path.join('content', page.relativePath)} redirect entry (${redirectFrom}) has a trailing slash`, ) } - redirectFroms.set(redirectFrom, page.relativePath) - } - } - - const errors = [] - for (const page of pageList) { - const asPath = Permalink.relativePathToSuffix(page.relativePath) - if (redirectFroms.has(asPath)) { - errors.push( - `${asPath} is a redirect_from in ${path.join('content', redirectFroms.get(asPath))}`, - ) } } expect(errors.length, errors.join('\n')).toBe(0) diff --git a/src/redirects/tests/unit/precompile.ts b/src/redirects/tests/unit/precompile.ts new file mode 100644 index 000000000000..e702ee09205e --- /dev/null +++ b/src/redirects/tests/unit/precompile.ts @@ -0,0 +1,79 @@ +import { describe, expect, test, vi } from 'vitest' + +import type { Page } from '@/types' + +vi.mock('@/frame/lib/read-json-file', () => ({ + readCompressedJsonFileFallback: () => ({}), +})) + +vi.mock('../../lib/exception-redirects', () => ({ + default: () => ({}), +})) + +const { default: precompileRedirects } = await import('../../lib/precompile') +const { default: generateRedirectsForPermalinks } = await import('../../lib/permalinks') + +// Minimal stand-in for a Page instance. precompileRedirects() only relies on +// `languageCode`, `permalinks`, and `buildRedirects()`. +function makePage( + languageCode: string, + permalinks: { pageVersion: string; hrefWithoutLanguage: string }[], + redirectFrom: string[], +): Page { + const fullPermalinks = permalinks.map((permalink) => ({ + languageCode, + title: 'Title', + href: `/${languageCode}${permalink.hrefWithoutLanguage}`, + ...permalink, + })) + return { + languageCode, + permalinks: fullPermalinks, + redirect_from: redirectFrom, + buildRedirects: () => generateRedirectsForPermalinks(fullPermalinks, redirectFrom), + } as unknown as Page +} + +describe('precompileRedirects', () => { + test('removes a redirect_from-generated redirect that clobbers a live old-page permalink, but keeps it for versions where the old page is absent', async () => { + // The old page only exists in GHES 3.14. + const oldPage = makePage( + 'en', + [ + { + pageVersion: 'enterprise-server@3.14', + hrefWithoutLanguage: '/enterprise-server@3.14/foo', + }, + ], + [], + ) + + // The replacement page exists in both 3.14 and 3.15, and declares + // `redirect_from: ['/foo']`, which would otherwise clobber the old + // page's live permalink in 3.14. + const newPage = makePage( + 'en', + [ + { + pageVersion: 'enterprise-server@3.14', + hrefWithoutLanguage: '/enterprise-server@3.14/bar', + }, + { + pageVersion: 'enterprise-server@3.15', + hrefWithoutLanguage: '/enterprise-server@3.15/bar', + }, + ], + ['/foo'], + ) + + const redirects = await precompileRedirects([oldPage, newPage]) + + // The old page's live permalink in 3.14 must not be clobbered by the + // replacement page's redirect_from. + expect(redirects['/enterprise-server@3.14/foo']).toBeUndefined() + + // But in 3.15, where the old page doesn't exist, the redirect must + // still be there. + expect(redirects['/enterprise-server@3.15/foo']).toBe('/enterprise-server@3.15/bar') + }) +}) From 1dbae1b74b05afe9c9adbee0fa284dd5668c4a44 Mon Sep 17 00:00:00 2001 From: Cory Calahan Date: Wed, 19 Aug 2026 13:57:59 +0000 Subject: [PATCH 6/7] removed preview labels for code quality (#62829) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- ...code-security-and-analysis-for-your-enterprise.md | 12 ++++++++---- .../concepts/code-quality/enablement-at-scale.md | 6 +++--- .../security-and-quality-ai-features.md | 1 - data/features/code-quality.yml | 2 +- data/variables/product.yml | 3 --- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-security-and-analysis-for-your-enterprise.md b/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-security-and-analysis-for-your-enterprise.md index 19eb29704933..da10260c6e95 100644 --- a/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-security-and-analysis-for-your-enterprise.md +++ b/content/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-code-security-and-analysis-for-your-enterprise.md @@ -28,7 +28,11 @@ category: You can enforce policies to manage the use of security features within organizations owned by your enterprise. You can allow or disallow people with admin access to a repository to enable or disable the security and analysis features. -Additionally, you can enforce policies for the use of {% data variables.product.prodname_GH_sp_cs_and_cq_or_as %} in your enterprise's organizations and repositories. +Additionally, you can enforce policies for the use of {% data variables.product.prodname_GHAS_cs_or_sp %} in your enterprise's organizations and repositories. + +{% ifversion code-quality %} +Policies for {% data variables.product.prodname_AS %} do not control access to {% data variables.product.prodname_code_quality %}. To manage access, see [AUTOTITLE](/code-security/how-tos/secure-at-scale/configure-enterprise-security/configure-specific-tools/allow-github-code-quality-in-enterprise). +{% endif %} ## Enforcing a policy for the availability of {% data variables.product.prodname_AS %} in your enterprise's organizations @@ -36,7 +40,7 @@ You are billed for {% data variables.product.prodname_GHAS_cs_and_sp %} products You can enforce a policy that controls whether repository administrators are allowed to enable features for {% data variables.product.prodname_AS %} in an organization's repositories. You can configure a policy for all organizations owned by your enterprise account, or for individual organizations that you choose. -Disallowing {% data variables.product.prodname_GH_sp_cs_and_cq_or_as %} for an organization prevents repository administrators from enabling these features for additional repositories, but does not disable the features for repositories where the features are already enabled. +Disallowing {% data variables.product.prodname_GHAS_cs_or_sp %} for an organization prevents repository administrators from enabling these features for additional repositories, but does not disable the features for repositories where the features are already enabled. {% data reusables.enterprise.role-permission-hierarchy %} @@ -47,7 +51,7 @@ Disallowing {% data variables.product.prodname_GH_sp_cs_and_cq_or_as %} for an o {% data reusables.enterprise-accounts.advanced-security-individual-organization-policy-drop-down %} > [!NOTE] -> If {% data variables.product.prodname_actions %} is not available for an organization, {% data variables.product.prodname_code_scanning %} and {% data variables.product.prodname_code_quality %} will be unable to run even if they are made available with this policy. See [AUTOTITLE](/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#policies). +> If {% data variables.product.prodname_actions %} is not available for an organization, {% data variables.product.prodname_code_scanning %} will be unable to run even if it is made available with this policy.{% ifversion code-quality %} Similarly, {% data variables.product.prodname_code_quality %} will be unable to run even if it is made available with its own policy.{% endif %} See [AUTOTITLE](/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#policies). {% ifversion ghec %} @@ -88,7 +92,7 @@ Across all of your enterprise's organizations, you can allow or disallow people {% data reusables.enterprise-accounts.access-enterprise %} {% data reusables.enterprise-accounts.policies-tab %} {% data reusables.enterprise-accounts.code-security-and-analysis-policies %} -1. In the "Policies" section, under "Repository administrators can enable or disable `PRODUCT`", use the dropdown menu to define whether repository administrators can change the enablement of {% data variables.product.prodname_GH_sp_cs_and_cq_or_as %}. +1. In the "Policies" section, under "Repository administrators can enable or disable `PRODUCT`", use the dropdown menu to define whether repository administrators can change the enablement of {% data variables.product.prodname_GHAS_cs_or_sp %}. diff --git a/content/code-security/concepts/code-quality/enablement-at-scale.md b/content/code-security/concepts/code-quality/enablement-at-scale.md index 42539ae29814..7171e731a255 100644 --- a/content/code-security/concepts/code-quality/enablement-at-scale.md +++ b/content/code-security/concepts/code-quality/enablement-at-scale.md @@ -39,12 +39,12 @@ You can apply one of the following options at a time. | **No repositories** | Disables {% data variables.product.prodname_code_quality_short %} for all current and future repositories in the organization. | | **Let repositories decide** | The organization neither enables nor disables {% data variables.product.prodname_code_quality_short %}. Repository administrators choose whether to enable it for their own repositories. This option cannot be enforced. | | **All repositories** | Enables {% data variables.product.prodname_code_quality_short %} for all current and future repositories. | -| **Selected repositories** | Enables {% data variables.product.prodname_code_quality_short %} for a specific list of repositories that you choose. Repositories you do not select are disabled, and new repositories are not enabled automatically. Best for pilots or exceptions. | -| **Matching a filter** | Enables {% data variables.product.prodname_code_quality_short %} for repositories that match a filter you define, now and in the future. Repositories that do not match are disabled. See [Filtering repositories](#filtering-repositories). | +| **Selected repositories...** | Enables {% data variables.product.prodname_code_quality_short %} for a specific list of repositories that you choose. Repositories you do not select are disabled, and new repositories are not enabled automatically. Best for pilots or exceptions. | +| **Matching a filter...** | Enables {% data variables.product.prodname_code_quality_short %} for repositories that match a filter you define, now and in the future. Repositories that do not match are disabled. See [Filtering repositories](#filtering-repositories). | ### Filtering repositories -When you choose **Matching a filter**, you create a dynamic filter that automatically enables {% data variables.product.prodname_code_quality_short %} for existing and future repositories that match your criteria. This is useful for ongoing governance at scale. +When you choose **Matching a filter...**, you create a dynamic filter that automatically enables {% data variables.product.prodname_code_quality_short %} for existing and future repositories that match your criteria. This is useful for ongoing governance at scale. You can filter on any combination of the following criteria: diff --git a/content/code-security/responsible-use/security-and-quality-ai-features.md b/content/code-security/responsible-use/security-and-quality-ai-features.md index 269dc6a16335..523a21bed646 100644 --- a/content/code-security/responsible-use/security-and-quality-ai-features.md +++ b/content/code-security/responsible-use/security-and-quality-ai-features.md @@ -244,7 +244,6 @@ GitHub Code Quality's LLM-powered analysis shares the evaluation framework of Co * **Dry-run validation for generated patterns**: Generated regular expressions from the custom pattern regex generator must go through a dry-run validation step before deployment. Users explicitly import a result into the custom pattern form and test it across their repository or organization, ensuring patterns perform as expected before they are used in production. * **Explicit user action required**: The regex generator does not automatically deploy patterns. Users must click **Use result** to copy a generated expression into the custom pattern form, then manually save and enable the pattern. * **Feedback mechanism for Code Quality**: Users can provide feedback on Code Quality suggestions using the thumbs up and thumbs down buttons on the `github-code-quality` bot's comments, helping GitHub improve suggestion quality. -* **Preview-gated availability**: GitHub Code Quality is available as a preview, allowing organizations to evaluate the feature before broader adoption. ## 10. Best practices for deploying and adopting GitHub Code Security AI features diff --git a/data/features/code-quality.yml b/data/features/code-quality.yml index 2084f36340fb..1e858974d0b9 100644 --- a/data/features/code-quality.yml +++ b/data/features/code-quality.yml @@ -1,5 +1,5 @@ # Reference: #17415 -# Code quality (public preview) +# Code quality # This feature is not yet available for GitHub Enterprise Server. versions: fpt: '*' diff --git a/data/variables/product.yml b/data/variables/product.yml index b38b0609abdc..97449a43bb92 100644 --- a/data/variables/product.yml +++ b/data/variables/product.yml @@ -204,9 +204,6 @@ prodname_GHAS_or_secret_protection: 'GitHub Secret Protection or GitHub Advanced prodname_GHAS_cs_or_sp: 'GitHub Secret Protection, GitHub Code Security, or GitHub Advanced Security' prodname_GH_cs_or_sp: 'GitHub Secret Protection or GitHub Code Security' -## GitHub Code Quality preview only -prodname_GH_sp_cs_and_cq_or_as: '{% data variables.product.prodname_GH_secret_protection %}, {% data variables.product.prodname_GH_code_security %}{% ifversion code-quality %} and {% data variables.product.prodname_code_quality %} ({% data variables.release-phases.public_preview %}){% endif %}, or {% data variables.product.prodname_GHAS %}' - ## GHAS and GHAS products prodname_GHAS_cs_and_sp: 'GitHub Secret Protection, GitHub Code Security, and GitHub Advanced Security' prodname_GH_cs_and_sp: 'GitHub Secret Protection and GitHub Code Security' From f03ef292283a89ca09a67205adc46fe4c4722ca0 Mon Sep 17 00:00:00 2001 From: Emmanuel Chigbo Date: Wed, 19 Aug 2026 14:10:43 +0000 Subject: [PATCH 7/7] Fix AI adoption phase classification signals in Copilot usage metrics reference (#62814) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Eric Hollenberry Co-authored-by: Eric Hollenberry --- .../copilot-usage-metrics/copilot-metrics.md | 6 +++--- .../copilot-usage-metrics.md | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md b/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md index a4a28c2dbb1c..9631932b9b4d 100644 --- a/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md +++ b/content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md @@ -121,9 +121,9 @@ Users are grouped into the following phases: | Phase | What it represents | |:--|:--| -| Passive users | The user has not met the engagement threshold for a phase during the period. In the underlying data, this phase is labeled `No Cohort`. | -| Phase 1: Code first | The user engaged with code completions and/or IDE agent mode. | -| Phase 2: Agent first | The user engaged with a single {% data variables.product.github %}-based agent surface, such as {% data variables.copilot.copilot_cloud_agent %}, {% data variables.copilot.copilot_code-review_short %}, or {% data variables.copilot.copilot_cli_short %}. Only active engagement with {% data variables.copilot.copilot_code-review_short %} counts here; having it automatically assigned to review a pull request without further engagement does not. | +| Passive users | The user has not met the engagement threshold for a phase during the period. A passive user may still be using {% data variables.product.prodname_copilot_short %} regularly, for example by asking questions in {% data variables.copilot.copilot_chat_short %} or agent mode without applying any code edits. In the API, this phase is labeled `No Cohort`. | +| Phase 1: Code first | The user engaged with code completions and/or agent edits, where {% data variables.product.prodname_copilot_short %} writes changes directly into files in the IDE. Using {% data variables.copilot.copilot_chat_short %} or agent mode without producing code completion or agent edit activity does not qualify on its own. | +| Phase 2: Agent first | The user engaged with a single {% data variables.product.github %}-based agent surface, such as {% data variables.copilot.copilot_cloud_agent %}, {% data variables.copilot.copilot_code-review_short %}, or {% data variables.copilot.copilot_cli_short %}. Both active engagement with {% data variables.copilot.copilot_code-review_short %} and having it automatically assigned to review a pull request count as the same surface. | | Phase 3: Multi-agent | The user engaged with two or more {% data variables.product.github %}-based agent surfaces, or with the {% data variables.copilot.github_copilot_app %}. | To be grouped into a phase, a user must meet an engagement threshold of at least two active days out of the trailing 28-day window, using the surfaces associated with that phase. A user only needs two qualifying days on a higher phase's surfaces to progress to that phase. Agent usage alone can qualify a user, without separate days of plain completions. diff --git a/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md b/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md index da659b7b5702..8204cedaa531 100644 --- a/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md +++ b/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md @@ -323,16 +323,21 @@ The `pull_requests` object appears in aggregated enterprise and organization rep #### Classification logic -A user is classified into a phase based on which `used_*` per-user fields (see [Per-user report fields](#per-user-report-fields)) are `true` on at least **two active days within the trailing 28-day window**: +A user is classified into a phase based on the {% data variables.product.prodname_copilot_short %} features they are **engaged** with. A user is engaged with a feature when they use it on at least **two distinct days within the trailing 28-day window**. Engagement is evaluated from the feature-level activity signals in the table below, not directly from the single-day `used_*` [per-user fields](#per-user-report-fields) or from `code_acceptance_activity_count`. Phases are evaluated from the top down, and a user is assigned the highest phase they qualify for. -| Phase | Surface criteria | +| Phase | Engagement criteria | |:--|:--| -| No Cohort (displayed as "Passive users" in the impact dashboard) | The user has not met the two-day engagement threshold for any phase in the window. | -| Phase 1: Code first | At least two active days where `used_chat` is `true`, `code_acceptance_activity_count` is greater than `0`, or `used_agent` is `true`. | -| Phase 2: Agent first | At least two active days where a single GitHub-based agent surface was used: `used_cli` is `true`, `used_copilot_cloud_agent` is `true`, or `used_copilot_code_review_active` is `true`. Passive {% data variables.copilot.copilot_code-review_short %} activity (`used_copilot_code_review_passive`) doesn't count toward phase classification. | -| Phase 3: Multi-agent | At least two active days where two or more of the GitHub-based agent surfaces listed under Phase 2 were used. | +| No Cohort (displayed as "Passive users" in the impact dashboard) | The user isn't engaged with any feature that qualifies for a phase. This doesn't mean the user is inactive. A user in this group can still be using {% data variables.product.prodname_copilot_short %} regularly and consuming premium requests, but hasn't used a qualifying feature on at least two distinct days within the trailing 28-day window. The most common case is conversational use of {% data variables.copilot.copilot_chat_short %} or agent mode, recorded as `chat_panel_agent_mode`, that never produces `code_completion` or `agent_edit` activity. Copying code out of a chat response also doesn't produce either signal. | +| Phase 1: Code first | Engaged with inline code completions (the `code_completion` value of the `feature` dimension) or with agent edits written directly to files (the `agent_edit` value of the `feature` dimension). | +| Phase 2: Agent first | Engaged with exactly one {% data variables.product.github %}-based agent surface: {% data variables.copilot.copilot_cli_short %} (the `copilot_cli` value of the `feature` dimension), {% data variables.copilot.copilot_cloud_agent %} (`used_copilot_cloud_agent`), or {% data variables.copilot.copilot_code-review_short %} (`used_copilot_code_review_active` or `used_copilot_code_review_passive`). Active and passive {% data variables.copilot.copilot_code-review_short %} count together as a single surface. | +| Phase 3: Multi-agent | Engaged with the {% data variables.copilot.github_copilot_app_short %} (the `copilot_app` value of the `feature` dimension), or engaged with two or more of the agent surfaces listed for Phase 2. | -A user only needs two qualifying days on a phase's own criteria to reach that phase. A user doesn't need to independently meet Phase 1 criteria to reach Phase 2 or Phase 3, although in practice most agent surface usage co-occurs with completions or chat activity. +A user only needs to be engaged with a phase's own signals to reach that phase. A user doesn't need to independently meet Phase 1 criteria to reach Phase 2 or Phase 3, although in practice agent-surface usage often co-occurs with completions or agent edits. + +> [!NOTE] +> Because classification uses feature-level engagement, some activity doesn't affect a user's phase on its own. Using IDE chat (`used_chat`) or agent mode (`used_agent`) doesn't qualify a user for Phase 1 unless it produces `code_completion` or `agent_edit` activity. +> +> For example, asking a question in agent mode without letting {% data variables.product.prodname_copilot_short %} edit your files records `chat_panel_agent_mode` activity, not `agent_edit`. A user whose usage is entirely conversational in this way stays in the No Cohort group even though they are actively using {% data variables.product.prodname_copilot_short %} and can still incur premium request usage. Likewise, `code_acceptance_activity_count` includes chat-based acceptances, such as "apply to file" and the **Copy** button, that aren't inline `code_completion` activity, so it isn't used for classification. For more about the `feature` dimension, see [Breakdown dimension values](#breakdown-dimension-values). Phase assignment is recalculated each day using the trailing 28-day window, so a user's phase can change from one day to the next as their activity within the window shifts. This is expected behavior and does not indicate a data error.