From 4a3fe4bc00e2cb46bd9e8acd6d7b3c27f9efdbb3 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 10:12:47 +0200 Subject: [PATCH 01/44] bugfix: bound durable Actions permission fixtures (#577) --- docs/development/testing.mdx | 17 +++++++++++++++++ .../setup_permission_operator_actions.test.ts | 7 ++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/development/testing.mdx b/docs/development/testing.mdx index 157088acf..839328fc3 100644 --- a/docs/development/testing.mdx +++ b/docs/development/testing.mdx @@ -184,6 +184,23 @@ or model-only `READY` response cannot certify real tool execution. See [tool smoke evidence](/security-operations/operations/smoke-tests). +## Permission journal integration budget + +`setup_permission_operator_actions.test.ts` uses a real temporary directory and +journal, including file writes, `fsync`, atomic replacement, recovery and cleanup. +Its tests and hooks have a bounded 30-second Jest budget. A rejected dispatch +alone flushes six journal versions, so the generic five-second unit-test deadline +can expire during slow filesystem operations under hosted Windows coverage. + +For issue #577, adding 900 ms to each real journal flush reproduced the original +five-second timeout. With the 30-second integration budget, all eight cases +completed, including the two-transaction recovery case. This demonstrates the +budget mismatch; historical CI logs do not identify the underlying host storage +or scheduling delay. Keep real persistence and every authority/cleanup assertion. +Fake timers cover Actions polling; recovery switches back to real timers before +starting its next journal transaction. Other suites retain their existing budgets. +Hosted Windows full coverage remains the platform verification gate. + ## Semantic component rendering The component suites use a real Vite/Svelte SSR renderer isolated from Jest. diff --git a/src/infrastructure/__tests__/setup_permission_operator_actions.test.ts b/src/infrastructure/__tests__/setup_permission_operator_actions.test.ts index 0faf057db..fcba3404d 100644 --- a/src/infrastructure/__tests__/setup_permission_operator_actions.test.ts +++ b/src/infrastructure/__tests__/setup_permission_operator_actions.test.ts @@ -6,6 +6,11 @@ import { SetupPermissionProbeHttp } from '../setup_permission_probe_http'; import { SetupPermissionProbeJournal } from '../setup_permission_probe_journal'; import type { SetupTokenPermissionRequirement } from '../../domain/setup_token_permissions'; +// These HTTP fixtures keep real journal writes, fsync, rename, and cleanup. +// Even a rejected dispatch flushes six journal versions; hosted Windows +// coverage can exceed Jest's 5s default. Share the bounded recovery budget. +jest.setTimeout(30_000); + const root = '/repos/owner/repo'; const path = '.github/workflows/registered.yml'; const sha = 'a'.repeat(40); @@ -167,7 +172,7 @@ describe('setup preparation of a bot Actions permission check', () => { expect(value.hasBranch()).toBe(false); expect(await readdir(folder)).toEqual([]); } finally { jest.useRealTimers(); } - }, 30_000); // Two durable journal transactions can exceed 5s on Windows under coverage. + }); it('uses setup authority only for pending Actions recovery, preserving candidate authority for Projects', async () => { const journal = new SetupPermissionProbeJournal(folder); const action = await journal.begin({ owner: 'owner', repository: 'repo', scope: 'repository', probe: 'actions', From ae66873c6ece94153dacd3fc934d8d23225a1a2f Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 10:30:08 +0200 Subject: [PATCH 02/44] docs-637-clarify-deployment-queue-syntax-and-managed-agents-md-hash-scope: clarify deployment queues and managed pointer hashes --- docs/agents/repository-collaboration.mdx | 7 +++ .../repository-guidance-troubleshooting.mdx | 47 +++++++++++++++++++ docs/features.mdx | 6 +-- docs/issues/deployment-orchestration.mdx | 36 +++++++++++++- 4 files changed, 91 insertions(+), 5 deletions(-) diff --git a/docs/agents/repository-collaboration.mdx b/docs/agents/repository-collaboration.mdx index 540dc108a..7e8cd5a42 100644 --- a/docs/agents/repository-collaboration.mdx +++ b/docs/agents/repository-collaboration.mdx @@ -15,6 +15,13 @@ Repository collaborator agents use the same public controls as human contributor - `.copilot/setup-manifest.json`: generator version, profile digest, artifact roles, and SHA-256 hashes. - an optional marker-bounded pointer in root `AGENTS.md`. +Manifest hashes use LF-normalized content. For the `AGENTS.md` entry with +`role: "pointer"`, the hash covers only the managed block, including both marker +comments. It excludes repository-authored text outside the block and any newline +after the end marker. A whole-file `shasum -a 256 AGENTS.md` can therefore differ +from the manifest without indicating drift. See [pointer hash verification](/agents/repository-guidance-troubleshooting#agentsmd-pointer-hash-scope) +for a check using the same scope as setup and doctor. + The profile contains only enabled kinds, effective forms and labels, required fields, branch roles, relevant release/hotfix workflow names, PR linkage, and deployment boundaries. It contains no token, Secret, arbitrary action input, executable command, or provider response. The generated guide links to the shared documentation in `vypdev/copilot` through absolute HTTPS URLs. These links follow the source repository's `master` documentation, so destination repositories do not need a copied documentation tree. Links to installed artifacts, such as `repository-profile.json`, remain relative to the generated guide. diff --git a/docs/agents/repository-guidance-troubleshooting.mdx b/docs/agents/repository-guidance-troubleshooting.mdx index 197719df4..e226fe6f8 100644 --- a/docs/agents/repository-guidance-troubleshooting.mdx +++ b/docs/agents/repository-guidance-troubleshooting.mdx @@ -28,3 +28,50 @@ Setup writes each generated artifact atomically and the manifest last. Approved Older generated guides may link to `../docs/agents/` files that were never installed in the destination repository. Update Copilot and rerun setup with the same configuration to replace an unchanged, setup-owned guide with absolute links to the shared documentation. The previous guide is backed up. If the guide was edited or is not setup-owned, preserve those edits and follow the normal conflict recovery above. Do not repair drift by editing `.copilot/repository-profile.json` or its hashes. Change the setup configuration and rerun setup so forms, Variables, workflows, guide, skill, and manifest converge from one plan. + +## AGENTS.md pointer hash scope + +In `.copilot/setup-manifest.json`, the `AGENTS.md` record has `role: "pointer"`. +Its SHA-256 covers only the block from `` +through ``, including both markers. Hashing +normalizes CRLF to LF. Text outside that block, including a trailing newline +after the end marker, is excluded so repository-authored instructions remain +outside setup ownership. + +Comparing this record with `shasum -a 256 AGENTS.md` hashes different content. +Even a freshly generated pointer-only file ends with a newline outside the +managed block, so a different whole-file hash is expected. This alone is not +generated-file corruption or drift. + +Use `copilot doctor --config copilot.setup.yml` to inspect the installation, or +run this read-only check from the repository root with Node.js: + +```bash +node <<'NODE' +const fs = require('node:fs'); +const { createHash } = require('node:crypto'); +const manifest = JSON.parse(fs.readFileSync('.copilot/setup-manifest.json', 'utf8')); +const record = manifest.artifacts['AGENTS.md']; +if (record?.role !== 'pointer') throw new Error('No managed AGENTS.md pointer record.'); +const content = fs.readFileSync('AGENTS.md', 'utf8').replace(/\r\n/g, '\n'); +const start = ''; +const end = ''; +const from = content.indexOf(start); +const to = content.indexOf(end); +if (content.split(start).length !== 2 || content.split(end).length !== 2 || to < from) { + throw new Error('Missing, duplicate, or malformed pointer markers; inspect with doctor.'); +} +const block = content.slice(from, to + end.length); +const actual = createHash('sha256').update(block, 'utf8').digest('hex'); +console.log({ expected: record.sha256, actual, matches: actual === record.sha256 }); +process.exitCode = actual === record.sha256 ? 0 : 1; +NODE +``` + +If this scoped check differs, inspect changes inside the markers and follow the +normal drift recovery above. Preserve surrounding instructions and review the +managed block before reconciling; do not replace its manifest hash with a +whole-file digest. + +For workflow linter errors about `concurrency.queue`, see +[validating `queue: max`](/issues/deployment-orchestration#validating-queue-max). diff --git a/docs/features.mdx b/docs/features.mdx index 9f950a751..11b1564b9 100644 --- a/docs/features.mdx +++ b/docs/features.mdx @@ -166,10 +166,10 @@ decorative media or expose configuration for it. ## Workflow concurrency and sequential execution - **Two coordination policies:** durable mutation workflows preserve every admitted event in a workflow-local queue. Commit and Pull Request each have a separate repository/branch latest-revision lane, so paired events cannot cancel one another. + **Coordination policies:** issue and comment mutation workflows preserve admitted events in a workflow-local queue. Deployment mutations use a shared issue-scoped native queue. Commit and Pull Request each have a separate repository/branch latest-revision lane, so paired events cannot cancel one another. -GitHub's native [concurrency](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency) can cancel in-progress runs when a newer one starts and can retain only one pending run. The replaceable branch jobs therefore use event-specific keys: Commit uses `copilot-push-${{ github.repository }}-${{ github.ref_name }}`; Pull Request code/lifecycle analysis uses the branch key with an `analysis` suffix; and the dedicated review-state workflow uses the same branch key with a `review-state` suffix. Each lane cancels only its own obsolete revision. Commit still synchronizes issue progress, then Bugbot performs a read-only exact-head lookup because a `push` payload does not contain PR identity. A validated open same-repository PR makes the push stop before review-context loading or agent invocation; the PR `synchronize` event exclusively owns review for that head. This prevents duplicate reviews without letting a push or review-state event cancel useful PR analysis. Branches without an open PR retain push-time Bugbot. Metadata-only `pull_request: edited` events are not subscribed because Copilot changes the PR body itself; excluding them prevents self-generated run cascades and preserves human metadata edits. Application-level head guards prevent an older run from updating a newer PR, and the next code/lifecycle run repairs any durable half-transition discovered after cancellation. Fixed workflow/job names expose analysis and review-state checks without leaking an unevaluated expression when GitHub skips bot-authored events. A separate merge-group workflow avoids a skipped duplicate on normal PRs while deliberately preserving the exact `Copilot - Pull Request` required-check context for branch-protection compatibility. +GitHub's native [concurrency](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency) can cancel in-progress runs when a newer one starts. Its default `queue: single` retains only one pending run; `queue: max` allows up to 100 pending jobs or workflow runs when `cancel-in-progress` is `false` or omitted. The replaceable branch jobs therefore use event-specific keys: Commit uses `copilot-push-${{ github.repository }}-${{ github.ref_name }}`; Pull Request code/lifecycle analysis uses the branch key with an `analysis` suffix; and the dedicated review-state workflow uses the same branch key with a `review-state` suffix. Each lane cancels only its own obsolete revision. Commit still synchronizes issue progress, then Bugbot performs a read-only exact-head lookup because a `push` payload does not contain PR identity. A validated open same-repository PR makes the push stop before review-context loading or agent invocation; the PR `synchronize` event exclusively owns review for that head. This prevents duplicate reviews without letting a push or review-state event cancel useful PR analysis. Branches without an open PR retain push-time Bugbot. Metadata-only `pull_request: edited` events are not subscribed because Copilot changes the PR body itself; excluding them prevents self-generated run cascades and preserves human metadata edits. Application-level head guards prevent an older run from updating a newer PR, and the next code/lifecycle run repairs any durable half-transition discovered after cancellation. Fixed workflow/job names expose analysis and review-state checks without leaking an unevaluated expression when GitHub skips bot-authored events. A separate merge-group workflow avoids a skipped duplicate on normal PRs while deliberately preserving the exact `Copilot - Pull Request` required-check context for branch-protection compatibility. For non-replaceable issue and comment mutations, Copilot adds an application-level queue per workflow: every started run waits for earlier active runs of that same workflow, so intermediate events are not discarded by a native concurrency group. Runs triggered by the PAT owner that would only re-trigger the normal pipeline complete before entering this queue. @@ -221,7 +221,7 @@ jobs: project-ids: '2,3' ``` -Durable mutation workflows deliberately do not use a GitHub Actions `concurrency` block: native cancellation retains only one pending run and can discard intermediate issue, comment, or release mutations. The Commit and Pull Request templates are the deliberate exception for their own replaceable branch revisions, but they use distinct groups and cannot cancel one another. Native concurrency also remains appropriate for replaceable read-only workflows such as CI and RepoWise. +Issue and comment mutation workflows use the application-level queue above to preserve intermediate events. Release, hotfix, and managed-PR deployment mutations use native `concurrency` with `queue: max` and `cancel-in-progress: false`; this is valid GitHub Actions syntax. See [deployment concurrency validation](/issues/deployment-orchestration#validating-queue-max) before changing generated workflows in response to a linter error. Commit and Pull Request use separate native groups with cancellation for their own replaceable branch revisions. Native concurrency also remains appropriate for replaceable read-only workflows such as CI and RepoWise. --- diff --git a/docs/issues/deployment-orchestration.mdx b/docs/issues/deployment-orchestration.mdx index ba7f71e26..c2471a351 100644 --- a/docs/issues/deployment-orchestration.mdx +++ b/docs/issues/deployment-orchestration.mdx @@ -146,8 +146,10 @@ provider mutation. Start a new deployment from valid current configuration. ## Serialization, durable revisions, and safe retries All release, hotfix, and managed-PR mutation routes for the same launcher issue -share one repository-and-issue concurrency group. The workflows retain every -waiting run and never cancel an in-progress deployment owner. A validation job +share one repository-and-issue concurrency group with `queue: max` and +`cancel-in-progress: false`. GitHub allows up to 100 pending jobs or workflow +runs in that group; additional arrivals are canceled when the queue is full. +The workflows never cancel an in-progress deployment owner. A validation job with `permissions: {}` rejects an invalid issue, mode, version, operation ID, title, or changelog before a job receives write permission. It uses the runtime bundled with `actions/github-script@v9` and its automatic token, without a PAT or @@ -155,6 +157,36 @@ configured secret. Leave `github-token` unspecified: an empty override prevents the Action from starting. No host-installed Node executable is required by this validation step. +### Validating `queue: max` + +`queue: max` is valid at both workflow and job level. GitHub added larger +concurrency queues on [May 7, 2026](https://github.blog/changelog/2026-05-07-github-actions-concurrency-groups-now-allow-larger-queues/). +The [official concurrency documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/control-workflow-concurrency) +defines `single` (the default) and `max`; `max` requires `cancel-in-progress` to +be `false` or omitted. Combining it with `cancel-in-progress: true` is invalid. + +The generated release and hotfix workflows use: + +```yaml +concurrency: + group: copilot-deployment-${{ github.repository_id }}-${{ inputs.issue }} + cancel-in-progress: false + queue: max +``` + +The deployment continuation uses the same queue settings on its mutation job, +with the issue resolved by its read-only predecessor. A diagnostic such as +`unexpected key "queue" for "concurrency" section` from `actionlint` 1.7.12 is a +false positive against this supported syntax. Use a validator that supports +`queue: max`. Keep the generated queue setting: removing it restores the default +single pending slot, where a new pending run replaces the previous one. + +Queue order is not deployment authority. If the queue reaches capacity, use +**Retry current deployment phase** from the launcher dashboard; the retry +reloads durable state before continuing. + +### Durable revisions + The launcher issue stores only deployment state version 1. The first snapshot is revision 1; every accepted state change increments it by exactly one and saves against the previously read operation ID, phase, and revision. A stale delivery From eb97eeeebdec482c0ecae1fb972b81fe4d005511 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 10:40:58 +0200 Subject: [PATCH 03/44] chore: run RepoWise only through manual dispatch --- .github/workflows/repowise.yml | 34 +++---- docs/development/release-process.mdx | 3 +- docs/development/testing.mdx | 36 ++++--- docs/features.mdx | 2 +- docs/issues/deployment-orchestration.mdx | 2 +- .../security/self-hosted-runners.mdx | 12 ++- scripts/validate-workflow-contract.cjs | 48 +++++++--- specs/CATALOG.md | 8 +- specs/catalog.json | 6 +- specs/local-web-setup-assistant.md | 20 +++- specs/merge-queue-readiness.md | 94 ++++++++++++++++++- .../validate_workflow_contract.test.ts | 74 ++++++++++++--- 12 files changed, 254 insertions(+), 85 deletions(-) diff --git a/.github/workflows/repowise.yml b/.github/workflows/repowise.yml index 02c7efed0..938c4b642 100644 --- a/.github/workflows/repowise.yml +++ b/.github/workflows/repowise.yml @@ -1,32 +1,27 @@ name: RepoWise Code Health on: - push: - branches: [master] - pull_request: - types: [opened, synchronize, reopened] - merge_group: - types: [checks_requested] workflow_dispatch: concurrency: - group: repowise-${{ github.event.pull_request.number || github.ref }} + group: repowise-${{ github.ref }} cancel-in-progress: true permissions: contents: read +defaults: + run: + shell: bash + jobs: code-health: name: RepoWise code health - # A merge group can contain fork code without exposing the originating PR here. - runs-on: ${{ fromJSON((github.event_name == 'merge_group' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository)) && '["ubuntu-latest"]' || '["self-hosted","codex","Linux"]') }} + runs-on: [self-hosted, codex, Linux] timeout-minutes: 30 env: REPOWISE_VENV_NAME: repowise-venv-${{ github.run_id }}-${{ github.run_attempt }}-code-health REPOWISE_REPORT_NAME: repowise-report-${{ github.run_id }}-${{ github.run_attempt }}-code-health - REPOWISE_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || '' }} - REPOWISE_EVENT_NAME: ${{ github.event_name }} steps: - name: Verify Ubuntu runner shell: bash @@ -66,6 +61,8 @@ jobs: report_dir="$RUNNER_TEMP/$REPOWISE_REPORT_NAME" repowise_bin="$RUNNER_TEMP/$REPOWISE_VENV_NAME/bin/repowise" mkdir -p "$report_dir" + analyzed_sha="$(git rev-parse HEAD)" + printf '%s\n' "$analyzed_sha" > "$report_dir/revision.txt" cleanup() { rm -rf .repowise .mcp.json rm -f .vscode/mcp.json .vscode/extensions.json @@ -90,23 +87,14 @@ jobs: fi } advisory_scan dead-code "$repowise_bin" dead-code --safe-only --no-workspace --format json . - if [ "$REPOWISE_EVENT_NAME" = workflow_dispatch ]; then - echo 'security scope: full reachable history (manual dispatch)' >> "$report_dir/advisory-status.txt" - advisory_scan security "$repowise_bin" security scan --history --path . --format json - elif [[ "$REPOWISE_BASE_SHA" =~ ^[0-9a-f]{40}$ ]] \ - && git cat-file -e "$REPOWISE_BASE_SHA^{commit}" \ - && git merge-base --is-ancestor "$REPOWISE_BASE_SHA" HEAD; then - printf 'security scope: %s..%s\n' "$REPOWISE_BASE_SHA" "$(git rev-parse HEAD)" >> "$report_dir/advisory-status.txt" - advisory_scan security "$repowise_bin" security scan --history --since "$REPOWISE_BASE_SHA" --to HEAD --path . --format json - else - echo 'security: incomplete (event base unavailable or not an ancestor)' >> "$report_dir/advisory-status.txt" - echo '::warning::RepoWise security advisory scope could not be verified; no full-history fallback was attempted.' - fi + echo 'security scope: full reachable history (manual dispatch)' >> "$report_dir/advisory-status.txt" + advisory_scan security "$repowise_bin" security scan --history --path . --format json { echo '## RepoWise code health' echo echo 'Advisory reports are retained as workflow artifacts for this commit.' echo + printf 'Analyzed revision: `%s`\n\n' "$analyzed_sha" sed -n '1,100p' "$report_dir/health.md" echo echo '### Advisory scan status' diff --git a/docs/development/release-process.mdx b/docs/development/release-process.mdx index c13dc9b4d..b2660e44b 100644 --- a/docs/development/release-process.mdx +++ b/docs/development/release-process.mdx @@ -36,7 +36,8 @@ prepare release -> production PR -> accepted production SHA For unattended completion, enable repository auto-merge and active required validation on both production and development targets. This repository requires -GitHub Actions `CI Check` on `master` and `develop`; RepoWise is advisory. +GitHub Actions `CI Check` on `master` and `develop`; RepoWise is optional and +runs only through manual dispatch. Default `auto` mode enables native auto-merge while a managed PR must wait. When GitHub already reports the PR ready, Copilot requests a normal merge pinned to its verified head SHA. This also handles pending advisory checks, without diff --git a/docs/development/testing.mdx b/docs/development/testing.mdx index 157088acf..834e23dd4 100644 --- a/docs/development/testing.mdx +++ b/docs/development/testing.mdx @@ -104,20 +104,28 @@ local topology before an architecture review with Graphify, and use the RepoWise index-only health/dead-code reports to distinguish current complexity from history-based churn signals: -The required `RepoWise code health` workflow publishes its index and health -reports. Its dead-code and history-security scans have separate time and memory limits; -the Job Summary and artifact status identify an incomplete advisory scan -instead of claiming that it passed. -For PRs, pushes and merge groups, history-security scans cover the native event -base through the checked-out HEAD, including commits that introduced and then -removed a finding. The base must be a valid commit and an ancestor of HEAD; -missing or unrelated evidence produces an incomplete advisory result. The -artifact records both immutable bounds. Manual dispatch scans the complete -reachable history within the same limits; a successful event-range scan is -not evidence of a complete historical audit. -Repository-owned PRs, pushes and merge groups run RepoWise and `CI Check` on -self-hosted Ubuntu `codex` runners. Fork PRs use GitHub-hosted Ubuntu for -these checks. The automatic setup fixture matrix remains hosted on three +`RepoWise Code Health` is an optional manual workflow. PRs, pushes and merge +groups do not launch it, and it must not be a required branch check. To run an +analysis, open **Actions → RepoWise Code Health → Run workflow**, select a +reviewed repository branch, and launch it. The CLI equivalent for development is +`gh workflow run repowise.yml --ref develop`. The workflow already exists on the +default branch, as required for [manual dispatch](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manually-run-a-workflow). + +Open the run's Job Summary for the analyzed commit and scan status. Download +the `repowise-code-health` artifact for the index log, Markdown/JSON health +reports, `revision.txt` and `advisory-status.txt`; artifacts are retained for +14 days. History security scans cover the complete reachable history of that +revision. Dead-code and security scans each have a 90-second, 2 GiB limit +inside the 30-minute job budget. An incomplete scan produces a warning and an +incomplete status while preserving completed health reports. A failed health +step fails the run; available files are still uploaded. Inspect the failure +before retrying. A newer manual run for the same ref cancels the older one; +cancellation or runner loss can prevent artifact publication. No manual run +blocks the automatic CI path. + +Manual RepoWise runs use self-hosted Ubuntu `codex` runners. `CI Check` uses +that pool for repository-owned PRs and pushes; fork PRs and all merge groups +use disposable GitHub-hosted Ubuntu runners. The automatic setup fixture matrix remains hosted on three operating systems, with service-runner fixtures available by manual dispatch. Runner routing is contract-checked, but actual runner availability and remote results require evidence from the corresponding Actions runs. diff --git a/docs/features.mdx b/docs/features.mdx index 9f950a751..2af9d6035 100644 --- a/docs/features.mdx +++ b/docs/features.mdx @@ -221,7 +221,7 @@ jobs: project-ids: '2,3' ``` -Durable mutation workflows deliberately do not use a GitHub Actions `concurrency` block: native cancellation retains only one pending run and can discard intermediate issue, comment, or release mutations. The Commit and Pull Request templates are the deliberate exception for their own replaceable branch revisions, but they use distinct groups and cannot cancel one another. Native concurrency also remains appropriate for replaceable read-only workflows such as CI and RepoWise. +Durable mutation workflows deliberately do not use a GitHub Actions `concurrency` block: native cancellation retains only one pending run and can discard intermediate issue, comment, or release mutations. The Commit and Pull Request templates are the deliberate exception for their own replaceable branch revisions, but they use distinct groups and cannot cancel one another. Native concurrency also remains appropriate for replaceable read-only workflows such as CI and the optional, manually dispatched RepoWise analysis. --- diff --git a/docs/issues/deployment-orchestration.mdx b/docs/issues/deployment-orchestration.mdx index ba7f71e26..6c4e06fae 100644 --- a/docs/issues/deployment-orchestration.mdx +++ b/docs/issues/deployment-orchestration.mdx @@ -58,7 +58,7 @@ Complete this once before starting the first production-first operation: ancestry relationship; - activate required validation on every promotion/reconciliation target. This project requires GitHub Actions `CI Check` on both `master` and `develop`; - RepoWise remains advisory; + RepoWise is optional and runs only through manual dispatch; - enable repository auto-merge if selecting `auto-merge`, or configure every required check for `merge_group` if the target requires a merge queue, and add an exact attestation only for a producer Copilot cannot inspect; diff --git a/docs/security-operations/security/self-hosted-runners.mdx b/docs/security-operations/security/self-hosted-runners.mdx index f2925d0e4..3130652bd 100644 --- a/docs/security-operations/security/self-hosted-runners.mdx +++ b/docs/security-operations/security/self-hosted-runners.mdx @@ -22,9 +22,8 @@ package-manager caching. This keeps a successful full validation from timing out in the post-job archive step; hosted fixture caching is retained. See the [setup-node cache inputs](https://github.com/actions/setup-node#usage). -This repository runs `CI Check` and `RepoWise code health` on self-hosted -Ubuntu `codex` runners for its own PRs and pushes. Fork PRs and all merge -groups keep the same quality checks on disposable GitHub-hosted Ubuntu +This repository runs `CI Check` on self-hosted Ubuntu `codex` runners for its +own PRs and pushes. Fork PRs and all merge groups run CI on disposable GitHub-hosted Ubuntu runners. A merge group can contain fork code without exposing its origin to the runner selector; never route it to a persistent service runner. The trusted-default-branch PR approval observer also runs on a self-hosted Ubuntu `codex` runner. The @@ -48,7 +47,12 @@ self-hosted runners. RepoWise obtains a complete Python 3.12 distribution via `actions/setup-python`, creates its virtual environment and reports in run-specific temporary directories, and removes them after artifact upload. Its runner needs a writable Actions tool cache; the workflow does not install -Ubuntu system packages. +Ubuntu system packages. RepoWise runs only through manual dispatch on +`[self-hosted, codex, Linux]`, using the reviewed repository ref selected by the +maintainer. It is optional and must not be required by branch protections or +rulesets. It no longer consumes this pool on every PR or push. See +[testing and manual analysis](/development/testing) for launch instructions, +revision evidence, scan limits, artifacts, and retry behavior. The `[self-hosted, codex]` pool routes agent jobs to macOS and Ubuntu. Windows services MUST omit `codex` on registration; recreate existing registrations to diff --git a/scripts/validate-workflow-contract.cjs b/scripts/validate-workflow-contract.cjs index 096a9f50e..06f2e5447 100644 --- a/scripts/validate-workflow-contract.cjs +++ b/scripts/validate-workflow-contract.cjs @@ -259,15 +259,38 @@ function assertRepoWiseTemporaryCleanup(relativeFile, job) { throw new Error(`${relativeFile} must select complete Python, isolate RepoWise files, and remove them after artifact upload.`); } const reports = (job.steps ?? []).find(step => step?.name === 'Generate RepoWise reports'); - if (job.env?.REPOWISE_BASE_SHA !== "${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || '' }}" - || job.env?.REPOWISE_EVENT_NAME !== '${{ github.event_name }}' - || !reports?.run?.includes('[[ "$REPOWISE_BASE_SHA" =~ ^[0-9a-f]{40}$ ]]') - || !reports.run.includes('git cat-file -e "$REPOWISE_BASE_SHA^{commit}"') - || !reports.run.includes('git merge-base --is-ancestor "$REPOWISE_BASE_SHA" HEAD') - || !reports.run.includes('--since "$REPOWISE_BASE_SHA" --to HEAD') - || !reports.run.includes('[ "$REPOWISE_EVENT_NAME" = workflow_dispatch ]') - || !reports.run.includes('security: incomplete (event base unavailable or not an ancestor)')) { - throw new Error(`${relativeFile} must verify and report event-scoped security history; only manual dispatch may scan full history.`); + if (!reports?.run?.includes('advisory_scan security "$repowise_bin" security scan --history --path . --format json') + || !reports.run.includes('security scope: full reachable history (manual dispatch)') + || !reports.run.includes('ulimit -v 2097152; timeout --kill-after=10s 90s') + || !reports.run.includes('incomplete (exit %s)') + || !reports.run.includes('health --no-workspace --refactoring-targets --format md') + || !reports.run.includes('health --no-workspace --refactoring-targets --format json') + || !reports.run.includes('analyzed_sha="$(git rev-parse HEAD)"') + || !reports.run.includes('printf \'%s\\n\' "$analyzed_sha" > "$report_dir/revision.txt"') + || !reports.run.includes('printf \'Analyzed revision: `%s`\\n\\n\' "$analyzed_sha"') + || !reports.run.includes('>> "$GITHUB_STEP_SUMMARY"') + || upload.if !== '${{ always() }}' + || upload.with?.['retention-days'] !== 14) { + throw new Error(`${relativeFile} must preserve bounded manual history scans, health reports, revision evidence, summary and unconditional artifacts.`); + } +} + +function assertManualRepoWiseWorkflow(file, workflow) { + const relativeFile = relativeWorkflow(file); + if (relativeFile !== '.github/workflows/repowise.yml') return; + if (Object.keys(workflow.on ?? {}).join(',') !== 'workflow_dispatch') { + throw new Error(`${relativeFile} must run only through workflow_dispatch.`); + } + const job = workflow.jobs?.['code-health']; + const checkout = (job?.steps ?? []).find(step => step?.uses === CHECKOUT_ACTION); + if (job?.['timeout-minutes'] !== 30 + || JSON.stringify(workflow.permissions) !== JSON.stringify({ contents: 'read' }) + || job.permissions !== undefined + || checkout?.with?.['fetch-depth'] !== 0 + || checkout.with?.ref !== undefined + || workflow.concurrency?.group !== 'repowise-${{ github.ref }}' + || workflow.concurrency?.['cancel-in-progress'] !== true) { + throw new Error(`${relativeFile} must retain its manual job budget, read-only permissions, selected revision and per-ref concurrency.`); } } @@ -451,8 +474,9 @@ function assertRunner(file, workflow) { } else if (relativeFile === '.github/workflows/copilot_runner_diagnostics.yml') { if (jobId !== 'linux') throw new Error(`${relativeFile} contains an unsupported Codex diagnostic job.`); expected = ['self-hosted', 'codex', 'Linux']; - } else if (relativeFile === '.github/workflows/ci_check.yml' - || relativeFile === '.github/workflows/repowise.yml') { + } else if (relativeFile === '.github/workflows/repowise.yml') { + expected = ['self-hosted', 'codex', 'Linux']; + } else if (relativeFile === '.github/workflows/ci_check.yml') { expected = [QUALITY_RUNNER_BY_TRUST]; } const labels = runnerLabels(job['runs-on']); @@ -1233,7 +1257,6 @@ function assertMergeQueueWorkflowSupport(file, workflow) { const relativeFile = relativeWorkflow(file); const required = new Set([ '.github/workflows/ci_check.yml', - '.github/workflows/repowise.yml', '.github/workflows/copilot_pull_request_merge_queue.yml', 'setup/workflows/copilot_pull_request_merge_queue.yml', ]); @@ -1379,6 +1402,7 @@ function assertIssueBranchConfigurationInputs(file, workflow) { function validateWorkflow(file, workflow) { if (!workflow || typeof workflow !== 'object') throw new Error('workflow document is empty.'); + assertManualRepoWiseWorkflow(file, workflow); assertDirectEventTriggers(file, workflow); assertApprovalObserverWorkflow(file, workflow); assertPullRequestMergeQueueWorkflow(file, workflow); diff --git a/specs/CATALOG.md b/specs/CATALOG.md index b5608fbec..1cabdc39b 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -12,12 +12,12 @@ debt or convert unknown historic intent into a design decision. |---|---|---|---|---| | `github-communication-experience` | Implemented | English-default, localized, semantic, bounded, and idempotent product messages across GitHub and repository-aware operator surfaces | [Semantic GitHub communication and repository localization](./semantic-github-publication-and-notification.md) + 3 companion | 277 paths · 2026-10-20 | | `release-orchestration` | Implemented | Release and hotfix promotion, publication, bounded merge readiness recovery, and receipt-verified reconciliation without republication | [Configurable production-first release orchestration](./configurable-release-orchestration.md) + 2 companion | 59 paths · 2026-10-16 | -| `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 24 paths · 2026-10-15 | +| `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 24 paths · 2026-10-21 | | `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 59 paths · 2026-10-11 | | `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 97 paths · 2026-10-14 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | | `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 5 companion | 326 paths · 2026-10-20 | -| `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 1 companion | 238 paths · 2026-10-20 | +| `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 1 companion | 238 paths · 2026-10-21 | | `guided-bot-pat-onboarding` | Proposed | Guide creation of the persistent workflow PAT, verify bot identity and grants, recover explicitly from wrong-account input within the session, and install the approved Actions Secret | [Guided bot PAT onboarding](./guided-bot-pat-onboarding.md) | 39 paths · 2026-10-07 | | `temporary-setup-operator-authorization` | Proposed | Guide creation of the one-run operator PAT through GitHub's official form, verify final setup access, and report user-owned deletion accurately | [Assisted setup PAT creation](./temporary-setup-operator-authorization.md) | 36 paths · 2026-10-18 | | `issue-start-and-sdd-readiness` | Implemented | Start every admitted issue with one explicit signal and publish a validated SDD before eligible Action-managed branch work; inspect verified SDD status and bounded structural publication comparisons | [Uniform issue start and pre-branch SDD readiness](./issue-start-and-branch-readiness.md) + 3 companion | 116 paths · 2026-10-19 | @@ -59,7 +59,7 @@ debt or convert unknown historic intent into a design decision. ### `merge-queue-readiness` — Merge queue readiness and effective target rules - Owner: Copilot maintainers -- Last verified: 2026-10-15 +- Last verified: 2026-10-21 - Specifications: [`specs/merge-queue-readiness.md`](./merge-queue-readiness.md) - Workflows: [`.github/workflows/ci_check.yml`](../.github/workflows/ci_check.yml) · [`.github/workflows/repowise.yml`](../.github/workflows/repowise.yml) · [`.github/workflows/copilot_pull_request_merge_queue.yml`](../.github/workflows/copilot_pull_request_merge_queue.yml) · [`setup/workflows/copilot_pull_request_merge_queue.yml`](../setup/workflows/copilot_pull_request_merge_queue.yml) · [`.github/workflows/copilot_deployment_orchestration.yml`](../.github/workflows/copilot_deployment_orchestration.yml) - Entrypoints: [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) @@ -114,7 +114,7 @@ debt or convert unknown historic intent into a design decision. ### `local-web-setup-assistant` — Local web setup assistant - Owner: Copilot maintainers -- Last verified: 2026-10-20 +- Last verified: 2026-10-21 - Specifications: [`specs/local-web-setup-assistant.md`](./local-web-setup-assistant.md) · [`specs/setup-configuration-management.md`](./setup-configuration-management.md) - Workflows: [`.github/workflows/ci_check.yml`](../.github/workflows/ci_check.yml) · [`.github/workflows/repowise.yml`](../.github/workflows/repowise.yml) · [`.github/workflows/setup_platform_smoke.yml`](../.github/workflows/setup_platform_smoke.yml) · [`.github/workflows/copilot_pull_request_approval.yml`](../.github/workflows/copilot_pull_request_approval.yml) - Entrypoints: [`src/cli/commands/setup.ts`](../src/cli/commands/setup.ts) · [`package.json`](../package.json) · [`web/src/main.ts`](../web/src/main.ts) diff --git a/specs/catalog.json b/specs/catalog.json index 73491e557..5aa5def10 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -388,9 +388,9 @@ "id": "merge-queue-readiness", "title": "Merge queue readiness and effective target rules", "status": "implemented", - "scope": "Fail-closed validation of required checks and merge-group workflow support", + "scope": "Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration", "owner": "Copilot maintainers", - "lastVerified": "2026-10-15", + "lastVerified": "2026-10-21", "specs": [ "specs/merge-queue-readiness.md" ], @@ -1082,7 +1082,7 @@ "status": "proposed", "scope": "Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification", "owner": "Copilot maintainers", - "lastVerified": "2026-10-20", + "lastVerified": "2026-10-21", "specs": [ "specs/local-web-setup-assistant.md", "specs/setup-configuration-management.md" diff --git a/specs/local-web-setup-assistant.md b/specs/local-web-setup-assistant.md index ef167c155..72f8a0840 100644 --- a/specs/local-web-setup-assistant.md +++ b/specs/local-web-setup-assistant.md @@ -2415,8 +2415,9 @@ called secure. That external policy review remains an open security gate. The 2026-10-05 runner-cost decision supersedes only the blanket hosted-runner requirement for the repository's `CI Check` and `RepoWise code health` jobs. -Both MUST use an Ubuntu self-hosted `codex` runner for repository-owned PRs, -pushes, and manual runs. A fork PR or any merge-group event MUST instead use +As amended by issue #639 on 2026-10-21, `CI Check` MUST use an Ubuntu +self-hosted `codex` runner for repository-owned PRs, pushes, and manual runs. +A fork PR or any merge-group event MUST instead use disposable `ubuntu-latest`: a merge group can contain fork code but its event does not expose the original PR trust classification to the runner selector. The quality checks still run without executing that code on a persistent @@ -2445,6 +2446,16 @@ exception. A fresh run on each selected runner type is required before calling the routing operationally verified; static workflow checks alone do not prove runner availability or the outcome of remote jobs. +Issue #639 supersedes RepoWise's automatic routing cases above. RepoWise MUST +now run only under `workflow_dispatch` on Ubuntu `codex` with the native selected +repository ref; it MUST NOT run on PR, push or merge-group events or be required +for them. The retained CI routing cases still prove the fork/merge-group trust +boundary. The [manual-only migration contract](./merge-queue-readiness.md#manual-only-repowise-migration-2026-10-21-issue-639) +defines the 24-case regression floor, live required-check evidence, immutable +revision reporting, unchanged scan budgets and cleanup, operator journey, +failure/retry behavior and final-revision manual acceptance. This is a workflow +scheduling change with no setup-session, PAT, web UX or new configuration change. + The first [RepoWise run on `e197cb0c`](https://github.com/vypdev/copilot/actions/runs/37289899480) failed workflow validation before any job started. Its job-level `env` used `runner.temp`, which GitHub's [context availability table](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#context-availability) @@ -2613,8 +2624,9 @@ pass; the prior manual result does not substitute for it. recovery, and PAT cleanup/renewal guidance are linked and validated. - [ ] Build, lint, typecheck, coverage, architecture, workflow, package, documentation, catalog generation, and `validate:specifications` pass. -- [ ] Repository-owned CI and RepoWise run on self-hosted Ubuntu, fork PRs on - hosted Ubuntu, and the approval observer on self-hosted `codex`. +- [ ] Repository-owned CI and manual-only RepoWise run on self-hosted Ubuntu; + CI for fork PRs/merge groups runs on hosted Ubuntu, and the approval + observer runs on self-hosted `codex`. The self-hosted macOS, Ubuntu and Windows fixture matrix is manual only. npm publication remains hosted for Trusted Publishing. All six platform jobs pass their full fixture, package, coverage and validator contracts; diff --git a/specs/merge-queue-readiness.md b/specs/merge-queue-readiness.md index 3506bf285..5cdc3f774 100644 --- a/specs/merge-queue-readiness.md +++ b/specs/merge-queue-readiness.md @@ -4,7 +4,7 @@ complete; clean-tree bundle validation and controlled live queue validation remain external completion gates - Date: 2026-09-10 -- Last updated: 2026-09-15 +- Last updated: 2026-10-21 - Owners: `vypdev/copilot` product and engineering maintainers - Scope: discover the effective merge policy of every deployment target and prevent a managed pull request from entering an unusable merge queue. @@ -89,7 +89,11 @@ longer exhibit these behaviors. 6. Enqueueing does not pass GraphQL `expectedHeadOid`, and queue membership is not read before a retry. -### 2.3 Live repository evidence captured on 2026-09-10 +### 2.3 Historical repository evidence captured on 2026-09-10 + +The RepoWise required-check and automatic-trigger facts below are historical. +The manual-only migration below supersedes them; queue readiness still inspects +live effective rules rather than assuming that this snapshot remains current. - `GET /repos/vypdev/copilot/branches/master/protection` returned `404 Branch not protected` because no classic protection rule applies. @@ -116,6 +120,9 @@ longer exhibit these behaviors. ### Event-scoped advisory history correction (2026-10-14) +This event-range contract is retained as historical evidence. The manual-only +migration below retires the automatic event-base path. + Dogfooding [#496](https://github.com/vypdev/copilot/issues/496) reproduced a RepoWise 0.45.0 `MemoryError` while batch-reading all historical blobs in [run 38472995406](https://github.com/vypdev/copilot/actions/runs/38472995406). @@ -151,6 +158,88 @@ historical audit. Run workflow/specification/documentation validators and the workflow regression suite; no coverage threshold is reduced. A fresh exact-head run must prove the producer reaches artifact upload and reports any incomplete advisory scan honestly; it is still an open gate. + +### Manual-only RepoWise migration (2026-10-21, issue #639) + +RepoWise MUST run only through `workflow_dispatch`. PRs, pushes, merge groups, +schedules and reusable-workflow calls MUST NOT launch it. CI and merge queue +MUST complete without a RepoWise result. This supersedes the earlier required +RepoWise producer and event-range scanning contract, without changing runtime +queue-readiness policy or any consumer's required checks. + +Live GitHub inspection on 2026-10-21 found active repository ruleset +`25205979` (`Release automation required CI`) requiring only GitHub Actions +`CI Check` on both `master` and `develop`. Classic protection on `master` is +absent (404); classic protection on `develop` also requires only `CI Check`. +The old `Master Push Check` and `Develop Push Check` rulesets are disabled. +RepoWise therefore needs no live protection change for this migration. Operators +MUST recheck effective rules before rollout; if RepoWise becomes required again, +remove only that requirement before retiring automatic triggers, preserving all +other checks. A manual-only required producer remains unsupported by the existing +fail-closed merge-queue preflight; no attestation may bypass that known fact. + +```text +Maintainer -> Actions / RepoWise Code Health / Run workflow -> select reviewed ref + -> bounded analysis -> commit-bound Job Summary and report artifact +PR / push / merge group -> normal CI -> no RepoWise dependency +``` + +Text equivalent: maintainers explicitly select a reviewed repository branch and +inspect that run's summary and artifact; automatic change validation does not +start or await RepoWise. The native selector uses the repository default branch +unless another ref is selected. No new input, secret, runtime option or durable +application state is introduced. Dispatch is available because the workflow +already exists on the default branch. CLI example: +`gh workflow run repowise.yml --ref develop`. + +The workflow owns event admission, Ubuntu `codex` runner selection, read-only +contents permission and a 30-minute job budget. Checkout MUST retain the selected +revision and full history without credentials. Each advisory subprocess retains +its 90-second and 2 GiB limits; manual security scanning covers full reachable +history. Per-ref `repowise-` concurrency cancels an older manual run for the same +ref without sharing CI's group. Python environments and reports remain isolated +by run/attempt, with unconditional upload followed by cleanup. No domain, use +case, port, provider DTO or composition change is needed: the repository workflow +is the adapter boundary, enforced by the existing parsed-YAML contract validator. + +| Visible state | Meaning and next action | Retained evidence | +|---|---|---| +| Queued/running | Analysis requested; open this Actions run, no automatic CI wait | Native run/ref identity | +| Complete | Read `Analyzed revision: ` and download `repowise-code-health` | `revision.txt`, index log, health Markdown/JSON, advisory status; 14 days | +| Partial | `security: incomplete (exit )`; inspect the warning before retrying | Completed health reports remain; no complete-audit claim | +| Failed | A core setup/index/health step failed; inspect logs and retry after correction | Available files upload even after failure | +| Canceled | A newer run for the same ref replaced this one, or an operator canceled it | Native cancellation state; runner loss/cancellation can prevent upload | + +The existing English Job Summary adds only the immutable commit SHA; it does not +render an untrusted branch name. Native GitHub status and artifact links provide +navigation in narrow/light/dark views. There are no new bot comments or locale +inputs. Restoring automatic execution would require coordinated workflow, +contract, documentation and required-check review; restoring only a required +RepoWise rule would block change validation. + +Regression floor: **24 distinct workflow-contract cases**: one valid manual +dispatch, five forbidden automatic/reusable triggers, one missing dispatch, +seven budget/permission/checkout/concurrency mutations, one Ubuntu runner +selection, and nine scan/report/revision/summary/artifact mutations. Retain the +existing Python-isolation, cleanup and incomplete-scan cases and all repository +coverage thresholds. These deterministic YAML mutations cover admission, +execution bounds and reporting; runtime policy, localization and new provider +adapter tests are not applicable because those contracts do not change. + +Acceptance and traceability: + +| Observable requirement | Evidence | Documentation | +|---|---|---| +| Automatic events do not launch RepoWise | Parsed trigger mutations plus final-head PR run inventory | `docs/development/testing.mdx` | +| Manual selected-revision reports remain useful and bounded | Execution/report mutations plus final-head manual run and artifact | testing and self-hosted runner guides | +| CI/merge queue can complete independently | Live rules above, retained merge-group contracts and final-head CI | deployment and release-process guides | + +Run workflow regressions, workflow/documentation/specification validators, and +Graphify update. Completion requires a real manual run on the final revision and +review of its summary/artifact; a queued run or static test is insufficient. +Catalog evidence and the runner appendix in the setup-assistant SDD MUST agree. + +### Other merge-queue evidence from the original implementation - Copilot's own required PR context is produced for merge groups by the dedicated `copilot_pull_request_merge_queue.yml` workflow. Keeping that lightweight producer separate avoids a skipped duplicate check on every @@ -549,7 +638,6 @@ Queue rule: required Producer Source Evidence CI Check GitHub Actions Verified · ci_check.yml handles merge_group -RepoWise code health GitHub Actions Verified · repowise.yml handles merge_group No action required. Rerun `copilot doctor` after changing rules, workflows, or attestations and before the next release. diff --git a/src/tooling/__tests__/validate_workflow_contract.test.ts b/src/tooling/__tests__/validate_workflow_contract.test.ts index 6d4873010..2a6329c37 100644 --- a/src/tooling/__tests__/validate_workflow_contract.test.ts +++ b/src/tooling/__tests__/validate_workflow_contract.test.ts @@ -494,7 +494,6 @@ describe('workflow contract validator', () => { it.each([ '.github/workflows/ci_check.yml', - '.github/workflows/repowise.yml', '.github/workflows/copilot_pull_request_merge_queue.yml', 'setup/workflows/copilot_pull_request_merge_queue.yml', ])('requires merge-group checks in %s', (relativeFile) => { @@ -985,7 +984,6 @@ describe('workflow contract validator', () => { ['setup/workflows', 'copilot_credential_health.yml'], ['setup/workflows', 'copilot_issue.yml'], ['.github/workflows', 'ci_check.yml'], - ['.github/workflows', 'repowise.yml'], ])('prevents grouped routing from overriding the hosted/trust role in %s/%s', (directory, name) => { const { file, workflow } = loadMutationWorkflow(directory, name); Object.values(workflow.jobs)[0]['runs-on'] = { group: 'vypdev', labels: ['self-hosted', 'codex', 'Linux'] }; @@ -1270,9 +1268,6 @@ describe('workflow contract validator', () => { ['ci_check.yml', 'ci-check', 'pull_request', 'vypdev/copilot', '["self-hosted","codex","Linux"]'], ['ci_check.yml', 'ci-check', 'pull_request', 'outside/fork', '["ubuntu-latest"]'], ['ci_check.yml', 'ci-check', 'merge_group', 'vypdev/copilot', '["ubuntu-latest"]'], - ['repowise.yml', 'code-health', 'pull_request', 'vypdev/copilot', '["self-hosted","codex","Linux"]'], - ['repowise.yml', 'code-health', 'pull_request', 'outside/fork', '["ubuntu-latest"]'], - ['repowise.yml', 'code-health', 'merge_group', 'vypdev/copilot', '["ubuntu-latest"]'], ])('routes %s %s code from %s to %s', (fileName, jobId, eventName, headRepository, expectedRunner) => { const file = path.join(process.cwd(), '.github', 'workflows', fileName); const workflow = yaml.load(readFileSync(file, 'utf8')) as MutationWorkflow; @@ -1423,7 +1418,7 @@ describe('workflow contract validator', () => { } }); - it('bounds RepoWise advisory scans and preserves required health artifacts', () => { + it('bounds RepoWise advisory scans and preserves manual health artifacts', () => { const file = path.join(process.cwd(), '.github', 'workflows', 'repowise.yml'); const workflow = yaml.load(readFileSync(file, 'utf8')) as MutationWorkflow; const steps = workflow.jobs['code-health'].steps; @@ -1436,18 +1431,67 @@ describe('workflow contract validator', () => { expect(upload.if).toBe('${{ always() }}'); }); - it.each(['event-base', 'ancestry', 'range', 'manual-only'] as const)( - 'rejects loss of the RepoWise history scope boundary: %s', (boundary) => { - const file = path.join(process.cwd(), '.github', 'workflows', 'repowise.yml'); - const workflow = yaml.load(readFileSync(file, 'utf8')) as MutationWorkflow; + it('accepts RepoWise manual dispatch with native branch selection and isolated concurrency', () => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); + expect(workflow.on).toEqual({ workflow_dispatch: null }); + expect(workflow.concurrency).toEqual({ group: 'repowise-${{ github.ref }}', 'cancel-in-progress': true }); + expect(() => validateWorkflow(file, workflow)).not.toThrow(); + }); + + it.each(['push', 'pull_request', 'merge_group', 'workflow_call', 'schedule'])( + 'rejects the RepoWise automatic or reusable trigger %s', event => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); + workflow.on[event] = event === 'schedule' ? [{ cron: '0 0 * * *' }] : {}; + expect(() => validateWorkflow(file, workflow)).toThrow('must run only through workflow_dispatch'); + }, + ); + + it('rejects removal of RepoWise manual dispatch', () => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); + delete workflow.on.workflow_dispatch; + expect(() => validateWorkflow(file, workflow)).toThrow('must run only through workflow_dispatch'); + }); + + it.each(['timeout', 'permissions', 'job-permissions', 'history', 'selected-ref', 'concurrency', 'cancellation'])( + 'preserves the RepoWise manual execution boundary: %s', boundary => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); + const job = workflow.jobs['code-health']; + const checkout = job.steps.find((step: { uses?: string }) => step.uses === 'actions/checkout@v5'); + if (boundary === 'timeout') job['timeout-minutes'] = 60; + else if (boundary === 'permissions') workflow.permissions.contents = 'write'; + else if (boundary === 'job-permissions') job.permissions = { contents: 'write' }; + else if (boundary === 'history') checkout.with['fetch-depth'] = 1; + else if (boundary === 'selected-ref') checkout.with.ref = 'master'; + else if (boundary === 'concurrency') workflow.concurrency.group = 'ci-${{ github.ref }}'; + else workflow.concurrency['cancel-in-progress'] = false; + expect(() => validateWorkflow(file, workflow)).toThrow('manual job budget, read-only permissions, selected revision and per-ref concurrency'); + }, + ); + + it('keeps RepoWise manual runs on Ubuntu codex runners', () => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); + expect(workflow.jobs['code-health']['runs-on']).toEqual(['self-hosted', 'codex', 'Linux']); + expect(() => validateWorkflow(file, workflow)).not.toThrow(); + workflow.jobs['code-health']['runs-on'] = ['ubuntu-latest']; + expect(() => assertRunner(file, workflow)).toThrow('must use runs-on self-hosted, codex, Linux'); + }); + + it.each(['full-history', 'scan-budget', 'incomplete-status', 'revision-file', 'summary', 'upload', 'retention', 'health-md', 'health-json'])( + 'rejects loss of RepoWise manual report evidence: %s', boundary => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); expect(() => validateWorkflow(file, workflow)).not.toThrow(); const job = workflow.jobs['code-health']; const reports = job.steps.find((step: { name?: string }) => step.name === 'Generate RepoWise reports'); - if (boundary === 'event-base') job.env.REPOWISE_BASE_SHA = '${{ github.sha }}'; - else if (boundary === 'ancestry') reports.run = reports.run.replace('git merge-base --is-ancestor "$REPOWISE_BASE_SHA" HEAD', 'true'); - else if (boundary === 'range') reports.run = reports.run.replace('--since "$REPOWISE_BASE_SHA" --to HEAD', ''); - else reports.run = reports.run.replace('[ "$REPOWISE_EVENT_NAME" = workflow_dispatch ]', 'true'); - expect(() => validateWorkflow(file, workflow)).toThrow('event-scoped security history'); + const upload = job.steps.find((step: { name?: string }) => step.name === 'Upload RepoWise reports'); + if (boundary === 'full-history') reports.run = reports.run.replace('--history --path .', '--history --since HEAD --path .'); + else if (boundary === 'scan-budget') reports.run = reports.run.replace('ulimit -v 2097152;', ''); + else if (boundary === 'incomplete-status') reports.run = reports.run.replace('incomplete (exit %s)', 'complete'); + else if (boundary === 'revision-file') reports.run = reports.run.replace('> "$report_dir/revision.txt"', '> /dev/null'); + else if (boundary === 'summary') reports.run = reports.run.replace('>> "$GITHUB_STEP_SUMMARY"', '> /dev/null'); + else if (boundary === 'upload') delete upload.if; + else if (boundary === 'retention') upload.with['retention-days'] = 1; + else reports.run = reports.run.replace(`health --no-workspace --refactoring-targets --format ${boundary === 'health-md' ? 'md' : 'json'}`, 'status'); + expect(() => validateWorkflow(file, workflow)).toThrow('bounded manual history scans, health reports, revision evidence'); }, ); From ff3410bfa3e21022375d78bc130713e557fd7456 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 11:17:56 +0200 Subject: [PATCH 04/44] fix: diagnose unsupported stored configuration with safe recovery --- build/api/index.js | 13 ++ .../api/src/data/model/application_error.d.ts | 15 +- build/cli/index.js | 112 ++++++++++++- build/github_action/index.js | 123 +++++++++++++-- docs/configuration.mdx | 8 + .../operations/error-reference.mdx | 10 ++ .../operations/troubleshooting.mdx | 35 +++++ specs/CATALOG.md | 10 +- specs/catalog.json | 15 +- .../execution-error-and-context-hardening.md | 102 ++++++++++++ src/actions/__tests__/github_action.test.ts | 43 +++++ src/actions/github_action.ts | 12 +- .../__tests__/application_error.test.ts | 12 ++ ...lication_error_presentation_policy.test.ts | 7 + .../application_error_message_catalog.ts | 35 +++++ .../application_error_presentation_policy.ts | 7 +- src/data/model/application_error.ts | 17 ++ .../repository/github/github_error_policy.ts | 14 ++ .../issue_content_repository.test.ts | 29 +++- .../issue/issue_content_repository.ts | 7 +- .../__tests__/configuration_handler.test.ts | 7 +- .../__tests__/configuration_recovery.test.ts | 147 ++++++++++++++++++ .../description/configuration_handler.ts | 39 ++++- 23 files changed, 776 insertions(+), 43 deletions(-) create mode 100644 src/manager/description/__tests__/configuration_recovery.test.ts diff --git a/build/api/index.js b/build/api/index.js index ca974bedf..02582bbcd 100644 --- a/build/api/index.js +++ b/build/api/index.js @@ -5171,6 +5171,9 @@ exports.APPLICATION_ERROR_RECOVERY_IDS = Object.freeze([ 'workspace-changes-rejected', 'closed-issue-reconciliation-failed', 'approval-evidence-read-failed', + 'stored-configuration-schema-missing', + 'stored-configuration-schema-unsupported', + 'stored-configuration-invalid', ]); const PRESERVED_STATE = 'Existing persisted state and completed external effects were preserved.'; const UNCHANGED_STATE = 'No new state or external effect was created.'; @@ -5362,6 +5365,9 @@ class ApplicationError extends Error { exports.ApplicationError = ApplicationError; _ApplicationError_cause = new WeakMap(); const RECOVERY_VARIABLE_KEYS = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze(['issueNumber', 'expectedVersion']), + 'stored-configuration-schema-unsupported': Object.freeze(['issueNumber', 'expectedVersion', 'actualVersion']), + 'stored-configuration-invalid': Object.freeze(['issueNumber', 'expectedVersion']), 'closed-issue-reconciliation-failed': Object.freeze(['resultId', 'phase', 'state', 'reason', 'changed', 'remaining']), 'approval-evidence-read-failed': Object.freeze(['operation', 'reason', 'permission']), 'pull-request-link-restored': Object.freeze([]), @@ -5391,6 +5397,13 @@ function normalizeApplicationErrorRecovery(recovery) { || actualKeys.some((key, index) => key !== expectedKeys[index])) { throw new TypeError(`Application error recovery variables are invalid for ${recovery.id}.`); } + if (recovery.id.startsWith('stored-configuration-') + && (![variables.issueNumber, variables.expectedVersion].every(value => typeof value === 'number' && Number.isSafeInteger(value) && value > 0) + || (recovery.id === 'stored-configuration-schema-unsupported' + && !(typeof variables.actualVersion === 'number' + && Number.isSafeInteger(variables.actualVersion) && variables.actualVersion >= 0)))) { + throw new TypeError('Stored configuration diagnostic is invalid.'); + } if (recovery.id === 'managed-branch-enrichment-failed' && (typeof variables.branchName !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/u.test(variables.branchName))) { diff --git a/build/api/src/data/model/application_error.d.ts b/build/api/src/data/model/application_error.d.ts index bd017218f..63bbe93cb 100644 --- a/build/api/src/data/model/application_error.d.ts +++ b/build/api/src/data/model/application_error.d.ts @@ -3,9 +3,22 @@ import { type ApprovalEvidenceDiagnostic } from '../../domain/approval_evidence_ import { type BranchSyncValidationCode } from '../../domain/branch_sync_validation'; export type ApplicationErrorKind = 'configuration' | 'authorization' | 'provider' | 'agent' | 'validation' | 'workflow' | 'unknown'; export type ApplicationErrorCode = 'configuration.invalid' | 'configuration.unsupported' | 'authorization.denied' | 'authorization.credential-invalid' | 'provider.not-found' | 'provider.conflict' | 'provider.rate-limited' | 'provider.unavailable' | 'provider.contract-invalid' | 'agent.policy-rejected' | 'agent.failed' | 'locale.output-invalid' | 'locale.translation-failed' | 'validation.invalid-input' | 'validation.evidence-too-large' | 'validation.evidence-unavailable' | 'workflow.invalid-event' | 'workflow.stale' | 'workflow.cancelled' | 'workflow.failed' | 'workflow.presentation-pending' | 'timeout' | 'unexpected'; -export declare const APPLICATION_ERROR_RECOVERY_IDS: readonly ["pull-request-link-restored", "pull-request-link-base-retained", "pull-request-link-reference-retained", "pull-request-link-base-and-reference-retained", "managed-branch-enrichment-failed", "inactivity-explanation-failed", "bugbot-review-blocks-pending", "branch-sync-agent-disabled", "branch-sync-fixer-unavailable", "branch-sync-resolution-invalid", "sdd-draft-size-exceeded", "sdd-draft-format-invalid", "workspace-changes-rejected", "closed-issue-reconciliation-failed", "approval-evidence-read-failed"]; +export declare const APPLICATION_ERROR_RECOVERY_IDS: readonly ["pull-request-link-restored", "pull-request-link-base-retained", "pull-request-link-reference-retained", "pull-request-link-base-and-reference-retained", "managed-branch-enrichment-failed", "inactivity-explanation-failed", "bugbot-review-blocks-pending", "branch-sync-agent-disabled", "branch-sync-fixer-unavailable", "branch-sync-resolution-invalid", "sdd-draft-size-exceeded", "sdd-draft-format-invalid", "workspace-changes-rejected", "closed-issue-reconciliation-failed", "approval-evidence-read-failed", "stored-configuration-schema-missing", "stored-configuration-schema-unsupported", "stored-configuration-invalid"]; export type ApplicationErrorRecoveryId = typeof APPLICATION_ERROR_RECOVERY_IDS[number]; interface ApplicationErrorRecoveryVariables { + readonly 'stored-configuration-schema-missing': Readonly<{ + issueNumber: number; + expectedVersion: number; + }>; + readonly 'stored-configuration-schema-unsupported': Readonly<{ + issueNumber: number; + expectedVersion: number; + actualVersion: number; + }>; + readonly 'stored-configuration-invalid': Readonly<{ + issueNumber: number; + expectedVersion: number; + }>; readonly 'closed-issue-reconciliation-failed': ClosedIssueReconciliationFacts; readonly 'approval-evidence-read-failed': ApprovalEvidenceDiagnostic; readonly 'pull-request-link-restored': Readonly>; diff --git a/build/cli/index.js b/build/cli/index.js index c85895d11..addfe08bd 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -39313,7 +39313,26 @@ const SPANISH_CONTENT = Object.freeze({ retainedState: PRESERVED_STATE_ES, }), }); +const STORED_CONFIGURATION_ACTION_EN = 'A maintainer must review {recoveryGuide}. Preserve a copy before removing only a verified obsolete unmanaged block. If managed branch, release, hotfix or orchestration state may exist, stop and restore verified supported state with a maintainer. Do not just add a schema version or delete managed state. Correct the configuration before rerunning; retrying unchanged state will fail again.'; +const STORED_CONFIGURATION_ACTION_ES = 'Un mantenedor debe revisar {recoveryGuide}. Conserva una copia antes de retirar solo un bloque obsoleto confirmado como no gestionado. Si puede existir estado gestionado de ramas, releases, hotfixes u orquestación, detente y restaura estado compatible verificado con un mantenedor. No añadas simplemente una versión de esquema ni borres estado gestionado. Corrige la configuración antes de reejecutar; el mismo estado volverá a fallar.'; +const STORED_CONFIGURATION_RETAINED_EN = 'The issue/PR description and stored configuration were not changed by this read.'; +const STORED_CONFIGURATION_RETAINED_ES = 'Esta lectura no modificó la descripción de la issue/PR ni su configuración almacenada.'; const ENGLISH_RECOVERY_CONTENT = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: the stored configuration has no schema version; version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), + 'stored-configuration-schema-unsupported': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: stored schema version {actualVersion} is unsupported; version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), + 'stored-configuration-invalid': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: the stored configuration, markers or schema value are malformed; valid schema version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), 'closed-issue-reconciliation-failed': Object.freeze({ impact: 'Issue cleanup remains unverified: {resultId}, phase {phase}; native state {state}, reason {reason}.', action: 'Inspect the closed-issue or merged-PR run and current native state. Retry cleanup only if the issue is still closed with the intended reason; leave reopened work open. Resolve the named failure before retrying.', @@ -39391,6 +39410,21 @@ const ENGLISH_RECOVERY_CONTENT = Object.freeze({ }), }); const SPANISH_RECOVERY_CONTENT = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la configuración almacenada no tiene versión de esquema; se requiere la versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), + 'stored-configuration-schema-unsupported': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la versión de esquema almacenada {actualVersion} no es compatible; se requiere la versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), + 'stored-configuration-invalid': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la configuración almacenada, sus delimitadores o el valor del esquema no son válidos; se requiere un esquema válido de versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), 'closed-issue-reconciliation-failed': Object.freeze({ impact: 'La limpieza de la issue sigue sin verificarse: {resultId}, fase {phase}; estado nativo {state}, motivo {reason}.', action: 'Revisa la ejecución de cierre o de la PR fusionada y el estado nativo actual. Reintenta la limpieza solo si la issue sigue cerrada con el motivo previsto; conserva abierto el trabajo reabierto. Resuelve el fallo indicado antes de reintentar.', @@ -39520,12 +39554,16 @@ exports.buildApplicationErrorPresentation = buildApplicationErrorPresentation; exports.renderApplicationErrorText = renderApplicationErrorText; exports.renderApplicationErrorMarkdown = renderApplicationErrorMarkdown; const application_error_message_catalog_1 = __nccwpck_require__(64809); +// This trusted destination is inserted after localization, never supplied by a body or translation. +const STORED_CONFIGURATION_RECOVERY_URL = 'https://docs.page/vypdev/copilot/security-operations/operations/troubleshooting#unsupported-stored-configuration'; /** Shared semantic view model for terminal, GitHub, and API presentation. */ function buildApplicationErrorPresentation(error, message = application_error_message_catalog_1.readEnglishApplicationErrorMessage) { const descriptor = error.recovery ? `error.recovery.${error.recovery.id}` : `error.${error.code}`; - const variables = error.recovery?.variables; + const variables = error.recovery?.id.startsWith('stored-configuration-') + ? { ...error.recovery.variables, recoveryGuide: STORED_CONFIGURATION_RECOVERY_URL } + : error.recovery?.variables; return { impact: message(`${descriptor}.impact`, variables), code: error.code, @@ -78373,6 +78411,9 @@ exports.APPLICATION_ERROR_RECOVERY_IDS = Object.freeze([ 'workspace-changes-rejected', 'closed-issue-reconciliation-failed', 'approval-evidence-read-failed', + 'stored-configuration-schema-missing', + 'stored-configuration-schema-unsupported', + 'stored-configuration-invalid', ]); const PRESERVED_STATE = 'Existing persisted state and completed external effects were preserved.'; const UNCHANGED_STATE = 'No new state or external effect was created.'; @@ -78564,6 +78605,9 @@ class ApplicationError extends Error { exports.ApplicationError = ApplicationError; _ApplicationError_cause = new WeakMap(); const RECOVERY_VARIABLE_KEYS = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze(['issueNumber', 'expectedVersion']), + 'stored-configuration-schema-unsupported': Object.freeze(['issueNumber', 'expectedVersion', 'actualVersion']), + 'stored-configuration-invalid': Object.freeze(['issueNumber', 'expectedVersion']), 'closed-issue-reconciliation-failed': Object.freeze(['resultId', 'phase', 'state', 'reason', 'changed', 'remaining']), 'approval-evidence-read-failed': Object.freeze(['operation', 'reason', 'permission']), 'pull-request-link-restored': Object.freeze([]), @@ -78593,6 +78637,13 @@ function normalizeApplicationErrorRecovery(recovery) { || actualKeys.some((key, index) => key !== expectedKeys[index])) { throw new TypeError(`Application error recovery variables are invalid for ${recovery.id}.`); } + if (recovery.id.startsWith('stored-configuration-') + && (![variables.issueNumber, variables.expectedVersion].every(value => typeof value === 'number' && Number.isSafeInteger(value) && value > 0) + || (recovery.id === 'stored-configuration-schema-unsupported' + && !(typeof variables.actualVersion === 'number' + && Number.isSafeInteger(variables.actualVersion) && variables.actualVersion >= 0)))) { + throw new TypeError('Stored configuration diagnostic is invalid.'); + } if (recovery.id === 'managed-branch-enrichment-failed' && (typeof variables.branchName !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/u.test(variables.branchName))) { @@ -83899,6 +83950,7 @@ function combineOrganizationAccess(secrets, variables) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isGithubAlreadyExists = exports.isGithubPermissionDenied = exports.isGithubRateLimited = exports.isGithubNotFound = exports.getGithubErrorStatus = void 0; +exports.githubReadErrorCode = githubReadErrorCode; const getGithubErrorStatus = (error) => { if (typeof error !== "object" || error === null) return undefined; @@ -83908,6 +83960,23 @@ const getGithubErrorStatus = (error) => { exports.getGithubErrorStatus = getGithubErrorStatus; const isGithubNotFound = (error) => (0, exports.getGithubErrorStatus)(error) === 404; exports.isGithubNotFound = isGithubNotFound; +/** Maps failed metadata reads without copying untrusted provider text. */ +function githubReadErrorCode(error) { + const status = (0, exports.getGithubErrorStatus)(error); + if (status === 401) + return 'authorization.credential-invalid'; + if ((0, exports.isGithubRateLimited)(error)) + return 'provider.rate-limited'; + if (status === 403) + return 'authorization.denied'; + if (status === 404) + return 'provider.not-found'; + if (status === 409 || status === 412) + return 'provider.conflict'; + if (status === 400 || status === 422) + return 'provider.contract-invalid'; + return 'provider.unavailable'; +} const isGithubRateLimited = (error) => { const status = (0, exports.getGithubErrorStatus)(error); if (status === 429) @@ -84618,8 +84687,9 @@ class IssueContentRepository { return issue.body ?? ''; } catch (error) { - (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', `Unable to read issue #${issueNumber} description.`)); - throw error; + const semanticError = (0, application_error_1.toApplicationError)(error, (0, github_error_policy_1.githubReadErrorCode)(error), 'Unable to read the issue or pull-request description.'); + (0, logger_1.logError)(semanticError); + throw semanticError; } }; this.getIssueDescription = async (owner, repository, issueNumber, token) => { @@ -102753,18 +102823,44 @@ class ConfigurationHandler extends issue_content_interface_1.IssueContentInterfa return this.internalUpdate(query, (0, configuration_payload_policy_1.buildConfigurationPayload)(context, storedRaw)); }; this.get = async (query) => { + let description; + try { + description = await this.issueDescriptionPort.getDescription(query.owner, query.repository, query.issueNumber, query.token); + } + catch (cause) { + const semanticError = (0, application_error_1.toApplicationError)(cause, 'provider.unavailable', 'Unable to read issue configuration.'); + (0, logger_1.logError)(semanticError); + throw semanticError; + } + const variables = { issueNumber: query.issueNumber, expectedVersion: config_1.CONFIG_SCHEMA_VERSION }; + let recovery = { id: 'stored-configuration-invalid', variables }; try { - const description = await this.issueDescriptionPort.getDescription(query.owner, query.repository, query.issueNumber, query.token); const config = this.getContent(description); if (config === undefined) { + if (description?.includes('')) { + throw new Error('Stored configuration markers are inconsistent.'); + } return undefined; } - const branchConfig = (0, config_1.requireCurrentConfigurationPayload)(JSON.parse(config)); + const parsed = JSON.parse(config); + if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) { + const version = parsed.schemaVersion; + if (version === undefined) { + recovery = { id: 'stored-configuration-schema-missing', variables }; + } + else if (typeof version === 'number' && Number.isSafeInteger(version) + && version >= 0 && version !== config_1.CONFIG_SCHEMA_VERSION) { + recovery = { id: 'stored-configuration-schema-unsupported', variables: { ...variables, actualVersion: version } }; + } + } + const branchConfig = (0, config_1.requireCurrentConfigurationPayload)(parsed); return new config_1.Config(branchConfig); } - catch (error) { - (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'configuration.invalid', 'Unable to read issue configuration.')); - throw error; + catch (cause) { + const semanticError = (0, application_error_1.toApplicationError)(cause, 'configuration.invalid', 'Stored issue/PR configuration is invalid.', { recovery }); + (0, logger_1.logError)(semanticError); + throw semanticError; } }; } diff --git a/build/github_action/index.js b/build/github_action/index.js index fc8a49c6b..9cd6d5ace 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -37081,7 +37081,16 @@ async function runGitHubActionEntry(run = runGitHubAction) { catch (cause) { const semanticError = (0, application_error_1.toApplicationError)(cause, 'workflow.failed', 'GitHub Action execution failed.'); (0, logger_1.logError)(semanticError); - core.setFailed((0, application_error_presentation_policy_1.renderApplicationErrorText)(semanticError, earlyGithubActionErrorMessage())); + const message = earlyGithubActionErrorMessage(); + core.setFailed((0, application_error_presentation_policy_1.renderApplicationErrorText)(semanticError, message)); + if (semanticError.recovery?.id.startsWith('stored-configuration-')) { + try { + await (0, github_action_summary_composition_root_1.createGithubActionSummaryCompositionRoot)().publish((0, application_error_presentation_policy_1.renderApplicationErrorMarkdown)(semanticError, message)); + } + catch (summaryCause) { + (0, logger_1.logError)((0, application_error_1.toApplicationError)(summaryCause, 'provider.unavailable', 'Unable to publish the configuration failure summary.')); + } + } } }); } @@ -40666,7 +40675,26 @@ const SPANISH_CONTENT = Object.freeze({ retainedState: PRESERVED_STATE_ES, }), }); +const STORED_CONFIGURATION_ACTION_EN = 'A maintainer must review {recoveryGuide}. Preserve a copy before removing only a verified obsolete unmanaged block. If managed branch, release, hotfix or orchestration state may exist, stop and restore verified supported state with a maintainer. Do not just add a schema version or delete managed state. Correct the configuration before rerunning; retrying unchanged state will fail again.'; +const STORED_CONFIGURATION_ACTION_ES = 'Un mantenedor debe revisar {recoveryGuide}. Conserva una copia antes de retirar solo un bloque obsoleto confirmado como no gestionado. Si puede existir estado gestionado de ramas, releases, hotfixes u orquestación, detente y restaura estado compatible verificado con un mantenedor. No añadas simplemente una versión de esquema ni borres estado gestionado. Corrige la configuración antes de reejecutar; el mismo estado volverá a fallar.'; +const STORED_CONFIGURATION_RETAINED_EN = 'The issue/PR description and stored configuration were not changed by this read.'; +const STORED_CONFIGURATION_RETAINED_ES = 'Esta lectura no modificó la descripción de la issue/PR ni su configuración almacenada.'; const ENGLISH_RECOVERY_CONTENT = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: the stored configuration has no schema version; version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), + 'stored-configuration-schema-unsupported': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: stored schema version {actualVersion} is unsupported; version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), + 'stored-configuration-invalid': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: the stored configuration, markers or schema value are malformed; valid schema version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), 'closed-issue-reconciliation-failed': Object.freeze({ impact: 'Issue cleanup remains unverified: {resultId}, phase {phase}; native state {state}, reason {reason}.', action: 'Inspect the closed-issue or merged-PR run and current native state. Retry cleanup only if the issue is still closed with the intended reason; leave reopened work open. Resolve the named failure before retrying.', @@ -40744,6 +40772,21 @@ const ENGLISH_RECOVERY_CONTENT = Object.freeze({ }), }); const SPANISH_RECOVERY_CONTENT = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la configuración almacenada no tiene versión de esquema; se requiere la versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), + 'stored-configuration-schema-unsupported': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la versión de esquema almacenada {actualVersion} no es compatible; se requiere la versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), + 'stored-configuration-invalid': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la configuración almacenada, sus delimitadores o el valor del esquema no son válidos; se requiere un esquema válido de versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), 'closed-issue-reconciliation-failed': Object.freeze({ impact: 'La limpieza de la issue sigue sin verificarse: {resultId}, fase {phase}; estado nativo {state}, motivo {reason}.', action: 'Revisa la ejecución de cierre o de la PR fusionada y el estado nativo actual. Reintenta la limpieza solo si la issue sigue cerrada con el motivo previsto; conserva abierto el trabajo reabierto. Resuelve el fallo indicado antes de reintentar.', @@ -40873,12 +40916,16 @@ exports.buildApplicationErrorPresentation = buildApplicationErrorPresentation; exports.renderApplicationErrorText = renderApplicationErrorText; exports.renderApplicationErrorMarkdown = renderApplicationErrorMarkdown; const application_error_message_catalog_1 = __nccwpck_require__(64809); +// This trusted destination is inserted after localization, never supplied by a body or translation. +const STORED_CONFIGURATION_RECOVERY_URL = 'https://docs.page/vypdev/copilot/security-operations/operations/troubleshooting#unsupported-stored-configuration'; /** Shared semantic view model for terminal, GitHub, and API presentation. */ function buildApplicationErrorPresentation(error, message = application_error_message_catalog_1.readEnglishApplicationErrorMessage) { const descriptor = error.recovery ? `error.recovery.${error.recovery.id}` : `error.${error.code}`; - const variables = error.recovery?.variables; + const variables = error.recovery?.id.startsWith('stored-configuration-') + ? { ...error.recovery.variables, recoveryGuide: STORED_CONFIGURATION_RECOVERY_URL } + : error.recovery?.variables; return { impact: message(`${descriptor}.impact`, variables), code: error.code, @@ -68788,6 +68835,9 @@ exports.APPLICATION_ERROR_RECOVERY_IDS = Object.freeze([ 'workspace-changes-rejected', 'closed-issue-reconciliation-failed', 'approval-evidence-read-failed', + 'stored-configuration-schema-missing', + 'stored-configuration-schema-unsupported', + 'stored-configuration-invalid', ]); const PRESERVED_STATE = 'Existing persisted state and completed external effects were preserved.'; const UNCHANGED_STATE = 'No new state or external effect was created.'; @@ -68979,6 +69029,9 @@ class ApplicationError extends Error { exports.ApplicationError = ApplicationError; _ApplicationError_cause = new WeakMap(); const RECOVERY_VARIABLE_KEYS = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze(['issueNumber', 'expectedVersion']), + 'stored-configuration-schema-unsupported': Object.freeze(['issueNumber', 'expectedVersion', 'actualVersion']), + 'stored-configuration-invalid': Object.freeze(['issueNumber', 'expectedVersion']), 'closed-issue-reconciliation-failed': Object.freeze(['resultId', 'phase', 'state', 'reason', 'changed', 'remaining']), 'approval-evidence-read-failed': Object.freeze(['operation', 'reason', 'permission']), 'pull-request-link-restored': Object.freeze([]), @@ -69008,6 +69061,13 @@ function normalizeApplicationErrorRecovery(recovery) { || actualKeys.some((key, index) => key !== expectedKeys[index])) { throw new TypeError(`Application error recovery variables are invalid for ${recovery.id}.`); } + if (recovery.id.startsWith('stored-configuration-') + && (![variables.issueNumber, variables.expectedVersion].every(value => typeof value === 'number' && Number.isSafeInteger(value) && value > 0) + || (recovery.id === 'stored-configuration-schema-unsupported' + && !(typeof variables.actualVersion === 'number' + && Number.isSafeInteger(variables.actualVersion) && variables.actualVersion >= 0)))) { + throw new TypeError('Stored configuration diagnostic is invalid.'); + } if (recovery.id === 'managed-branch-enrichment-failed' && (typeof variables.branchName !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/u.test(variables.branchName))) { @@ -74451,6 +74511,7 @@ function combineOrganizationAccess(secrets, variables) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isGithubAlreadyExists = exports.isGithubPermissionDenied = exports.isGithubRateLimited = exports.isGithubNotFound = exports.getGithubErrorStatus = void 0; +exports.githubReadErrorCode = githubReadErrorCode; const getGithubErrorStatus = (error) => { if (typeof error !== "object" || error === null) return undefined; @@ -74460,6 +74521,23 @@ const getGithubErrorStatus = (error) => { exports.getGithubErrorStatus = getGithubErrorStatus; const isGithubNotFound = (error) => (0, exports.getGithubErrorStatus)(error) === 404; exports.isGithubNotFound = isGithubNotFound; +/** Maps failed metadata reads without copying untrusted provider text. */ +function githubReadErrorCode(error) { + const status = (0, exports.getGithubErrorStatus)(error); + if (status === 401) + return 'authorization.credential-invalid'; + if ((0, exports.isGithubRateLimited)(error)) + return 'provider.rate-limited'; + if (status === 403) + return 'authorization.denied'; + if (status === 404) + return 'provider.not-found'; + if (status === 409 || status === 412) + return 'provider.conflict'; + if (status === 400 || status === 422) + return 'provider.contract-invalid'; + return 'provider.unavailable'; +} const isGithubRateLimited = (error) => { const status = (0, exports.getGithubErrorStatus)(error); if (status === 429) @@ -75170,8 +75248,9 @@ class IssueContentRepository { return issue.body ?? ''; } catch (error) { - (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', `Unable to read issue #${issueNumber} description.`)); - throw error; + const semanticError = (0, application_error_1.toApplicationError)(error, (0, github_error_policy_1.githubReadErrorCode)(error), 'Unable to read the issue or pull-request description.'); + (0, logger_1.logError)(semanticError); + throw semanticError; } }; this.getIssueDescription = async (owner, repository, issueNumber, token) => { @@ -88967,18 +89046,44 @@ class ConfigurationHandler extends issue_content_interface_1.IssueContentInterfa return this.internalUpdate(query, (0, configuration_payload_policy_1.buildConfigurationPayload)(context, storedRaw)); }; this.get = async (query) => { + let description; + try { + description = await this.issueDescriptionPort.getDescription(query.owner, query.repository, query.issueNumber, query.token); + } + catch (cause) { + const semanticError = (0, application_error_1.toApplicationError)(cause, 'provider.unavailable', 'Unable to read issue configuration.'); + (0, logger_1.logError)(semanticError); + throw semanticError; + } + const variables = { issueNumber: query.issueNumber, expectedVersion: config_1.CONFIG_SCHEMA_VERSION }; + let recovery = { id: 'stored-configuration-invalid', variables }; try { - const description = await this.issueDescriptionPort.getDescription(query.owner, query.repository, query.issueNumber, query.token); const config = this.getContent(description); if (config === undefined) { + if (description?.includes('')) { + throw new Error('Stored configuration markers are inconsistent.'); + } return undefined; } - const branchConfig = (0, config_1.requireCurrentConfigurationPayload)(JSON.parse(config)); + const parsed = JSON.parse(config); + if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) { + const version = parsed.schemaVersion; + if (version === undefined) { + recovery = { id: 'stored-configuration-schema-missing', variables }; + } + else if (typeof version === 'number' && Number.isSafeInteger(version) + && version >= 0 && version !== config_1.CONFIG_SCHEMA_VERSION) { + recovery = { id: 'stored-configuration-schema-unsupported', variables: { ...variables, actualVersion: version } }; + } + } + const branchConfig = (0, config_1.requireCurrentConfigurationPayload)(parsed); return new config_1.Config(branchConfig); } - catch (error) { - (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'configuration.invalid', 'Unable to read issue configuration.')); - throw error; + catch (cause) { + const semanticError = (0, application_error_1.toApplicationError)(cause, 'configuration.invalid', 'Stored issue/PR configuration is invalid.', { recovery }); + (0, logger_1.logError)(semanticError); + throw semanticError; } }; } diff --git a/docs/configuration.mdx b/docs/configuration.mdx index 555c142eb..a987ad8aa 100644 --- a/docs/configuration.mdx +++ b/docs/configuration.mdx @@ -326,6 +326,14 @@ When updating the configuration (for example, after a push or label change), Cop The hidden block is owned by Copilot. Do not add third-party or manually managed keys to it; they are outside the contract and will be removed on the next write. +An invalid stored block fails with `configuration.invalid` and is not retryable +without correction. Its diagnostic identifies the issue/PR, distinguishes a +missing schema from an unsupported version or malformed state, and states the +required version. An absent block remains distinct from invalid stored state. +Follow [stored-configuration recovery](/security-operations/operations/troubleshooting#unsupported-stored-configuration) +before editing or removing a block; never add a version number merely to bypass +validation. No automatic migration or reset is performed. + ### Persistence failures If GitHub cannot read or update the issue description, the run fails closed after diff --git a/docs/security-operations/operations/error-reference.mdx b/docs/security-operations/operations/error-reference.mdx index 110dd972f..fb122c06a 100644 --- a/docs/security-operations/operations/error-reference.mdx +++ b/docs/security-operations/operations/error-reference.mdx @@ -41,6 +41,16 @@ Retryability is determined by the code. A specific operation can make a normally retryable failure terminal, but presentation never turns a terminal code into a retry recommendation. +For stored issue/PR state, `configuration.invalid` includes the affected number, +the expected schema version, and a missing-schema, unsupported-version or +malformed-content diagnosis in the failure annotation and Job Summary. It +remains nonretryable until corrected; the same correlation reference survives +to the final Action failure. The read does not rewrite the body. Use +[stored-configuration recovery](/security-operations/operations/troubleshooting#unsupported-stored-configuration): +only a verified obsolete unmanaged block may be removed after preserving a +copy. Potentially valuable managed state requires maintainer review and verified +restoration. Provider/authentication failures are not schema failures. + Some partial operations add a closed recovery variant, for example to name a retained managed branch or a closed issue whose final explanation was not published. These variants use reviewed catalog templates and only bounded, diff --git a/docs/security-operations/operations/troubleshooting.mdx b/docs/security-operations/operations/troubleshooting.mdx index 737179f10..d8f38bd1a 100644 --- a/docs/security-operations/operations/troubleshooting.mdx +++ b/docs/security-operations/operations/troubleshooting.mdx @@ -548,3 +548,38 @@ When current-repository organization reuse reports configuration/access changed after review, inspect the credential-health workflow too. Its installation or removal changes required bootstrap permissions. Prepare and approve a fresh plan instead of applying a previously audited permission set. + +## Unsupported stored configuration + +An issue or PR with an invalid stored Copilot block stops with +`configuration.invalid` and **Retryable: No**. The annotation and Job Summary +identify its number, the missing/unsupported/malformed state, the required +schema version (currently `3`), and the same reference. Retrying unchanged state +will fail again. The failed read does not change the body or stored state. + +| Stored content | Meaning | Next action | +|---|---|---| +| No Copilot block | No previous state to restore | An unlinked PR can follow its normal PR workflow. | +| Missing schema, unsupported version, malformed JSON/value or incomplete delimiters | Stored state cannot be trusted | A maintainer must review it before retrying. | +| Valid current-schema block | Supported state | Continue through normal validation; this is not a reset instruction. | + +Recovery is manual and depends on what the block owns: + +1. Preserve the original body using GitHub history or a copy before editing. +2. If a maintainer verifies that the issue/PR is unmanaged and the block is + only an obsolete marker with no branch, release, hotfix or orchestration + state to retain, remove **only that block**, preserve the human description, + and rerun the failed workflow. An obsolete reproduction example can instead + show its JSON without live Copilot comment delimiters: the current reader + also recognizes those delimiters inside fenced issue/PR examples. +3. If managed state may exist or ownership is unclear, stop. Ask a maintainer + to inspect linked branches and operations and restore verified supported + state through the supported workflow before rerunning. Do not discard + unknown state. + +Never repair this by merely adding `schemaVersion: 3`, changing a version number, +automatically migrating/resetting state, or turning the failed check into a +successful skip. A version field alone does not prove that the stored branch or +operation facts are valid. Authorization and temporary GitHub read failures +retain their own error categories; follow their permission/provider recovery +instead of deleting configuration. diff --git a/specs/CATALOG.md b/specs/CATALOG.md index b5608fbec..42b05c721 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -14,7 +14,7 @@ debt or convert unknown historic intent into a design decision. | `release-orchestration` | Implemented | Release and hotfix promotion, publication, bounded merge readiness recovery, and receipt-verified reconciliation without republication | [Configurable production-first release orchestration](./configurable-release-orchestration.md) + 2 companion | 59 paths · 2026-10-16 | | `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 24 paths · 2026-10-15 | | `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 59 paths · 2026-10-11 | -| `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 97 paths · 2026-10-14 | +| `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 104 paths · 2026-10-21 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | | `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 5 companion | 326 paths · 2026-10-20 | | `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 1 companion | 238 paths · 2026-10-20 | @@ -81,13 +81,13 @@ debt or convert unknown historic intent into a design decision. ### `execution-lifecycle` — Execution admission, queueing, routing, and result publication - Owner: Copilot maintainers -- Last verified: 2026-10-14 +- Last verified: 2026-10-21 - Specifications: [`specs/execution-admission-queue-and-publication.md`](./execution-admission-queue-and-publication.md) · [`specs/execution-error-and-context-hardening.md`](./execution-error-and-context-hardening.md) · [`specs/execution-boundary-closure-audit.md`](./execution-boundary-closure-audit.md) · [`specs/push-and-single-action-context-hardening.md`](./push-and-single-action-context-hardening.md) - Workflows: [`.github/workflows/copilot_issue.yml`](../.github/workflows/copilot_issue.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_pull_request.yml`](../.github/workflows/copilot_pull_request.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) · [`.github/workflows/copilot_commit.yml`](../.github/workflows/copilot_commit.yml) - Entrypoints: [`src/actions/github_action.ts`](../src/actions/github_action.ts) · [`src/actions/common_action.ts`](../src/actions/common_action.ts) -- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/validate-coverage-budgets.cjs`](../scripts/validate-coverage-budgets.cjs) · [`src/actions/main_run_lifecycle.ts`](../src/actions/main_run_lifecycle.ts) · [`src/actions/main_run_route.ts`](../src/actions/main_run_route.ts) · [`src/actions/github_action_completion.ts`](../src/actions/github_action_completion.ts) · [`src/api.ts`](../src/api.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/errors/application_error.ts`](../src/application/errors/application_error.ts) · [`src/application/errors/application_error_context.ts`](../src/application/errors/application_error_context.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/application/policies/application_error_presentation_policy.ts`](../src/application/policies/application_error_presentation_policy.ts) · [`src/application/policies/bugbot_result_finding_state_projection_policy.ts`](../src/application/policies/bugbot_result_finding_state_projection_policy.ts) · [`src/application/policies/bugbot_telemetry_projection_policy.ts`](../src/application/policies/bugbot_telemetry_projection_policy.ts) · [`src/application/policies/action_summary_policy.ts`](../src/application/policies/action_summary_policy.ts) · [`src/application/policies/copilot_evidence_policy.ts`](../src/application/policies/copilot_evidence_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/policies/github_execution_admission_policy.ts`](../src/application/policies/github_execution_admission_policy.ts) · [`src/application/policies/workflow_queue_policy.ts`](../src/application/policies/workflow_queue_policy.ts) · [`src/application/usecases/actions/lifecycle_synchronization_context.ts`](../src/application/usecases/actions/lifecycle_synchronization_context.ts) · [`src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts`](../src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts) · [`src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts`](../src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts) · [`src/application/policies/semantic_result_publication_policy.ts`](../src/application/policies/semantic_result_publication_policy.ts) · [`src/application/usecases/steps/common/status_card_publication_workflow.ts`](../src/application/usecases/steps/common/status_card_publication_workflow.ts) · [`src/application/usecases/comment_automation_context.ts`](../src/application/usecases/comment_automation_context.ts) · [`src/application/usecases/issue_workflow_context.ts`](../src/application/usecases/issue_workflow_context.ts) · [`src/application/usecases/pull_request_workflow_context.ts`](../src/application/usecases/pull_request_workflow_context.ts) · [`src/application/usecases/push_single_action_contexts.ts`](../src/application/usecases/push_single_action_contexts.ts) · [`src/application/usecases/steps/common/check_permissions_workflow.ts`](../src/application/usecases/steps/common/check_permissions_workflow.ts) · [`src/application/usecases/steps/common/comment_language_translation_workflow.ts`](../src/application/usecases/steps/common/comment_language_translation_workflow.ts) · [`src/application/usecases/steps/common/think_workflow.ts`](../src/application/usecases/steps/common/think_workflow.ts) · [`src/application/usecases/steps/common/update_title_workflow.ts`](../src/application/usecases/steps/common/update_title_workflow.ts) · [`src/application/usecases/steps/common/project_content_link_workflow.ts`](../src/application/usecases/steps/common/project_content_link_workflow.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`src/application/usecases/steps/common/store_configuration_use_case.ts`](../src/application/usecases/steps/common/store_configuration_use_case.ts) · [`src/infrastructure/composition/shared_capability_port_binding.ts`](../src/infrastructure/composition/shared_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_capability_port_binding.ts`](../src/infrastructure/composition/lifecycle_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_state_composition_root.ts`](../src/infrastructure/composition/lifecycle_state_composition_root.ts) · [`src/infrastructure/composition/push_single_action_capability_port_binding.ts`](../src/infrastructure/composition/push_single_action_capability_port_binding.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/application/policies/configuration_persistence_policy.ts`](../src/application/policies/configuration_persistence_policy.ts) · [`src/application/ports/project_board_query_ports.ts`](../src/application/ports/project_board_query_ports.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts) · [`src/application/usecases/steps/commit/update_change_size_labels.ts`](../src/application/usecases/steps/commit/update_change_size_labels.ts) · [`src/data/repository/project/project_board_item_query.ts`](../src/data/repository/project/project_board_item_query.ts) · [`src/infrastructure/composition/change_size_project_membership_composition_root.ts`](../src/infrastructure/composition/change_size_project_membership_composition_root.ts) -- Tests: [`src/tooling/__tests__/coverage_budget_validator.test.ts`](../src/tooling/__tests__/coverage_budget_validator.test.ts) · [`src/__tests__/api.test.ts`](../src/__tests__/api.test.ts) · [`src/actions/__tests__/github_action.test.ts`](../src/actions/__tests__/github_action.test.ts) · [`src/actions/__tests__/github_action_completion.test.ts`](../src/actions/__tests__/github_action_completion.test.ts) · [`src/application/errors/__tests__/application_error.test.ts`](../src/application/errors/__tests__/application_error.test.ts) · [`src/application/policies/__tests__/application_error_message_catalog.test.ts`](../src/application/policies/__tests__/application_error_message_catalog.test.ts) · [`src/application/policies/__tests__/application_error_presentation_policy.test.ts`](../src/application/policies/__tests__/application_error_presentation_policy.test.ts) · [`src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts) · [`src/application/policies/__tests__/action_summary_policy.test.ts`](../src/application/policies/__tests__/action_summary_policy.test.ts) · [`src/application/policies/__tests__/copilot_evidence_policy.test.ts`](../src/application/policies/__tests__/copilot_evidence_policy.test.ts) · [`src/application/policies/__tests__/lifecycle_state_policy.test.ts`](../src/application/policies/__tests__/lifecycle_state_policy.test.ts) · [`src/application/policies/__tests__/status_command_policy.test.ts`](../src/application/policies/__tests__/status_command_policy.test.ts) · [`src/application/usecases/actions/__tests__/lifecycle_synchronization_context.test.ts`](../src/application/usecases/actions/__tests__/lifecycle_synchronization_context.test.ts) · [`src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts`](../src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts) · [`src/application/usecases/actions/__tests__/lifecycle_event_replay.integration.test.ts`](../src/application/usecases/actions/__tests__/lifecycle_event_replay.integration.test.ts) · [`src/architecture/__tests__/execution_import_ratchet.test.ts`](../src/architecture/__tests__/execution_import_ratchet.test.ts) · [`src/architecture/__tests__/raw_error_logging_boundaries.test.ts`](../src/architecture/__tests__/raw_error_logging_boundaries.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/bugbot_review_operation_context.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/bugbot_review_operation_context.test.ts) · [`src/application/usecases/steps/common/__tests__/shared_capability_context_projection.test.ts`](../src/application/usecases/steps/common/__tests__/shared_capability_context_projection.test.ts) · [`src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts`](../src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts) · [`src/infrastructure/composition/__tests__/shared_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/shared_capability_port_binding.test.ts) · [`src/application/usecases/__tests__/issue_pull_request_context_projection.test.ts`](../src/application/usecases/__tests__/issue_pull_request_context_projection.test.ts) · [`src/infrastructure/composition/__tests__/lifecycle_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/lifecycle_capability_port_binding.test.ts) · [`src/infrastructure/composition/__tests__/lifecycle_state_composition_root.test.ts`](../src/infrastructure/composition/__tests__/lifecycle_state_composition_root.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/usecases/__tests__/single_action_workflow.test.ts`](../src/application/usecases/__tests__/single_action_workflow.test.ts) · [`src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts) · [`src/application/usecases/execution/__tests__/resolve_github_execution_admission_use_case.test.ts`](../src/application/usecases/execution/__tests__/resolve_github_execution_admission_use_case.test.ts) · [`src/application/usecases/workflow/__tests__/wait_for_previous_workflow_runs_use_case.test.ts`](../src/application/usecases/workflow/__tests__/wait_for_previous_workflow_runs_use_case.test.ts) · [`src/application/policies/__tests__/configuration_persistence_policy.test.ts`](../src/application/policies/__tests__/configuration_persistence_policy.test.ts) · [`src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts`](../src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts) · [`src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts`](../src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts) · [`src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts`](../src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts) · [`src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts`](../src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts) -- User documentation: [`docs/overview.mdx`](../docs/overview.mdx) · [`docs/bugbot/programmatic-api.mdx`](../docs/bugbot/programmatic-api.mdx) · [`docs/security-operations/operations/error-reference.mdx`](../docs/security-operations/operations/error-reference.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/bugbot/quality-observability.mdx`](../docs/bugbot/quality-observability.mdx) · [`docs/bugbot/failure-scenarios.mdx`](../docs/bugbot/failure-scenarios.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/issues/assignees-and-projects.mdx`](../docs/issues/assignees-and-projects.mdx) +- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/validate-coverage-budgets.cjs`](../scripts/validate-coverage-budgets.cjs) · [`src/actions/main_run_lifecycle.ts`](../src/actions/main_run_lifecycle.ts) · [`src/actions/main_run_route.ts`](../src/actions/main_run_route.ts) · [`src/actions/github_action_completion.ts`](../src/actions/github_action_completion.ts) · [`src/api.ts`](../src/api.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/errors/application_error.ts`](../src/application/errors/application_error.ts) · [`src/application/errors/application_error_context.ts`](../src/application/errors/application_error_context.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/application/policies/application_error_presentation_policy.ts`](../src/application/policies/application_error_presentation_policy.ts) · [`src/application/policies/bugbot_result_finding_state_projection_policy.ts`](../src/application/policies/bugbot_result_finding_state_projection_policy.ts) · [`src/application/policies/bugbot_telemetry_projection_policy.ts`](../src/application/policies/bugbot_telemetry_projection_policy.ts) · [`src/application/policies/action_summary_policy.ts`](../src/application/policies/action_summary_policy.ts) · [`src/application/policies/copilot_evidence_policy.ts`](../src/application/policies/copilot_evidence_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/policies/github_execution_admission_policy.ts`](../src/application/policies/github_execution_admission_policy.ts) · [`src/application/policies/workflow_queue_policy.ts`](../src/application/policies/workflow_queue_policy.ts) · [`src/application/usecases/actions/lifecycle_synchronization_context.ts`](../src/application/usecases/actions/lifecycle_synchronization_context.ts) · [`src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts`](../src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts) · [`src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts`](../src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts) · [`src/application/policies/semantic_result_publication_policy.ts`](../src/application/policies/semantic_result_publication_policy.ts) · [`src/application/usecases/steps/common/status_card_publication_workflow.ts`](../src/application/usecases/steps/common/status_card_publication_workflow.ts) · [`src/application/usecases/comment_automation_context.ts`](../src/application/usecases/comment_automation_context.ts) · [`src/application/usecases/issue_workflow_context.ts`](../src/application/usecases/issue_workflow_context.ts) · [`src/application/usecases/pull_request_workflow_context.ts`](../src/application/usecases/pull_request_workflow_context.ts) · [`src/application/usecases/push_single_action_contexts.ts`](../src/application/usecases/push_single_action_contexts.ts) · [`src/application/usecases/steps/common/check_permissions_workflow.ts`](../src/application/usecases/steps/common/check_permissions_workflow.ts) · [`src/application/usecases/steps/common/comment_language_translation_workflow.ts`](../src/application/usecases/steps/common/comment_language_translation_workflow.ts) · [`src/application/usecases/steps/common/think_workflow.ts`](../src/application/usecases/steps/common/think_workflow.ts) · [`src/application/usecases/steps/common/update_title_workflow.ts`](../src/application/usecases/steps/common/update_title_workflow.ts) · [`src/application/usecases/steps/common/project_content_link_workflow.ts`](../src/application/usecases/steps/common/project_content_link_workflow.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`src/application/usecases/steps/common/store_configuration_use_case.ts`](../src/application/usecases/steps/common/store_configuration_use_case.ts) · [`src/infrastructure/composition/shared_capability_port_binding.ts`](../src/infrastructure/composition/shared_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_capability_port_binding.ts`](../src/infrastructure/composition/lifecycle_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_state_composition_root.ts`](../src/infrastructure/composition/lifecycle_state_composition_root.ts) · [`src/infrastructure/composition/push_single_action_capability_port_binding.ts`](../src/infrastructure/composition/push_single_action_capability_port_binding.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/application/policies/configuration_persistence_policy.ts`](../src/application/policies/configuration_persistence_policy.ts) · [`src/application/ports/project_board_query_ports.ts`](../src/application/ports/project_board_query_ports.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts) · [`src/application/usecases/steps/commit/update_change_size_labels.ts`](../src/application/usecases/steps/commit/update_change_size_labels.ts) · [`src/data/repository/project/project_board_item_query.ts`](../src/data/repository/project/project_board_item_query.ts) · [`src/infrastructure/composition/change_size_project_membership_composition_root.ts`](../src/infrastructure/composition/change_size_project_membership_composition_root.ts) · [`src/manager/description/configuration_handler.ts`](../src/manager/description/configuration_handler.ts) · [`src/data/repository/issue/issue_content_repository.ts`](../src/data/repository/issue/issue_content_repository.ts) · [`src/data/repository/github/github_error_policy.ts`](../src/data/repository/github/github_error_policy.ts) +- Tests: [`src/tooling/__tests__/coverage_budget_validator.test.ts`](../src/tooling/__tests__/coverage_budget_validator.test.ts) · [`src/__tests__/api.test.ts`](../src/__tests__/api.test.ts) · [`src/actions/__tests__/github_action.test.ts`](../src/actions/__tests__/github_action.test.ts) · [`src/actions/__tests__/github_action_completion.test.ts`](../src/actions/__tests__/github_action_completion.test.ts) · [`src/application/errors/__tests__/application_error.test.ts`](../src/application/errors/__tests__/application_error.test.ts) · [`src/application/policies/__tests__/application_error_message_catalog.test.ts`](../src/application/policies/__tests__/application_error_message_catalog.test.ts) · [`src/application/policies/__tests__/application_error_presentation_policy.test.ts`](../src/application/policies/__tests__/application_error_presentation_policy.test.ts) · [`src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts) · [`src/application/policies/__tests__/action_summary_policy.test.ts`](../src/application/policies/__tests__/action_summary_policy.test.ts) · [`src/application/policies/__tests__/copilot_evidence_policy.test.ts`](../src/application/policies/__tests__/copilot_evidence_policy.test.ts) · [`src/application/policies/__tests__/lifecycle_state_policy.test.ts`](../src/application/policies/__tests__/lifecycle_state_policy.test.ts) · [`src/application/policies/__tests__/status_command_policy.test.ts`](../src/application/policies/__tests__/status_command_policy.test.ts) · [`src/application/usecases/actions/__tests__/lifecycle_synchronization_context.test.ts`](../src/application/usecases/actions/__tests__/lifecycle_synchronization_context.test.ts) · [`src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts`](../src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts) · [`src/application/usecases/actions/__tests__/lifecycle_event_replay.integration.test.ts`](../src/application/usecases/actions/__tests__/lifecycle_event_replay.integration.test.ts) · [`src/architecture/__tests__/execution_import_ratchet.test.ts`](../src/architecture/__tests__/execution_import_ratchet.test.ts) · [`src/architecture/__tests__/raw_error_logging_boundaries.test.ts`](../src/architecture/__tests__/raw_error_logging_boundaries.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/bugbot_review_operation_context.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/bugbot_review_operation_context.test.ts) · [`src/application/usecases/steps/common/__tests__/shared_capability_context_projection.test.ts`](../src/application/usecases/steps/common/__tests__/shared_capability_context_projection.test.ts) · [`src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts`](../src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts) · [`src/infrastructure/composition/__tests__/shared_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/shared_capability_port_binding.test.ts) · [`src/application/usecases/__tests__/issue_pull_request_context_projection.test.ts`](../src/application/usecases/__tests__/issue_pull_request_context_projection.test.ts) · [`src/infrastructure/composition/__tests__/lifecycle_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/lifecycle_capability_port_binding.test.ts) · [`src/infrastructure/composition/__tests__/lifecycle_state_composition_root.test.ts`](../src/infrastructure/composition/__tests__/lifecycle_state_composition_root.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/usecases/__tests__/single_action_workflow.test.ts`](../src/application/usecases/__tests__/single_action_workflow.test.ts) · [`src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts) · [`src/application/usecases/execution/__tests__/resolve_github_execution_admission_use_case.test.ts`](../src/application/usecases/execution/__tests__/resolve_github_execution_admission_use_case.test.ts) · [`src/application/usecases/workflow/__tests__/wait_for_previous_workflow_runs_use_case.test.ts`](../src/application/usecases/workflow/__tests__/wait_for_previous_workflow_runs_use_case.test.ts) · [`src/application/policies/__tests__/configuration_persistence_policy.test.ts`](../src/application/policies/__tests__/configuration_persistence_policy.test.ts) · [`src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts`](../src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts) · [`src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts`](../src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts) · [`src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts`](../src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts) · [`src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts`](../src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts) · [`src/manager/description/__tests__/configuration_recovery.test.ts`](../src/manager/description/__tests__/configuration_recovery.test.ts) · [`src/manager/description/__tests__/configuration_handler.test.ts`](../src/manager/description/__tests__/configuration_handler.test.ts) · [`src/data/repository/issue/__tests__/issue_content_repository.test.ts`](../src/data/repository/issue/__tests__/issue_content_repository.test.ts) +- User documentation: [`docs/overview.mdx`](../docs/overview.mdx) · [`docs/bugbot/programmatic-api.mdx`](../docs/bugbot/programmatic-api.mdx) · [`docs/security-operations/operations/error-reference.mdx`](../docs/security-operations/operations/error-reference.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/bugbot/quality-observability.mdx`](../docs/bugbot/quality-observability.mdx) · [`docs/bugbot/failure-scenarios.mdx`](../docs/bugbot/failure-scenarios.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/issues/assignees-and-projects.mdx`](../docs/issues/assignees-and-projects.mdx) · [`docs/configuration.mdx`](../docs/configuration.mdx) ### `architecture-quality-hardening` — Architecture quality and scalability hardening diff --git a/specs/catalog.json b/specs/catalog.json index 73491e557..dcb1f73d3 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -515,7 +515,7 @@ "status": "implemented", "scope": "Shared GitHub Action lifecycle from event admission through durable user-facing results", "owner": "Copilot maintainers", - "lastVerified": "2026-10-14", + "lastVerified": "2026-10-21", "specs": [ "specs/execution-admission-queue-and-publication.md", "specs/execution-error-and-context-hardening.md", @@ -580,7 +580,10 @@ "src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts", "src/application/usecases/steps/commit/update_change_size_labels.ts", "src/data/repository/project/project_board_item_query.ts", - "src/infrastructure/composition/change_size_project_membership_composition_root.ts" + "src/infrastructure/composition/change_size_project_membership_composition_root.ts", + "src/manager/description/configuration_handler.ts", + "src/data/repository/issue/issue_content_repository.ts", + "src/data/repository/github/github_error_policy.ts" ], "tests": [ "src/tooling/__tests__/coverage_budget_validator.test.ts", @@ -617,7 +620,10 @@ "src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts", "src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts", "src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts", - "src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts" + "src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts", + "src/manager/description/__tests__/configuration_recovery.test.ts", + "src/manager/description/__tests__/configuration_handler.test.ts", + "src/data/repository/issue/__tests__/issue_content_repository.test.ts" ], "documentation": [ "docs/overview.mdx", @@ -627,7 +633,8 @@ "docs/bugbot/quality-observability.mdx", "docs/bugbot/failure-scenarios.mdx", "docs/development/architecture.mdx", - "docs/issues/assignees-and-projects.mdx" + "docs/issues/assignees-and-projects.mdx", + "docs/configuration.mdx" ] }, { diff --git a/specs/execution-error-and-context-hardening.md b/specs/execution-error-and-context-hardening.md index 4c5bc2675..f245e17b0 100644 --- a/specs/execution-error-and-context-hardening.md +++ b/specs/execution-error-and-context-hardening.md @@ -804,3 +804,105 @@ pure cases cover native closure, closed label callbacks, open state and missing state. They belong only to this owner: the #474 extension is now 15 execution cases, separate from 56 semantic publication and six autofix cases. Terminal routing/bot-event tests belong to branch synchronization and are not recounted. + +### Stored configuration diagnostics and recovery: #635 (2026-10-21) + +**Problem and preserved contract.** Run +[39565969565](https://github.com/vypdev/zstandard/actions/runs/39565969565/job/119108205733) +rejected a PR block without a schema version. Rejection is intentional: +only the current durable schema is supported. The defect was that the reader +logged a semantic configuration error but rethrew its raw cause; the final +boundary consequently presented `workflow.failed` and retryable true. An +unlinked PR without any block remains eligible for its ordinary PR route. + +**Journey and architecture.** The description adapter maps read failures to +semantic provider/authorization errors. The configuration reader performs strict +parsing/validation and throws `configuration.invalid` with one closed recovery +descriptor: `stored-configuration-schema-missing`, +`stored-configuration-schema-unsupported`, or `stored-configuration-invalid`. +Only a positive safe issue/PR number and expected version, plus a nonnegative +safe numeric actual version for the unsupported case, cross this boundary. +Malformed JSON, values, fields and incomplete delimiters use the invalid +descriptor without copying body/schema text. + +```text +Read issue/PR -> validate stored block -> fail with safe configuration facts + -> localized annotation + Job Summary -> maintainer correction -> rerun +``` + +The flow reads first, rejects unsupported state before PR/issue route mutations, +and exposes a manual recovery action. The final Action boundary MUST preserve +code, nonretryability and correlation identity. It uses existing presentation and +summary ports even when execution setup never completed. Summary publication +failure MUST NOT replace the original failed annotation or turn the run into +success. Existing architecture/taint checks enforce the application/model/adapter +boundaries; raw causes remain private. + +**Configuration and security.** No setting, schema version change, compatibility +reader, automatic migration/reset, workflow, setup step or extra comment is +introduced. Supported state and absent blocks keep their existing behavior. +The failure MUST leave the issue/PR body and configuration untouched. Missing, +old, future and malformed versions MUST remain failed and nonretryable without +correction. A version number alone never establishes valid managed state. +Provider failures retain their own categories and retryability. Closed variable +validation excludes arbitrary text, URLs, credentials and extra fields. + +**GitHub content and recovery.** English and Spanish catalogs cover all three +diagnoses. Other early locales use the established atomic fallback without a +new model call. A fixed recovery URL is inserted by presentation after +localization, so translations cannot supply URLs and remain subject to existing +safe-text validation. Representative missing-schema content: + +```text +Impact: Automation stopped for issue/PR #144: the stored configuration has no +schema version; version 3 is required. +Error code: configuration.invalid +Action: A maintainer must review the recovery guide before correcting the block. +Retained state: The issue/PR description and stored configuration were not changed by this read. +Retryable: No +Reference: +``` + +The complete action links to +[recovery](/security-operations/operations/troubleshooting#unsupported-stored-configuration) +and requires preservation of the original body before removing only a verified +obsolete unmanaged block. If managed branch, release, hotfix or orchestration +state may exist, the operator MUST stop for maintainer review and verified +supported-state restoration. It MUST NOT advise blindly adding a schema version, +deleting managed state, or skipping a failed check. Repeating unchanged invalid +state remains failed without writes. After verified obsolete-marker removal, +the real unlinked setup route MUST configure without inventing an issue link. + +Pending/completed states retain their existing presentation. Partial mutation, +new cancellation/race machinery and navigation registration are not applicable +to this early read failure. Rollout changes only diagnostics; rollback reverts +the diagnostic change while preserving strict validation. Existing in-flight +managed state is never automatically rewritten. + +**Verification floor: 15 distinct cases**, owned only by this extension: + +| Area | Cases | Acceptance/evidence | +|---|---:|---| +| Payload/routing | 6 | absent block, missing version, old version, future version, malformed JSON, valid current state | +| Propagation/provider | 3 | final annotation/summary preserve code/reference/retry; authorization and transient reads retain their own categories | +| Presentation/security | 4 | English, Spanish/fallback, hostile/oversized text excluded, no blind managed-state removal/version edits | +| Recovery/replay | 2 | unchanged replay fails without writes; deliberate obsolete-marker removal recovers an unlinked PR | + +`configuration_recovery.test.ts` owns payload and real setup/replay evidence; +`github_action.test.ts` owns annotation/summary/reference/fallback and summary +failure evidence; issue-content adapter and error/presentation suites own +provider mapping and bounded descriptor tests. Additional malformed-value, +marker, forged-variable and mapping cases do not reduce this floor. +Assertions inspect structured semantics and absence of mutation, not only +snapshots. Existing repository and changed-module coverage thresholds, type +checking, architecture/taint guards, documentation and specification validation +remain required. Inspect a narrow annotation/Job Summary and its recovery link +for readability; native replay of the new diagnostic remains a separate live +verification step until the change is deployed. + +**Documentation and delivery.** Update configuration persistence, error reference +and troubleshooting (including a stable recovery heading), plus the execution +catalog evidence and generated catalog. The implementation sequence is closed +facts/reader, final boundary and localization, adapter mapping, deterministic +tests, docs/catalog, then validation. Done requires all acceptance rows to pass, +generated evidence to be current and strict rejection to remain intact. diff --git a/src/actions/__tests__/github_action.test.ts b/src/actions/__tests__/github_action.test.ts index ecf959668..898a1ebfb 100644 --- a/src/actions/__tests__/github_action.test.ts +++ b/src/actions/__tests__/github_action.test.ts @@ -677,6 +677,49 @@ describe('runGitHubActionEntry', () => { jest.clearAllMocks(); }); + it.each([ + ['en-US', '{"branchType":"feature"}', 'has no schema version', 'Retryable: No'], + ['es-MX', '{"schemaVersion":2}', 'versión de esquema almacenada 2', 'Reintentable: No'], + ['fr-FR', '{"schemaVersion":99}', 'stored schema version 99', 'Retryable: No'], + ])('preserves real stored-configuration diagnostics in the annotation and summary for %s', async (locale, json, causeText, retryText) => { + (core.getInput as jest.Mock).mockImplementation((key: string) => key === INPUT_KEYS.REPOSITORY_LOCALE ? locale : ''); + const { ConfigurationHandler: RealHandler } = jest.requireActual('../../manager/description/configuration_handler'); + const updateDescription = jest.fn(); + const reader = new RealHandler({ + getDescription: jest.fn(async () => ''), + updateDescription, + }); + const failure = await reader.get({ owner: 'o', repository: 'r', issueNumber: 144, token: 'fixture' }).catch(error => error); + await runGitHubActionEntry(async () => { throw failure; }); + const annotation = (core.setFailed as jest.Mock).mock.calls[0][0] as string; + const markdown = (core.summary.addRaw as jest.Mock).mock.calls[0][0] as string; + for (const surface of [annotation, markdown]) { + expect(surface).toContain(causeText); + expect(surface).toContain('144'); + expect(surface).toContain('configuration.invalid'); + expect(surface).toContain(failure.correlationId); + expect(surface).toContain('#unsupported-stored-configuration'); + expect(surface).not.toContain('workflow.failed'); + expect(surface).not.toContain(json); + } + expect(annotation).toContain(retryText); + expect(core.summary.write).toHaveBeenCalledTimes(1); + expect(core.setFailed).toHaveBeenCalledTimes(1); + expect(updateDescription).not.toHaveBeenCalled(); + }); + + it('keeps the configuration failure when summary publication fails', async () => { + (core.getInput as jest.Mock).mockReturnValue(''); + (core.summary.write as jest.Mock).mockRejectedValueOnce(new Error('PRIVATE-SUMMARY-FAILURE')); + const failure = new ApplicationError('configuration.invalid', 'Safe detail.', { + recovery: { id: 'stored-configuration-schema-missing', variables: { issueNumber: 144, expectedVersion: 3 } }, + }); + await expect(runGitHubActionEntry(async () => { throw failure; })).resolves.toBeUndefined(); + expect(core.setFailed).toHaveBeenCalledTimes(1); + expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining('configuration.invalid')); + expect(core.setFailed).not.toHaveBeenCalledWith(expect.stringContaining('PRIVATE-SUMMARY-FAILURE')); + }); + it('lets Node preserve an existing failure exit code after a resolved run', async () => { const previousExitCode = process.exitCode; process.exitCode = 1; diff --git a/src/actions/github_action.ts b/src/actions/github_action.ts index 4baae0618..e94c26acb 100644 --- a/src/actions/github_action.ts +++ b/src/actions/github_action.ts @@ -23,7 +23,7 @@ import { activeAgentTasks, isUnaddressedCommentEvent } from '../application/poli import { createActorAuthorizationRepository } from '../infrastructure/composition/actor_authorization_composition_root'; import { runAtApplicationErrorBoundary } from '../application/errors/application_error_context'; import { toApplicationError } from '../application/errors/application_error'; -import { renderApplicationErrorText } from '../application/policies/application_error_presentation_policy'; +import { renderApplicationErrorMarkdown, renderApplicationErrorText } from '../application/policies/application_error_presentation_policy'; import { bindIssueCommentPublication } from '../infrastructure/composition/push_single_action_capability_port_binding'; import { bindPublicationSourceQuery } from '../infrastructure/composition/shared_capability_port_binding'; import { GithubPublicationSourceRepository } from '../data/repository/github_publication_source_repository'; @@ -230,7 +230,15 @@ export async function runGitHubActionEntry( } catch (cause: unknown) { const semanticError = toApplicationError(cause, 'workflow.failed', 'GitHub Action execution failed.'); logError(semanticError); - core.setFailed(renderApplicationErrorText(semanticError, earlyGithubActionErrorMessage())); + const message = earlyGithubActionErrorMessage(); + core.setFailed(renderApplicationErrorText(semanticError, message)); + if (semanticError.recovery?.id.startsWith('stored-configuration-')) { + try { + await createGithubActionSummaryCompositionRoot().publish(renderApplicationErrorMarkdown(semanticError, message)); + } catch (summaryCause) { + logError(toApplicationError(summaryCause, 'provider.unavailable', 'Unable to publish the configuration failure summary.')); + } + } } }); } diff --git a/src/application/errors/__tests__/application_error.test.ts b/src/application/errors/__tests__/application_error.test.ts index b6ce587c3..fb585a96c 100644 --- a/src/application/errors/__tests__/application_error.test.ts +++ b/src/application/errors/__tests__/application_error.test.ts @@ -9,6 +9,18 @@ import { runAtApplicationErrorBoundary, runWithApplicationErrorCorrelation } fro const CORRELATION_ID = '6f173f89-96a3-4fc8-b90e-4f8f48e0e319'; describe('ApplicationError', () => { + it.each([ + { id: 'stored-configuration-schema-missing', variables: { issueNumber: 0, expectedVersion: 3 } }, + { id: 'stored-configuration-invalid', variables: { issueNumber: 144, expectedVersion: 0 } }, + { id: 'stored-configuration-schema-unsupported', variables: { issueNumber: 144, expectedVersion: 3, actualVersion: 'PRIVATE' } }, + { id: 'stored-configuration-schema-unsupported', variables: { issueNumber: 144, expectedVersion: 3, actualVersion: -1 } }, + { id: 'stored-configuration-schema-unsupported', variables: { issueNumber: 144, expectedVersion: 3, actualVersion: Number.MAX_SAFE_INTEGER + 1 } }, + { id: 'stored-configuration-schema-missing', variables: { issueNumber: 144, expectedVersion: 3, body: 'PRIVATE' } }, + ])('rejects forged stored-configuration facts: $id $variables', recovery => { + expect(() => new ApplicationError('configuration.invalid', 'Invalid state.', { + recovery: recovery as never, + })).toThrow(); + }); it('rejects a forged branch synchronization diagnostic descriptor', () => { expect(() => new ApplicationError('workflow.failed', 'private', { recovery: { id: 'branch-sync-resolution-invalid', variables: { validationCode: 'TOKEN=secret', command: '/copilot sync-branch' } } as never, diff --git a/src/application/policies/__tests__/application_error_presentation_policy.test.ts b/src/application/policies/__tests__/application_error_presentation_policy.test.ts index 8b4c007fe..1318ac91e 100644 --- a/src/application/policies/__tests__/application_error_presentation_policy.test.ts +++ b/src/application/policies/__tests__/application_error_presentation_policy.test.ts @@ -19,6 +19,13 @@ const RECOVERY_CASES: readonly Readonly<{ english: string; spanish: string; }>[] = [ + ...(['stored-configuration-schema-missing', 'stored-configuration-schema-unsupported', 'stored-configuration-invalid'] as const).map(id => ({ + recovery: id === 'stored-configuration-schema-unsupported' + ? { id, variables: { issueNumber: 144, expectedVersion: 3, actualVersion: 2 } } + : { id, variables: { issueNumber: 144, expectedVersion: 3 } }, + english: 'The issue/PR description and stored configuration were not changed by this read.', + spanish: 'Esta lectura no modificó la descripción de la issue/PR ni su configuración almacenada.', + })), { recovery: { id: 'closed-issue-reconciliation-failed', variables: { resultId: 'RetireProgressUseCase', phase: 'card-verification', state: 'closed', reason: 'completed', changed: 1, remaining: 1 } }, english: 'Native state was preserved. Confirmed changes: 1; remaining required changes in the last verified plan: 1. Unavailable reads do not establish completion.', diff --git a/src/application/policies/application_error_message_catalog.ts b/src/application/policies/application_error_message_catalog.ts index 9b8d7c0d6..e5d244305 100644 --- a/src/application/policies/application_error_message_catalog.ts +++ b/src/application/policies/application_error_message_catalog.ts @@ -205,7 +205,27 @@ const SPANISH_CONTENT: ErrorContent = Object.freeze({ }), }); +const STORED_CONFIGURATION_ACTION_EN = 'A maintainer must review {recoveryGuide}. Preserve a copy before removing only a verified obsolete unmanaged block. If managed branch, release, hotfix or orchestration state may exist, stop and restore verified supported state with a maintainer. Do not just add a schema version or delete managed state. Correct the configuration before rerunning; retrying unchanged state will fail again.'; +const STORED_CONFIGURATION_ACTION_ES = 'Un mantenedor debe revisar {recoveryGuide}. Conserva una copia antes de retirar solo un bloque obsoleto confirmado como no gestionado. Si puede existir estado gestionado de ramas, releases, hotfixes u orquestación, detente y restaura estado compatible verificado con un mantenedor. No añadas simplemente una versión de esquema ni borres estado gestionado. Corrige la configuración antes de reejecutar; el mismo estado volverá a fallar.'; +const STORED_CONFIGURATION_RETAINED_EN = 'The issue/PR description and stored configuration were not changed by this read.'; +const STORED_CONFIGURATION_RETAINED_ES = 'Esta lectura no modificó la descripción de la issue/PR ni su configuración almacenada.'; + const ENGLISH_RECOVERY_CONTENT: RecoveryContent = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: the stored configuration has no schema version; version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), + 'stored-configuration-schema-unsupported': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: stored schema version {actualVersion} is unsupported; version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), + 'stored-configuration-invalid': Object.freeze({ + impact: 'Automation stopped for issue/PR #{issueNumber}: the stored configuration, markers or schema value are malformed; valid schema version {expectedVersion} is required.', + action: STORED_CONFIGURATION_ACTION_EN, + retainedState: STORED_CONFIGURATION_RETAINED_EN, + }), 'closed-issue-reconciliation-failed': Object.freeze({ impact: 'Issue cleanup remains unverified: {resultId}, phase {phase}; native state {state}, reason {reason}.', action: 'Inspect the closed-issue or merged-PR run and current native state. Retry cleanup only if the issue is still closed with the intended reason; leave reopened work open. Resolve the named failure before retrying.', @@ -285,6 +305,21 @@ const ENGLISH_RECOVERY_CONTENT: RecoveryContent = Object.freeze({ }); const SPANISH_RECOVERY_CONTENT: RecoveryContent = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la configuración almacenada no tiene versión de esquema; se requiere la versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), + 'stored-configuration-schema-unsupported': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la versión de esquema almacenada {actualVersion} no es compatible; se requiere la versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), + 'stored-configuration-invalid': Object.freeze({ + impact: 'La automatización se detuvo para la issue/PR #{issueNumber}: la configuración almacenada, sus delimitadores o el valor del esquema no son válidos; se requiere un esquema válido de versión {expectedVersion}.', + action: STORED_CONFIGURATION_ACTION_ES, + retainedState: STORED_CONFIGURATION_RETAINED_ES, + }), 'closed-issue-reconciliation-failed': Object.freeze({ impact: 'La limpieza de la issue sigue sin verificarse: {resultId}, fase {phase}; estado nativo {state}, motivo {reason}.', action: 'Revisa la ejecución de cierre o de la PR fusionada y el estado nativo actual. Reintenta la limpieza solo si la issue sigue cerrada con el motivo previsto; conserva abierto el trabajo reabierto. Resuelve el fallo indicado antes de reintentar.', diff --git a/src/application/policies/application_error_presentation_policy.ts b/src/application/policies/application_error_presentation_policy.ts index 5f60eec6d..f556a4972 100644 --- a/src/application/policies/application_error_presentation_policy.ts +++ b/src/application/policies/application_error_presentation_policy.ts @@ -7,6 +7,9 @@ import { type ApplicationErrorMessageReader, } from './application_error_message_catalog'; +// This trusted destination is inserted after localization, never supplied by a body or translation. +const STORED_CONFIGURATION_RECOVERY_URL = 'https://docs.page/vypdev/copilot/security-operations/operations/troubleshooting#unsupported-stored-configuration'; + export interface ApplicationErrorPresentation { readonly impact: string; readonly code: string; @@ -31,7 +34,9 @@ export function buildApplicationErrorPresentation( const descriptor = error.recovery ? `error.recovery.${error.recovery.id}` as const : `error.${error.code}` as const; - const variables = error.recovery?.variables; + const variables = error.recovery?.id.startsWith('stored-configuration-') + ? { ...error.recovery.variables, recoveryGuide: STORED_CONFIGURATION_RECOVERY_URL } + : error.recovery?.variables; return { impact: message(`${descriptor}.impact`, variables), code: error.code, diff --git a/src/data/model/application_error.ts b/src/data/model/application_error.ts index 03eabf60d..274af0a25 100644 --- a/src/data/model/application_error.ts +++ b/src/data/model/application_error.ts @@ -53,12 +53,18 @@ export const APPLICATION_ERROR_RECOVERY_IDS = Object.freeze([ 'workspace-changes-rejected', 'closed-issue-reconciliation-failed', 'approval-evidence-read-failed', + 'stored-configuration-schema-missing', + 'stored-configuration-schema-unsupported', + 'stored-configuration-invalid', ] as const); export type ApplicationErrorRecoveryId = typeof APPLICATION_ERROR_RECOVERY_IDS[number]; interface ApplicationErrorRecoveryVariables { + readonly 'stored-configuration-schema-missing': Readonly<{ issueNumber: number; expectedVersion: number }>; + readonly 'stored-configuration-schema-unsupported': Readonly<{ issueNumber: number; expectedVersion: number; actualVersion: number }>; + readonly 'stored-configuration-invalid': Readonly<{ issueNumber: number; expectedVersion: number }>; readonly 'closed-issue-reconciliation-failed': ClosedIssueReconciliationFacts; readonly 'approval-evidence-read-failed': ApprovalEvidenceDiagnostic; @@ -316,6 +322,9 @@ export class ApplicationError extends Error { } const RECOVERY_VARIABLE_KEYS: Readonly> = Object.freeze({ + 'stored-configuration-schema-missing': Object.freeze(['issueNumber', 'expectedVersion']), + 'stored-configuration-schema-unsupported': Object.freeze(['issueNumber', 'expectedVersion', 'actualVersion']), + 'stored-configuration-invalid': Object.freeze(['issueNumber', 'expectedVersion']), 'closed-issue-reconciliation-failed': Object.freeze(['resultId', 'phase', 'state', 'reason', 'changed', 'remaining']), 'approval-evidence-read-failed': Object.freeze(['operation', 'reason', 'permission']), @@ -348,6 +357,14 @@ function normalizeApplicationErrorRecovery( || actualKeys.some((key, index) => key !== expectedKeys[index])) { throw new TypeError(`Application error recovery variables are invalid for ${recovery.id}.`); } + if (recovery.id.startsWith('stored-configuration-') + && (![variables.issueNumber, variables.expectedVersion].every(value => + typeof value === 'number' && Number.isSafeInteger(value) && value > 0) + || (recovery.id === 'stored-configuration-schema-unsupported' + && !(typeof variables.actualVersion === 'number' + && Number.isSafeInteger(variables.actualVersion) && variables.actualVersion >= 0)))) { + throw new TypeError('Stored configuration diagnostic is invalid.'); + } if (recovery.id === 'managed-branch-enrichment-failed' && (typeof variables.branchName !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._/-]{0,254}$/u.test(variables.branchName))) { diff --git a/src/data/repository/github/github_error_policy.ts b/src/data/repository/github/github_error_policy.ts index 6a888fbb6..e6231538a 100644 --- a/src/data/repository/github/github_error_policy.ts +++ b/src/data/repository/github/github_error_policy.ts @@ -1,3 +1,5 @@ +import type { ApplicationErrorCode } from '../../model/application_error'; + export interface GithubErrorShape { status?: number; message?: string; @@ -12,6 +14,18 @@ export const getGithubErrorStatus = (error: unknown): number | undefined => { export const isGithubNotFound = (error: unknown): boolean => getGithubErrorStatus(error) === 404; +/** Maps failed metadata reads without copying untrusted provider text. */ +export function githubReadErrorCode(error: unknown): ApplicationErrorCode { + const status = getGithubErrorStatus(error); + if (status === 401) return 'authorization.credential-invalid'; + if (isGithubRateLimited(error)) return 'provider.rate-limited'; + if (status === 403) return 'authorization.denied'; + if (status === 404) return 'provider.not-found'; + if (status === 409 || status === 412) return 'provider.conflict'; + if (status === 400 || status === 422) return 'provider.contract-invalid'; + return 'provider.unavailable'; +} + export const isGithubRateLimited = (error: unknown): boolean => { const status = getGithubErrorStatus(error); if (status === 429) return true; diff --git a/src/data/repository/issue/__tests__/issue_content_repository.test.ts b/src/data/repository/issue/__tests__/issue_content_repository.test.ts index 1e2b66a77..572083314 100644 --- a/src/data/repository/issue/__tests__/issue_content_repository.test.ts +++ b/src/data/repository/issue/__tests__/issue_content_repository.test.ts @@ -53,7 +53,34 @@ describe('IssueContentRepository', () => { it('preserves issue access failures instead of presenting them as an empty description', async () => { mockGet.mockRejectedValue(new Error('Not Found')); - await expect(repository.getDescription('owner', 'repo', 7, 'token')).rejects.toThrow('Not Found'); + await expect(repository.getDescription('owner', 'repo', 7, 'token')).rejects.toMatchObject({ + code: 'provider.unavailable', retryable: true, + }); + }); + + it.each([ + [401, 'authorization.credential-invalid', false], + [403, 'authorization.denied', false], + [404, 'provider.not-found', false], + [409, 'provider.conflict', true], + [412, 'provider.conflict', true], + [400, 'provider.contract-invalid', false], + [422, 'provider.contract-invalid', false], + [429, 'provider.rate-limited', true], + [503, 'provider.unavailable', true], + ])('maps description-read HTTP %s to %s without exposing provider text', async (status, code, retryable) => { + mockGet.mockRejectedValue({ status, message: 'PRIVATE-PROVIDER-BODY' }); + const error = await repository.getDescription('owner', 'repo', 7, 'token').catch(error => error); + expect(error).toMatchObject({ code, retryable }); + expect(JSON.stringify(error)).not.toContain('PRIVATE-PROVIDER-BODY'); + expect(mockUpdate).not.toHaveBeenCalled(); + }); + + it('preserves rate-limit semantics for a 403 description read', async () => { + mockGet.mockRejectedValue({ status: 403, response: { headers: { 'x-ratelimit-remaining': '0' } } }); + await expect(repository.getDescription('owner', 'repo', 7, 'token')).rejects.toMatchObject({ + code: 'provider.rate-limited', retryable: true, + }); }); it('publishes exactly the semantic body without a visible branding footer', async () => { diff --git a/src/data/repository/issue/issue_content_repository.ts b/src/data/repository/issue/issue_content_repository.ts index 02e1092bc..184aaf253 100644 --- a/src/data/repository/issue/issue_content_repository.ts +++ b/src/data/repository/issue/issue_content_repository.ts @@ -7,7 +7,7 @@ import type { } from "../../../infrastructure/github/ports/github_issue_provider_ports"; import { requireArrayPage } from "../github/github_pagination_policy"; import { toApplicationError } from '../../../application/errors/application_error'; -import { getGithubErrorStatus, isGithubPermissionDenied } from '../github/github_error_policy'; +import { getGithubErrorStatus, githubReadErrorCode, isGithubPermissionDenied } from '../github/github_error_policy'; import type { IssueCommentRemovalOutcome } from '../../../application/ports/issue_lifecycle_ports'; export interface IssueComment { @@ -58,8 +58,9 @@ export class IssueContentRepository { }); return issue.body ?? ''; } catch (error) { - logError(toApplicationError(error, 'provider.unavailable', `Unable to read issue #${issueNumber} description.`)); - throw error; + const semanticError = toApplicationError(error, githubReadErrorCode(error), 'Unable to read the issue or pull-request description.'); + logError(semanticError); + throw semanticError; } }; diff --git a/src/manager/description/__tests__/configuration_handler.test.ts b/src/manager/description/__tests__/configuration_handler.test.ts index 773db0a72..9a860fd61 100644 --- a/src/manager/description/__tests__/configuration_handler.test.ts +++ b/src/manager/description/__tests__/configuration_handler.test.ts @@ -261,9 +261,12 @@ describe('ConfigurationHandler', () => { expect(result).toBeUndefined(); }); - it('get throws informative error on invalid JSON', async () => { + it('get rejects invalid JSON through the safe configuration error contract', async () => { mockGetDescription.mockResolvedValue(descriptionWithConfig('{ "broken": ')); - await expect(handler.get(configurationQuery())).rejects.toThrow(/Unexpected end of JSON input|SyntaxError/); + await expect(handler.get(configurationQuery())).rejects.toMatchObject({ + code: 'configuration.invalid', retryable: false, + recovery: { id: 'stored-configuration-invalid' }, + }); }); }); }); diff --git a/src/manager/description/__tests__/configuration_recovery.test.ts b/src/manager/description/__tests__/configuration_recovery.test.ts new file mode 100644 index 000000000..a72a05c31 --- /dev/null +++ b/src/manager/description/__tests__/configuration_recovery.test.ts @@ -0,0 +1,147 @@ +import { ConfigurationHandler } from '../configuration_handler'; +import { ApplicationError } from '../../../application/errors/application_error'; +import { runWithApplicationErrorCorrelation } from '../../../application/errors/application_error_context'; +import { renderApplicationErrorText } from '../../../application/policies/application_error_presentation_policy'; +import { resolveStaticApplicationErrorCatalog } from '../../../application/policies/application_error_message_catalog'; +import { runSetupExecution } from '../../../application/usecases/execution/setup_execution_workflow'; +import type { SetupExecutionContext } from '../../../application/usecases/execution/setup_execution_contracts'; + +jest.mock('../../../utils/logger', () => ({ logError: jest.fn() })); + +const REFERENCE = '6f173f89-96a3-4fc8-b90e-4f8f48e0e319'; +const query = { owner: 'fixture', repository: 'fixture', issueNumber: 144, token: 'fixture' }; +const block = (json: string) => 'Human PR body\n'; + +function fixture(initialBody: string) { + let body = initialBody; + const getDescription = jest.fn(async () => body); + const updateDescription = jest.fn(); + const handler = new ConfigurationHandler({ getDescription, updateDescription }); + return { handler, getDescription, updateDescription, setBody: (next: string) => { body = next; } }; +} + +function unlinkedPrContext(): SetupExecutionContext { + return { + debug: false, local: false, tokenUser: 'fixture-user', issueNumber: -1, + eventName: 'pull_request', isSingleAction: false, isIssue: false, isPullRequest: true, isPush: false, + issue: { number: -1 }, pullRequest: { number: 144, head: 'codex/integrity-audit', base: 'develop' }, + commit: { branch: '' }, + singleAction: { issue: -1, currentAction: '', isIssue: false, isPullRequest: false, isPush: false }, + branches: { featureTree: 'feature', bugfixTree: 'bugfix', hotfixTree: 'hotfix', releaseTree: 'release', docsTree: 'docs', choreTree: 'chore' }, + labelNames: { feature: 'feature', enhancement: 'enhancement', bugfix: 'bugfix', bug: 'bug', hotfix: 'hotfix', release: 'release', docs: 'docs', documentation: 'documentation', chore: 'chore', maintenance: 'maintenance' }, + currentPullRequestLabels: [], release: { active: false }, hotfix: { active: false }, + }; +} + +describe('stored configuration diagnostics and recovery (#635)', () => { + it.each([ + ['missing schema', '{"branchType":"feature"}', 'stored-configuration-schema-missing', undefined], + ['old schema', '{"schemaVersion":2,"branchType":"feature"}', 'stored-configuration-schema-unsupported', 2], + ['future schema', '{"schemaVersion":99,"branchType":"feature"}', 'stored-configuration-schema-unsupported', 99], + ['malformed JSON', '{"schemaVersion":', 'stored-configuration-invalid', undefined], + ])('rejects %s with safe nonretryable facts and no writes', async (_name, json, id, actualVersion) => { + const f = fixture(block(json as string)); + const error = await runWithApplicationErrorCorrelation(REFERENCE, () => f.handler.get(query).catch(error => error)); + expect(error).toBeInstanceOf(ApplicationError); + expect(error).toMatchObject({ + code: 'configuration.invalid', retryable: false, correlationId: REFERENCE, + recovery: { id, variables: { issueNumber: 144, expectedVersion: 3, ...(actualVersion === undefined ? {} : { actualVersion }) } }, + }); + expect(f.getDescription).toHaveBeenCalledWith('fixture', 'fixture', 144, 'fixture'); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it('keeps an absent block distinct from an invalid stored block', async () => { + const f = fixture('Human PR body without stored state'); + await expect(f.handler.get(query)).resolves.toBeUndefined(); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it('continues reading supported state without rewriting it', async () => { + const f = fixture(block('{"schemaVersion":3,"branchType":"feature","workingBranch":"feature/42-work"}')); + await expect(f.handler.get(query)).resolves.toMatchObject({ schemaVersion: 3, workingBranch: 'feature/42-work' }); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it.each([ + 'null', '[]', '{"schemaVersion":"3"}', '{"schemaVersion":-1}', '{"schemaVersion":1.5}', + '{"schemaVersion":1e99}', '{"schemaVersion":3,"recommendationState":{"invalid":true}}', + ])('rejects malformed payload %s without exposing its contents', async json => { + const f = fixture(block(json)); + await expect(f.handler.get(query)).rejects.toMatchObject({ + code: 'configuration.invalid', retryable: false, recovery: { id: 'stored-configuration-invalid' }, + }); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it.each([ + 'Human body\n', + ])('rejects incomplete markers as invalid state rather than an absent block', async body => { + const f = fixture(body); + await expect(f.handler.get(query)).rejects.toMatchObject({ + code: 'configuration.invalid', recovery: { id: 'stored-configuration-invalid' }, + }); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it.each(['authorization.denied', 'provider.unavailable'] as const)('preserves an originating %s read failure and its reference', async code => { + const f = fixture('unread'); + const original = new ApplicationError(code, 'Safe provider failure.', { correlationId: REFERENCE }); + f.getDescription.mockRejectedValue(original); + await expect(f.handler.get(query)).rejects.toBe(original); + expect(original.recovery).toBeUndefined(); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it.each(['en-US', 'es-MX'])('shows the cause and safe recovery in %s without leaking schema/body text', async locale => { + const secret = 'PRIVATE-BODY-::error::' + 'x'.repeat(10000); + const f = fixture(block(JSON.stringify({ schemaVersion: secret, token: secret }))); + const error = await f.handler.get(query).catch(error => error); + const text = renderApplicationErrorText(error, resolveStaticApplicationErrorCatalog(locale).message); + expect(text).toContain('144'); + expect(text).toContain(locale === 'en-US' ? 'version 3' : 'versión 3'); + expect(text).toContain('configuration.invalid'); + expect(text).toContain(locale === 'en-US' ? 'Retryable: No' : 'Reintentable: No'); + expect(text).toContain('#unsupported-stored-configuration'); + expect(text).toContain(locale === 'en-US' ? 'Do not just add a schema version or delete managed state' : 'No añadas simplemente una versión de esquema ni borres estado gestionado'); + expect(text).toContain(locale === 'en-US' ? 'stop and restore verified supported state' : 'detente y restaura estado compatible verificado'); + expect(text).not.toContain('PRIVATE-BODY'); + expect(JSON.stringify(error)).not.toContain('PRIVATE-BODY'); + expect(text.length).toBeLessThan(1800); + }); + + it('keeps an unchanged invalid PR failed on replay without writes or fabricated linkage', async () => { + const f = fixture(block('{"branchType":"feature"}')); + for (let attempt = 0; attempt < 2; attempt++) { + await expect(f.handler.get(query)).rejects.toMatchObject({ code: 'configuration.invalid', retryable: false }); + } + expect(f.getDescription).toHaveBeenCalledTimes(2); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it('lets verified obsolete-marker removal recover the real unlinked setup route', async () => { + const f = fixture(block('{"branchType":"feature"}')); + const issuePort = { + isPullRequest: jest.fn(), isIssue: jest.fn(), getHeadBranch: jest.fn(), getLabels: jest.fn(async () => []), + getDescription: jest.fn(), getTitle: jest.fn(), + }; + const dependencies = { + issueSetupPort: issuePort, organizationSetupPort: { getTokenUser: jest.fn() }, + configurationPort: { get: (issueNumber: number) => f.handler.get({ ...query, issueNumber }) }, + branchVersionResolver: { resolve: jest.fn() }, + }; + await expect(runSetupExecution(unlinkedPrContext(), dependencies)).rejects.toMatchObject({ code: 'configuration.invalid' }); + f.setBody('Human PR body preserved after a maintainer verified and removed only the obsolete block.'); + const result = await runSetupExecution(unlinkedPrContext(), dependencies); + expect(result).toMatchObject({ + status: 'configured', + state: { previousConfiguration: undefined, configuration: { workingBranch: 'codex/integrity-audit', parentBranch: 'develop' } }, + }); + expect(result.issueResolution.issueNumber).toBeUndefined(); + expect(issuePort.isIssue).not.toHaveBeenCalled(); + expect(issuePort.getDescription).not.toHaveBeenCalled(); + expect(dependencies.branchVersionResolver.resolve).not.toHaveBeenCalled(); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); +}); diff --git a/src/manager/description/configuration_handler.ts b/src/manager/description/configuration_handler.ts index 4bd1e5ca9..67735a917 100644 --- a/src/manager/description/configuration_handler.ts +++ b/src/manager/description/configuration_handler.ts @@ -1,10 +1,10 @@ -import { Config, requireCurrentConfigurationPayload } from "../../data/model/config"; +import { CONFIG_SCHEMA_VERSION, Config, requireCurrentConfigurationPayload } from "../../data/model/config"; import type { ExecutionConfigurationQuery } from "../../application/ports/execution_configuration_ports"; import type { ConfigurationPersistenceContext } from '../../application/ports/configuration_store_ports'; import { logError } from "../../utils/logger"; import { IssueContentInterface } from "./base/issue_content_interface"; import { buildConfigurationPayload } from './configuration_payload_policy'; -import { toApplicationError } from '../../application/errors/application_error'; +import { toApplicationError, type ApplicationErrorRecovery } from '../../application/errors/application_error'; export class ConfigurationHandler extends IssueContentInterface { @@ -22,22 +22,47 @@ export class ConfigurationHandler extends IssueContentInterface { } get = async (query: ExecutionConfigurationQuery): Promise => { + let description: string | undefined; try { - const description = await this.issueDescriptionPort.getDescription( + description = await this.issueDescriptionPort.getDescription( query.owner, query.repository, query.issueNumber, query.token, ); + } catch (cause) { + const semanticError = toApplicationError(cause, 'provider.unavailable', 'Unable to read issue configuration.'); + logError(semanticError); + throw semanticError; + } + + const variables = { issueNumber: query.issueNumber, expectedVersion: CONFIG_SCHEMA_VERSION }; + let recovery: ApplicationErrorRecovery = { id: 'stored-configuration-invalid', variables }; + try { const config = this.getContent(description); if (config === undefined) { + if (description?.includes('')) { + throw new Error('Stored configuration markers are inconsistent.'); + } return undefined; } - const branchConfig = requireCurrentConfigurationPayload(JSON.parse(config)); + const parsed: unknown = JSON.parse(config); + if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) { + const version = (parsed as Record).schemaVersion; + if (version === undefined) { + recovery = { id: 'stored-configuration-schema-missing', variables }; + } else if (typeof version === 'number' && Number.isSafeInteger(version) + && version >= 0 && version !== CONFIG_SCHEMA_VERSION) { + recovery = { id: 'stored-configuration-schema-unsupported', variables: { ...variables, actualVersion: version } }; + } + } + const branchConfig = requireCurrentConfigurationPayload(parsed); return new Config(branchConfig); - } catch (error) { - logError(toApplicationError(error, 'configuration.invalid', 'Unable to read issue configuration.')); - throw error; + } catch (cause) { + const semanticError = toApplicationError(cause, 'configuration.invalid', 'Stored issue/PR configuration is invalid.', { recovery }); + logError(semanticError); + throw semanticError; } } } From 55a75494f75f8b3a328f073c47685aa9c84c7f51 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 11:56:55 +0200 Subject: [PATCH 05/44] chore: bound manual RepoWise history and reuse indexed analysis --- .github/workflows/repowise.yml | 42 +-- .gitignore | 3 + docs/development/testing.mdx | 38 ++- .../security/self-hosted-runners.mdx | 5 +- scripts/repowise_history.py | 160 ++++++++++ scripts/repowise_reports.py | 166 ++++++++++ scripts/tests/test_repowise.py | 287 ++++++++++++++++++ scripts/validate-workflow-contract.cjs | 20 +- specs/CATALOG.md | 8 +- specs/catalog.json | 13 +- specs/local-web-setup-assistant.md | 7 +- specs/merge-queue-readiness.md | 113 ++++++- .../validate_workflow_contract.test.ts | 27 +- 13 files changed, 800 insertions(+), 89 deletions(-) create mode 100644 scripts/repowise_history.py create mode 100644 scripts/repowise_reports.py create mode 100644 scripts/tests/test_repowise.py diff --git a/.github/workflows/repowise.yml b/.github/workflows/repowise.yml index 938c4b642..7ee5cd04a 100644 --- a/.github/workflows/repowise.yml +++ b/.github/workflows/repowise.yml @@ -18,7 +18,7 @@ jobs: code-health: name: RepoWise code health runs-on: [self-hosted, codex, Linux] - timeout-minutes: 30 + timeout-minutes: 40 env: REPOWISE_VENV_NAME: repowise-venv-${{ github.run_id }}-${{ github.run_attempt }}-code-health REPOWISE_REPORT_NAME: repowise-report-${{ github.run_id }}-${{ github.run_attempt }}-code-health @@ -52,54 +52,22 @@ jobs: "$RUNNER_TEMP/$REPOWISE_VENV_NAME/bin/python" -m pip install \ --disable-pip-version-check \ --no-cache-dir \ - 'repowise==0.45.0' + 'repowise==0.58.0' - name: Generate RepoWise reports env: REPOWISE_SKIP_EDITOR_SETUP: '1' run: | set -euo pipefail report_dir="$RUNNER_TEMP/$REPOWISE_REPORT_NAME" - repowise_bin="$RUNNER_TEMP/$REPOWISE_VENV_NAME/bin/repowise" - mkdir -p "$report_dir" - analyzed_sha="$(git rev-parse HEAD)" - printf '%s\n' "$analyzed_sha" > "$report_dir/revision.txt" + python_bin="$RUNNER_TEMP/$REPOWISE_VENV_NAME/bin/python" cleanup() { rm -rf .repowise .mcp.json rm -f .vscode/mcp.json .vscode/extensions.json rmdir .vscode 2>/dev/null || true } trap cleanup EXIT - "$repowise_bin" init \ - --no-prose --no-claude-md --no-codex --no-editor-setup \ - --no-onboarding --no-distill-hook --no-workspace . > "$report_dir/index.log" - "$repowise_bin" health --no-workspace --refactoring-targets --format md . | tee "$report_dir/health.md" - "$repowise_bin" health --no-workspace --refactoring-targets --format json . > "$report_dir/health.json" - advisory_scan() { - local name="$1" - shift - if (ulimit -v 2097152; timeout --kill-after=10s 90s "$@") > "$report_dir/$name.json"; then - printf '%s: complete\n' "$name" >> "$report_dir/advisory-status.txt" - else - local status="$?" - rm -f "$report_dir/$name.json" - printf '%s: incomplete (exit %s)\n' "$name" "$status" >> "$report_dir/advisory-status.txt" - echo "::warning::RepoWise $name advisory scan incomplete (exit $status); completed health reports remain available." - fi - } - advisory_scan dead-code "$repowise_bin" dead-code --safe-only --no-workspace --format json . - echo 'security scope: full reachable history (manual dispatch)' >> "$report_dir/advisory-status.txt" - advisory_scan security "$repowise_bin" security scan --history --path . --format json - { - echo '## RepoWise code health' - echo - echo 'Advisory reports are retained as workflow artifacts for this commit.' - echo - printf 'Analyzed revision: `%s`\n\n' "$analyzed_sha" - sed -n '1,100p' "$report_dir/health.md" - echo - echo '### Advisory scan status' - cat "$report_dir/advisory-status.txt" - } >> "$GITHUB_STEP_SUMMARY" + "$python_bin" -m unittest discover -s scripts/tests -p 'test_repowise*.py' -v + "$python_bin" scripts/repowise_reports.py --report-dir "$report_dir" - name: Upload RepoWise reports if: ${{ always() }} uses: actions/upload-artifact@v6 diff --git a/.gitignore b/.gitignore index 9a83bca90..eb924bdb6 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,6 @@ opencode.json # Repository-local scratch output, including sandboxed Jest transform caches .tmp/ + +# Python analysis tooling +__pycache__/ diff --git a/docs/development/testing.mdx b/docs/development/testing.mdx index e0b9e9dd1..9c952976e 100644 --- a/docs/development/testing.mdx +++ b/docs/development/testing.mdx @@ -111,17 +111,33 @@ reviewed repository branch, and launch it. The CLI equivalent for development is `gh workflow run repowise.yml --ref develop`. The workflow already exists on the default branch, as required for [manual dispatch](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manually-run-a-workflow). -Open the run's Job Summary for the analyzed commit and scan status. Download -the `repowise-code-health` artifact for the index log, Markdown/JSON health -reports, `revision.txt` and `advisory-status.txt`; artifacts are retained for -14 days. History security scans cover the complete reachable history of that -revision. Dead-code and security scans each have a 90-second, 2 GiB limit -inside the 30-minute job budget. An incomplete scan produces a warning and an -incomplete status while preserving completed health reports. A failed health -step fails the run; available files are still uploaded. Inspect the failure -before retrying. A newer manual run for the same ref cancels the older one; -cancellation or runner loss can prevent artifact publication. No manual run -blocks the automatic CI path. +Open the run's Job Summary for the analyzed commit, phase status, elapsed time +and peak RSS. Download `repowise-code-health` (14 days) for health Markdown/JSON, +safe-only dead-code JSON, the security JSON aggregate, index/phase logs, +`revision.txt`, `scope.json`, `timings.json` and `history-resources.json`. + +The pinned RepoWise 0.58.0 builds one fresh standard index and exports its stored +health/dead-code results. Index git analytics retain a 500-commit limit; security +separately covers **all reachable history**, including removed secrets and generated +bundles, using RepoWise's supported source extensions, secret patterns and +allowlists. Historical blob contents are read one at a time. The adapter avoids +computing code-smell findings discarded by history mode. This remains an advisory +signal scanner; an aggregate with no findings is not proof that no secrets exist. + +Indexing has a 900-second/4 GiB virtual-memory cap. Each health export and dead-code +has a 60-second/2 GiB cap; security has a 1200-second/2 GiB cap, inside the +40-minute job. Limits apply per process; reported peak RSS is the largest process, +not aggregate simultaneous memory. These budgets accommodate the roughly 9 GB of +historical JavaScript without retaining all of it in memory. + +An interrupted scan, Git error, stale/failed index or invalid report marks analysis +incomplete and fails this optional run. Completed reports and diagnostics still +upload; invalid JSON is removed. Inspect the named phase log, fix the cause, then +rerun. A newer manual run for the same ref cancels the older one; cancellation or +runner loss can prevent publication. No manual run blocks automatic CI. Upgrading +the pin requires the Python compatibility fixtures, which run before every manual +analysis. They compare secret detection with upstream and verify deleted secrets, +other refs, bounded reads and failures. Manual RepoWise runs use self-hosted Ubuntu `codex` runners. `CI Check` uses that pool for repository-owned PRs and pushes; fork PRs and all merge groups diff --git a/docs/security-operations/security/self-hosted-runners.mdx b/docs/security-operations/security/self-hosted-runners.mdx index 3130652bd..ec0aec513 100644 --- a/docs/security-operations/security/self-hosted-runners.mdx +++ b/docs/security-operations/security/self-hosted-runners.mdx @@ -46,7 +46,10 @@ Publishing currently requires a hosted runner. Their other jobs continue on self-hosted runners. RepoWise obtains a complete Python 3.12 distribution via `actions/setup-python`, creates its virtual environment and reports in run-specific temporary directories, and removes them after artifact upload. -Its runner needs a writable Actions tool cache; the workflow does not install +Its runner needs a writable Actions tool cache and GNU `/usr/bin/time` for phase +RSS evidence. The isolated Python suite verifies the pinned history adapter before +analysis; phase time/virtual-memory caps and a 40-minute job bound the run. +The workflow does not install Ubuntu system packages. RepoWise runs only through manual dispatch on `[self-hosted, codex, Linux]`, using the reviewed repository ref selected by the maintainer. It is optional and must not be required by branch protections or diff --git a/scripts/repowise_history.py b/scripts/repowise_history.py new file mode 100644 index 000000000..f05bd85c0 --- /dev/null +++ b/scripts/repowise_history.py @@ -0,0 +1,160 @@ +"""Bounded full-history adapter for the explicitly pinned RepoWise version. + +Keep RepoWise's traversal, provenance, allowlists, deduplication and detectors. +Replace only its eager blob dictionary and work discarded by secrets-only mode. +Private interfaces are deliberate: upgrades require the compatibility fixtures. +""" + +from __future__ import annotations + +import atexit +from importlib.metadata import version +from pathlib import Path +import subprocess + +REPOWISE_VERSION = "0.58.0" + + +class BlobReader: + """One request/response at a time; never retain previous blob contents.""" + + def __init__(self, repo: Path): + self.process = subprocess.Popen( + ["git", "-C", str(repo), "cat-file", "--batch"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, + ) + self.count = 0 + self.bytes_read = 0 + self.largest_blob = 0 + atexit.register(self.close) + + def get(self, sha: str, default: str = "") -> str: + # Object names come from Git, never accept a batch protocol injection. + if len(sha) not in (40, 64) or any(c not in "0123456789abcdef" for c in sha): + raise ValueError("Invalid blob object name") + self.process.stdin.write((sha + "\n").encode("ascii")) + self.process.stdin.flush() + header = self.process.stdout.readline(256).split() + if len(header) != 3 or header[0].decode("ascii") != sha or header[1] != b"blob": + raise RuntimeError("Missing or malformed Git blob response") + size = int(header[2]) + if size < 0: + raise RuntimeError("Negative Git blob size") + content = self.process.stdout.read(size) + if len(content) != size or self.process.stdout.read(1) != b"\n": + raise RuntimeError("Truncated Git blob response") + self.count += 1 + self.bytes_read += size + self.largest_blob = max(self.largest_blob, size) + if self.count % 1000 == 0: + import sys + print(f"History: {self.count} source blobs, {self.bytes_read} bytes read", file=sys.stderr, flush=True) + return content.decode("utf-8", errors="replace") + + def close(self): + if self.process.poll() is None: + self.process.terminate() + try: + self.process.wait(timeout=2) + except subprocess.TimeoutExpired: + self.process.kill() + self.process.wait() + for stream in (self.process.stdin, self.process.stdout): + if stream: + stream.close() + + +class SecretPrefilter: + # Necessary literals in every line-oriented SECRET_KINDS regex in 0.58.0. + # False positives are allowed; authoritative matching stays in RepoWise. + # PEM is a separate spanning pass and deliberately never gated here. + literals = ( + "password", "apikey", "api_key", "secret", "token", "accesskey", "access_key", + "akia", "asia", "gho_", "ghp_", "ghr_", "ghs_", "ghu_", "github_pat_", + "xox", "aiza", "sk_", "rk_", "glpat-", "gldt-", "glrt-", "glptt-", + "gloas-", "glimt-", "glcbt-", "gr1348941", "azdo", "://", + ) + + def search(self, text): + # Python IGNORECASE also accepts dotless i, long s and dotted I. + lowered = text.lower().replace("ı", "i").replace("ſ", "s").replace("\u0307", "") + return any(literal in lowered for literal in self.literals) + + +def configure_secret_scan(): + from repowise.core.analysis.security import scanner + from repowise.core.analysis.security.patterns import SECRET_KINDS + + scanner._PATTERNS = [p for p in scanner._PATTERNS if p[1] in SECRET_KINDS] + scanner._SPANNING_PATTERNS = [p for p in scanner._SPANNING_PATTERNS if p[1] in SECRET_KINDS] + scanner._ANY_PATTERN = SecretPrefilter() + # History's secrets_only=True discards all call findings; don't compute them. + scanner._call_findings = lambda *args: [] + + +def strict_git(repo_path, args, *, timeout=30.0): + # Upstream's best-effort helper returns an empty string on Git failures, + # which could otherwise turn a failed history enumeration into a clean scan. + return subprocess.run( + ["git", "-C", str(repo_path), *args], check=True, timeout=timeout, + capture_output=True, text=True, encoding="utf-8", errors="replace", + ).stdout + + +def fail_on_persistence_error(): + import logging + + class PersistenceFailure(logging.Handler): + def emit(self, record): + if record.getMessage().startswith("security_finding_persist_failed"): + raise RuntimeError("History finding persistence failed") + + logger = logging.getLogger("repowise.core.analysis.security_scan") + # Override the CLI's ancestor ERROR level: upstream logs swallowed writes + # at WARNING. This handler raises before a diagnostic can pollute JSON. + logger.setLevel(logging.WARNING) + handler = PersistenceFailure() + logger.addHandler(handler) + return handler + + +def main(): + import json + import os + + if version("repowise") != REPOWISE_VERSION: + raise RuntimeError("Unsupported RepoWise version; rerun compatibility fixtures before upgrading") + from repowise.core.analysis import history_scan + from repowise.cli.main import cli + + readers = [] + original = history_scan.HistorySecurityScanner + + class BoundedHistoryScanner(original): + def _read_blobs_batch(self, repo_path, blob_shas): + reader = BlobReader(repo_path) + readers.append(reader) + return reader + + fail_on_persistence_error() + history_scan._run_git = strict_git + history_scan.HistorySecurityScanner = BoundedHistoryScanner + configure_secret_scan() + try: + cli(["security", "scan", "--history", "--path", ".", "--format", "json"]) + finally: + for reader in readers: + reader.close() + metrics = os.environ.get("REPOWISE_HISTORY_METRICS") + if metrics: + Path(metrics).write_text(json.dumps({ + "blobs_read": sum(r.count for r in readers), + "bytes_read": sum(r.bytes_read for r in readers), + "largest_blob_bytes": max((r.largest_blob for r in readers), default=0), + "reader_cache_blobs": 0, + "max_blob_requests_in_flight": 1, + }) + "\n") + + +if __name__ == "__main__": + main() diff --git a/scripts/repowise_reports.py b/scripts/repowise_reports.py new file mode 100644 index 000000000..55d50a797 --- /dev/null +++ b/scripts/repowise_reports.py @@ -0,0 +1,166 @@ +"""Manual RepoWise orchestration. Stdlib only; no application/runtime dependency.""" + +from __future__ import annotations + +import argparse +import json +import os +from pathlib import Path +import resource +import signal +import subprocess +import sys +import time + +from repowise_history import REPOWISE_VERSION + +# Maximum wall seconds and virtual MiB per process. Sum fits the 40-minute job, +# leaving setup, tests, publication and cleanup time. No caller-controlled flags. +BUDGETS = {"index": (900, 4096), "health-md": (60, 2048), + "health-json": (60, 2048), "dead-code": (60, 2048), "security": (1200, 2048)} + + +def validate_index(path): + events = [json.loads(line) for line in path.read_text().splitlines() if line.strip()] + summaries = [e for e in events if e.get("event") == "summary"] + dead = [e for e in events if e.get("phase") == "dead_code" and e.get("state") == "done"] + health = [e for e in events if e.get("phase") == "health" and e.get("state") == "done"] + if not summaries or summaries[-1].get("status") != "ready" or not dead or not health: + raise ValueError("Index did not confirm ready status and completed dead-code analysis") + if any(e.get("state") in ("failed", "error") for e in events): + raise ValueError("Index contains an incomplete phase") + state = json.loads(Path(".repowise/state.json").read_text()) + head = subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip() + if state.get("last_sync_commit") != head: + raise ValueError("Index revision does not match HEAD") + + +def validate_json(path, kind): + value = json.loads(path.read_text()) + if kind == "dead-code": + if not isinstance(value, list) or not all(isinstance(f, dict) and "kind" in f for f in value): + raise ValueError("Invalid dead-code report") + return value + if not isinstance(value, dict): + raise ValueError("Expected a JSON object") + required = {"health-json": ("targets", "refactoring_plans"), + "security": ("commits_scanned", "files_scanned", "blobs_scanned", "by_kind", "by_severity")}[kind] + if not all(k in value for k in required): + raise ValueError("Incomplete report schema") + if kind == "health-json" and value.get("source") != "index": + raise ValueError("Health report did not reuse the index") + if kind == "security" and (value["commits_scanned"] <= 0 or value["files_scanned"] <= 0): + raise ValueError("History scan did not cover any commits or source blobs") + if kind == "security": + expected = int(subprocess.check_output(["git", "rev-list", "--all", "--count"], text=True)) + measured = json.loads((path.parent / "history-resources.json").read_text()) + if value["commits_scanned"] != expected or measured["blobs_read"] != value["files_scanned"]: + raise ValueError("History coverage does not match reachable commits and requested source blobs") + return value + + +def run_stage(name, command, output, report_dir, validator=None): + seconds, memory_mib = BUDGETS[name] + started = time.monotonic() + measurement = report_dir / (name + ".resources.txt") + result = {"status": "incomplete", "timeout_seconds": seconds, "virtual_memory_mib": memory_mib} + + def limits(): + resource.setrlimit(resource.RLIMIT_AS, (memory_mib * 1024**2,) * 2) + + try: + with output.open("w") as out, (report_dir / (name + ".stderr.log")).open("w") as err: + process = subprocess.Popen( + ["/usr/bin/time", "-f", "%e %M", "-o", str(measurement), *command], + stdout=out, stderr=err, start_new_session=True, preexec_fn=limits, + ) + try: + code = process.wait(timeout=seconds) + except subprocess.TimeoutExpired: + os.killpg(process.pid, signal.SIGKILL) + process.wait() + raise RuntimeError(f"Timed out after {seconds}s") + if code: + raise RuntimeError(f"Command exited {code}; inspect {name}.stderr.log") + if validator: + validator(output) + elif not output.stat().st_size: + raise ValueError("Empty report") + result["status"] = "complete" + except Exception as error: + result["error"] = str(error) + # Keep diagnostic/index logs; never publish malformed JSON as a report. + if output.suffix == ".json": + output.unlink(missing_ok=True) + print(f"::warning::RepoWise {name} incomplete: {error}", flush=True) + finally: + result["wall_seconds"] = round(time.monotonic() - started, 3) + if measurement.exists(): + fields = (measurement.read_text().splitlines() or [""])[-1].split() + if len(fields) == 2 and fields[1].isdigit(): + result["peak_rss_kib"] = int(fields[1]) + print(f"RepoWise {name}: {result['status']} ({result['wall_seconds']}s)", flush=True) + return result + + +def write_summary(report_dir, sha, results): + lines = ["## RepoWise code health", "", f"Analyzed revision: `{sha}`", "", + "Security scope: full reachable history, RepoWise secret patterns; generated bundles included.", + "Health and safe-only dead-code: stored results from this revision's completed index.", "", + "| Phase | Status | Seconds | Peak RSS (MiB) |", "|---|---|---:|---:|"] + for name, result in results.items(): + rss = result.get("peak_rss_kib") + lines.append(f"| {name} | {result['status']} | {result.get('wall_seconds', '—')} | {round(rss / 1024, 1) if rss is not None else '—'} |") + incomplete = any(r["status"] != "complete" for r in results.values()) + lines += ["", ("Analysis incomplete. Inspect phase logs in the artifact, fix the cause, then rerun." + if incomplete else "Analysis complete. Findings are advisory; download the reports to review them."), + "Artifact: `repowise-code-health` (14 days), including scope, timings, logs and completed reports.", ""] + text = "\n".join(lines) + (report_dir / "summary.md").write_text(text) + (report_dir / "timings.json").write_text(json.dumps(results, indent=2) + "\n") + (report_dir / "advisory-status.txt").write_text("\n".join(f"{n}: {r['status']}" for n, r in results.items()) + "\n") + if os.environ.get("GITHUB_STEP_SUMMARY"): + with open(os.environ["GITHUB_STEP_SUMMARY"], "a") as summary: + summary.write(text) + return incomplete + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--report-dir", required=True, type=Path) + args = parser.parse_args() + report_dir = args.report_dir.resolve() + report_dir.mkdir(parents=True, exist_ok=True) + sha = subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip() + (report_dir / "revision.txt").write_text(sha + "\n") + refs = subprocess.check_output(["git", "for-each-ref", "--format=%(objectname) %(refname)"], text=True).splitlines() + (report_dir / "scope.json").write_text(json.dumps({ + "revision": sha, "refs": refs, "repowise_version": REPOWISE_VERSION, + "security": "full reachable history (--all), RepoWise source extensions and secret patterns; upstream allowlists apply", + "health": "all indexed origins, cached refactoring targets", "dead_code": "cached safe-only findings", + "index_commit_limit": 500, "history_commit_limit": None, + }, indent=2) + "\n") + os.environ.update(OPENBLAS_NUM_THREADS="1", OMP_NUM_THREADS="1", REPOWISE_SKIP_EDITOR_SETUP="1", REPOWISE_NO_SAVE_KEY="1", + REPOWISE_HISTORY_METRICS=str(report_dir / "history-resources.json")) + binary = str(Path(sys.executable).with_name("repowise")) + commands = { + "index": ([binary, "init", "--no-prose", "--no-claude-md", "--no-codex", "--no-editor-setup", + "--no-onboarding", "--no-distill-hook", "--no-workspace", "--no-seed", "--no-save-key", + "--commit-limit", "500", "--progress", "json", "."], "index.log", validate_index), + "health-md": ([binary, "health", "--no-workspace", "--refactoring-targets", "--scope", "all", "--format", "md", "."], "health.md", None), + "health-json": ([binary, "health", "--no-workspace", "--refactoring-targets", "--scope", "all", "--format", "json", "."], "health.json", lambda p: validate_json(p, "health-json")), + "dead-code": ([binary, "dead-code", "--safe-only", "--no-workspace", "--format", "json", "."], "dead-code.json", lambda p: validate_json(p, "dead-code")), + "security": ([sys.executable, str(Path(__file__).with_name("repowise_history.py"))], "security.json", lambda p: validate_json(p, "security")), + } + results = {} + for name, (command, filename, validator) in commands.items(): + # Exporting cached empty data after a failed index would be misleading. + if name != "security" and name != "index" and results["index"]["status"] != "complete": + results[name] = {"status": "incomplete", "error": "Index did not complete"} + continue + results[name] = run_stage(name, command, report_dir / filename, report_dir, validator) + return int(write_summary(report_dir, sha, results)) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/tests/test_repowise.py b/scripts/tests/test_repowise.py new file mode 100644 index 000000000..926c631ca --- /dev/null +++ b/scripts/tests/test_repowise.py @@ -0,0 +1,287 @@ +"""Pinned-package compatibility and resource/failure regressions for manual CI.""" + +import asyncio +from contextlib import contextmanager +from importlib.metadata import version +import io +import json +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest +from unittest.mock import Mock, patch + +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) +import repowise_history as history +import repowise_reports as reports +from repowise.core.analysis import history_scan +from repowise.core.analysis.security import scanner +from repowise.core.analysis.security.patterns import SECRET_KINDS + + +@contextmanager +def optimized(): + names = ("_PATTERNS", "_SPANNING_PATTERNS", "_ANY_PATTERN", "_call_findings") + saved = {name: getattr(scanner, name) for name in names} + try: + history.configure_secret_scan() + yield + finally: + for name, value in saved.items(): + setattr(scanner, name, value) + + +class SecretCompatibility(unittest.TestCase): + def compare(self, kind, text): + expected = [f for f in scanner.scan_source("src/code.ts", text) if f["kind"] in SECRET_KINDS] + self.assertIn(kind, {f["kind"] for f in expected}) + with optimized(): + self.assertEqual(expected, scanner.scan_source("src/code.ts", text)) + + def test_pin(self): + self.assertEqual(history.REPOWISE_VERSION, version("repowise")) + + def test_password(self): + self.compare("hardcoded_password", 'password = "Q9vLm2rX7pNs4kT8"') + + def test_secret(self): + self.compare("hardcoded_secret", 'API_KEY = "V8mK2qZ9fT4nY7jP"') + + def test_unicode_case(self): + self.compare("hardcoded_secret", 'APı_KEY = "V8mK2qZ9fT4nY7jP"') + + def test_aws(self): + self.compare("aws_access_key", 'const x = "AK' + 'IA' + 'QWERTYUIOPASDFGH"') + + def test_github(self): + self.compare("github_token", 'const x = "gh' + 'p_' + 'Q2wE3rT4yU5iO6pA7sD8fG9hJ0kL1zX2cV3b' + '"') + + def test_slack(self): + self.compare("slack_token", 'const x = "xo' + 'xb-' + '123456789012-987654321012-A7bC9dE2fG4hI6jK"') + + def test_google(self): + self.compare("google_api_key", 'const x = "AI' + 'za' + 'Q2wE3rT4yU5iO6pA7sD8fG9hJ0kL1zX2cV3"') + + def test_stripe(self): + self.compare("stripe_key", 'const x = "sk_' + 'live_' + 'Q2wE3rT4yU5iO6pA7sD8fG9h"') + + def test_gitlab(self): + self.compare("gitlab_token", 'const x = "gl' + 'pat-' + 'Q2wE3rT4yU5iO6pA7sD8fG9h"') + + def test_azure(self): + self.compare("azure_devops_pat", 'const x = "' + ('Q2wE3rT4yU5iO6pA7sD8fG9hJ0kL1zX2cV3bN4m' * 3)[:76] + 'AZDOq7W2"') + + def test_git_url(self): + self.compare("git_url_credentials", 'const x = "https://user:Q9vLm2rX7pNs4kT8@github.com/org/repo.git"') + + def test_multiline_pem(self): + self.compare("private_key_pem", '-----BEGIN PRIVATE KEY-----\n' + 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASC' * 3 + '\n-----END PRIVATE KEY-----') + + def test_placeholders_and_suppression(self): + text = 'api_key = "example"; eval("code");\n// repowise:ignore\npassword = "${ENV}"' + expected = [f for f in scanner.scan_source("tests/a.ts", text) if f["kind"] in SECRET_KINDS] + with optimized(): + self.assertEqual(expected, scanner.scan_source("tests/a.ts", text)) + + +class BlobProtocol(unittest.TestCase): + def reader(self, response): + process = Mock(stdin=io.BytesIO(), stdout=io.BytesIO(response)) + process.poll.return_value = 0 + with patch.object(history.subprocess, "Popen", return_value=process), patch.object(history.atexit, "register"): + return history.BlobReader(Path(".")) + + def test_sequential_blobs_no_cache(self): + sha = "a" * 40 + reader = self.reader(f"{sha} blob 3\none\n{sha} blob 3\ntwo\n".encode()) + self.assertEqual("one", reader.get(sha)) + self.assertEqual("two", reader.get(sha)) + self.assertEqual((2, 6, 3), (reader.count, reader.bytes_read, reader.largest_blob)) + self.assertNotIn("contents", reader.__dict__) + + def test_missing_blob_fails(self): + reader = self.reader(b"a missing\n") + with self.assertRaises(RuntimeError): + reader.get("a" * 40) + + def test_truncated_blob_fails(self): + reader = self.reader(("a" * 40 + " blob 100\nshort").encode()) + with self.assertRaises(RuntimeError): + reader.get("a" * 40) + + def test_protocol_injection_rejected(self): + with self.assertRaises(ValueError): + self.reader(b"").get("HEAD\nHEAD") + + def test_git_error_is_not_empty_history(self): + with tempfile.TemporaryDirectory() as directory: + with self.assertRaises(subprocess.CalledProcessError): + history.strict_git(Path(directory), ["rev-list", "--all"]) + + +class HistoryIntegration(unittest.TestCase): + def test_deleted_and_other_ref_secrets_preserve_upstream_provenance(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + def git(*args): + return subprocess.check_output(["git", "-C", directory, *args], stderr=subprocess.DEVNULL, text=True).strip() + git("init", "-b", "main") + git("config", "user.name", "Fixture") + git("config", "user.email", "fixture@example.invalid") + (root / "deleted.ts").write_text('password = "Q9vLm2rX7pNs4kT8"') + git("add", ".") + git("-c", "core.hooksPath=/dev/null", "commit", "-qm", "introduce") + introduction = git("rev-parse", "HEAD") + git("rm", "deleted.ts") + git("-c", "core.hooksPath=/dev/null", "commit", "-qm", "remove") + git("checkout", "-b", "other") + (root / "other.ts").write_text('secret = "J4fT8nP2qW6rY9kZ"') + git("add", ".") + git("-c", "core.hooksPath=/dev/null", "commit", "-qm", "other branch") + git("checkout", "main") + + class Sink: + def __init__(self): self.saved = [] + async def scan_file(self, path, content, symbols): return scanner.scan_source(path, content, symbols) + async def persist(self, path, findings, **provenance): + self.saved.append((path, findings, provenance)) + return len(findings) + + async def scan(bounded): + instance = history_scan.HistorySecurityScanner(None, "fixture") + sink = Sink() + instance._scanner = sink + reader = history.BlobReader(root) if bounded else None + if bounded: + instance._read_blobs_batch = lambda *_: reader + try: + with patch.object(history_scan, "_run_git", history.strict_git): + summary = await instance.scan_history(root) + return summary, sink.saved + finally: + if reader: reader.close() + + expected = asyncio.run(scan(False)) + with optimized(): actual = asyncio.run(scan(True)) + self.assertEqual(expected, actual) + self.assertEqual(3, actual[0].commits_scanned) + self.assertEqual(2, actual[0].findings_inserted) + deleted = next(f for f in actual[1] if f[0] == "deleted.ts") + self.assertEqual(introduction, deleted[2]["commit_sha"]) + + +class ReportFailures(unittest.TestCase): + def test_swallowed_persistence_failure_becomes_fatal(self): + from repowise.core.analysis.security.store import SecurityScanner, logger + from unittest.mock import AsyncMock + previous = logger.level + handler = history.fail_on_persistence_error() + session = Mock(); session.execute = AsyncMock(side_effect=RuntimeError("broken database")) + try: + instance = SecurityScanner(session, "fixture") + with self.assertRaisesRegex(RuntimeError, "persistence failed"): + asyncio.run(instance.persist("a.ts", [{"kind": "hardcoded_secret", "severity": "high"}])) + finally: + logger.removeHandler(handler) + logger.setLevel(previous) + + def test_budgets_fit_job_with_publication_margin(self): + self.assertLessEqual(sum(v[0] for v in reports.BUDGETS.values()), 38 * 60) + self.assertEqual((1200, 2048), reports.BUDGETS["security"]) + self.assertEqual((60, 2048), reports.BUDGETS["dead-code"]) + + def test_success_measures_rss_and_publishes_valid_json(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory); p = root / "dead-code.json" + def start(command, **kwargs): + kwargs["stdout"].write("[]") + kwargs["stdout"].flush() + (root / "dead-code.resources.txt").write_text("1.2 2048\n") + process = Mock(); process.wait.return_value = 0 + return process + with patch.object(reports.subprocess, "Popen", side_effect=start): + result = reports.run_stage("dead-code", ["fixture"], p, root, lambda p: reports.validate_json(p, "dead-code")) + self.assertEqual("complete", result["status"]) + self.assertEqual(2048, result["peak_rss_kib"]) + self.assertTrue(p.exists()) + + def test_command_failure_is_incomplete(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory); process = Mock(); process.wait.return_value = 1 + with patch.object(reports.subprocess, "Popen", return_value=process): + result = reports.run_stage("security", ["fixture"], root / "security.json", root) + self.assertEqual("incomplete", result["status"]) + self.assertIn("exited 1", result["error"]) + + def test_security_coverage_mismatch_rejected(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory); p = root / "security.json" + p.write_text(json.dumps(dict(commits_scanned=3, files_scanned=2, blobs_scanned=3, by_kind={}, by_severity={}))) + (root / "history-resources.json").write_text('{"blobs_read":1}') + with patch.object(reports.subprocess, "check_output", return_value="3"): + with self.assertRaises(ValueError): reports.validate_json(p, "security") + + def test_live_health_report_rejected(self): + with tempfile.TemporaryDirectory() as directory: + p = Path(directory) / "health.json" + p.write_text('{"targets":[],"refactoring_plans":[],"source":"live"}') + with self.assertRaises(ValueError): reports.validate_json(p, "health-json") + + def test_dead_code_report_schema_rejected(self): + with tempfile.TemporaryDirectory() as directory: + p = Path(directory) / "dead-code.json"; p.write_text('{}') + with self.assertRaises(ValueError): reports.validate_json(p, "dead-code") + + def test_index_requires_completed_dead_code(self): + with tempfile.TemporaryDirectory() as directory: + p = Path(directory) / "index.log" + p.write_text(json.dumps({"event": "summary", "status": "ready"}) + "\n") + with self.assertRaises(ValueError): reports.validate_index(p) + + def test_index_rejects_degraded(self): + with tempfile.TemporaryDirectory() as directory: + p = Path(directory) / "index.log" + p.write_text('{"phase":"dead_code","state":"done"}\n{"event":"summary","status":"partial"}\n') + with self.assertRaises(ValueError): reports.validate_index(p) + + def test_malformed_json_deleted_and_failure_reported(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory); p = root / "security.json" + process = Mock(pid=1234); process.wait.return_value = 0 + with patch.object(reports.subprocess, "Popen", return_value=process): + result = reports.run_stage("security", ["fixture"], p, root, lambda p: reports.validate_json(p, "security")) + self.assertEqual("incomplete", result["status"]) + self.assertFalse(p.exists()) + + def test_timeout_kills_process_group(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory); process = Mock(pid=1234) + process.wait.side_effect = [subprocess.TimeoutExpired("fixture", 1), 0] + with patch.object(reports.subprocess, "Popen", return_value=process), patch.object(reports.os, "killpg") as kill: + result = reports.run_stage("dead-code", ["fixture"], root / "dead-code.json", root) + kill.assert_called_once_with(1234, reports.signal.SIGKILL) + self.assertEqual("incomplete", result["status"]) + + def test_empty_security_coverage_rejected(self): + with tempfile.TemporaryDirectory() as directory: + p = Path(directory) / "security.json" + p.write_text(json.dumps(dict(commits_scanned=0, files_scanned=0, blobs_scanned=0, by_kind={}, by_severity={}))) + with self.assertRaises(ValueError): reports.validate_json(p, "security") + + def test_partial_summary_retains_complete_phases(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + incomplete = reports.write_summary(root, "a" * 40, { + "health-md": {"status": "complete", "wall_seconds": 1, "peak_rss_kib": 1024}, + "security": {"status": "incomplete", "wall_seconds": 1200}, + }) + self.assertTrue(incomplete) + text = (root / "summary.md").read_text() + self.assertIn("Analysis incomplete", text) + self.assertIn("| health-md | complete |", text) + self.assertIn("full reachable history", text) + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/validate-workflow-contract.cjs b/scripts/validate-workflow-contract.cjs index 06f2e5447..51eb5fb60 100644 --- a/scripts/validate-workflow-contract.cjs +++ b/scripts/validate-workflow-contract.cjs @@ -259,19 +259,15 @@ function assertRepoWiseTemporaryCleanup(relativeFile, job) { throw new Error(`${relativeFile} must select complete Python, isolate RepoWise files, and remove them after artifact upload.`); } const reports = (job.steps ?? []).find(step => step?.name === 'Generate RepoWise reports'); - if (!reports?.run?.includes('advisory_scan security "$repowise_bin" security scan --history --path . --format json') - || !reports.run.includes('security scope: full reachable history (manual dispatch)') - || !reports.run.includes('ulimit -v 2097152; timeout --kill-after=10s 90s') - || !reports.run.includes('incomplete (exit %s)') - || !reports.run.includes('health --no-workspace --refactoring-targets --format md') - || !reports.run.includes('health --no-workspace --refactoring-targets --format json') - || !reports.run.includes('analyzed_sha="$(git rev-parse HEAD)"') - || !reports.run.includes('printf \'%s\\n\' "$analyzed_sha" > "$report_dir/revision.txt"') - || !reports.run.includes('printf \'Analyzed revision: `%s`\\n\\n\' "$analyzed_sha"') - || !reports.run.includes('>> "$GITHUB_STEP_SUMMARY"') + const install = (job.steps ?? []).find(step => step?.name === 'Install RepoWise'); + if (!install?.run?.includes("'repowise==0.58.0'") + || !reports?.run?.includes('"$python_bin" scripts/repowise_reports.py --report-dir "$report_dir"') + || !reports.run.includes('"$python_bin" -m unittest discover -s scripts/tests -p \'test_repowise*.py\' -v') + || !reports.run.includes('trap cleanup EXIT') + || reports.run.replace('rmdir .vscode 2>/dev/null || true', '').includes('|| true') || upload.if !== '${{ always() }}' || upload.with?.['retention-days'] !== 14) { - throw new Error(`${relativeFile} must preserve bounded manual history scans, health reports, revision evidence, summary and unconditional artifacts.`); + throw new Error(`${relativeFile} must preserve pinned bounded reports, compatibility tests, cleanup and unconditional artifacts.`); } } @@ -283,7 +279,7 @@ function assertManualRepoWiseWorkflow(file, workflow) { } const job = workflow.jobs?.['code-health']; const checkout = (job?.steps ?? []).find(step => step?.uses === CHECKOUT_ACTION); - if (job?.['timeout-minutes'] !== 30 + if (job?.['timeout-minutes'] !== 40 || JSON.stringify(workflow.permissions) !== JSON.stringify({ contents: 'read' }) || job.permissions !== undefined || checkout?.with?.['fetch-depth'] !== 0 diff --git a/specs/CATALOG.md b/specs/CATALOG.md index 1cabdc39b..e78248ac6 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -12,7 +12,7 @@ debt or convert unknown historic intent into a design decision. |---|---|---|---|---| | `github-communication-experience` | Implemented | English-default, localized, semantic, bounded, and idempotent product messages across GitHub and repository-aware operator surfaces | [Semantic GitHub communication and repository localization](./semantic-github-publication-and-notification.md) + 3 companion | 277 paths · 2026-10-20 | | `release-orchestration` | Implemented | Release and hotfix promotion, publication, bounded merge readiness recovery, and receipt-verified reconciliation without republication | [Configurable production-first release orchestration](./configurable-release-orchestration.md) + 2 companion | 59 paths · 2026-10-16 | -| `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 24 paths · 2026-10-21 | +| `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration; cached RepoWise exports and bounded full-history secret processing with truthful completeness and resource evidence | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 29 paths · 2026-10-21 | | `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 59 paths · 2026-10-11 | | `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 97 paths · 2026-10-14 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | @@ -63,9 +63,9 @@ debt or convert unknown historic intent into a design decision. - Specifications: [`specs/merge-queue-readiness.md`](./merge-queue-readiness.md) - Workflows: [`.github/workflows/ci_check.yml`](../.github/workflows/ci_check.yml) · [`.github/workflows/repowise.yml`](../.github/workflows/repowise.yml) · [`.github/workflows/copilot_pull_request_merge_queue.yml`](../.github/workflows/copilot_pull_request_merge_queue.yml) · [`setup/workflows/copilot_pull_request_merge_queue.yml`](../setup/workflows/copilot_pull_request_merge_queue.yml) · [`.github/workflows/copilot_deployment_orchestration.yml`](../.github/workflows/copilot_deployment_orchestration.yml) - Entrypoints: [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) -- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`src/domain/merge_queue_readiness.ts`](../src/domain/merge_queue_readiness.ts) · [`src/application/policies/merge_queue_message_catalog.ts`](../src/application/policies/merge_queue_message_catalog.ts) · [`src/application/policies/deployment_message_catalog.ts`](../src/application/policies/deployment_message_catalog.ts) · [`src/application/policies/deployment_plan_policy.ts`](../src/application/policies/deployment_plan_policy.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) · [`src/data/repository/deployment/github_target_merge_capabilities_inspector.ts`](../src/data/repository/deployment/github_target_merge_capabilities_inspector.ts) · [`src/infrastructure/github/octokit_checks_adapters.ts`](../src/infrastructure/github/octokit_checks_adapters.ts) · [`scripts/validate-workflow-contract.cjs`](../scripts/validate-workflow-contract.cjs) -- Tests: [`src/domain/__tests__/merge_queue_readiness.test.ts`](../src/domain/__tests__/merge_queue_readiness.test.ts) · [`src/application/policies/__tests__/deployment_plan_policy.test.ts`](../src/application/policies/__tests__/deployment_plan_policy.test.ts) · [`src/application/policies/__tests__/setup_doctor_message_catalog.test.ts`](../src/application/policies/__tests__/setup_doctor_message_catalog.test.ts) · [`src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts`](../src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts) · [`src/data/repository/deployment/__tests__/github_deployment_adapters.test.ts`](../src/data/repository/deployment/__tests__/github_deployment_adapters.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) -- User documentation: [`docs/issues/deployment-orchestration.mdx`](../docs/issues/deployment-orchestration.mdx) · [`docs/security-operations/operations/verification.mdx`](../docs/security-operations/operations/verification.mdx) +- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`src/domain/merge_queue_readiness.ts`](../src/domain/merge_queue_readiness.ts) · [`src/application/policies/merge_queue_message_catalog.ts`](../src/application/policies/merge_queue_message_catalog.ts) · [`src/application/policies/deployment_message_catalog.ts`](../src/application/policies/deployment_message_catalog.ts) · [`src/application/policies/deployment_plan_policy.ts`](../src/application/policies/deployment_plan_policy.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) · [`src/data/repository/deployment/github_target_merge_capabilities_inspector.ts`](../src/data/repository/deployment/github_target_merge_capabilities_inspector.ts) · [`src/infrastructure/github/octokit_checks_adapters.ts`](../src/infrastructure/github/octokit_checks_adapters.ts) · [`scripts/validate-workflow-contract.cjs`](../scripts/validate-workflow-contract.cjs) · [`scripts/repowise_history.py`](../scripts/repowise_history.py) · [`scripts/repowise_reports.py`](../scripts/repowise_reports.py) +- Tests: [`src/domain/__tests__/merge_queue_readiness.test.ts`](../src/domain/__tests__/merge_queue_readiness.test.ts) · [`src/application/policies/__tests__/deployment_plan_policy.test.ts`](../src/application/policies/__tests__/deployment_plan_policy.test.ts) · [`src/application/policies/__tests__/setup_doctor_message_catalog.test.ts`](../src/application/policies/__tests__/setup_doctor_message_catalog.test.ts) · [`src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts`](../src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts) · [`src/data/repository/deployment/__tests__/github_deployment_adapters.test.ts`](../src/data/repository/deployment/__tests__/github_deployment_adapters.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) · [`scripts/tests/test_repowise.py`](../scripts/tests/test_repowise.py) +- User documentation: [`docs/issues/deployment-orchestration.mdx`](../docs/issues/deployment-orchestration.mdx) · [`docs/security-operations/operations/verification.mdx`](../docs/security-operations/operations/verification.mdx) · [`docs/development/testing.mdx`](../docs/development/testing.mdx) · [`docs/security-operations/security/self-hosted-runners.mdx`](../docs/security-operations/security/self-hosted-runners.mdx) ### `bugbot-review-state-reconciliation` — Bugbot review-state reconciliation diff --git a/specs/catalog.json b/specs/catalog.json index 5aa5def10..7bb958ab6 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -388,7 +388,7 @@ "id": "merge-queue-readiness", "title": "Merge queue readiness and effective target rules", "status": "implemented", - "scope": "Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration", + "scope": "Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration; cached RepoWise exports and bounded full-history secret processing with truthful completeness and resource evidence", "owner": "Copilot maintainers", "lastVerified": "2026-10-21", "specs": [ @@ -414,7 +414,9 @@ "src/application/usecases/setup/merge_queue_readiness_use_case.ts", "src/data/repository/deployment/github_target_merge_capabilities_inspector.ts", "src/infrastructure/github/octokit_checks_adapters.ts", - "scripts/validate-workflow-contract.cjs" + "scripts/validate-workflow-contract.cjs", + "scripts/repowise_history.py", + "scripts/repowise_reports.py" ], "tests": [ "src/domain/__tests__/merge_queue_readiness.test.ts", @@ -422,11 +424,14 @@ "src/application/policies/__tests__/setup_doctor_message_catalog.test.ts", "src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts", "src/data/repository/deployment/__tests__/github_deployment_adapters.test.ts", - "src/tooling/__tests__/validate_workflow_contract.test.ts" + "src/tooling/__tests__/validate_workflow_contract.test.ts", + "scripts/tests/test_repowise.py" ], "documentation": [ "docs/issues/deployment-orchestration.mdx", - "docs/security-operations/operations/verification.mdx" + "docs/security-operations/operations/verification.mdx", + "docs/development/testing.mdx", + "docs/security-operations/security/self-hosted-runners.mdx" ] }, { diff --git a/specs/local-web-setup-assistant.md b/specs/local-web-setup-assistant.md index 72f8a0840..b52c967be 100644 --- a/specs/local-web-setup-assistant.md +++ b/specs/local-web-setup-assistant.md @@ -2451,9 +2451,10 @@ now run only under `workflow_dispatch` on Ubuntu `codex` with the native selecte repository ref; it MUST NOT run on PR, push or merge-group events or be required for them. The retained CI routing cases still prove the fork/merge-group trust boundary. The [manual-only migration contract](./merge-queue-readiness.md#manual-only-repowise-migration-2026-10-21-issue-639) -defines the 24-case regression floor, live required-check evidence, immutable -revision reporting, unchanged scan budgets and cleanup, operator journey, -failure/retry behavior and final-revision manual acceptance. This is a workflow +and its [bounded-analysis follow-up](./merge-queue-readiness.md#bounded-manual-repowise-analysis-2026-10-21-issue-644) +define the 54-case regression floor, live required-check evidence, immutable +revision reporting, measured phase budgets and cleanup, operator journey, +failure/retry behavior and complete final-revision manual acceptance. This is a workflow scheduling change with no setup-session, PAT, web UX or new configuration change. The first [RepoWise run on `e197cb0c`](https://github.com/vypdev/copilot/actions/runs/37289899480) diff --git a/specs/merge-queue-readiness.md b/specs/merge-queue-readiness.md index 5cdc3f774..5e8c2b113 100644 --- a/specs/merge-queue-readiness.md +++ b/specs/merge-queue-readiness.md @@ -193,10 +193,10 @@ already exists on the default branch. CLI example: `gh workflow run repowise.yml --ref develop`. The workflow owns event admission, Ubuntu `codex` runner selection, read-only -contents permission and a 30-minute job budget. Checkout MUST retain the selected -revision and full history without credentials. Each advisory subprocess retains -its 90-second and 2 GiB limits; manual security scanning covers full reachable -history. Per-ref `repowise-` concurrency cancels an older manual run for the same +contents permission and originally a 30-minute job budget. Checkout MUST retain the selected +revision and full history without credentials. The original advisory subprocesses used +90-second and 2 GiB limits; issue #644 supersedes these budgets below. Manual +security scanning covers full reachable history. Per-ref `repowise-` concurrency cancels an older manual run for the same ref without sharing CI's group. Python environments and reports remain isolated by run/attempt, with unconditional upload followed by cleanup. No domain, use case, port, provider DTO or composition change is needed: the repository workflow @@ -239,6 +239,111 @@ Graphify update. Completion requires a real manual run on the final revision and review of its summary/artifact; a queued run or static test is insufficient. Catalog evidence and the runner appendix in the setup-assistant SDD MUST agree. +### Bounded manual RepoWise analysis (2026-10-21, issue #644) + +Status: implemented contract; native final-revision evidence is required before +completion. Owner: Copilot maintainers. No open design decisions. This section +supersedes the original budgets, incomplete-status handling and regression count +above; admission, permissions, checkout, isolation and retention stay in force. + +The [previous manual run](https://github.com/vypdev/copilot/actions/runs/39573977241) +spent 20m37s in the job: indexing took 8m6s, health ran twice, dead-code exceeded +90 seconds and full-history security raised `MemoryError` under 2 GiB. Historical +JavaScript blobs alone total approximately 9.2 GB. Upstream +[RepoWise 0.58.0](https://github.com/repowise-dev/repowise/releases/tag/v0.58.0) +serves stored health/dead-code, but its history reader still materializes all +blobs. Upgrading alone does not resolve the memory failure. + +```text +Manual selected ref -> one fresh standard index -> cached health MD/JSON + safe dead-code + -> full-history secret scan, one blob request at a time + -> validated reports + scope/timings -> artifact + summary +``` + +Text equivalent: index once, export stored results, scan full history with bounded +blob residency, validate completeness, and publish evidence. No application +runtime, setup session, domain model, provider port or public configuration changes +are needed. The workflow owns execution and cleanup; `repowise_reports.py` owns +phase sequencing, resource limits, validation and summary presentation; +`repowise_history.py` adapts pinned RepoWise/Git interfaces. Neither imports the +TypeScript application. YAML mutation tests enforce wiring; Python fixtures enforce +the private-package adapter and output semantics. + +Fixed, non-configurable execution budgets: + +| Phase | Wall limit | Virtual memory per process | Behavior | +|---|---:|---:|---| +| Fresh standard index | 900s | 4096 MiB | No prose/editor/key/hook setup or worktree seeding; 500 commits for git analytics | +| Each cached health format | 60s | 2048 MiB | All indexed origins, refactoring targets, no recomputation | +| Cached safe-only dead-code | 60s | 2048 MiB | Requires successful dead-code phase and matching index SHA | +| Full-history security | 1200s | 2048 MiB | All reachable refs/commits, supported source extensions, RepoWise secret kinds and upstream allowlists | +| Complete job | 40 minutes | Phase limits above | Leaves two minutes beyond summed phase ceilings for setup/publication | + +The 500-commit analytics setting preserves the former index default and MUST NOT +limit history security. Bundles remain included. The history adapter MUST retain +upstream provenance, secret kinds, deduplication, line suppression, path allowlists +and multiline PEM detection. It MUST fail on Git enumeration/read/persistence +errors. One request/response is in flight and the reader retains no blob cache; +memory scales with metadata plus current blob processing, not total historical +content. Existing upstream metadata tables are still materialized. A single giant +blob can exceed the process cap; that is incomplete, never silently skipped. + +The adapter omits call/code-smell analysis that upstream history mode discards, +and uses a conservative literal prefilter before the unchanged secret detectors. +Fixtures MUST compare every supported secret kind, Unicode keyword matching, +multiline PEM and removed/other-ref secrets against upstream behavior. The +version is pinned exactly; any upgrade requires compatibility fixtures before +publication. No remote cache or stale index is accepted. JSON health identifies +`source: index`; index events MUST confirm ready status plus completed health and +dead-code analysis at HEAD. Security MUST match the reachable commit count and +requested/read source-blob count. Malformed JSON is removed instead of published +as a complete report. + +The artifact MUST contain `revision.txt`, `scope.json` (SHA, ref snapshot, tool +version and explicit scopes), `timings.json`, `history-resources.json`, per-phase +logs/resource records, `summary.md`, advisory status and all completed reports. +RSS is GNU time's largest-process peak, not a sum of simultaneous processes; +virtual-memory limits apply to each process. Security output is RepoWise's JSON +aggregate, not a guarantee that no secrets exist. The local database is removed +and findings/secret material are not added to the artifact. + +The English summary shows status first by phase, SHA, seconds and peak RSS with +artifact/retry instructions. Example rows: `dead-code | complete | 2.1 | 96.0` and +`security | incomplete | 1200 | —`. Completed analysis says "Analysis complete. +Findings are advisory"; partial analysis says "Analysis incomplete. Inspect phase +logs in the artifact, fix the cause, then rerun." Incomplete scans now fail this +optional job while preserving completed reports. Index failure blocks cached +exports but still attempts the independent history scan. Timeout kills the process +group. Cancellation/runner loss can still prevent publication; retry manually. +No comments, locale settings or automatic retries are introduced. Native GitHub +queued/running/canceled states and artifact links remain the navigation; textual +statuses and plain tables work on narrow screens and in light/dark mode. + +Regression floor: **54 distinct cases**, comprising the retained **21** manual +workflow admission/permission/isolation/wiring/report mutations and **33** Python +cases: 14 detector/version compatibility, 5 blob/Git protocol/error cases, +1 deleted-secret/other-ref/provenance integration and 13 resource/report/failure +cases. Cases use synthetic credentials, temporary repositories and mocked clocks/ +processes for timeouts; they do not need live services or real waits. The Python +suite runs in the pinned Python 3.12 manual environment before analysis. Repository +Jest coverage thresholds remain in force; the standalone Python adapter uses +behavioral compatibility/failure evidence rather than a new percentage threshold. + +| Requirement | Acceptance/evidence | Documentation | +|---|---|---| +| Cached results belong to completed current index | Progress/state/JSON guards, fixtures and final-head artifact | Testing guide | +| Full history completes without bulk contents | All-kind differential fixtures, deleted/other-ref provenance, native counts/RSS/bytes/timing | Testing + runner guides | +| Failures remain truthful and bounded | Protocol, malformed data, exit, timeout/group kill, partial summary fixtures | Retry instructions | +| Optional workflow remains isolated | Parsed YAML regressions, CI and manual final-head run | Manual dispatch guide | + +Roll out only through the linked PR. Rollback restores the former pin/workflow +but also restores known incomplete scans; it must not restore automatic triggers +or required checks. Definition of Done: the numeric test budget passes; workflow, +documentation and specification validators pass; catalog evidence and Graphify +are current; native final-head analysis produces **complete dead-code and security** +with measured time/memory and inspected summary/artifact; CI passes independently. +A queued run, green partial job, or merely relaxed limits is insufficient. + ### Other merge-queue evidence from the original implementation - Copilot's own required PR context is produced for merge groups by the dedicated `copilot_pull_request_merge_queue.yml` workflow. Keeping that diff --git a/src/tooling/__tests__/validate_workflow_contract.test.ts b/src/tooling/__tests__/validate_workflow_contract.test.ts index 2a6329c37..2da3fc728 100644 --- a/src/tooling/__tests__/validate_workflow_contract.test.ts +++ b/src/tooling/__tests__/validate_workflow_contract.test.ts @@ -1424,10 +1424,12 @@ describe('workflow contract validator', () => { const steps = workflow.jobs['code-health'].steps; const reports = steps.find((step: { name?: string }) => step.name === 'Generate RepoWise reports'); const upload = steps.find((step: { name?: string }) => step.name === 'Upload RepoWise reports'); - expect(reports.run).toContain('health --no-workspace --refactoring-targets --format md'); - expect(reports.run).toContain('health --no-workspace --refactoring-targets --format json'); - expect(reports.run).toContain('ulimit -v 2097152; timeout --kill-after=10s 90s'); - expect(reports.run).toContain('incomplete (exit %s)'); + expect(reports.run).toContain('"$python_bin" scripts/repowise_reports.py --report-dir "$report_dir"'); + expect(reports.run).toContain('"$python_bin" -m unittest discover'); + const adapter = readFileSync(path.join(process.cwd(), 'scripts', 'repowise_reports.py'), 'utf8'); + expect(adapter).toContain('resource.RLIMIT_AS'); + expect(adapter).toContain('os.killpg(process.pid, signal.SIGKILL)'); + expect(adapter).toContain('write_summary(report_dir, sha, results)'); expect(upload.if).toBe('${{ always() }}'); }); @@ -1476,22 +1478,21 @@ describe('workflow contract validator', () => { expect(() => assertRunner(file, workflow)).toThrow('must use runs-on self-hosted, codex, Linux'); }); - it.each(['full-history', 'scan-budget', 'incomplete-status', 'revision-file', 'summary', 'upload', 'retention', 'health-md', 'health-json'])( + it.each(['pin', 'script', 'compatibility', 'cleanup', 'upload', 'retention'])( 'rejects loss of RepoWise manual report evidence: %s', boundary => { const { file, workflow } = loadMutationWorkflow('.github/workflows', 'repowise.yml'); expect(() => validateWorkflow(file, workflow)).not.toThrow(); const job = workflow.jobs['code-health']; const reports = job.steps.find((step: { name?: string }) => step.name === 'Generate RepoWise reports'); + const install = job.steps.find((step: { name?: string }) => step.name === 'Install RepoWise'); const upload = job.steps.find((step: { name?: string }) => step.name === 'Upload RepoWise reports'); - if (boundary === 'full-history') reports.run = reports.run.replace('--history --path .', '--history --since HEAD --path .'); - else if (boundary === 'scan-budget') reports.run = reports.run.replace('ulimit -v 2097152;', ''); - else if (boundary === 'incomplete-status') reports.run = reports.run.replace('incomplete (exit %s)', 'complete'); - else if (boundary === 'revision-file') reports.run = reports.run.replace('> "$report_dir/revision.txt"', '> /dev/null'); - else if (boundary === 'summary') reports.run = reports.run.replace('>> "$GITHUB_STEP_SUMMARY"', '> /dev/null'); + if (boundary === 'pin') install.run = install.run.replace('repowise==0.58.0', 'repowise'); + else if (boundary === 'script') reports.run = reports.run.replace('scripts/repowise_reports.py', 'other.py'); + else if (boundary === 'compatibility') reports.run = reports.run.replace('-m unittest discover', '-m other'); + else if (boundary === 'cleanup') reports.run = reports.run.replace('trap cleanup EXIT', ''); else if (boundary === 'upload') delete upload.if; - else if (boundary === 'retention') upload.with['retention-days'] = 1; - else reports.run = reports.run.replace(`health --no-workspace --refactoring-targets --format ${boundary === 'health-md' ? 'md' : 'json'}`, 'status'); - expect(() => validateWorkflow(file, workflow)).toThrow('bounded manual history scans, health reports, revision evidence'); + else upload.with['retention-days'] = 1; + expect(() => validateWorkflow(file, workflow)).toThrow('pinned bounded reports, compatibility tests'); }, ); From 3031f2d23fc41f824110dfbe626b931e59119cbf Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 12:00:01 +0200 Subject: [PATCH 06/44] test: isolate RepoWise failure fixtures from live summaries --- scripts/tests/test_repowise.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/tests/test_repowise.py b/scripts/tests/test_repowise.py index 926c631ca..7da0391a5 100644 --- a/scripts/tests/test_repowise.py +++ b/scripts/tests/test_repowise.py @@ -172,6 +172,16 @@ async def scan(bounded): class ReportFailures(unittest.TestCase): + def setUp(self): + # Failure fixtures must not publish fake warnings or a synthetic partial + # Job Summary when this suite runs inside the real manual workflow. + output = patch("sys.stdout", new_callable=io.StringIO) + output.start() + self.addCleanup(output.stop) + environment = patch.dict(reports.os.environ, {"GITHUB_STEP_SUMMARY": ""}) + environment.start() + self.addCleanup(environment.stop) + def test_swallowed_persistence_failure_becomes_fatal(self): from repowise.core.analysis.security.store import SecurityScanner, logger from unittest.mock import AsyncMock From de6ae7bc04eba24ea2adaf51261bcef1e66be229 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 12:01:32 +0200 Subject: [PATCH 07/44] test: enforce current cached RepoWise report provenance --- scripts/repowise_reports.py | 6 ++++++ scripts/tests/test_repowise.py | 17 +++++++++++++++++ specs/local-web-setup-assistant.md | 2 +- specs/merge-queue-readiness.md | 6 +++--- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/scripts/repowise_reports.py b/scripts/repowise_reports.py index 55d50a797..a0dcd53a2 100644 --- a/scripts/repowise_reports.py +++ b/scripts/repowise_reports.py @@ -40,6 +40,8 @@ def validate_json(path, kind): if kind == "dead-code": if not isinstance(value, list) or not all(isinstance(f, dict) and "kind" in f for f in value): raise ValueError("Invalid dead-code report") + if "Read from the index" not in (path.parent / "dead-code.stderr.log").read_text(): + raise ValueError("Dead-code did not reuse the index") return value if not isinstance(value, dict): raise ValueError("Expected a JSON object") @@ -49,6 +51,10 @@ def validate_json(path, kind): raise ValueError("Incomplete report schema") if kind == "health-json" and value.get("source") != "index": raise ValueError("Health report did not reuse the index") + if kind == "health-json": + head = subprocess.check_output(["git", "rev-parse", "HEAD"], text=True).strip() + if value.get("analyzed_commit") != head: + raise ValueError("Stored health revision does not match HEAD") if kind == "security" and (value["commits_scanned"] <= 0 or value["files_scanned"] <= 0): raise ValueError("History scan did not cover any commits or source blobs") if kind == "security": diff --git a/scripts/tests/test_repowise.py b/scripts/tests/test_repowise.py index 7da0391a5..d0c50a9e0 100644 --- a/scripts/tests/test_repowise.py +++ b/scripts/tests/test_repowise.py @@ -207,6 +207,8 @@ def test_success_measures_rss_and_publishes_valid_json(self): def start(command, **kwargs): kwargs["stdout"].write("[]") kwargs["stdout"].flush() + kwargs["stderr"].write("Read from the index") + kwargs["stderr"].flush() (root / "dead-code.resources.txt").write_text("1.2 2048\n") process = Mock(); process.wait.return_value = 0 return process @@ -216,6 +218,21 @@ def start(command, **kwargs): self.assertEqual(2048, result["peak_rss_kib"]) self.assertTrue(p.exists()) + def test_dead_code_live_fallback_rejected(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory); p = root / "dead-code.json" + p.write_text('[]'); (root / "dead-code.stderr.log").write_text("Computing live") + with self.assertRaisesRegex(ValueError, "reuse the index"): + reports.validate_json(p, "dead-code") + + def test_stale_health_revision_rejected(self): + with tempfile.TemporaryDirectory() as directory: + p = Path(directory) / "health.json" + p.write_text('{"targets":[],"refactoring_plans":[],"source":"index","analyzed_commit":"old"}') + with patch.object(reports.subprocess, "check_output", return_value="current"): + with self.assertRaisesRegex(ValueError, "revision"): + reports.validate_json(p, "health-json") + def test_command_failure_is_incomplete(self): with tempfile.TemporaryDirectory() as directory: root = Path(directory); process = Mock(); process.wait.return_value = 1 diff --git a/specs/local-web-setup-assistant.md b/specs/local-web-setup-assistant.md index b52c967be..20222a865 100644 --- a/specs/local-web-setup-assistant.md +++ b/specs/local-web-setup-assistant.md @@ -2452,7 +2452,7 @@ repository ref; it MUST NOT run on PR, push or merge-group events or be required for them. The retained CI routing cases still prove the fork/merge-group trust boundary. The [manual-only migration contract](./merge-queue-readiness.md#manual-only-repowise-migration-2026-10-21-issue-639) and its [bounded-analysis follow-up](./merge-queue-readiness.md#bounded-manual-repowise-analysis-2026-10-21-issue-644) -define the 54-case regression floor, live required-check evidence, immutable +define the 56-case regression floor, live required-check evidence, immutable revision reporting, measured phase budgets and cleanup, operator journey, failure/retry behavior and complete final-revision manual acceptance. This is a workflow scheduling change with no setup-session, PAT, web UX or new configuration change. diff --git a/specs/merge-queue-readiness.md b/specs/merge-queue-readiness.md index 5e8c2b113..8a3c491d1 100644 --- a/specs/merge-queue-readiness.md +++ b/specs/merge-queue-readiness.md @@ -319,10 +319,10 @@ No comments, locale settings or automatic retries are introduced. Native GitHub queued/running/canceled states and artifact links remain the navigation; textual statuses and plain tables work on narrow screens and in light/dark mode. -Regression floor: **54 distinct cases**, comprising the retained **21** manual -workflow admission/permission/isolation/wiring/report mutations and **33** Python +Regression floor: **56 distinct cases**, comprising the retained **21** manual +workflow admission/permission/isolation/wiring/report mutations and **35** Python cases: 14 detector/version compatibility, 5 blob/Git protocol/error cases, -1 deleted-secret/other-ref/provenance integration and 13 resource/report/failure +1 deleted-secret/other-ref/provenance integration and 15 resource/report/failure cases. Cases use synthetic credentials, temporary repositories and mocked clocks/ processes for timeouts; they do not need live services or real waits. The Python suite runs in the pinned Python 3.12 manual environment before analysis. Repository From defc7b98b0255f14a73ab352fcba7be011fab840 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 12:15:58 +0200 Subject: [PATCH 08/44] perf: bound parallel RepoWise history scanning to two workers --- docs/development/testing.mdx | 8 ++- scripts/repowise_history.py | 110 ++++++++++++++++++++++++++--- scripts/repowise_reports.py | 2 +- scripts/tests/test_repowise.py | 51 +++++++++++-- specs/local-web-setup-assistant.md | 2 +- specs/merge-queue-readiness.md | 22 ++++-- 6 files changed, 167 insertions(+), 28 deletions(-) diff --git a/docs/development/testing.mdx b/docs/development/testing.mdx index 9c952976e..8e202eb47 100644 --- a/docs/development/testing.mdx +++ b/docs/development/testing.mdx @@ -120,15 +120,17 @@ The pinned RepoWise 0.58.0 builds one fresh standard index and exports its store health/dead-code results. Index git analytics retain a 500-commit limit; security separately covers **all reachable history**, including removed secrets and generated bundles, using RepoWise's supported source extensions, secret patterns and -allowlists. Historical blob contents are read one at a time. The adapter avoids +allowlists. Two spawned workers read one blob at a time each, with at most two tasks/results +in flight and results consumed in upstream order. Worker failures propagate. The adapter avoids computing code-smell findings discarded by history mode. This remains an advisory signal scanner; an aggregate with no findings is not proof that no secrets exist. Indexing has a 900-second/4 GiB virtual-memory cap. Each health export and dead-code -has a 60-second/2 GiB cap; security has a 1200-second/2 GiB cap, inside the +has a 60-second/2 GiB cap; security has a 1200-second/2 GiB coordinator cap and a 1 GiB cap per worker, inside the 40-minute job. Limits apply per process; reported peak RSS is the largest process, not aggregate simultaneous memory. These budgets accommodate the roughly 9 GB of -historical JavaScript without retaining all of it in memory. +historical JavaScript without retaining all of it in memory. Two available CPU cores are recommended +for the bounded parallel history scan. An interrupted scan, Git error, stale/failed index or invalid report marks analysis incomplete and fails this optional run. Completed reports and diagnostics still diff --git a/scripts/repowise_history.py b/scripts/repowise_history.py index f05bd85c0..9fb0007af 100644 --- a/scripts/repowise_history.py +++ b/scripts/repowise_history.py @@ -8,11 +8,15 @@ from __future__ import annotations import atexit +from collections import deque +from concurrent.futures import ProcessPoolExecutor from importlib.metadata import version +import multiprocessing from pathlib import Path import subprocess REPOWISE_VERSION = "0.58.0" +HISTORY_WORKERS = 2 class BlobReader: @@ -92,6 +96,97 @@ def configure_secret_scan(): scanner._call_findings = lambda *args: [] +def initialize_worker(repo): + import resource + import sys + from multiprocessing.util import Finalize + + # Two workers have a deliberately smaller cap than the coordinating CLI. + if sys.platform == "linux": + resource.setrlimit(resource.RLIMIT_AS, (1024 * 1024**2,) * 2) + configure_secret_scan() + global worker_reader + worker_reader = BlobReader(Path(repo)) + Finalize(None, worker_reader.close, exitpriority=10) + + +def scan_blob(sha, path): + from repowise.core.analysis.security.scanner import scan_source + + before = worker_reader.bytes_read + content = worker_reader.get(sha) + findings = scan_source(path, content) + # Upstream only needs source again for findings' fingerprints/material. + # Negative results carry no large source string across the process pipe. + return findings, content if findings else "", worker_reader.bytes_read - before + + +class PrefetchedBlobs: + """At most two tasks/results resident; consume in upstream history order.""" + + def __init__(self, repo, shas, paths): + self.pool = ProcessPoolExecutor( + max_workers=HISTORY_WORKERS, mp_context=multiprocessing.get_context("spawn"), + initializer=initialize_worker, initargs=(str(repo),), + ) + self.remaining = iter(shas) + self.paths = paths + self.pending = deque() + self.findings = [] + self.count = self.bytes_read = self.largest_blob = 0 + for _ in range(HISTORY_WORKERS): + self.enqueue() + + def enqueue(self): + sha = next(self.remaining, None) + if sha: + self.pending.append((sha, self.pool.submit(scan_blob, sha, self.paths[sha]))) + + def get(self, sha, default=""): + expected, future = self.pending.popleft() + if expected != sha: + raise RuntimeError("History traversal order changed; adapter compatibility failure") + self.findings, content, size = future.result() + self.count += 1 + self.bytes_read += size + self.largest_blob = max(self.largest_blob, size) + self.enqueue() + if self.count % 1000 == 0: + import sys + print(f"History: {self.count} source blobs, {self.bytes_read} bytes scanned", file=sys.stderr, flush=True) + return content + + def close(self): + self.pool.shutdown(wait=True, cancel_futures=True) + + +class PrefetchedScanner: + def __init__(self, reader, delegate): + self.reader = reader + self.delegate = delegate + + async def scan_file(self, path, content, symbols): + return self.reader.findings + + async def persist(self, *args, **kwargs): + return await self.delegate.persist(*args, **kwargs) + + +def bounded_scanner_class(original, readers): + class BoundedHistoryScanner(original): + def _unique_blobs(self, *args): + self.blob_paths = super()._unique_blobs(*args) + return self.blob_paths + + def _read_blobs_batch(self, repo_path, blob_shas): + reader = PrefetchedBlobs(repo_path, blob_shas, self.blob_paths) + readers.append(reader) + self._scanner = PrefetchedScanner(reader, self._scanner) + return reader + + return BoundedHistoryScanner + + def strict_git(repo_path, args, *, timeout=30.0): # Upstream's best-effort helper returns an empty string on Git failures, # which could otherwise turn a failed history enumeration into a clean scan. @@ -128,18 +223,9 @@ def main(): from repowise.cli.main import cli readers = [] - original = history_scan.HistorySecurityScanner - - class BoundedHistoryScanner(original): - def _read_blobs_batch(self, repo_path, blob_shas): - reader = BlobReader(repo_path) - readers.append(reader) - return reader - fail_on_persistence_error() history_scan._run_git = strict_git - history_scan.HistorySecurityScanner = BoundedHistoryScanner - configure_secret_scan() + history_scan.HistorySecurityScanner = bounded_scanner_class(history_scan.HistorySecurityScanner, readers) try: cli(["security", "scan", "--history", "--path", ".", "--format", "json"]) finally: @@ -152,7 +238,9 @@ def _read_blobs_batch(self, repo_path, blob_shas): "bytes_read": sum(r.bytes_read for r in readers), "largest_blob_bytes": max((r.largest_blob for r in readers), default=0), "reader_cache_blobs": 0, - "max_blob_requests_in_flight": 1, + "max_blob_requests_in_flight": HISTORY_WORKERS, + "workers": HISTORY_WORKERS, + "worker_virtual_memory_mib": 1024, }) + "\n") diff --git a/scripts/repowise_reports.py b/scripts/repowise_reports.py index a0dcd53a2..e3cb0c8e8 100644 --- a/scripts/repowise_reports.py +++ b/scripts/repowise_reports.py @@ -144,7 +144,7 @@ def main(): "revision": sha, "refs": refs, "repowise_version": REPOWISE_VERSION, "security": "full reachable history (--all), RepoWise source extensions and secret patterns; upstream allowlists apply", "health": "all indexed origins, cached refactoring targets", "dead_code": "cached safe-only findings", - "index_commit_limit": 500, "history_commit_limit": None, + "index_commit_limit": 500, "history_commit_limit": None, "logical_cpus": os.cpu_count(), }, indent=2) + "\n") os.environ.update(OPENBLAS_NUM_THREADS="1", OMP_NUM_THREADS="1", REPOWISE_SKIP_EDITOR_SETUP="1", REPOWISE_NO_SAVE_KEY="1", REPOWISE_HISTORY_METRICS=str(report_dir / "history-resources.json")) diff --git a/scripts/tests/test_repowise.py b/scripts/tests/test_repowise.py index d0c50a9e0..a41a400ff 100644 --- a/scripts/tests/test_repowise.py +++ b/scripts/tests/test_repowise.py @@ -149,18 +149,17 @@ async def persist(self, path, findings, **provenance): return len(findings) async def scan(bounded): - instance = history_scan.HistorySecurityScanner(None, "fixture") + readers = [] + cls = history.bounded_scanner_class(history_scan.HistorySecurityScanner, readers) if bounded else history_scan.HistorySecurityScanner + instance = cls(None, "fixture") sink = Sink() instance._scanner = sink - reader = history.BlobReader(root) if bounded else None - if bounded: - instance._read_blobs_batch = lambda *_: reader try: with patch.object(history_scan, "_run_git", history.strict_git): summary = await instance.scan_history(root) return summary, sink.saved finally: - if reader: reader.close() + for reader in readers: reader.close() expected = asyncio.run(scan(False)) with optimized(): actual = asyncio.run(scan(True)) @@ -171,6 +170,48 @@ async def scan(bounded): self.assertEqual(introduction, deleted[2]["commit_sha"]) +class BoundedPrefetch(unittest.TestCase): + def reader(self, count=5): + pool = Mock() + def submit(function, sha, path): + future = Mock() + future.result.return_value = ([], "", 3) + return future + pool.submit.side_effect = submit + with patch.object(history, "ProcessPoolExecutor", return_value=pool): + reader = history.PrefetchedBlobs(Path("."), [str(i) for i in range(count)], {str(i): "a.ts" for i in range(count)}) + return reader, pool + + def test_queue_has_fixed_width(self): + reader, pool = self.reader() + self.assertEqual(2, pool.submit.call_count) + for i in range(5): + reader.get(str(i)) + self.assertLessEqual(len(reader.pending), 2) + self.assertEqual((5, 15), (reader.count, reader.bytes_read)) + reader.close() + pool.shutdown.assert_called_once_with(wait=True, cancel_futures=True) + + def test_traversal_order_mismatch_fails(self): + reader, _ = self.reader() + with self.assertRaises(RuntimeError): reader.get("other") + + def test_worker_failure_propagates(self): + reader, _ = self.reader() + reader.pending[0][1].result.side_effect = RuntimeError("worker failed") + with self.assertRaisesRegex(RuntimeError, "worker failed"): reader.get("0") + self.assertEqual(0, reader.count) + + def test_prefetched_results_preserve_delegate_persistence(self): + from unittest.mock import AsyncMock + reader = Mock(findings=[{"kind": "hardcoded_secret"}]) + delegate = Mock(); delegate.persist = AsyncMock(return_value=1) + instance = history.PrefetchedScanner(reader, delegate) + self.assertEqual(reader.findings, asyncio.run(instance.scan_file("a.ts", "", []))) + self.assertEqual(1, asyncio.run(instance.persist("a.ts", reader.findings, commit_sha="abc"))) + delegate.persist.assert_awaited_once_with("a.ts", reader.findings, commit_sha="abc") + + class ReportFailures(unittest.TestCase): def setUp(self): # Failure fixtures must not publish fake warnings or a synthetic partial diff --git a/specs/local-web-setup-assistant.md b/specs/local-web-setup-assistant.md index 20222a865..4b04c5fa2 100644 --- a/specs/local-web-setup-assistant.md +++ b/specs/local-web-setup-assistant.md @@ -2452,7 +2452,7 @@ repository ref; it MUST NOT run on PR, push or merge-group events or be required for them. The retained CI routing cases still prove the fork/merge-group trust boundary. The [manual-only migration contract](./merge-queue-readiness.md#manual-only-repowise-migration-2026-10-21-issue-639) and its [bounded-analysis follow-up](./merge-queue-readiness.md#bounded-manual-repowise-analysis-2026-10-21-issue-644) -define the 56-case regression floor, live required-check evidence, immutable +define the 60-case regression floor, live required-check evidence, immutable revision reporting, measured phase budgets and cleanup, operator journey, failure/retry behavior and complete final-revision manual acceptance. This is a workflow scheduling change with no setup-session, PAT, web UX or new configuration change. diff --git a/specs/merge-queue-readiness.md b/specs/merge-queue-readiness.md index 8a3c491d1..7a8a4545b 100644 --- a/specs/merge-queue-readiness.md +++ b/specs/merge-queue-readiness.md @@ -252,11 +252,14 @@ spent 20m37s in the job: indexing took 8m6s, health ran twice, dead-code exceede JavaScript blobs alone total approximately 9.2 GB. Upstream [RepoWise 0.58.0](https://github.com/repowise-dev/repowise/releases/tag/v0.58.0) serves stored health/dead-code, but its history reader still materializes all -blobs. Upgrading alone does not resolve the memory failure. +blobs. Upgrading alone does not resolve the memory failure. A local single-worker +streaming trial covered 22,975 source blobs / 9,515,793,415 bytes in 1232 seconds; +this CPU measurement motivates the fixed two-worker queue rather than merely +extending the history deadline. Native final-head metrics remain the release gate. ```text Manual selected ref -> one fresh standard index -> cached health MD/JSON + safe dead-code - -> full-history secret scan, one blob request at a time + -> full-history secret scan, two bounded analysis workers -> validated reports + scope/timings -> artifact + summary ``` @@ -276,18 +279,23 @@ Fixed, non-configurable execution budgets: | Fresh standard index | 900s | 4096 MiB | No prose/editor/key/hook setup or worktree seeding; 500 commits for git analytics | | Each cached health format | 60s | 2048 MiB | All indexed origins, refactoring targets, no recomputation | | Cached safe-only dead-code | 60s | 2048 MiB | Requires successful dead-code phase and matching index SHA | -| Full-history security | 1200s | 2048 MiB | All reachable refs/commits, supported source extensions, RepoWise secret kinds and upstream allowlists | +| Full-history security | 1200s | 2048 MiB coordinator; 1024 MiB per worker | Two workers, all reachable refs/commits, supported source extensions, RepoWise secret kinds and upstream allowlists | | Complete job | 40 minutes | Phase limits above | Leaves two minutes beyond summed phase ceilings for setup/publication | The 500-commit analytics setting preserves the former index default and MUST NOT limit history security. Bundles remain included. The history adapter MUST retain upstream provenance, secret kinds, deduplication, line suppression, path allowlists and multiline PEM detection. It MUST fail on Git enumeration/read/persistence -errors. One request/response is in flight and the reader retains no blob cache; +errors. At most two tasks/results are in flight, with one request/response per worker. +The reader retains no blob cache; results are consumed in upstream history order. memory scales with metadata plus current blob processing, not total historical content. Existing upstream metadata tables are still materialized. A single giant blob can exceed the process cap; that is incomplete, never silently skipped. +The adapter uses two spawned processes with a fixed-width prefetch queue. +Negative results do not copy source text back to the coordinator; positive results +retain complete text for unchanged fingerprint/material handling. Worker failures +propagate, and timeout kills the entire process group, including workers and Git. The adapter omits call/code-smell analysis that upstream history mode discards, and uses a conservative literal prefilter before the unchanged secret detectors. Fixtures MUST compare every supported secret kind, Unicode keyword matching, @@ -319,10 +327,10 @@ No comments, locale settings or automatic retries are introduced. Native GitHub queued/running/canceled states and artifact links remain the navigation; textual statuses and plain tables work on narrow screens and in light/dark mode. -Regression floor: **56 distinct cases**, comprising the retained **21** manual -workflow admission/permission/isolation/wiring/report mutations and **35** Python +Regression floor: **60 distinct cases**, comprising the retained **21** manual +workflow admission/permission/isolation/wiring/report mutations and **39** Python cases: 14 detector/version compatibility, 5 blob/Git protocol/error cases, -1 deleted-secret/other-ref/provenance integration and 15 resource/report/failure +1 deleted-secret/other-ref/provenance integration 15 resource/report/failure cases and 4 bounded-prefetch/order/worker-failure/delegation cases. Cases use synthetic credentials, temporary repositories and mocked clocks/ processes for timeouts; they do not need live services or real waits. The Python suite runs in the pinned Python 3.12 manual environment before analysis. Repository From 6a6dc1227ab1dea54b930b996fe8b7e25a13c3d2 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 12:16:40 +0200 Subject: [PATCH 09/44] docs: clarify bounded RepoWise worker budgets --- docs/development/testing.mdx | 12 +++++++----- specs/merge-queue-readiness.md | 6 +++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/development/testing.mdx b/docs/development/testing.mdx index 8e202eb47..01a16d9f1 100644 --- a/docs/development/testing.mdx +++ b/docs/development/testing.mdx @@ -120,17 +120,19 @@ The pinned RepoWise 0.58.0 builds one fresh standard index and exports its store health/dead-code results. Index git analytics retain a 500-commit limit; security separately covers **all reachable history**, including removed secrets and generated bundles, using RepoWise's supported source extensions, secret patterns and -allowlists. Two spawned workers read one blob at a time each, with at most two tasks/results -in flight and results consumed in upstream order. Worker failures propagate. The adapter avoids +allowlists. Two spawned workers read one blob at a time each, with at most two +tasks/results in flight and results consumed in upstream order. Worker failures +propagate. The adapter avoids computing code-smell findings discarded by history mode. This remains an advisory signal scanner; an aggregate with no findings is not proof that no secrets exist. Indexing has a 900-second/4 GiB virtual-memory cap. Each health export and dead-code -has a 60-second/2 GiB cap; security has a 1200-second/2 GiB coordinator cap and a 1 GiB cap per worker, inside the +has a 60-second/2 GiB cap; security has a 1200-second/2 GiB coordinator cap and +a 1 GiB cap per worker, inside the 40-minute job. Limits apply per process; reported peak RSS is the largest process, not aggregate simultaneous memory. These budgets accommodate the roughly 9 GB of -historical JavaScript without retaining all of it in memory. Two available CPU cores are recommended -for the bounded parallel history scan. +historical JavaScript without retaining all of it in memory. Two available CPU +cores are recommended for the bounded parallel history scan. An interrupted scan, Git error, stale/failed index or invalid report marks analysis incomplete and fails this optional run. Completed reports and diagnostics still diff --git a/specs/merge-queue-readiness.md b/specs/merge-queue-readiness.md index 7a8a4545b..aa52a8ca8 100644 --- a/specs/merge-queue-readiness.md +++ b/specs/merge-queue-readiness.md @@ -288,7 +288,7 @@ upstream provenance, secret kinds, deduplication, line suppression, path allowli and multiline PEM detection. It MUST fail on Git enumeration/read/persistence errors. At most two tasks/results are in flight, with one request/response per worker. The reader retains no blob cache; results are consumed in upstream history order. -memory scales with metadata plus current blob processing, not total historical +Memory scales with metadata plus current blob processing, not total historical content. Existing upstream metadata tables are still materialized. A single giant blob can exceed the process cap; that is incomplete, never silently skipped. @@ -330,8 +330,8 @@ statuses and plain tables work on narrow screens and in light/dark mode. Regression floor: **60 distinct cases**, comprising the retained **21** manual workflow admission/permission/isolation/wiring/report mutations and **39** Python cases: 14 detector/version compatibility, 5 blob/Git protocol/error cases, -1 deleted-secret/other-ref/provenance integration 15 resource/report/failure cases and 4 bounded-prefetch/order/worker-failure/delegation -cases. Cases use synthetic credentials, temporary repositories and mocked clocks/ +1 deleted-secret/other-ref/provenance integration, 15 resource/report/failure cases, +and 4 bounded-prefetch/order/worker-failure/delegation cases. Cases use synthetic credentials, temporary repositories and mocked clocks/ processes for timeouts; they do not need live services or real waits. The Python suite runs in the pinned Python 3.12 manual environment before analysis. Repository Jest coverage thresholds remain in force; the standalone Python adapter uses From 1285e4a5d68297bffd3bd02df5be65f3ceefa9d0 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 13:32:18 +0200 Subject: [PATCH 10/44] fix: pass live queue attestations on publication callbacks --- .github/workflows/hotfix_workflow.yml | 1 + .github/workflows/release_workflow.yml | 1 + docs/issues/deployment-orchestration.mdx | 6 +++-- scripts/validate-workflow-contract.cjs | 4 ++++ setup/workflows/hotfix_workflow.yml | 1 + setup/workflows/release_workflow.yml | 1 + specs/merge-queue-readiness.md | 23 +++++++++++++++++++ .../validate_workflow_contract.test.ts | 15 ++++++++++++ 8 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hotfix_workflow.yml b/.github/workflows/hotfix_workflow.yml index 5ba20c1f7..a0dc50735 100644 --- a/.github/workflows/hotfix_workflow.yml +++ b/.github/workflows/hotfix_workflow.yml @@ -365,6 +365,7 @@ jobs: uses: ./ with: single-action: published_deployment_action + merge-queue-check-attestations: ${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }} single-action-issue: ${{ inputs.issue }} issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} single-action-operation-id: ${{ inputs.operation-id }} diff --git a/.github/workflows/release_workflow.yml b/.github/workflows/release_workflow.yml index 54805a236..688b8f8d5 100644 --- a/.github/workflows/release_workflow.yml +++ b/.github/workflows/release_workflow.yml @@ -365,6 +365,7 @@ jobs: uses: ./ with: single-action: published_deployment_action + merge-queue-check-attestations: ${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }} single-action-issue: ${{ inputs.issue }} issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} single-action-operation-id: ${{ inputs.operation-id }} diff --git a/docs/issues/deployment-orchestration.mdx b/docs/issues/deployment-orchestration.mdx index 2b3b1a0f1..085ea171d 100644 --- a/docs/issues/deployment-orchestration.mdx +++ b/docs/issues/deployment-orchestration.mdx @@ -329,8 +329,10 @@ branch roles and orchestration choices are snapshotted; changing those Variables does not rewrite an in-flight deployment. Merge-queue attestations are the exception: they are live repository policy and are reread with effective target rules at every readiness decision. Both publishing workflows and the managed-PR -continuation workflow pass `MERGE_QUEUE_CHECK_ATTESTATIONS`, so a multi-target -operation does not fall back to stale or empty trust policy between events. +continuation workflow pass `MERGE_QUEUE_CHECK_ATTESTATIONS` (with `[]` only as +the absent-variable fallback). Normal publication callbacks and reconciliation-only +resume both receive this live value in consumer and source workflows, so a +multi-target operation does not fall back to stale or empty trust policy between events. A recommended non-interactive fragment is: diff --git a/scripts/validate-workflow-contract.cjs b/scripts/validate-workflow-contract.cjs index 51eb5fb60..64a69df77 100644 --- a/scripts/validate-workflow-contract.cjs +++ b/scripts/validate-workflow-contract.cjs @@ -1145,6 +1145,10 @@ function assertPhaseConditions(relativeFile, jobs, finalJob) { if (publishedActions.length !== 2) { throw new Error(`${relativeFile} must project publication through published_deployment_action.`); } + if ([...preparationActions, ...publishedActions].some(step => + step.with?.['merge-queue-check-attestations'] !== "${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }}")) { + throw new Error(`${relativeFile} must pass live merge-queue attestations on every preparation and reconciliation entrypoint.`); + } const trustedContinuations = Object.values(jobs).flatMap(job => job.steps ?? []) .filter(step => isCopilotAction(step) && [ 'create_tag', diff --git a/setup/workflows/hotfix_workflow.yml b/setup/workflows/hotfix_workflow.yml index bcd718bcf..10efa7cd1 100644 --- a/setup/workflows/hotfix_workflow.yml +++ b/setup/workflows/hotfix_workflow.yml @@ -179,6 +179,7 @@ jobs: uses: vypdev/copilot@v3 with: single-action: published_deployment_action + merge-queue-check-attestations: ${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }} single-action-issue: ${{ inputs.issue }} issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} single-action-operation-id: ${{ inputs.operation-id }} diff --git a/setup/workflows/release_workflow.yml b/setup/workflows/release_workflow.yml index 63b340a85..b5300c717 100644 --- a/setup/workflows/release_workflow.yml +++ b/setup/workflows/release_workflow.yml @@ -179,6 +179,7 @@ jobs: uses: vypdev/copilot@v3 with: single-action: published_deployment_action + merge-queue-check-attestations: ${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }} single-action-issue: ${{ inputs.issue }} issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} single-action-operation-id: ${{ inputs.operation-id }} diff --git a/specs/merge-queue-readiness.md b/specs/merge-queue-readiness.md index aa52a8ca8..cad8b464e 100644 --- a/specs/merge-queue-readiness.md +++ b/specs/merge-queue-readiness.md @@ -1075,3 +1075,26 @@ feature must prevent and violates the event-driven no-polling architecture. for merge-queue targets. - Automatic edits to rulesets or vendor CI. - A live destructive merge-queue test in a user repository. + + +### Publication callback policy parity (2026-10-21, #643) + +Preparation, normal publication, reconciliation-only resume and managed-PR +continuation MUST all pass the live `MERGE_QUEUE_CHECK_ATTESTATIONS` Repository +Variable with an absent-value `[]` fallback. Consumer templates and source +release/hotfix workflows share this contract. A normal callback starts +reconciliation just as resume does; neither may substitute an empty literal or +a snapshotted preparation value. Target selection, producer identity, failed +policy handling and retained publication state remain unchanged. No new input, +permission, UI state, automatic retry or deployment is introduced. + +Flow: prepared promotion -> confirmed publication -> live target policy -> +reconciliation, or the existing blocked recovery state. Existing status cards +and recovery guidance remain authoritative; install updated generated workflows +to adopt the correction. The added numeric test budget is **24 distinct cases**: +source/consumer × release/hotfix × preparation/publication/resume × missing/stale +input. Existing continuation tests cover its fourth entrypoint. Structural +workflow validation rejects either omission or a literal value; all canonical +workflows must pass. Documentation: deployment orchestration's live-policy mapping. +Acceptance: each entrypoint supplies the expression on the actual Action step; +no publication/release is launched to test wiring. diff --git a/src/tooling/__tests__/validate_workflow_contract.test.ts b/src/tooling/__tests__/validate_workflow_contract.test.ts index 2da3fc728..db7489c7a 100644 --- a/src/tooling/__tests__/validate_workflow_contract.test.ts +++ b/src/tooling/__tests__/validate_workflow_contract.test.ts @@ -645,6 +645,21 @@ describe('workflow contract validator', () => { } }); + it.each(mutationDirectories.flatMap(directory => mutationWorkflowNames.flatMap(fileName => + ['prepare', 'publish', 'resume'].flatMap(phase => ['missing', 'stale'].map(value => [directory, fileName, phase, value])))))( + 'rejects %s/%s %s with %s merge-queue attestations', (directory, fileName, phase, value) => { + expectMutationRejected(directory, fileName, workflow => { + const action = phase === 'prepare' ? 'prepare_deployment_action' : 'published_deployment_action'; + const job = phase === 'resume' ? workflow.jobs['resume-reconciliation'] + : Object.entries(workflow.jobs).find(([id, job]) => id !== 'resume-reconciliation' + && (job.steps ?? []).some((step: any) => step.with?.['single-action'] === action))![1]; + const step = job.steps.find((step: any) => step.with?.['single-action'] === action); + if (value === 'missing') delete step.with['merge-queue-check-attestations']; + else step.with['merge-queue-check-attestations'] = '[]'; + }, 'live merge-queue attestations'); + }, + ); + it.each(mutationWorkflowNames)('enforces the active compiled-files budget for %s', (fileName) => { expectMutationRejected('.github/workflows', fileName, (workflow) => { workflow.jobs['prepare-compiled-files']['timeout-minutes'] = PREPARE_COMPILED_TIMEOUT_MINUTES - 1; From 8725ad706cbc377f11df62f37da65e6e7f689125 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 13:39:10 +0200 Subject: [PATCH 11/44] fix: surface rejected SDD ownership with bounded recovery --- build/cli/index.js | 90 ++++++++++++++++--- build/github_action/index.js | 90 ++++++++++++++++--- docs/issues/pre-branch-sdds.mdx | 16 ++++ specs/CATALOG.md | 6 +- specs/catalog.json | 5 +- specs/pre-branch-sdd-gate.md | 55 ++++++++++++ .../policies/sdd_analysis_status_policy.ts | 25 ++++++ .../sdd/pre_branch_sdd_gate_use_case.ts | 25 +++++- .../pre_branch_sdd_gate_use_case.test.ts | 84 +++++++++++++++++ src/domain/__tests__/pre_branch_sdd.test.ts | 13 +++ src/domain/pre_branch_sdd.ts | 23 +++-- 11 files changed, 398 insertions(+), 34 deletions(-) create mode 100644 src/application/policies/sdd_analysis_status_policy.ts diff --git a/build/cli/index.js b/build/cli/index.js index addfe08bd..10462212d 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -46430,6 +46430,40 @@ function calculateReviewersStillNeeded(desiredCount, currentCount, confirmedCoun } +/***/ }), + +/***/ 81053: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.sddAnalysisStatusMarker = sddAnalysisStatusMarker; +exports.renderSddAnalysisStatus = renderSddAnalysisStatus; +function sddAnalysisStatusMarker(issueNumber) { + return ``; +} +const reasons = { + 'update-owner-mismatch': ['The update path does not belong to the selected catalog owner.', 'La ruta de actualización no pertenece al propietario seleccionado del catálogo.'], + 'companion-owner-unknown': ['The companion owner is absent from the catalog.', 'El propietario del SDD complementario no existe en el catálogo.'], + 'companion-path-registered': ['The companion path is already registered in the catalog.', 'La ruta del SDD complementario ya está registrada en el catálogo.'], + 'new-owner-registered': ['The proposed new capability already exists in the catalog.', 'La capacidad propuesta como nueva ya existe en el catálogo.'], + 'new-path-registered': ['The proposed new SDD path is already registered in the catalog.', 'La ruta propuesta como nueva ya está registrada en el catálogo.'], +}; +/** Stateless diagnostic, deliberately separate from the validated readiness record. */ +function renderSddAnalysisStatus(issueNumber, locale, reason) { + const spanish = /^es(?:-|$)/i.test(locale ?? ''); + const marker = sddAnalysisStatusMarker(issueNumber); + if (!reason) + return spanish + ? `## Estado del análisis del SDD\n\nEl análisis posterior ha validado la propiedad. La publicación y la preparación de la rama siguen pendientes de sus comprobaciones.\n\n${marker}` + : `## SDD analysis status\n\nA subsequent analysis validated ownership. Publication and branch readiness remain subject to their checks.\n\n${marker}`; + return spanish + ? `## Estado del SDD: análisis bloqueado\n\nNo se ha preparado ningún borrador ni publicación nueva. ${reasons[reason][1]}\n\n**Acción de mantenimiento:** Aclara en la misma issue el ID de capacidad del catálogo y la ruta: una actualización usa una ruta de ese propietario; un complemento usa un propietario existente y una ruta nueva; una capacidad nueva necesita ID y ruta sin registrar. Después vuelve a ejecutar el workflow original. Cada ejecución hace un solo análisis; no hay reparación ni reintento automático. Se conservan las respuestas, los SDD y las publicaciones anteriores.\n\n**Diagnóstico:** \`${reason}\`. La decisión rechazada no autoriza una rama ni la etiqueta de preparación.\n\n${marker}` + : `## SDD work status: analysis blocked\n\nNo draft or new publication was prepared. ${reasons[reason][0]}\n\n**Maintainer action:** Clarify the catalog capability ID and path in this same issue: an update uses a path owned by that capability; a companion uses an existing owner and a new path; a new capability needs an unregistered ID and path. Then rerun the original workflow. Each invocation performs one analysis; there is no automatic repair or retry. Existing answers, SDDs and publications are retained.\n\n**Diagnostic:** \`${reason}\`. The rejected decision authorizes no branch or readiness label.\n\n${marker}`; +} + + /***/ }), /***/ 2230: @@ -60716,6 +60750,7 @@ const issue_start_policy_1 = __nccwpck_require__(90332); const pre_branch_sdd_1 = __nccwpck_require__(34730); const recommendation_policy_1 = __nccwpck_require__(39410); const logging_ports_1 = __nccwpck_require__(6152); +const sdd_analysis_status_policy_1 = __nccwpck_require__(81053); const application_error_1 = __nccwpck_require__(75999); const pre_branch_sdd_draft_workflow_1 = __nccwpck_require__(93454); const ANALYSIS_SCHEMA = { @@ -60838,11 +60873,21 @@ class PreBranchSddGateUseCase { }); const analysisValue = asRecord(analysis); const owners = new Map(snapshot.capabilities.map(capability => [capability.id, capability.specs])); - const plan = (0, pre_branch_sdd_1.parseSddPlan)(analysisValue, owners); + let plan; + try { + plan = (0, pre_branch_sdd_1.parseSddPlan)(analysisValue, owners); + } + catch (error) { + if (!(error instanceof pre_branch_sdd_1.SddOwnershipFailure)) + throw error; + await this.writeAnalysisStatus(context, allComments, error.reason); + throw new application_error_1.ApplicationError('provider.contract-invalid', `${error.message} Clarify the catalog owner/path in the same issue and rerun the original workflow. No automatic retry was attempted.`); + } if (card?.record.branchName && (plan.action !== 'update' || plan.path !== card.record.plan.path || plan.capabilityId !== card.record.plan.capabilityId)) { throw new Error('An existing linked branch can only revise its owning SDD on the same path.'); } + await this.writeAnalysisStatus(context, allComments); const round = publicationRetry ? card.record.round : card?.record.phase === 'awaiting-answer' && card.record.issueDigest === digest && !staleAwaiting ? card.record.round + (plan.questions.length > 0 ? 1 : 0) : 1; @@ -60954,6 +60999,20 @@ class PreBranchSddGateUseCase { else await this.comments.updateComment(issueNumber, cardId, body); } + async writeAnalysisStatus(context, comments, reason) { + const marker = (0, sdd_analysis_status_policy_1.sddAnalysisStatusMarker)(context.issueNumber); + const prior = comments.filter(comment => comment.user?.login?.toLowerCase() === context.tokenUser.toLowerCase() + && comment.body?.includes(marker)).sort((a, b) => b.id - a.id)[0]; + if (!reason && !prior) + return; + const body = (0, sdd_analysis_status_policy_1.renderSddAnalysisStatus)(context.issueNumber, context.issueLocale, reason); + if (prior) { + if (prior.body !== body) + await this.comments.updateComment(context.issueNumber, prior.id, body); + } + else + await this.comments.addComment(context.issueNumber, body); + } async assertFresh(context, expectedBaseSha, sourceBranch) { const [liveBody, liveTitle, snapshot] = await Promise.all([ this.descriptions.getDescription(context.issueNumber), @@ -91943,7 +92002,7 @@ function parsePositiveSafeInteger(value) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.SDD_REQUIRED_HEADINGS = exports.SddOwnerFormatFailure = exports.SddDraftFormatFailure = exports.SDD_MAX_UPDATE_CHARACTERS = exports.SDD_MAX_DRAFT_CHARACTERS = exports.SDD_MIN_DRAFT_CHARACTERS = exports.SDD_GATE_MARKER = void 0; +exports.SDD_REQUIRED_HEADINGS = exports.SddOwnerFormatFailure = exports.SddDraftFormatFailure = exports.SddOwnershipFailure = exports.SDD_MAX_UPDATE_CHARACTERS = exports.SDD_MAX_DRAFT_CHARACTERS = exports.SDD_MIN_DRAFT_CHARACTERS = exports.SDD_GATE_MARKER = void 0; exports.retainSddAnswers = retainSddAnswers; exports.normalizeSddIssueTitle = normalizeSddIssueTitle; exports.isSafeSddPath = isSafeSddPath; @@ -91981,6 +92040,15 @@ function normalizeSddIssueTitle(title) { function isSafeSddPath(path) { return SDD_PATH.test(path) && !['specs/CATALOG.md', 'specs/_template.md'].includes(path); } +/** Closed diagnostics contain no model-selected identifiers or provider text. */ +class SddOwnershipFailure extends Error { + constructor(reason) { + super(`SDD ownership analysis rejected (${reason}).`); + this.reason = reason; + this.name = 'SddOwnershipFailure'; + } +} +exports.SddOwnershipFailure = SddOwnershipFailure; /** The agent may propose ownership but cannot invent a catalogued owner or arbitrary path. */ function parseSddPlan(value, catalog) { if (!isRecord(value)) @@ -91998,14 +92066,16 @@ function parseSddPlan(value, catalog) { const ownerPaths = catalog.get(capabilityId); const registered = [...catalog.values()].some(paths => paths.includes(path)); if (action === 'update' && (!ownerPaths?.includes(path) || !registered)) { - throw new Error('The requested SDD update is not owned by the selected catalog capability.'); - } - if (action === 'companion' && (!ownerPaths || registered)) { - throw new Error('A companion SDD requires an existing owner and a new path.'); - } - if (action === 'new' && (ownerPaths || registered)) { - throw new Error('A new SDD requires an unregistered capability and path.'); - } + throw new SddOwnershipFailure('update-owner-mismatch'); + } + if (action === 'companion' && !ownerPaths) + throw new SddOwnershipFailure('companion-owner-unknown'); + if (action === 'companion' && registered) + throw new SddOwnershipFailure('companion-path-registered'); + if (action === 'new' && ownerPaths) + throw new SddOwnershipFailure('new-owner-registered'); + if (action === 'new' && registered) + throw new SddOwnershipFailure('new-path-registered'); if (!Array.isArray(value.questions) || value.questions.length > 8) { throw new Error('The SDD analysis must contain at most eight blocking questions.'); } diff --git a/build/github_action/index.js b/build/github_action/index.js index 9cd6d5ace..66263e0b3 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -47972,6 +47972,40 @@ function calculateReviewersStillNeeded(desiredCount, currentCount, confirmedCoun } +/***/ }), + +/***/ 81053: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.sddAnalysisStatusMarker = sddAnalysisStatusMarker; +exports.renderSddAnalysisStatus = renderSddAnalysisStatus; +function sddAnalysisStatusMarker(issueNumber) { + return ``; +} +const reasons = { + 'update-owner-mismatch': ['The update path does not belong to the selected catalog owner.', 'La ruta de actualización no pertenece al propietario seleccionado del catálogo.'], + 'companion-owner-unknown': ['The companion owner is absent from the catalog.', 'El propietario del SDD complementario no existe en el catálogo.'], + 'companion-path-registered': ['The companion path is already registered in the catalog.', 'La ruta del SDD complementario ya está registrada en el catálogo.'], + 'new-owner-registered': ['The proposed new capability already exists in the catalog.', 'La capacidad propuesta como nueva ya existe en el catálogo.'], + 'new-path-registered': ['The proposed new SDD path is already registered in the catalog.', 'La ruta propuesta como nueva ya está registrada en el catálogo.'], +}; +/** Stateless diagnostic, deliberately separate from the validated readiness record. */ +function renderSddAnalysisStatus(issueNumber, locale, reason) { + const spanish = /^es(?:-|$)/i.test(locale ?? ''); + const marker = sddAnalysisStatusMarker(issueNumber); + if (!reason) + return spanish + ? `## Estado del análisis del SDD\n\nEl análisis posterior ha validado la propiedad. La publicación y la preparación de la rama siguen pendientes de sus comprobaciones.\n\n${marker}` + : `## SDD analysis status\n\nA subsequent analysis validated ownership. Publication and branch readiness remain subject to their checks.\n\n${marker}`; + return spanish + ? `## Estado del SDD: análisis bloqueado\n\nNo se ha preparado ningún borrador ni publicación nueva. ${reasons[reason][1]}\n\n**Acción de mantenimiento:** Aclara en la misma issue el ID de capacidad del catálogo y la ruta: una actualización usa una ruta de ese propietario; un complemento usa un propietario existente y una ruta nueva; una capacidad nueva necesita ID y ruta sin registrar. Después vuelve a ejecutar el workflow original. Cada ejecución hace un solo análisis; no hay reparación ni reintento automático. Se conservan las respuestas, los SDD y las publicaciones anteriores.\n\n**Diagnóstico:** \`${reason}\`. La decisión rechazada no autoriza una rama ni la etiqueta de preparación.\n\n${marker}` + : `## SDD work status: analysis blocked\n\nNo draft or new publication was prepared. ${reasons[reason][0]}\n\n**Maintainer action:** Clarify the catalog capability ID and path in this same issue: an update uses a path owned by that capability; a companion uses an existing owner and a new path; a new capability needs an unregistered ID and path. Then rerun the original workflow. Each invocation performs one analysis; there is no automatic repair or retry. Existing answers, SDDs and publications are retained.\n\n**Diagnostic:** \`${reason}\`. The rejected decision authorizes no branch or readiness label.\n\n${marker}`; +} + + /***/ }), /***/ 2230: @@ -58757,6 +58791,7 @@ const issue_start_policy_1 = __nccwpck_require__(90332); const pre_branch_sdd_1 = __nccwpck_require__(34730); const recommendation_policy_1 = __nccwpck_require__(39410); const logging_ports_1 = __nccwpck_require__(6152); +const sdd_analysis_status_policy_1 = __nccwpck_require__(81053); const application_error_1 = __nccwpck_require__(75999); const pre_branch_sdd_draft_workflow_1 = __nccwpck_require__(93454); const ANALYSIS_SCHEMA = { @@ -58879,11 +58914,21 @@ class PreBranchSddGateUseCase { }); const analysisValue = asRecord(analysis); const owners = new Map(snapshot.capabilities.map(capability => [capability.id, capability.specs])); - const plan = (0, pre_branch_sdd_1.parseSddPlan)(analysisValue, owners); + let plan; + try { + plan = (0, pre_branch_sdd_1.parseSddPlan)(analysisValue, owners); + } + catch (error) { + if (!(error instanceof pre_branch_sdd_1.SddOwnershipFailure)) + throw error; + await this.writeAnalysisStatus(context, allComments, error.reason); + throw new application_error_1.ApplicationError('provider.contract-invalid', `${error.message} Clarify the catalog owner/path in the same issue and rerun the original workflow. No automatic retry was attempted.`); + } if (card?.record.branchName && (plan.action !== 'update' || plan.path !== card.record.plan.path || plan.capabilityId !== card.record.plan.capabilityId)) { throw new Error('An existing linked branch can only revise its owning SDD on the same path.'); } + await this.writeAnalysisStatus(context, allComments); const round = publicationRetry ? card.record.round : card?.record.phase === 'awaiting-answer' && card.record.issueDigest === digest && !staleAwaiting ? card.record.round + (plan.questions.length > 0 ? 1 : 0) : 1; @@ -58995,6 +59040,20 @@ class PreBranchSddGateUseCase { else await this.comments.updateComment(issueNumber, cardId, body); } + async writeAnalysisStatus(context, comments, reason) { + const marker = (0, sdd_analysis_status_policy_1.sddAnalysisStatusMarker)(context.issueNumber); + const prior = comments.filter(comment => comment.user?.login?.toLowerCase() === context.tokenUser.toLowerCase() + && comment.body?.includes(marker)).sort((a, b) => b.id - a.id)[0]; + if (!reason && !prior) + return; + const body = (0, sdd_analysis_status_policy_1.renderSddAnalysisStatus)(context.issueNumber, context.issueLocale, reason); + if (prior) { + if (prior.body !== body) + await this.comments.updateComment(context.issueNumber, prior.id, body); + } + else + await this.comments.addComment(context.issueNumber, body); + } async assertFresh(context, expectedBaseSha, sourceBranch) { const [liveBody, liveTitle, snapshot] = await Promise.all([ this.descriptions.getDescription(context.issueNumber), @@ -82436,7 +82495,7 @@ function parsePositiveSafeInteger(value) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.SDD_REQUIRED_HEADINGS = exports.SddOwnerFormatFailure = exports.SddDraftFormatFailure = exports.SDD_MAX_UPDATE_CHARACTERS = exports.SDD_MAX_DRAFT_CHARACTERS = exports.SDD_MIN_DRAFT_CHARACTERS = exports.SDD_GATE_MARKER = void 0; +exports.SDD_REQUIRED_HEADINGS = exports.SddOwnerFormatFailure = exports.SddDraftFormatFailure = exports.SddOwnershipFailure = exports.SDD_MAX_UPDATE_CHARACTERS = exports.SDD_MAX_DRAFT_CHARACTERS = exports.SDD_MIN_DRAFT_CHARACTERS = exports.SDD_GATE_MARKER = void 0; exports.retainSddAnswers = retainSddAnswers; exports.normalizeSddIssueTitle = normalizeSddIssueTitle; exports.isSafeSddPath = isSafeSddPath; @@ -82474,6 +82533,15 @@ function normalizeSddIssueTitle(title) { function isSafeSddPath(path) { return SDD_PATH.test(path) && !['specs/CATALOG.md', 'specs/_template.md'].includes(path); } +/** Closed diagnostics contain no model-selected identifiers or provider text. */ +class SddOwnershipFailure extends Error { + constructor(reason) { + super(`SDD ownership analysis rejected (${reason}).`); + this.reason = reason; + this.name = 'SddOwnershipFailure'; + } +} +exports.SddOwnershipFailure = SddOwnershipFailure; /** The agent may propose ownership but cannot invent a catalogued owner or arbitrary path. */ function parseSddPlan(value, catalog) { if (!isRecord(value)) @@ -82491,14 +82559,16 @@ function parseSddPlan(value, catalog) { const ownerPaths = catalog.get(capabilityId); const registered = [...catalog.values()].some(paths => paths.includes(path)); if (action === 'update' && (!ownerPaths?.includes(path) || !registered)) { - throw new Error('The requested SDD update is not owned by the selected catalog capability.'); - } - if (action === 'companion' && (!ownerPaths || registered)) { - throw new Error('A companion SDD requires an existing owner and a new path.'); - } - if (action === 'new' && (ownerPaths || registered)) { - throw new Error('A new SDD requires an unregistered capability and path.'); - } + throw new SddOwnershipFailure('update-owner-mismatch'); + } + if (action === 'companion' && !ownerPaths) + throw new SddOwnershipFailure('companion-owner-unknown'); + if (action === 'companion' && registered) + throw new SddOwnershipFailure('companion-path-registered'); + if (action === 'new' && ownerPaths) + throw new SddOwnershipFailure('new-owner-registered'); + if (action === 'new' && registered) + throw new SddOwnershipFailure('new-path-registered'); if (!Array.isArray(value.questions) || value.questions.length > 8) { throw new Error('The SDD analysis must contain at most eight blocking questions.'); } diff --git a/docs/issues/pre-branch-sdds.mdx b/docs/issues/pre-branch-sdds.mdx index f2a2cfb77..4b25c54cc 100644 --- a/docs/issues/pre-branch-sdds.mdx +++ b/docs/issues/pre-branch-sdds.mdx @@ -118,6 +118,22 @@ Opening a PR replaces GitHub's direct issue-to-branch connection with its issue- Automatic updates retain the owning SDD from its original Git commit, including when Windows converts checkout line endings. +### Ownership analysis recovery + +If the analysis proposes an unknown companion owner or a path already registered +in the catalog, Copilot blocks before drafting and publishes an editable **SDD +work status: analysis blocked** card. The card identifies a closed failure +category without exposing the model's proposed values or raw response. + +Clarify the existing capability ID and intended SDD path in the same issue, then +rerun the original workflow. Updates use a path registered to that owner; +companions use an existing owner and a new path; new capabilities use a new ID +and path. Each invocation makes one analysis attempt with no automatic repair. +Existing answers, SDDs, branches and commits remain intact. A later valid analysis +updates the diagnostic; normal publication checks still determine readiness. +The diagnostic is separate from the validated question/publication record and +cannot authorize a branch or `branched` label. + ### Draft validation recovery Drafting aims for a complete compact document: about 6,000 characters for an diff --git a/specs/CATALOG.md b/specs/CATALOG.md index 7729c582d..e935d9366 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -20,7 +20,7 @@ debt or convert unknown historic intent into a design decision. | `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 1 companion | 238 paths · 2026-10-21 | | `guided-bot-pat-onboarding` | Proposed | Guide creation of the persistent workflow PAT, verify bot identity and grants, recover explicitly from wrong-account input within the session, and install the approved Actions Secret | [Guided bot PAT onboarding](./guided-bot-pat-onboarding.md) | 39 paths · 2026-10-07 | | `temporary-setup-operator-authorization` | Proposed | Guide creation of the one-run operator PAT through GitHub's official form, verify final setup access, and report user-owned deletion accurately | [Assisted setup PAT creation](./temporary-setup-operator-authorization.md) | 36 paths · 2026-10-18 | -| `issue-start-and-sdd-readiness` | Implemented | Start every admitted issue with one explicit signal and publish a validated SDD before eligible Action-managed branch work; inspect verified SDD status and bounded structural publication comparisons | [Uniform issue start and pre-branch SDD readiness](./issue-start-and-branch-readiness.md) + 3 companion | 116 paths · 2026-10-19 | +| `issue-start-and-sdd-readiness` | Implemented | Start every admitted issue with one explicit signal and publish a validated SDD before eligible Action-managed branch work; inspect verified SDD status and bounded structural publication comparisons | [Uniform issue start and pre-branch SDD readiness](./issue-start-and-branch-readiness.md) + 3 companion | 117 paths · 2026-10-21 | | `managed-issue-lifecycle` | As-built baseline | Convert typed issues into traceable work branches, project state, and lifecycle state | [Managed issue and branch lifecycle](./managed-issue-and-branch-lifecycle.md) | 71 paths · 2026-10-20 | | `comment-automation` | Implemented | Admit only explicit commands or exact mentions, then route them while protecting repository mutations | [Comment automation and authorization](./comment-automation-and-authorization.md) | 79 paths · 2026-10-11 | | `bugbot-analysis-and-autofix` | Implemented | Select one canonical PR, exhaustively analyze its bounded diff partitions, publish stable findings atomically, and apply authorized verified fixes | [Bugbot analysis, finding publication, and autofix](./bugbot-analysis-publication-and-autofix.md) + 2 companion | 109 paths · 2026-10-13 | @@ -147,11 +147,11 @@ debt or convert unknown historic intent into a design decision. ### `issue-start-and-sdd-readiness` — Uniform issue start and pre-branch SDD readiness - Owner: Copilot maintainers -- Last verified: 2026-10-19 +- Last verified: 2026-10-21 - Specifications: [`specs/issue-start-and-branch-readiness.md`](./issue-start-and-branch-readiness.md) · [`specs/pre-branch-sdd-gate.md`](./pre-branch-sdd-gate.md) · [`specs/pre-branch-sdd-diff.md`](./pre-branch-sdd-diff.md) · [`specs/pre-branch-sdd-status-readiness.md`](./pre-branch-sdd-status-readiness.md) - Workflows: [`.github/workflows/copilot_issue.yml`](../.github/workflows/copilot_issue.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_commit.yml`](../.github/workflows/copilot_commit.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) - Entrypoints: [`action.yml`](../action.yml) · [`src/actions/common_action.ts`](../src/actions/common_action.ts) · [`src/actions/github_action.ts`](../src/actions/github_action.ts) -- Core code: [`src/domain/issue_workflow_runtime_policy.ts`](../src/domain/issue_workflow_runtime_policy.ts) · [`src/domain/copilot_lifecycle.ts`](../src/domain/copilot_lifecycle.ts) · [`src/data/model/execution.ts`](../src/data/model/execution.ts) · [`src/application/usecases/issue_workflow.ts`](../src/application/usecases/issue_workflow.ts) · [`src/application/usecases/steps/issue/prepare_branches_use_case.ts`](../src/application/usecases/steps/issue/prepare_branches_use_case.ts) · [`src/application/policies/setup_issue_workflow_policy.ts`](../src/application/policies/setup_issue_workflow_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts`](../src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts) · [`src/infrastructure/git_commit_adapter.ts`](../src/infrastructure/git_commit_adapter.ts) · [`scripts/validate-specification-catalog.cjs`](../scripts/validate-specification-catalog.cjs) · [`src/domain/issue_start_policy.ts`](../src/domain/issue_start_policy.ts) · [`src/domain/pre_branch_sdd.ts`](../src/domain/pre_branch_sdd.ts) · [`src/application/ports/pre_branch_sdd_ports.ts`](../src/application/ports/pre_branch_sdd_ports.ts) · [`src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts`](../src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts) · [`src/application/usecases/steps/issue/reconcile_branch_readiness_use_case.ts`](../src/application/usecases/steps/issue/reconcile_branch_readiness_use_case.ts) · [`src/data/repository/branch/linked_branch_readiness_repository.ts`](../src/data/repository/branch/linked_branch_readiness_repository.ts) · [`src/infrastructure/pre_branch_sdd_workspace_adapter.ts`](../src/infrastructure/pre_branch_sdd_workspace_adapter.ts) · [`src/infrastructure/specification_catalog_validator.cjs`](../src/infrastructure/specification_catalog_validator.cjs) · [`src/actions/input_boolean_policy.ts`](../src/actions/input_boolean_policy.ts) · [`src/domain/issue_workflow_profile.ts`](../src/domain/issue_workflow_profile.ts) · [`src/application/usecases/read_copilot_status_workflow.ts`](../src/application/usecases/read_copilot_status_workflow.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/policies/publication_message_catalog.ts`](../src/application/policies/publication_message_catalog.ts) · [`src/application/usecases/sdd/pre_branch_sdd_draft_workflow.ts`](../src/application/usecases/sdd/pre_branch_sdd_draft_workflow.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/domain/agent_response_length_failure.ts`](../src/domain/agent_response_length_failure.ts) · [`src/data/repository/agent_json_schema_validator.ts`](../src/data/repository/agent_json_schema_validator.ts) · [`src/application/ports/sdd_evidence_read_ports.ts`](../src/application/ports/sdd_evidence_read_ports.ts) · [`src/application/policies/sdd_issue_identity_policy.ts`](../src/application/policies/sdd_issue_identity_policy.ts) · [`src/application/policies/sdd_query_card_policy.ts`](../src/application/policies/sdd_query_card_policy.ts) · [`src/application/policies/sdd_status_policy.ts`](../src/application/policies/sdd_status_policy.ts) · [`src/application/usecases/sdd/sdd_evidence_query_use_case.ts`](../src/application/usecases/sdd/sdd_evidence_query_use_case.ts) · [`src/application/usecases/comment_automation_context.ts`](../src/application/usecases/comment_automation_context.ts) · [`src/application/usecases/comment_automation_command_workflow.ts`](../src/application/usecases/comment_automation_command_workflow.ts) · [`src/application/usecases/comment_automation_contracts.ts`](../src/application/usecases/comment_automation_contracts.ts) · [`src/application/usecases/issue_comment_use_case.ts`](../src/application/usecases/issue_comment_use_case.ts) · [`src/application/policies/semantic_result_publication_policy.ts`](../src/application/policies/semantic_result_publication_policy.ts) · [`src/infrastructure/composition/sdd_evidence_composition_root.ts`](../src/infrastructure/composition/sdd_evidence_composition_root.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/domain/pre_branch_sdd_diff.ts`](../src/domain/pre_branch_sdd_diff.ts) · [`src/application/policies/sdd_diff_message_catalog.ts`](../src/application/policies/sdd_diff_message_catalog.ts) · [`src/application/policies/sdd_diff_presentation_policy.ts`](../src/application/policies/sdd_diff_presentation_policy.ts) · [`src/application/ports/sdd_diff_read_ports.ts`](../src/application/ports/sdd_diff_read_ports.ts) · [`src/application/usecases/sdd/sdd_diff_query_use_case.ts`](../src/application/usecases/sdd/sdd_diff_query_use_case.ts) · [`src/data/repository/sdd/sdd_diff_link_repository.ts`](../src/data/repository/sdd/sdd_diff_link_repository.ts) · [`src/infrastructure/composition/sdd_diff_composition_root.ts`](../src/infrastructure/composition/sdd_diff_composition_root.ts) · [`src/application/usecases/pull_request_review_comment_use_case.ts`](../src/application/usecases/pull_request_review_comment_use_case.ts) · [`src/application/usecases/steps/common/reply_publication_workflow.ts`](../src/application/usecases/steps/common/reply_publication_workflow.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`src/architecture/github_publication_mutation_baseline.json`](../src/architecture/github_publication_mutation_baseline.json) · [`src/domain/specification_catalog_path_policy.cjs`](../src/domain/specification_catalog_path_policy.cjs) · [`src/application/policies/github_runtime_doctor_policy.ts`](../src/application/policies/github_runtime_doctor_policy.ts) · [`src/infrastructure/setup_workspace_adapter.ts`](../src/infrastructure/setup_workspace_adapter.ts) · [`src/application/usecases/setup/doctor_use_case.ts`](../src/application/usecases/setup/doctor_use_case.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/domain/sdd_prerequisite_policy.cjs`](../src/domain/sdd_prerequisite_policy.cjs) +- Core code: [`src/domain/issue_workflow_runtime_policy.ts`](../src/domain/issue_workflow_runtime_policy.ts) · [`src/domain/copilot_lifecycle.ts`](../src/domain/copilot_lifecycle.ts) · [`src/data/model/execution.ts`](../src/data/model/execution.ts) · [`src/application/usecases/issue_workflow.ts`](../src/application/usecases/issue_workflow.ts) · [`src/application/usecases/steps/issue/prepare_branches_use_case.ts`](../src/application/usecases/steps/issue/prepare_branches_use_case.ts) · [`src/application/policies/setup_issue_workflow_policy.ts`](../src/application/policies/setup_issue_workflow_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts`](../src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts) · [`src/infrastructure/git_commit_adapter.ts`](../src/infrastructure/git_commit_adapter.ts) · [`scripts/validate-specification-catalog.cjs`](../scripts/validate-specification-catalog.cjs) · [`src/domain/issue_start_policy.ts`](../src/domain/issue_start_policy.ts) · [`src/domain/pre_branch_sdd.ts`](../src/domain/pre_branch_sdd.ts) · [`src/application/ports/pre_branch_sdd_ports.ts`](../src/application/ports/pre_branch_sdd_ports.ts) · [`src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts`](../src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts) · [`src/application/usecases/steps/issue/reconcile_branch_readiness_use_case.ts`](../src/application/usecases/steps/issue/reconcile_branch_readiness_use_case.ts) · [`src/data/repository/branch/linked_branch_readiness_repository.ts`](../src/data/repository/branch/linked_branch_readiness_repository.ts) · [`src/infrastructure/pre_branch_sdd_workspace_adapter.ts`](../src/infrastructure/pre_branch_sdd_workspace_adapter.ts) · [`src/infrastructure/specification_catalog_validator.cjs`](../src/infrastructure/specification_catalog_validator.cjs) · [`src/actions/input_boolean_policy.ts`](../src/actions/input_boolean_policy.ts) · [`src/domain/issue_workflow_profile.ts`](../src/domain/issue_workflow_profile.ts) · [`src/application/usecases/read_copilot_status_workflow.ts`](../src/application/usecases/read_copilot_status_workflow.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/policies/publication_message_catalog.ts`](../src/application/policies/publication_message_catalog.ts) · [`src/application/usecases/sdd/pre_branch_sdd_draft_workflow.ts`](../src/application/usecases/sdd/pre_branch_sdd_draft_workflow.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/domain/agent_response_length_failure.ts`](../src/domain/agent_response_length_failure.ts) · [`src/data/repository/agent_json_schema_validator.ts`](../src/data/repository/agent_json_schema_validator.ts) · [`src/application/ports/sdd_evidence_read_ports.ts`](../src/application/ports/sdd_evidence_read_ports.ts) · [`src/application/policies/sdd_issue_identity_policy.ts`](../src/application/policies/sdd_issue_identity_policy.ts) · [`src/application/policies/sdd_query_card_policy.ts`](../src/application/policies/sdd_query_card_policy.ts) · [`src/application/policies/sdd_status_policy.ts`](../src/application/policies/sdd_status_policy.ts) · [`src/application/usecases/sdd/sdd_evidence_query_use_case.ts`](../src/application/usecases/sdd/sdd_evidence_query_use_case.ts) · [`src/application/usecases/comment_automation_context.ts`](../src/application/usecases/comment_automation_context.ts) · [`src/application/usecases/comment_automation_command_workflow.ts`](../src/application/usecases/comment_automation_command_workflow.ts) · [`src/application/usecases/comment_automation_contracts.ts`](../src/application/usecases/comment_automation_contracts.ts) · [`src/application/usecases/issue_comment_use_case.ts`](../src/application/usecases/issue_comment_use_case.ts) · [`src/application/policies/semantic_result_publication_policy.ts`](../src/application/policies/semantic_result_publication_policy.ts) · [`src/infrastructure/composition/sdd_evidence_composition_root.ts`](../src/infrastructure/composition/sdd_evidence_composition_root.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/domain/pre_branch_sdd_diff.ts`](../src/domain/pre_branch_sdd_diff.ts) · [`src/application/policies/sdd_diff_message_catalog.ts`](../src/application/policies/sdd_diff_message_catalog.ts) · [`src/application/policies/sdd_diff_presentation_policy.ts`](../src/application/policies/sdd_diff_presentation_policy.ts) · [`src/application/ports/sdd_diff_read_ports.ts`](../src/application/ports/sdd_diff_read_ports.ts) · [`src/application/usecases/sdd/sdd_diff_query_use_case.ts`](../src/application/usecases/sdd/sdd_diff_query_use_case.ts) · [`src/data/repository/sdd/sdd_diff_link_repository.ts`](../src/data/repository/sdd/sdd_diff_link_repository.ts) · [`src/infrastructure/composition/sdd_diff_composition_root.ts`](../src/infrastructure/composition/sdd_diff_composition_root.ts) · [`src/application/usecases/pull_request_review_comment_use_case.ts`](../src/application/usecases/pull_request_review_comment_use_case.ts) · [`src/application/usecases/steps/common/reply_publication_workflow.ts`](../src/application/usecases/steps/common/reply_publication_workflow.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`src/architecture/github_publication_mutation_baseline.json`](../src/architecture/github_publication_mutation_baseline.json) · [`src/domain/specification_catalog_path_policy.cjs`](../src/domain/specification_catalog_path_policy.cjs) · [`src/application/policies/github_runtime_doctor_policy.ts`](../src/application/policies/github_runtime_doctor_policy.ts) · [`src/infrastructure/setup_workspace_adapter.ts`](../src/infrastructure/setup_workspace_adapter.ts) · [`src/application/usecases/setup/doctor_use_case.ts`](../src/application/usecases/setup/doctor_use_case.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/domain/sdd_prerequisite_policy.cjs`](../src/domain/sdd_prerequisite_policy.cjs) · [`src/application/policies/sdd_analysis_status_policy.ts`](../src/application/policies/sdd_analysis_status_policy.ts) - Tests: [`src/domain/__tests__/issue_workflow_runtime_policy.test.ts`](../src/domain/__tests__/issue_workflow_runtime_policy.test.ts) · [`src/data/model/__tests__/execution.test.ts`](../src/data/model/__tests__/execution.test.ts) · [`src/application/usecases/__tests__/issue_use_case.test.ts`](../src/application/usecases/__tests__/issue_use_case.test.ts) · [`src/application/usecases/steps/issue/__tests__/prepare_branches_use_case.test.ts`](../src/application/usecases/steps/issue/__tests__/prepare_branches_use_case.test.ts) · [`src/application/policies/__tests__/lifecycle_state_policy.test.ts`](../src/application/policies/__tests__/lifecycle_state_policy.test.ts) · [`src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts`](../src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts) · [`src/tooling/__tests__/validate_specification_catalog.test.ts`](../src/tooling/__tests__/validate_specification_catalog.test.ts) · [`src/domain/__tests__/issue_start_policy.test.ts`](../src/domain/__tests__/issue_start_policy.test.ts) · [`src/domain/__tests__/pre_branch_sdd.test.ts`](../src/domain/__tests__/pre_branch_sdd.test.ts) · [`src/application/usecases/steps/issue/__tests__/pre_branch_sdd_gate_use_case.test.ts`](../src/application/usecases/steps/issue/__tests__/pre_branch_sdd_gate_use_case.test.ts) · [`src/application/usecases/steps/issue/__tests__/reconcile_branch_readiness_use_case.test.ts`](../src/application/usecases/steps/issue/__tests__/reconcile_branch_readiness_use_case.test.ts) · [`src/infrastructure/__tests__/pre_branch_sdd_workspace_adapter.test.ts`](../src/infrastructure/__tests__/pre_branch_sdd_workspace_adapter.test.ts) · [`src/architecture/__tests__/github_publication_boundaries.test.ts`](../src/architecture/__tests__/github_publication_boundaries.test.ts) · [`src/actions/__tests__/input_boolean_policy.test.ts`](../src/actions/__tests__/input_boolean_policy.test.ts) · [`src/domain/__tests__/issue_workflow_profile.test.ts`](../src/domain/__tests__/issue_workflow_profile.test.ts) · [`src/application/policies/__tests__/status_command_policy.test.ts`](../src/application/policies/__tests__/status_command_policy.test.ts) · [`src/application/usecases/sdd/pre_branch_sdd_draft_workflow.test.ts`](../src/application/usecases/sdd/pre_branch_sdd_draft_workflow.test.ts) · [`src/application/policies/__tests__/application_error_presentation_policy.test.ts`](../src/application/policies/__tests__/application_error_presentation_policy.test.ts) · [`src/data/repository/__tests__/agent_json_schema_validator.test.ts`](../src/data/repository/__tests__/agent_json_schema_validator.test.ts) · [`src/application/policies/__tests__/sdd_issue_identity_policy.test.ts`](../src/application/policies/__tests__/sdd_issue_identity_policy.test.ts) · [`src/application/policies/__tests__/sdd_query_card_policy.test.ts`](../src/application/policies/__tests__/sdd_query_card_policy.test.ts) · [`src/application/policies/__tests__/sdd_status_policy.test.ts`](../src/application/policies/__tests__/sdd_status_policy.test.ts) · [`src/application/usecases/sdd/__tests__/sdd_evidence_query_use_case.test.ts`](../src/application/usecases/sdd/__tests__/sdd_evidence_query_use_case.test.ts) · [`src/data/repository/branch/__tests__/linked_branch_readiness_repository.test.ts`](../src/data/repository/branch/__tests__/linked_branch_readiness_repository.test.ts) · [`src/application/usecases/__tests__/read_copilot_status_workflow.test.ts`](../src/application/usecases/__tests__/read_copilot_status_workflow.test.ts) · [`src/infrastructure/composition/__tests__/main_run_route_composition_root.test.ts`](../src/infrastructure/composition/__tests__/main_run_route_composition_root.test.ts) · [`src/infrastructure/composition/__tests__/sdd_evidence_composition_root.test.ts`](../src/infrastructure/composition/__tests__/sdd_evidence_composition_root.test.ts) · [`src/domain/__tests__/pre_branch_sdd_diff.test.ts`](../src/domain/__tests__/pre_branch_sdd_diff.test.ts) · [`src/application/policies/__tests__/sdd_diff_presentation_policy.test.ts`](../src/application/policies/__tests__/sdd_diff_presentation_policy.test.ts) · [`src/application/usecases/sdd/__tests__/sdd_diff_query_use_case.test.ts`](../src/application/usecases/sdd/__tests__/sdd_diff_query_use_case.test.ts) · [`src/data/repository/sdd/__tests__/sdd_diff_link_repository.test.ts`](../src/data/repository/sdd/__tests__/sdd_diff_link_repository.test.ts) · [`src/infrastructure/composition/__tests__/sdd_diff_composition_root.test.ts`](../src/infrastructure/composition/__tests__/sdd_diff_composition_root.test.ts) · [`src/application/usecases/__tests__/sdd_diff_comment_interaction.test.ts`](../src/application/usecases/__tests__/sdd_diff_comment_interaction.test.ts) · [`src/application/usecases/steps/common/__tests__/sdd_diff_reply_publication.test.ts`](../src/application/usecases/steps/common/__tests__/sdd_diff_reply_publication.test.ts) · [`src/application/usecases/__tests__/sdd_status_workflow_integration.test.ts`](../src/application/usecases/__tests__/sdd_status_workflow_integration.test.ts) · [`src/tooling/__tests__/portable_specification_catalog.test.ts`](../src/tooling/__tests__/portable_specification_catalog.test.ts) · [`src/application/policies/__tests__/github_runtime_doctor_policy.test.ts`](../src/application/policies/__tests__/github_runtime_doctor_policy.test.ts) · [`src/infrastructure/__tests__/setup_sdd_prerequisites.test.ts`](../src/infrastructure/__tests__/setup_sdd_prerequisites.test.ts) · [`src/application/usecases/setup/__tests__/doctor_use_case.test.ts`](../src/application/usecases/setup/__tests__/doctor_use_case.test.ts) · [`src/infrastructure/__tests__/branch_sync_sdd_catalog.test.ts`](../src/infrastructure/__tests__/branch_sync_sdd_catalog.test.ts) · [`src/cli/__tests__/setup_presenters.test.ts`](../src/cli/__tests__/setup_presenters.test.ts) - User documentation: [`docs/issues/branch-management.mdx`](../docs/issues/branch-management.mdx) · [`docs/issues/workflow-setup.mdx`](../docs/issues/workflow-setup.mdx) · [`docs/issues/comment-commands.mdx`](../docs/issues/comment-commands.mdx) · [`docs/development/specifications.mdx`](../docs/development/specifications.mdx) · [`docs/issues/pre-branch-sdds.mdx`](../docs/issues/pre-branch-sdds.mdx) · [`docs/issues/index.mdx`](../docs/issues/index.mdx) · [`docs/issues/labels-and-branch-types.mdx`](../docs/issues/labels-and-branch-types.mdx) · [`docs/issues/configuration.mdx`](../docs/issues/configuration.mdx) · [`docs/configuration.mdx`](../docs/configuration.mdx) · [`docs/single-actions/workflow-and-cli.mdx`](../docs/single-actions/workflow-and-cli.mdx) diff --git a/specs/catalog.json b/specs/catalog.json index d2a52a9bb..95fed7d33 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -1469,7 +1469,7 @@ "status": "implemented", "scope": "Start every admitted issue with one explicit signal and publish a validated SDD before eligible Action-managed branch work; inspect verified SDD status and bounded structural publication comparisons", "owner": "Copilot maintainers", - "lastVerified": "2026-10-19", + "lastVerified": "2026-10-21", "specs": [ "specs/issue-start-and-branch-readiness.md", "specs/pre-branch-sdd-gate.md", @@ -1545,7 +1545,8 @@ "src/infrastructure/setup_workspace_adapter.ts", "src/application/usecases/setup/doctor_use_case.ts", "src/application/policies/setup_doctor_message_catalog.ts", - "src/domain/sdd_prerequisite_policy.cjs" + "src/domain/sdd_prerequisite_policy.cjs", + "src/application/policies/sdd_analysis_status_policy.ts" ], "tests": [ "src/domain/__tests__/issue_workflow_runtime_policy.test.ts", diff --git a/specs/pre-branch-sdd-gate.md b/specs/pre-branch-sdd-gate.md index 57b071ff5..82fa10a53 100644 --- a/specs/pre-branch-sdd-gate.md +++ b/specs/pre-branch-sdd-gate.md @@ -1085,3 +1085,58 @@ migration; adapted standards retain that rule in a numbered section. The canonical normative rule MUST occur inside one numbered section; concatenating fragments across section boundaries cannot establish it. Two additional adapter cases cover this boundary, included in the 91-case amendment floor. + + +### Safe rejected ownership and bounded recovery (2026-10-21, #636) + +Observed defect: semantic ownership validation could reject a successful model +response before any issue card, leaving only generic workflow failure. The gate +MUST preserve validation and classify update-owner mismatch, unknown companion +owner, registered companion path, registered new owner and registered new path +with closed typed reasons. When both companion constraints fail, unknown owner +has deterministic precedence. Generated owner/path values and response text MUST +NOT enter this diagnostic. The immutable snapshot and catalog remain authoritative. + +The recovery policy is **one analysis per invocation, zero automatic repairs**. +A maintainer clarifies the catalog ID/path in the same issue and reruns the +original workflow, which performs fresh analysis and unchanged freshness checks. +This amendment selects the maintainer-recovery option; invalid proposals never +become invented clarification plans or stored validated owners. Existing answers, +SDDs and published branches/commits are retained. A provider outage or malformed +shape remains its existing failure, not an ownership retry. + +```text +Analysis -> semantic rejection -> owned diagnostic -> maintainer clarification +-> normal rerun -> fresh valid analysis -> unchanged draft/publication checks +``` + +Text equivalent: a rejected decision blocks; a human clarifies the same issue; +a fresh invocation may progress only after normal semantic and publication checks. + +UI: **SDD work status: analysis blocked** explains that no new draft/publication +was prepared, gives the specific closed cause, then asks the maintainer to clarify +and rerun. English/Spanish copy uses the issue locale. An owned, issue-bound +`copilot:sdd-analysis-status:v1` diagnostic is reused and unchanged retries emit +no mutation. It has no readiness marker, no questions, proposed values, commands, +external URLs or new configuration. A later validated owner updates it to +“Publication and branch readiness remain subject to their checks.” Existing +pending/question, partial-publication and completed cards retain their contracts. +A foreign marker is never overwritten. Failed comment publication remains blocked. + +Domain owns typed semantic failures; the application presentation policy owns +closed localized content; the use case uses its existing bound comment port. +No SDK, filesystem, process or provider DTO crosses into either pure module. +Typecheck, architecture tests and fault-injected use-case tests enforce the +boundary. No credential or permission expansion, migration or new state schema. +Upgrade the Action, clarify the same issue and rerun; rollback loses this +additional diagnosis but cannot authorize invalid ownership. + +The additional budget is **21 distinct cases**: five typed domain classifications; +ten use-case reason/locale boundaries; six retry, recovery, identity, provider and +comment-failure cases. Existing valid update/companion/new tests remain required. +Acceptance checks that invalid analysis makes no draft validation or publication +call, does not add `branched`, leaks no proposed identifiers or response, and is +not parsed as readiness. Documentation: ownership analysis recovery in the +pre-branch SDD guide. Definition of Done also requires existing global quality, +package and catalog gates, preserved safety checks and review of both locale +messages; tests do not claim a live consumer recovery. diff --git a/src/application/policies/sdd_analysis_status_policy.ts b/src/application/policies/sdd_analysis_status_policy.ts new file mode 100644 index 000000000..6ba15c49c --- /dev/null +++ b/src/application/policies/sdd_analysis_status_policy.ts @@ -0,0 +1,25 @@ +import type { SddOwnershipFailureReason } from '../../domain/pre_branch_sdd'; + +export function sddAnalysisStatusMarker(issueNumber: number): string { + return ``; +} + +const reasons: Record = { + 'update-owner-mismatch': ['The update path does not belong to the selected catalog owner.', 'La ruta de actualización no pertenece al propietario seleccionado del catálogo.'], + 'companion-owner-unknown': ['The companion owner is absent from the catalog.', 'El propietario del SDD complementario no existe en el catálogo.'], + 'companion-path-registered': ['The companion path is already registered in the catalog.', 'La ruta del SDD complementario ya está registrada en el catálogo.'], + 'new-owner-registered': ['The proposed new capability already exists in the catalog.', 'La capacidad propuesta como nueva ya existe en el catálogo.'], + 'new-path-registered': ['The proposed new SDD path is already registered in the catalog.', 'La ruta propuesta como nueva ya está registrada en el catálogo.'], +}; + +/** Stateless diagnostic, deliberately separate from the validated readiness record. */ +export function renderSddAnalysisStatus(issueNumber: number, locale: string | undefined, reason?: SddOwnershipFailureReason): string { + const spanish = /^es(?:-|$)/i.test(locale ?? ''); + const marker = sddAnalysisStatusMarker(issueNumber); + if (!reason) return spanish + ? `## Estado del análisis del SDD\n\nEl análisis posterior ha validado la propiedad. La publicación y la preparación de la rama siguen pendientes de sus comprobaciones.\n\n${marker}` + : `## SDD analysis status\n\nA subsequent analysis validated ownership. Publication and branch readiness remain subject to their checks.\n\n${marker}`; + return spanish + ? `## Estado del SDD: análisis bloqueado\n\nNo se ha preparado ningún borrador ni publicación nueva. ${reasons[reason][1]}\n\n**Acción de mantenimiento:** Aclara en la misma issue el ID de capacidad del catálogo y la ruta: una actualización usa una ruta de ese propietario; un complemento usa un propietario existente y una ruta nueva; una capacidad nueva necesita ID y ruta sin registrar. Después vuelve a ejecutar el workflow original. Cada ejecución hace un solo análisis; no hay reparación ni reintento automático. Se conservan las respuestas, los SDD y las publicaciones anteriores.\n\n**Diagnóstico:** \`${reason}\`. La decisión rechazada no autoriza una rama ni la etiqueta de preparación.\n\n${marker}` + : `## SDD work status: analysis blocked\n\nNo draft or new publication was prepared. ${reasons[reason][0]}\n\n**Maintainer action:** Clarify the catalog capability ID and path in this same issue: an update uses a path owned by that capability; a companion uses an existing owner and a new path; a new capability needs an unregistered ID and path. Then rerun the original workflow. Each invocation performs one analysis; there is no automatic repair or retry. Existing answers, SDDs and publications are retained.\n\n**Diagnostic:** \`${reason}\`. The rejected decision authorizes no branch or readiness label.\n\n${marker}`; +} diff --git a/src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts b/src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts index 7dd628025..f81d37acc 100644 --- a/src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts +++ b/src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts @@ -11,6 +11,7 @@ import type { BoundLinkedBranchReadinessPort } from '../../ports/linked_branch_r import { Result } from '../../../data/model/result'; import { SDD_REQUIRED_LABEL } from '../../../domain/issue_start_policy'; import { + SddOwnershipFailure, parseSddAnswer, parseSddPlan, readSddGateRecord, @@ -24,7 +25,8 @@ import { } from '../../../domain/pre_branch_sdd'; import { getVisibleIssueDescription } from '../../policies/recommendation_policy'; import { logError } from '../../ports/logging_ports'; -import { toApplicationError } from '../../errors/application_error'; +import { renderSddAnalysisStatus, sddAnalysisStatusMarker } from '../../policies/sdd_analysis_status_policy'; +import { ApplicationError, toApplicationError } from '../../errors/application_error'; import { draftSddMarkdown } from './pre_branch_sdd_draft_workflow'; export interface PreBranchSddContext { @@ -174,11 +176,19 @@ export class PreBranchSddGateUseCase { }); const analysisValue = asRecord(analysis); const owners = new Map(snapshot.capabilities.map(capability => [capability.id, capability.specs])); - const plan = parseSddPlan(analysisValue, owners); + let plan: SddPlan; + try { + plan = parseSddPlan(analysisValue, owners); + } catch (error) { + if (!(error instanceof SddOwnershipFailure)) throw error; + await this.writeAnalysisStatus(context, allComments, error.reason); + throw new ApplicationError('provider.contract-invalid', `${error.message} Clarify the catalog owner/path in the same issue and rerun the original workflow. No automatic retry was attempted.`); + } if (card?.record.branchName && (plan.action !== 'update' || plan.path !== card.record.plan.path || plan.capabilityId !== card.record.plan.capabilityId)) { throw new Error('An existing linked branch can only revise its owning SDD on the same path.'); } + await this.writeAnalysisStatus(context, allComments); const round = publicationRetry ? card.record.round : card?.record.phase === 'awaiting-answer' && card.record.issueDigest === digest && !staleAwaiting ? card.record.round + (plan.questions.length > 0 ? 1 : 0) : 1; @@ -284,6 +294,17 @@ export class PreBranchSddGateUseCase { else await this.comments.updateComment(issueNumber, cardId, body); } + private async writeAnalysisStatus(context: PreBranchSddContext, comments: readonly IssueCommentPublicationTarget[], reason?: SddOwnershipFailure['reason']): Promise { + const marker = sddAnalysisStatusMarker(context.issueNumber); + const prior = comments.filter(comment => comment.user?.login?.toLowerCase() === context.tokenUser.toLowerCase() + && comment.body?.includes(marker)).sort((a, b) => b.id - a.id)[0]; + if (!reason && !prior) return; + const body = renderSddAnalysisStatus(context.issueNumber, context.issueLocale, reason); + if (prior) { + if (prior.body !== body) await this.comments.updateComment(context.issueNumber, prior.id, body); + } else await this.comments.addComment(context.issueNumber, body); + } + private async assertFresh(context: PreBranchSddContext, expectedBaseSha: string, sourceBranch: string): Promise { const [liveBody, liveTitle, snapshot] = await Promise.all([ this.descriptions.getDescription(context.issueNumber), diff --git a/src/application/usecases/steps/issue/__tests__/pre_branch_sdd_gate_use_case.test.ts b/src/application/usecases/steps/issue/__tests__/pre_branch_sdd_gate_use_case.test.ts index 0f233820c..baae4be83 100644 --- a/src/application/usecases/steps/issue/__tests__/pre_branch_sdd_gate_use_case.test.ts +++ b/src/application/usecases/steps/issue/__tests__/pre_branch_sdd_gate_use_case.test.ts @@ -601,3 +601,87 @@ describe('PreBranchSddGateUseCase', () => { expect(h.query).not.toHaveBeenCalled(); }); }); + + +describe('safe ownership diagnostics (#636)', () => { + const invalid = [ + ['update-owner-mismatch', { ...plan, path: 'specs/private-update.md' }], + ['companion-owner-unknown', { ...plan, action: 'companion', capabilityId: 'private-owner', path: 'specs/private-companion.md' }], + ['companion-path-registered', { ...plan, action: 'companion' }], + ['new-owner-registered', { ...plan, action: 'new', path: 'specs/private-new.md' }], + ['new-path-registered', { ...plan, action: 'new', capabilityId: 'private-owner' }], + ] as const; + it.each(invalid.flatMap(([code, decision]) => ['en-US', 'es-ES'].map(locale => ({ code, decision, locale }))))( + 'blocks $code in $locale without exposing generated data or publishing a draft', async ({ code, decision, locale }) => { + const h = harness(); + h.query.mockResolvedValue({ ...decision, reason: 'secret-provider-data '.repeat(4) }); + const outcome = await h.useCase.begin({ ...context(), issueLocale: locale }); + expect(outcome.status).toBe('blocked'); + expect(h.query).toHaveBeenCalledTimes(1); + expect(h.readSdd).not.toHaveBeenCalled(); + expect(h.validateDraft).not.toHaveBeenCalled(); + expect(h.publish).not.toHaveBeenCalled(); + expect(h.labels()).not.toContain('branched'); + const body = h.comments[0].body; + expect(body).toContain(code); + expect(body).not.toMatch(/private-|secret-provider-data/); + expect(readSddGateRecord(body, 42)).toBeUndefined(); + expect(outcome.results[0].errors[0]).toMatchObject({ code: 'provider.contract-invalid' }); + }, + ); + it('reuses the owned diagnostic on retry and marks recovery without granting readiness', async () => { + const h = harness(); + h.query.mockResolvedValueOnce(invalid[1][1]).mockResolvedValueOnce(invalid[2][1]); + await h.useCase.begin(context()); + await h.useCase.begin(context()); + expect(h.addComment).toHaveBeenCalledTimes(1); + expect(h.updateComment).toHaveBeenCalledTimes(1); + h.query.mockResolvedValueOnce(plan).mockResolvedValueOnce({ markdown: '# Valid' }); + expect((await h.useCase.begin(context())).status).toBe('drafted'); + expect(h.comments[0].body).toContain('validated ownership'); + expect(h.labels()).not.toContain('branched'); + }); + it('does not overwrite a foreign diagnostic marker', async () => { + const h = harness(); + h.comments.push({ id: 99, body: '', user: { login: 'attacker' } }); + h.query.mockResolvedValue(invalid[1][1]); + await h.useCase.begin(context()); + expect(h.updateComment).not.toHaveBeenCalled(); + expect(h.addComment).toHaveBeenCalledTimes(1); + }); + it('does not classify an unrelated provider failure as rejected ownership or retry it', async () => { + const h = harness(); + h.query.mockRejectedValue(new Error('Provider unavailable')); + expect((await h.useCase.begin(context())).status).toBe('blocked'); + expect(h.query).toHaveBeenCalledTimes(1); + expect(h.addComment).not.toHaveBeenCalled(); + }); + it('withholds all publication when diagnostic publication itself fails', async () => { + const h = harness(); + h.query.mockResolvedValue(invalid[1][1]); + h.addComment.mockRejectedValue(new Error('Comment unavailable')); + expect((await h.useCase.begin(context())).status).toBe('blocked'); + expect(h.validateDraft).not.toHaveBeenCalled(); + expect(h.publish).not.toHaveBeenCalled(); + }); +}); + + +it('keeps repeated identical ownership failures to one unchanged diagnostic card', async () => { + const h = harness(); + h.query.mockResolvedValue({ ...plan, action: 'companion', capabilityId: 'unknown' }); + await h.useCase.begin(context()); + await h.useCase.begin(context()); + expect(h.addComment).toHaveBeenCalledTimes(1); + expect(h.updateComment).not.toHaveBeenCalled(); +}); + +it('reports a later valid ownership analysis in Spanish without a readiness record', async () => { + const h = harness(); + h.query.mockResolvedValueOnce({ ...plan, action: 'companion', capabilityId: 'unknown' }); + await h.useCase.begin({ ...context(), issueLocale: 'es-ES' }); + h.query.mockResolvedValueOnce(plan).mockResolvedValueOnce({ markdown: '# Valid' }); + await h.useCase.begin({ ...context(), issueLocale: 'es-ES' }); + expect(h.comments[0].body).toContain('ha validado la propiedad'); + expect(readSddGateRecord(h.comments[0].body, 42)).toBeUndefined(); +}); diff --git a/src/domain/__tests__/pre_branch_sdd.test.ts b/src/domain/__tests__/pre_branch_sdd.test.ts index e8196c5cc..a13c1ffd6 100644 --- a/src/domain/__tests__/pre_branch_sdd.test.ts +++ b/src/domain/__tests__/pre_branch_sdd.test.ts @@ -11,6 +11,7 @@ import { normalizeSddIssueTitle, retainSddAnswers, SddOwnerFormatFailure, + SddOwnershipFailure, type SddGateRecord, } from '../pre_branch_sdd'; @@ -247,3 +248,15 @@ describe('retained SDD answer provenance', () => { expect(readSddGateRecord(rendered, 42)?.answers).toEqual([malicious]); }); }); + + +it.each([ + ['update-owner-mismatch', { action: 'update', path: 'specs/other.md' }], + ['companion-owner-unknown', { action: 'companion', capabilityId: 'unknown' }], + ['companion-path-registered', { action: 'companion' }], + ['new-owner-registered', { action: 'new' }], + ['new-path-registered', { action: 'new', capabilityId: 'unknown' }], +])('classifies ownership rejection %s without retaining proposed values', (reason, change) => { + try { parseSddPlan({ ...plan, ...(change as object) }, catalog); throw new Error('expected rejection'); } + catch (error) { expect(error).toBeInstanceOf(SddOwnershipFailure); expect(error).toMatchObject({ reason }); } +}); diff --git a/src/domain/pre_branch_sdd.ts b/src/domain/pre_branch_sdd.ts index d7b8d4120..7b1943f8c 100644 --- a/src/domain/pre_branch_sdd.ts +++ b/src/domain/pre_branch_sdd.ts @@ -73,6 +73,17 @@ export function isSafeSddPath(path: string): boolean { return SDD_PATH.test(path) && !['specs/CATALOG.md', 'specs/_template.md'].includes(path); } +export type SddOwnershipFailureReason = 'update-owner-mismatch' | 'companion-owner-unknown' + | 'companion-path-registered' | 'new-owner-registered' | 'new-path-registered'; + +/** Closed diagnostics contain no model-selected identifiers or provider text. */ +export class SddOwnershipFailure extends Error { + constructor(readonly reason: SddOwnershipFailureReason) { + super(`SDD ownership analysis rejected (${reason}).`); + this.name = 'SddOwnershipFailure'; + } +} + /** The agent may propose ownership but cannot invent a catalogued owner or arbitrary path. */ export function parseSddPlan(value: unknown, catalog: ReadonlyMap): SddPlan { if (!isRecord(value)) throw new Error('The SDD analysis must be an object.'); @@ -89,14 +100,12 @@ export function parseSddPlan(value: unknown, catalog: ReadonlyMap paths.includes(path)); if (action === 'update' && (!ownerPaths?.includes(path) || !registered)) { - throw new Error('The requested SDD update is not owned by the selected catalog capability.'); - } - if (action === 'companion' && (!ownerPaths || registered)) { - throw new Error('A companion SDD requires an existing owner and a new path.'); - } - if (action === 'new' && (ownerPaths || registered)) { - throw new Error('A new SDD requires an unregistered capability and path.'); + throw new SddOwnershipFailure('update-owner-mismatch'); } + if (action === 'companion' && !ownerPaths) throw new SddOwnershipFailure('companion-owner-unknown'); + if (action === 'companion' && registered) throw new SddOwnershipFailure('companion-path-registered'); + if (action === 'new' && ownerPaths) throw new SddOwnershipFailure('new-owner-registered'); + if (action === 'new' && registered) throw new SddOwnershipFailure('new-path-registered'); if (!Array.isArray(value.questions) || value.questions.length > 8) { throw new Error('The SDD analysis must contain at most eight blocking questions.'); } From bbcce0f23bd673c02f2b96454da17926e7e75ad3 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 13:46:45 +0200 Subject: [PATCH 12/44] test: register bounded SDD diagnostic publication authority --- src/architecture/github_publication_mutation_baseline.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/architecture/github_publication_mutation_baseline.json b/src/architecture/github_publication_mutation_baseline.json index 679c26090..07c361a51 100644 --- a/src/architecture/github_publication_mutation_baseline.json +++ b/src/architecture/github_publication_mutation_baseline.json @@ -20,9 +20,9 @@ }, { "file": "src/application/usecases/sdd/pre_branch_sdd_gate_use_case.ts", - "addComment": 1, - "updateComment": 1, - "reason": "Creates or updates one bot-owned SDD clarification and publication status card after issue and branch verification." + "addComment": 2, + "updateComment": 2, + "reason": "Creates or updates the verified bot-owned SDD clarification/publication card, plus one separate issue-bound ownership-analysis diagnostic; rejected plans never create a readiness record, and unchanged diagnostics emit no write." }, { "file": "src/application/usecases/steps/commit/bugbot/publish_issue_finding_comment.ts", From 0b19fe4390e968e9e945a28c1531e6e10be6dc4b Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 14:00:20 +0200 Subject: [PATCH 13/44] fix: preserve actionable finding mutation diagnostics --- build/api/index.js | 134 +++++++++--- build/api/src/domain/bugbot/context.d.ts | 2 + build/cli/index.js | 199 +++++++++++++----- build/github_action/index.js | 199 +++++++++++++----- docs/bugbot/failure-scenarios.mdx | 7 + specs/CATALOG.md | 8 +- specs/bugbot-review-state-reconciliation.md | 69 ++++++ specs/catalog.json | 10 +- .../contracts/bugbot_reconciliation.ts | 2 + .../__tests__/bugbot_mutation_error.test.ts | 34 +++ .../errors/bugbot_mutation_error.ts | 35 +++ .../policies/bugbot_message_catalog.ts | 4 + .../bugbot_review_presentation_policy.ts | 3 + .../ports/pull_request_review_errors.ts | 13 +- ...detect_potential_problems_use_case.test.ts | 4 +- .../__tests__/bugbot_review_context.test.ts | 15 ++ .../finding_mutation_recovery.test.ts | 53 +++++ .../mark_findings_resolved_use_case.test.ts | 4 +- .../publish_findings_use_case.test.ts | 21 ++ ...le_bugbot_review_state_integration.test.ts | 32 +++ .../commit/bugbot/apply_detected_findings.ts | 3 +- .../commit/bugbot/bugbot_review_context.ts | 5 + .../bugbot/load_bugbot_context_use_case.ts | 1 + .../bugbot/mark_findings_resolved_workflow.ts | 31 ++- .../bugbot/publish_findings_use_case.ts | 35 +-- .../reconcile_bugbot_review_state_use_case.ts | 8 +- ...ize_bugbot_review_presentation_use_case.ts | 4 +- ..._review_comment_command_repository.test.ts | 8 + .../pull_request_changes_repository.ts | 2 +- ...quest_review_comment_command_repository.ts | 2 +- ...request_review_comment_query_repository.ts | 2 +- .../pull_request_review_error_metadata.ts | 16 ++ .../pull_request_review_thread_repository.ts | 2 +- .../pull_request_reviewer_repository.ts | 2 +- src/domain/bugbot/context.ts | 2 + 35 files changed, 780 insertions(+), 191 deletions(-) create mode 100644 src/application/errors/__tests__/bugbot_mutation_error.test.ts create mode 100644 src/application/errors/bugbot_mutation_error.ts create mode 100644 src/application/usecases/steps/commit/bugbot/__tests__/finding_mutation_recovery.test.ts create mode 100644 src/data/repository/pull_request/pull_request_review_error_metadata.ts diff --git a/build/api/index.js b/build/api/index.js index 02582bbcd..110efe745 100644 --- a/build/api/index.js +++ b/build/api/index.js @@ -68,6 +68,43 @@ function runAtApplicationErrorBoundary(operation) { } +/***/ }), + +/***/ 2937: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BugbotMutationError = void 0; +exports.bugbotMutationError = bugbotMutationError; +const application_error_1 = __nccwpck_require__(5999); +const pull_request_review_errors_1 = __nccwpck_require__(6445); +class BugbotMutationError extends application_error_1.ApplicationError { + constructor(diagnostic) { + super(diagnostic.errorCode, `Bugbot ${diagnostic.stage} failed: operation=${diagnostic.operation}; finding=${diagnostic.findingId}; affected=${diagnostic.affectedCount}; ${diagnostic.providerStatus}; provider-reference=${diagnostic.providerReference}. Completed effects are retained; correct the named cause and recheck the same target.`); + this.diagnostic = diagnostic; + } +} +exports.BugbotMutationError = BugbotMutationError; +function bugbotMutationError(cause, stage, findingIds, fallback) { + if (cause instanceof BugbotMutationError) + return cause; + const provider = cause instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? cause : undefined; + const status = provider?.providerStatus; + const errorCode = status === 401 ? 'authorization.credential-invalid' : status === 403 ? 'authorization.denied' + : status === 404 ? 'provider.not-found' : status === 409 ? 'provider.conflict' + : status === 429 ? 'provider.rate-limited' : status && status < 500 ? 'provider.contract-invalid' : 'provider.unavailable'; + const first = findingIds[0]; + return new BugbotMutationError(Object.freeze({ + stage, operation: provider?.operation ?? fallback, + findingId: typeof first === 'string' && /^[A-Za-z0-9_./:-]{1,200}$/.test(first) ? first : 'unavailable', + affectedCount: Math.min(findingIds.length, 10000), + providerStatus: status ? `http-${status}` : 'http-unavailable', + providerReference: provider?.providerReference ?? 'unavailable', errorCode, + })); +} + + /***/ }), /***/ 601: @@ -796,6 +833,7 @@ exports.BUGBOT_MESSAGE_IDS = Object.freeze([ 'bugbot.overflow.body', 'bugbot.common.more', 'bugbot.diagnostic.operationFailed', + 'bugbot.diagnostic.findingMutationFailed', 'bugbot.diagnostic.identityUnavailable', 'bugbot.diagnostic.pullRequestCommentsFailed', 'bugbot.diagnostic.reviewThreadsFailed', @@ -881,6 +919,7 @@ const ENGLISH_MESSAGES = Object.freeze({ 'bugbot.overflow.heading': 'More findings (comment limit)', 'bugbot.overflow.body': Object.freeze({ one: 'There is {count} more finding that was not published as an individual comment. Review locally or in the full diff to see the list.', other: 'There are {count} more findings that were not published as individual comments. Review locally or in the full diff to see the list.' }), 'bugbot.common.more': Object.freeze({ one: 'and {count} more.', other: 'and {count} more.' }), + 'bugbot.diagnostic.findingMutationFailed': 'Finding mutation failed: stage={stage}; operation={operation}; finding={findingId}; affected={affectedCount}; {providerStatus}; provider reference={providerReference}. Completed effects are retained. Correct access/contract errors before retrying; for transient failures restore provider availability, then recheck the same PR. Recheck reconciles existing reviews and threads.', 'bugbot.diagnostic.operationFailed': 'Bugbot could not complete one or more finding mutations.', 'bugbot.diagnostic.identityUnavailable': 'The authenticated Bugbot identity is unavailable.', 'bugbot.diagnostic.pullRequestCommentsFailed': 'Unable to re-read pull request review comments.', @@ -970,6 +1009,7 @@ const SPANISH_MESSAGES = Object.freeze({ 'bugbot.overflow.heading': 'Más hallazgos (límite de comentarios)', 'bugbot.overflow.body': Object.freeze({ one: 'Hay {count} hallazgo más que no se publicó como comentario individual. Revísalo localmente o en el diff completo para consultar la lista.', many: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.', other: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.' }), 'bugbot.common.more': Object.freeze({ one: 'y {count} más.', many: 'y {count} más.', other: 'y {count} más.' }), + 'bugbot.diagnostic.findingMutationFailed': 'Falló una mutación: fase={stage}; operación={operation}; hallazgo={findingId}; afectados={affectedCount}; {providerStatus}; referencia del proveedor={providerReference}. Se conservan los efectos completados. Corrige acceso/contrato antes de reintentar; para fallos transitorios restaura el proveedor y revisa la misma PR. La revisión reconcilia comentarios e hilos existentes.', 'bugbot.diagnostic.operationFailed': 'Bugbot no pudo completar una o más mutaciones de hallazgos.', 'bugbot.diagnostic.identityUnavailable': 'La identidad autenticada de Bugbot no está disponible.', 'bugbot.diagnostic.pullRequestCommentsFailed': 'No se pudieron volver a leer los comentarios del review del pull request.', @@ -1009,6 +1049,7 @@ async function resolveBugbotCatalog(locale, configuration, resolver) { } function renderBugbotDiagnostic(diagnostic, catalog) { switch (diagnostic.code) { + case 'finding-mutation-failed': return catalog.message('bugbot.diagnostic.findingMutationFailed', { ...diagnostic.mutation }); case 'operation-failed': return catalog.message('bugbot.diagnostic.operationFailed'); case 'identity-unavailable': return catalog.message('bugbot.diagnostic.identityUnavailable'); case 'snapshot-pull-request-comments-failed': return catalog.message('bugbot.diagnostic.pullRequestCommentsFailed'); @@ -1558,6 +1599,10 @@ function renderBugbotStatusCard(projection, catalogOrLocale, links) { facts.push(catalog.message('bugbot.coverage.omitted', { count: source.omittedItems })); if (source.truncatedItems > 0) facts.push(catalog.message('bugbot.coverage.truncated', { count: source.truncatedItems })); + const truncatedIds = source.truncatedItemIds?.slice(0, 50) + .filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160); + if (truncatedIds?.length) + facts.push(`truncated-source-ids=${truncatedIds.join(', ')}`); if (source.providerLimitReached) facts.push(catalog.message('bugbot.coverage.providerLimit')); return `- ${source.source}: ${source.status}; ${facts.join(', ')}`; @@ -2136,6 +2181,13 @@ class PullRequestReviewOperationError extends Error { super(buildMessage(operation, context)); this.name = "PullRequestReviewOperationError"; this.operation = operation; + const status = context?.providerStatus; + if (typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599) { + this.providerStatus = status; + } + if (typeof context?.providerReference === 'string' && /^[A-Za-z0-9:-]{1,64}$/.test(context.providerReference)) { + this.providerReference = context.providerReference; + } } } exports.PullRequestReviewOperationError = PullRequestReviewOperationError; @@ -2254,6 +2306,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyDetectedFindings = applyDetectedFindings; const mark_findings_resolved_use_case_1 = __nccwpck_require__(6963); const publish_findings_use_case_1 = __nccwpck_require__(8442); +const bugbot_mutation_error_1 = __nccwpck_require__(2937); const pull_request_review_errors_1 = __nccwpck_require__(6445); async function applyDetectedFindings(operation, context, prepared, publicationPorts, resolutionPorts, catalog) { try { @@ -2269,7 +2322,7 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo }); } catch (error) { - const publicationError = error instanceof pull_request_review_errors_1.PullRequestReviewOperationError + const publicationError = error instanceof bugbot_mutation_error_1.BugbotMutationError || error instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? error : new Error("Unable to publish findings."); return [publicationError]; @@ -2658,6 +2711,10 @@ function buildReviewConversationContext(issueComments, commentsByPullRequest, bo omitted, truncated: chronological.filter((entry) => entry.truncated).length, retained: chronological.length, + ...(chronological.some(entry => entry.truncated) ? { + truncatedItemIds: chronological.filter(entry => entry.truncated) + .map(entry => entry.providerId).filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160), + } : {}), }; } function appendConversationEntry(entries, author, kind, body, createdAt, providerId) { @@ -3339,6 +3396,7 @@ async function loadBugbotContext(request, ports, resolvedPreflight) { itemsFetched: conversationContext.retained + conversationContext.omitted, omittedItems: conversationContext.omitted, truncatedItems: conversationContext.truncated, + ...(conversationContext.truncatedItemIds ? { truncatedItemIds: conversationContext.truncatedItemIds } : {}), limitReached: conversationContext.omitted > 0 || conversationContext.truncated > 0, }, { @@ -3537,11 +3595,11 @@ Object.defineProperty(exports, "markFindingsResolved", ({ enumerable: true, get: Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = markFindingsResolved; -const pull_request_review_errors_1 = __nccwpck_require__(6445); const logging_ports_1 = __nccwpck_require__(6152); const resolve_issue_finding_1 = __nccwpck_require__(5300); const resolve_pull_request_finding_1 = __nccwpck_require__(4567); const review_state_1 = __nccwpck_require__(9200); +const bugbot_mutation_error_1 = __nccwpck_require__(2937); const application_error_1 = __nccwpck_require__(5999); async function markFindingsResolved(param) { const errors = []; @@ -3569,8 +3627,8 @@ async function repairExistingPullRequestFinding(ports, operation, findingId, des try { await ports.pullRequestComments.unresolvePullRequestReviewThread(destination.pullRequestNumber, destination.commentIdentity); } - catch { - addResolutionError(errors, 'pull request'); + catch (cause) { + addResolutionError(errors, 'pull request', findingId, cause); } } } @@ -3584,7 +3642,7 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) { return; const comment = param.context.issueComments.find(item => item.id === destination.commentId); if (comment?.body == null) { - addResolutionError(errors, 'issue'); + addResolutionError(errors, 'issue', findingId); return; } try { @@ -3595,8 +3653,8 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) { resolution: param.resolvedFindingResolutions?.get(findingId), }, param.catalog); } - catch { - addResolutionError(errors, 'issue'); + catch (cause) { + addResolutionError(errors, 'issue', findingId, cause); } } async function tryResolvePullRequestFinding(ports, findingId, destination, errors, resolution, catalog) { @@ -3608,17 +3666,14 @@ async function tryResolvePullRequestFinding(ports, findingId, destination, error resolution, }, catalog); } - catch { - addResolutionError(errors, 'pull request'); + catch (cause) { + addResolutionError(errors, 'pull request', findingId, cause); } } -function addResolutionError(errors, destination) { - const cause = destination === 'pull request' - ? new pull_request_review_errors_1.PullRequestReviewOperationError('mark-resolved') - : new Error('Unable to mark an issue finding as resolved.'); - const semanticError = new application_error_1.ApplicationError('provider.unavailable', destination === 'pull request' - ? 'Unable to mark a pull request finding as resolved.' - : 'Unable to mark an issue finding as resolved.', { cause }); +function addResolutionError(errors, destination, findingId, cause) { + const semanticError = destination === 'pull request' + ? (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'resolution', [findingId], 'mark-resolved') + : new application_error_1.ApplicationError('provider.unavailable', 'Unable to mark an issue finding as resolved.'); (0, logging_ports_1.logError)(semanticError); errors.push(semanticError); } @@ -3867,6 +3922,7 @@ function isRecord(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishFindings = publishFindings; +const bugbot_mutation_error_1 = __nccwpck_require__(2937); const finding_1 = __nccwpck_require__(1011); const publish_issue_finding_comment_1 = __nccwpck_require__(4950); const publish_pr_review_comments_1 = __nccwpck_require__(352); @@ -3886,14 +3942,24 @@ async function publishFindings(param) { }) : undefined; for (const finding of findings) { - if (operation.target.issueNumber > 0 && !reviewPublisher) { - await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog); + try { + if (operation.target.issueNumber > 0 && !reviewPublisher) { + await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog); + } + if (reviewPublisher) { + await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding)); + } } - if (reviewPublisher) { - await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding)); + catch (cause) { + throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', [finding.id], 'publish-comments'); } } - await reviewPublisher?.flush(overflowCount, overflowTitles); + try { + await reviewPublisher?.flush(overflowCount, overflowTitles); + } + catch (cause) { + throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', findings.map(finding => finding.id), 'publish-comments'); + } if (operation.target.issueNumber > 0 && !reviewPublisher) { await (0, publish_overflow_comment_1.publishOverflowComment)(ports.issueComments, operation.target.issueNumber, overflowCount, overflowTitles, commitSha, catalog); } @@ -4188,6 +4254,7 @@ async function queryBugbotPartitionFindings(repository, configuration, prompt, t Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileBugbotReviewState = reconcileBugbotReviewState; +const bugbot_mutation_error_1 = __nccwpck_require__(2937); const review_projection_1 = __nccwpck_require__(859); const bugbot_reconciliation_policy_1 = __nccwpck_require__(8128); const bugbot_provider_projection_policy_1 = __nccwpck_require__(5821); @@ -4219,10 +4286,9 @@ async function reconcileBugbotReviewState(input) { } const snapshot = snapshotResult.snapshot; const diagnostics = [ - ...(input.mutationErrors ?? []).map((error) => ({ - code: 'operation-failed', - operatorMessage: toSafeOperationMessage(error), - })), + ...(input.mutationErrors ?? []).map((error) => error instanceof bugbot_mutation_error_1.BugbotMutationError + ? { code: 'finding-mutation-failed', mutation: error.diagnostic } + : { code: 'operation-failed', operatorMessage: toSafeOperationMessage(error) }), ...(!input.target.trustedAuthorLogin?.trim() ? [{ code: 'identity-unavailable' }] : []), @@ -4697,14 +4763,16 @@ function toPresentationFailure(diagnostic) { const message = (0, bugbot_message_catalog_1.bugbotDiagnosticOperatorMessage)(diagnostic); return { diagnostic, - error: diagnostic.code === 'review-updates-pending' - ? new application_error_1.ApplicationError('workflow.presentation-pending', message, { - recovery: { - id: 'bugbot-review-blocks-pending', - variables: { pendingCount: diagnostic.count }, - }, - }) - : new Error(message), + error: diagnostic.code === 'finding-mutation-failed' + ? new application_error_1.ApplicationError(diagnostic.mutation.errorCode, message) + : diagnostic.code === 'review-updates-pending' + ? new application_error_1.ApplicationError('workflow.presentation-pending', message, { + recovery: { + id: 'bugbot-review-blocks-pending', + variables: { pendingCount: diagnostic.count }, + }, + }) + : new Error(message), }; } function report(projection, reviewUpdates, pendingReviewUpdates, statusCardOperation, errors) { diff --git a/build/api/src/domain/bugbot/context.d.ts b/build/api/src/domain/bugbot/context.d.ts index f4ee3769b..144b133c7 100644 --- a/build/api/src/domain/bugbot/context.d.ts +++ b/build/api/src/domain/bugbot/context.d.ts @@ -8,6 +8,8 @@ export interface BugbotSourceCoverage { readonly itemsRetained: number; readonly omittedItems: number; readonly truncatedItems: number; + /** Exact bounded provider identities of retained conversation items truncated by the prompt. */ + readonly truncatedItemIds?: readonly string[]; readonly limitReached: boolean; /** True when a provider page cap hides an unknown number of older records. */ readonly providerLimitReached?: boolean; diff --git a/build/cli/index.js b/build/cli/index.js index addfe08bd..ed8b3b1ad 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -38119,6 +38119,44 @@ function approvalDiagnosticError(diagnostic) { } +/***/ }), + +/***/ 82937: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BugbotMutationError = void 0; +exports.bugbotMutationError = bugbotMutationError; +const application_error_1 = __nccwpck_require__(75999); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +class BugbotMutationError extends application_error_1.ApplicationError { + constructor(diagnostic) { + super(diagnostic.errorCode, `Bugbot ${diagnostic.stage} failed: operation=${diagnostic.operation}; finding=${diagnostic.findingId}; affected=${diagnostic.affectedCount}; ${diagnostic.providerStatus}; provider-reference=${diagnostic.providerReference}. Completed effects are retained; correct the named cause and recheck the same target.`); + this.diagnostic = diagnostic; + } +} +exports.BugbotMutationError = BugbotMutationError; +function bugbotMutationError(cause, stage, findingIds, fallback) { + if (cause instanceof BugbotMutationError) + return cause; + const provider = cause instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? cause : undefined; + const status = provider?.providerStatus; + const errorCode = status === 401 ? 'authorization.credential-invalid' : status === 403 ? 'authorization.denied' + : status === 404 ? 'provider.not-found' : status === 409 ? 'provider.conflict' + : status === 429 ? 'provider.rate-limited' : status && status < 500 ? 'provider.contract-invalid' : 'provider.unavailable'; + const first = findingIds[0]; + return new BugbotMutationError(Object.freeze({ + stage, operation: provider?.operation ?? fallback, + findingId: typeof first === 'string' && /^[A-Za-z0-9_./:-]{1,200}$/.test(first) ? first : 'unavailable', + affectedCount: Math.min(findingIds.length, 10000), + providerStatus: status ? `http-${status}` : 'http-unavailable', + providerReference: provider?.providerReference ?? 'unavailable', errorCode, + })); +} + + /***/ }), /***/ 12183: @@ -40679,6 +40717,7 @@ exports.BUGBOT_MESSAGE_IDS = Object.freeze([ 'bugbot.overflow.body', 'bugbot.common.more', 'bugbot.diagnostic.operationFailed', + 'bugbot.diagnostic.findingMutationFailed', 'bugbot.diagnostic.identityUnavailable', 'bugbot.diagnostic.pullRequestCommentsFailed', 'bugbot.diagnostic.reviewThreadsFailed', @@ -40764,6 +40803,7 @@ const ENGLISH_MESSAGES = Object.freeze({ 'bugbot.overflow.heading': 'More findings (comment limit)', 'bugbot.overflow.body': Object.freeze({ one: 'There is {count} more finding that was not published as an individual comment. Review locally or in the full diff to see the list.', other: 'There are {count} more findings that were not published as individual comments. Review locally or in the full diff to see the list.' }), 'bugbot.common.more': Object.freeze({ one: 'and {count} more.', other: 'and {count} more.' }), + 'bugbot.diagnostic.findingMutationFailed': 'Finding mutation failed: stage={stage}; operation={operation}; finding={findingId}; affected={affectedCount}; {providerStatus}; provider reference={providerReference}. Completed effects are retained. Correct access/contract errors before retrying; for transient failures restore provider availability, then recheck the same PR. Recheck reconciles existing reviews and threads.', 'bugbot.diagnostic.operationFailed': 'Bugbot could not complete one or more finding mutations.', 'bugbot.diagnostic.identityUnavailable': 'The authenticated Bugbot identity is unavailable.', 'bugbot.diagnostic.pullRequestCommentsFailed': 'Unable to re-read pull request review comments.', @@ -40853,6 +40893,7 @@ const SPANISH_MESSAGES = Object.freeze({ 'bugbot.overflow.heading': 'Más hallazgos (límite de comentarios)', 'bugbot.overflow.body': Object.freeze({ one: 'Hay {count} hallazgo más que no se publicó como comentario individual. Revísalo localmente o en el diff completo para consultar la lista.', many: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.', other: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.' }), 'bugbot.common.more': Object.freeze({ one: 'y {count} más.', many: 'y {count} más.', other: 'y {count} más.' }), + 'bugbot.diagnostic.findingMutationFailed': 'Falló una mutación: fase={stage}; operación={operation}; hallazgo={findingId}; afectados={affectedCount}; {providerStatus}; referencia del proveedor={providerReference}. Se conservan los efectos completados. Corrige acceso/contrato antes de reintentar; para fallos transitorios restaura el proveedor y revisa la misma PR. La revisión reconcilia comentarios e hilos existentes.', 'bugbot.diagnostic.operationFailed': 'Bugbot no pudo completar una o más mutaciones de hallazgos.', 'bugbot.diagnostic.identityUnavailable': 'La identidad autenticada de Bugbot no está disponible.', 'bugbot.diagnostic.pullRequestCommentsFailed': 'No se pudieron volver a leer los comentarios del review del pull request.', @@ -40892,6 +40933,7 @@ async function resolveBugbotCatalog(locale, configuration, resolver) { } function renderBugbotDiagnostic(diagnostic, catalog) { switch (diagnostic.code) { + case 'finding-mutation-failed': return catalog.message('bugbot.diagnostic.findingMutationFailed', { ...diagnostic.mutation }); case 'operation-failed': return catalog.message('bugbot.diagnostic.operationFailed'); case 'identity-unavailable': return catalog.message('bugbot.diagnostic.identityUnavailable'); case 'snapshot-pull-request-comments-failed': return catalog.message('bugbot.diagnostic.pullRequestCommentsFailed'); @@ -41519,6 +41561,10 @@ function renderBugbotStatusCard(projection, catalogOrLocale, links) { facts.push(catalog.message('bugbot.coverage.omitted', { count: source.omittedItems })); if (source.truncatedItems > 0) facts.push(catalog.message('bugbot.coverage.truncated', { count: source.truncatedItems })); + const truncatedIds = source.truncatedItemIds?.slice(0, 50) + .filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160); + if (truncatedIds?.length) + facts.push(`truncated-source-ids=${truncatedIds.join(', ')}`); if (source.providerLimitReached) facts.push(catalog.message('bugbot.coverage.providerLimit')); return `- ${source.source}: ${source.status}; ${facts.join(', ')}`; @@ -53459,6 +53505,13 @@ class PullRequestReviewOperationError extends Error { super(buildMessage(operation, context)); this.name = "PullRequestReviewOperationError"; this.operation = operation; + const status = context?.providerStatus; + if (typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599) { + this.providerStatus = status; + } + if (typeof context?.providerReference === 'string' && /^[A-Za-z0-9:-]{1,64}$/.test(context.providerReference)) { + this.providerReference = context.providerReference; + } } } exports.PullRequestReviewOperationError = PullRequestReviewOperationError; @@ -64546,6 +64599,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyDetectedFindings = applyDetectedFindings; const mark_findings_resolved_use_case_1 = __nccwpck_require__(96963); const publish_findings_use_case_1 = __nccwpck_require__(88442); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const pull_request_review_errors_1 = __nccwpck_require__(46445); async function applyDetectedFindings(operation, context, prepared, publicationPorts, resolutionPorts, catalog) { try { @@ -64561,7 +64615,7 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo }); } catch (error) { - const publicationError = error instanceof pull_request_review_errors_1.PullRequestReviewOperationError + const publicationError = error instanceof bugbot_mutation_error_1.BugbotMutationError || error instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? error : new Error("Unable to publish findings."); return [publicationError]; @@ -65231,6 +65285,10 @@ function buildReviewConversationContext(issueComments, commentsByPullRequest, bo omitted, truncated: chronological.filter((entry) => entry.truncated).length, retained: chronological.length, + ...(chronological.some(entry => entry.truncated) ? { + truncatedItemIds: chronological.filter(entry => entry.truncated) + .map(entry => entry.providerId).filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160), + } : {}), }; } function appendConversationEntry(entries, author, kind, body, createdAt, providerId) { @@ -66722,6 +66780,7 @@ async function loadBugbotContext(request, ports, resolvedPreflight) { itemsFetched: conversationContext.retained + conversationContext.omitted, omittedItems: conversationContext.omitted, truncatedItems: conversationContext.truncated, + ...(conversationContext.truncatedItemIds ? { truncatedItemIds: conversationContext.truncatedItemIds } : {}), limitReached: conversationContext.omitted > 0 || conversationContext.truncated > 0, }, { @@ -66923,11 +66982,11 @@ Object.defineProperty(exports, "markFindingsResolved", ({ enumerable: true, get: Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = markFindingsResolved; -const pull_request_review_errors_1 = __nccwpck_require__(46445); const logging_ports_1 = __nccwpck_require__(6152); const resolve_issue_finding_1 = __nccwpck_require__(35300); const resolve_pull_request_finding_1 = __nccwpck_require__(64567); const review_state_1 = __nccwpck_require__(79200); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const application_error_1 = __nccwpck_require__(75999); async function markFindingsResolved(param) { const errors = []; @@ -66955,8 +67014,8 @@ async function repairExistingPullRequestFinding(ports, operation, findingId, des try { await ports.pullRequestComments.unresolvePullRequestReviewThread(destination.pullRequestNumber, destination.commentIdentity); } - catch { - addResolutionError(errors, 'pull request'); + catch (cause) { + addResolutionError(errors, 'pull request', findingId, cause); } } } @@ -66970,7 +67029,7 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) { return; const comment = param.context.issueComments.find(item => item.id === destination.commentId); if (comment?.body == null) { - addResolutionError(errors, 'issue'); + addResolutionError(errors, 'issue', findingId); return; } try { @@ -66981,8 +67040,8 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) { resolution: param.resolvedFindingResolutions?.get(findingId), }, param.catalog); } - catch { - addResolutionError(errors, 'issue'); + catch (cause) { + addResolutionError(errors, 'issue', findingId, cause); } } async function tryResolvePullRequestFinding(ports, findingId, destination, errors, resolution, catalog) { @@ -66994,17 +67053,14 @@ async function tryResolvePullRequestFinding(ports, findingId, destination, error resolution, }, catalog); } - catch { - addResolutionError(errors, 'pull request'); + catch (cause) { + addResolutionError(errors, 'pull request', findingId, cause); } } -function addResolutionError(errors, destination) { - const cause = destination === 'pull request' - ? new pull_request_review_errors_1.PullRequestReviewOperationError('mark-resolved') - : new Error('Unable to mark an issue finding as resolved.'); - const semanticError = new application_error_1.ApplicationError('provider.unavailable', destination === 'pull request' - ? 'Unable to mark a pull request finding as resolved.' - : 'Unable to mark an issue finding as resolved.', { cause }); +function addResolutionError(errors, destination, findingId, cause) { + const semanticError = destination === 'pull request' + ? (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'resolution', [findingId], 'mark-resolved') + : new application_error_1.ApplicationError('provider.unavailable', 'Unable to mark an issue finding as resolved.'); (0, logging_ports_1.logError)(semanticError); errors.push(semanticError); } @@ -67257,6 +67313,7 @@ function isRecord(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishFindings = publishFindings; +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const finding_1 = __nccwpck_require__(31011); const publish_issue_finding_comment_1 = __nccwpck_require__(84950); const publish_pr_review_comments_1 = __nccwpck_require__(50352); @@ -67276,14 +67333,24 @@ async function publishFindings(param) { }) : undefined; for (const finding of findings) { - if (operation.target.issueNumber > 0 && !reviewPublisher) { - await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog); + try { + if (operation.target.issueNumber > 0 && !reviewPublisher) { + await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog); + } + if (reviewPublisher) { + await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding)); + } } - if (reviewPublisher) { - await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding)); + catch (cause) { + throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', [finding.id], 'publish-comments'); } } - await reviewPublisher?.flush(overflowCount, overflowTitles); + try { + await reviewPublisher?.flush(overflowCount, overflowTitles); + } + catch (cause) { + throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', findings.map(finding => finding.id), 'publish-comments'); + } if (operation.target.issueNumber > 0 && !reviewPublisher) { await (0, publish_overflow_comment_1.publishOverflowComment)(ports.issueComments, operation.target.issueNumber, overflowCount, overflowTitles, commitSha, catalog); } @@ -67583,6 +67650,7 @@ async function queryBugbotPartitionFindings(repository, configuration, prompt, t Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileBugbotReviewState = reconcileBugbotReviewState; +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const review_projection_1 = __nccwpck_require__(80859); const bugbot_reconciliation_policy_1 = __nccwpck_require__(78128); const bugbot_provider_projection_policy_1 = __nccwpck_require__(85821); @@ -67614,10 +67682,9 @@ async function reconcileBugbotReviewState(input) { } const snapshot = snapshotResult.snapshot; const diagnostics = [ - ...(input.mutationErrors ?? []).map((error) => ({ - code: 'operation-failed', - operatorMessage: toSafeOperationMessage(error), - })), + ...(input.mutationErrors ?? []).map((error) => error instanceof bugbot_mutation_error_1.BugbotMutationError + ? { code: 'finding-mutation-failed', mutation: error.diagnostic } + : { code: 'operation-failed', operatorMessage: toSafeOperationMessage(error) }), ...(!input.target.trustedAuthorLogin?.trim() ? [{ code: 'identity-unavailable' }] : []), @@ -68141,14 +68208,16 @@ function toPresentationFailure(diagnostic) { const message = (0, bugbot_message_catalog_1.bugbotDiagnosticOperatorMessage)(diagnostic); return { diagnostic, - error: diagnostic.code === 'review-updates-pending' - ? new application_error_1.ApplicationError('workflow.presentation-pending', message, { - recovery: { - id: 'bugbot-review-blocks-pending', - variables: { pendingCount: diagnostic.count }, - }, - }) - : new Error(message), + error: diagnostic.code === 'finding-mutation-failed' + ? new application_error_1.ApplicationError(diagnostic.mutation.errorCode, message) + : diagnostic.code === 'review-updates-pending' + ? new application_error_1.ApplicationError('workflow.presentation-pending', message, { + recovery: { + id: 'bugbot-review-blocks-pending', + variables: { pendingCount: diagnostic.count }, + }, + }) + : new Error(message), }; } function report(projection, reviewUpdates, pendingReviewUpdates, statusCardOperation, errors) { @@ -87051,8 +87120,8 @@ function collectDiagnostic(diagnostics, cause) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestChangesRepository = void 0; +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const logger_1 = __nccwpck_require__(91151); -const pull_request_review_errors_1 = __nccwpck_require__(46445); const github_pagination_policy_1 = __nccwpck_require__(44812); const application_error_1 = __nccwpck_require__(75999); class PullRequestChangesRepository { @@ -87065,7 +87134,7 @@ class PullRequestChangesRepository { } catch (error) { (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', 'Unable to read the pull request review diff.')); - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-files'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-files'); } }; this.getBoundedBugbotReviewDiffSnapshot = async (owner, repository, pullNumber, token) => { @@ -87107,7 +87176,7 @@ class PullRequestChangesRepository { } catch (error) { (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', 'Unable to read the pull request review diff.')); - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-files'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-files'); } }; /** Head commit SHA of the PR (for creating review). */ @@ -87126,7 +87195,7 @@ class PullRequestChangesRepository { } catch (error) { (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', 'Unable to read the pull request head SHA.')); - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "get-head-sha"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "get-head-sha"); } }; } @@ -87469,6 +87538,7 @@ function toBugbotPullRequestIdentity(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentCommandRepository = void 0; +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const pull_request_review_errors_1 = __nccwpck_require__(46445); const github_pagination_policy_1 = __nccwpck_require__(44812); class PullRequestReviewCommentCommandRepository { @@ -87537,7 +87607,7 @@ class PullRequestReviewCommentCommandRepository { const context = comments.length > 0 ? { failedCount: comments.length, totalCount: comments.length } : undefined; - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "publish-comments", context); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "publish-comments", context); } } async updatePullRequestReview(owner, repository, pullRequestNumber, reviewIdentity, body, token) { @@ -87558,7 +87628,7 @@ class PullRequestReviewCommentCommandRepository { throw new pull_request_review_errors_1.PullRequestReviewOperationError('update-review'); } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'update-review'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'update-review'); } } async updatePullRequestReviewComment(_owner, _repository, commentIdentity, body, token) { @@ -87577,7 +87647,7 @@ class PullRequestReviewCommentCommandRepository { } } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "update-comment"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "update-comment"); } } } @@ -87593,7 +87663,7 @@ exports.PullRequestReviewCommentCommandRepository = PullRequestReviewCommentComm Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentQueryRepository = void 0; -const pull_request_review_errors_1 = __nccwpck_require__(46445); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const github_pagination_policy_1 = __nccwpck_require__(44812); function toReviewComment(comment) { if (typeof comment.node_id !== "string" || comment.node_id.length === 0) { @@ -87649,7 +87719,7 @@ class PullRequestReviewCommentQueryRepository { return comments; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "list-comments"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "list-comments"); } } async listBugbotPullRequestReviewCommentsBounded(owner, repository, pullRequestNumber, token) { @@ -87692,7 +87762,7 @@ class PullRequestReviewCommentQueryRepository { }; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "list-comments"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "list-comments"); } } async listPullRequestReviews(owner, repository, pullRequestNumber, token) { @@ -87706,7 +87776,7 @@ class PullRequestReviewCommentQueryRepository { return reviews; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-reviews'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-reviews'); } } async getPullRequestReviewCommentBody(owner, repository, _pullRequestNumber, commentId, token) { @@ -87720,13 +87790,37 @@ class PullRequestReviewCommentQueryRepository { return data.body ?? null; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "get-comment"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "get-comment"); } } } exports.PullRequestReviewCommentQueryRepository = PullRequestReviewCommentQueryRepository; +/***/ }), + +/***/ 54354: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.toPullRequestReviewOperationError = toPullRequestReviewOperationError; +const pull_request_review_errors_1 = __nccwpck_require__(46445); +/** Only safe HTTP metadata crosses the provider boundary; provider prose never does. */ +function toPullRequestReviewOperationError(error, operation, context) { + if (!error || typeof error !== 'object') + return (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, operation, context); + const record = error; + return (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, operation, { + ...context, + ...(typeof record.status === 'number' ? { providerStatus: record.status } : {}), + ...(typeof record.response?.headers?.['x-github-request-id'] === 'string' + ? { providerReference: record.response.headers['x-github-request-id'] } : {}), + }); +} + + /***/ }), /***/ 2307: @@ -87837,6 +87931,7 @@ function nextConnectionCursor(pageInfo, seenCursors) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewThreadRepository = void 0; +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const logger_1 = __nccwpck_require__(91151); const pull_request_review_errors_1 = __nccwpck_require__(46445); const pull_request_review_thread_locator_1 = __nccwpck_require__(2307); @@ -87884,7 +87979,7 @@ class PullRequestReviewThreadRepository { return states; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-threads'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-threads'); } }; this.listBugbotPullRequestReviewThreadStatesBounded = async (owner, repository, pullNumber, token) => { @@ -87953,7 +88048,7 @@ class PullRequestReviewThreadRepository { }; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-threads'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-threads'); } }; this.resolvePullRequestReviewThread = async (owner, repository, pullNumber, commentIdentity, token) => { @@ -87977,7 +88072,7 @@ class PullRequestReviewThreadRepository { (0, logger_1.logDebugInfo)('Resolved pull request review thread.'); } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'resolve-thread'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'resolve-thread'); } }; this.unresolvePullRequestReviewThread = async (owner, repository, pullNumber, commentIdentity, token) => { @@ -88001,7 +88096,7 @@ class PullRequestReviewThreadRepository { (0, logger_1.logDebugInfo)('Reopened pull request review thread.'); } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'unresolve-thread'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'unresolve-thread'); } }; } @@ -88018,7 +88113,7 @@ exports.PullRequestReviewThreadRepository = PullRequestReviewThreadRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewerRepository = void 0; -const pull_request_review_errors_1 = __nccwpck_require__(46445); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const github_pagination_policy_1 = __nccwpck_require__(44812); const COMPLETED_REVIEW_STATES = new Set([ "APPROVED", @@ -88051,7 +88146,7 @@ class PullRequestReviewerRepository { return [...reviewers.values()]; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "list-reviewers"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "list-reviewers"); } } async addReviewersToPullRequest(owner, repository, pullRequestNumber, reviewers, token) { @@ -88076,7 +88171,7 @@ class PullRequestReviewerRepository { return [...confirmed.values()]; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "request-reviewers"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "request-reviewers"); } } async listRequestedReviewers(client, parameters) { diff --git a/build/github_action/index.js b/build/github_action/index.js index 9cd6d5ace..c1e6a9d3b 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -38866,6 +38866,44 @@ function approvalDiagnosticError(diagnostic) { } +/***/ }), + +/***/ 82937: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BugbotMutationError = void 0; +exports.bugbotMutationError = bugbotMutationError; +const application_error_1 = __nccwpck_require__(75999); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +class BugbotMutationError extends application_error_1.ApplicationError { + constructor(diagnostic) { + super(diagnostic.errorCode, `Bugbot ${diagnostic.stage} failed: operation=${diagnostic.operation}; finding=${diagnostic.findingId}; affected=${diagnostic.affectedCount}; ${diagnostic.providerStatus}; provider-reference=${diagnostic.providerReference}. Completed effects are retained; correct the named cause and recheck the same target.`); + this.diagnostic = diagnostic; + } +} +exports.BugbotMutationError = BugbotMutationError; +function bugbotMutationError(cause, stage, findingIds, fallback) { + if (cause instanceof BugbotMutationError) + return cause; + const provider = cause instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? cause : undefined; + const status = provider?.providerStatus; + const errorCode = status === 401 ? 'authorization.credential-invalid' : status === 403 ? 'authorization.denied' + : status === 404 ? 'provider.not-found' : status === 409 ? 'provider.conflict' + : status === 429 ? 'provider.rate-limited' : status && status < 500 ? 'provider.contract-invalid' : 'provider.unavailable'; + const first = findingIds[0]; + return new BugbotMutationError(Object.freeze({ + stage, operation: provider?.operation ?? fallback, + findingId: typeof first === 'string' && /^[A-Za-z0-9_./:-]{1,200}$/.test(first) ? first : 'unavailable', + affectedCount: Math.min(findingIds.length, 10000), + providerStatus: status ? `http-${status}` : 'http-unavailable', + providerReference: provider?.providerReference ?? 'unavailable', errorCode, + })); +} + + /***/ }), /***/ 12183: @@ -41967,6 +42005,7 @@ exports.BUGBOT_MESSAGE_IDS = Object.freeze([ 'bugbot.overflow.body', 'bugbot.common.more', 'bugbot.diagnostic.operationFailed', + 'bugbot.diagnostic.findingMutationFailed', 'bugbot.diagnostic.identityUnavailable', 'bugbot.diagnostic.pullRequestCommentsFailed', 'bugbot.diagnostic.reviewThreadsFailed', @@ -42052,6 +42091,7 @@ const ENGLISH_MESSAGES = Object.freeze({ 'bugbot.overflow.heading': 'More findings (comment limit)', 'bugbot.overflow.body': Object.freeze({ one: 'There is {count} more finding that was not published as an individual comment. Review locally or in the full diff to see the list.', other: 'There are {count} more findings that were not published as individual comments. Review locally or in the full diff to see the list.' }), 'bugbot.common.more': Object.freeze({ one: 'and {count} more.', other: 'and {count} more.' }), + 'bugbot.diagnostic.findingMutationFailed': 'Finding mutation failed: stage={stage}; operation={operation}; finding={findingId}; affected={affectedCount}; {providerStatus}; provider reference={providerReference}. Completed effects are retained. Correct access/contract errors before retrying; for transient failures restore provider availability, then recheck the same PR. Recheck reconciles existing reviews and threads.', 'bugbot.diagnostic.operationFailed': 'Bugbot could not complete one or more finding mutations.', 'bugbot.diagnostic.identityUnavailable': 'The authenticated Bugbot identity is unavailable.', 'bugbot.diagnostic.pullRequestCommentsFailed': 'Unable to re-read pull request review comments.', @@ -42141,6 +42181,7 @@ const SPANISH_MESSAGES = Object.freeze({ 'bugbot.overflow.heading': 'Más hallazgos (límite de comentarios)', 'bugbot.overflow.body': Object.freeze({ one: 'Hay {count} hallazgo más que no se publicó como comentario individual. Revísalo localmente o en el diff completo para consultar la lista.', many: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.', other: 'Hay {count} hallazgos más que no se publicaron como comentarios individuales. Revísalos localmente o en el diff completo para consultar la lista.' }), 'bugbot.common.more': Object.freeze({ one: 'y {count} más.', many: 'y {count} más.', other: 'y {count} más.' }), + 'bugbot.diagnostic.findingMutationFailed': 'Falló una mutación: fase={stage}; operación={operation}; hallazgo={findingId}; afectados={affectedCount}; {providerStatus}; referencia del proveedor={providerReference}. Se conservan los efectos completados. Corrige acceso/contrato antes de reintentar; para fallos transitorios restaura el proveedor y revisa la misma PR. La revisión reconcilia comentarios e hilos existentes.', 'bugbot.diagnostic.operationFailed': 'Bugbot no pudo completar una o más mutaciones de hallazgos.', 'bugbot.diagnostic.identityUnavailable': 'La identidad autenticada de Bugbot no está disponible.', 'bugbot.diagnostic.pullRequestCommentsFailed': 'No se pudieron volver a leer los comentarios del review del pull request.', @@ -42180,6 +42221,7 @@ async function resolveBugbotCatalog(locale, configuration, resolver) { } function renderBugbotDiagnostic(diagnostic, catalog) { switch (diagnostic.code) { + case 'finding-mutation-failed': return catalog.message('bugbot.diagnostic.findingMutationFailed', { ...diagnostic.mutation }); case 'operation-failed': return catalog.message('bugbot.diagnostic.operationFailed'); case 'identity-unavailable': return catalog.message('bugbot.diagnostic.identityUnavailable'); case 'snapshot-pull-request-comments-failed': return catalog.message('bugbot.diagnostic.pullRequestCommentsFailed'); @@ -42807,6 +42849,10 @@ function renderBugbotStatusCard(projection, catalogOrLocale, links) { facts.push(catalog.message('bugbot.coverage.omitted', { count: source.omittedItems })); if (source.truncatedItems > 0) facts.push(catalog.message('bugbot.coverage.truncated', { count: source.truncatedItems })); + const truncatedIds = source.truncatedItemIds?.slice(0, 50) + .filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160); + if (truncatedIds?.length) + facts.push(`truncated-source-ids=${truncatedIds.join(', ')}`); if (source.providerLimitReached) facts.push(catalog.message('bugbot.coverage.providerLimit')); return `- ${source.source}: ${source.status}; ${facts.join(', ')}`; @@ -51205,6 +51251,13 @@ class PullRequestReviewOperationError extends Error { super(buildMessage(operation, context)); this.name = "PullRequestReviewOperationError"; this.operation = operation; + const status = context?.providerStatus; + if (typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599) { + this.providerStatus = status; + } + if (typeof context?.providerReference === 'string' && /^[A-Za-z0-9:-]{1,64}$/.test(context.providerReference)) { + this.providerReference = context.providerReference; + } } } exports.PullRequestReviewOperationError = PullRequestReviewOperationError; @@ -59775,6 +59828,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyDetectedFindings = applyDetectedFindings; const mark_findings_resolved_use_case_1 = __nccwpck_require__(96963); const publish_findings_use_case_1 = __nccwpck_require__(88442); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const pull_request_review_errors_1 = __nccwpck_require__(46445); async function applyDetectedFindings(operation, context, prepared, publicationPorts, resolutionPorts, catalog) { try { @@ -59790,7 +59844,7 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo }); } catch (error) { - const publicationError = error instanceof pull_request_review_errors_1.PullRequestReviewOperationError + const publicationError = error instanceof bugbot_mutation_error_1.BugbotMutationError || error instanceof pull_request_review_errors_1.PullRequestReviewOperationError ? error : new Error("Unable to publish findings."); return [publicationError]; @@ -60460,6 +60514,10 @@ function buildReviewConversationContext(issueComments, commentsByPullRequest, bo omitted, truncated: chronological.filter((entry) => entry.truncated).length, retained: chronological.length, + ...(chronological.some(entry => entry.truncated) ? { + truncatedItemIds: chronological.filter(entry => entry.truncated) + .map(entry => entry.providerId).filter(id => /^(?:issue:[0-9]+|review:[A-Za-z0-9_=-]+)$/.test(id) && id.length <= 160), + } : {}), }; } function appendConversationEntry(entries, author, kind, body, createdAt, providerId) { @@ -61951,6 +62009,7 @@ async function loadBugbotContext(request, ports, resolvedPreflight) { itemsFetched: conversationContext.retained + conversationContext.omitted, omittedItems: conversationContext.omitted, truncatedItems: conversationContext.truncated, + ...(conversationContext.truncatedItemIds ? { truncatedItemIds: conversationContext.truncatedItemIds } : {}), limitReached: conversationContext.omitted > 0 || conversationContext.truncated > 0, }, { @@ -62152,11 +62211,11 @@ Object.defineProperty(exports, "markFindingsResolved", ({ enumerable: true, get: Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = markFindingsResolved; -const pull_request_review_errors_1 = __nccwpck_require__(46445); const logging_ports_1 = __nccwpck_require__(6152); const resolve_issue_finding_1 = __nccwpck_require__(35300); const resolve_pull_request_finding_1 = __nccwpck_require__(64567); const review_state_1 = __nccwpck_require__(79200); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const application_error_1 = __nccwpck_require__(75999); async function markFindingsResolved(param) { const errors = []; @@ -62184,8 +62243,8 @@ async function repairExistingPullRequestFinding(ports, operation, findingId, des try { await ports.pullRequestComments.unresolvePullRequestReviewThread(destination.pullRequestNumber, destination.commentIdentity); } - catch { - addResolutionError(errors, 'pull request'); + catch (cause) { + addResolutionError(errors, 'pull request', findingId, cause); } } } @@ -62199,7 +62258,7 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) { return; const comment = param.context.issueComments.find(item => item.id === destination.commentId); if (comment?.body == null) { - addResolutionError(errors, 'issue'); + addResolutionError(errors, 'issue', findingId); return; } try { @@ -62210,8 +62269,8 @@ async function resolveIssueIfNeeded(param, findingId, destination, errors) { resolution: param.resolvedFindingResolutions?.get(findingId), }, param.catalog); } - catch { - addResolutionError(errors, 'issue'); + catch (cause) { + addResolutionError(errors, 'issue', findingId, cause); } } async function tryResolvePullRequestFinding(ports, findingId, destination, errors, resolution, catalog) { @@ -62223,17 +62282,14 @@ async function tryResolvePullRequestFinding(ports, findingId, destination, error resolution, }, catalog); } - catch { - addResolutionError(errors, 'pull request'); + catch (cause) { + addResolutionError(errors, 'pull request', findingId, cause); } } -function addResolutionError(errors, destination) { - const cause = destination === 'pull request' - ? new pull_request_review_errors_1.PullRequestReviewOperationError('mark-resolved') - : new Error('Unable to mark an issue finding as resolved.'); - const semanticError = new application_error_1.ApplicationError('provider.unavailable', destination === 'pull request' - ? 'Unable to mark a pull request finding as resolved.' - : 'Unable to mark an issue finding as resolved.', { cause }); +function addResolutionError(errors, destination, findingId, cause) { + const semanticError = destination === 'pull request' + ? (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'resolution', [findingId], 'mark-resolved') + : new application_error_1.ApplicationError('provider.unavailable', 'Unable to mark an issue finding as resolved.'); (0, logging_ports_1.logError)(semanticError); errors.push(semanticError); } @@ -62486,6 +62542,7 @@ function isRecord(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishFindings = publishFindings; +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const finding_1 = __nccwpck_require__(31011); const publish_issue_finding_comment_1 = __nccwpck_require__(84950); const publish_pr_review_comments_1 = __nccwpck_require__(50352); @@ -62505,14 +62562,24 @@ async function publishFindings(param) { }) : undefined; for (const finding of findings) { - if (operation.target.issueNumber > 0 && !reviewPublisher) { - await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog); + try { + if (operation.target.issueNumber > 0 && !reviewPublisher) { + await (0, publish_issue_finding_comment_1.publishIssueFindingComment)(ports.issueComments, operation.target.issueNumber, finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding), commitSha, catalog); + } + if (reviewPublisher) { + await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding)); + } } - if (reviewPublisher) { - await reviewPublisher.publish(finding, (0, finding_1.findExistingFindingInfo)(existingByFindingId, finding)); + catch (cause) { + throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', [finding.id], 'publish-comments'); } } - await reviewPublisher?.flush(overflowCount, overflowTitles); + try { + await reviewPublisher?.flush(overflowCount, overflowTitles); + } + catch (cause) { + throw (0, bugbot_mutation_error_1.bugbotMutationError)(cause, 'publication', findings.map(finding => finding.id), 'publish-comments'); + } if (operation.target.issueNumber > 0 && !reviewPublisher) { await (0, publish_overflow_comment_1.publishOverflowComment)(ports.issueComments, operation.target.issueNumber, overflowCount, overflowTitles, commitSha, catalog); } @@ -62812,6 +62879,7 @@ async function queryBugbotPartitionFindings(repository, configuration, prompt, t Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileBugbotReviewState = reconcileBugbotReviewState; +const bugbot_mutation_error_1 = __nccwpck_require__(82937); const review_projection_1 = __nccwpck_require__(80859); const bugbot_reconciliation_policy_1 = __nccwpck_require__(78128); const bugbot_provider_projection_policy_1 = __nccwpck_require__(85821); @@ -62843,10 +62911,9 @@ async function reconcileBugbotReviewState(input) { } const snapshot = snapshotResult.snapshot; const diagnostics = [ - ...(input.mutationErrors ?? []).map((error) => ({ - code: 'operation-failed', - operatorMessage: toSafeOperationMessage(error), - })), + ...(input.mutationErrors ?? []).map((error) => error instanceof bugbot_mutation_error_1.BugbotMutationError + ? { code: 'finding-mutation-failed', mutation: error.diagnostic } + : { code: 'operation-failed', operatorMessage: toSafeOperationMessage(error) }), ...(!input.target.trustedAuthorLogin?.trim() ? [{ code: 'identity-unavailable' }] : []), @@ -63370,14 +63437,16 @@ function toPresentationFailure(diagnostic) { const message = (0, bugbot_message_catalog_1.bugbotDiagnosticOperatorMessage)(diagnostic); return { diagnostic, - error: diagnostic.code === 'review-updates-pending' - ? new application_error_1.ApplicationError('workflow.presentation-pending', message, { - recovery: { - id: 'bugbot-review-blocks-pending', - variables: { pendingCount: diagnostic.count }, - }, - }) - : new Error(message), + error: diagnostic.code === 'finding-mutation-failed' + ? new application_error_1.ApplicationError(diagnostic.mutation.errorCode, message) + : diagnostic.code === 'review-updates-pending' + ? new application_error_1.ApplicationError('workflow.presentation-pending', message, { + recovery: { + id: 'bugbot-review-blocks-pending', + variables: { pendingCount: diagnostic.count }, + }, + }) + : new Error(message), }; } function report(projection, reviewUpdates, pendingReviewUpdates, statusCardOperation, errors) { @@ -77612,8 +77681,8 @@ function collectDiagnostic(diagnostics, cause) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestChangesRepository = void 0; +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const logger_1 = __nccwpck_require__(91151); -const pull_request_review_errors_1 = __nccwpck_require__(46445); const github_pagination_policy_1 = __nccwpck_require__(44812); const application_error_1 = __nccwpck_require__(75999); class PullRequestChangesRepository { @@ -77626,7 +77695,7 @@ class PullRequestChangesRepository { } catch (error) { (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', 'Unable to read the pull request review diff.')); - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-files'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-files'); } }; this.getBoundedBugbotReviewDiffSnapshot = async (owner, repository, pullNumber, token) => { @@ -77668,7 +77737,7 @@ class PullRequestChangesRepository { } catch (error) { (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', 'Unable to read the pull request review diff.')); - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-files'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-files'); } }; /** Head commit SHA of the PR (for creating review). */ @@ -77687,7 +77756,7 @@ class PullRequestChangesRepository { } catch (error) { (0, logger_1.logError)((0, application_error_1.toApplicationError)(error, 'provider.unavailable', 'Unable to read the pull request head SHA.')); - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "get-head-sha"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "get-head-sha"); } }; } @@ -78030,6 +78099,7 @@ function toBugbotPullRequestIdentity(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentCommandRepository = void 0; +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const pull_request_review_errors_1 = __nccwpck_require__(46445); const github_pagination_policy_1 = __nccwpck_require__(44812); class PullRequestReviewCommentCommandRepository { @@ -78098,7 +78168,7 @@ class PullRequestReviewCommentCommandRepository { const context = comments.length > 0 ? { failedCount: comments.length, totalCount: comments.length } : undefined; - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "publish-comments", context); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "publish-comments", context); } } async updatePullRequestReview(owner, repository, pullRequestNumber, reviewIdentity, body, token) { @@ -78119,7 +78189,7 @@ class PullRequestReviewCommentCommandRepository { throw new pull_request_review_errors_1.PullRequestReviewOperationError('update-review'); } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'update-review'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'update-review'); } } async updatePullRequestReviewComment(_owner, _repository, commentIdentity, body, token) { @@ -78138,7 +78208,7 @@ class PullRequestReviewCommentCommandRepository { } } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "update-comment"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "update-comment"); } } } @@ -78154,7 +78224,7 @@ exports.PullRequestReviewCommentCommandRepository = PullRequestReviewCommentComm Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentQueryRepository = void 0; -const pull_request_review_errors_1 = __nccwpck_require__(46445); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const github_pagination_policy_1 = __nccwpck_require__(44812); function toReviewComment(comment) { if (typeof comment.node_id !== "string" || comment.node_id.length === 0) { @@ -78210,7 +78280,7 @@ class PullRequestReviewCommentQueryRepository { return comments; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "list-comments"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "list-comments"); } } async listBugbotPullRequestReviewCommentsBounded(owner, repository, pullRequestNumber, token) { @@ -78253,7 +78323,7 @@ class PullRequestReviewCommentQueryRepository { }; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "list-comments"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "list-comments"); } } async listPullRequestReviews(owner, repository, pullRequestNumber, token) { @@ -78267,7 +78337,7 @@ class PullRequestReviewCommentQueryRepository { return reviews; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-reviews'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-reviews'); } } async getPullRequestReviewCommentBody(owner, repository, _pullRequestNumber, commentId, token) { @@ -78281,13 +78351,37 @@ class PullRequestReviewCommentQueryRepository { return data.body ?? null; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "get-comment"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "get-comment"); } } } exports.PullRequestReviewCommentQueryRepository = PullRequestReviewCommentQueryRepository; +/***/ }), + +/***/ 54354: +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.toPullRequestReviewOperationError = toPullRequestReviewOperationError; +const pull_request_review_errors_1 = __nccwpck_require__(46445); +/** Only safe HTTP metadata crosses the provider boundary; provider prose never does. */ +function toPullRequestReviewOperationError(error, operation, context) { + if (!error || typeof error !== 'object') + return (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, operation, context); + const record = error; + return (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, operation, { + ...context, + ...(typeof record.status === 'number' ? { providerStatus: record.status } : {}), + ...(typeof record.response?.headers?.['x-github-request-id'] === 'string' + ? { providerReference: record.response.headers['x-github-request-id'] } : {}), + }); +} + + /***/ }), /***/ 2307: @@ -78398,6 +78492,7 @@ function nextConnectionCursor(pageInfo, seenCursors) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewThreadRepository = void 0; +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const logger_1 = __nccwpck_require__(91151); const pull_request_review_errors_1 = __nccwpck_require__(46445); const pull_request_review_thread_locator_1 = __nccwpck_require__(2307); @@ -78445,7 +78540,7 @@ class PullRequestReviewThreadRepository { return states; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-threads'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-threads'); } }; this.listBugbotPullRequestReviewThreadStatesBounded = async (owner, repository, pullNumber, token) => { @@ -78514,7 +78609,7 @@ class PullRequestReviewThreadRepository { }; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'list-threads'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'list-threads'); } }; this.resolvePullRequestReviewThread = async (owner, repository, pullNumber, commentIdentity, token) => { @@ -78538,7 +78633,7 @@ class PullRequestReviewThreadRepository { (0, logger_1.logDebugInfo)('Resolved pull request review thread.'); } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'resolve-thread'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'resolve-thread'); } }; this.unresolvePullRequestReviewThread = async (owner, repository, pullNumber, commentIdentity, token) => { @@ -78562,7 +78657,7 @@ class PullRequestReviewThreadRepository { (0, logger_1.logDebugInfo)('Reopened pull request review thread.'); } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, 'unresolve-thread'); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, 'unresolve-thread'); } }; } @@ -78579,7 +78674,7 @@ exports.PullRequestReviewThreadRepository = PullRequestReviewThreadRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewerRepository = void 0; -const pull_request_review_errors_1 = __nccwpck_require__(46445); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); const github_pagination_policy_1 = __nccwpck_require__(44812); const COMPLETED_REVIEW_STATES = new Set([ "APPROVED", @@ -78612,7 +78707,7 @@ class PullRequestReviewerRepository { return [...reviewers.values()]; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "list-reviewers"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "list-reviewers"); } } async addReviewersToPullRequest(owner, repository, pullRequestNumber, reviewers, token) { @@ -78637,7 +78732,7 @@ class PullRequestReviewerRepository { return [...confirmed.values()]; } catch (error) { - throw (0, pull_request_review_errors_1.toPullRequestReviewOperationError)(error, "request-reviewers"); + throw (0, pull_request_review_error_metadata_1.toPullRequestReviewOperationError)(error, "request-reviewers"); } } async listRequestedReviewers(client, parameters) { diff --git a/docs/bugbot/failure-scenarios.mdx b/docs/bugbot/failure-scenarios.mdx index 0264b84cd..c65052edd 100644 --- a/docs/bugbot/failure-scenarios.mdx +++ b/docs/bugbot/failure-scenarios.mdx @@ -51,6 +51,13 @@ description: Diagnose terminal failures across detection, publication, autofix, Bugbot updates historical review blocks in sequential batches of 20, up to 100 per run. If more remain, or a batch fails, the status card and Check report the exact unattempted count and the Action uses `workflow.presentation-pending` for a budget remainder. This does not mean the provider is unavailable or that the diff was only partly analyzed. Re-run `/copilot recheck` after inspecting any separate write failure; successful updates are kept and already-current blocks are skipped. The canonical status card remains the aggregate view throughout. + + Successful publication can precede a later failed marker/thread mutation. The recovery details identify the publication or resolution stage, exact operation, affected finding (plus batch count), HTTP status and provider request reference when available. Missing provider metadata is explicitly unavailable. Existing reviews, comments and durable dismissal intent are retained; a zero completed-publication count on a failed run does not prove that no native review exists. + + Correct permanent credential/access or contract failures before retrying. For a transient outage or rate limit, restore provider availability first, then run `/copilot recheck` on the same PR. The normal fresh provider read reconciles existing comments and threads rather than recreating completed effects. Do not delete a review or install an application dependency merely to clear an unrelated finding-publication failure. + + **Incomplete coverage** remains separate. `human-conversation` lists retained, omitted and truncated counts plus `truncated-source-ids` for exact retained records, such as `issue:6311517518` (a general issue/PR comment ID) or `review:PRRC_50` (an inline comment node ID). Inspect that source from the linked PR/issue, preserve its substantive decisions and reduce only redundant text before rechecking. Source IDs contain no comment text. A mutation retry never upgrades incomplete conversation evidence to complete. + See [Verification commands](/bugbot/verification-commands) and [Security & Operations](/security-operations). diff --git a/specs/CATALOG.md b/specs/CATALOG.md index 7729c582d..2b69c4a1f 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -13,7 +13,7 @@ debt or convert unknown historic intent into a design decision. | `github-communication-experience` | Implemented | English-default, localized, semantic, bounded, and idempotent product messages across GitHub and repository-aware operator surfaces | [Semantic GitHub communication and repository localization](./semantic-github-publication-and-notification.md) + 3 companion | 277 paths · 2026-10-20 | | `release-orchestration` | Implemented | Release and hotfix promotion, publication, bounded merge readiness recovery, and receipt-verified reconciliation without republication | [Configurable production-first release orchestration](./configurable-release-orchestration.md) + 2 companion | 59 paths · 2026-10-16 | | `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration; cached RepoWise exports and bounded full-history secret processing with truthful completeness and resource evidence | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 29 paths · 2026-10-21 | -| `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 59 paths · 2026-10-11 | +| `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 63 paths · 2026-10-21 | | `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 104 paths · 2026-10-21 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | | `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 5 companion | 326 paths · 2026-10-20 | @@ -70,12 +70,12 @@ debt or convert unknown historic intent into a design decision. ### `bugbot-review-state-reconciliation` — Bugbot review-state reconciliation - Owner: Copilot maintainers -- Last verified: 2026-10-11 +- Last verified: 2026-10-21 - Specifications: [`specs/bugbot-review-state-reconciliation.md`](./bugbot-review-state-reconciliation.md) - Workflows: [`.github/workflows/copilot_commit.yml`](../.github/workflows/copilot_commit.yml) · [`.github/workflows/copilot_pull_request.yml`](../.github/workflows/copilot_pull_request.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) - Entrypoints: [`src/application/usecases/steps/commit/detect_potential_problems_workflow.ts`](../src/application/usecases/steps/commit/detect_potential_problems_workflow.ts) · [`src/application/usecases/steps/commit/bugbot/reconcile_bugbot_review_state_use_case.ts`](../src/application/usecases/steps/commit/bugbot/reconcile_bugbot_review_state_use_case.ts) · [`src/actions/github_action_completion.ts`](../src/actions/github_action_completion.ts) · [`src/api.ts`](../src/api.ts) -- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`src/domain/bugbot/review_state.ts`](../src/domain/bugbot/review_state.ts) · [`src/domain/bugbot/review_projection.ts`](../src/domain/bugbot/review_projection.ts) · [`src/application/policies/bugbot_reconciliation_policy.ts`](../src/application/policies/bugbot_reconciliation_policy.ts) · [`src/application/policies/bugbot_event_ownership_policy.ts`](../src/application/policies/bugbot_event_ownership_policy.ts) · [`src/application/policies/bugbot_result_finding_state_projection_policy.ts`](../src/application/policies/bugbot_result_finding_state_projection_policy.ts) · [`src/application/policies/bugbot_telemetry_projection_policy.ts`](../src/application/policies/bugbot_telemetry_projection_policy.ts) · [`src/application/policies/bugbot_message_catalog.ts`](../src/application/policies/bugbot_message_catalog.ts) · [`src/application/policies/bugbot_finding_marker_policy.ts`](../src/application/policies/bugbot_finding_marker_policy.ts) · [`src/application/policies/bugbot_review_presentation_policy.ts`](../src/application/policies/bugbot_review_presentation_policy.ts) · [`src/application/policies/action_summary_policy.ts`](../src/application/policies/action_summary_policy.ts) · [`src/application/policies/copilot_evidence_policy.ts`](../src/application/policies/copilot_evidence_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`src/application/usecases/steps/commit/bugbot/load_bugbot_context_use_case.ts`](../src/application/usecases/steps/commit/bugbot/load_bugbot_context_use_case.ts) · [`src/application/usecases/steps/commit/bugbot/schema.ts`](../src/application/usecases/steps/commit/bugbot/schema.ts) · [`src/application/usecases/steps/commit/bugbot/prepare_bugbot_findings_policy.ts`](../src/application/usecases/steps/commit/bugbot/prepare_bugbot_findings_policy.ts) · [`src/application/usecases/steps/commit/bugbot/publish_pr_review_comments.ts`](../src/application/usecases/steps/commit/bugbot/publish_pr_review_comments.ts) · [`src/application/usecases/steps/commit/bugbot/synchronize_bugbot_review_presentation_use_case.ts`](../src/application/usecases/steps/commit/bugbot/synchronize_bugbot_review_presentation_use_case.ts) · [`src/application/policies/bugbot_status_count_marker_policy.ts`](../src/application/policies/bugbot_status_count_marker_policy.ts) -- Tests: [`src/domain/bugbot/__tests__/review_state.test.ts`](../src/domain/bugbot/__tests__/review_state.test.ts) · [`src/domain/bugbot/__tests__/review_projection.test.ts`](../src/domain/bugbot/__tests__/review_projection.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/schema.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/schema.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/prepare_bugbot_findings.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/prepare_bugbot_findings.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/synchronize_bugbot_review_presentation_use_case.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/synchronize_bugbot_review_presentation_use_case.test.ts) · [`src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_event_ownership_policy.test.ts`](../src/application/policies/__tests__/bugbot_event_ownership_policy.test.ts) · [`src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_message_catalog.test.ts`](../src/application/policies/__tests__/bugbot_message_catalog.test.ts) · [`src/application/policies/__tests__/bugbot_finding_marker_policy.test.ts`](../src/application/policies/__tests__/bugbot_finding_marker_policy.test.ts) · [`src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts`](../src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts) · [`src/application/policies/__tests__/action_summary_policy.test.ts`](../src/application/policies/__tests__/action_summary_policy.test.ts) · [`src/application/policies/__tests__/copilot_evidence_policy.test.ts`](../src/application/policies/__tests__/copilot_evidence_policy.test.ts) · [`src/application/policies/__tests__/lifecycle_state_policy.test.ts`](../src/application/policies/__tests__/lifecycle_state_policy.test.ts) · [`src/application/policies/__tests__/status_command_policy.test.ts`](../src/application/policies/__tests__/status_command_policy.test.ts) · [`src/actions/__tests__/github_action_completion.test.ts`](../src/actions/__tests__/github_action_completion.test.ts) · [`src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts`](../src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts) · [`src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts`](../src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts) · [`src/application/usecases/steps/commit/__tests__/detect_potential_problems_use_case.test.ts`](../src/application/usecases/steps/commit/__tests__/detect_potential_problems_use_case.test.ts) · [`src/infrastructure/composition/__tests__/pull_request_use_case_composition_root.test.ts`](../src/infrastructure/composition/__tests__/pull_request_use_case_composition_root.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) +- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`src/domain/bugbot/review_state.ts`](../src/domain/bugbot/review_state.ts) · [`src/domain/bugbot/review_projection.ts`](../src/domain/bugbot/review_projection.ts) · [`src/application/policies/bugbot_reconciliation_policy.ts`](../src/application/policies/bugbot_reconciliation_policy.ts) · [`src/application/policies/bugbot_event_ownership_policy.ts`](../src/application/policies/bugbot_event_ownership_policy.ts) · [`src/application/policies/bugbot_result_finding_state_projection_policy.ts`](../src/application/policies/bugbot_result_finding_state_projection_policy.ts) · [`src/application/policies/bugbot_telemetry_projection_policy.ts`](../src/application/policies/bugbot_telemetry_projection_policy.ts) · [`src/application/policies/bugbot_message_catalog.ts`](../src/application/policies/bugbot_message_catalog.ts) · [`src/application/policies/bugbot_finding_marker_policy.ts`](../src/application/policies/bugbot_finding_marker_policy.ts) · [`src/application/policies/bugbot_review_presentation_policy.ts`](../src/application/policies/bugbot_review_presentation_policy.ts) · [`src/application/policies/action_summary_policy.ts`](../src/application/policies/action_summary_policy.ts) · [`src/application/policies/copilot_evidence_policy.ts`](../src/application/policies/copilot_evidence_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`src/application/usecases/steps/commit/bugbot/load_bugbot_context_use_case.ts`](../src/application/usecases/steps/commit/bugbot/load_bugbot_context_use_case.ts) · [`src/application/usecases/steps/commit/bugbot/schema.ts`](../src/application/usecases/steps/commit/bugbot/schema.ts) · [`src/application/usecases/steps/commit/bugbot/prepare_bugbot_findings_policy.ts`](../src/application/usecases/steps/commit/bugbot/prepare_bugbot_findings_policy.ts) · [`src/application/usecases/steps/commit/bugbot/publish_pr_review_comments.ts`](../src/application/usecases/steps/commit/bugbot/publish_pr_review_comments.ts) · [`src/application/usecases/steps/commit/bugbot/synchronize_bugbot_review_presentation_use_case.ts`](../src/application/usecases/steps/commit/bugbot/synchronize_bugbot_review_presentation_use_case.ts) · [`src/application/policies/bugbot_status_count_marker_policy.ts`](../src/application/policies/bugbot_status_count_marker_policy.ts) · [`src/application/errors/bugbot_mutation_error.ts`](../src/application/errors/bugbot_mutation_error.ts) · [`src/data/repository/pull_request/pull_request_review_error_metadata.ts`](../src/data/repository/pull_request/pull_request_review_error_metadata.ts) +- Tests: [`src/domain/bugbot/__tests__/review_state.test.ts`](../src/domain/bugbot/__tests__/review_state.test.ts) · [`src/domain/bugbot/__tests__/review_projection.test.ts`](../src/domain/bugbot/__tests__/review_projection.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/schema.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/schema.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/prepare_bugbot_findings.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/prepare_bugbot_findings.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/synchronize_bugbot_review_presentation_use_case.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/synchronize_bugbot_review_presentation_use_case.test.ts) · [`src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_event_ownership_policy.test.ts`](../src/application/policies/__tests__/bugbot_event_ownership_policy.test.ts) · [`src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_message_catalog.test.ts`](../src/application/policies/__tests__/bugbot_message_catalog.test.ts) · [`src/application/policies/__tests__/bugbot_finding_marker_policy.test.ts`](../src/application/policies/__tests__/bugbot_finding_marker_policy.test.ts) · [`src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts`](../src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts) · [`src/application/policies/__tests__/action_summary_policy.test.ts`](../src/application/policies/__tests__/action_summary_policy.test.ts) · [`src/application/policies/__tests__/copilot_evidence_policy.test.ts`](../src/application/policies/__tests__/copilot_evidence_policy.test.ts) · [`src/application/policies/__tests__/lifecycle_state_policy.test.ts`](../src/application/policies/__tests__/lifecycle_state_policy.test.ts) · [`src/application/policies/__tests__/status_command_policy.test.ts`](../src/application/policies/__tests__/status_command_policy.test.ts) · [`src/actions/__tests__/github_action_completion.test.ts`](../src/actions/__tests__/github_action_completion.test.ts) · [`src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts`](../src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts) · [`src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts`](../src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts) · [`src/application/usecases/steps/commit/__tests__/detect_potential_problems_use_case.test.ts`](../src/application/usecases/steps/commit/__tests__/detect_potential_problems_use_case.test.ts) · [`src/infrastructure/composition/__tests__/pull_request_use_case_composition_root.test.ts`](../src/infrastructure/composition/__tests__/pull_request_use_case_composition_root.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) · [`src/application/errors/__tests__/bugbot_mutation_error.test.ts`](../src/application/errors/__tests__/bugbot_mutation_error.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/finding_mutation_recovery.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/finding_mutation_recovery.test.ts) - User documentation: [`docs/bugbot/detection.mdx`](../docs/bugbot/detection.mdx) · [`docs/bugbot/finding-publication.mdx`](../docs/bugbot/finding-publication.mdx) · [`docs/bugbot/quality-observability.mdx`](../docs/bugbot/quality-observability.mdx) · [`docs/bugbot/failure-scenarios.mdx`](../docs/bugbot/failure-scenarios.mdx) · [`docs/bugbot/configuration.mdx`](../docs/bugbot/configuration.mdx) · [`docs/bugbot/how-it-works.mdx`](../docs/bugbot/how-it-works.mdx) · [`docs/bugbot/programmatic-api.mdx`](../docs/bugbot/programmatic-api.mdx) · [`docs/pull-requests/workflow-setup.mdx`](../docs/pull-requests/workflow-setup.mdx) · [`docs/issues/comment-commands.mdx`](../docs/issues/comment-commands.mdx) ### `execution-lifecycle` — Execution admission, queueing, routing, and result publication diff --git a/specs/bugbot-review-state-reconciliation.md b/specs/bugbot-review-state-reconciliation.md index 4bd9be5bf..7c2d2aeb5 100644 --- a/specs/bugbot-review-state-reconciliation.md +++ b/specs/bugbot-review-state-reconciliation.md @@ -1601,3 +1601,72 @@ from one trusted bot-owned complete current-head card; it grants no approval or mutation authority. Marker/reader tests (24 cases) belong exclusively to the comment automation SDD budget. User documentation explains recheck recovery when evidence is absent or stale. + + +### Actionable finding mutation failures (2026-10-21, #646) + +Observed: a native review and inline comment could persist before resolution +failed; the adapter and application discarded the failed operation/HTTP facts, +leaving only `provider.unavailable`. The exact consumer API cause remains unknown. +This amendment MUST preserve incomplete evidence and completed effects while +retaining closed stage (`publication`/`resolution`), adapter operation, first +finding ID, affected batch count, optional HTTP status and safe provider request +reference. Batch diagnosis names its first finding and count, without falsely +claiming which individual item failed inside an atomic provider request. + +Only integer HTTP 400–599 and a 1–64-character alphanumeric/colon/hyphen request +reference are retained. Raw error prose, response bodies, URLs, request headers, +credentials and rejected provider content MUST NOT cross this diagnostic boundary. +Finding IDs use a bounded 200-character identifier alphabet; unavailable or unsafe +IDs are represented explicitly. Existing locally computed fingerprints remain +reconciliation authority; diagnostic IDs grant no mutation permission. + +```text +Publish native review -> attempt durable reconciliation -> failure retains effects +-> safe diagnostic plus independent coverage -> correct cause -> normal recheck +-> fresh provider read -> reuse native finding and retained dismissal +``` + +Text equivalent: partial success is retained and diagnosed; a recheck discovers +existing provider state before continuing, without duplicate review/thread creation +or reversal of a durable human dismissal. There is no new automatic retry or +rollback and no change to freshness, ownership, evidence or mutation ordering. + +The semantic error class MUST preserve authorization, not-found, conflict, +rate-limit, client-contract and transient-provider categories. Recovery details +in the owned status card remain localized with existing English/Spanish catalogs. +Example: “Finding mutation failed: stage=resolution; operation=resolve-thread; +finding=backend/Dockerfile:20:healthcheck-requires-curl; affected=1; http-503; +provider reference=AB12:34CD. Completed effects are retained.” Correct access and +contract failures before retrying; restore availability for transient failures, +then recheck the same PR. Existing pending, attention and successful cards remain. +No new comment stream, permission, configuration input or durable marker schema. +Absent metadata remains unavailable; no inference of a specific provider cause. + +Conversation truncation MUST remain independently partial. Coverage can attach +up to 50 bounded provider identities for retained truncated sources (`issue:` +or `review:`), never comment text or arbitrary links. The aggregate shows +these identities under Incomplete coverage, separately from Recovery details. +A failed mutation cannot turn partial coverage into complete, and a coverage +limitation cannot conceal the semantic mutation failure. Existing projection +precedence (partial coverage may yield a partial projection with failed Result) +is retained. Old coverage without identities remains compatible and unverified. + +Adapters own safe provider metadata; application errors own the credential-free +mutation diagnostic; publication/resolution use cases bind finding identity; +reconciliation and catalog presentation consume typed facts. Domain coverage +adds optional source identities only. Typecheck, architecture, localization and +fault-injection regressions enforce these boundaries; SDKs remain outside policy. + +The additional budget is **19 distinct cases**: eleven HTTP/classification/privacy +and error-preservation cases, two publication-stage identity/batch cases, one real +publication-to-failed-resolution-to-retry integration, two locale/projection and +independent-coverage cases, two exact-source/privacy cases and one adapter case. +Existing global coverage/quality thresholds and all prior state/replay tests +remain required. Acceptance proves a persisted native review survives a subsequent +503, one recheck produces no duplicate native review/thread, dismissal bytes are +retained, and diagnostics distinguish that error from truncated conversation. +Documentation: Bugbot failure scenarios. Upgrade the Action and recheck the same +PR after recovery; rollback only loses richer diagnostics. Definition of Done: +all package, documentation, catalog and existing architecture gates pass; no live +consumer recovery is claimed by deterministic fixtures. diff --git a/specs/catalog.json b/specs/catalog.json index d2a52a9bb..f70d81690 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -440,7 +440,7 @@ "status": "implemented", "scope": "Reconcile review snapshots, findings, threads, comments, and check conclusions", "owner": "Copilot maintainers", - "lastVerified": "2026-10-11", + "lastVerified": "2026-10-21", "specs": [ "specs/bugbot-review-state-reconciliation.md" ], @@ -476,7 +476,9 @@ "src/application/usecases/steps/commit/bugbot/prepare_bugbot_findings_policy.ts", "src/application/usecases/steps/commit/bugbot/publish_pr_review_comments.ts", "src/application/usecases/steps/commit/bugbot/synchronize_bugbot_review_presentation_use_case.ts", - "src/application/policies/bugbot_status_count_marker_policy.ts" + "src/application/policies/bugbot_status_count_marker_policy.ts", + "src/application/errors/bugbot_mutation_error.ts", + "src/data/repository/pull_request/pull_request_review_error_metadata.ts" ], "tests": [ "src/domain/bugbot/__tests__/review_state.test.ts", @@ -500,7 +502,9 @@ "src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts", "src/application/usecases/steps/commit/__tests__/detect_potential_problems_use_case.test.ts", "src/infrastructure/composition/__tests__/pull_request_use_case_composition_root.test.ts", - "src/tooling/__tests__/validate_workflow_contract.test.ts" + "src/tooling/__tests__/validate_workflow_contract.test.ts", + "src/application/errors/__tests__/bugbot_mutation_error.test.ts", + "src/application/usecases/steps/commit/bugbot/__tests__/finding_mutation_recovery.test.ts" ], "documentation": [ "docs/bugbot/detection.mdx", diff --git a/src/application/contracts/bugbot_reconciliation.ts b/src/application/contracts/bugbot_reconciliation.ts index 192ac3f24..3fd4a673c 100644 --- a/src/application/contracts/bugbot_reconciliation.ts +++ b/src/application/contracts/bugbot_reconciliation.ts @@ -1,3 +1,4 @@ +import type { BugbotMutationDiagnostic } from '../errors/bugbot_mutation_error'; import type { BugbotIssueComment } from '../ports/bugbot_issue_read_ports'; import type { BugbotReviewNavigation } from '../ports/bugbot_review_navigation_ports'; import type { @@ -60,6 +61,7 @@ export type BugbotReconciliationSnapshotResult = }; export type BugbotPresentationDiagnostic = + | { readonly code: 'finding-mutation-failed'; readonly mutation: BugbotMutationDiagnostic } | { readonly code: 'operation-failed'; readonly operatorMessage: string } | { readonly code: 'identity-unavailable' } | { readonly code: 'snapshot-pull-request-comments-failed' } diff --git a/src/application/errors/__tests__/bugbot_mutation_error.test.ts b/src/application/errors/__tests__/bugbot_mutation_error.test.ts new file mode 100644 index 000000000..a85091301 --- /dev/null +++ b/src/application/errors/__tests__/bugbot_mutation_error.test.ts @@ -0,0 +1,34 @@ +import { BugbotMutationError, bugbotMutationError } from '../bugbot_mutation_error'; +import { PullRequestReviewOperationError, toPullRequestReviewOperationError } from '../../ports/pull_request_review_errors'; + +it.each([ + [401, 'authorization.credential-invalid'], [403, 'authorization.denied'], [404, 'provider.not-found'], + [409, 'provider.conflict'], [422, 'provider.contract-invalid'], [429, 'provider.rate-limited'], + [503, 'provider.unavailable'], +])('preserves safe HTTP %s metadata and classifies recovery as %s', (status, code) => { + const cause = new PullRequestReviewOperationError('resolve-thread', { providerStatus: status, providerReference: 'AB12:34CD' }); + const error = bugbotMutationError(cause, 'resolution', ['backend/Dockerfile:20:healthcheck-requires-curl'], 'mark-resolved'); + expect(error).toMatchObject({ code, diagnostic: { stage: 'resolution', operation: 'resolve-thread', + providerStatus: `http-${status}`, providerReference: 'AB12:34CD' } }); + expect(JSON.stringify(error)).not.toMatch(/private-/); +}); + +it('drops malformed provider status/reference and unsafe finding markup', () => { + const cause = new PullRequestReviewOperationError('publish-comments', { providerStatus: 400.5, providerReference: '@team\nsecret' }); + const error = bugbotMutationError(cause, 'publication', ['@team + diff --git a/docs/configuration.mdx b/docs/configuration.mdx index f2490172c..1b19107ca 100644 --- a/docs/configuration.mdx +++ b/docs/configuration.mdx @@ -63,7 +63,7 @@ PR bot approval uses the versioned `pullRequestApproval` setup object and `PR_AP ## Branch Management - `issue-managed-branches`: Create and verify a linked branch after `in-progress` (default: "true") - - `verification-setup`: Run the trusted main-branch composite action before each configured verification command in generated GitHub Actions callbacks (default: "false"). See [repository-owned setup](/security-operations/operations/verification#repository-owned-setup). + - `verification-setup`: Run the trusted main-branch composite action before each configured verification command in generated GitHub Actions callbacks (default: "false"). Setup's terminal/web question maps `repository.verificationSetup` to `VERIFICATION_SETUP` using the existing storage/reuse precedence. Setup creates `.github/actions/copilot-verification-setup/action.yml` only if missing and preserves an existing action and its assets. Customize the failing starter and review it onto `MAIN_BRANCH` before enabling; generation and activation do not prove readiness. See [repository-owned setup](/security-operations/operations/verification#repository-owned-setup) and [upgrade/rollback](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository). - `pre-branch-sdd`: Require a validated SDD before implementation for eligible issues (default: "false") - `branch-management-emoji`: Emoji for branched issues (default: "🧑‍💻") diff --git a/docs/development/architecture.mdx b/docs/development/architecture.mdx index 63611b0c4..4f1071274 100644 --- a/docs/development/architecture.mdx +++ b/docs/development/architecture.mdx @@ -4,6 +4,18 @@ description: Clean Architecture boundaries for agent execution and workflow auto --- # Architecture +Verification setup onboarding uses the shared repository questionnaire and the +existing `repository.verificationSetup` boolean. The package supplies a native +composite starter under `setup/actions/`; the filesystem adapter inspects only +the fixed consumer path and creates it exclusively when absent. Existing action +contents and auxiliaries are outside generator overwrite and retirement ownership. +Installation review records create/preserve/blocked, activation and trusted main +as semantic facts shared by terminal, web and batch PR presentation. Batch Git +inventory permits the exact entrypoint and rejects unsafe parent/file modes or +case collisions before rendering. See [the onboarding +SDD](https://github.com/vypdev/copilot/blob/develop/specs/verification-setup-onboarding.md) +and the [verification guide](/security-operations/operations/verification#repository-owned-setup). + ### Setup runner profiles and installation parity `setup_runner_policy` owns pure registry validation, precedence, fixed job roles, diff --git a/docs/security-operations/operations/upgrade-rollback.mdx b/docs/security-operations/operations/upgrade-rollback.mdx index 1df6e15e9..0c39612a8 100644 --- a/docs/security-operations/operations/upgrade-rollback.mdx +++ b/docs/security-operations/operations/upgrade-rollback.mdx @@ -36,6 +36,85 @@ copilot --version Use `@latest` only when the latest published release is intentionally selected. Keep explicit versions for reproducible rollback procedures. +## Upgrade an existing Copilot repository + +Copilot has three separate versioned layers: + +| Layer | What changes it | What still needs review | +|---|---|---| +| Installed CLI | `copilot upgrade` or an explicit npm/pnpm package version | The CLI prepares local files; it does not rewrite committed workflows merely by upgrading | +| Remote Action reference | The Copilot `uses` references in committed workflows | `@v3` follows the published major tag; an exact version or commit SHA stays pinned until explicitly changed | +| Generated workflow files | An approved `copilot setup --update-workflows` run | New jobs, inputs and native continuation steps must be committed, reviewed and merged | + +Moving a tag does not add steps to an old YAML file. Upgrading the CLI does not +change the Action references in Git. A merge into `develop` is not a package or +Action release: first select a [published release](https://github.com/vypdev/copilot/releases) +that contains the required setup and native verification support. + +For verification setup adoption: + +1. Start with a clean branch, record the currently reviewed workflow references, + and keep `VERIFICATION_SETUP=false` during preparation. Inspect the effective + repository/organization value; a repository Variable overrides an inherited + organization value. +2. Upgrade the CLI and confirm `copilot --version`. Preview the installation: + + ```bash + copilot upgrade + copilot --version + copilot setup --web --dry-run + ``` + +3. Apply a reviewed workflow upgrade: + + ```bash + copilot setup --web --update-workflows + ``` + + The shared assistant also works in the terminal without `--web`. Keep the + verification setup question disabled for this preparation pass. Review the + displayed create/preserve result and changes before approval. The installer + creates `.github/actions/copilot-verification-setup/action.yml` only if absent; + existing action bytes and auxiliary files are preserved through upgrades. + Generated workflows use `vypdev/copilot@v3`. If your repository pins versions + or SHAs, review **every** Copilot `uses` reference, including native + continuation/post steps, and apply the same chosen compatible published ref. + Workflow backups are retained under `.copilot/setup-backups/`. +4. Replace the starter's failing placeholder with reviewed project-specific + dependency preparation. Commit the action, its auxiliary files and the updated + workflows. Review and merge them onto the configured trusted `MAIN_BRANCH`; + the installer PR's default target may differ from this trusted branch. Follow + the repository's branch/promotion process until both contain the reviewed + changes. Creating or merging an installer PR alone does not verify the runtime. +5. Re-run the assistant and enable **Prepare dependencies with the repository + verification setup action?**, or use: + + ```yaml + repository: + verificationSetup: true + ``` + + Setup writes `VERIFICATION_SETUP` only when Variable management is enabled + and follows the reviewed storage/reuse policy. With `--skip-variables`, update + the effective Variable manually. Confirm that generated workflows pass the + `verification-setup` input and that the trusted action has been customized. + Choose **Customize** when changing an existing repository Variable; **Reuse** + keeps existing values. If an organization value must differ for this project, + select `VERIFICATION_SETUP` in the repository Variable overrides and review the + scope before Apply. +6. Run `copilot doctor --read-only`, then an authorized write/sync operation that + actually executes the configured verification commands. Inspect the native + action and verifier results; a doctor pass, dry run or already-aligned sync + does not prove dependency preparation. + +To roll back adoption, first set the effective `VERIFICATION_SETUP=false` (or +answer No with Variable management enabled). This stops the optional hook and +retains the existing verification commands. Restore the previous reviewed +workflow files and Action refs together if necessary, and install the prior CLI +version explicitly. Consumer action files are retained; restore any owner changes +through Git review instead of asking setup to overwrite or delete them. Inspect +partial setup receipts and GitHub resources before retrying a failed upgrade. + ## Rollback 1. Restore the last known-good version variable. diff --git a/docs/security-operations/operations/verification.mdx b/docs/security-operations/operations/verification.mdx index baadf536a..4235f05d9 100644 --- a/docs/security-operations/operations/verification.mdx +++ b/docs/security-operations/operations/verification.mdx @@ -135,15 +135,52 @@ flowchart LR Text equivalent: prepare the candidate, install its dependencies, verify it, then apply the existing publication guards. A separate CI job does not prepare this job. -1. Review `.github/actions/copilot-verification-setup/action.yml` and its auxiliary - scripts onto your configured `main-branch` (normally production). Candidate or - model changes cannot activate a different setup implementation. -2. Update the generated comment workflows with `copilot setup`. They contain the - native setup and continuation steps; an older callback cannot execute YAML. -3. Enable Repository Variable `VERIFICATION_SETUP=true`, or plan it with setup - configuration `repository: { verificationSetup: true }`. The corresponding - boolean Action input is `verification-setup`; its default is `false`. -4. Retry the authorized modification or `/copilot sync-branch --no-agent`. +1. Run `copilot setup` or `copilot setup --web` with a published CLI version that + includes this onboarding support. The plan shows **Create the starter only if + missing** or **Preserve the existing project action** at + `.github/actions/copilot-verification-setup/action.yml`, plus the activation + state and configured trusted main branch. Setup creates this file even when + activation is disabled. It never overwrites an existing regular action, + changes its auxiliary files or retires it when you disable the option. +2. Leave **Prepare dependencies with the repository verification setup action?** + disabled while preparing the action. The generated native composite contains + a failing placeholder with customization instructions. Replace that step with + your project's reviewed runtime and dependency setup; no language, version or + install command is inferred, and setup does not execute the action. +3. Update the generated comment workflows with `copilot setup --update-workflows` + and review the complete diff. They need the native setup and continuation + steps; an older callback cannot execute YAML. Review the action, auxiliary + scripts and workflows onto the configured `main-branch` (`MAIN_BRANCH`, normally + production). Candidate or model changes cannot replace the trusted action. +4. Enable the same question in the terminal/web assistant, or set non-secret + configuration `repository: { verificationSetup: true }`. With Variable + management enabled, setup plans `VERIFICATION_SETUP=true` using the selected + storage/reuse policy. Existing configured values are shown; the default is + `false`. If Variable management is skipped, set the effective GitHub Actions + Variable yourself. The corresponding boolean Action input is + `verification-setup`. + Choose **Customize** to change an existing repository Variable; **Reuse** + retains existing effective values. To override an inherited organization value + just for this repository, select `VERIFICATION_SETUP` under repository Variable + overrides and review its scope. +5. Retry an authorized modification or `/copilot sync-branch --no-agent` that + actually needs configured verification. Inspect the native setup and verifier + results. A dry run, no-op sync, read-only doctor result, generated file or + installer PR does not establish runtime readiness. + +The starter deliberately fails until customized. Enabling the flag before the +reviewed action is available on trusted main blocks verification and publication; +it does not bypass the placeholder. Batch setup uses the same create/preserve +rule and includes a missing starter in its installation PR. An existing action +stays outside generator ownership and out of the update diff. Unsafe parent +links, non-regular action paths and collisions block setup; inspect the path and +review a fresh plan. If a file appears after review, setup preserves it and stops +the stale creation. Dry-run, cancellation and declined approval create no starter. + +For an existing installation, follow the [three-layer upgrade and rollback +procedure](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository). +This repository's `setup_platform_smoke.yml` is internal CI and is not installed +in consumer projects. Copilot captures the complete action directory from an immutable trusted Git SHA before candidate changes. The trusted origin ref must be available locally; diff --git a/docs/setup-web.mdx b/docs/setup-web.mdx index b3a421d61..36e7a02c1 100644 --- a/docs/setup-web.mdx +++ b/docs/setup-web.mdx @@ -53,6 +53,18 @@ Choose **This repository** for your first installation. A new checkout offers ** Choose **Basic guided setup** unless you need every advanced setting. Basic still asks for permission, branch, runner, Project, approval and storage decisions. **Customize every setting** exposes the advanced configuration. Use **Previous question** or the plan's **Change** controls to revise answers without losing the others. +Both modes ask **Prepare dependencies with the repository verification setup +action?** The default is disabled; configured and reused values remain visible. +The plan shows whether `.github/actions/copilot-verification-setup/action.yml` +will be created or preserved, the activation state and the configured trusted main +branch. Apply creates a failing starter only when missing and preserves existing +project actions and auxiliary files. Customize and review the action on +`MAIN_BRANCH` before enabling `VERIFICATION_SETUP`, then exercise a real verifier. +No dependency installation runs during setup. Follow the [upgrade and rollback +guide](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository) +for an existing installation; creating an installer PR does not establish runtime +readiness. + The six milestones are: ```text diff --git a/docs/single-actions/workflow-and-cli.mdx b/docs/single-actions/workflow-and-cli.mdx index 84dcb6c27..846da64ae 100644 --- a/docs/single-actions/workflow-and-cli.mdx +++ b/docs/single-actions/workflow-and-cli.mdx @@ -217,6 +217,16 @@ copilot setup Run it from the target repository root. Existing setup files are not overwritten unless you approve the update prompt or pass `--update-workflows`. The interactive flow installs the selected workflows/templates, asks for agent routing and operational settings, inspects the repository's effective Actions resources, and asks separately where Secrets and Variables should live. Organization scope requires an organization-owned repository and the corresponding organization permissions on the setup PAT. Existing repository resources take precedence over organization resources; setup preserves an inherited organization resource unless you explicitly request a repository override. +Setup also creates `.github/actions/copilot-verification-setup/action.yml` only +if missing. This project-owned action and its auxiliaries are preserved even +with `--update-workflows`; they are never retired on deselection. The shared +terminal/web repository question controls the existing boolean +`repository.verificationSetup` / `VERIFICATION_SETUP`, disabled by default. +Customize the generated failing placeholder and review it on configured +`MAIN_BRANCH` before activation. Preview/cancel/decline creates no starter; +setup does not infer or install dependencies. See the [ordered upgrade +procedure](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository). + The questionnaire is forward-only and immutable. Its stable stages are capabilities, issue workflow multi-select, agent runtime, model defaults, optional role overrides, repository, deployment, Bugbot, optional Projects, provisioning, storage, review, and confirmation. The issue workflow selector uses the usual `Space` to toggle and `Enter` to confirm; `All` is selected by default. `Ctrl-C` or end-of-input closes the prompt once, exits 130, and writes nothing. Declining the final plan exits 0 and also writes nothing; rerun setup or edit the config file to change earlier answers. The wizard covers these features: `issues`, `pullRequests`, `commits`, `issueComments`, `pullRequestComments`, `release`, `hotfix`, `agentProvisioning`, `credentialHealth`, `inactiveIssueClosure`, `issueTemplates`, and `pullRequestTemplate`. It also asks whether to generate repository agent guidance; this is enabled by default. The agent tasks are `planner`, `findings`, `reviewer`, `fixer`, and `tester`; each can use any of the three supported runtimes independently. Model provider, model, effort, branch strategy, locales, AI ignore patterns, project columns, Bugbot policy, and initial-tag creation are also configurable. Cursor is available as an experimental runtime and is called out in the review plan with its extra credential/checksum requirements. diff --git a/package.json b/package.json index b52c34bf5..4a13b15e2 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "build/api/index.js", "build/api/src/", "setup/ISSUE_TEMPLATE/", + "setup/actions/", "setup/workflows/", "setup/source-workflows/", "setup/pull_request_template.md", diff --git a/scripts/coverage-budgets.json b/scripts/coverage-budgets.json index 784bc5834..9f0033c4c 100644 --- a/scripts/coverage-budgets.json +++ b/scripts/coverage-budgets.json @@ -931,6 +931,27 @@ } ], "successMessage": "verification setup coverage: PASS (95% lines/statements, 90% branches/functions)" + }, + { + "name": "Verification setup onboarding", + "missingEntryLabel": "verification setup onboarding", + "rules": [ + { + "files": [ + "src/application/policies/setup_verification_action_summary_policy.ts" + ], + "mode": "each", + "thresholdProfile": "exhaustive" + }, + { + "files": [ + "src/infrastructure/setup_verification_action.ts" + ], + "mode": "each", + "thresholdProfile": "default" + } + ], + "successMessage": "verification setup onboarding coverage: PASS (summary decisions 100%; safe file adapter 95% lines/statements, 90% branches/functions)" } ] } diff --git a/scripts/smoke-test-npm-package.cjs b/scripts/smoke-test-npm-package.cjs index a411d8920..496bac85f 100644 --- a/scripts/smoke-test-npm-package.cjs +++ b/scripts/smoke-test-npm-package.cjs @@ -45,6 +45,11 @@ try { const help = execFileSync(process.execPath, [cliPath, '--help'], { encoding: 'utf8' }); const bugbotApi = require(bugbotApiPath); const cliBundle = fs.readFileSync(cliPath, 'utf8'); + const verificationStarter = fs.readFileSync(path.join(packageRoot, 'setup/actions/copilot-verification-setup/action.yml'), 'utf8'); + if (!verificationStarter.includes('using: composite') || !verificationStarter.includes('exit 1') + || !verificationStarter.includes('MAIN_BRANCH') || !cliBundle.includes('setup/actions/copilot-verification-setup/action.yml')) { + throw new Error('Packaged setup must resolve the fail-closed consumer verification starter.'); + } for (const runtime of ['github_action', 'api']) { const bundle = fs.readFileSync(path.join(packageRoot, 'build', runtime, 'index.js'), 'utf8'); if (bundle.includes('Local setup web assets are incomplete') || bundle.includes('Control moved to another tab.')) { diff --git a/scripts/validate-npm-package.cjs b/scripts/validate-npm-package.cjs index 5ec818f86..ca5c35c79 100644 --- a/scripts/validate-npm-package.cjs +++ b/scripts/validate-npm-package.cjs @@ -39,6 +39,7 @@ const requiredPackageFiles = [ 'build/api/index.js', 'build/api/src/', 'setup/ISSUE_TEMPLATE/', + 'setup/actions/', 'setup/workflows/', 'setup/pull_request_template.md', 'scripts/install-git-hooks.cjs', @@ -58,6 +59,7 @@ const requiredRepositoryFiles = [ 'build/api/index.js', 'build/api/src/api.d.ts', 'setup/workflows/copilot_issue.yml', + 'setup/actions/copilot-verification-setup/action.yml', 'setup/ISSUE_TEMPLATE/config.yml', 'setup/ISSUE_TEMPLATE/feature_request.yml', 'setup/ISSUE_TEMPLATE/bug_report.yml', diff --git a/scripts/web-setup-runner-review-fixtures.cjs b/scripts/web-setup-runner-review-fixtures.cjs index 2c118c247..8b9575a12 100644 --- a/scripts/web-setup-runner-review-fixtures.cjs +++ b/scripts/web-setup-runner-review-fixtures.cjs @@ -62,6 +62,7 @@ const runnerDiscoveryPresentation = { }; /** Credential-free presentation evidence; no provider or mutation adapters. */ const installationReview = { + verificationSetup: { action: 'create', enabled: false, mainBranch: 'main' }, blockers: [], jobs: [ { file: 'copilot_issue.yml', job: 'copilot-issues', role: 'agent', runsOn: { group: 'vypdev', labels: ['self-hosted', 'codex', 'Linux'] }, status: 'pending-capacity', retained: false }, diff --git a/setup/actions/copilot-verification-setup/action.yml b/setup/actions/copilot-verification-setup/action.yml new file mode 100644 index 000000000..354055158 --- /dev/null +++ b/setup/actions/copilot-verification-setup/action.yml @@ -0,0 +1,13 @@ +# Created once by Copilot setup. This action and its assets belong to your project. +# Replace the placeholder with reviewed runtime/dependency setup, then merge onto MAIN_BRANCH. +name: Prepare project verification +description: Configure project dependencies before enabling VERIFICATION_SETUP. +runs: + using: composite + steps: + - name: Configure project verification dependencies + shell: bash + run: | + printf '%s\n' 'Configure .github/actions/copilot-verification-setup/action.yml with your project dependencies before enabling VERIFICATION_SETUP.' + printf '%s\n' 'Replace this failing placeholder, review and merge it onto the configured MAIN_BRANCH, then run a real verification.' + exit 1 diff --git a/specs/CATALOG.md b/specs/CATALOG.md index a128c7b0d..5f0c75c44 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -17,7 +17,7 @@ debt or convert unknown historic intent into a design decision. | `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 104 paths · 2026-10-21 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | | `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 5 companion | 328 paths · 2026-10-20 | -| `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 2 companion | 238 paths · 2026-10-21 | +| `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 2 companion | 247 paths · 2026-10-21 | | `guided-bot-pat-onboarding` | Proposed | Guide creation of the persistent workflow PAT, verify bot identity and grants, recover explicitly from wrong-account input within the session, and install the approved Actions Secret | [Guided bot PAT onboarding](./guided-bot-pat-onboarding.md) | 39 paths · 2026-10-07 | | `temporary-setup-operator-authorization` | Proposed | Guide creation of the one-run operator PAT through GitHub's official form, verify final setup access, and report user-owned deletion accurately | [Assisted setup PAT creation](./temporary-setup-operator-authorization.md) | 36 paths · 2026-10-18 | | `issue-start-and-sdd-readiness` | Implemented | Start every admitted issue with one explicit signal and publish a validated SDD before eligible Action-managed branch work; inspect verified SDD status and bounded structural publication comparisons | [Uniform issue start and pre-branch SDD readiness](./issue-start-and-branch-readiness.md) + 3 companion | 117 paths · 2026-10-21 | @@ -118,9 +118,9 @@ debt or convert unknown historic intent into a design decision. - Specifications: [`specs/local-web-setup-assistant.md`](./local-web-setup-assistant.md) · [`specs/setup-configuration-management.md`](./setup-configuration-management.md) · [`specs/verification-setup-onboarding.md`](./verification-setup-onboarding.md) - Workflows: [`.github/workflows/ci_check.yml`](../.github/workflows/ci_check.yml) · [`.github/workflows/repowise.yml`](../.github/workflows/repowise.yml) · [`.github/workflows/setup_platform_smoke.yml`](../.github/workflows/setup_platform_smoke.yml) · [`.github/workflows/copilot_pull_request_approval.yml`](../.github/workflows/copilot_pull_request_approval.yml) - Entrypoints: [`src/cli/commands/setup.ts`](../src/cli/commands/setup.ts) · [`package.json`](../package.json) · [`web/src/main.ts`](../web/src/main.ts) -- Core code: [`web/src/App.svelte`](../web/src/App.svelte) · [`web/src/session/setupSession.ts`](../web/src/session/setupSession.ts) · [`web/src/components/ActionButton.svelte`](../web/src/components/ActionButton.svelte) · [`web/src/components/PairingPanel.svelte`](../web/src/components/PairingPanel.svelte) · [`web/src/lib/pairingCode.ts`](../web/src/lib/pairingCode.ts) · [`web/src/components/ContextPanel.svelte`](../web/src/components/ContextPanel.svelte) · [`web/src/i18n/permissionEvidence.ts`](../web/src/i18n/permissionEvidence.ts) · [`web/src/i18n/permissionProgress.ts`](../web/src/i18n/permissionProgress.ts) · [`web/src/components/PermissionProgressPanel.svelte`](../web/src/components/PermissionProgressPanel.svelte) · [`web/src/components/PromptCard.svelte`](../web/src/components/PromptCard.svelte) · [`web/src/components/ResultPanel.svelte`](../web/src/components/ResultPanel.svelte) · [`web/src/components/SetupPatCorrectionPanel.svelte`](../web/src/components/SetupPatCorrectionPanel.svelte) · [`web/src/components/ResourceProgress.svelte`](../web/src/components/ResourceProgress.svelte) · [`web/src/components/PlanPrompt.svelte`](../web/src/components/PlanPrompt.svelte) · [`web/src/components/PlanDecisionSummary.svelte`](../web/src/components/PlanDecisionSummary.svelte) · [`web/src/components/QuestionPrompt.svelte`](../web/src/components/QuestionPrompt.svelte) · [`web/src/components/FixedWorkflowNotice.svelte`](../web/src/components/FixedWorkflowNotice.svelte) · [`web/src/components/QuestionGuidance.svelte`](../web/src/components/QuestionGuidance.svelte) · [`web/src/components/DiscoveryNotice.svelte`](../web/src/components/DiscoveryNotice.svelte) · [`web/src/components/ProducerSelector.svelte`](../web/src/components/ProducerSelector.svelte) · [`web/src/lib/manualProducerIdentity.ts`](../web/src/lib/manualProducerIdentity.ts) · [`web/src/components/CoverageCheckEvidence.svelte`](../web/src/components/CoverageCheckEvidence.svelte) · [`web/src/components/ProjectSelector.svelte`](../web/src/components/ProjectSelector.svelte) · [`web/src/i18n/catalog.ts`](../web/src/i18n/catalog.ts) · [`web/src/i18n/projectTransitions.ts`](../web/src/i18n/projectTransitions.ts) · [`web/src/i18n/permissionTerms.ts`](../web/src/i18n/permissionTerms.ts) · [`web/src/components/StatusBanner.svelte`](../web/src/components/StatusBanner.svelte) · [`web/src/lib/questionAnswer.ts`](../web/src/lib/questionAnswer.ts) · [`web/src/lib/githubLink.ts`](../web/src/lib/githubLink.ts) · [`web/src/lib/focusOnRevision.ts`](../web/src/lib/focusOnRevision.ts) · [`web/src/i18n/featureNames.ts`](../web/src/i18n/featureNames.ts) · [`web/src/i18n/agentRoleNames.ts`](../web/src/i18n/agentRoleNames.ts) · [`web/src/i18n/checkEvidence.ts`](../web/src/i18n/checkEvidence.ts) · [`web/src/styles/controls.css`](../web/src/styles/controls.css) · [`web/src/styles/tokens.css`](../web/src/styles/tokens.css) · [`web/src/style.css`](../web/src/style.css) · [`src/application/contracts/web_setup_view.ts`](../src/application/contracts/web_setup_view.ts) · [`src/application/ports/setup_terminal_ports.ts`](../src/application/ports/setup_terminal_ports.ts) · [`src/application/errors/setup_interaction_cancelled_error.ts`](../src/application/errors/setup_interaction_cancelled_error.ts) · [`src/application/policies/merge_setup_overrides_policy.ts`](../src/application/policies/merge_setup_overrides_policy.ts) · [`src/application/policies/setup_remote_facts_policy.ts`](../src/application/policies/setup_remote_facts_policy.ts) · [`src/application/usecases/setup/prepare_setup_pat_intent_use_case.ts`](../src/application/usecases/setup/prepare_setup_pat_intent_use_case.ts) · [`src/application/usecases/setup/audit_configured_setup_pat_use_case.ts`](../src/application/usecases/setup/audit_configured_setup_pat_use_case.ts) · [`src/infrastructure/setup_permission_actions_probe.ts`](../src/infrastructure/setup_permission_actions_probe.ts) · [`src/infrastructure/setup_permission_issue_probe.ts`](../src/infrastructure/setup_permission_issue_probe.ts) · [`src/infrastructure/setup_permission_issue_cleanup.ts`](../src/infrastructure/setup_permission_issue_cleanup.ts) · [`src/infrastructure/setup_permission_probe_journal.ts`](../src/infrastructure/setup_permission_probe_journal.ts) · [`src/infrastructure/setup_permission_probe_transaction.ts`](../src/infrastructure/setup_permission_probe_transaction.ts) · [`src/infrastructure/setup_permission_resource_probes.ts`](../src/infrastructure/setup_permission_resource_probes.ts) · [`src/application/usecases/setup/verify_web_setup_apply_use_case.ts`](../src/application/usecases/setup/verify_web_setup_apply_use_case.ts) · [`src/application/usecases/setup/setup_session_coordinator.ts`](../src/application/usecases/setup/setup_session_coordinator.ts) · [`src/application/usecases/setup/verify_setup_pat_bootstrap_use_case.ts`](../src/application/usecases/setup/verify_setup_pat_bootstrap_use_case.ts) · [`src/cli_context.ts`](../src/cli_context.ts) · [`src/cli/setup_command_options.ts`](../src/cli/setup_command_options.ts) · [`src/cli/commands/setup_execution.ts`](../src/cli/commands/setup_execution.ts) · [`src/cli/setup_credential_collection.ts`](../src/cli/setup_credential_collection.ts) · [`src/cli/setup_pat_intent_adapter.ts`](../src/cli/setup_pat_intent_adapter.ts) · [`src/cli/setup_apply_authorization.ts`](../src/cli/setup_apply_authorization.ts) · [`src/cli/setup_outcome_adapter.ts`](../src/cli/setup_outcome_adapter.ts) · [`src/cli/web_setup_bridge.ts`](../src/cli/web_setup_bridge.ts) · [`src/cli/web_setup_adapters.ts`](../src/cli/web_setup_adapters.ts) · [`src/cli/web_setup_server.ts`](../src/cli/web_setup_server.ts) · [`src/cli/setup_apply_snapshot.ts`](../src/cli/setup_apply_snapshot.ts) · [`src/cli/setup_result_receipt.ts`](../src/cli/setup_result_receipt.ts) · [`src/application/usecases/actions/initial_setup_workflow.ts`](../src/application/usecases/actions/initial_setup_workflow.ts) · [`src/actions/local_action.ts`](../src/actions/local_action.ts) · [`src/cli/setup_session_guard.ts`](../src/cli/setup_session_guard.ts) · [`src/application/usecases/setup/setup_wizard_use_case.ts`](../src/application/usecases/setup/setup_wizard_use_case.ts) · [`src/application/usecases/setup/setup_questionnaire_controller.ts`](../src/application/usecases/setup/setup_questionnaire_controller.ts) · [`src/application/policies/setup_terminal_choice_policy.ts`](../src/application/policies/setup_terminal_choice_policy.ts) · [`src/cli/setup_terminal_driver.ts`](../src/cli/setup_terminal_driver.ts) · [`src/cli/setup_question_renderer.ts`](../src/cli/setup_question_renderer.ts) · [`src/application/usecases/setup/setup_journey_use_case.ts`](../src/application/usecases/setup/setup_journey_use_case.ts) · [`src/application/usecases/setup/setup_credentials_use_case.ts`](../src/application/usecases/setup/setup_credentials_use_case.ts) · [`src/application/policies/setup_questionnaire_policy.ts`](../src/application/policies/setup_questionnaire_policy.ts) · [`src/application/policies/setup_project_selection_policy.ts`](../src/application/policies/setup_project_selection_policy.ts) · [`src/application/ports/setup_project_discovery_port.ts`](../src/application/ports/setup_project_discovery_port.ts) · [`src/application/ports/setup_approval_check_discovery_port.ts`](../src/application/ports/setup_approval_check_discovery_port.ts) · [`src/infrastructure/github_setup_project_discovery_adapter.ts`](../src/infrastructure/github_setup_project_discovery_adapter.ts) · [`src/infrastructure/github_setup_approval_check_discovery_adapter.ts`](../src/infrastructure/github_setup_approval_check_discovery_adapter.ts) · [`src/application/policies/setup_question_documentation_policy.ts`](../src/application/policies/setup_question_documentation_policy.ts) · [`src/application/policies/setup_question_guidance_policy.ts`](../src/application/policies/setup_question_guidance_policy.ts) · [`src/application/policies/setup_question_purpose_policy.ts`](../src/application/policies/setup_question_purpose_policy.ts) · [`src/application/policies/setup_token_permission_policy.ts`](../src/application/policies/setup_token_permission_policy.ts) · [`src/application/policies/setup_configuration_plan.ts`](../src/application/policies/setup_configuration_plan.ts) · [`src/application/policies/setup_pat_creation_url_policy.ts`](../src/application/policies/setup_pat_creation_url_policy.ts) · [`src/infrastructure/composition/setup_credentials_composition_root.ts`](../src/infrastructure/composition/setup_credentials_composition_root.ts) · [`scripts/validate-npm-package.cjs`](../scripts/validate-npm-package.cjs) · [`scripts/smoke-test-npm-package.cjs`](../scripts/smoke-test-npm-package.cjs) · [`scripts/smoke-packaged-web-session.cjs`](../scripts/smoke-packaged-web-session.cjs) · [`scripts/validate-setup-assistant-acceptance.cjs`](../scripts/validate-setup-assistant-acceptance.cjs) · [`scripts/serve-web-setup-review.cjs`](../scripts/serve-web-setup-review.cjs) · [`scripts/validate-workflow-contract.cjs`](../scripts/validate-workflow-contract.cjs) · [`scripts/documentation_checkout_text.cjs`](../scripts/documentation_checkout_text.cjs) · [`scripts/set-cli-executable.cjs`](../scripts/set-cli-executable.cjs) · [`scripts/render-web-setup-component.cjs`](../scripts/render-web-setup-component.cjs) · [`web/src/i18n/permissionPrerequisite.ts`](../web/src/i18n/permissionPrerequisite.ts) · [`scripts/web-setup-review-views.cjs`](../scripts/web-setup-review-views.cjs) · [`src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts`](../src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts) · [`src/cli/setup_workflow_pat_storage_copy.ts`](../src/cli/setup_workflow_pat_storage_copy.ts) · [`web/src/components/WorkflowPatStorageNotice.svelte`](../web/src/components/WorkflowPatStorageNotice.svelte) · [`src/cli/commands/setup_policy.ts`](../src/cli/commands/setup_policy.ts) · [`src/application/usecases/execution/execution_issue_number_policy.ts`](../src/application/usecases/execution/execution_issue_number_policy.ts) · [`src/application/usecases/execution/setup_execution_workflow.ts`](../src/application/usecases/execution/setup_execution_workflow.ts) · [`src/domain/setup_management.ts`](../src/domain/setup_management.ts) · [`src/application/contracts/setup_management_view.ts`](../src/application/contracts/setup_management_view.ts) · [`src/application/ports/setup_management_ports.ts`](../src/application/ports/setup_management_ports.ts) · [`src/application/policies/setup_quick_settings_policy.ts`](../src/application/policies/setup_quick_settings_policy.ts) · [`src/application/policies/setup_management_policy.ts`](../src/application/policies/setup_management_policy.ts) · [`src/application/policies/setup_management_permissions_policy.ts`](../src/application/policies/setup_management_permissions_policy.ts) · [`src/application/usecases/setup/manage_setup_use_case.ts`](../src/application/usecases/setup/manage_setup_use_case.ts) · [`src/infrastructure/setup_management_workspace_adapter.ts`](../src/infrastructure/setup_management_workspace_adapter.ts) · [`src/cli/setup_management_adapter.ts`](../src/cli/setup_management_adapter.ts) · [`web/src/components/SetupManagementPanel.svelte`](../web/src/components/SetupManagementPanel.svelte) · [`web/src/components/ManagementInventory.svelte`](../web/src/components/ManagementInventory.svelte) · [`web/src/components/QuickSettingPrompt.svelte`](../web/src/components/QuickSettingPrompt.svelte) · [`web/src/i18n/managementCopy.ts`](../web/src/i18n/managementCopy.ts) · [`web/src/styles/management.css`](../web/src/styles/management.css) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`web/src/session/setupCommandTransport.ts`](../web/src/session/setupCommandTransport.ts) · [`scripts/serve-web-setup-journey.cjs`](../scripts/serve-web-setup-journey.cjs) · [`web/src/components/SetupHeader.svelte`](../web/src/components/SetupHeader.svelte) · [`web/src/components/WaitingPanel.svelte`](../web/src/components/WaitingPanel.svelte) · [`web/src/styles/layout.css`](../web/src/styles/layout.css) · [`web/src/i18n/en.ts`](../web/src/i18n/en.ts) · [`web/src/i18n/es.ts`](../web/src/i18n/es.ts) · [`web/src/i18n/fr.ts`](../web/src/i18n/fr.ts) · [`web/src/i18n/pt.ts`](../web/src/i18n/pt.ts) · [`web/src/i18n/sessionErrors.ts`](../web/src/i18n/sessionErrors.ts) · [`web/src/i18n/errors/en.ts`](../web/src/i18n/errors/en.ts) · [`web/src/i18n/errors/es.ts`](../web/src/i18n/errors/es.ts) · [`web/src/i18n/errors/fr.ts`](../web/src/i18n/errors/fr.ts) · [`web/src/i18n/errors/pt.ts`](../web/src/i18n/errors/pt.ts) · [`web/src/components/SetupSidebar.svelte`](../web/src/components/SetupSidebar.svelte) · [`web/src/components/RepositorySelector.svelte`](../web/src/components/RepositorySelector.svelte) · [`web/src/components/BatchSetupPanel.svelte`](../web/src/components/BatchSetupPanel.svelte) · [`web/src/components/BatchSafetyBanner.svelte`](../web/src/components/BatchSafetyBanner.svelte) · [`web/src/components/InstallationReview.svelte`](../web/src/components/InstallationReview.svelte) · [`web/src/components/RunnerQuestionDetails.svelte`](../web/src/components/RunnerQuestionDetails.svelte) · [`web/src/i18n/runnerCopy.ts`](../web/src/i18n/runnerCopy.ts) · [`scripts/web-setup-runner-review-fixtures.cjs`](../scripts/web-setup-runner-review-fixtures.cjs) · [`src/application/contracts/setup_documentation.ts`](../src/application/contracts/setup_documentation.ts) · [`src/cli/setup_journey_presenter.ts`](../src/cli/setup_journey_presenter.ts) · [`web/src/components/SetupHelp.svelte`](../web/src/components/SetupHelp.svelte) · [`web/src/components/CompletedSetupHelp.svelte`](../web/src/components/CompletedSetupHelp.svelte) -- Tests: [`src/__tests__/cli.test.ts`](../src/__tests__/cli.test.ts) · [`src/__tests__/cli_context_branch.test.ts`](../src/__tests__/cli_context_branch.test.ts) · [`src/__tests__/cli_context_root.test.ts`](../src/__tests__/cli_context_root.test.ts) · [`src/cli/__tests__/web_setup_bridge.test.ts`](../src/cli/__tests__/web_setup_bridge.test.ts) · [`src/cli/__tests__/web_setup_adapters.test.ts`](../src/cli/__tests__/web_setup_adapters.test.ts) · [`src/cli/__tests__/web_setup_palette.test.ts`](../src/cli/__tests__/web_setup_palette.test.ts) · [`src/cli/__tests__/web_setup_ui_helpers.test.ts`](../src/cli/__tests__/web_setup_ui_helpers.test.ts) · [`src/cli/__tests__/web_setup_browser_session.test.ts`](../src/cli/__tests__/web_setup_browser_session.test.ts) · [`src/cli/__tests__/web_setup_server.test.ts`](../src/cli/__tests__/web_setup_server.test.ts) · [`src/cli/__tests__/web_setup_browser_open.test.ts`](../src/cli/__tests__/web_setup_browser_open.test.ts) · [`src/cli/__tests__/setup_apply_snapshot.test.ts`](../src/cli/__tests__/setup_apply_snapshot.test.ts) · [`src/cli/__tests__/setup_result_receipt.test.ts`](../src/cli/__tests__/setup_result_receipt.test.ts) · [`src/cli/__tests__/setup_session_guard.test.ts`](../src/cli/__tests__/setup_session_guard.test.ts) · [`src/cli/__tests__/setup_command_options.test.ts`](../src/cli/__tests__/setup_command_options.test.ts) · [`src/cli/__tests__/web_setup_components.test.ts`](../src/cli/__tests__/web_setup_components.test.ts) · [`src/cli/__tests__/setup_terminal_driver.test.ts`](../src/cli/__tests__/setup_terminal_driver.test.ts) · [`src/cli/__tests__/setup_terminal_driver_stream_integration.test.ts`](../src/cli/__tests__/setup_terminal_driver_stream_integration.test.ts) · [`src/cli/__tests__/setup_presenters.test.ts`](../src/cli/__tests__/setup_presenters.test.ts) · [`src/cli/__tests__/web_setup_catalog.test.ts`](../src/cli/__tests__/web_setup_catalog.test.ts) · [`src/architecture/__tests__/web_setup_boundaries.test.ts`](../src/architecture/__tests__/web_setup_boundaries.test.ts) · [`src/application/usecases/setup/__tests__/prepare_setup_pat_intent_use_case.test.ts`](../src/application/usecases/setup/__tests__/prepare_setup_pat_intent_use_case.test.ts) · [`src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts`](../src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts) · [`src/infrastructure/__tests__/setup_permission_resource_probes.test.ts`](../src/infrastructure/__tests__/setup_permission_resource_probes.test.ts) · [`src/application/usecases/setup/__tests__/verify_web_setup_apply_use_case.test.ts`](../src/application/usecases/setup/__tests__/verify_web_setup_apply_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts`](../src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts) · [`src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts`](../src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts) · [`src/actions/__tests__/local_action.test.ts`](../src/actions/__tests__/local_action.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) · [`src/domain/__tests__/setup_approval_workflow.test.ts`](../src/domain/__tests__/setup_approval_workflow.test.ts) · [`src/tooling/__tests__/documentation_checkout_text.test.ts`](../src/tooling/__tests__/documentation_checkout_text.test.ts) · [`src/application/policies/__tests__/setup_remote_facts_policy.test.ts`](../src/application/policies/__tests__/setup_remote_facts_policy.test.ts) · [`src/application/usecases/setup/__tests__/verify_setup_pat_bootstrap_use_case.test.ts`](../src/application/usecases/setup/__tests__/verify_setup_pat_bootstrap_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts`](../src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts) · [`src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts) · [`src/application/policies/__tests__/setup_questionnaire_policy.test.ts`](../src/application/policies/__tests__/setup_questionnaire_policy.test.ts) · [`src/application/policies/__tests__/setup_project_selection_policy.test.ts`](../src/application/policies/__tests__/setup_project_selection_policy.test.ts) · [`src/infrastructure/__tests__/github_setup_project_discovery_adapter.test.ts`](../src/infrastructure/__tests__/github_setup_project_discovery_adapter.test.ts) · [`src/infrastructure/__tests__/github_setup_approval_check_discovery_adapter.test.ts`](../src/infrastructure/__tests__/github_setup_approval_check_discovery_adapter.test.ts) · [`src/infrastructure/__tests__/setup_check_discovery_sdk_contract.integration.test.ts`](../src/infrastructure/__tests__/setup_check_discovery_sdk_contract.integration.test.ts) · [`src/application/policies/__tests__/setup_question_documentation_policy.test.ts`](../src/application/policies/__tests__/setup_question_documentation_policy.test.ts) · [`src/application/policies/__tests__/setup_question_purpose_policy.test.ts`](../src/application/policies/__tests__/setup_question_purpose_policy.test.ts) · [`src/application/policies/__tests__/setup_token_permission_policy.test.ts`](../src/application/policies/__tests__/setup_token_permission_policy.test.ts) · [`src/architecture/__tests__/setup_doctor_boundaries.test.ts`](../src/architecture/__tests__/setup_doctor_boundaries.test.ts) · [`src/infrastructure/__tests__/setup_pat_audit.test.ts`](../src/infrastructure/__tests__/setup_pat_audit.test.ts) · [`src/infrastructure/__tests__/setup_permission_projects_access.test.ts`](../src/infrastructure/__tests__/setup_permission_projects_access.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_recovery.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_recovery.test.ts) · [`src/cli/__tests__/web_setup_bot_pat_recovery.test.ts`](../src/cli/__tests__/web_setup_bot_pat_recovery.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts) · [`src/data/repository/__tests__/setup_organization_pat_inventory.test.ts`](../src/data/repository/__tests__/setup_organization_pat_inventory.test.ts) · [`src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts`](../src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts) · [`src/actions/__tests__/local_setup_apply_contract.test.ts`](../src/actions/__tests__/local_setup_apply_contract.test.ts) · [`src/cli/commands/__tests__/setup_policy.test.ts`](../src/cli/commands/__tests__/setup_policy.test.ts) · [`src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts`](../src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts) · [`src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts`](../src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts) · [`src/application/policies/__tests__/setup_management_policy.test.ts`](../src/application/policies/__tests__/setup_management_policy.test.ts) · [`src/application/usecases/setup/__tests__/manage_setup_use_case.test.ts`](../src/application/usecases/setup/__tests__/manage_setup_use_case.test.ts) · [`src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts`](../src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts) · [`src/cli/__tests__/setup_management_adapter.test.ts`](../src/cli/__tests__/setup_management_adapter.test.ts) · [`src/cli/__tests__/web_setup_management_components.test.ts`](../src/cli/__tests__/web_setup_management_components.test.ts) · [`src/cli/__tests__/web_setup_runner_components.test.ts`](../src/cli/__tests__/web_setup_runner_components.test.ts) · [`src/cli/__tests__/setup_documentation_navigation.test.ts`](../src/cli/__tests__/setup_documentation_navigation.test.ts) -- User documentation: [`README.md`](../README.md) · [`docs/how-to-use.mdx`](../docs/how-to-use.mdx) · [`docs/authentication.mdx`](../docs/authentication.mdx) · [`docs/issues/assignees-and-projects.mdx`](../docs/issues/assignees-and-projects.mdx) · [`docs/pull-requests/guarded-approval.mdx`](../docs/pull-requests/guarded-approval.mdx) · [`docs/configuration.mdx`](../docs/configuration.mdx) · [`docs/configuration-checklist.mdx`](../docs/configuration-checklist.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/development/setup-assistant-review.mdx`](../docs/development/setup-assistant-review.mdx) · [`docs/development/testing.mdx`](../docs/development/testing.mdx) · [`docs/dependency-rules.md`](../docs/dependency-rules.md) · [`docs/security-operations/security/self-hosted-runners.mdx`](../docs/security-operations/security/self-hosted-runners.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/security-operations/operations/provisioning.mdx`](../docs/security-operations/operations/provisioning.mdx) · [`docs/setup-web.mdx`](../docs/setup-web.mdx) · [`docs/first-workflow.mdx`](../docs/first-workflow.mdx) · [`docs/using-the-docs.mdx`](../docs/using-the-docs.mdx) · [`docs/guides/index.mdx`](../docs/guides/index.mdx) · [`docs/guides/issues-and-branches.mdx`](../docs/guides/issues-and-branches.mdx) · [`docs/guides/review-pull-requests.mdx`](../docs/guides/review-pull-requests.mdx) · [`docs/guides/work-with-the-bot.mdx`](../docs/guides/work-with-the-bot.mdx) · [`docs/guides/releases-and-hotfixes.mdx`](../docs/guides/releases-and-hotfixes.mdx) +- Core code: [`web/src/App.svelte`](../web/src/App.svelte) · [`web/src/session/setupSession.ts`](../web/src/session/setupSession.ts) · [`web/src/components/ActionButton.svelte`](../web/src/components/ActionButton.svelte) · [`web/src/components/PairingPanel.svelte`](../web/src/components/PairingPanel.svelte) · [`web/src/lib/pairingCode.ts`](../web/src/lib/pairingCode.ts) · [`web/src/components/ContextPanel.svelte`](../web/src/components/ContextPanel.svelte) · [`web/src/i18n/permissionEvidence.ts`](../web/src/i18n/permissionEvidence.ts) · [`web/src/i18n/permissionProgress.ts`](../web/src/i18n/permissionProgress.ts) · [`web/src/components/PermissionProgressPanel.svelte`](../web/src/components/PermissionProgressPanel.svelte) · [`web/src/components/PromptCard.svelte`](../web/src/components/PromptCard.svelte) · [`web/src/components/ResultPanel.svelte`](../web/src/components/ResultPanel.svelte) · [`web/src/components/SetupPatCorrectionPanel.svelte`](../web/src/components/SetupPatCorrectionPanel.svelte) · [`web/src/components/ResourceProgress.svelte`](../web/src/components/ResourceProgress.svelte) · [`web/src/components/PlanPrompt.svelte`](../web/src/components/PlanPrompt.svelte) · [`web/src/components/PlanDecisionSummary.svelte`](../web/src/components/PlanDecisionSummary.svelte) · [`web/src/components/QuestionPrompt.svelte`](../web/src/components/QuestionPrompt.svelte) · [`web/src/components/FixedWorkflowNotice.svelte`](../web/src/components/FixedWorkflowNotice.svelte) · [`web/src/components/QuestionGuidance.svelte`](../web/src/components/QuestionGuidance.svelte) · [`web/src/components/DiscoveryNotice.svelte`](../web/src/components/DiscoveryNotice.svelte) · [`web/src/components/ProducerSelector.svelte`](../web/src/components/ProducerSelector.svelte) · [`web/src/lib/manualProducerIdentity.ts`](../web/src/lib/manualProducerIdentity.ts) · [`web/src/components/CoverageCheckEvidence.svelte`](../web/src/components/CoverageCheckEvidence.svelte) · [`web/src/components/ProjectSelector.svelte`](../web/src/components/ProjectSelector.svelte) · [`web/src/i18n/catalog.ts`](../web/src/i18n/catalog.ts) · [`web/src/i18n/projectTransitions.ts`](../web/src/i18n/projectTransitions.ts) · [`web/src/i18n/permissionTerms.ts`](../web/src/i18n/permissionTerms.ts) · [`web/src/components/StatusBanner.svelte`](../web/src/components/StatusBanner.svelte) · [`web/src/lib/questionAnswer.ts`](../web/src/lib/questionAnswer.ts) · [`web/src/lib/githubLink.ts`](../web/src/lib/githubLink.ts) · [`web/src/lib/focusOnRevision.ts`](../web/src/lib/focusOnRevision.ts) · [`web/src/i18n/featureNames.ts`](../web/src/i18n/featureNames.ts) · [`web/src/i18n/agentRoleNames.ts`](../web/src/i18n/agentRoleNames.ts) · [`web/src/i18n/checkEvidence.ts`](../web/src/i18n/checkEvidence.ts) · [`web/src/styles/controls.css`](../web/src/styles/controls.css) · [`web/src/styles/tokens.css`](../web/src/styles/tokens.css) · [`web/src/style.css`](../web/src/style.css) · [`src/application/contracts/web_setup_view.ts`](../src/application/contracts/web_setup_view.ts) · [`src/application/ports/setup_terminal_ports.ts`](../src/application/ports/setup_terminal_ports.ts) · [`src/application/errors/setup_interaction_cancelled_error.ts`](../src/application/errors/setup_interaction_cancelled_error.ts) · [`src/application/policies/merge_setup_overrides_policy.ts`](../src/application/policies/merge_setup_overrides_policy.ts) · [`src/application/policies/setup_remote_facts_policy.ts`](../src/application/policies/setup_remote_facts_policy.ts) · [`src/application/usecases/setup/prepare_setup_pat_intent_use_case.ts`](../src/application/usecases/setup/prepare_setup_pat_intent_use_case.ts) · [`src/application/usecases/setup/audit_configured_setup_pat_use_case.ts`](../src/application/usecases/setup/audit_configured_setup_pat_use_case.ts) · [`src/infrastructure/setup_permission_actions_probe.ts`](../src/infrastructure/setup_permission_actions_probe.ts) · [`src/infrastructure/setup_permission_issue_probe.ts`](../src/infrastructure/setup_permission_issue_probe.ts) · [`src/infrastructure/setup_permission_issue_cleanup.ts`](../src/infrastructure/setup_permission_issue_cleanup.ts) · [`src/infrastructure/setup_permission_probe_journal.ts`](../src/infrastructure/setup_permission_probe_journal.ts) · [`src/infrastructure/setup_permission_probe_transaction.ts`](../src/infrastructure/setup_permission_probe_transaction.ts) · [`src/infrastructure/setup_permission_resource_probes.ts`](../src/infrastructure/setup_permission_resource_probes.ts) · [`src/application/usecases/setup/verify_web_setup_apply_use_case.ts`](../src/application/usecases/setup/verify_web_setup_apply_use_case.ts) · [`src/application/usecases/setup/setup_session_coordinator.ts`](../src/application/usecases/setup/setup_session_coordinator.ts) · [`src/application/usecases/setup/verify_setup_pat_bootstrap_use_case.ts`](../src/application/usecases/setup/verify_setup_pat_bootstrap_use_case.ts) · [`src/cli_context.ts`](../src/cli_context.ts) · [`src/cli/setup_command_options.ts`](../src/cli/setup_command_options.ts) · [`src/cli/commands/setup_execution.ts`](../src/cli/commands/setup_execution.ts) · [`src/cli/setup_credential_collection.ts`](../src/cli/setup_credential_collection.ts) · [`src/cli/setup_pat_intent_adapter.ts`](../src/cli/setup_pat_intent_adapter.ts) · [`src/cli/setup_apply_authorization.ts`](../src/cli/setup_apply_authorization.ts) · [`src/cli/setup_outcome_adapter.ts`](../src/cli/setup_outcome_adapter.ts) · [`src/cli/web_setup_bridge.ts`](../src/cli/web_setup_bridge.ts) · [`src/cli/web_setup_adapters.ts`](../src/cli/web_setup_adapters.ts) · [`src/cli/web_setup_server.ts`](../src/cli/web_setup_server.ts) · [`src/cli/setup_apply_snapshot.ts`](../src/cli/setup_apply_snapshot.ts) · [`src/cli/setup_result_receipt.ts`](../src/cli/setup_result_receipt.ts) · [`src/application/usecases/actions/initial_setup_workflow.ts`](../src/application/usecases/actions/initial_setup_workflow.ts) · [`src/actions/local_action.ts`](../src/actions/local_action.ts) · [`src/cli/setup_session_guard.ts`](../src/cli/setup_session_guard.ts) · [`src/application/usecases/setup/setup_wizard_use_case.ts`](../src/application/usecases/setup/setup_wizard_use_case.ts) · [`src/application/usecases/setup/setup_questionnaire_controller.ts`](../src/application/usecases/setup/setup_questionnaire_controller.ts) · [`src/application/policies/setup_terminal_choice_policy.ts`](../src/application/policies/setup_terminal_choice_policy.ts) · [`src/cli/setup_terminal_driver.ts`](../src/cli/setup_terminal_driver.ts) · [`src/cli/setup_question_renderer.ts`](../src/cli/setup_question_renderer.ts) · [`src/application/usecases/setup/setup_journey_use_case.ts`](../src/application/usecases/setup/setup_journey_use_case.ts) · [`src/application/usecases/setup/setup_credentials_use_case.ts`](../src/application/usecases/setup/setup_credentials_use_case.ts) · [`src/application/policies/setup_questionnaire_policy.ts`](../src/application/policies/setup_questionnaire_policy.ts) · [`src/application/policies/setup_project_selection_policy.ts`](../src/application/policies/setup_project_selection_policy.ts) · [`src/application/ports/setup_project_discovery_port.ts`](../src/application/ports/setup_project_discovery_port.ts) · [`src/application/ports/setup_approval_check_discovery_port.ts`](../src/application/ports/setup_approval_check_discovery_port.ts) · [`src/infrastructure/github_setup_project_discovery_adapter.ts`](../src/infrastructure/github_setup_project_discovery_adapter.ts) · [`src/infrastructure/github_setup_approval_check_discovery_adapter.ts`](../src/infrastructure/github_setup_approval_check_discovery_adapter.ts) · [`src/application/policies/setup_question_documentation_policy.ts`](../src/application/policies/setup_question_documentation_policy.ts) · [`src/application/policies/setup_question_guidance_policy.ts`](../src/application/policies/setup_question_guidance_policy.ts) · [`src/application/policies/setup_question_purpose_policy.ts`](../src/application/policies/setup_question_purpose_policy.ts) · [`src/application/policies/setup_token_permission_policy.ts`](../src/application/policies/setup_token_permission_policy.ts) · [`src/application/policies/setup_configuration_plan.ts`](../src/application/policies/setup_configuration_plan.ts) · [`src/application/policies/setup_pat_creation_url_policy.ts`](../src/application/policies/setup_pat_creation_url_policy.ts) · [`src/infrastructure/composition/setup_credentials_composition_root.ts`](../src/infrastructure/composition/setup_credentials_composition_root.ts) · [`scripts/validate-npm-package.cjs`](../scripts/validate-npm-package.cjs) · [`scripts/smoke-test-npm-package.cjs`](../scripts/smoke-test-npm-package.cjs) · [`scripts/smoke-packaged-web-session.cjs`](../scripts/smoke-packaged-web-session.cjs) · [`scripts/validate-setup-assistant-acceptance.cjs`](../scripts/validate-setup-assistant-acceptance.cjs) · [`scripts/serve-web-setup-review.cjs`](../scripts/serve-web-setup-review.cjs) · [`scripts/validate-workflow-contract.cjs`](../scripts/validate-workflow-contract.cjs) · [`scripts/documentation_checkout_text.cjs`](../scripts/documentation_checkout_text.cjs) · [`scripts/set-cli-executable.cjs`](../scripts/set-cli-executable.cjs) · [`scripts/render-web-setup-component.cjs`](../scripts/render-web-setup-component.cjs) · [`web/src/i18n/permissionPrerequisite.ts`](../web/src/i18n/permissionPrerequisite.ts) · [`scripts/web-setup-review-views.cjs`](../scripts/web-setup-review-views.cjs) · [`src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts`](../src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts) · [`src/cli/setup_workflow_pat_storage_copy.ts`](../src/cli/setup_workflow_pat_storage_copy.ts) · [`web/src/components/WorkflowPatStorageNotice.svelte`](../web/src/components/WorkflowPatStorageNotice.svelte) · [`src/cli/commands/setup_policy.ts`](../src/cli/commands/setup_policy.ts) · [`src/application/usecases/execution/execution_issue_number_policy.ts`](../src/application/usecases/execution/execution_issue_number_policy.ts) · [`src/application/usecases/execution/setup_execution_workflow.ts`](../src/application/usecases/execution/setup_execution_workflow.ts) · [`src/domain/setup_management.ts`](../src/domain/setup_management.ts) · [`src/application/contracts/setup_management_view.ts`](../src/application/contracts/setup_management_view.ts) · [`src/application/ports/setup_management_ports.ts`](../src/application/ports/setup_management_ports.ts) · [`src/application/policies/setup_quick_settings_policy.ts`](../src/application/policies/setup_quick_settings_policy.ts) · [`src/application/policies/setup_management_policy.ts`](../src/application/policies/setup_management_policy.ts) · [`src/application/policies/setup_management_permissions_policy.ts`](../src/application/policies/setup_management_permissions_policy.ts) · [`src/application/usecases/setup/manage_setup_use_case.ts`](../src/application/usecases/setup/manage_setup_use_case.ts) · [`src/infrastructure/setup_management_workspace_adapter.ts`](../src/infrastructure/setup_management_workspace_adapter.ts) · [`src/cli/setup_management_adapter.ts`](../src/cli/setup_management_adapter.ts) · [`web/src/components/SetupManagementPanel.svelte`](../web/src/components/SetupManagementPanel.svelte) · [`web/src/components/ManagementInventory.svelte`](../web/src/components/ManagementInventory.svelte) · [`web/src/components/QuickSettingPrompt.svelte`](../web/src/components/QuickSettingPrompt.svelte) · [`web/src/i18n/managementCopy.ts`](../web/src/i18n/managementCopy.ts) · [`web/src/styles/management.css`](../web/src/styles/management.css) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`web/src/session/setupCommandTransport.ts`](../web/src/session/setupCommandTransport.ts) · [`scripts/serve-web-setup-journey.cjs`](../scripts/serve-web-setup-journey.cjs) · [`web/src/components/SetupHeader.svelte`](../web/src/components/SetupHeader.svelte) · [`web/src/components/WaitingPanel.svelte`](../web/src/components/WaitingPanel.svelte) · [`web/src/styles/layout.css`](../web/src/styles/layout.css) · [`web/src/i18n/en.ts`](../web/src/i18n/en.ts) · [`web/src/i18n/es.ts`](../web/src/i18n/es.ts) · [`web/src/i18n/fr.ts`](../web/src/i18n/fr.ts) · [`web/src/i18n/pt.ts`](../web/src/i18n/pt.ts) · [`web/src/i18n/sessionErrors.ts`](../web/src/i18n/sessionErrors.ts) · [`web/src/i18n/errors/en.ts`](../web/src/i18n/errors/en.ts) · [`web/src/i18n/errors/es.ts`](../web/src/i18n/errors/es.ts) · [`web/src/i18n/errors/fr.ts`](../web/src/i18n/errors/fr.ts) · [`web/src/i18n/errors/pt.ts`](../web/src/i18n/errors/pt.ts) · [`web/src/components/SetupSidebar.svelte`](../web/src/components/SetupSidebar.svelte) · [`web/src/components/RepositorySelector.svelte`](../web/src/components/RepositorySelector.svelte) · [`web/src/components/BatchSetupPanel.svelte`](../web/src/components/BatchSetupPanel.svelte) · [`web/src/components/BatchSafetyBanner.svelte`](../web/src/components/BatchSafetyBanner.svelte) · [`web/src/components/InstallationReview.svelte`](../web/src/components/InstallationReview.svelte) · [`web/src/components/RunnerQuestionDetails.svelte`](../web/src/components/RunnerQuestionDetails.svelte) · [`web/src/i18n/runnerCopy.ts`](../web/src/i18n/runnerCopy.ts) · [`scripts/web-setup-runner-review-fixtures.cjs`](../scripts/web-setup-runner-review-fixtures.cjs) · [`src/application/contracts/setup_documentation.ts`](../src/application/contracts/setup_documentation.ts) · [`src/cli/setup_journey_presenter.ts`](../src/cli/setup_journey_presenter.ts) · [`web/src/components/SetupHelp.svelte`](../web/src/components/SetupHelp.svelte) · [`web/src/components/CompletedSetupHelp.svelte`](../web/src/components/CompletedSetupHelp.svelte) · [`src/domain/setup_verification_action.ts`](../src/domain/setup_verification_action.ts) · [`src/infrastructure/setup_verification_action.ts`](../src/infrastructure/setup_verification_action.ts) · [`src/application/policies/setup_verification_action_summary_policy.ts`](../src/application/policies/setup_verification_action_summary_policy.ts) +- Tests: [`src/__tests__/cli.test.ts`](../src/__tests__/cli.test.ts) · [`src/__tests__/cli_context_branch.test.ts`](../src/__tests__/cli_context_branch.test.ts) · [`src/__tests__/cli_context_root.test.ts`](../src/__tests__/cli_context_root.test.ts) · [`src/cli/__tests__/web_setup_bridge.test.ts`](../src/cli/__tests__/web_setup_bridge.test.ts) · [`src/cli/__tests__/web_setup_adapters.test.ts`](../src/cli/__tests__/web_setup_adapters.test.ts) · [`src/cli/__tests__/web_setup_palette.test.ts`](../src/cli/__tests__/web_setup_palette.test.ts) · [`src/cli/__tests__/web_setup_ui_helpers.test.ts`](../src/cli/__tests__/web_setup_ui_helpers.test.ts) · [`src/cli/__tests__/web_setup_browser_session.test.ts`](../src/cli/__tests__/web_setup_browser_session.test.ts) · [`src/cli/__tests__/web_setup_server.test.ts`](../src/cli/__tests__/web_setup_server.test.ts) · [`src/cli/__tests__/web_setup_browser_open.test.ts`](../src/cli/__tests__/web_setup_browser_open.test.ts) · [`src/cli/__tests__/setup_apply_snapshot.test.ts`](../src/cli/__tests__/setup_apply_snapshot.test.ts) · [`src/cli/__tests__/setup_result_receipt.test.ts`](../src/cli/__tests__/setup_result_receipt.test.ts) · [`src/cli/__tests__/setup_session_guard.test.ts`](../src/cli/__tests__/setup_session_guard.test.ts) · [`src/cli/__tests__/setup_command_options.test.ts`](../src/cli/__tests__/setup_command_options.test.ts) · [`src/cli/__tests__/web_setup_components.test.ts`](../src/cli/__tests__/web_setup_components.test.ts) · [`src/cli/__tests__/setup_terminal_driver.test.ts`](../src/cli/__tests__/setup_terminal_driver.test.ts) · [`src/cli/__tests__/setup_terminal_driver_stream_integration.test.ts`](../src/cli/__tests__/setup_terminal_driver_stream_integration.test.ts) · [`src/cli/__tests__/setup_presenters.test.ts`](../src/cli/__tests__/setup_presenters.test.ts) · [`src/cli/__tests__/web_setup_catalog.test.ts`](../src/cli/__tests__/web_setup_catalog.test.ts) · [`src/architecture/__tests__/web_setup_boundaries.test.ts`](../src/architecture/__tests__/web_setup_boundaries.test.ts) · [`src/application/usecases/setup/__tests__/prepare_setup_pat_intent_use_case.test.ts`](../src/application/usecases/setup/__tests__/prepare_setup_pat_intent_use_case.test.ts) · [`src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts`](../src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts) · [`src/infrastructure/__tests__/setup_permission_resource_probes.test.ts`](../src/infrastructure/__tests__/setup_permission_resource_probes.test.ts) · [`src/application/usecases/setup/__tests__/verify_web_setup_apply_use_case.test.ts`](../src/application/usecases/setup/__tests__/verify_web_setup_apply_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts`](../src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts) · [`src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts`](../src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts) · [`src/actions/__tests__/local_action.test.ts`](../src/actions/__tests__/local_action.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) · [`src/domain/__tests__/setup_approval_workflow.test.ts`](../src/domain/__tests__/setup_approval_workflow.test.ts) · [`src/tooling/__tests__/documentation_checkout_text.test.ts`](../src/tooling/__tests__/documentation_checkout_text.test.ts) · [`src/application/policies/__tests__/setup_remote_facts_policy.test.ts`](../src/application/policies/__tests__/setup_remote_facts_policy.test.ts) · [`src/application/usecases/setup/__tests__/verify_setup_pat_bootstrap_use_case.test.ts`](../src/application/usecases/setup/__tests__/verify_setup_pat_bootstrap_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts`](../src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts) · [`src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts) · [`src/application/policies/__tests__/setup_questionnaire_policy.test.ts`](../src/application/policies/__tests__/setup_questionnaire_policy.test.ts) · [`src/application/policies/__tests__/setup_project_selection_policy.test.ts`](../src/application/policies/__tests__/setup_project_selection_policy.test.ts) · [`src/infrastructure/__tests__/github_setup_project_discovery_adapter.test.ts`](../src/infrastructure/__tests__/github_setup_project_discovery_adapter.test.ts) · [`src/infrastructure/__tests__/github_setup_approval_check_discovery_adapter.test.ts`](../src/infrastructure/__tests__/github_setup_approval_check_discovery_adapter.test.ts) · [`src/infrastructure/__tests__/setup_check_discovery_sdk_contract.integration.test.ts`](../src/infrastructure/__tests__/setup_check_discovery_sdk_contract.integration.test.ts) · [`src/application/policies/__tests__/setup_question_documentation_policy.test.ts`](../src/application/policies/__tests__/setup_question_documentation_policy.test.ts) · [`src/application/policies/__tests__/setup_question_purpose_policy.test.ts`](../src/application/policies/__tests__/setup_question_purpose_policy.test.ts) · [`src/application/policies/__tests__/setup_token_permission_policy.test.ts`](../src/application/policies/__tests__/setup_token_permission_policy.test.ts) · [`src/architecture/__tests__/setup_doctor_boundaries.test.ts`](../src/architecture/__tests__/setup_doctor_boundaries.test.ts) · [`src/infrastructure/__tests__/setup_pat_audit.test.ts`](../src/infrastructure/__tests__/setup_pat_audit.test.ts) · [`src/infrastructure/__tests__/setup_permission_projects_access.test.ts`](../src/infrastructure/__tests__/setup_permission_projects_access.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_recovery.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_recovery.test.ts) · [`src/cli/__tests__/web_setup_bot_pat_recovery.test.ts`](../src/cli/__tests__/web_setup_bot_pat_recovery.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts) · [`src/data/repository/__tests__/setup_organization_pat_inventory.test.ts`](../src/data/repository/__tests__/setup_organization_pat_inventory.test.ts) · [`src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts`](../src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts) · [`src/actions/__tests__/local_setup_apply_contract.test.ts`](../src/actions/__tests__/local_setup_apply_contract.test.ts) · [`src/cli/commands/__tests__/setup_policy.test.ts`](../src/cli/commands/__tests__/setup_policy.test.ts) · [`src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts`](../src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts) · [`src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts`](../src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts) · [`src/application/policies/__tests__/setup_management_policy.test.ts`](../src/application/policies/__tests__/setup_management_policy.test.ts) · [`src/application/usecases/setup/__tests__/manage_setup_use_case.test.ts`](../src/application/usecases/setup/__tests__/manage_setup_use_case.test.ts) · [`src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts`](../src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts) · [`src/cli/__tests__/setup_management_adapter.test.ts`](../src/cli/__tests__/setup_management_adapter.test.ts) · [`src/cli/__tests__/web_setup_management_components.test.ts`](../src/cli/__tests__/web_setup_management_components.test.ts) · [`src/cli/__tests__/web_setup_runner_components.test.ts`](../src/cli/__tests__/web_setup_runner_components.test.ts) · [`src/cli/__tests__/setup_documentation_navigation.test.ts`](../src/cli/__tests__/setup_documentation_navigation.test.ts) · [`src/infrastructure/__tests__/setup_verification_action.test.ts`](../src/infrastructure/__tests__/setup_verification_action.test.ts) · [`src/application/policies/__tests__/setup_verification_onboarding_policy.test.ts`](../src/application/policies/__tests__/setup_verification_onboarding_policy.test.ts) · [`src/cli/__tests__/setup_verification_onboarding_components.test.ts`](../src/cli/__tests__/setup_verification_onboarding_components.test.ts) · [`src/application/usecases/setup/__tests__/setup_verification_onboarding_flow.test.ts`](../src/application/usecases/setup/__tests__/setup_verification_onboarding_flow.test.ts) +- User documentation: [`README.md`](../README.md) · [`docs/how-to-use.mdx`](../docs/how-to-use.mdx) · [`docs/authentication.mdx`](../docs/authentication.mdx) · [`docs/issues/assignees-and-projects.mdx`](../docs/issues/assignees-and-projects.mdx) · [`docs/pull-requests/guarded-approval.mdx`](../docs/pull-requests/guarded-approval.mdx) · [`docs/configuration.mdx`](../docs/configuration.mdx) · [`docs/configuration-checklist.mdx`](../docs/configuration-checklist.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/development/setup-assistant-review.mdx`](../docs/development/setup-assistant-review.mdx) · [`docs/development/testing.mdx`](../docs/development/testing.mdx) · [`docs/dependency-rules.md`](../docs/dependency-rules.md) · [`docs/security-operations/security/self-hosted-runners.mdx`](../docs/security-operations/security/self-hosted-runners.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/security-operations/operations/provisioning.mdx`](../docs/security-operations/operations/provisioning.mdx) · [`docs/setup-web.mdx`](../docs/setup-web.mdx) · [`docs/first-workflow.mdx`](../docs/first-workflow.mdx) · [`docs/using-the-docs.mdx`](../docs/using-the-docs.mdx) · [`docs/guides/index.mdx`](../docs/guides/index.mdx) · [`docs/guides/issues-and-branches.mdx`](../docs/guides/issues-and-branches.mdx) · [`docs/guides/review-pull-requests.mdx`](../docs/guides/review-pull-requests.mdx) · [`docs/guides/work-with-the-bot.mdx`](../docs/guides/work-with-the-bot.mdx) · [`docs/guides/releases-and-hotfixes.mdx`](../docs/guides/releases-and-hotfixes.mdx) · [`docs/security-operations/operations/verification.mdx`](../docs/security-operations/operations/verification.mdx) · [`docs/security-operations/operations/upgrade-rollback.mdx`](../docs/security-operations/operations/upgrade-rollback.mdx) ### `guided-bot-pat-onboarding` — Guided bot PAT onboarding diff --git a/specs/catalog.json b/specs/catalog.json index b61aefff9..54664ccca 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -1262,7 +1262,10 @@ "src/application/contracts/setup_documentation.ts", "src/cli/setup_journey_presenter.ts", "web/src/components/SetupHelp.svelte", - "web/src/components/CompletedSetupHelp.svelte" + "web/src/components/CompletedSetupHelp.svelte", + "src/domain/setup_verification_action.ts", + "src/infrastructure/setup_verification_action.ts", + "src/application/policies/setup_verification_action_summary_policy.ts" ], "tests": [ "src/__tests__/cli.test.ts", @@ -1328,7 +1331,11 @@ "src/cli/__tests__/setup_management_adapter.test.ts", "src/cli/__tests__/web_setup_management_components.test.ts", "src/cli/__tests__/web_setup_runner_components.test.ts", - "src/cli/__tests__/setup_documentation_navigation.test.ts" + "src/cli/__tests__/setup_documentation_navigation.test.ts", + "src/infrastructure/__tests__/setup_verification_action.test.ts", + "src/application/policies/__tests__/setup_verification_onboarding_policy.test.ts", + "src/cli/__tests__/setup_verification_onboarding_components.test.ts", + "src/application/usecases/setup/__tests__/setup_verification_onboarding_flow.test.ts" ], "documentation": [ "README.md", @@ -1352,7 +1359,9 @@ "docs/guides/issues-and-branches.mdx", "docs/guides/review-pull-requests.mdx", "docs/guides/work-with-the-bot.mdx", - "docs/guides/releases-and-hotfixes.mdx" + "docs/guides/releases-and-hotfixes.mdx", + "docs/security-operations/operations/verification.mdx", + "docs/security-operations/operations/upgrade-rollback.mdx" ] }, { diff --git a/specs/local-web-setup-assistant.md b/specs/local-web-setup-assistant.md index 4b04c5fa2..cf65f78a5 100644 --- a/specs/local-web-setup-assistant.md +++ b/specs/local-web-setup-assistant.md @@ -47,6 +47,13 @@ installation questionnaire. Terminal behavior and full-wizard guards remain. ## 1. Executive summary +The additive verification starter, shared activation question, create/preserve +review and upgrade behavior are defined in the catalogued companion +[`verification-setup-onboarding.md`](./verification-setup-onboarding.md). It uses +the existing boolean and setup approval pipeline; consumer action assets remain +outside generator overwrite/retirement ownership. + + The default `copilot setup` remains the terminal wizard. `copilot setup --web` starts a short-lived web assistant on this machine and opens the default browser. It presents repository identity, setup choices, the temporary setup diff --git a/specs/repository-verification-setup-hooks.md b/specs/repository-verification-setup-hooks.md index 9b9d2848d..8bc3851e2 100644 --- a/specs/repository-verification-setup-hooks.md +++ b/specs/repository-verification-setup-hooks.md @@ -210,6 +210,15 @@ Logs name the fixed action and pinned source SHA, preparation success, and the e ## 13. Compatibility, migration, rollout, and rollback +Installer onboarding is specified by the existing setup capability's companion +[`verification-setup-onboarding.md`](./verification-setup-onboarding.md): seed the +fixed action only if missing, preserve existing consumer bytes and auxiliaries, +show the shared terminal/web activation question (default false), and document +CLI/Action-ref/workflow upgrades. Seeding a file does not transfer generator +ownership or alter this native execution/trusted-main contract. The generated +placeholder fails until the owner customizes it and reviews it onto trusted main. + + Existing installations remain disabled by default. The unreleased `.copilot/verification-setup.mjs` prototype is removed rather than maintained as a second execution mode. Consumers opting in MUST update generated callbacks before activation and review the composite directory onto trusted main. Setup/install/update MUST preserve that directory and all its assets. Rollback disables the Variable and restores ordinary same-job provisioning; no remote migration, release or tag is required. ## 14. Testing strategy and numeric budget diff --git a/specs/setup-configuration-management.md b/specs/setup-configuration-management.md index efff5a0d1..f21fe0328 100644 --- a/specs/setup-configuration-management.md +++ b/specs/setup-configuration-management.md @@ -12,6 +12,13 @@ ## 1. Executive summary +The additive verification starter, shared activation question, create/preserve +review and upgrade behavior are defined in the catalogued companion +[`verification-setup-onboarding.md`](./verification-setup-onboarding.md). It uses +the existing boolean and setup approval pipeline; consumer action assets remain +outside generator overwrite/retirement ownership. + + Opening web setup MUST begin with a configuration panel after repository confirmation and browser pairing. A new repository explains that Copilot is not configured and offers **Start setup**. An existing repository offers **Read configuration from GitHub**, **Quick adjustments**, and **Run the complete assistant**. Reading the panel MUST NOT mutate anything or request a bot PAT. ```text diff --git a/specs/verification-setup-onboarding.md b/specs/verification-setup-onboarding.md index c488d6fb0..56c783659 100644 --- a/specs/verification-setup-onboarding.md +++ b/specs/verification-setup-onboarding.md @@ -1,9 +1,9 @@ # Verification Setup Onboarding Specification -- Status: Draft +- Status: Implemented in source; final-head CI and review pending - Date: 2026-10-21 - Catalog capability ID: `local-web-setup-assistant` -- Last verified: not applicable (prospective companion) +- Last verified: 2026-10-21 (local focused suites, package smoke and responsive fixture; final-head evidence remains pending) - Owners: Copilot maintainers - Scope: Complete onboarding for the repository-owned verification setup starter, its explicit activation choice, and safe upgrade guidance. - Related issues/PRs: [Issue #656](https://github.com/vypdev/copilot/issues/656), #647, #652; existing owning specifications: [`specs/local-web-setup-assistant.md`](./local-web-setup-assistant.md), [`specs/setup-configuration-management.md`](./setup-configuration-management.md); native execution contract: [`specs/repository-verification-setup-hooks.md`](./repository-verification-setup-hooks.md). @@ -212,7 +212,7 @@ Automated boundary checks MUST ensure questionnaire semantics are shared by term - [x] Created `.github/actions/copilot-verification-setup/action.yml` because it was absent. - [x] Set `VERIFICATION_SETUP` to enabled. -- [ ] Customize and review the action on the configured trusted main branch. +- [x] Customize and review the action on the configured trusted main branch. ## What happens next @@ -344,20 +344,20 @@ Scenario IDs use the `VSO-` namespace and are unique. ## 19. Definition of Done -- [ ] Every normative requirement maps to acceptance and traceability. -- [ ] Consumer action creation is missing-only, race-safe, and preserves existing bytes and auxiliary files. -- [ ] Shared terminal/web activation uses the existing boolean, remains disabled by default, and respects preselected/configured values. -- [ ] Starter fails with customization instructions until replaced; setup performs no inferred installation. -- [ ] Local, batch, and packaged flows satisfy the same ownership contract. -- [ ] Existing receipts, permission checks, review gates, runner selections, and credential handling remain valid. -- [ ] Numeric 48-case budget and pure-policy/adapter coverage thresholds pass; repository-wide budgets remain satisfied. -- [ ] Accessibility, localization, responsive content, sanitization, and UX review pass. -- [ ] Migration, rollback, three-layer upgrade, and release distinction are documented and discoverable. -- [ ] Failure, partial success, retry, race, security, and cleanup scenarios pass. -- [ ] Required generated artifacts and repository validation commands pass. -- [ ] `specs/catalog.json` and `specs/CATALOG.md` are current and `pnpm run validate:specifications` passes. +- [x] Every normative requirement maps to acceptance and traceability. +- [x] Consumer action creation is missing-only, race-safe, and preserves existing bytes and auxiliary files. +- [x] Shared terminal/web activation uses the existing boolean, remains disabled by default, and respects preselected/configured values. +- [x] Starter fails with customization instructions until replaced; setup performs no inferred installation. +- [x] Local, batch, and packaged flows satisfy the same ownership contract. +- [x] Existing receipts, permission checks, review gates, runner selections, and credential handling remain valid. +- [x] Numeric 48-case budget and pure-policy/adapter coverage thresholds pass; repository-wide budgets remain satisfied. +- [x] Accessibility, localization, responsive content, sanitization, and UX review pass. +- [x] Migration, rollback, three-layer upgrade, and release distinction are documented and discoverable. +- [x] Failure, partial success, retry, race, security, and cleanup scenarios pass. +- [x] Required generated artifacts and repository validation commands pass. +- [x] `specs/catalog.json` and `specs/CATALOG.md` are current and `pnpm run validate:specifications` passes. - [ ] PR is merged into `develop` only after applicable final-head checks pass and no findings remain unresolved; no release is implied. -- [ ] No readiness-blocking decision remains unresolved. +- [x] No readiness-blocking decision remains unresolved. ## 20. References and decisions @@ -365,4 +365,31 @@ Scenario IDs use the `VSO-` namespace and are unique. - Related specs: [`specs/local-web-setup-assistant.md`](./local-web-setup-assistant.md), [`specs/setup-configuration-management.md`](./setup-configuration-management.md), [`specs/repository-verification-setup-hooks.md`](./repository-verification-setup-hooks.md). - Related issue/PRs: [Issue #656](https://github.com/vypdev/copilot/issues/656), #647, #652. - Decisions: companion owned by existing `local-web-setup-assistant` capability; native execution contract remains in `repository-verification-setup-hooks.md`; consumer action is create-once and consumer-owned; activation is explicit; starter is fail-closed; no automatic release or installation into other repositories. -- Follow-up outside scope: publishing a release and installing changes into consumer repositories. \ No newline at end of file +- Follow-up outside scope: publishing a release and installing changes into consumer repositories. +### Implementation and local verification evidence + +The create-once adapter is `src/infrastructure/setup_verification_action.ts`; +`src/domain/setup_verification_action.ts` fixes its path and public review facts. +`setup_files.ts` and `setup_installation_review.ts` share this adapter. The +reviewed create/preserve state travels through CLI/application/workspace contracts +so a changed path blocks Apply; exclusive creation also rejects a final collision. +Batch inventory preserves the exact action as an unchanged base-tree entry and +rejects unsafe parent/file modes and case collisions before downloading blobs. +The action never enters the generator ownership manifest. + +Executable coverage is in `setup_verification_action.test.ts`, +`setup_verification_onboarding_policy.test.ts`, +`setup_verification_onboarding_flow.test.ts`, +`setup_verification_onboarding_components.test.ts`, and focused additions to the +batch inventory/workspace, initial setup workflow and context projection suites. +The new summary policy and file adapter have explicit coverage budgets. The complete local suite passed: 707 suites, 11,597 passed tests and 35 existing +skips, including all 87 new VSO cases. Both modules report 100% in every coverage +metric. All repository coverage budgets and setup acceptance validation pass. Package validation and an extracted npm +smoke verify the starter and its CLI resolver. The credential-free +`serve-web-setup-review.cjs runner-plan` fixture was reviewed at 1280 px and 375 px, +including Spanish: the fixed path wraps and the create/disabled/trusted-main and +customization guidance remain readable. SSR contracts cover create/preserve/blocked, +enabled/disabled and completion navigation in all four supported locales. + +No release or consumer installation was performed. Final PR checks and resolved +finding evidence belong to the linked implementation PR. diff --git a/src/application/contracts/setup_documentation.ts b/src/application/contracts/setup_documentation.ts index c5a082a43..064221987 100644 --- a/src/application/contracts/setup_documentation.ts +++ b/src/application/contracts/setup_documentation.ts @@ -3,4 +3,5 @@ export const SETUP_DOCUMENTATION = { tutorial: 'https://docs.page/vypdev/copilot/setup-web', firstWorkflow: 'https://docs.page/vypdev/copilot/first-workflow', recovery: 'https://docs.page/vypdev/copilot/security-operations/operations/troubleshooting', + verification: 'https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-owned-setup', } as const; diff --git a/src/application/policies/__tests__/setup_configuration_policy.test.ts b/src/application/policies/__tests__/setup_configuration_policy.test.ts index 2401a075e..dccd1fe9d 100644 --- a/src/application/policies/__tests__/setup_configuration_policy.test.ts +++ b/src/application/policies/__tests__/setup_configuration_policy.test.ts @@ -34,7 +34,7 @@ describe('setup configuration policy', () => { expect(plan.workflowFiles).toHaveLength(13); expect(plan.issueTemplateFiles).toHaveLength(8); - expect(plan.selectedFiles).toHaveLength(27); + expect(plan.selectedFiles).toHaveLength(28); expect(plan.selectedFiles).toContain('AGENTS.md (managed pointer only)'); expect(plan.variables).toEqual(expect.arrayContaining([ { name: 'AGENT_PROVIDER', value: 'codex' }, @@ -107,7 +107,7 @@ describe('setup configuration policy', () => { 'copilot_branch_sync.yml', ])); expect(plan.workflowFiles).not.toContain('release_workflow.yml'); - expect(plan.selectedFiles).toHaveLength(14); + expect(plan.selectedFiles).toHaveLength(15); }); it('keeps inactivity closure opt-in and wires its threshold when enabled', () => { diff --git a/src/application/policies/__tests__/setup_verification_onboarding_policy.test.ts b/src/application/policies/__tests__/setup_verification_onboarding_policy.test.ts new file mode 100644 index 000000000..d9d0d23ba --- /dev/null +++ b/src/application/policies/__tests__/setup_verification_onboarding_policy.test.ts @@ -0,0 +1,76 @@ +import { createDefaultSetupConfiguration } from '../setup_configuration_defaults'; +import { buildSetupPlan, buildSetupActionInputs, buildSetupRepositoryVariables, setupPlanGuardPaths } from '../setup_configuration_plan'; +import { createSetupQuestionnaire, transitionSetupQuestionnaire, setupBasicSkippedQuestionIds } from '../setup_questionnaire_policy'; +import { setupQuestionPresentation } from '../setup_question_guidance_policy'; +import { setupVerificationActionSummary } from '../setup_verification_action_summary_policy'; +import { validSetupBatchAssetPath } from '../setup_batch_policy'; +import { SETUP_VERIFICATION_ACTION_PATH as asset } from '../../../domain/setup_verification_action'; +import { importSetupOrganizationConfiguration } from '../setup_organization_import_policy'; +import { unavailableSetupRemoteConfiguration } from '../setup_remote_facts_policy'; +import type { SetupConfiguration } from '../../../domain/setup'; + +function question(configuration = createDefaultSetupConfiguration()) { + let state = createSetupQuestionnaire(configuration); + for (let i = 0; i < 200 && state.question?.id !== 'repository.verificationSetup'; i++) { + if (!state.question) throw new Error('verification setup question is missing'); + state = transitionSetupQuestionnaire(state, { kind: 'answer', value: '' }); + } + expect(state.question?.id).toBe('repository.verificationSetup'); return state; +} +describe('shared verification onboarding decisions', () => { + test('VSO-05 new and legacy configuration default to disabled in the shared boolean question', () => { + const config = createDefaultSetupConfiguration(); delete config.repository.verificationSetup; + const state = question(config); expect(state.question).toMatchObject({ kind: 'boolean', defaultValue: false }); + expect(setupBasicSkippedQuestionIds()).not.toContain('repository.verificationSetup'); + }); + test.each([true, false])('VSO-05 retains the preselected %s value when accepting the default', value => { + const config = createDefaultSetupConfiguration(); config.repository.verificationSetup = value; + const state = question(config); expect(state.question?.defaultValue).toBe(value); + expect(transitionSetupQuestionnaire(state, { kind: 'answer', value: '' }).draft.repository.verificationSetup).toBe(value); + }); + test.each([['yes', true], ['no', false]] as const)('VSO-04 answering %s drives the same Variable and Action input', (answer, expected) => { + const config = transitionSetupQuestionnaire(question(), { kind: 'answer', value: answer }).draft; + expect(config.repository.verificationSetup).toBe(expected); + expect(buildSetupRepositoryVariables(config)).toContainEqual({ name: 'VERIFICATION_SETUP', value: String(expected) }); + expect(buildSetupActionInputs(config)['verification-setup']).toBe(String(expected)); + }); + test('VSO-04 invalid activation input stays on the same question and retains the draft', () => { + const state = question(); const invalid = transitionSetupQuestionnaire(state, { kind: 'answer', value: '/arbitrary/setup' }); + expect(invalid.question?.id).toBe(state.question?.id); expect(invalid.validation).toBeTruthy(); expect(invalid.draft).toEqual(state.draft); + }); + test('VSO-04 revisiting activation retains the changed answer', () => { + const answered = transitionSetupQuestionnaire(question(), { kind: 'answer', value: 'yes' }); + const back = transitionSetupQuestionnaire(answered, { kind: 'back' }); + expect(back.question?.id).toBe('repository.verificationSetup'); expect(back.question?.defaultValue).toBe(true); + }); + test.each(['en', 'es', 'fr', 'pt'] as const)('VSO-06 %s guidance describes creation, customization, trusted main and real verification', locale => { + const content = setupQuestionPresentation(question().question!)[locale]; + expect(content.label).toBeTruthy(); expect(content.effect).toContain(asset); expect(content.verify).toContain('MAIN_BRANCH'); + expect(content.example).toContain('VERIFICATION_SETUP=false'); expect(content.documentation.url).toContain('#repository-owned-setup'); + expect(content.summary).not.toBe('repository.verificationSetup'); + }); + test('VSO-01 planned files and web drift guards include the exact fixed consumer action', () => { + const plan = buildSetupPlan(createDefaultSetupConfiguration()); expect(plan.selectedFiles).toContain(asset); expect(setupPlanGuardPaths(plan)).toContain(asset); + }); + test('VSO-06 older reviews without verification metadata have no fabricated outcome', () => expect(setupVerificationActionSummary()).toEqual([])); + test.each(['create', 'preserve', 'blocked'] as const)('VSO-06 %s summary states ownership, explicit activation and no readiness claim', action => { + const text = setupVerificationActionSummary({ action, enabled: true, mainBranch: '@mention' }).join('\n'); + expect(text).toContain(asset); expect(text).toContain('true (enabled)'); expect(text).toContain('MAIN_BRANCH'); expect(text).toContain('does not establish runtime readiness'); + expect(text).not.toContain(''); + }); + test('VSO-06 disabled summary never claims activation', () => { + expect(setupVerificationActionSummary({ action: 'create', enabled: false, mainBranch: 'main' }).join('\n')).toContain('false (disabled)'); + }); + test('VSO-10 permits only the fixed action entrypoint in batch inventory', () => { + expect(validSetupBatchAssetPath(asset)).toBe(true); + for (const other of [asset.replace('action.yml', 'other.sh'), asset.replace('action.yml', 'action.yaml'), '.github/actions/other/action.yml', `${asset}/extra`]) expect(validSetupBatchAssetPath(other)).toBe(false); + }); + test.each(['organization', 'repository', 'explicit'] as const)('VSO-05 respects %s activation precedence', scope => { + const config: SetupConfiguration = createDefaultSetupConfiguration(); config.repository.verificationSetup = false; + const result = importSetupOrganizationConfiguration({ configuration: config, + explicitQuestionIds: scope === 'explicit' ? ['repository.verificationSetup'] : [], + remote: { ...unavailableSetupRemoteConfiguration(), ownerType: 'Organization', repositoryVariablesAccess: 'available', organizationVariablesAccess: 'available', + organizationVariables: [{ name: 'VERIFICATION_SETUP', value: 'true' }], repositoryVariables: scope === 'repository' ? [{ name: 'VERIFICATION_SETUP', value: 'false' }] : [] } }); + expect(result.configuration.repository.verificationSetup).toBe(scope === 'organization'); + }); +}); diff --git a/src/application/policies/repository_agent_guidance_policy.ts b/src/application/policies/repository_agent_guidance_policy.ts index 9e3e3bdac..54da7a1a7 100644 --- a/src/application/policies/repository_agent_guidance_policy.ts +++ b/src/application/policies/repository_agent_guidance_policy.ts @@ -200,7 +200,7 @@ The setup runner profile selects placement; it does not install the project's la Declare reviewed version prefixes in \`.copilot/verification-prerequisites.json\` (schemaVersion 1, runtimes such as java 17, node 24, pnpm 10). Copilot checks declared versions in the credential-free verification environment before each configured verification command; a missing or incompatible runtime blocks publication. Without this optional declaration, existing verification behavior remains and no language is inferred. Java provisioning may use \`actions/setup-java\`; \`JAVA_HOME\` and \`PATH\` survive isolation, while agent credentials and tool-option injection variables do not. Do not add an unreviewed bootstrap or weaken verification to work around a missing runtime. Read [verification prerequisites and same-job setup](https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites). -The optional repository-owned composite action prepares each candidate before verification. Review \`.github/actions/copilot-verification-setup/action.yml\` and its assets onto trusted main, update generated workflows, then enable \`VERIFICATION_SETUP=true\` (Action input \`verification-setup\`, disabled by default). GitHub Actions executes the trusted snapshot before each command with a fresh private HOME; candidate changes cannot replace it. Native post steps finish before profile cleanup. Setup failure blocks verification and commit/push. The local CLI cannot execute composite actions and fails closed when opted in. Read [repository-owned setup](https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-owned-setup). +The optional repository-owned composite action prepares each candidate before verification. Setup creates .github/actions/copilot-verification-setup/action.yml only if missing and preserves an existing consumer action and its assets. The shared terminal/web assistant offers explicit activation, disabled by default. Customize the generated failing placeholder before enabling; setup generation and installer PRs do not prove runtime readiness. Review \`.github/actions/copilot-verification-setup/action.yml\` and its assets onto trusted main, update generated workflows, then enable \`VERIFICATION_SETUP=true\` (Action input \`verification-setup\`, disabled by default). GitHub Actions executes the trusted snapshot before each command with a fresh private HOME; candidate changes cannot replace it. Native post steps finish before profile cleanup. Setup failure blocks verification and commit/push. The local CLI cannot execute composite actions and fails closed when opted in. Read [repository-owned setup](https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-owned-setup). For the full contributor flow, read [repository collaboration](https://github.com/vypdev/copilot/blob/master/docs/agents/repository-collaboration.mdx). For drift and recovery, read [guidance troubleshooting](https://github.com/vypdev/copilot/blob/master/docs/agents/repository-guidance-troubleshooting.mdx). `; diff --git a/src/application/policies/setup_batch_policy.ts b/src/application/policies/setup_batch_policy.ts index 4bb25749a..1d2e5c9cf 100644 --- a/src/application/policies/setup_batch_policy.ts +++ b/src/application/policies/setup_batch_policy.ts @@ -1,5 +1,6 @@ import { SETUP_BATCH_MAX_TARGETS, type SetupBatchInstallationReceipt, type SetupBatchOperation, type SetupBatchPlan, type SetupBatchSharedResource, type SetupBatchTarget } from '../../domain/setup_batch'; +import { SETUP_VERIFICATION_ACTION_PATH } from '../../domain/setup_verification_action'; const uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u; const sha = /^[a-f0-9]{40}$/u; @@ -88,6 +89,7 @@ export function parseSetupBatchOperation(value: unknown): SetupBatchOperation { export function validSetupBatchAssetPath(path: string): boolean { if (path.length > 240 || path.split('/').some(part => !part || part === '.' || part === '..') || /[^A-Za-z0-9_./-]/u.test(path)) return false; return path === 'AGENTS.md' || path === '.agents/skills/copilot-repository-workflow/SKILL.md' + || path === SETUP_VERIFICATION_ACTION_PATH || /^\.github\/(?:workflows|ISSUE_TEMPLATE)\/[A-Za-z0-9_.-]+\.(?:yml|yaml)$/u.test(path) || path === '.github/pull_request_template.md' || /^\.copilot\/(?:repository-profile|setup-manifest|runner-profile)\.json$/u.test(path) || path === '.copilot/AGENT_GUIDE.md' || path.startsWith('.copilot/setup-backups/'); diff --git a/src/application/policies/setup_configuration_plan.ts b/src/application/policies/setup_configuration_plan.ts index 1a771cdcb..924c14e6a 100644 --- a/src/application/policies/setup_configuration_plan.ts +++ b/src/application/policies/setup_configuration_plan.ts @@ -15,6 +15,7 @@ import { buildSetupCredentialRequirements } from './setup_credential_requirement import { resolveLocaleProfile } from '../../domain/locale'; import { ISSUE_WORKFLOW_CATALOG, ISSUE_WORKFLOW_KINDS, issueWorkflowFormFiles, serializeIssueWorkflowProfile } from '../../domain/issue_workflow_profile'; import { effectiveIssueWorkflowFeatures, effectiveIssueWorkflowProfile } from './setup_issue_workflow_policy'; +import { SETUP_VERIFICATION_ACTION_PATH } from '../../domain/setup_verification_action'; import { REPOSITORY_AGENT_GUIDE_PATH, REPOSITORY_AGENT_MANIFEST_PATH, @@ -39,6 +40,7 @@ export function buildSetupPlan( .filter(file => configuration.features.release !== false || file !== 'release.yml') .filter(file => configuration.features.hotfix !== false || file !== 'hotfix.yml'); const selectedFiles = [ + SETUP_VERIFICATION_ACTION_PATH, ...(configuration.runners && configuration.runners.mode !== 'retain' ? ['.copilot/runner-profile.json'] : []), ...workflowFiles.map(file => `workflows/${file}`), ...issueTemplateFiles.map(file => `ISSUE_TEMPLATE/${file}`), diff --git a/src/application/policies/setup_question_documentation_policy.ts b/src/application/policies/setup_question_documentation_policy.ts index 9581bb463..5b1d92e12 100644 --- a/src/application/policies/setup_question_documentation_policy.ts +++ b/src/application/policies/setup_question_documentation_policy.ts @@ -45,6 +45,7 @@ export function setupQuestionDocumentation(question: Pick> = { }; const special: Readonly> = { + 'repository.verificationSetup': { summary: 'Activez l’action composite du projet avant chaque commande de vérification réelle.', when: 'Gardez cette option désactivée avant de définir et revoir les dépendances sur MAIN_BRANCH.', example: 'Non garde VERIFICATION_SETUP=false ; Oui active le hook sans installer de dépendances maintenant.', effect: 'Setup crée .github/actions/copilot-verification-setup/action.yml seulement si absent et conserve le fichier existant. Le modèle échoue avant personnalisation.', verify: 'Personnalisez, révisez et fusionnez sur MAIN_BRANCH, puis lancez une vraie vérification. Une PR d’installation ne prouve pas le fonctionnement.' }, 'agents.findings.executable': { summary: 'Choisissez la commande de l’agent sur le runner GitHub Actions, pas sur cet ordinateur.', when: 'Ne la changez que si un agent personnalisé est délibérément installé sur le runner.', example: 'Laissez vide pour codex, opencode ou agent selon le fournisseur.', effect: 'Le chemin personnalisé est utilisé pour les tâches choisies et n’est jamais installé automatiquement.', verify: 'Vérifiez que le runner possède exactement cet exécutable avant d’activer le workflow.' }, 'ai.includeReasoning': { summary: 'Demandez des explications supplémentaires si la réponse du fournisseur les contient.', when: 'Réservé aux diagnostics avancés ; le parcours CLI actuel ne fournit pas de parties de raisonnement séparées.', example: 'Laissez désactivé pour une configuration normale.', effect: 'Cela peut ajouter du texte du fournisseur, sans garantir des métadonnées brèves.', verify: 'Inspectez une réponse structurée contrôlée ; ne supposez pas que l’option a produit plus de texte.' }, 'ai.bugbotDryRun': { summary: 'Gardez Bugbot en mode analyse seule pour ses futures exécutions.', when: 'Utile pour une évaluation ; incompatible avec les preuves nécessaires à l’approbation.', example: 'Choisissez Non pour publier les revues normales.', effect: 'Bugbot analyse sans publier de résultat ni modifier le dépôt. Ce n’est pas setup --dry-run.', verify: 'Inspectez le résultat du workflow Bugbot : le mode analyse seule ne publie ni revue ni vérification.' }, diff --git a/src/application/policies/setup_question_guidance_policy.ts b/src/application/policies/setup_question_guidance_policy.ts index cfcb05ac4..715772528 100644 --- a/src/application/policies/setup_question_guidance_policy.ts +++ b/src/application/policies/setup_question_guidance_policy.ts @@ -24,6 +24,10 @@ const location: Readonly> = { + 'repository.verificationSetup': { + en: { summary: 'Enable the project-owned composite action before each real verification command.', when: 'Leave disabled until your project dependencies are defined and reviewed on the configured MAIN_BRANCH.', example: 'No keeps VERIFICATION_SETUP=false. Yes enables the existing hook; it does not infer or install dependencies now.', effect: 'Setup creates .github/actions/copilot-verification-setup/action.yml only if missing and preserves existing actions. The starter fails until customized.', verify: 'Customize the placeholder, review and merge on MAIN_BRANCH, then run an authorized modification or sync with verification. An installer PR is not runtime proof.' }, + es: { summary: 'Activa la acción compuesta del proyecto antes de cada comando real de verificación.', when: 'Déjala desactivada hasta definir y revisar las dependencias en la MAIN_BRANCH configurada.', example: 'No conserva VERIFICATION_SETUP=false. Sí activa el hook existente; ahora no se deducen ni instalan dependencias.', effect: 'Setup crea .github/actions/copilot-verification-setup/action.yml solo si falta y conserva las acciones existentes. La plantilla falla hasta personalizarla.', verify: 'Personaliza la plantilla, revisa y fusiona en MAIN_BRANCH y ejecuta una modificación o sincronización autorizada con verificación. Una PR de instalación no demuestra que el entorno funcione.' }, + }, 'agents.findings.executable': { en: { summary: 'Choose the agent command used on the GitHub Actions runner, not on this computer.', when: 'Only change this for a runner with a deliberately installed custom agent binary.', example: 'Leave empty for codex, opencode, or agent according to the provider.', effect: 'A custom path is shared unless a task has its own override; it is never installed automatically.', verify: 'Check the runner has this exact executable before enabling the workflow.' }, es: { summary: 'Elige el comando del agente en el runner de GitHub Actions, no en este ordenador.', when: 'Cámbialo solo si el runner tiene instalado expresamente otro binario.', example: 'Déjalo vacío para usar codex, opencode o agent según el proveedor.', effect: 'La ruta personalizada se comparte salvo que una tarea tenga su propia excepción; nunca se instala automáticamente.', verify: 'Comprueba que el runner tiene exactamente ese ejecutable.' }, diff --git a/src/application/policies/setup_question_guidance_pt.ts b/src/application/policies/setup_question_guidance_pt.ts index 32c3a7f28..732b656d4 100644 --- a/src/application/policies/setup_question_guidance_pt.ts +++ b/src/application/policies/setup_question_guidance_pt.ts @@ -34,6 +34,7 @@ const section: Readonly> = { }; const special: Readonly> = { + 'repository.verificationSetup': { summary: 'Ative a ação composta do projeto antes de cada comando real de verificação.', when: 'Mantenha desativado até definir e rever as dependências na MAIN_BRANCH configurada.', example: 'Não mantém VERIFICATION_SETUP=false; Sim ativa o hook sem instalar dependências agora.', effect: 'Setup cria .github/actions/copilot-verification-setup/action.yml só se faltar e preserva o existente. O modelo falha até ser personalizado.', verify: 'Personalize, reveja e faça merge na MAIN_BRANCH, depois execute uma verificação real. Uma PR de instalação não comprova o funcionamento.' }, 'agents.findings.executable': { summary: 'Escolha o comando do agente no runner GitHub Actions, não neste computador.', when: 'Altere-o apenas se tiver instalado deliberadamente outro agente no runner.', example: 'Deixe vazio para codex, opencode ou agent, conforme o fornecedor.', effect: 'O caminho personalizado é usado pelas tarefas escolhidas e nunca é instalado automaticamente.', verify: 'Confirme que o runner tem exatamente este executável antes de ativar o fluxo.' }, 'ai.includeReasoning': { summary: 'Peça explicações adicionais se a resposta do fornecedor as disponibilizar.', when: 'Só para diagnóstico avançado; o percurso CLI atual não fornece partes de raciocínio separadas.', example: 'Mantenha desativado numa configuração normal.', effect: 'Pode acrescentar texto do fornecedor, sem garantir metadados breves.', verify: 'Inspecione uma resposta estruturada controlada; não presuma que a opção produziu texto adicional.' }, 'ai.bugbotDryRun': { summary: 'Mantenha o Bugbot em modo apenas de análise nas próximas execuções.', when: 'Útil numa avaliação; incompatível com provas de aprovação.', example: 'Escolha Não para publicar revisões normais.', effect: 'O Bugbot analisa sem publicar resultados nem alterar o repositório. Não é setup --dry-run.', verify: 'Inspecione o resultado do fluxo Bugbot: a simulação não publica revisão nem verificação.' }, diff --git a/src/application/policies/setup_question_labels/fr.ts b/src/application/policies/setup_question_labels/fr.ts index dc8185457..49d288c11 100644 --- a/src/application/policies/setup_question_labels/fr.ts +++ b/src/application/policies/setup_question_labels/fr.ts @@ -2,6 +2,7 @@ import type { spanishQuestionLabels } from '../setup_question_translations'; /** French presentation labels; semantic question IDs remain unchanged. */ export const questionLabelsFr: Readonly> = { + 'repository.verificationSetup': 'Préparer les dépendances avec l’action de vérification du dépôt ?', 'features.issues': 'Automatiser les tickets : branches, étiquettes, projets et cycle de vie', 'features.pullRequests': 'Automatiser les pull requests : revue, description et cycle de vie', 'features.commits': 'Automatiser les commits : progression, taille et analyse Bugbot', diff --git a/src/application/policies/setup_question_labels/pt.ts b/src/application/policies/setup_question_labels/pt.ts index d3173436c..608b36146 100644 --- a/src/application/policies/setup_question_labels/pt.ts +++ b/src/application/policies/setup_question_labels/pt.ts @@ -2,6 +2,7 @@ import type { spanishQuestionLabels } from '../setup_question_translations'; /** Portuguese presentation labels; semantic question IDs remain unchanged. */ export const questionLabelsPt: Readonly> = { + 'repository.verificationSetup': 'Preparar dependências com a ação de verificação do repositório?', 'features.issues': 'Automatizar questões: ramos, etiquetas, projetos e ciclo de vida', 'features.pullRequests': 'Automatizar pull requests: revisão, descrição e ciclo de vida', 'features.commits': 'Automatizar commits: progresso, tamanho e análise do Bugbot', diff --git a/src/application/policies/setup_question_purpose/fr.ts b/src/application/policies/setup_question_purpose/fr.ts index 072b6ec70..eb0d2dba2 100644 --- a/src/application/policies/setup_question_purpose/fr.ts +++ b/src/application/policies/setup_question_purpose/fr.ts @@ -1,5 +1,6 @@ /** French question-specific purposes. */ export const purposesFr: Readonly> = { + 'repository.verificationSetup': 'Activez la préparation des dépendances du dépôt avant la vérification ; personnalisez et révisez le modèle sur MAIN_BRANCH au préalable.', 'issueWorkflows.enabled': 'Choisissez les workflows de ticket que Copilot pourra exécuter ; chacun agit différemment sur les branches, étiquettes et automatisations.', 'repositoryAgentGuidance.enabled': 'Générez des instructions pour aider les agents IA à travailler en sécurité dans ce projet.', 'repositoryAgentGuidance.agentsPointer': 'Décidez si le fichier AGENTS.md racine renvoie aux instructions générées, est créé s’il manque, ou reste intact.', diff --git a/src/application/policies/setup_question_purpose/pt.ts b/src/application/policies/setup_question_purpose/pt.ts index 94580ee9a..24af34095 100644 --- a/src/application/policies/setup_question_purpose/pt.ts +++ b/src/application/policies/setup_question_purpose/pt.ts @@ -1,5 +1,6 @@ /** Portuguese question-specific purposes. */ export const purposesPt: Readonly> = { + 'repository.verificationSetup': 'Ative a preparação das dependências antes da verificação; personalize e reveja o modelo na MAIN_BRANCH primeiro.', 'issueWorkflows.enabled': 'Escolha os fluxos de questões que o Copilot poderá executar; cada um afeta de forma diferente ramos, etiquetas e automatizações.', 'repositoryAgentGuidance.enabled': 'Gere instruções para ajudar os agentes de IA a trabalhar com segurança neste projeto.', 'repositoryAgentGuidance.agentsPointer': 'Decida se o AGENTS.md da raiz aponta para as instruções geradas, é criado se faltar ou permanece intacto.', diff --git a/src/application/policies/setup_question_purpose_policy.ts b/src/application/policies/setup_question_purpose_policy.ts index 0d0f80852..86602382e 100644 --- a/src/application/policies/setup_question_purpose_policy.ts +++ b/src/application/policies/setup_question_purpose_policy.ts @@ -5,6 +5,7 @@ type Purpose = Readonly<{ en: string; es: string }>; /** Field-specific meaning for choices whose label alone is easy to misinterpret. */ export const setupQuestionPurposes: Readonly> = { + 'repository.verificationSetup': { en: 'Enable the repository-owned dependency setup before verification. The starter must be customized and reviewed on MAIN_BRANCH first.', es: 'Activa la preparación de dependencias del repositorio antes de verificar. Primero personaliza y revisa la plantilla en MAIN_BRANCH.' }, 'issueWorkflows.enabled': { en: 'Choose the issue workflows Copilot may run; each type has different branch, label and automation effects.', es: 'Elige los flujos de issues que podrá ejecutar Copilot; cada tipo tiene efectos distintos sobre ramas, etiquetas y automatización.' }, 'repositoryAgentGuidance.enabled': { en: 'Generate repository instructions that tell AI agents how to work safely in this project.', es: 'Genera instrucciones para que los agentes de IA trabajen con seguridad en este proyecto.' }, 'repositoryAgentGuidance.agentsPointer': { en: 'Choose whether the root AGENTS.md points to generated instructions, is created if missing, or stays untouched.', es: 'Elige si el AGENTS.md raíz apunta a las instrucciones generadas, se crea si falta o permanece intacto.' }, diff --git a/src/application/policies/setup_question_translations.ts b/src/application/policies/setup_question_translations.ts index 025d05ad9..27816339a 100644 --- a/src/application/policies/setup_question_translations.ts +++ b/src/application/policies/setup_question_translations.ts @@ -1,6 +1,7 @@ import type { SetupQuestion } from '../../domain/setup_questionnaire'; export const spanishQuestionLabels: Readonly> = { + 'repository.verificationSetup': '¿Preparar dependencias con la acción de verificación del repositorio?', 'features.issues': 'Automatizar issues: ramas, etiquetas, proyectos y ciclo de vida', 'features.pullRequests': 'Automatizar pull requests: revisión, descripción y ciclo de vida', 'features.commits': 'Automatizar commits: progreso, tamaño y análisis de Bugbot', diff --git a/src/application/policies/setup_questionnaire_policy.ts b/src/application/policies/setup_questionnaire_policy.ts index 98803b62a..a6ae16804 100644 --- a/src/application/policies/setup_questionnaire_policy.ts +++ b/src/application/policies/setup_questionnaire_policy.ts @@ -384,6 +384,7 @@ function repositoryQuestions(): QuestionDefinition[] { ['choreTree', 'Chore branch prefix', 'text'], ['issueManagedBranches', 'Let the Action create linked branches after in-progress?', 'boolean'], ['preBranchSdd', 'Require an SDD before feature and contract-change branches?', 'boolean'], + ['verificationSetup', 'Prepare dependencies with the repository verification setup action?', 'boolean'], ['reopenIssueOnPush', 'Reopen closed issues when a related branch receives a push?', 'boolean'], ['desiredAssigneesCount', 'Desired issue assignees (0 disables automatic assignment)', 'number'], ['desiredReviewersCount', 'Desired pull-request reviewers (0 disables automatic assignment)', 'number'], @@ -573,6 +574,7 @@ function readPath( path: string, allowedNames?: readonly string[], ): string | number | boolean { + if (path === 'repository.verificationSetup') return configuration.repository.verificationSetup ?? false; const value = path.split('.').reduce((current, key) => (current as Record)[key], configuration); if (path.endsWith('.overrides')) { diff --git a/src/application/policies/setup_runner_installation_summary_policy.ts b/src/application/policies/setup_runner_installation_summary_policy.ts index 28774b857..bcd0c92ad 100644 --- a/src/application/policies/setup_runner_installation_summary_policy.ts +++ b/src/application/policies/setup_runner_installation_summary_policy.ts @@ -1,6 +1,7 @@ import type { SetupBatchTargetPlan } from '../../domain/setup_batch'; import { selectedSetupRunsOn } from './setup_runner_policy'; import type { SetupRunsOn } from '../../domain/setup_runner'; +import { setupVerificationActionSummary } from './setup_verification_action_summary_policy'; function routeBlock(route: SetupRunsOn): readonly string[] { const json = JSON.stringify(route, null, 2); @@ -25,5 +26,6 @@ export function setupRunnerInstallationSummary(plan: SetupBatchTargetPlan): stri `**Parity:** ${assets.filter(asset => asset.status === 'source-only').length} source extensions; ${assets.filter(asset => asset.status === 'missing').length} missing assets (including disabled optional capabilities); ${assets.filter(asset => asset.status === 'customized').length} customized; ${assets.filter(asset => asset.status === 'incompatible').length} incompatible metadata retained or blocked before regeneration.`, 'Inspect the complete Files changed view and `.copilot/runner-profile.json`. Any replacements retain setup backups under `.copilot/setup-backups/`.', 'Runner access, capacity and agent authentication are separate. Selection grants no group access and never falls back to another runner. Human merge and actual trusted workflow verification remain pending.', + ...setupVerificationActionSummary(review?.verificationSetup), ].join('\n'); } diff --git a/src/application/policies/setup_verification_action_summary_policy.ts b/src/application/policies/setup_verification_action_summary_policy.ts new file mode 100644 index 000000000..6c4caa153 --- /dev/null +++ b/src/application/policies/setup_verification_action_summary_policy.ts @@ -0,0 +1,11 @@ +import type { SetupVerificationActionReview } from '../../domain/setup_verification_action'; +import { SETUP_VERIFICATION_ACTION_PATH } from '../../domain/setup_verification_action'; + +/** Shared terminal/installation-PR copy contains no repository-controlled Markdown. */ +export function setupVerificationActionSummary(review?: SetupVerificationActionReview): readonly string[] { + if (!review) return []; + const outcomes = { create: 'Create the starter only if missing', preserve: 'Preserve the existing consumer action byte-for-byte', blocked: 'Blocked: inspect the unsafe action path' }; + return ['Verification setup', `${outcomes[review.action]}: ${SETUP_VERIFICATION_ACTION_PATH}.`, + `VERIFICATION_SETUP=${review.enabled ? 'true (enabled)' : 'false (disabled)'}.`, + 'The generated placeholder fails until customized. Review and merge project dependency setup onto configured MAIN_BRANCH, then run a real verification. Setup or an installer PR does not establish runtime readiness.']; +} diff --git a/src/application/ports/setup_workspace_ports.ts b/src/application/ports/setup_workspace_ports.ts index 7c8fcfbf4..4c68780ac 100644 --- a/src/application/ports/setup_workspace_ports.ts +++ b/src/application/ports/setup_workspace_ports.ts @@ -6,6 +6,7 @@ export interface SetupWorkspaceResult { } export interface SetupWorkspaceSelection { + verificationActionState?: import('../../domain/setup_verification_action').SetupVerificationActionState; features?: SetupFeatures; updateExistingWorkflows?: boolean; approvedWorkflowFiles?: readonly string[]; diff --git a/src/application/usecases/__tests__/push_single_action_contexts.test.ts b/src/application/usecases/__tests__/push_single_action_contexts.test.ts index 678d5f69d..f0e6a8326 100644 --- a/src/application/usecases/__tests__/push_single_action_contexts.test.ts +++ b/src/application/usecases/__tests__/push_single_action_contexts.test.ts @@ -487,3 +487,8 @@ describe('push and single-action context projection', () => { expect(withoutOperation.currentConfiguration.deploymentOrchestration).toBeUndefined(); }); }); + +test.each(['create', 'preserve', 'invalid', undefined])('VSO-09 projects only the reviewed action state %s', state => { + const value = source(); value.inputs!.setupVerificationActionState = state; + expect(projectInitialSetupContext(value).verificationActionState).toBe(state === 'create' || state === 'preserve' ? state : undefined); +}); diff --git a/src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts b/src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts index f0349846f..548aa570a 100644 --- a/src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts +++ b/src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts @@ -124,6 +124,20 @@ describe('InitialSetupUseCase', () => { expect(mockSetupPrepare).toHaveBeenCalledTimes(1); expect(mockSetupHasValidToken).toHaveBeenCalledTimes(1); }); + it.each(['create', 'preserve'] as const)('VSO-09 carries reviewed %s intent to the workspace and reports its completed outcome', async state => { + const config = createDefaultSetupConfiguration(); config.manageRepositorySecrets = false; config.manageRepositoryVariables = false; + config.repository.verificationSetup = state === 'preserve'; + const results = await useCase.invoke(baseParam({ inputs: { setupConfiguration: config, setupVerificationActionState: state } })); + expect(mockSetupPrepare).toHaveBeenCalledWith(expect.objectContaining({ verificationActionState: state })); + expect(results[0].success).toBe(true); + expect(results[0].steps).toContainEqual(expect.stringContaining(`Verification setup action ${state === 'create' ? 'created' : 'preserved'}; VERIFICATION_SETUP=${state === 'preserve'}`)); + }); + it('VSO-09 stops a stale action plan before writing Variables or provisioning issue resources', async () => { + mockSetupPrepare.mockImplementationOnce(() => { throw new Error('Verification action changed after review'); }); + const results = await useCase.invoke(baseParam({ inputs: { setupVerificationActionState: 'create' } })); + expect(results[0].success).toBe(false); expect(mockSetupVariablesUpsert).not.toHaveBeenCalled(); expect(mockEnsureInitialLabels).not.toHaveBeenCalled(); + expect(results[0].steps).not.toContainEqual(expect.stringContaining('Verification setup action created')); + }); it('returns failure and does not continue when hasValidSetupToken is false', async () => { mockSetupHasValidToken.mockReturnValue(false); diff --git a/src/application/usecases/actions/initial_setup_workflow.ts b/src/application/usecases/actions/initial_setup_workflow.ts index 9904029e5..5ef85b8fa 100644 --- a/src/application/usecases/actions/initial_setup_workflow.ts +++ b/src/application/usecases/actions/initial_setup_workflow.ts @@ -132,6 +132,7 @@ export async function runInitialSetupWorkflow( logInfo('📋 Ensuring .github and copying setup files...'); const workspaceSelection = { + ...(request.verificationActionState ? { verificationActionState: request.verificationActionState } : {}), features: setupConfiguration?.features, setupConfiguration, ...(request.workflowUpdates.length > 0 ? { @@ -143,6 +144,7 @@ export async function runInitialSetupWorkflow( const filesResult = dependencies.setupWorkspacePort.prepare(workspaceSelection); mark('files', filesResult.copied > 0 ? 'completed' : 'skipped'); steps.push(`✅ Setup files: ${filesResult.copied} copied, ${filesResult.skipped} already existed`); + if (request.verificationActionState) steps.push(`✅ Verification setup action ${request.verificationActionState === 'create' ? 'created' : 'preserved'}; VERIFICATION_SETUP=${setupConfiguration?.repository.verificationSetup ?? false}. Customize and review on MAIN_BRANCH, then run a real verification.`); if (setupConfiguration?.manageRepositorySecrets && secretValues > 0) mark('secrets', 'in-progress'); const secrets = await ensureRepositorySecrets(request, dependencies, setupConfiguration, remoteConfiguration); diff --git a/src/application/usecases/push_single_action_contexts.ts b/src/application/usecases/push_single_action_contexts.ts index 0a64b42f6..9b312357a 100644 --- a/src/application/usecases/push_single_action_contexts.ts +++ b/src/application/usecases/push_single_action_contexts.ts @@ -124,6 +124,7 @@ export interface AgentActivityOutcome { } export interface InitialSetupContext { + readonly verificationActionState?: import('../../domain/setup_verification_action').SetupVerificationActionState; readonly setupConfigurationSource?: 'organization' | 'customize'; readonly labels: InitialLabelConfiguration; readonly issueTypes: InitialIssueTypeConfiguration; @@ -157,6 +158,7 @@ export interface PushSingleActionContextSource { readonly setupCredentials?: unknown; readonly setupRemoteConfiguration?: unknown; readonly setupWorkflowUpdates?: unknown; + readonly setupVerificationActionState?: unknown; }; readonly commit: { readonly branch: string }; readonly currentConfiguration: { @@ -388,6 +390,8 @@ export function projectInitialSetupContext(source: PushSingleActionContextSource ...(credentials ? { setupCredentials: deepFreezeCopy(credentials) } : {}), ...(remote ? { setupRemoteConfiguration: deepFreezeCopy(remote) } : {}), workflowUpdates: Object.freeze(asStringArray(source.inputs?.setupWorkflowUpdates)), + ...(source.inputs?.setupVerificationActionState === 'create' || source.inputs?.setupVerificationActionState === 'preserve' + ? { verificationActionState: source.inputs.setupVerificationActionState } : {}), }); } diff --git a/src/application/usecases/setup/__tests__/setup_verification_onboarding_flow.test.ts b/src/application/usecases/setup/__tests__/setup_verification_onboarding_flow.test.ts new file mode 100644 index 000000000..2acdbb6af --- /dev/null +++ b/src/application/usecases/setup/__tests__/setup_verification_onboarding_flow.test.ts @@ -0,0 +1,21 @@ +import fs from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { SetupWizardUseCase } from '../setup_wizard_use_case'; +import { inspectSetupInstallation } from '../../../../utils/setup_installation_review'; +import { createDefaultSetupConfiguration } from '../../../policies/setup_configuration_defaults'; +describe('verification onboarding no-write exits', () => { + let root: string; + beforeEach(() => { root = fs.mkdtempSync(join(tmpdir(), 'copilot-verification-preview-')); }); + afterEach(() => fs.rmSync(root, { recursive: true, force: true })); + test.each(['approved', 'declined', 'cancelled'] as const)('VSO-07 %s preview never creates a starter or runs permission writes', async kind => { + const audit = jest.fn(); const present = jest.fn(); + const usecase = new SetupWizardUseCase({ planPresenter: { present }, confirmation: { confirm: async () => ({ kind }) }, + finalPermissionAudit: { audit }, installationReview: { inspect: async configuration => inspectSetupInstallation(root, configuration) } }); + const config = createDefaultSetupConfiguration(); config.repository.verificationSetup = true; config.pullRequestApproval = { ...config.pullRequestApproval, mode: 'off' }; + const result = await usecase.execute({ mode: 'non-interactive', previewOnly: true, skipRepositoryVariables: true, skipRepositorySecrets: true, overrides: config }); + expect(result.status).toBe(kind === 'approved' ? 'completed' : 'cancelled'); + expect(present.mock.calls[0][0].installationReview.verificationSetup).toMatchObject({ action: 'create', enabled: true }); + expect(audit).not.toHaveBeenCalled(); expect(fs.readdirSync(root)).toEqual([]); + }); +}); diff --git a/src/cli/__tests__/setup_documentation_navigation.test.ts b/src/cli/__tests__/setup_documentation_navigation.test.ts index 0e8258de5..c4e6d9dc9 100644 --- a/src/cli/__tests__/setup_documentation_navigation.test.ts +++ b/src/cli/__tests__/setup_documentation_navigation.test.ts @@ -25,7 +25,7 @@ describe('setup documentation navigation', () => { expect(html).toContain(title); expect(html).toContain(hint); for (const url of Object.values(SETUP_DOCUMENTATION)) expect(html).toContain(`href="${url}"`); - expect(html.match(/target="_blank" rel="noopener noreferrer"/gu)).toHaveLength(3); + expect(html.match(/target="_blank" rel="noopener noreferrer"/gu)).toHaveLength(4); expect(html).not.toContain(' { + test.each(['en', 'es', 'fr', 'pt'] as const)('VSO-06 %s plan exposes create, disabled, main branch and real verification guidance', async locale => { + const review = { ...empty, verificationSetup: { action: 'create' as const, enabled: false, mainBranch: 'production' } }; + const html = await markup('InstallationReview', { review }, locale); + for (const key of ['title', 'create', 'disabled', 'main', 'next'] as const) expect(html).toContain(verificationSetupText(key, locale)); + expect(html).toContain('production'); expect(html).toContain('.github/actions/copilot-verification-setup/action.yml'); + }); + test.each(['preserve', 'blocked'] as const)('VSO-06 %s plan shows enabled state and escapes a repository-controlled branch', async action => { + const review = { ...empty, verificationSetup: { action, enabled: true, mainBranch: '' } }; + const html = await markup('InstallationReview', { review }); + expect(html).toContain(verificationSetupText(action, 'en')); expect(html).toContain(verificationSetupText('enabled', 'en')); + expect(html).toContain('<script>'); expect(html).not.toContain('

{tr('botRenewal', $setupLocale)}

+

{verificationSetupText('result', $setupLocale)} {verificationSetupText('guide', $setupLocale)} ↗

{tr('setupNextWorkflow', $setupLocale)} {tr('firstWorkflowGuide', $setupLocale)} ↗

diff --git a/web/src/components/InstallationReview.svelte b/web/src/components/InstallationReview.svelte index 0cb0b288f..625e1f59e 100644 --- a/web/src/components/InstallationReview.svelte +++ b/web/src/components/InstallationReview.svelte @@ -2,9 +2,17 @@ import type { WebSetupPlan } from '../../../src/application/contracts/web_setup_view'; import { runnerText } from '../i18n/runnerCopy'; import { setupLocale } from '../i18n/localeStore'; + import { verificationSetupText } from '../i18n/verificationSetupCopy'; export let review: NonNullable;
+ {#if review.verificationSetup}
+

{verificationSetupText('title', $setupLocale)}

+

{verificationSetupText(review.verificationSetup.action, $setupLocale)}: .github/actions/copilot-verification-setup/action.yml

+

{verificationSetupText(review.verificationSetup.enabled ? 'enabled' : 'disabled', $setupLocale)}

+

{verificationSetupText('main', $setupLocale)}: {review.verificationSetup.mainBranch}

+

{verificationSetupText('next', $setupLocale)}

+
{/if}

{runnerText('title', $setupLocale)}

{runnerText('help', $setupLocale)}

{#if review.blockers.length}

{runnerText('blockedAction', $setupLocale)}

{runnerText('blockers', $setupLocale)}
    {#each review.blockers as blocker}
  • {blocker}
  • {/each}
{/if} diff --git a/web/src/components/SetupHelp.svelte b/web/src/components/SetupHelp.svelte index b7c4bf399..e78c8bed7 100644 --- a/web/src/components/SetupHelp.svelte +++ b/web/src/components/SetupHelp.svelte @@ -2,6 +2,7 @@ import { SETUP_DOCUMENTATION } from '../../../src/application/contracts/setup_documentation'; import { tr } from '../i18n/catalog'; import { setupLocale } from '../i18n/localeStore'; + import { verificationSetupText } from '../i18n/verificationSetupCopy'; diff --git a/web/src/i18n/verificationSetupCopy.ts b/web/src/i18n/verificationSetupCopy.ts new file mode 100644 index 000000000..0d8ae542b --- /dev/null +++ b/web/src/i18n/verificationSetupCopy.ts @@ -0,0 +1,8 @@ +import type { SetupLocale } from './catalog'; +const copy = { + en: { title: 'Verification setup', create: 'Create the starter only if missing', preserve: 'Preserve the existing project action byte-for-byte', blocked: 'Blocked: inspect the unsafe action path', enabled: 'VERIFICATION_SETUP: enabled', disabled: 'VERIFICATION_SETUP: disabled', main: 'Trusted main branch', next: 'The starter fails until customized. Review and merge the project dependencies onto configured MAIN_BRANCH, then run a real verification. An installer PR does not prove runtime readiness.', result: 'Inspect .github/actions/copilot-verification-setup/action.yml. Setup creates it only if missing and preserves existing project actions. Customize the placeholder and review on MAIN_BRANCH before enabling VERIFICATION_SETUP, then run a real verification.', guide: 'Verification setup and upgrade guide' }, + es: { title: 'Preparación de la verificación', create: 'Crear la plantilla solo si falta', preserve: 'Conservar intacta la acción existente del proyecto', blocked: 'Bloqueado: revisa la ruta insegura de la acción', enabled: 'VERIFICATION_SETUP: activado', disabled: 'VERIFICATION_SETUP: desactivado', main: 'Rama principal de confianza', next: 'La plantilla falla hasta personalizarla. Revisa y fusiona las dependencias del proyecto en la MAIN_BRANCH configurada y ejecuta una verificación real. Una PR de instalación no demuestra que el entorno funcione.', result: 'Revisa .github/actions/copilot-verification-setup/action.yml. Setup lo crea solo si falta y conserva la acción existente. Personaliza la plantilla y revísala en MAIN_BRANCH antes de activar VERIFICATION_SETUP; después ejecuta una verificación real.', guide: 'Guía de preparación y actualización de la verificación' }, + fr: { title: 'Préparation de la vérification', create: 'Créer le modèle seulement si absent', preserve: 'Conserver intégralement l’action existante du projet', blocked: 'Bloqué : inspectez le chemin non sûr de l’action', enabled: 'VERIFICATION_SETUP : activé', disabled: 'VERIFICATION_SETUP : désactivé', main: 'Branche principale de confiance', next: 'Le modèle échoue avant personnalisation. Révisez et fusionnez les dépendances du projet sur MAIN_BRANCH, puis lancez une vraie vérification. Une PR d’installation ne prouve pas le fonctionnement.', result: 'Inspectez .github/actions/copilot-verification-setup/action.yml. Setup le crée seulement si absent et conserve l’action existante. Personnalisez et révisez le modèle sur MAIN_BRANCH avant d’activer VERIFICATION_SETUP, puis lancez une vraie vérification.', guide: 'Guide de préparation et de mise à niveau de la vérification' }, + pt: { title: 'Preparação da verificação', create: 'Criar o modelo só se faltar', preserve: 'Preservar integralmente a ação existente do projeto', blocked: 'Bloqueado: inspecione o caminho inseguro da ação', enabled: 'VERIFICATION_SETUP: ativo', disabled: 'VERIFICATION_SETUP: desativado', main: 'Ramo principal de confiança', next: 'O modelo falha até ser personalizado. Reveja e faça merge das dependências na MAIN_BRANCH configurada, depois execute uma verificação real. Uma PR de instalação não comprova o funcionamento.', result: 'Inspecione .github/actions/copilot-verification-setup/action.yml. Setup cria-o só se faltar e preserva a ação existente. Personalize e reveja o modelo na MAIN_BRANCH antes de ativar VERIFICATION_SETUP, depois execute uma verificação real.', guide: 'Guia de preparação e atualização da verificação' }, +} as const; +export function verificationSetupText(key: keyof typeof copy.en, locale: SetupLocale): string { return copy[locale][key]; } From a8f8dbba6d9956063c3fbdd0d42d24be8d2eb639 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 20:16:41 +0200 Subject: [PATCH 32/44] bugfix-653-bug-generated-companion-sdd-publishes-colliding-case-ids-and-inconsistent-acceptance-mappings: preserve fenced SDD content until a valid closing marker --- build/cli/index.js | 29 +++++++++++---- build/github_action/index.js | 29 +++++++++++---- docs/issues/pre-branch-sdds.mdx | 6 ++++ specs/pre-branch-sdd-gate.md | 25 ++++++++++--- .../__tests__/sdd_draft_consistency.test.ts | 36 +++++++++++++++++++ src/domain/sdd_draft_consistency.ts | 23 +++++++++--- .../pre_branch_sdd_workspace_adapter.test.ts | 12 +++++++ 7 files changed, 138 insertions(+), 22 deletions(-) diff --git a/build/cli/index.js b/build/cli/index.js index 5ee4d1497..eefac3f27 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -93219,16 +93219,33 @@ function fail(reason) { /** Excludes examples and hidden records from the contract. */ function visible(source) { let fence; - return source.replace(/|$)/gu, '\n').replace(/\r\n/gu, '\n').split('\n').map(line => { + let comment = false; + return source.replace(/\r\n/gu, '\n').split('\n').map(line => { const boundary = /^\s*(`{3,}|~{3,})/u.exec(line); - if (boundary) { - if (!fence) - fence = boundary[1]; - else if (boundary[1][0] === fence[0] && boundary[1].length >= fence.length) + if (fence) { + // Comment syntax inside code is literal; only the original line can close it. + if (boundary && boundary[1][0] === fence[0] && boundary[1].length >= fence.length + && /^ {0,3}(?:`+|~+)[ \t]*$/u.test(line)) fence = undefined; return ''; } - return fence ? '' : line; + if (!comment && boundary) { + fence = boundary[1]; + return ''; + } + let result = ''; + let offset = 0; + while (offset < line.length) { + const marker = comment ? '-->' : '|$)/gu, '\n').replace(/\r\n/gu, '\n').split('\n').map(line => { + let comment = false; + return source.replace(/\r\n/gu, '\n').split('\n').map(line => { const boundary = /^\s*(`{3,}|~{3,})/u.exec(line); - if (boundary) { - if (!fence) - fence = boundary[1]; - else if (boundary[1][0] === fence[0] && boundary[1].length >= fence.length) + if (fence) { + // Comment syntax inside code is literal; only the original line can close it. + if (boundary && boundary[1][0] === fence[0] && boundary[1].length >= fence.length + && /^ {0,3}(?:`+|~+)[ \t]*$/u.test(line)) fence = undefined; return ''; } - return fence ? '' : line; + if (!comment && boundary) { + fence = boundary[1]; + return ''; + } + let result = ''; + let offset = 0; + while (offset < line.length) { + const marker = comment ? '-->' : '\n${sddConsistencyFixture()}`; + expect(() => validate(markdown)).toThrow(expect.objectContaining({ reason: 'requirement-mapping' })); + }); + + it('keeps comment syntax literal inside a fence so it cannot hide the visible contract after the close', () => { + expect(() => validate('```md\n\n' + sddConsistencyFixture())).not.toThrow(); + }); + + it('keeps owner identities around multiple inline comments while excluding their hidden identities', () => { + const markdown = 'first-C01middle-C01final-C01'; + expect(reservedSddCaseIds([{ path: 'specs/examples.md', markdown }])).toEqual(['final-C01', 'first-C01', 'middle-C01']); + }); + + it('does not let an unclosed HTML comment expose its contract', () => { + expect(() => validate(`|$)/gu, '\n').replace(/\r\n/gu, '\n').split('\n').map(line => { + let comment = false; + return source.replace(/\r\n/gu, '\n').split('\n').map(line => { const boundary = /^\s*(`{3,}|~{3,})/u.exec(line); - if (boundary) { - if (!fence) fence = boundary[1]; - else if (boundary[1][0] === fence[0] && boundary[1].length >= fence.length) fence = undefined; + if (fence) { + // Comment syntax inside code is literal; only the original line can close it. + if (boundary && boundary[1][0] === fence[0] && boundary[1].length >= fence.length + && /^ {0,3}(?:`+|~+)[ \t]*$/u.test(line)) fence = undefined; return ''; } - return fence ? '' : line; + if (!comment && boundary) { fence = boundary[1]; return ''; } + let result = ''; + let offset = 0; + while (offset < line.length) { + const marker = comment ? '-->' : '\n```md\nexample-C01\n```' }])) .toEqual(['payments-C01', 'payments-session-C09']); diff --git a/src/domain/sdd_draft_consistency.ts b/src/domain/sdd_draft_consistency.ts index ba2d21b64..e92ab6fd8 100644 --- a/src/domain/sdd_draft_consistency.ts +++ b/src/domain/sdd_draft_consistency.ts @@ -187,7 +187,7 @@ function validatePaths(source: string, inventory: SddRepositoryInventory, sddPat }; // Relative Markdown file links resolve against the selected SDD, never the current checkout. for (const match of source.matchAll(/\]\(([^\s)]+)\)/gu)) { - const href = match[1].split('#')[0]; + const href = match[1].split(/[?#]/u)[0]; if (!href || /^(?:[a-z][a-z0-9+.-]*:|\/)/iu.test(href)) continue; let decoded: string; try { decoded = decodeURIComponent(href); } catch { return fail('repository-path'); } diff --git a/src/infrastructure/__tests__/pre_branch_sdd_workspace_adapter.test.ts b/src/infrastructure/__tests__/pre_branch_sdd_workspace_adapter.test.ts index 535c4bede..d33439208 100644 --- a/src/infrastructure/__tests__/pre_branch_sdd_workspace_adapter.test.ts +++ b/src/infrastructure/__tests__/pre_branch_sdd_workspace_adapter.test.ts @@ -95,6 +95,17 @@ describe('PreBranchSddWorkspaceAdapter with a local bare remote', () => { expect(git(repo, 'worktree', 'list', '--porcelain').match(/^worktree /gm)).toHaveLength(1); }); + it.each(['update', 'companion'] as const)('validates %s links with queries against immutable files and explicitly proposed SDDs', async action => { + const workspace = new PreBranchSddWorkspaceAdapter(repo); + const snapshot = await workspace.loadSnapshot('develop'); + const selected = { ...plan, action, path: action === 'update' ? plan.path : 'specs/companion.md' }; + const markdown = draft(selected.path, action) + `\n[Guide](../docs/payments.mdx?view=compact#intro) and [SDD](./${path.basename(selected.path)}?draft=1)`; + const prepared = await workspace.validateDraft(snapshot, selected, markdown); + expect(prepared.markdown).toContain('[Guide](../docs/payments.mdx?view=compact#intro)'); + expect(git(repo, 'status', '--porcelain')).toBe(''); + expect(git(repo, 'worktree', 'list', '--porcelain').match(/^worktree /gm)).toHaveLength(1); + }); + it('rejects an unsafe owning SDD path before reading external owner evidence', async () => { const workspace = new PreBranchSddWorkspaceAdapter(repo); const snapshot = await workspace.loadSnapshot('develop'); From a271064aea3fbe51f0cdd8641d852fe1047df0fa Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 20:41:51 +0200 Subject: [PATCH 34/44] fix(#656): pin setup directory traversal and regenerate isolated bundles --- build/api/index.js | 630 +- build/cli/index.js | 7825 +++++++++-------- build/github_action/index.js | 6813 +++++++------- specs/verification-setup-onboarding.md | 40 +- .../setup_verification_action.test.ts | 98 +- .../setup_verification_action.ts | 66 +- 6 files changed, 7867 insertions(+), 7605 deletions(-) diff --git a/build/api/index.js b/build/api/index.js index 4a60f2a46..1d58a5f8b 100644 --- a/build/api/index.js +++ b/build/api/index.js @@ -2,16 +2,16 @@ /******/ "use strict"; /******/ var __webpack_modules__ = ({ -/***/ 1889: +/***/ 5999: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ApplicationError = exports.APPLICATION_ERROR_RECOVERY_IDS = exports.APPLICATION_ERROR_METADATA = void 0; exports.toApplicationError = toApplicationError; -const application_error_1 = __nccwpck_require__(2525); -const application_error_context_1 = __nccwpck_require__(8040); -var application_error_2 = __nccwpck_require__(2525); +const application_error_1 = __nccwpck_require__(7790); +const application_error_context_1 = __nccwpck_require__(4034); +var application_error_2 = __nccwpck_require__(7790); Object.defineProperty(exports, "APPLICATION_ERROR_METADATA", ({ enumerable: true, get: function () { return application_error_2.APPLICATION_ERROR_METADATA; } })); Object.defineProperty(exports, "APPLICATION_ERROR_RECOVERY_IDS", ({ enumerable: true, get: function () { return application_error_2.APPLICATION_ERROR_RECOVERY_IDS; } })); /** Creates a semantic error and owns correlation identity outside the pure model. */ @@ -35,7 +35,7 @@ function toApplicationError(error, code, message, options = {}) { /***/ }), -/***/ 8040: +/***/ 4034: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -46,7 +46,7 @@ exports.runWithApplicationErrorCorrelation = runWithApplicationErrorCorrelation; exports.runAtApplicationErrorBoundary = runAtApplicationErrorBoundary; const node_async_hooks_1 = __nccwpck_require__(2761); const node_crypto_1 = __nccwpck_require__(6005); -const application_error_1 = __nccwpck_require__(2525); +const application_error_1 = __nccwpck_require__(7790); const applicationErrorCorrelation = new node_async_hooks_1.AsyncLocalStorage(); function getApplicationErrorCorrelationId() { return applicationErrorCorrelation.getStore(); @@ -70,15 +70,15 @@ function runAtApplicationErrorBoundary(operation) { /***/ }), -/***/ 7020: +/***/ 2937: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotMutationError = void 0; exports.bugbotMutationError = bugbotMutationError; -const application_error_1 = __nccwpck_require__(1889); -const pull_request_review_errors_1 = __nccwpck_require__(2151); +const application_error_1 = __nccwpck_require__(5999); +const pull_request_review_errors_1 = __nccwpck_require__(6445); class BugbotMutationError extends application_error_1.ApplicationError { constructor(diagnostic) { super(diagnostic.errorCode, `Bugbot ${diagnostic.stage} failed: operation=${diagnostic.operation}; finding=${diagnostic.findingId}; affected=${diagnostic.affectedCount}; ${diagnostic.providerStatus}; provider-reference=${diagnostic.providerReference}. Completed effects are retained; correct the named cause and recheck the same target.`); @@ -109,7 +109,7 @@ function bugbotMutationError(cause, stage, findingIds, fallback, affectedCount = /***/ }), -/***/ 8114: +/***/ 601: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -118,7 +118,7 @@ exports.AGENT_OUTPUT_LOCALE_SCHEMA_PROPERTY = exports.PRODUCT_FACING_AGENT_TASKS exports.productFacingAgentQueryOptions = productFacingAgentQueryOptions; exports.validateAgentOutputLocale = validateAgentOutputLocale; exports.agentOutputLocaleFailureMessage = agentOutputLocaleFailureMessage; -const locale_1 = __nccwpck_require__(2028); +const locale_1 = __nccwpck_require__(5386); exports.PRODUCT_FACING_AGENT_TASKS = [ 'think', 'answer-issue-help', @@ -196,7 +196,7 @@ function agentOutputLocaleFailureMessage(validation) { /***/ }), -/***/ 4816: +/***/ 5712: /***/ ((__unused_webpack_module, exports) => { @@ -227,7 +227,7 @@ function resolveThinkAgentTask(commandName, destinationType) { /***/ }), -/***/ 3783: +/***/ 5596: /***/ ((__unused_webpack_module, exports) => { @@ -268,7 +268,7 @@ async function runWithConcurrencyLimit(tasks, limit) { /***/ }), -/***/ 7194: +/***/ 1389: /***/ ((__unused_webpack_module, exports) => { @@ -284,7 +284,7 @@ exports.BUGBOT_MIN_SEVERITY = 'low'; /***/ }), -/***/ 4008: +/***/ 1601: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -293,9 +293,9 @@ exports.BugbotDiffPlanLimitError = exports.MAX_REVIEW_DIFF_NORMALIZED_INPUT_LENG exports.buildReviewDiffPlan = buildReviewDiffPlan; exports.splitReviewDiffPatch = splitReviewDiffPatch; const node_crypto_1 = __nccwpck_require__(6005); -const untrusted_content_1 = __nccwpck_require__(127); -const git_object_id_1 = __nccwpck_require__(5534); -const file_ignore_policy_1 = __nccwpck_require__(8774); +const untrusted_content_1 = __nccwpck_require__(7057); +const git_object_id_1 = __nccwpck_require__(8623); +const file_ignore_policy_1 = __nccwpck_require__(542); exports.MAX_REVIEW_DIFF_PARTITION_LENGTH = 64000; exports.MAX_REVIEW_DIFF_FRAGMENT_LENGTH = 12000; exports.MAX_REVIEW_DIFF_PARTITIONS = 64; @@ -504,7 +504,7 @@ function stableDiffPartitionDigest(value) { /***/ }), -/***/ 2322: +/***/ 2771: /***/ ((__unused_webpack_module, exports) => { @@ -525,7 +525,7 @@ function selectPullRequestOwnerForPushReview(context) { /***/ }), -/***/ 8304: +/***/ 8024: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -546,10 +546,10 @@ exports.replaceMarkerInBody = replaceMarkerInBody; exports.extractTitleFromBody = extractTitleFromBody; exports.buildCommentBody = buildCommentBody; exports.buildResolvedFindingNote = buildResolvedFindingNote; -const bugbot_constants_1 = __nccwpck_require__(7194); -const application_error_1 = __nccwpck_require__(1889); -const github_comment_publication_policy_1 = __nccwpck_require__(7104); -const bugbot_message_catalog_1 = __nccwpck_require__(1164); +const bugbot_constants_1 = __nccwpck_require__(1389); +const application_error_1 = __nccwpck_require__(5999); +const github_comment_publication_policy_1 = __nccwpck_require__(2712); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); /** Maximum lossless finding identity accepted by the marker contract. */ exports.MAX_FINDING_ID_LENGTH = 200; /** Safe character set for finding IDs in regex (alphanumeric, path/segment chars). */ @@ -699,13 +699,13 @@ function buildResolvedFindingNote(resolution, catalog = (0, bugbot_message_catal /***/ }), -/***/ 264: +/***/ 3822: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectBugbotFindingStatuses = projectBugbotFindingStatuses; -const review_state_1 = __nccwpck_require__(7220); +const review_state_1 = __nccwpck_require__(9200); /** Projects durable comment markers and the current analysis into a stable finding state. */ function projectBugbotFindingStatuses(existingByFindingId, activeFindings, resolvedFindingIds = new Set(), resolvedFindingResolutions = new Map()) { const ids = new Set([ @@ -751,7 +751,7 @@ function countStatuses(statuses) { /***/ }), -/***/ 1164: +/***/ 7406: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -761,8 +761,8 @@ exports.resolveStaticBugbotCatalog = resolveStaticBugbotCatalog; exports.resolveBugbotCatalog = resolveBugbotCatalog; exports.renderBugbotDiagnostic = renderBugbotDiagnostic; exports.bugbotDiagnosticOperatorMessage = bugbotDiagnosticOperatorMessage; -const message_catalog_1 = __nccwpck_require__(9292); -const resolved_message_catalog_policy_1 = __nccwpck_require__(1992); +const message_catalog_1 = __nccwpck_require__(7097); +const resolved_message_catalog_policy_1 = __nccwpck_require__(5069); exports.BUGBOT_MESSAGE_IDS = Object.freeze([ 'bugbot.status.heading.partial', 'bugbot.status.heading.verification', @@ -1084,7 +1084,7 @@ function bugbotDiagnosticOperatorMessage(diagnostic) { /***/ }), -/***/ 4151: +/***/ 7555: /***/ ((__unused_webpack_module, exports) => { @@ -1114,16 +1114,16 @@ function formatBugbotPartitionCompletion(input) { /***/ }), -/***/ 3245: +/***/ 5821: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectBugbotProviderEvidence = projectBugbotProviderEvidence; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(8304); -const bugbot_constants_1 = __nccwpck_require__(7194); -const github_user_policy_1 = __nccwpck_require__(4900); -const review_state_1 = __nccwpck_require__(7220); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(8024); +const bugbot_constants_1 = __nccwpck_require__(1389); +const github_user_policy_1 = __nccwpck_require__(4403); +const review_state_1 = __nccwpck_require__(9200); /** * Converts a provider snapshot into semantic finding evidence. Issue and PR * destinations are projected independently and then folded conservatively, so @@ -1311,7 +1311,7 @@ function containsBugbotFindingMarkerSyntax(body) { /***/ }), -/***/ 5390: +/***/ 8128: /***/ ((__unused_webpack_module, exports) => { @@ -1435,7 +1435,7 @@ function hasMissingNonCleanDurableDestination(findingId, finding, observed) { /***/ }), -/***/ 3031: +/***/ 9189: /***/ ((__unused_webpack_module, exports) => { @@ -1458,15 +1458,15 @@ function filterEligibleBugbotResolutionIds(claimedIds, eligibleIds, existingByFi /***/ }), -/***/ 1686: +/***/ 3288: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectOwnedBugbotReviews = selectOwnedBugbotReviews; exports.isTrustedBugbotAuthor = isTrustedBugbotAuthor; -const github_user_policy_1 = __nccwpck_require__(4900); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(8304); +const github_user_policy_1 = __nccwpck_require__(4403); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(8024); /** Associates trusted review summaries with every child finding they own. */ function selectOwnedBugbotReviews(input) { const findingById = new Map(input.findings.map((finding) => [finding.id, finding])); @@ -1514,7 +1514,7 @@ function addFinding(findingsByReview, reviewIdentity, findingId) { /***/ }), -/***/ 4649: +/***/ 3799: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { @@ -1527,11 +1527,11 @@ exports.isBugbotStatusComment = isBugbotStatusComment; exports.renderBugbotStatusCard = renderBugbotStatusCard; exports.renderBugbotReviewSnapshot = renderBugbotReviewSnapshot; exports.buildNewBugbotReviewSnapshotHeader = buildNewBugbotReviewSnapshotHeader; -const review_state_1 = __nccwpck_require__(7220); -const github_comment_publication_policy_1 = __nccwpck_require__(7104); -const publication_identity_policy_1 = __nccwpck_require__(7167); -const bugbot_status_count_marker_policy_1 = __nccwpck_require__(7427); -const bugbot_message_catalog_1 = __nccwpck_require__(1164); +const review_state_1 = __nccwpck_require__(9200); +const github_comment_publication_policy_1 = __nccwpck_require__(2712); +const publication_identity_policy_1 = __nccwpck_require__(5403); +const bugbot_status_count_marker_policy_1 = __nccwpck_require__(8654); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); exports.BUGBOT_STATUS_MARKER_PREFIX = 'copilot-bugbot-status'; exports.BUGBOT_REVIEW_MARKER_PREFIX = 'copilot-bugbot-review'; exports.BUGBOT_REVIEW_STATUS_START = '`; @@ -43186,7 +43186,7 @@ function shortSha(value) { /***/ }), -/***/ 62640: +/***/ 61833: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -43275,7 +43275,7 @@ function doctorWorkflowCondition(value, event) { /***/ }), -/***/ 7243: +/***/ 87989: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -43318,7 +43318,7 @@ function record(value) { /***/ }), -/***/ 38774: +/***/ 20542: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -43380,7 +43380,7 @@ function fileMatchesIgnorePatterns(filePath, ignorePatterns) { /***/ }), -/***/ 27104: +/***/ 72712: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -43389,8 +43389,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.sanitizeAgentMarkdown = sanitizeAgentMarkdown; exports.sanitizePublishedError = sanitizePublishedError; exports.escapeHtml = escapeHtml; -const untrusted_content_1 = __nccwpck_require__(30127); -const secret_redaction_1 = __nccwpck_require__(11978); +const untrusted_content_1 = __nccwpck_require__(67057); +const secret_redaction_1 = __nccwpck_require__(254); /** * Model output is untrusted too. Keep useful Markdown, but neutralize the * GitHub automation surfaces that could create side effects when published. @@ -43433,7 +43433,7 @@ function neutralizeGithubControls(value) { /***/ }), -/***/ 51599: +/***/ 99566: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -43442,18 +43442,18 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validDoctorConfiguration = validDoctorConfiguration; exports.doctorRepositoryPrerequisites = doctorRepositoryPrerequisites; exports.doctorWorkflowContracts = doctorWorkflowContracts; -const doctor_workflow_matrix_policy_1 = __nccwpck_require__(7243); -const github_runtime_doctor_1 = __nccwpck_require__(56756); -const doctor_workflow_condition_policy_1 = __nccwpck_require__(62640); -const js_yaml_1 = __nccwpck_require__(49278); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); +const doctor_workflow_matrix_policy_1 = __nccwpck_require__(87989); +const github_runtime_doctor_1 = __nccwpck_require__(20413); +const doctor_workflow_condition_policy_1 = __nccwpck_require__(61833); +const js_yaml_1 = __nccwpck_require__(783); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); // eslint-disable-next-line @typescript-eslint/no-require-imports -const { validateSddPrerequisiteDocuments } = __nccwpck_require__(81422); +const { validateSddPrerequisiteDocuments } = __nccwpck_require__(95990); // CommonJS keeps this pure policy usable by the standalone Node catalog validator. // eslint-disable-next-line @typescript-eslint/no-require-imports -const { matchesFieldBoundary } = __nccwpck_require__(1164); +const { matchesFieldBoundary } = __nccwpck_require__(66014); function validDoctorConfiguration(value) { if (!value || typeof value.preBranchSdd !== 'boolean' || typeof value.issueManagedBranches !== 'boolean' || !(0, github_runtime_doctor_1.isDoctorBranchReference)(value.dependencyBranch)) @@ -43624,7 +43624,7 @@ function completeFileSamples(read, paths) { /***/ }), -/***/ 3571: +/***/ 2808: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -43632,8 +43632,8 @@ function completeFileSamples(read, paths) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isGithubRuntimeDoctorProjection = isGithubRuntimeDoctorProjection; exports.formatGithubRuntimeDoctor = formatGithubRuntimeDoctor; -const github_runtime_doctor_1 = __nccwpck_require__(56756); -const publication_message_catalog_1 = __nccwpck_require__(92221); +const github_runtime_doctor_1 = __nccwpck_require__(20413); +const publication_message_catalog_1 = __nccwpck_require__(34223); const ACTIONS = ['configuration', 'workflow', 'retry', 'issue', 'specifications', 'branch', 'policy', 'declared']; const STATES = ['pass', 'warning', 'blocked', 'unavailable', 'not-applicable']; function isGithubRuntimeDoctorProjection(value) { @@ -43707,7 +43707,7 @@ function repositorySource(value) { /***/ }), -/***/ 39606: +/***/ 30203: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -43715,7 +43715,7 @@ function repositorySource(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IMPLEMENTATION_REPLY_RESULT_ID = void 0; exports.readImplementationResult = readImplementationResult; -const result_1 = __nccwpck_require__(99917); +const result_1 = __nccwpck_require__(73817); exports.IMPLEMENTATION_REPLY_RESULT_ID = 'CommentAutomation.ImplementationReply'; /** A receipt proves the operation's outcome, not feature acceptance or completeness. */ function readImplementationResult(resultId, payload) { @@ -43735,7 +43735,7 @@ function readImplementationResult(resultId, payload) { /***/ }), -/***/ 20617: +/***/ 74902: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -43744,8 +43744,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.INACTIVITY_CATALOG_DEFINITIONS = exports.SPANISH_INACTIVITY_DEFINITION = exports.ENGLISH_INACTIVITY_DEFINITION = exports.INACTIVITY_MESSAGE_IDS = void 0; exports.resolveStaticInactivityCatalog = resolveStaticInactivityCatalog; exports.resolveInactivityCatalog = resolveInactivityCatalog; -const message_catalog_1 = __nccwpck_require__(69292); -const resolved_message_catalog_policy_1 = __nccwpck_require__(1992); +const message_catalog_1 = __nccwpck_require__(27097); +const resolved_message_catalog_policy_1 = __nccwpck_require__(55069); exports.INACTIVITY_MESSAGE_IDS = Object.freeze([ 'inactivity.closure.heading', 'inactivity.closure.reason', @@ -43839,7 +43839,7 @@ async function resolveInactivityCatalog(locale, configuration, resolver) { /***/ }), -/***/ 59025: +/***/ 1572: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -43847,7 +43847,7 @@ async function resolveInactivityCatalog(locale, configuration, resolver) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildInactivityClosureComment = buildInactivityClosureComment; exports.buildInactivitySummarySteps = buildInactivitySummarySteps; -const publication_identity_policy_1 = __nccwpck_require__(17167); +const publication_identity_policy_1 = __nccwpck_require__(45403); function buildInactivityClosureComment(input) { const digest = (0, publication_identity_policy_1.createSemanticDigest)({ updatedAt: input.candidate.updatedAt, @@ -43888,16 +43888,16 @@ function buildInactivitySummarySteps(input) { /***/ }), -/***/ 47570: +/***/ 73160: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildInitialLabelProvisioningPlan = buildInitialLabelProvisioningPlan; -const progress_labels_1 = __nccwpck_require__(11696); -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const issue_start_policy_1 = __nccwpck_require__(59704); +const progress_labels_1 = __nccwpck_require__(97890); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const issue_start_policy_1 = __nccwpck_require__(90332); const normalizeLabelName = (name) => name.trim().toLowerCase(); function configuredLabelDefinitions(labels) { const metadata = [ @@ -43981,15 +43981,15 @@ function buildInitialLabelProvisioningPlan(labels, existingLabelNames) { /***/ }), -/***/ 14047: +/***/ 61899: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveIssueCommentPublicationRequest = resolveIssueCommentPublicationRequest; -const comment_content_policy_1 = __nccwpck_require__(11965); -const input_keys_1 = __nccwpck_require__(27112); +const comment_content_policy_1 = __nccwpck_require__(77454); +const input_keys_1 = __nccwpck_require__(88539); function resolveIssueCommentPublicationRequest(input) { if (!(0, comment_content_policy_1.hasVisibleCommentContent)(input.message)) { return new Error(`${input_keys_1.INPUT_KEYS.SINGLE_ACTION_MESSAGE} must contain a visible message.`); @@ -44021,15 +44021,15 @@ function resolveMode(mode, commentId) { /***/ }), -/***/ 94990: +/***/ 28615: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readLocalLabelsAndIssueTypes = readLocalLabelsAndIssueTypes; -const input_keys_1 = __nccwpck_require__(27112); -const action_input_source_1 = __nccwpck_require__(66436); +const input_keys_1 = __nccwpck_require__(88539); +const action_input_source_1 = __nccwpck_require__(25911); function readIssueType(additionalParams, actionInputs, name, description, color) { return { name: (0, action_input_source_1.resolveActionInput)(additionalParams, actionInputs, name), @@ -44123,15 +44123,15 @@ function readLocalLabelsAndIssueTypes(additionalParams, actionInputs) { /***/ }), -/***/ 30404: +/***/ 99190: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.assertLocalSingleActionAllowed = assertLocalSingleActionAllowed; -const action_types_1 = __nccwpck_require__(78468); -const application_error_1 = __nccwpck_require__(1889); +const action_types_1 = __nccwpck_require__(19625); +const application_error_1 = __nccwpck_require__(75999); const GITHUB_WORKFLOW_ONLY_ACTIONS = [ action_types_1.ACTIONS.CREATE_TAG, action_types_1.ACTIONS.CREATE_RELEASE, @@ -44150,7 +44150,7 @@ function assertLocalSingleActionAllowed(requestedAction) { /***/ }), -/***/ 49744: +/***/ 55078: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -44205,7 +44205,7 @@ function buildManagedBranchPresentation(input) { /***/ }), -/***/ 35785: +/***/ 56033: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44215,7 +44215,7 @@ exports.SPANISH_MERGE_QUEUE_MESSAGES = exports.ENGLISH_MERGE_QUEUE_MESSAGES = ex exports.renderMergeQueueReadinessFailure = renderMergeQueueReadinessFailure; exports.producerStateMessageId = producerStateMessageId; exports.boundedMergeQueueDiagnostic = boundedMergeQueueDiagnostic; -const sensitive_text_1 = __nccwpck_require__(57472); +const sensitive_text_1 = __nccwpck_require__(47122); exports.MERGE_QUEUE_MESSAGE_IDS = Object.freeze([ 'mergeQueue.readiness.failure', 'mergeQueue.readiness.incompleteEvidence', @@ -44338,14 +44338,14 @@ function boundedMergeQueueDiagnostic(value) { /***/ }), -/***/ 46908: +/***/ 39267: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.mergeSetupOverrides = mergeSetupOverrides; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); /** Explicit CLI flags override only their fields; file-only settings remain intact. */ function mergeSetupOverrides(fileOverrides, flagOverrides) { const agents = { ...fileOverrides.agents, ...flagOverrides.agents }; @@ -44382,7 +44382,7 @@ function mergeSetupOverrides(fileOverrides, flagOverrides) { /***/ }), -/***/ 59296: +/***/ 70628: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44391,7 +44391,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_PROGRESS_PARTITIONS = exports.MAX_PROGRESS_EVIDENCE_BYTES = void 0; exports.progressEvidenceTooLarge = progressEvidenceTooLarge; exports.partitionProgressDiff = partitionProgressDiff; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); exports.MAX_PROGRESS_EVIDENCE_BYTES = 256000; exports.MAX_PROGRESS_PARTITIONS = 16; function progressEvidenceTooLarge() { @@ -44431,7 +44431,7 @@ function partitionProgressDiff(baseSha, headSha, changes) { /***/ }), -/***/ 11696: +/***/ 97890: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -44465,7 +44465,7 @@ function progressPercentToColor(percent) { /***/ }), -/***/ 51545: +/***/ 30025: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44476,9 +44476,9 @@ exports.progressPartitionResponseSchema = progressPartitionResponseSchema; exports.parseProgressPartitionFacts = parseProgressPartitionFacts; exports.progressPartitionFactLimit = progressPartitionFactLimit; exports.aggregateProgressFacts = aggregateProgressFacts; -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); // Leaves space inside the unchanged 512 KiB runtime prompt ceiling. The caller // further subtracts the exact issue/prompt envelope before requesting facts. exports.MAX_PROGRESS_AGGREGATE_BYTES = 384000; @@ -44551,7 +44551,7 @@ function invalid() { /***/ }), -/***/ 17167: +/***/ 45403: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44568,7 +44568,7 @@ exports.buildPublicationTransitionMarker = buildPublicationTransitionMarker; exports.parsePublicationTransitionMarker = parsePublicationTransitionMarker; exports.buildDuplicateMarker = buildDuplicateMarker; const node_crypto_1 = __nccwpck_require__(6005); -const github_publication_1 = __nccwpck_require__(16812); +const github_publication_1 = __nccwpck_require__(35793); exports.PUBLICATION_SCHEMA = '1'; exports.PUBLICATION_MARKER_PREFIX = 'copilot:publication'; exports.PUBLICATION_DUPLICATE_MARKER_PREFIX = 'copilot:publication-duplicate'; @@ -44699,7 +44699,7 @@ function stableSerialize(value) { /***/ }), -/***/ 92221: +/***/ 34223: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44710,9 +44710,9 @@ exports.publicationLocaleNeedsDynamicCatalog = publicationLocaleNeedsDynamicCata exports.resolveStaticPublicationCatalog = resolveStaticPublicationCatalog; exports.resolvePublicationCatalog = resolvePublicationCatalog; exports.toPublicationCatalog = toPublicationCatalog; -const message_catalog_1 = __nccwpck_require__(69292); -const locale_1 = __nccwpck_require__(52028); -const application_error_message_catalog_1 = __nccwpck_require__(47861); +const message_catalog_1 = __nccwpck_require__(27097); +const locale_1 = __nccwpck_require__(15386); +const application_error_message_catalog_1 = __nccwpck_require__(64809); const PUBLICATION_SURFACE_MESSAGE_IDS = Object.freeze([ 'publication.implementationPlan', 'publication.planReady', @@ -45457,7 +45457,7 @@ exports.SPANISH_PUBLICATION_CATALOG = toPublicationCatalog(Object.freeze({ /***/ }), -/***/ 45483: +/***/ 79719: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45469,8 +45469,8 @@ exports.buildDuplicateCompactionPublicationPayload = buildDuplicateCompactionPub exports.duplicateCompactionPublicationOutcomes = duplicateCompactionPublicationOutcomes; exports.buildTransitionPublicationPayload = buildTransitionPublicationPayload; exports.transitionPublicationOutcomes = transitionPublicationOutcomes; -const result_1 = __nccwpck_require__(99917); -const github_publication_1 = __nccwpck_require__(16812); +const result_1 = __nccwpck_require__(73817); +const github_publication_1 = __nccwpck_require__(35793); const MAX_REPORTED_COMMENT_IDS = 20; const MAX_REPORTED_TRANSITIONS = 20; /** Builds bounded evidence for a commit-derived result that was intentionally suppressed. */ @@ -45582,7 +45582,7 @@ function areOrderedUniquePositiveIntegers(values) { /***/ }), -/***/ 69975: +/***/ 79017: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -45701,7 +45701,7 @@ function escapeMarkdown(value) { /***/ }), -/***/ 80608: +/***/ 43268: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45709,7 +45709,7 @@ function escapeMarkdown(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_PULL_REQUEST_DESCRIPTION_LENGTH = void 0; exports.renderPullRequestDescriptionContent = renderPullRequestDescriptionContent; -const github_comment_publication_policy_1 = __nccwpck_require__(27104); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); exports.MAX_PULL_REQUEST_DESCRIPTION_LENGTH = 12000; const CONTENT_KEYS = Object.freeze([ 'outputLocale', @@ -45901,7 +45901,7 @@ function renderList(values) { /***/ }), -/***/ 79355: +/***/ 79794: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45910,8 +45910,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.unavailablePullRequestReadiness = unavailablePullRequestReadiness; exports.disabledPullRequestReadiness = disabledPullRequestReadiness; exports.projectPullRequestReadiness = projectPullRequestReadiness; -const pull_request_approval_1 = __nccwpck_require__(96191); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); +const pull_request_approval_1 = __nccwpck_require__(8024); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); const objectId = (value) => typeof value === 'string' && /^[a-f0-9]{40}$/u.test(value); function unavailablePullRequestReadiness(code = 'evidence-unavailable', action = 'retry') { return Object.freeze({ readiness: 'unavailable', mode: 'unavailable', headSha: '', baseSha: '', code, @@ -45986,7 +45986,7 @@ function projectPullRequestReadiness(rawPolicy, evidence, final) { /***/ }), -/***/ 56053: +/***/ 99448: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -46040,7 +46040,7 @@ function verifiedReadinessLink(snapshot, number) { /***/ }), -/***/ 94675: +/***/ 59756: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -46068,7 +46068,7 @@ function generatedPullRequestTitle(sourceTitle, sanitizedSubject, issueNumber, l /***/ }), -/***/ 33990: +/***/ 39410: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46108,7 +46108,7 @@ function createSha256(value) { /***/ }), -/***/ 24504: +/***/ 67402: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46120,9 +46120,9 @@ exports.renderRepositoryAgentArtifacts = renderRepositoryAgentArtifacts; exports.renderRepositoryAgentGuide = renderRepositoryAgentGuide; exports.renderRepositoryAgentSkill = renderRepositoryAgentSkill; exports.renderRepositoryAgentPointerBlock = renderRepositoryAgentPointerBlock; -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const issue_start_policy_1 = __nccwpck_require__(59704); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const issue_start_policy_1 = __nccwpck_require__(90332); exports.REPOSITORY_AGENT_PROFILE_PATH = '.copilot/repository-profile.json'; exports.REPOSITORY_AGENT_GUIDE_PATH = '.copilot/AGENT_GUIDE.md'; exports.REPOSITORY_AGENT_SKILL_PATH = '.agents/skills/copilot-repository-workflow/SKILL.md'; @@ -46294,7 +46294,7 @@ function renderRepositoryAgentPointerBlock() { /***/ }), -/***/ 1992: +/***/ 55069: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46303,8 +46303,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.toResolvedMessageCatalogView = toResolvedMessageCatalogView; exports.resolveStaticMessageCatalogView = resolveStaticMessageCatalogView; exports.resolveMessageCatalogView = resolveMessageCatalogView; -const message_catalog_1 = __nccwpck_require__(69292); -const locale_1 = __nccwpck_require__(52028); +const message_catalog_1 = __nccwpck_require__(27097); +const locale_1 = __nccwpck_require__(15386); function toResolvedMessageCatalogView(resolved) { return Object.freeze({ locale: resolved.resolvedLocale, @@ -46370,15 +46370,15 @@ async function resolveMessageCatalogView(locale, ids, sourceCatalog, bundledCata /***/ }), -/***/ 96361: +/***/ 93427: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildRetiredProgressComment = buildRetiredProgressComment; -const publication_identity_policy_1 = __nccwpck_require__(17167); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); const archiveStart = ''; const archiveEnd = ''; const head = '(?:[a-f0-9]{40}|[a-f0-9]{64})'; @@ -46439,7 +46439,7 @@ function buildRetiredProgressComment(body, locale, reason) { /***/ }), -/***/ 44551: +/***/ 88350: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -46486,7 +46486,7 @@ function calculateReviewersStillNeeded(desiredCount, currentCount, confirmedCoun /***/ }), -/***/ 85365: +/***/ 81053: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -46520,7 +46520,7 @@ function renderSddAnalysisStatus(issueNumber, locale, reason) { /***/ }), -/***/ 29948: +/***/ 2230: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46529,8 +46529,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SPANISH_SDD_DIFF_DEFINITION = exports.ENGLISH_SDD_DIFF_DEFINITION = exports.SDD_DIFF_MESSAGE_IDS = void 0; exports.resolveSddDiffCatalog = resolveSddDiffCatalog; exports.isSddDiffResolvedLocale = isSddDiffResolvedLocale; -const message_catalog_1 = __nccwpck_require__(69292); -const resolved_message_catalog_policy_1 = __nccwpck_require__(1992); +const message_catalog_1 = __nccwpck_require__(27097); +const resolved_message_catalog_policy_1 = __nccwpck_require__(55069); exports.SDD_DIFF_MESSAGE_IDS = Object.freeze([ 'sddDiff.heading', 'sddDiff.status', 'sddDiff.action', 'sddDiff.not-applicable', 'sddDiff.no-publication', 'sddDiff.initial-only', 'sddDiff.stale', 'sddDiff.pending-revision', 'sddDiff.invalid', 'sddDiff.unavailable', @@ -46608,14 +46608,14 @@ function isSddDiffResolvedLocale(value) { /***/ }), -/***/ 11594: +/***/ 63302: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.renderSddDiff = renderSddDiff; -const pre_branch_sdd_1 = __nccwpck_require__(56394); +const pre_branch_sdd_1 = __nccwpck_require__(34730); const STATES = ['not-applicable', 'no-publication', 'initial-only', 'stale', 'pending-revision', 'invalid', 'unavailable', 'ambiguous', 'bounded', 'compared']; const ACTIONS = Object.freeze({ 'not-applicable': 'sddDiff.none', 'no-publication': 'sddDiff.publish', 'initial-only': 'sddDiff.none', @@ -46712,7 +46712,7 @@ function escapeTitle(value) { /***/ }), -/***/ 81773: +/***/ 99167: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46720,8 +46720,8 @@ function escapeTitle(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildSddIssueDigest = buildSddIssueDigest; const node_crypto_1 = __nccwpck_require__(6005); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const recommendation_policy_1 = __nccwpck_require__(33990); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const recommendation_policy_1 = __nccwpck_require__(39410); /** Producer and read-only queries use the same identity and immutable first base. */ function buildSddIssueDigest(context, baseSha) { return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify([ @@ -46733,15 +46733,15 @@ function buildSddIssueDigest(context, baseSha) { /***/ }), -/***/ 50681: +/***/ 56285: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectOwnedSddCard = selectOwnedSddCard; -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const publication_identity_policy_1 = __nccwpck_require__(17167); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const publication_identity_policy_1 = __nccwpck_require__(45403); /** The latest owned card is authoritative even when invalid; an older card cannot restore readiness. */ function selectOwnedSddCard(comments, issueNumber, trustedBotLogin) { const login = trustedBotLogin.trim().toLowerCase(); @@ -46797,7 +46797,7 @@ function isOtherOwnedPublication(body, issueNumber) { /***/ }), -/***/ 11756: +/***/ 6853: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46806,8 +46806,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.initialSddStatus = initialSddStatus; exports.projectSddStatus = projectSddStatus; exports.formatSddStatus = formatSddStatus; -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); /** Uses the admitted workflow/start policy; output labels cannot establish eligibility. */ function initialSddStatus(context, labels) { if (!context.admittedKind || typeof context.issueManagedBranches !== 'boolean' || typeof context.preBranchSdd !== 'boolean') { @@ -46907,7 +46907,7 @@ function safeIssueUrl(value, issueNumber, identity) { /***/ }), -/***/ 78334: +/***/ 81985: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46919,24 +46919,24 @@ exports.hasOwnedPrimaryIssuePublication = hasOwnedPrimaryIssuePublication; exports.selectSemanticReplyIntents = selectSemanticReplyIntents; exports.renderSemanticReply = renderSemanticReply; exports.renderSemanticStatus = renderSemanticStatus; -const sdd_diff_message_catalog_1 = __nccwpck_require__(29948); -const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(3571); -const copilot_operation_1 = __nccwpck_require__(18679); -const copilot_history_presentation_policy_1 = __nccwpck_require__(41063); -const copilot_history_projection_policy_1 = __nccwpck_require__(67091); -const github_publication_1 = __nccwpck_require__(16812); -const github_user_policy_1 = __nccwpck_require__(84900); -const result_1 = __nccwpck_require__(99917); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const publication_message_catalog_1 = __nccwpck_require__(92221); -const copilot_interaction_policy_1 = __nccwpck_require__(52113); -const status_command_policy_1 = __nccwpck_require__(33849); -const comment_translation_policy_1 = __nccwpck_require__(47336); -const application_error_presentation_policy_1 = __nccwpck_require__(95982); -const git_object_id_1 = __nccwpck_require__(65534); -const implementation_result_policy_1 = __nccwpck_require__(39606); -const implementation_plan_1 = __nccwpck_require__(8768); +const sdd_diff_message_catalog_1 = __nccwpck_require__(2230); +const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(2808); +const copilot_operation_1 = __nccwpck_require__(40221); +const copilot_history_presentation_policy_1 = __nccwpck_require__(55507); +const copilot_history_projection_policy_1 = __nccwpck_require__(99186); +const github_publication_1 = __nccwpck_require__(35793); +const github_user_policy_1 = __nccwpck_require__(84403); +const result_1 = __nccwpck_require__(73817); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const publication_message_catalog_1 = __nccwpck_require__(34223); +const copilot_interaction_policy_1 = __nccwpck_require__(90108); +const status_command_policy_1 = __nccwpck_require__(3449); +const comment_translation_policy_1 = __nccwpck_require__(27150); +const application_error_presentation_policy_1 = __nccwpck_require__(95067); +const git_object_id_1 = __nccwpck_require__(88623); +const implementation_result_policy_1 = __nccwpck_require__(30203); +const implementation_plan_1 = __nccwpck_require__(77001); function selectSemanticStatusIntents(context) { return Object.freeze(context.results.flatMap(result => { if (!result.executed || !result.success) @@ -47453,15 +47453,15 @@ function operationMarker(intent) { /***/ }), -/***/ 90975: +/***/ 53296: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildApprovalDoctorChecks = buildApprovalDoctorChecks; -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const setup_doctor_message_catalog_1 = __nccwpck_require__(80653); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const setup_doctor_message_catalog_1 = __nccwpck_require__(80226); /** Stable ordered checks; unknown prerequisites never project native-approval readiness. */ function buildApprovalDoctorChecks(input) { const checks = []; @@ -47544,7 +47544,7 @@ function check(id, status, summary, action, blockedBy = []) { /***/ }), -/***/ 13056: +/***/ 15486: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47552,10 +47552,10 @@ function check(id, status, summary, action, blockedBy = []) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectSetupBatchSharedBindings = projectSetupBatchSharedBindings; exports.planSetupBatchSharedAccess = planSetupBatchSharedAccess; -const setup_batch_policy_1 = __nccwpck_require__(2886); -const setup_credential_binding_policy_1 = __nccwpck_require__(22770); -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); +const setup_batch_policy_1 = __nccwpck_require__(52214); +const setup_credential_binding_policy_1 = __nccwpck_require__(24663); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); function projectSetupBatchSharedBindings(remote, resources, target) { const usable = resources.filter(resource => (0, setup_batch_policy_1.setupSharedResourceApplies)(resource, target) || resource.visibility === 'selected'); return { ...remote, @@ -47597,7 +47597,7 @@ function planSetupBatchSharedAccess(configuration, target, remote, shared) { /***/ }), -/***/ 2886: +/***/ 52214: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47612,8 +47612,8 @@ exports.assertSetupBatchOperationMatchesPlan = assertSetupBatchOperationMatchesP exports.isSetupBatchInstallationReceipt = isSetupBatchInstallationReceipt; exports.parseSetupBatchOperation = parseSetupBatchOperation; exports.validSetupBatchAssetPath = validSetupBatchAssetPath; -const setup_batch_1 = __nccwpck_require__(48421); -const setup_verification_action_1 = __nccwpck_require__(29549); +const setup_batch_1 = __nccwpck_require__(88308); +const setup_verification_action_1 = __nccwpck_require__(33156); const uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u; const sha = /^[a-f0-9]{40}$/u; const digest = /^[a-f0-9]{64}$/u; @@ -47735,7 +47735,7 @@ function exact(value, keys) { return Object.keys(value).length === keys.length & /***/ }), -/***/ 76159: +/***/ 70775: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -47763,7 +47763,7 @@ function setupBatchRateLimitDelay(headers, now) { /***/ }), -/***/ 36296: +/***/ 1694: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -47801,16 +47801,16 @@ function parseSetupBatchSelectionIntent(value, view) { /***/ }), -/***/ 58563: +/***/ 86156: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildSetupBatchView = buildSetupBatchView; -const setup_token_permission_policy_1 = __nccwpck_require__(32450); -const setup_batch_policy_1 = __nccwpck_require__(2886); -const setup_batch_access_policy_1 = __nccwpck_require__(13056); +const setup_token_permission_policy_1 = __nccwpck_require__(99590); +const setup_batch_policy_1 = __nccwpck_require__(52214); +const setup_batch_access_policy_1 = __nccwpck_require__(15486); /** Only installer-constructed GitHub destinations and metadata enter the paired view. */ function buildSetupBatchView(plan, operation, phase, retryRemaining) { return { operationId: plan.operationId, organization: plan.organization, phase, retryRemaining, @@ -47837,14 +47837,14 @@ function buildSetupBatchView(plan, operation, phase, retryRemaining) { /***/ }), -/***/ 57097: +/***/ 85881: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.cloneSetupConfiguration = cloneSetupConfiguration; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); /** Returns a reference-isolated configuration snapshot without serializing it. */ function cloneSetupConfiguration(configuration) { const agents = Object.fromEntries(setup_configuration_defaults_1.SETUP_AGENT_TASKS.map((task) => [ @@ -47893,7 +47893,7 @@ function cloneSetupConfiguration(configuration) { /***/ }), -/***/ 6736: +/***/ 23381: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47905,14 +47905,14 @@ exports.createDefaultSetupStorageConfiguration = createDefaultSetupStorageConfig exports.createDefaultSetupConfiguration = createDefaultSetupConfiguration; exports.mergeSetupConfiguration = mergeSetupConfiguration; exports.normalizeSetupConfigurationLocales = normalizeSetupConfigurationLocales; -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const agent_1 = __nccwpck_require__(18773); -const issue_inactivity_1 = __nccwpck_require__(15236); -const deployment_configuration_1 = __nccwpck_require__(86193); -const locale_1 = __nccwpck_require__(52028); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const setup_runner_1 = __nccwpck_require__(34512); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const agent_1 = __nccwpck_require__(89040); +const issue_inactivity_1 = __nccwpck_require__(38572); +const deployment_configuration_1 = __nccwpck_require__(22495); +const locale_1 = __nccwpck_require__(15386); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const setup_runner_1 = __nccwpck_require__(94301); exports.SETUP_AGENT_TASKS = [ 'planner', 'findings', @@ -48121,7 +48121,7 @@ function normalizeSetupConfigurationLocales(configuration) { /***/ }), -/***/ 69620: +/***/ 87770: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -48132,17 +48132,17 @@ exports.buildSetupPlan = buildSetupPlan; exports.setupPlanGuardPaths = setupPlanGuardPaths; exports.buildSetupRepositoryVariables = buildSetupRepositoryVariables; exports.buildSetupActionInputs = buildSetupActionInputs; -const pull_request_description_1 = __nccwpck_require__(8324); -const setup_workflow_catalog_1 = __nccwpck_require__(53376); -const setup_configuration_defaults_1 = __nccwpck_require__(6736); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); +const pull_request_description_1 = __nccwpck_require__(45315); +const setup_workflow_catalog_1 = __nccwpck_require__(24596); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); Object.defineProperty(exports, "buildSetupCredentialRequirements", ({ enumerable: true, get: function () { return setup_credential_requirement_policy_1.buildSetupCredentialRequirements; } })); -const locale_1 = __nccwpck_require__(52028); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const setup_verification_action_1 = __nccwpck_require__(29549); -const repository_agent_guidance_policy_1 = __nccwpck_require__(24504); +const locale_1 = __nccwpck_require__(15386); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const setup_verification_action_1 = __nccwpck_require__(33156); +const repository_agent_guidance_policy_1 = __nccwpck_require__(67402); function buildSetupPlan(configuration, mergeQueueReadiness = [], approvalReadiness = []) { const workflowFiles = (0, setup_workflow_catalog_1.enabledSetupWorkflowFiles)((0, setup_issue_workflow_policy_1.effectiveIssueWorkflowFeatures)(configuration)) .filter(file => file !== 'copilot_pull_request_approval.yml' || configuration.pullRequestApproval.mode !== 'off'); @@ -48429,7 +48429,7 @@ function unique(values) { /***/ }), -/***/ 58409: +/***/ 56637: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -48450,16 +48450,16 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); /** Public setup-policy boundary. Each concern is implemented in a focused policy module. */ -__exportStar(__nccwpck_require__(6736), exports); -__exportStar(__nccwpck_require__(69620), exports); -__exportStar(__nccwpck_require__(14845), exports); -__exportStar(__nccwpck_require__(62784), exports); -__exportStar(__nccwpck_require__(63312), exports); +__exportStar(__nccwpck_require__(23381), exports); +__exportStar(__nccwpck_require__(87770), exports); +__exportStar(__nccwpck_require__(2554), exports); +__exportStar(__nccwpck_require__(13339), exports); +__exportStar(__nccwpck_require__(81182), exports); /***/ }), -/***/ 14845: +/***/ 2554: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -48480,7 +48480,7 @@ exports.validateSetupManagedResourceInventory = validateSetupManagedResourceInve exports.setupWorkflowPatStorageNotice = setupWorkflowPatStorageNotice; exports.usesOrganizationStorage = usesOrganizationStorage; exports.validateStorageConfiguration = validateStorageConfiguration; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); function resolveSetupResourceScope(policy, name) { return policy.overrides[name] ?? policy.defaultScope; } @@ -48713,24 +48713,24 @@ function mergeStoragePolicy(base, override) { /***/ }), -/***/ 62784: +/***/ 13339: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validateSetupConfiguration = validateSetupConfiguration; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); -const agent_configuration_validation_policy_1 = __nccwpck_require__(17220); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); -const issue_inactivity_1 = __nccwpck_require__(15236); -const deployment_configuration_1 = __nccwpck_require__(86193); -const locale_1 = __nccwpck_require__(52028); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const setup_project_selection_policy_1 = __nccwpck_require__(59068); -const setup_runner_policy_1 = __nccwpck_require__(70801); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); +const agent_configuration_validation_policy_1 = __nccwpck_require__(60596); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); +const issue_inactivity_1 = __nccwpck_require__(38572); +const deployment_configuration_1 = __nccwpck_require__(22495); +const locale_1 = __nccwpck_require__(15386); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const setup_project_selection_policy_1 = __nccwpck_require__(73750); +const setup_runner_policy_1 = __nccwpck_require__(91027); function validateSetupConfiguration(configuration, options = {}) { const errors = []; errors.push(...(0, setup_runner_policy_1.validateSetupRunners)(configuration.runners)); @@ -48903,7 +48903,7 @@ function validateLocale(errors, label, value, optional) { /***/ }), -/***/ 22770: +/***/ 24663: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -48956,14 +48956,14 @@ function selectedExistingSetupCredentials(requirements, remote) { /***/ }), -/***/ 56161: +/***/ 43562: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildSetupCredentialRequirements = buildSetupCredentialRequirements; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); const SECRET_BY_MODEL_PROVIDER = { openai: 'OPENAI_API_KEY', anthropic: 'ANTHROPIC_API_KEY', @@ -49071,7 +49071,7 @@ function uniqueDefined(current, next) { /***/ }), -/***/ 80653: +/***/ 80226: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49080,10 +49080,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SETUP_DOCTOR_CATALOG_DEFINITIONS = exports.SPANISH_SETUP_DOCTOR_DEFINITION = exports.ENGLISH_SETUP_DOCTOR_DEFINITION = exports.SETUP_DOCTOR_MESSAGE_IDS = void 0; exports.resolveStaticSetupDoctorCatalog = resolveStaticSetupDoctorCatalog; exports.resolveSetupDoctorCatalog = resolveSetupDoctorCatalog; -const message_catalog_1 = __nccwpck_require__(69292); -const resolved_message_catalog_policy_1 = __nccwpck_require__(1992); -const merge_queue_message_catalog_1 = __nccwpck_require__(35785); -const approval_doctor_message_catalog_1 = __nccwpck_require__(54095); +const message_catalog_1 = __nccwpck_require__(27097); +const resolved_message_catalog_policy_1 = __nccwpck_require__(55069); +const merge_queue_message_catalog_1 = __nccwpck_require__(56033); +const approval_doctor_message_catalog_1 = __nccwpck_require__(36904); const DOCTOR_ONLY_MESSAGE_IDS = Object.freeze([ 'doctor.sdd.valid', 'doctor.sdd.invalid', @@ -49424,7 +49424,7 @@ function resolveSetupDoctorCatalog(locale, configuration, resolver) { /***/ }), -/***/ 30942: +/***/ 67615: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49435,10 +49435,10 @@ exports.doctorCheck = doctorCheck; exports.skippedDoctorCheck = skippedDoctorCheck; exports.normalizedDoctorPathId = normalizedDoctorPathId; exports.buildLocaleDoctorChecks = buildLocaleDoctorChecks; -const locale_1 = __nccwpck_require__(52028); -const message_catalog_1 = __nccwpck_require__(69292); -const agent_1 = __nccwpck_require__(18773); -const setup_doctor_message_catalog_1 = __nccwpck_require__(80653); +const locale_1 = __nccwpck_require__(15386); +const message_catalog_1 = __nccwpck_require__(27097); +const agent_1 = __nccwpck_require__(89040); +const setup_doctor_message_catalog_1 = __nccwpck_require__(80226); const EMPTY_TOTALS = { pass: 0, warn: 0, @@ -49529,7 +49529,7 @@ function localeDoctorCheck(scope, configured, effective, inheritedWhenEmpty, dyn /***/ }), -/***/ 5660: +/***/ 67323: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49537,7 +49537,7 @@ function localeDoctorCheck(scope, configured, effective, inheritedWhenEmpty, dyn Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectedInitialLabels = selectedInitialLabels; exports.selectedInitialIssueTypes = selectedInitialIssueTypes; -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); /** Removes workflow-specific resources that are not part of the effective profile. */ function selectedInitialLabels(labels, configuration) { if (!configuration) @@ -49596,7 +49596,7 @@ function selectedInitialIssueTypes(issueTypes, configuration) { /***/ }), -/***/ 63312: +/***/ 81182: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49607,7 +49607,7 @@ exports.effectiveIssueWorkflowFeatures = effectiveIssueWorkflowFeatures; exports.effectiveIssueWorkflowLabels = effectiveIssueWorkflowLabels; exports.effectiveIssueFormLabels = effectiveIssueFormLabels; exports.setupNeedsInitialVersion = setupNeedsInitialVersion; -const issue_workflow_profile_1 = __nccwpck_require__(65360); +const issue_workflow_profile_1 = __nccwpck_require__(26744); /** Applies feature switches to the explicit issue workflow selection. */ function effectiveIssueWorkflowProfile(configuration) { const configured = configuration.issueWorkflows?.enabled ?? issue_workflow_profile_1.ISSUE_WORKFLOW_KINDS; @@ -49664,7 +49664,7 @@ function setupNeedsInitialVersion(configuration) { /***/ }), -/***/ 37300: +/***/ 53289: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -49704,7 +49704,7 @@ function buildSetupJourneyView(repository, stage, mutationStarted, outcome, choi /***/ }), -/***/ 57308: +/***/ 70371: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -49727,7 +49727,7 @@ function managementPermissions(scope, ownerType) { /***/ }), -/***/ 58343: +/***/ 50895: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49736,8 +49736,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.managementFingerprint = managementFingerprint; exports.buildSetupManagementView = buildSetupManagementView; exports.planQuickChange = planQuickChange; -const sensitive_text_1 = __nccwpck_require__(57472); -const setup_quick_settings_policy_1 = __nccwpck_require__(87533); +const sensitive_text_1 = __nccwpck_require__(47122); +const setup_quick_settings_policy_1 = __nccwpck_require__(40582); const safe = (value) => (0, sensitive_text_1.redactSensitiveText)(value.slice(0, 4096)); function managementFingerprint(local, remote, variable) { return JSON.stringify([local, remote.ownerType, remote.repositoryId, remote.repositoryVariablesAccess, @@ -49823,20 +49823,20 @@ function planQuickChange(local, remote, id, raw) { /***/ }), -/***/ 87045: +/***/ 97024: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.importSetupOrganizationConfiguration = importSetupOrganizationConfiguration; -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const sensitive_text_1 = __nccwpck_require__(57472); -const setup_configuration_clone_policy_1 = __nccwpck_require__(57097); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); -const setup_configuration_validation_1 = __nccwpck_require__(62784); -const setup_organization_variable_bindings_1 = __nccwpck_require__(86665); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const sensitive_text_1 = __nccwpck_require__(47122); +const setup_configuration_clone_policy_1 = __nccwpck_require__(85881); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); +const setup_configuration_validation_1 = __nccwpck_require__(13339); +const setup_organization_variable_bindings_1 = __nccwpck_require__(19698); /** Reads typed configuration only. No provider, credential collection or write authority. */ function importSetupOrganizationConfiguration(request) { let configuration = (0, setup_configuration_clone_policy_1.cloneSetupConfiguration)(request.configuration); @@ -49982,7 +49982,7 @@ function parseScalar(value, previous) { /***/ }), -/***/ 86665: +/***/ 19698: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49990,7 +49990,7 @@ function parseScalar(value, previous) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SETUP_ORGANIZATION_VARIABLE_BINDINGS = void 0; exports.setupOrganizationExplicitQuestionIds = setupOrganizationExplicitQuestionIds; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); const repositoryFields = [ ['MAIN_BRANCH', 'mainBranch'], ['DEVELOPMENT_BRANCH', 'developmentBranch'], ['FEATURE_TREE', 'featureTree'], ['BUGFIX_TREE', 'bugfixTree'], @@ -50051,7 +50051,7 @@ function setupOrganizationExplicitQuestionIds(overrides) { /***/ }), -/***/ 20994: +/***/ 63882: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50061,10 +50061,10 @@ exports.normalizeSetupStoredEmptyList = normalizeSetupStoredEmptyList; exports.buildSetupOrganizationReuseVariables = buildSetupOrganizationReuseVariables; exports.planSetupOrganizationVariableReuse = planSetupOrganizationVariableReuse; exports.configureSetupOrganizationReuseStorage = configureSetupOrganizationReuseStorage; -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); -const setup_configuration_plan_1 = __nccwpck_require__(69620); -const setup_organization_variable_bindings_1 = __nccwpck_require__(86665); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); +const setup_configuration_plan_1 = __nccwpck_require__(87770); +const setup_organization_variable_bindings_1 = __nccwpck_require__(19698); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); const node_util_1 = __nccwpck_require__(47261); /** Nonempty separators are native empty lists, including on older Action versions. */ const emptyLists = { @@ -50176,7 +50176,7 @@ function inventory(variables) { /***/ }), -/***/ 66277: +/***/ 54718: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50261,7 +50261,7 @@ function buildSetupPatCreationUrl(input) { /***/ }), -/***/ 86171: +/***/ 30748: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50270,7 +50270,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.fixedSetupPatIntentQuestionIds = fixedSetupPatIntentQuestionIds; exports.setupPatIntentNeedsOwnerKind = setupPatIntentNeedsOwnerKind; exports.setupPatIntentOwnerConflict = setupPatIntentOwnerConflict; -const setup_token_permission_policy_1 = __nccwpck_require__(32450); +const setup_token_permission_policy_1 = __nccwpck_require__(99590); /** Local inputs with explicit precedence are decisions, not questions. */ function fixedSetupPatIntentQuestionIds(overrides, skipVariables, skipSecrets) { const fixed = []; @@ -50315,7 +50315,7 @@ function setupPatIntentOwnerConflict(configuration, ownerKind, projectsWanted = /***/ }), -/***/ 8385: +/***/ 10267: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50334,7 +50334,7 @@ function summarizeSetupPermissions(requirements) { /***/ }), -/***/ 59068: +/***/ 73750: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50408,7 +50408,7 @@ function validateDiscoveredProjectStatuses(configuration, discovery) { /***/ }), -/***/ 78653: +/***/ 75280: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50508,15 +50508,15 @@ function setupQuestionDocumentation(question) { /***/ }), -/***/ 54018: +/***/ 49513: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.frenchQuestionExplanation = frenchQuestionExplanation; -const setup_question_labels_fr_pt_1 = __nccwpck_require__(52621); -const setup_question_purpose_fr_pt_1 = __nccwpck_require__(51277); +const setup_question_labels_fr_pt_1 = __nccwpck_require__(28247); +const setup_question_purpose_fr_pt_1 = __nccwpck_require__(98807); const where = { capabilities: 'La configuration écrit les workflows choisis dans ce dépôt et ne demande que les autorisations GitHub nécessaires.', 'agent-runtime': 'Les workflows GitHub Actions générés lancent cet agent sur leur runner ; rien n’est installé sur cet ordinateur.', @@ -50594,19 +50594,19 @@ function frenchQuestionExplanation(question, documentation) { /***/ }), -/***/ 86641: +/***/ 42775: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setupQuestionPresentation = setupQuestionPresentation; -const setup_runner_guidance_policy_1 = __nccwpck_require__(65439); -const setup_question_translations_1 = __nccwpck_require__(62619); -const setup_question_documentation_policy_1 = __nccwpck_require__(78653); -const setup_question_purpose_policy_1 = __nccwpck_require__(44036); -const setup_question_guidance_fr_1 = __nccwpck_require__(54018); -const setup_question_guidance_pt_1 = __nccwpck_require__(51504); +const setup_runner_guidance_policy_1 = __nccwpck_require__(10741); +const setup_question_translations_1 = __nccwpck_require__(3927); +const setup_question_documentation_policy_1 = __nccwpck_require__(75280); +const setup_question_purpose_policy_1 = __nccwpck_require__(77947); +const setup_question_guidance_fr_1 = __nccwpck_require__(49513); +const setup_question_guidance_pt_1 = __nccwpck_require__(14440); const location = { capabilities: { en: 'Setup writes the selected workflow files into this repository and requests only the GitHub permissions those workflows need.', es: 'Setup escribe los workflows seleccionados en este repositorio y solicita solo los permisos de GitHub necesarios.' }, 'agent-runtime': { en: 'The generated GitHub Actions workflows invoke this agent on their runner; this does not install an agent on your computer.', es: 'Los workflows de GitHub Actions invocan este agente en su runner; no se instala en tu ordenador.' }, @@ -50739,15 +50739,15 @@ function setupQuestionPresentation(question) { /***/ }), -/***/ 51504: +/***/ 14440: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.portugueseQuestionExplanation = portugueseQuestionExplanation; -const setup_question_labels_fr_pt_1 = __nccwpck_require__(52621); -const setup_question_purpose_fr_pt_1 = __nccwpck_require__(51277); +const setup_question_labels_fr_pt_1 = __nccwpck_require__(28247); +const setup_question_purpose_fr_pt_1 = __nccwpck_require__(98807); const where = { capabilities: 'A configuração escreve os fluxos escolhidos neste repositório e pede apenas as permissões GitHub necessárias.', 'agent-runtime': 'Os fluxos GitHub Actions gerados executam este agente no respetivo runner; nada é instalado neste computador.', @@ -50825,7 +50825,7 @@ function portugueseQuestionExplanation(question, documentation) { /***/ }), -/***/ 7059: +/***/ 55765: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50919,7 +50919,7 @@ exports.questionLabelsFr = { /***/ }), -/***/ 26175: +/***/ 6958: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51013,7 +51013,7 @@ exports.questionLabelsPt = { /***/ }), -/***/ 52621: +/***/ 28247: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -51021,9 +51021,9 @@ exports.questionLabelsPt = { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.questionLabelsFrPt = void 0; exports.translatedQuestionLabel = translatedQuestionLabel; -const setup_question_translations_1 = __nccwpck_require__(62619); -const fr_1 = __nccwpck_require__(7059); -const pt_1 = __nccwpck_require__(26175); +const setup_question_translations_1 = __nccwpck_require__(3927); +const fr_1 = __nccwpck_require__(55765); +const pt_1 = __nccwpck_require__(6958); exports.questionLabelsFrPt = { fr: fr_1.questionLabelsFr, pt: pt_1.questionLabelsPt }; const roleNames = { fr: { planner: 'Planification', findings: 'Résultats', reviewer: 'Revue', fixer: 'Correction', tester: 'Tests' }, @@ -51060,7 +51060,7 @@ function translatedQuestionLabel(question, locale) { /***/ }), -/***/ 99234: +/***/ 92139: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51122,7 +51122,7 @@ exports.purposesFr = { /***/ }), -/***/ 57909: +/***/ 48284: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51184,7 +51184,7 @@ exports.purposesPt = { /***/ }), -/***/ 51277: +/***/ 98807: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -51192,8 +51192,8 @@ exports.purposesPt = { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.purposesFrPt = void 0; exports.setupQuestionPurposeFrPt = setupQuestionPurposeFrPt; -const fr_1 = __nccwpck_require__(99234); -const pt_1 = __nccwpck_require__(57909); +const fr_1 = __nccwpck_require__(92139); +const pt_1 = __nccwpck_require__(48284); exports.purposesFrPt = { fr: fr_1.purposesFr, pt: pt_1.purposesPt }; function setupQuestionPurposeFrPt(question, locale) { const exact = exports.purposesFrPt[locale][question.id]; @@ -51252,7 +51252,7 @@ function setupQuestionPurposeFrPt(question, locale) { /***/ }), -/***/ 44036: +/***/ 77947: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -51260,7 +51260,7 @@ function setupQuestionPurposeFrPt(question, locale) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setupQuestionPurposes = void 0; exports.setupQuestionPurpose = setupQuestionPurpose; -const setup_runner_guidance_policy_1 = __nccwpck_require__(65439); +const setup_runner_guidance_policy_1 = __nccwpck_require__(10741); /** Field-specific meaning for choices whose label alone is easy to misinterpret. */ exports.setupQuestionPurposes = { 'repository.verificationSetup': { en: 'Enable the repository-owned dependency setup before verification. The starter must be customized and reviewed on MAIN_BRANCH first.', es: 'Activa la preparación de dependencias del repositorio antes de verificar. Primero personaliza y revisa la plantilla en MAIN_BRANCH.' }, @@ -51377,7 +51377,7 @@ function setupQuestionPurpose(question) { /***/ }), -/***/ 62619: +/***/ 3927: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51490,7 +51490,7 @@ function spanishQuestionLabel(question) { /***/ }), -/***/ 79825: +/***/ 6009: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -51510,12 +51510,12 @@ exports.enterSetupConfirmation = enterSetupConfirmation; exports.finishSetupQuestionnaire = finishSetupQuestionnaire; exports.setupQuestionnaireStateLabel = setupQuestionnaireStateLabel; exports.setupQuestionContentInventory = setupQuestionContentInventory; -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const setup_configuration_clone_policy_1 = __nccwpck_require__(57097); -const setup_configuration_defaults_1 = __nccwpck_require__(6736); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_project_selection_policy_1 = __nccwpck_require__(59068); -const setup_runner_question_policy_1 = __nccwpck_require__(23614); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const setup_configuration_clone_policy_1 = __nccwpck_require__(85881); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_project_selection_policy_1 = __nccwpck_require__(73750); +const setup_runner_question_policy_1 = __nccwpck_require__(91198); const AGENT_PROVIDERS = ['codex', 'opencode', 'cursor']; const MODEL_PROVIDERS = ['openai', 'anthropic', 'google', 'openrouter', 'opencode', 'local']; const PERMISSION_INTENT_QUESTION_IDS = new Set([ @@ -52227,7 +52227,7 @@ function projectLabel(field) { /***/ }), -/***/ 87533: +/***/ 40582: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -52236,8 +52236,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SETUP_QUICK_SETTINGS = void 0; exports.quickSetting = quickSetting; exports.validateQuickSetting = validateQuickSetting; -const issue_inactivity_1 = __nccwpck_require__(15236); -const pull_request_description_1 = __nccwpck_require__(8324); +const issue_inactivity_1 = __nccwpck_require__(38572); +const pull_request_description_1 = __nccwpck_require__(45315); /** Small independent runtime settings. Structural changes use the complete wizard. */ exports.SETUP_QUICK_SETTINGS = [ { id: 'assignees', questionId: 'repository.desiredAssigneesCount', variable: 'DESIRED_ASSIGNEES_COUNT', input: 'desired-assignees-count', min: 0, max: 10 }, @@ -52274,7 +52274,7 @@ function validateQuickSetting(id, raw) { /***/ }), -/***/ 49505: +/***/ 92567: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -52341,7 +52341,7 @@ function setupSecretRevisionSnapshot(remote) { /***/ }), -/***/ 65439: +/***/ 10741: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -52397,15 +52397,15 @@ function setupRunnerGuidance(question) { /***/ }), -/***/ 79397: +/***/ 14706: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setupRunnerInstallationSummary = setupRunnerInstallationSummary; -const setup_runner_policy_1 = __nccwpck_require__(70801); -const setup_verification_action_summary_policy_1 = __nccwpck_require__(89007); +const setup_runner_policy_1 = __nccwpck_require__(91027); +const setup_verification_action_summary_policy_1 = __nccwpck_require__(15818); function routeBlock(route) { const json = JSON.stringify(route, null, 2); const longest = (json.match(/`+/g) ?? []).reduce((length, run) => Math.max(length, run.length), 2); @@ -52436,7 +52436,7 @@ function setupRunnerInstallationSummary(plan) { /***/ }), -/***/ 70801: +/***/ 91027: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -52452,8 +52452,8 @@ exports.reusableSetupRunnerDefaults = reusableSetupRunnerDefaults; exports.setupRunnerRole = setupRunnerRole; exports.selectedSetupRunsOn = selectedSetupRunsOn; exports.setupRunnerReadiness = setupRunnerReadiness; -const setup_runner_1 = __nccwpck_require__(34512); -const sensitive_text_1 = __nccwpck_require__(57472); +const setup_runner_1 = __nccwpck_require__(94301); +const sensitive_text_1 = __nccwpck_require__(47122); const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value); const exact = (value, keys) => Object.keys(value).every(key => keys.includes(key)); const literal = (value, empty = false) => typeof value === 'string' && value.length <= 100 @@ -52618,7 +52618,7 @@ function setupRunnerReadiness(route, inventory) { /***/ }), -/***/ 23614: +/***/ 91198: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -52627,8 +52627,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setupRunnerQuestions = setupRunnerQuestions; exports.setupRunnerQuestion = setupRunnerQuestion; exports.applySetupRunnerAnswer = applySetupRunnerAnswer; -const setup_runner_1 = __nccwpck_require__(34512); -const setup_runner_policy_1 = __nccwpck_require__(70801); +const setup_runner_1 = __nccwpck_require__(94301); +const setup_runner_policy_1 = __nccwpck_require__(91027); function setupRunnerQuestions() { const manual = (draft) => draft.runners?.mode === 'manual-self-hosted'; return [ @@ -52700,7 +52700,7 @@ function applySetupRunnerAnswer(configuration, question, input, context) { /***/ }), -/***/ 32855: +/***/ 64662: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -52714,7 +52714,7 @@ function safeTerminalChoiceText(value) { /***/ }), -/***/ 48617: +/***/ 65640: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -52831,7 +52831,7 @@ function unverifiable(requirement, message) { /***/ }), -/***/ 32450: +/***/ 99590: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -52847,11 +52847,11 @@ exports.buildSetupPatIntentUncertainty = buildSetupPatIntentUncertainty; exports.requiredSetupPatPermissionDelta = requiredSetupPatPermissionDelta; exports.buildWorkflowPatPermissionRequirements = buildWorkflowPatPermissionRequirements; exports.normalizePermissionRequirements = normalizePermissionRequirements; -const setup_configuration_plan_1 = __nccwpck_require__(69620); -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); +const setup_configuration_plan_1 = __nccwpck_require__(87770); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); const requirement = (input) => { const { idSuffix, ...details } = input; return { @@ -53183,14 +53183,14 @@ function levelRank(level) { /***/ }), -/***/ 89007: +/***/ 15818: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setupVerificationActionSummary = setupVerificationActionSummary; -const setup_verification_action_1 = __nccwpck_require__(29549); +const setup_verification_action_1 = __nccwpck_require__(33156); /** Shared terminal/installation-PR copy contains no repository-controlled Markdown. */ function setupVerificationActionSummary(review) { if (!review) @@ -53204,7 +53204,7 @@ function setupVerificationActionSummary(review) { /***/ }), -/***/ 33849: +/***/ 3449: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -53214,14 +53214,14 @@ exports.buildCopilotStatusSnapshot = buildCopilotStatusSnapshot; exports.buildCopilotStatusResult = buildCopilotStatusResult; exports.formatCopilotStatus = formatCopilotStatus; exports.projectCurrentNativeStatus = projectCurrentNativeStatus; -const pull_request_readiness_status_policy_1 = __nccwpck_require__(56053); -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const sdd_status_policy_1 = __nccwpck_require__(11756); -const result_1 = __nccwpck_require__(99917); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const bugbot_result_finding_state_projection_policy_1 = __nccwpck_require__(99362); -const publication_message_catalog_1 = __nccwpck_require__(92221); +const pull_request_readiness_status_policy_1 = __nccwpck_require__(99448); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const sdd_status_policy_1 = __nccwpck_require__(6853); +const result_1 = __nccwpck_require__(73817); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const bugbot_result_finding_state_projection_policy_1 = __nccwpck_require__(98117); +const publication_message_catalog_1 = __nccwpck_require__(34223); /** Builds a read-only status snapshot from the facts already loaded by setup. */ function buildCopilotStatusSnapshot(execution) { const issueLabels = [...(execution.labels?.currentIssueLabels ?? [])]; @@ -53354,7 +53354,7 @@ function projectCurrentNativeStatus(status, facts) { /***/ }), -/***/ 88201: +/***/ 89347: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53435,7 +53435,7 @@ function verificationRuntimeMatches(required, observed) { /***/ }), -/***/ 90620: +/***/ 65326: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53487,7 +53487,7 @@ function parseVerificationSetupResult(value) { /***/ }), -/***/ 59989: +/***/ 43193: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53516,7 +53516,7 @@ function calculateJitteredWorkflowDelay(baseDelayMilliseconds, randomValue, poli /***/ }), -/***/ 57046: +/***/ 31811: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53533,7 +53533,7 @@ exports.AGENT_EXECUTION_OUTPUT_DIAGNOSTICS = [ /***/ }), -/***/ 63737: +/***/ 64921: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53548,7 +53548,7 @@ exports.DOCTOR_REPOSITORY_PATHS = [ /***/ }), -/***/ 97793: +/***/ 6152: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53611,7 +53611,7 @@ function setGlobalLoggerDebug(debug, isRemote = false) { /***/ }), -/***/ 62151: +/***/ 46445: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53669,7 +53669,7 @@ function toPullRequestReviewOperationError(error, operation, context) { /***/ }), -/***/ 77387: +/***/ 94752: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53699,7 +53699,7 @@ function bindSddEvidenceReadPorts(ports) { /***/ }), -/***/ 63512: +/***/ 26509: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53711,16 +53711,16 @@ exports.DISABLED_VERIFICATION_SETUP = Object.freeze({ kind: 'disabled' }); /***/ }), -/***/ 85130: +/***/ 84387: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeploymentMergeEffects = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_merge_effect_error_1 = __nccwpck_require__(90452); -const managed_pull_request_1 = __nccwpck_require__(59565); +const application_error_1 = __nccwpck_require__(75999); +const deployment_merge_effect_error_1 = __nccwpck_require__(72594); +const managed_pull_request_1 = __nccwpck_require__(95914); /** Applies current policy, with one bounded re-observation after a typed readiness rejection. */ class DeploymentMergeEffects { constructor(pullRequests) { @@ -53796,7 +53796,7 @@ function assertSamePullRequest(expected, current) { /***/ }), -/***/ 38233: +/***/ 77658: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -53811,14 +53811,14 @@ exports.deploymentSuccess = deploymentSuccess; exports.blockedDeploymentResult = blockedDeploymentResult; exports.shouldRecordUnexpectedFailure = shouldRecordUnexpectedFailure; exports.semanticCleanupError = semanticCleanupError; -const application_error_1 = __nccwpck_require__(1889); -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_presentation_policy_1 = __nccwpck_require__(77857); -const deployment_message_catalog_1 = __nccwpck_require__(21090); -const deployment_operation_1 = __nccwpck_require__(10915); -const merge_queue_readiness_1 = __nccwpck_require__(86918); -const result_1 = __nccwpck_require__(99917); -const deployment_merge_effects_1 = __nccwpck_require__(85130); +const application_error_1 = __nccwpck_require__(75999); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_presentation_policy_1 = __nccwpck_require__(83221); +const deployment_message_catalog_1 = __nccwpck_require__(79364); +const deployment_operation_1 = __nccwpck_require__(92730); +const merge_queue_readiness_1 = __nccwpck_require__(12515); +const result_1 = __nccwpck_require__(73817); +const deployment_merge_effects_1 = __nccwpck_require__(84387); exports.DEPLOYMENT_ORCHESTRATION_TASK_ID = "DeploymentOrchestrationUseCase"; class DeploymentOrchestrationRuntime { constructor(dependencies, stateBoundary) { @@ -54088,16 +54088,16 @@ function failureCategory(operation) { /***/ }), -/***/ 8563: +/***/ 27827: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SupersededDeploymentInvocationError = exports.DeploymentStateBoundary = void 0; -const deployment_state_fence_1 = __nccwpck_require__(78892); -const deployment_lifecycle_policy_1 = __nccwpck_require__(39578); -const application_error_1 = __nccwpck_require__(1889); +const deployment_state_fence_1 = __nccwpck_require__(72369); +const deployment_lifecycle_policy_1 = __nccwpck_require__(54037); +const application_error_1 = __nccwpck_require__(75999); class DeploymentStateBoundary { constructor(state, labels) { this.state = state; @@ -54177,14 +54177,14 @@ exports.SupersededDeploymentInvocationError = SupersededDeploymentInvocationErro /***/ }), -/***/ 1980: +/***/ 41601: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckProgressUseCase = void 0; -const check_progress_workflow_1 = __nccwpck_require__(88755); +const check_progress_workflow_1 = __nccwpck_require__(94343); /** Application boundary for assessing and publishing issue progress. */ class CheckProgressUseCase { constructor(issueDescriptionQueryPort, issueLabelsPort, issueProgressPort, branchRepository, pullRequestRepository, aiRepository, publicationSourceQuery, progressDiffQuery) { @@ -54216,21 +54216,21 @@ exports.CheckProgressUseCase = CheckProgressUseCase; /***/ }), -/***/ 88755: +/***/ 94343: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCheckProgressWorkflow = runCheckProgressWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const sync_progress_labels_to_open_pull_requests_1 = __nccwpck_require__(55198); -const progress_summary_builder_1 = __nccwpck_require__(42351); -const progress_analysis_workflow_1 = __nccwpck_require__(41135); -const application_error_1 = __nccwpck_require__(1889); -const publication_outcome_policy_1 = __nccwpck_require__(45483); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const sync_progress_labels_to_open_pull_requests_1 = __nccwpck_require__(18277); +const progress_summary_builder_1 = __nccwpck_require__(62721); +const progress_analysis_workflow_1 = __nccwpck_require__(88729); +const application_error_1 = __nccwpck_require__(75999); +const publication_outcome_policy_1 = __nccwpck_require__(79719); /** Publishes a completed progress assessment after the analysis workflow succeeds. */ async function runCheckProgressWorkflow(param, taskId, dependencies) { (0, logging_ports_1.logInfo)(`${(0, task_emoji_1.getTaskEmoji)(taskId)} Executing ${taskId}.`); @@ -54344,14 +54344,14 @@ function logProgressAssessment(progress, summary, reasoning, remaining) { /***/ }), -/***/ 38028: +/***/ 84579: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CloseInactiveIssuesUseCase = void 0; -const close_inactive_issues_workflow_1 = __nccwpck_require__(80159); +const close_inactive_issues_workflow_1 = __nccwpck_require__(86288); /** Application boundary for the scheduled inactivity-maintenance action. */ class CloseInactiveIssuesUseCase { constructor(issueQueryPort, issueClosurePort, clock, catalogResolver) { @@ -54375,19 +54375,19 @@ exports.CloseInactiveIssuesUseCase = CloseInactiveIssuesUseCase; /***/ }), -/***/ 80159: +/***/ 86288: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCloseInactiveIssuesWorkflow = runCloseInactiveIssuesWorkflow; -const result_1 = __nccwpck_require__(99917); -const issue_inactivity_1 = __nccwpck_require__(15236); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const inactivity_message_catalog_1 = __nccwpck_require__(20617); -const inactivity_notification_policy_1 = __nccwpck_require__(59025); +const result_1 = __nccwpck_require__(73817); +const issue_inactivity_1 = __nccwpck_require__(38572); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const inactivity_message_catalog_1 = __nccwpck_require__(74902); +const inactivity_notification_policy_1 = __nccwpck_require__(1572); const TASK_ID = 'CloseInactiveIssuesUseCase'; /** Scans waiting issues and closes only candidates that remain inactive. */ async function runCloseInactiveIssuesWorkflow(param, dependencies) { @@ -54541,7 +54541,7 @@ function unique(values) { /***/ }), -/***/ 3685: +/***/ 76549: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -54550,8 +54550,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validateReleaseInput = validateReleaseInput; exports.normalizeVersion = normalizeVersion; exports.versionForRelease = versionForRelease; -const input_keys_1 = __nccwpck_require__(27112); -const application_error_1 = __nccwpck_require__(1889); +const input_keys_1 = __nccwpck_require__(88539); +const application_error_1 = __nccwpck_require__(75999); const SEMVER_PATTERN = /^\d+(\.\d+){0,2}$/; function validateReleaseInput(input) { if (!input.version.length) @@ -54579,16 +54579,16 @@ function versionForRelease(version) { /***/ }), -/***/ 86222: +/***/ 25258: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CreateReleaseUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const create_release_workflow_1 = __nccwpck_require__(98684); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const create_release_workflow_1 = __nccwpck_require__(75138); class CreateReleaseUseCase { constructor(repositoryReleasePort) { this.repositoryReleasePort = repositoryReleasePort; @@ -54604,18 +54604,18 @@ exports.CreateReleaseUseCase = CreateReleaseUseCase; /***/ }), -/***/ 98684: +/***/ 75138: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCreateRelease = runCreateRelease; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const create_release_policy_1 = __nccwpck_require__(3685); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const create_release_policy_1 = __nccwpck_require__(76549); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); +const application_error_1 = __nccwpck_require__(75999); async function runCreateRelease(param, taskId, repositoryReleasePort) { const operation = param.operation; const continuationError = (0, deployment_continuation_guard_1.validateDeploymentContinuation)(operation, param.requestedOperationId, ["publishing"], param.requestedVersion); @@ -54666,16 +54666,16 @@ function failureResult(taskId, message, code) { /***/ }), -/***/ 54522: +/***/ 22120: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CreateTagUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const create_tag_workflow_1 = __nccwpck_require__(89893); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const create_tag_workflow_1 = __nccwpck_require__(23539); class CreateTagUseCase { constructor(repositoryReleasePort) { this.repositoryReleasePort = repositoryReleasePort; @@ -54691,17 +54691,17 @@ exports.CreateTagUseCase = CreateTagUseCase; /***/ }), -/***/ 89893: +/***/ 23539: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCreateTag = runCreateTag; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); +const application_error_1 = __nccwpck_require__(75999); async function runCreateTag(param, taskId, repositoryTagPort) { const validationFailure = validateTagInput(param, taskId); if (validationFailure) @@ -54741,14 +54741,14 @@ function noTagResult(taskId, tagName) { /***/ }), -/***/ 40810: +/***/ 28399: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AcceptPromotionHandler = void 0; -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class AcceptPromotionHandler { constructor(runtime) { this.runtime = runtime; @@ -54803,18 +54803,18 @@ function matchesPromotion(operation, pullRequest) { /***/ }), -/***/ 76203: +/***/ 46361: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ConfirmPublicationHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_operation_1 = __nccwpck_require__(10915); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); +const application_error_1 = __nccwpck_require__(75999); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_operation_1 = __nccwpck_require__(92730); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); class ConfirmPublicationHandler { constructor(runtime, reconciliation) { this.runtime = runtime; @@ -54911,17 +54911,17 @@ function requireProductionSha(operation) { /***/ }), -/***/ 24638: +/***/ 85138: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ContinueDeploymentHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_operation_1 = __nccwpck_require__(10915); -const managed_pull_request_1 = __nccwpck_require__(59565); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const application_error_1 = __nccwpck_require__(75999); +const deployment_operation_1 = __nccwpck_require__(92730); +const managed_pull_request_1 = __nccwpck_require__(95914); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class ContinueDeploymentHandler { constructor(runtime, acceptPromotion, reconciliation) { this.runtime = runtime; @@ -54997,17 +54997,17 @@ function assertSameRepository(context, pullRequest) { /***/ }), -/***/ 34630: +/***/ 43877: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PreparePromotionHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_operation_1 = __nccwpck_require__(10915); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const application_error_1 = __nccwpck_require__(75999); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_operation_1 = __nccwpck_require__(92730); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class PreparePromotionHandler { constructor(runtime, acceptPromotion) { this.runtime = runtime; @@ -55164,17 +55164,17 @@ function pendingPromotion(operation, pullRequest) { /***/ }), -/***/ 6091: +/***/ 3344: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReconciliationHandler = void 0; -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_operation_1 = __nccwpck_require__(10915); -const managed_pull_request_1 = __nccwpck_require__(59565); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_operation_1 = __nccwpck_require__(92730); +const managed_pull_request_1 = __nccwpck_require__(95914); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class ReconciliationHandler { constructor(runtime) { this.runtime = runtime; @@ -55336,17 +55336,17 @@ exports.ReconciliationHandler = ReconciliationHandler; /***/ }), -/***/ 47708: +/***/ 66571: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RecordFailureHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const result_1 = __nccwpck_require__(99917); -const deployment_operation_1 = __nccwpck_require__(10915); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const application_error_1 = __nccwpck_require__(75999); +const result_1 = __nccwpck_require__(73817); +const deployment_operation_1 = __nccwpck_require__(92730); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class RecordFailureHandler { constructor(runtime) { this.runtime = runtime; @@ -55385,23 +55385,23 @@ function failureCategory(phase) { /***/ }), -/***/ 54934: +/***/ 36850: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeploymentOrchestrationUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); -const deployment_state_boundary_1 = __nccwpck_require__(8563); -const result_1 = __nccwpck_require__(99917); -const accept_promotion_handler_1 = __nccwpck_require__(40810); -const confirm_publication_handler_1 = __nccwpck_require__(76203); -const continue_deployment_handler_1 = __nccwpck_require__(24638); -const prepare_promotion_handler_1 = __nccwpck_require__(34630); -const reconciliation_handler_1 = __nccwpck_require__(6091); -const record_failure_handler_1 = __nccwpck_require__(47708); +const application_error_1 = __nccwpck_require__(75999); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); +const deployment_state_boundary_1 = __nccwpck_require__(27827); +const result_1 = __nccwpck_require__(73817); +const accept_promotion_handler_1 = __nccwpck_require__(28399); +const confirm_publication_handler_1 = __nccwpck_require__(46361); +const continue_deployment_handler_1 = __nccwpck_require__(85138); +const prepare_promotion_handler_1 = __nccwpck_require__(43877); +const reconciliation_handler_1 = __nccwpck_require__(3344); +const record_failure_handler_1 = __nccwpck_require__(66571); class DeploymentOrchestrationUseCase { constructor(dependencies) { this.taskId = deployment_orchestration_runtime_1.DEPLOYMENT_ORCHESTRATION_TASK_ID; @@ -55458,14 +55458,14 @@ exports.DeploymentOrchestrationUseCase = DeploymentOrchestrationUseCase; /***/ }), -/***/ 86429: +/***/ 38575: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findIssueBranch = findIssueBranch; -const logging_ports_1 = __nccwpck_require__(97793); +const logging_ports_1 = __nccwpck_require__(6152); async function findIssueBranch(param, repository) { if (param.pushedBranch) return param.pushedBranch; @@ -55483,14 +55483,14 @@ async function findIssueBranch(param, repository) { /***/ }), -/***/ 98239: +/***/ 84837: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.InitialSetupUseCase = void 0; -const initial_setup_workflow_1 = __nccwpck_require__(42347); +const initial_setup_workflow_1 = __nccwpck_require__(18079); /** Application boundary for provisioning a repository for Copilot automation. */ class InitialSetupUseCase { constructor(authenticatedUserPort, initialLabelProvisioningPort, issueTypeProvisioningPort, latestTagQueryPort, repositoryDefaultBranchPort, repositoryTagPort, setupWorkspacePort, setupRepositoryVariablesPort, setupRepositorySecretsPort, setupRemoteConfigurationReadPort, progress) { @@ -55528,22 +55528,22 @@ exports.InitialSetupUseCase = InitialSetupUseCase; /***/ }), -/***/ 42347: +/***/ 18079: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runInitialSetupWorkflow = runInitialSetupWorkflow; -const result_1 = __nccwpck_require__(99917); -const version_policy_1 = __nccwpck_require__(36071); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const setup_resource_provisioning_1 = __nccwpck_require__(72108); -const application_error_1 = __nccwpck_require__(1889); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const setup_issue_resource_policy_1 = __nccwpck_require__(5660); -const setup_configuration_policy_1 = __nccwpck_require__(58409); +const result_1 = __nccwpck_require__(73817); +const version_policy_1 = __nccwpck_require__(8381); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const setup_resource_provisioning_1 = __nccwpck_require__(94894); +const application_error_1 = __nccwpck_require__(75999); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const setup_issue_resource_policy_1 = __nccwpck_require__(67323); +const setup_configuration_policy_1 = __nccwpck_require__(56637); const TASK_ID = 'InitialSetupUseCase'; /** Runs repository setup as an ordered application workflow with explicit port dependencies. */ async function runInitialSetupWorkflow(request, dependencies) { @@ -55803,7 +55803,7 @@ function variableFailureError(failure) { /***/ }), -/***/ 98322: +/***/ 28121: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -55894,22 +55894,22 @@ function projectEvidence(source) { /***/ }), -/***/ 83257: +/***/ 84542: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ObserveBranchSyncUseCase = void 0; -const publication_identity_policy_1 = __nccwpck_require__(17167); -const result_1 = __nccwpck_require__(99917); -const branch_sync_notification_policy_1 = __nccwpck_require__(13754); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const branch_sync_message_catalog_1 = __nccwpck_require__(23142); -const transition_notification_workflow_1 = __nccwpck_require__(59833); -const publication_outcome_policy_1 = __nccwpck_require__(45483); -const application_error_2 = __nccwpck_require__(1889); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const result_1 = __nccwpck_require__(73817); +const branch_sync_notification_policy_1 = __nccwpck_require__(79895); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const branch_sync_message_catalog_1 = __nccwpck_require__(89245); +const transition_notification_workflow_1 = __nccwpck_require__(1725); +const publication_outcome_policy_1 = __nccwpck_require__(79719); +const application_error_2 = __nccwpck_require__(75999); const TASK_ID = "ObserveBranchSyncUseCase"; /** * Cheap push-time observer. It only queries branch relationships/comparisons @@ -56084,27 +56084,27 @@ function failure(message, cause, payload) { /***/ }), -/***/ 41135: +/***/ 88729: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.analyzeProgress = analyzeProgress; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const find_issue_branch_1 = __nccwpck_require__(86429); -const progress_prerequisite_policy_1 = __nccwpck_require__(73684); -const progress_response_1 = __nccwpck_require__(11680); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const summarize_progress_diff_workflow_1 = __nccwpck_require__(47423); -const agent_execution_plan_1 = __nccwpck_require__(52013); -const progress_partition_response_policy_1 = __nccwpck_require__(51545); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const find_issue_branch_1 = __nccwpck_require__(38575); +const progress_prerequisite_policy_1 = __nccwpck_require__(31001); +const progress_response_1 = __nccwpck_require__(64264); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const summarize_progress_diff_workflow_1 = __nccwpck_require__(79582); +const agent_execution_plan_1 = __nccwpck_require__(12253); +const progress_partition_response_policy_1 = __nccwpck_require__(30025); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); /** Loads progress context and asks the configured agent for an assessment. */ async function analyzeProgress(param, taskId, dependencies) { const issueNumber = param.issueNumber; @@ -56200,7 +56200,7 @@ function failure(taskId, message, code) { /***/ }), -/***/ 73684: +/***/ 31001: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -56226,7 +56226,7 @@ function validateProgressPrerequisites(input) { /***/ }), -/***/ 11680: +/***/ 64264: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -56234,8 +56234,8 @@ function validateProgressPrerequisites(input) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PROGRESS_RESPONSE_SCHEMA = void 0; exports.parseProgressResponse = parseProgressResponse; -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const application_error_1 = __nccwpck_require__(1889); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const application_error_1 = __nccwpck_require__(75999); exports.PROGRESS_RESPONSE_SCHEMA = { type: 'object', properties: { @@ -56265,7 +56265,7 @@ function parseProgressResponse(response, targetLocale) { /***/ }), -/***/ 42351: +/***/ 62721: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -56297,16 +56297,16 @@ function buildProgressSummaryMessage({ summary, progress, remaining, reasoning } /***/ }), -/***/ 56702: +/***/ 68891: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PublishGithubActionUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const publish_github_action_workflow_1 = __nccwpck_require__(22075); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const publish_github_action_workflow_1 = __nccwpck_require__(63037); class PublishGithubActionUseCase { constructor(repositoryTagPort, repositoryReleasePort) { this.repositoryTagPort = repositoryTagPort; @@ -56323,18 +56323,18 @@ exports.PublishGithubActionUseCase = PublishGithubActionUseCase; /***/ }), -/***/ 22075: +/***/ 63037: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPublishGithubAction = runPublishGithubAction; -const result_1 = __nccwpck_require__(99917); -const input_keys_1 = __nccwpck_require__(27112); -const logging_ports_1 = __nccwpck_require__(97793); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const input_keys_1 = __nccwpck_require__(88539); +const logging_ports_1 = __nccwpck_require__(6152); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); +const application_error_1 = __nccwpck_require__(75999); async function runPublishGithubAction(param, taskId, repositoryTagPort, repositoryReleasePort) { const validationFailure = validateVersion(param, taskId); if (validationFailure) @@ -56379,16 +56379,16 @@ function failureResult(taskId, sourceTag, targetTag) { /***/ }), -/***/ 10562: +/***/ 61313: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PublishIssueCommentUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const publish_issue_comment_workflow_1 = __nccwpck_require__(84095); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const publish_issue_comment_workflow_1 = __nccwpck_require__(30626); /** Application boundary for creating or updating a specific issue comment. */ class PublishIssueCommentUseCase { constructor(issueCommentPort) { @@ -56405,16 +56405,16 @@ exports.PublishIssueCommentUseCase = PublishIssueCommentUseCase; /***/ }), -/***/ 84095: +/***/ 30626: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPublishIssueComment = runPublishIssueComment; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); async function runPublishIssueComment(param, taskId, issueCommentPort) { if (param.kind === 'invalid') { return [new result_1.Result({ @@ -56463,7 +56463,7 @@ function appendCommentContent(previous, addition) { /***/ }), -/***/ 23139: +/***/ 65928: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -56471,12 +56471,12 @@ function appendCommentContent(previous, addition) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildRecommendationResult = buildRecommendationResult; exports.extractImplementationPlan = extractImplementationPlan; -const result_1 = __nccwpck_require__(99917); -const recommendation_policy_1 = __nccwpck_require__(33990); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const implementation_plan_1 = __nccwpck_require__(8768); +const result_1 = __nccwpck_require__(73817); +const recommendation_policy_1 = __nccwpck_require__(39410); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const implementation_plan_1 = __nccwpck_require__(77001); function buildRecommendationResult(param, taskId, response, issueDescriptionFingerprint, previousRecommendation, issueNumber) { const extracted = extractImplementationPlan(response, param.targetLocale); if (!extracted) { @@ -56563,14 +56563,14 @@ function hasOnlyResponseKeys(payload) { /***/ }), -/***/ 32484: +/***/ 73746: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RecommendStepsUseCase = void 0; -const recommend_steps_workflow_1 = __nccwpck_require__(3298); +const recommend_steps_workflow_1 = __nccwpck_require__(77522); /** Application boundary for generating non-duplicated implementation guidance. */ class RecommendStepsUseCase { constructor(issueDescriptionQueryPort, aiRepository) { @@ -56590,7 +56590,7 @@ exports.RecommendStepsUseCase = RecommendStepsUseCase; /***/ }), -/***/ 3298: +/***/ 77522: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -56598,19 +56598,19 @@ exports.RecommendStepsUseCase = RecommendStepsUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runRecommendStepsWorkflow = runRecommendStepsWorkflow; exports.queryImplementationPlan = queryImplementationPlan; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const recommendation_policy_1 = __nccwpck_require__(33990); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const project_context_instruction_1 = __nccwpck_require__(55527); -const task_emoji_1 = __nccwpck_require__(8353); -const recommend_steps_result_policy_1 = __nccwpck_require__(23139); -const application_error_1 = __nccwpck_require__(1889); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const implementation_plan_1 = __nccwpck_require__(8768); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const recommendation_policy_1 = __nccwpck_require__(39410); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const project_context_instruction_1 = __nccwpck_require__(63907); +const task_emoji_1 = __nccwpck_require__(46103); +const recommend_steps_result_policy_1 = __nccwpck_require__(65928); +const application_error_1 = __nccwpck_require__(75999); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const implementation_plan_1 = __nccwpck_require__(77001); /** Runs the recommendation policy and agent interaction for an issue. */ async function runRecommendStepsWorkflow(param, taskId, dependencies) { (0, logging_ports_1.logInfo)(`${(0, task_emoji_1.getTaskEmoji)(taskId)} Executing ${taskId}.`); @@ -56708,17 +56708,17 @@ function failure(taskId, message, code) { /***/ }), -/***/ 30842: +/***/ 49050: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReconcileClosedIssueMetadataUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const reconcile_issue_completion_metadata_1 = __nccwpck_require__(73082); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const reconcile_issue_completion_metadata_1 = __nccwpck_require__(70614); /** Selective completion repair from fresh native facts; no native state authority. */ class ReconcileClosedIssueMetadataUseCase { constructor(issues) { @@ -56753,7 +56753,7 @@ function stale() { /***/ }), -/***/ 35318: +/***/ 11687: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -56776,7 +56776,7 @@ exports.ReconcileClosedIssueUseCase = ReconcileClosedIssueUseCase; /***/ }), -/***/ 73082: +/***/ 70614: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -56784,9 +56784,9 @@ exports.ReconcileClosedIssueUseCase = ReconcileClosedIssueUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.completionRepairProgress = void 0; exports.reconcileIssueCompletionMetadata = reconcileIssueCompletionMetadata; -const application_error_1 = __nccwpck_require__(1889); -const issue_completion_1 = __nccwpck_require__(28272); -const closed_issue_reconciliation_1 = __nccwpck_require__(31012); +const application_error_1 = __nccwpck_require__(75999); +const issue_completion_1 = __nccwpck_require__(31147); +const closed_issue_reconciliation_1 = __nccwpck_require__(21565); const completionRepairProgress = () => ({ nativeClosed: false, labelsChanged: 0, phase: 'identity', state: 'unavailable', reason: 'unavailable', remaining: 0 }); exports.completionRepairProgress = completionRepairProgress; @@ -56854,22 +56854,22 @@ async function reconcileIssueCompletionMetadata(target, number, configuration, p /***/ }), -/***/ 77535: +/***/ 74111: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RetireBranchSyncUseCase = void 0; -const verify_closed_issue_card_retirement_1 = __nccwpck_require__(68606); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const closed_issue_reconciliation_1 = __nccwpck_require__(31012); -const result_1 = __nccwpck_require__(99917); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const branch_sync_notification_policy_1 = __nccwpck_require__(13754); -const branch_sync_message_catalog_1 = __nccwpck_require__(23142); -const application_error_1 = __nccwpck_require__(1889); +const verify_closed_issue_card_retirement_1 = __nccwpck_require__(78813); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const closed_issue_reconciliation_1 = __nccwpck_require__(21565); +const result_1 = __nccwpck_require__(73817); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const branch_sync_notification_policy_1 = __nccwpck_require__(79895); +const branch_sync_message_catalog_1 = __nccwpck_require__(89245); +const application_error_1 = __nccwpck_require__(75999); /** Retire existing owned status cards only; no create/delete, labels, Git or agent authority. */ class RetireBranchSyncUseCase { constructor(issues, comments, cardFreshness) { @@ -56960,7 +56960,7 @@ function stale() { /***/ }), -/***/ 50831: +/***/ 11529: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -56983,21 +56983,21 @@ exports.RetireClosedIssueCardsUseCase = RetireClosedIssueCardsUseCase; /***/ }), -/***/ 7427: +/***/ 17025: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RetireProgressUseCase = void 0; -const verify_closed_issue_card_retirement_1 = __nccwpck_require__(68606); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const closed_issue_reconciliation_1 = __nccwpck_require__(31012); -const result_1 = __nccwpck_require__(99917); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const retired_progress_presentation_policy_1 = __nccwpck_require__(96361); -const application_error_1 = __nccwpck_require__(1889); +const verify_closed_issue_card_retirement_1 = __nccwpck_require__(78813); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const closed_issue_reconciliation_1 = __nccwpck_require__(21565); +const result_1 = __nccwpck_require__(73817); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const retired_progress_presentation_policy_1 = __nccwpck_require__(93427); +const application_error_1 = __nccwpck_require__(75999); /** Retire existing owned status cards only; no create/delete, labels, Git or agent authority. */ class RetireProgressUseCase { constructor(issues, comments, cardFreshness) { @@ -57086,7 +57086,7 @@ function stale() { /***/ }), -/***/ 72108: +/***/ 94894: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -57097,12 +57097,12 @@ exports.ensureRepositoryVariables = ensureRepositoryVariables; exports.ensureRepositorySecrets = ensureRepositorySecrets; exports.resolveRemoteConfiguration = resolveRemoteConfiguration; exports.groupSetupResources = groupSetupResources; -const setup_remote_facts_policy_1 = __nccwpck_require__(49505); -const setup_runner_policy_1 = __nccwpck_require__(70801); -const setup_configuration_policy_1 = __nccwpck_require__(58409); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); +const setup_remote_facts_policy_1 = __nccwpck_require__(92567); +const setup_runner_policy_1 = __nccwpck_require__(91027); +const setup_configuration_policy_1 = __nccwpck_require__(56637); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); exports.VARIABLE_PROVISIONING_UNAVAILABLE = 'GitHub Actions Variable provisioning is unavailable; no Variables were changed.'; exports.SECRET_PROVISIONING_UNAVAILABLE = 'GitHub Actions Secret provisioning is unavailable; no Secrets were changed.'; async function ensureRepositoryVariables(context, dependencies, setupConfiguration, remoteConfiguration) { @@ -57335,19 +57335,19 @@ async function upsertSecretGroups(context, port, groups) { /***/ }), -/***/ 47423: +/***/ 79582: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.summarizeProgressDiff = summarizeProgressDiff; -const agent_task_policy_1 = __nccwpck_require__(34816); -const progress_partition_response_policy_1 = __nccwpck_require__(51545); -const agent_execution_plan_1 = __nccwpck_require__(52013); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const logging_ports_1 = __nccwpck_require__(97793); +const agent_task_policy_1 = __nccwpck_require__(85712); +const progress_partition_response_policy_1 = __nccwpck_require__(30025); +const agent_execution_plan_1 = __nccwpck_require__(12253); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const logging_ports_1 = __nccwpck_require__(6152); /** Collects every part before exposing one aggregate to the final assessment. No mutation capability. */ async function summarizeProgressDiff(diff, context, issueDescription, agent, aggregateBudget) { if (diff.kind !== 'partitioned') @@ -57379,15 +57379,15 @@ immutableComparison: ${partition.evidence}`); /***/ }), -/***/ 55198: +/***/ 18277: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.syncProgressLabelsToOpenPullRequests = syncProgressLabelsToOpenPullRequests; -const progress_labels_1 = __nccwpck_require__(11696); -const logging_ports_1 = __nccwpck_require__(97793); +const progress_labels_1 = __nccwpck_require__(97890); +const logging_ports_1 = __nccwpck_require__(6152); async function syncProgressLabelsToOpenPullRequests(branch, progress, issueRepository, pullRequestRepository) { const roundedProgress = Math.min(100, Math.max(0, Math.round(progress / 5) * 5)); const newProgressLabel = `${roundedProgress}%`; @@ -57406,16 +57406,16 @@ async function syncProgressLabelsToOpenPullRequests(branch, progress, issueRepos /***/ }), -/***/ 64084: +/***/ 44880: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SynchronizeAgentActivityUseCase = void 0; -const agent_activity_label_policy_1 = __nccwpck_require__(69965); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const agent_activity_label_policy_1 = __nccwpck_require__(79966); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); /** * Maintains the temporary agent-activity label around a complete route. * Cleanup is deliberately best-effort so a label outage never hides the @@ -57468,15 +57468,15 @@ function sameLabels(left, right) { /***/ }), -/***/ 68606: +/***/ 78813: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.verifyClosedIssueCardRetirement = verifyClosedIssueCardRetirement; -const reply_request_digest_1 = __nccwpck_require__(73250); -const application_error_1 = __nccwpck_require__(1889); +const reply_request_digest_1 = __nccwpck_require__(47971); +const application_error_1 = __nccwpck_require__(75999); /** Adopt another invocation only after the exact final owned body and native closure are fresh. */ async function verifyClosedIssueCardRetirement(input) { const witness = (body) => Object.freeze({ surface: 'issue-comment', @@ -57510,16 +57510,16 @@ async function verifyClosedIssueCardRetirement(input) { /***/ }), -/***/ 68375: +/***/ 4643: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runBranchSyncCommand = runBranchSyncCommand; -const result_1 = __nccwpck_require__(99917); -const branch_sync_command_1 = __nccwpck_require__(48721); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const branch_sync_command_1 = __nccwpck_require__(51114); +const application_error_1 = __nccwpck_require__(75999); /** Authorizes and runs an explicit or natural-language branch synchronization request. */ async function runBranchSyncCommand(context, options, args, authorization) { const parsed = (0, branch_sync_command_1.parseBranchSyncCommandArguments)(args); @@ -57555,7 +57555,7 @@ function unauthorized(taskId) { /***/ }), -/***/ 43913: +/***/ 82113: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -57566,10 +57566,10 @@ exports.branchSyncConflictEligibilityFailure = branchSyncConflictEligibilityFail exports.completedBranchSyncResult = completedBranchSyncResult; exports.unavailableBranchSyncResult = unavailableBranchSyncResult; exports.failedBranchSyncResult = failedBranchSyncResult; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const workspace_changes_1 = __nccwpck_require__(33363); -const application_error_1 = __nccwpck_require__(1889); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const workspace_changes_1 = __nccwpck_require__(93370); +const application_error_1 = __nccwpck_require__(75999); exports.BRANCH_SYNC_TASK_ID = "SyncBranchUseCase"; const MAX_AGENT_CONFLICT_PATHS = 20; function branchSyncConflictEligibilityFailure(preparation, useAgent, agentConfiguration) { @@ -57637,19 +57637,19 @@ function failedBranchSyncResult(reason, cause, recovery) { /***/ }), -/***/ 97905: +/***/ 392: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SyncBranchUseCase = void 0; -const branch_sync_validation_1 = __nccwpck_require__(70155); -const branch_sync_conflicts_1 = __nccwpck_require__(49328); -const logging_ports_1 = __nccwpck_require__(97793); -const verify_command_policy_1 = __nccwpck_require__(23322); -const verify_command_runner_1 = __nccwpck_require__(50827); -const branch_sync_execution_policy_1 = __nccwpck_require__(43913); +const branch_sync_validation_1 = __nccwpck_require__(90981); +const branch_sync_conflicts_1 = __nccwpck_require__(84434); +const logging_ports_1 = __nccwpck_require__(6152); +const verify_command_policy_1 = __nccwpck_require__(96031); +const verify_command_runner_1 = __nccwpck_require__(57742); +const branch_sync_execution_policy_1 = __nccwpck_require__(82113); /** Performs a race-safe parent-to-child merge and invokes the fixer only for eligible conflicts. */ class SyncBranchUseCase { constructor(dependencies, workspace, fixer, authenticatedUser, git) { @@ -57782,14 +57782,14 @@ function validationRecovery(code) { /***/ }), -/***/ 63469: +/***/ 55721: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckCliUpdateUseCase = void 0; -const cli_version_1 = __nccwpck_require__(11149); +const cli_version_1 = __nccwpck_require__(27089); /** Checks for a newer published CLI version without coupling the application to npm. */ class CheckCliUpdateUseCase { constructor(cliUpdateCheckPort) { @@ -57807,20 +57807,20 @@ exports.CheckCliUpdateUseCase = CheckCliUpdateUseCase; /***/ }), -/***/ 29908: +/***/ 42442: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommentAutomationAction = runCommentAutomationAction; -const result_1 = __nccwpck_require__(99917); -const implementation_result_policy_1 = __nccwpck_require__(39606); -const commit_autofix_and_resolve_workflow_1 = __nccwpck_require__(98022); -const commit_user_request_workflow_1 = __nccwpck_require__(41729); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const comment_mutation_target_workflow_1 = __nccwpck_require__(63049); +const result_1 = __nccwpck_require__(73817); +const implementation_result_policy_1 = __nccwpck_require__(30203); +const commit_autofix_and_resolve_workflow_1 = __nccwpck_require__(93455); +const commit_user_request_workflow_1 = __nccwpck_require__(43393); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const comment_mutation_target_workflow_1 = __nccwpck_require__(81324); /** Runs the selected mutating action and returns any result records it produces. */ async function runCommentAutomationAction(param, options, route, intentPayload) { if (route === "review") @@ -57951,7 +57951,7 @@ async function runDoUserRequestAction(param, options, intentPayload) { /***/ }), -/***/ 39723: +/***/ 63134: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -57959,20 +57959,20 @@ async function runDoUserRequestAction(param, options, intentPayload) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runExplicitCommentCommand = runExplicitCommentCommand; exports.invalidCommentCommandResult = invalidCommentCommandResult; -const sdd_diff_presentation_policy_1 = __nccwpck_require__(11594); -const sdd_diff_message_catalog_1 = __nccwpck_require__(29948); -const read_copilot_doctor_workflow_1 = __nccwpck_require__(97584); -const read_copilot_history_workflow_1 = __nccwpck_require__(11603); -const result_1 = __nccwpck_require__(99917); -const read_copilot_status_workflow_1 = __nccwpck_require__(28724); -const copilot_interaction_policy_1 = __nccwpck_require__(52113); -const review_command_1 = __nccwpck_require__(93789); -const commit_user_request_workflow_1 = __nccwpck_require__(41729); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const branch_sync_comment_command_1 = __nccwpck_require__(68375); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const comment_mutation_target_workflow_1 = __nccwpck_require__(63049); +const sdd_diff_presentation_policy_1 = __nccwpck_require__(63302); +const sdd_diff_message_catalog_1 = __nccwpck_require__(2230); +const read_copilot_doctor_workflow_1 = __nccwpck_require__(12416); +const read_copilot_history_workflow_1 = __nccwpck_require__(8140); +const result_1 = __nccwpck_require__(73817); +const read_copilot_status_workflow_1 = __nccwpck_require__(57206); +const copilot_interaction_policy_1 = __nccwpck_require__(90108); +const review_command_1 = __nccwpck_require__(1811); +const commit_user_request_workflow_1 = __nccwpck_require__(43393); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const branch_sync_comment_command_1 = __nccwpck_require__(4643); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const comment_mutation_target_workflow_1 = __nccwpck_require__(81324); const LEARNED_BUGBOT_RULE_PATH = '.copilot/BUGBOT.learned.md'; /** Executes deterministic /copilot commands without routing them through intent detection. */ async function runExplicitCommentCommand(param, options, command, actorAuthorizationPort) { @@ -58174,16 +58174,16 @@ function invalidCommentCommandResult(taskId, reason) { /***/ }), -/***/ 10261: +/***/ 46187: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.completeCommentAutomation = completeCommentAutomation; -const bugbot_fix_intent_payload_1 = __nccwpck_require__(90862); -const logging_ports_1 = __nccwpck_require__(97793); -const comment_automation_action_workflow_1 = __nccwpck_require__(29908); +const bugbot_fix_intent_payload_1 = __nccwpck_require__(25734); +const logging_ports_1 = __nccwpck_require__(6152); +const comment_automation_action_workflow_1 = __nccwpck_require__(42442); async function completeCommentAutomation(param, options, decision) { logUnauthorizedActionSkip(decision); if (decision.route === 'think') { @@ -58203,7 +58203,7 @@ function logUnauthorizedActionSkip(decision) { /***/ }), -/***/ 90059: +/***/ 37055: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -58211,15 +58211,15 @@ function logUnauthorizedActionSkip(decision) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectCommentAutomationContext = projectCommentAutomationContext; exports.withCommentLanguageAdaptation = withCommentLanguageAdaptation; -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const status_command_policy_1 = __nccwpck_require__(33849); -const comment_language_translation_workflow_1 = __nccwpck_require__(59013); -const think_workflow_1 = __nccwpck_require__(84106); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const push_single_action_contexts_1 = __nccwpck_require__(68843); -const think_request_policy_1 = __nccwpck_require__(9106); -const think_input_policy_1 = __nccwpck_require__(84440); -const copilot_command_1 = __nccwpck_require__(28057); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const status_command_policy_1 = __nccwpck_require__(3449); +const comment_language_translation_workflow_1 = __nccwpck_require__(72770); +const think_workflow_1 = __nccwpck_require__(36450); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const push_single_action_contexts_1 = __nccwpck_require__(47841); +const think_request_policy_1 = __nccwpck_require__(23995); +const think_input_policy_1 = __nccwpck_require__(59687); +const copilot_command_1 = __nccwpck_require__(11771); function projectCommentAutomationContext(source, language, userComment) { const review = (0, bugbot_review_operation_context_1.projectBugbotReviewOperationContext)(source); return Object.freeze({ @@ -58340,18 +58340,18 @@ function projectSddDiffRequest(source) { /***/ }), -/***/ 19742: +/***/ 46175: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveCommentAutomationDecision = resolveCommentAutomationDecision; -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_fix_intent_payload_1 = __nccwpck_require__(90862); -const comment_automation_route_policy_1 = __nccwpck_require__(22503); -const copilot_comment_request_1 = __nccwpck_require__(16602); -const copilot_command_1 = __nccwpck_require__(28057); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_fix_intent_payload_1 = __nccwpck_require__(25734); +const comment_automation_route_policy_1 = __nccwpck_require__(47058); +const copilot_comment_request_1 = __nccwpck_require__(86819); +const copilot_command_1 = __nccwpck_require__(11771); async function resolveCommentAutomationDecision(param, options, actorAuthorizationPort) { (0, logging_ports_1.logInfo)("Running bugbot fix intent detection (before Think)."); const intentResults = await options.intentUseCase.invoke(param.bugbot.fixIntent); @@ -58380,15 +58380,15 @@ function logIntent(intentPayload) { /***/ }), -/***/ 83353: +/***/ 10554: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runNaturalLanguageCommentAutomation = runNaturalLanguageCommentAutomation; -const comment_automation_decision_workflow_1 = __nccwpck_require__(19742); -const comment_automation_completion_workflow_1 = __nccwpck_require__(10261); +const comment_automation_decision_workflow_1 = __nccwpck_require__(46175); +const comment_automation_completion_workflow_1 = __nccwpck_require__(46187); /** Runs the natural-language comment pipeline after deterministic commands are excluded. */ async function runNaturalLanguageCommentAutomation(param, options, actorAuthorizationPort, languageResults) { const decision = await (0, comment_automation_decision_workflow_1.resolveCommentAutomationDecision)(param, options, actorAuthorizationPort); @@ -58402,14 +58402,14 @@ async function runNaturalLanguageCommentAutomation(param, options, actorAuthoriz /***/ }), -/***/ 22503: +/***/ 47058: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveCommentAutomationRoute = resolveCommentAutomationRoute; -const bugbot_fix_intent_payload_1 = __nccwpck_require__(90862); +const bugbot_fix_intent_payload_1 = __nccwpck_require__(25734); function resolveCommentAutomationRoute(payload, allowedToModifyFiles, botMentioned = false, explicitMutationCommand = false) { if (!botMentioned && !explicitMutationCommand) return 'think'; @@ -58427,24 +58427,24 @@ function resolveCommentAutomationRoute(payload, allowedToModifyFiles, botMention /***/ }), -/***/ 29792: +/***/ 9661: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommentAutomation = runCommentAutomation; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const copilot_comment_request_1 = __nccwpck_require__(16602); -const copilot_command_1 = __nccwpck_require__(28057); -const comment_automation_command_workflow_1 = __nccwpck_require__(39723); -const comment_automation_natural_language_workflow_1 = __nccwpck_require__(83353); -const application_error_1 = __nccwpck_require__(1889); -const branch_sync_command_1 = __nccwpck_require__(48721); -const branch_sync_comment_command_1 = __nccwpck_require__(68375); -const comment_automation_context_1 = __nccwpck_require__(90059); -const comment_language_translation_workflow_1 = __nccwpck_require__(59013); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const copilot_comment_request_1 = __nccwpck_require__(86819); +const copilot_command_1 = __nccwpck_require__(11771); +const comment_automation_command_workflow_1 = __nccwpck_require__(63134); +const comment_automation_natural_language_workflow_1 = __nccwpck_require__(10554); +const application_error_1 = __nccwpck_require__(75999); +const branch_sync_command_1 = __nccwpck_require__(51114); +const branch_sync_comment_command_1 = __nccwpck_require__(4643); +const comment_automation_context_1 = __nccwpck_require__(37055); +const comment_language_translation_workflow_1 = __nccwpck_require__(72770); async function runCommentAutomation(initialParam, options, actorAuthorizationPort) { (0, logging_ports_1.logInfo)(`${options.taskId} started.`); let languageResults = []; @@ -58513,17 +58513,17 @@ async function runCommentAutomation(initialParam, options, actorAuthorizationPor /***/ }), -/***/ 63049: +/***/ 81324: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveCommentMutationBranch = resolveCommentMutationBranch; -const application_error_1 = __nccwpck_require__(1889); -const git_object_id_1 = __nccwpck_require__(65534); -const context_1 = __nccwpck_require__(8442); -const bugbot_context_request_1 = __nccwpck_require__(29868); +const application_error_1 = __nccwpck_require__(75999); +const git_object_id_1 = __nccwpck_require__(88623); +const context_1 = __nccwpck_require__(14712); +const bugbot_context_request_1 = __nccwpck_require__(98299); async function resolveCommentMutationBranch(param, options) { const operation = param.bugbot.fixIntent; if (!operation.target.isPullRequest) { @@ -58561,19 +58561,19 @@ async function resolveCommentMutationBranch(param, options) { /***/ }), -/***/ 58699: +/***/ 28001: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CommitUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const push_single_action_contexts_1 = __nccwpck_require__(68843); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const push_single_action_contexts_1 = __nccwpck_require__(47841); class CommitUseCase { constructor(notifyNewCommitUseCase, checkChangesIssueSizeUseCase, detectPotentialProblemsUseCase, checkProgressUseCase, actorAuthorizationPort) { this.notifyNewCommitUseCase = notifyNewCommitUseCase; @@ -58627,18 +58627,18 @@ exports.CommitUseCase = CommitUseCase; /***/ }), -/***/ 20038: +/***/ 71813: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ExecutionBranchVersionResolver = void 0; -const result_1 = __nccwpck_require__(99917); -const version_resolution_application_policy_1 = __nccwpck_require__(84631); -const version_resolution_outcome_policy_1 = __nccwpck_require__(48002); -const version_resolution_result_policy_1 = __nccwpck_require__(31533); -const version_resolution_policy_1 = __nccwpck_require__(87882); +const result_1 = __nccwpck_require__(73817); +const version_resolution_application_policy_1 = __nccwpck_require__(40231); +const version_resolution_outcome_policy_1 = __nccwpck_require__(43496); +const version_resolution_result_policy_1 = __nccwpck_require__(11730); +const version_resolution_policy_1 = __nccwpck_require__(92373); class ExecutionBranchVersionResolver { constructor(latestTagQueryPort, getReleaseVersion, getReleaseType, getHotfixVersion) { this.latestTagQueryPort = latestTagQueryPort; @@ -58736,7 +58736,7 @@ function unchanged(context) { /***/ }), -/***/ 84443: +/***/ 63436: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -58744,9 +58744,9 @@ function unchanged(context) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveEventIssueNumber = resolveEventIssueNumber; exports.resolveSingleActionIssueNumber = resolveSingleActionIssueNumber; -const positive_integer_policy_1 = __nccwpck_require__(20889); -const action_types_1 = __nccwpck_require__(78468); -const title_utils_1 = __nccwpck_require__(36183); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const action_types_1 = __nccwpck_require__(19625); +const title_utils_1 = __nccwpck_require__(46267); function resolveEventIssueNumber(context) { let issueNumber; if (context.isIssue) @@ -58845,14 +58845,14 @@ function currentSingleAction(context) { /***/ }), -/***/ 30220: +/***/ 90972: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveExecutionIssueNumber = resolveExecutionIssueNumber; -const execution_issue_number_policy_1 = __nccwpck_require__(84443); +const execution_issue_number_policy_1 = __nccwpck_require__(63436); async function resolveExecutionIssueNumber(context, issueRepository) { if (!context.isSingleAction && context.isPullRequest && ['issue_comment', 'pull_request_review_comment'].includes(context.eventName) @@ -58873,14 +58873,14 @@ async function resolveExecutionIssueNumber(context, issueRepository) { /***/ }), -/***/ 20380: +/***/ 88512: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupExecutionUseCase = void 0; -const setup_execution_workflow_1 = __nccwpck_require__(21595); +const setup_execution_workflow_1 = __nccwpck_require__(42285); class SetupExecutionUseCase { constructor(issueSetupPort, organizationSetupPort, configurationPort, branchVersionResolver) { this.issueSetupPort = issueSetupPort; @@ -58903,19 +58903,19 @@ exports.SetupExecutionUseCase = SetupExecutionUseCase; /***/ }), -/***/ 21595: +/***/ 42285: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runSetupExecution = runSetupExecution; -const application_error_1 = __nccwpck_require__(1889); -const action_types_1 = __nccwpck_require__(78468); -const previous_branch_state_policy_1 = __nccwpck_require__(890); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const logging_ports_1 = __nccwpck_require__(97793); -const resolve_execution_issue_number_1 = __nccwpck_require__(30220); +const application_error_1 = __nccwpck_require__(75999); +const action_types_1 = __nccwpck_require__(19625); +const previous_branch_state_policy_1 = __nccwpck_require__(43630); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const logging_ports_1 = __nccwpck_require__(6152); +const resolve_execution_issue_number_1 = __nccwpck_require__(90972); async function runSetupExecution(context, dependencies) { (0, logging_ports_1.setGlobalLoggerDebug)(context.debug, context.local); const tokenUser = await loadTokenUser(context, dependencies.organizationSetupPort); @@ -59083,22 +59083,22 @@ function positiveIssueNumberOrUndefined(value) { /***/ }), -/***/ 96349: +/***/ 72042: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueCommentUseCase = void 0; -const comment_automation_command_workflow_1 = __nccwpck_require__(39723); -const read_copilot_history_workflow_1 = __nccwpck_require__(11603); -const result_1 = __nccwpck_require__(99917); -const comment_automation_use_case_1 = __nccwpck_require__(29792); -const check_issue_comment_language_use_case_1 = __nccwpck_require__(55111); -const comment_automation_context_1 = __nccwpck_require__(90059); -const pull_request_workflow_context_1 = __nccwpck_require__(12372); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const copilot_command_1 = __nccwpck_require__(28057); +const comment_automation_command_workflow_1 = __nccwpck_require__(63134); +const read_copilot_history_workflow_1 = __nccwpck_require__(8140); +const result_1 = __nccwpck_require__(73817); +const comment_automation_use_case_1 = __nccwpck_require__(9661); +const check_issue_comment_language_use_case_1 = __nccwpck_require__(93152); +const comment_automation_context_1 = __nccwpck_require__(37055); +const pull_request_workflow_context_1 = __nccwpck_require__(73447); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const copilot_command_1 = __nccwpck_require__(11771); class IssueCommentUseCase { constructor(languageUseCase, intentUseCase, thinkUseCase, autofixUseCase, doUserRequestUseCase, actorAuthorizationPort, bugbotGitMutationPort, dismissBugbotFindingsUseCase, reviewPotentialProblemsUseCase, updatePullRequestDescriptionUseCase, rememberBugbotRuleUseCase, syncBranchUseCase, preBranchSddContinuation, rememberBranchPorts, statusReadPorts, historyReadPort, sddQueryPort, sddDiffQueryPort, nativeStatusReadPort, doctorReadPorts) { this.languageUseCase = languageUseCase; @@ -59187,24 +59187,24 @@ exports.IssueCommentUseCase = IssueCommentUseCase; /***/ }), -/***/ 12: +/***/ 65281: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const issue_workflow_1 = __nccwpck_require__(99026); -const check_permissions_workflow_1 = __nccwpck_require__(61273); -const update_title_workflow_1 = __nccwpck_require__(12039); -const project_content_link_workflow_1 = __nccwpck_require__(63457); -const issue_workflow_context_1 = __nccwpck_require__(85450); -const push_single_action_contexts_1 = __nccwpck_require__(68843); -const issue_start_policy_1 = __nccwpck_require__(59704); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const issue_workflow_1 = __nccwpck_require__(661); +const check_permissions_workflow_1 = __nccwpck_require__(17102); +const update_title_workflow_1 = __nccwpck_require__(50029); +const project_content_link_workflow_1 = __nccwpck_require__(89064); +const issue_workflow_context_1 = __nccwpck_require__(98005); +const push_single_action_contexts_1 = __nccwpck_require__(47841); +const issue_start_policy_1 = __nccwpck_require__(90332); class IssueUseCase { constructor(recommendStepsUseCase, answerIssueHelpUseCase, workflowSteps, issueCommentQueryPort, actorAuthorizationPort, preBranchSddGate) { this.recommendStepsUseCase = recommendStepsUseCase; @@ -59352,18 +59352,18 @@ function applyBranchConfigurationPatch(param, patch) { /***/ }), -/***/ 99026: +/***/ 661: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runIssueWorkflow = runIssueWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const copilot_interaction_policy_1 = __nccwpck_require__(52113); -const semantic_result_publication_policy_1 = __nccwpck_require__(78334); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const copilot_interaction_policy_1 = __nccwpck_require__(90108); +const semantic_result_publication_policy_1 = __nccwpck_require__(81985); +const application_error_1 = __nccwpck_require__(75999); /** Coordinates issue lifecycle steps in their required sequential order. */ async function runIssueWorkflow(context, taskId, ports) { const results = []; @@ -59525,7 +59525,7 @@ function issueWorkflowOutcome(results, branchConfigurationPatch, recommendationS /***/ }), -/***/ 85450: +/***/ 98005: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -59535,7 +59535,7 @@ exports.branchPreparationOutcome = branchPreparationOutcome; exports.projectIssueWorkflowStepContexts = projectIssueWorkflowStepContexts; exports.projectAssignmentContext = projectAssignmentContext; exports.copyProjects = copyProjects; -const issue_start_policy_1 = __nccwpck_require__(59704); +const issue_start_policy_1 = __nccwpck_require__(90332); function branchPreparationOutcome(results, configurationPatch = {}) { return Object.freeze({ results: Object.freeze([...results]), @@ -59689,7 +59689,7 @@ function selectIssueType(source) { /***/ }), -/***/ 5869: +/***/ 99961: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -59697,11 +59697,11 @@ function selectIssueType(source) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ResolveMessageCatalogUseCase = void 0; exports.buildCatalogResponseSchema = buildCatalogResponseSchema; -const agent_task_policy_1 = __nccwpck_require__(34816); -const message_catalog_1 = __nccwpck_require__(69292); -const locale_1 = __nccwpck_require__(52028); -const localize_message_catalog_1 = __nccwpck_require__(64868); -const logging_ports_1 = __nccwpck_require__(97793); +const agent_task_policy_1 = __nccwpck_require__(85712); +const message_catalog_1 = __nccwpck_require__(27097); +const locale_1 = __nccwpck_require__(15386); +const localize_message_catalog_1 = __nccwpck_require__(64005); +const logging_ports_1 = __nccwpck_require__(6152); class ResolveMessageCatalogUseCase { constructor(language) { this.language = language; @@ -59835,20 +59835,20 @@ function buildCatalogResponseSchema(source, ids, targetLocale = 'en-US') { /***/ }), -/***/ 68595: +/***/ 29415: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentUseCase = void 0; -const comment_automation_command_workflow_1 = __nccwpck_require__(39723); -const copilot_command_1 = __nccwpck_require__(28057); -const read_copilot_history_workflow_1 = __nccwpck_require__(11603); -const comment_automation_use_case_1 = __nccwpck_require__(29792); -const check_pull_request_comment_language_use_case_1 = __nccwpck_require__(92546); -const comment_automation_context_1 = __nccwpck_require__(90059); -const pull_request_workflow_context_1 = __nccwpck_require__(12372); +const comment_automation_command_workflow_1 = __nccwpck_require__(63134); +const copilot_command_1 = __nccwpck_require__(11771); +const read_copilot_history_workflow_1 = __nccwpck_require__(8140); +const comment_automation_use_case_1 = __nccwpck_require__(9661); +const check_pull_request_comment_language_use_case_1 = __nccwpck_require__(21729); +const comment_automation_context_1 = __nccwpck_require__(37055); +const pull_request_workflow_context_1 = __nccwpck_require__(73447); class PullRequestReviewCommentUseCase { constructor(languageUseCase, intentUseCase, thinkUseCase, autofixUseCase, doUserRequestUseCase, actorAuthorizationPort, bugbotGitMutationPort, dismissBugbotFindingsUseCase, reviewPotentialProblemsUseCase, updatePullRequestDescriptionUseCase, rememberBugbotRuleUseCase, syncBranchUseCase, rememberBranchPorts, statusReadPorts, historyReadPort, sddDiffQueryPort, nativeStatusReadPort, doctorReadPorts) { this.languageUseCase = languageUseCase; @@ -59921,20 +59921,20 @@ exports.PullRequestReviewCommentUseCase = PullRequestReviewCommentUseCase; /***/ }), -/***/ 86023: +/***/ 27259: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const pull_request_workflow_1 = __nccwpck_require__(61286); -const update_title_workflow_1 = __nccwpck_require__(12039); -const project_content_link_workflow_1 = __nccwpck_require__(63457); -const pull_request_workflow_context_1 = __nccwpck_require__(12372); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const pull_request_workflow_1 = __nccwpck_require__(95238); +const update_title_workflow_1 = __nccwpck_require__(50029); +const project_content_link_workflow_1 = __nccwpck_require__(89064); +const pull_request_workflow_context_1 = __nccwpck_require__(73447); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); class PullRequestUseCase { constructor(updatePullRequestDescriptionUseCase, workflowSteps, reviewPotentialProblemsUseCase, actorAuthorizationPort) { this.updatePullRequestDescriptionUseCase = updatePullRequestDescriptionUseCase; @@ -59989,16 +59989,16 @@ function projectPullRequestWorkflowRouteContext(param) { /***/ }), -/***/ 61286: +/***/ 95238: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPullRequestWorkflow = runPullRequestWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); /** Coordinates pull-request lifecycle actions while preserving their sequential order. */ async function runPullRequestWorkflow(context, taskId, ports) { try { @@ -60083,7 +60083,7 @@ function logPullRequestState(context) { /***/ }), -/***/ 12372: +/***/ 73447: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60091,8 +60091,8 @@ function logPullRequestState(context) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectPullRequestWorkflowStepContexts = projectPullRequestWorkflowStepContexts; exports.projectPullRequestDescriptionContext = projectPullRequestDescriptionContext; -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const issue_workflow_context_1 = __nccwpck_require__(98005); function projectPullRequestWorkflowStepContexts(source) { const projects = (0, issue_workflow_context_1.copyProjects)(source.project.getProjects()); return Object.freeze({ @@ -60163,7 +60163,7 @@ function projectPullRequestDescriptionContext(source) { /***/ }), -/***/ 68843: +/***/ 47841: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60182,9 +60182,9 @@ exports.projectChangeSizeContext = projectChangeSizeContext; exports.projectInitialSetupContext = projectInitialSetupContext; exports.projectIssueCommentActionContext = projectIssueCommentActionContext; exports.projectAgentActivityContext = projectAgentActivityContext; -const recommendation_state_1 = __nccwpck_require__(44113); -const issue_comment_publication_policy_1 = __nccwpck_require__(14047); -const git_object_id_1 = __nccwpck_require__(65534); +const recommendation_state_1 = __nccwpck_require__(68514); +const issue_comment_publication_policy_1 = __nccwpck_require__(61899); +const git_object_id_1 = __nccwpck_require__(88623); function projectDeploymentPublicationContext(source) { return Object.freeze({ requestedOperationId: source.singleAction.operationId, @@ -60418,22 +60418,22 @@ function deepFreezeCopy(value) { /***/ }), -/***/ 97584: +/***/ 12416: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCopilotDoctor = readCopilotDoctor; -const result_1 = __nccwpck_require__(99917); -const github_runtime_doctor_1 = __nccwpck_require__(56756); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const issue_start_policy_1 = __nccwpck_require__(59704); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const context_1 = __nccwpck_require__(8442); -const github_runtime_doctor_policy_1 = __nccwpck_require__(51599); -const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(3571); -const bugbot_context_request_1 = __nccwpck_require__(29868); +const result_1 = __nccwpck_require__(73817); +const github_runtime_doctor_1 = __nccwpck_require__(20413); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const issue_start_policy_1 = __nccwpck_require__(90332); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const context_1 = __nccwpck_require__(14712); +const github_runtime_doctor_policy_1 = __nccwpck_require__(99566); +const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(2808); +const bugbot_context_request_1 = __nccwpck_require__(98299); async function readCopilotDoctor(param, taskId, ports) { const repositoryId = (0, positive_integer_policy_1.parsePositiveSafeInteger)(param.bugbot.review.repository.id); const isPull = param.status.target === 'pull-request'; @@ -60536,15 +60536,15 @@ function doctorResult(taskId, report, serverOrigin, revision, owner, repository) /***/ }), -/***/ 11603: +/***/ 8140: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCopilotHistory = readCopilotHistory; -const result_1 = __nccwpck_require__(99917); -const copilot_history_policy_1 = __nccwpck_require__(44359); +const result_1 = __nccwpck_require__(73817); +const copilot_history_policy_1 = __nccwpck_require__(14335); /** A failed read cannot prove empty history or an operation failure. */ async function readCopilotHistory(request, ports) { let history = request.generalConversation ? copilot_history_policy_1.HISTORY_UNAVAILABLE : copilot_history_policy_1.HISTORY_UNSUPPORTED_SURFACE; @@ -60577,17 +60577,17 @@ async function readCopilotHistory(request, ports) { /***/ }), -/***/ 28724: +/***/ 57206: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCopilotStatus = readCopilotStatus; -const sdd_status_policy_1 = __nccwpck_require__(11756); -const status_command_policy_1 = __nccwpck_require__(33849); -const read_pull_request_status_readiness_workflow_1 = __nccwpck_require__(48006); -const application_error_1 = __nccwpck_require__(1889); +const sdd_status_policy_1 = __nccwpck_require__(6853); +const status_command_policy_1 = __nccwpck_require__(3449); +const read_pull_request_status_readiness_workflow_1 = __nccwpck_require__(18874); +const application_error_1 = __nccwpck_require__(75999); /** Shared read-only status path combines current native state with PR readiness evidence. */ async function readCopilotStatus(param, taskId, ports, sddQuery, nativeStatus) { let initialIssue; @@ -60653,21 +60653,21 @@ async function fenceNativeIssue(port, original) { /***/ }), -/***/ 48006: +/***/ 18874: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readPullRequestStatusReadiness = readPullRequestStatusReadiness; -const status_command_policy_1 = __nccwpck_require__(33849); -const bugbot_status_count_marker_policy_1 = __nccwpck_require__(37427); -const bugbot_review_ownership_policy_1 = __nccwpck_require__(51686); -const bugbot_review_presentation_policy_1 = __nccwpck_require__(94649); -const context_1 = __nccwpck_require__(8442); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const pull_request_readiness_policy_1 = __nccwpck_require__(79355); +const status_command_policy_1 = __nccwpck_require__(3449); +const bugbot_status_count_marker_policy_1 = __nccwpck_require__(8654); +const bugbot_review_ownership_policy_1 = __nccwpck_require__(83288); +const bugbot_review_presentation_policy_1 = __nccwpck_require__(43799); +const context_1 = __nccwpck_require__(14712); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const pull_request_readiness_policy_1 = __nccwpck_require__(79794); const positive = (value) => Number.isSafeInteger(value) && value > 0; const sha = (value) => typeof value === 'string' && /^[a-f0-9]{40}$/u.test(value); /** Independent reads retain verified facts. Unknown identity or freshness never becomes a clean snapshot. */ @@ -60847,16 +60847,16 @@ async function readPullRequestStatusReadiness(param, taskId, ports) { /***/ }), -/***/ 56461: +/***/ 93454: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.draftSddMarkdown = draftSddMarkdown; -const application_error_1 = __nccwpck_require__(1889); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const agent_response_length_failure_1 = __nccwpck_require__(11975); +const application_error_1 = __nccwpck_require__(75999); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const agent_response_length_failure_1 = __nccwpck_require__(28528); /** Size and typed format failures share one regeneration; the writer still validates every candidate. */ async function draftSddMarkdown(agent, configuration, plan, prompt, validate) { const maximum = plan.action === 'update' ? pre_branch_sdd_1.SDD_MAX_UPDATE_CHARACTERS : pre_branch_sdd_1.SDD_MAX_DRAFT_CHARACTERS; @@ -60918,22 +60918,22 @@ async function draftSddMarkdown(agent, configuration, plan, prompt, validate) { /***/ }), -/***/ 2776: +/***/ 29475: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PreBranchSddGateUseCase = void 0; -const sdd_issue_identity_policy_1 = __nccwpck_require__(81773); -const result_1 = __nccwpck_require__(99917); -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const recommendation_policy_1 = __nccwpck_require__(33990); -const logging_ports_1 = __nccwpck_require__(97793); -const sdd_analysis_status_policy_1 = __nccwpck_require__(85365); -const application_error_1 = __nccwpck_require__(1889); -const pre_branch_sdd_draft_workflow_1 = __nccwpck_require__(56461); +const sdd_issue_identity_policy_1 = __nccwpck_require__(99167); +const result_1 = __nccwpck_require__(73817); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const recommendation_policy_1 = __nccwpck_require__(39410); +const logging_ports_1 = __nccwpck_require__(6152); +const sdd_analysis_status_policy_1 = __nccwpck_require__(81053); +const application_error_1 = __nccwpck_require__(75999); +const pre_branch_sdd_draft_workflow_1 = __nccwpck_require__(93454); const ANALYSIS_SCHEMA = { type: 'object', properties: { @@ -61278,16 +61278,16 @@ function canonicalIssueUrl(context) { /***/ }), -/***/ 81101: +/***/ 48684: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SddDiffQueryUseCase = void 0; -const issue_start_policy_1 = __nccwpck_require__(59704); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const pre_branch_sdd_diff_1 = __nccwpck_require__(57493); +const issue_start_policy_1 = __nccwpck_require__(90332); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const pre_branch_sdd_diff_1 = __nccwpck_require__(28558); /** Structural comparison over shared verified evidence, with no writer/model capability. */ class SddDiffQueryUseCase { constructor(ports) { @@ -61476,7 +61476,7 @@ function associationProof(links) { /***/ }), -/***/ 28491: +/***/ 39893: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -61484,11 +61484,11 @@ function associationProof(links) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SddEvidenceQueryUseCase = void 0; const node_crypto_1 = __nccwpck_require__(6005); -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const sdd_evidence_read_ports_1 = __nccwpck_require__(77387); -const sdd_issue_identity_policy_1 = __nccwpck_require__(81773); -const sdd_query_card_policy_1 = __nccwpck_require__(50681); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const sdd_evidence_read_ports_1 = __nccwpck_require__(94752); +const sdd_issue_identity_policy_1 = __nccwpck_require__(99167); +const sdd_query_card_policy_1 = __nccwpck_require__(56285); const MAX_AUTHORIZATION_LOOKUPS = 16; /** Reads gate authority and immutable publication evidence without any mutation or model capability. */ class SddEvidenceQueryUseCase { @@ -61698,14 +61698,14 @@ function canonicalLabels(labels) { return JSON.stringify([...new Set(labels.map( /***/ }), -/***/ 73478: +/***/ 17602: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ApplySetupBatchUseCase = void 0; -const setup_batch_policy_1 = __nccwpck_require__(2886); +const setup_batch_policy_1 = __nccwpck_require__(52214); class ApplySetupBatchUseCase { constructor(ports) { this.ports = ports; @@ -61811,15 +61811,15 @@ class StaleSetupApply extends Error { /***/ }), -/***/ 40449: +/***/ 60830: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AuditConfiguredSetupPatUseCase = void 0; -const setup_pat_creation_url_policy_1 = __nccwpck_require__(66277); -const setup_token_permission_policy_1 = __nccwpck_require__(32450); +const setup_pat_creation_url_policy_1 = __nccwpck_require__(54718); +const setup_token_permission_policy_1 = __nccwpck_require__(99590); /** Rechecks the final plan without granting permission based on the browser preview. */ class AuditConfiguredSetupPatUseCase { constructor(context, ports) { @@ -61885,18 +61885,18 @@ exports.AuditConfiguredSetupPatUseCase = AuditConfiguredSetupPatUseCase; /***/ }), -/***/ 28407: +/***/ 5278: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ConfigureSetupBatchTargetUseCase = void 0; -const setup_batch_access_policy_1 = __nccwpck_require__(13056); -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); -const setup_token_permission_policy_1 = __nccwpck_require__(32450); -const setup_configuration_validation_1 = __nccwpck_require__(62784); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); +const setup_batch_access_policy_1 = __nccwpck_require__(15486); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); +const setup_token_permission_policy_1 = __nccwpck_require__(99590); +const setup_configuration_validation_1 = __nccwpck_require__(13339); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); /** Questionnaire and metadata verification are shared application work, independent of either UI. */ class ConfigureSetupBatchTargetUseCase { constructor(ports) { @@ -61951,20 +61951,20 @@ exports.ConfigureSetupBatchTargetUseCase = ConfigureSetupBatchTargetUseCase; /***/ }), -/***/ 58600: +/***/ 87328: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupDoctorUseCase = void 0; -const locale_1 = __nccwpck_require__(52028); -const setup_configuration_policy_1 = __nccwpck_require__(58409); -const setup_doctor_report_policy_1 = __nccwpck_require__(30942); -const bounded_concurrency_policy_1 = __nccwpck_require__(93783); -const setup_doctor_message_catalog_1 = __nccwpck_require__(80653); -const setup_approval_doctor_policy_1 = __nccwpck_require__(90975); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); +const locale_1 = __nccwpck_require__(15386); +const setup_configuration_policy_1 = __nccwpck_require__(56637); +const setup_doctor_report_policy_1 = __nccwpck_require__(67615); +const bounded_concurrency_policy_1 = __nccwpck_require__(35596); +const setup_doctor_message_catalog_1 = __nccwpck_require__(80226); +const setup_approval_doctor_policy_1 = __nccwpck_require__(53296); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); class SetupDoctorUseCase { constructor(dependencies) { this.dependencies = dependencies; @@ -62385,31 +62385,31 @@ function doctorCatalogLocale(configuration) { /***/ }), -/***/ 77766: +/***/ 36888: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupCredentialsUseCase = exports.SetupQuestionnaireController = exports.SetupWizardUseCase = void 0; -var setup_wizard_use_case_1 = __nccwpck_require__(91610); +var setup_wizard_use_case_1 = __nccwpck_require__(43433); Object.defineProperty(exports, "SetupWizardUseCase", ({ enumerable: true, get: function () { return setup_wizard_use_case_1.SetupWizardUseCase; } })); -var setup_questionnaire_controller_1 = __nccwpck_require__(75063); +var setup_questionnaire_controller_1 = __nccwpck_require__(41644); Object.defineProperty(exports, "SetupQuestionnaireController", ({ enumerable: true, get: function () { return setup_questionnaire_controller_1.SetupQuestionnaireController; } })); -var setup_credentials_use_case_1 = __nccwpck_require__(71899); +var setup_credentials_use_case_1 = __nccwpck_require__(67438); Object.defineProperty(exports, "SetupCredentialsUseCase", ({ enumerable: true, get: function () { return setup_credentials_use_case_1.SetupCredentialsUseCase; } })); /***/ }), -/***/ 64400: +/***/ 10989: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ManageSetupUseCase = void 0; -const setup_management_policy_1 = __nccwpck_require__(58343); +const setup_management_policy_1 = __nccwpck_require__(50895); /** Management owns the edit transaction; presenters cannot select a provider write. */ class ManageSetupUseCase { constructor(ports, readOnly = false) { @@ -62562,18 +62562,18 @@ exports.ManageSetupUseCase = ManageSetupUseCase; /***/ }), -/***/ 93843: +/***/ 9890: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupMergeQueueReadinessUseCase = void 0; -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const merge_queue_readiness_1 = __nccwpck_require__(86918); -const setup_doctor_report_policy_1 = __nccwpck_require__(30942); -const setup_doctor_message_catalog_1 = __nccwpck_require__(80653); -const merge_queue_message_catalog_1 = __nccwpck_require__(35785); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const merge_queue_readiness_1 = __nccwpck_require__(12515); +const setup_doctor_report_policy_1 = __nccwpck_require__(67615); +const setup_doctor_message_catalog_1 = __nccwpck_require__(80226); +const merge_queue_message_catalog_1 = __nccwpck_require__(56033); class SetupMergeQueueReadinessUseCase { constructor(targets, catalogResolver) { this.targets = targets; @@ -62721,23 +62721,23 @@ function uniqueTargets(targets) { /***/ }), -/***/ 67087: +/***/ 14769: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PrepareSetupBatchUseCase = void 0; -const setup_batch_policy_1 = __nccwpck_require__(2886); -const setup_remote_facts_policy_1 = __nccwpck_require__(49505); -const setup_configuration_defaults_1 = __nccwpck_require__(6736); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); -const setup_configuration_plan_1 = __nccwpck_require__(69620); -const setup_organization_variable_reuse_policy_2 = __nccwpck_require__(20994); -const setup_batch_access_policy_1 = __nccwpck_require__(13056); -const setup_configuration_validation_1 = __nccwpck_require__(62784); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); -const setup_runner_policy_1 = __nccwpck_require__(70801); +const setup_batch_policy_1 = __nccwpck_require__(52214); +const setup_remote_facts_policy_1 = __nccwpck_require__(92567); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); +const setup_configuration_plan_1 = __nccwpck_require__(87770); +const setup_organization_variable_reuse_policy_2 = __nccwpck_require__(63882); +const setup_batch_access_policy_1 = __nccwpck_require__(15486); +const setup_configuration_validation_1 = __nccwpck_require__(13339); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); +const setup_runner_policy_1 = __nccwpck_require__(91027); /** Sequential read-only planning; shared namespace metadata is inspected once per operation. */ class PrepareSetupBatchUseCase { constructor(ports) { @@ -62837,21 +62837,21 @@ exports.PrepareSetupBatchUseCase = PrepareSetupBatchUseCase; /***/ }), -/***/ 17889: +/***/ 69277: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PrepareSetupPatIntentUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); -const setup_configuration_policy_1 = __nccwpck_require__(58409); -const setup_questionnaire_policy_1 = __nccwpck_require__(79825); -const setup_pat_intent_policy_1 = __nccwpck_require__(86171); -const setup_token_permission_policy_1 = __nccwpck_require__(32450); -const setup_pat_creation_url_policy_1 = __nccwpck_require__(66277); -const setup_wizard_use_case_1 = __nccwpck_require__(91610); +const application_error_1 = __nccwpck_require__(75999); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); +const setup_configuration_policy_1 = __nccwpck_require__(56637); +const setup_questionnaire_policy_1 = __nccwpck_require__(6009); +const setup_pat_intent_policy_1 = __nccwpck_require__(30748); +const setup_token_permission_policy_1 = __nccwpck_require__(99590); +const setup_pat_creation_url_policy_1 = __nccwpck_require__(54718); +const setup_wizard_use_case_1 = __nccwpck_require__(43433); /** Frontend-neutral preparation; GitHub still issues the PAT in its own UI. */ class PrepareSetupPatIntentUseCase { constructor(ports) { @@ -62937,16 +62937,16 @@ exports.PrepareSetupPatIntentUseCase = PrepareSetupPatIntentUseCase; /***/ }), -/***/ 52487: +/***/ 31830: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ResolveSetupWorkflowPatConflictUseCase = void 0; -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); -const setup_configuration_clone_policy_1 = __nccwpck_require__(57097); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); +const setup_configuration_clone_policy_1 = __nccwpck_require__(85881); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); /** Explicit, read-only conflict recovery. A claimed deletion is never evidence. */ class ResolveSetupWorkflowPatConflictUseCase { constructor(prompt, remote) { @@ -62993,15 +62993,15 @@ exports.ResolveSetupWorkflowPatConflictUseCase = ResolveSetupWorkflowPatConflict /***/ }), -/***/ 72352: +/***/ 60527: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SelectSetupBatchTargetsUseCase = void 0; -const setup_batch_selection_policy_1 = __nccwpck_require__(36296); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); +const setup_batch_selection_policy_1 = __nccwpck_require__(1694); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); /** Limited discovery is a convenience view. Only explicit, re-resolved IDs become targets. */ class SelectSetupBatchTargetsUseCase { constructor(ports) { @@ -63099,14 +63099,14 @@ exports.SelectSetupBatchTargetsUseCase = SelectSetupBatchTargetsUseCase; /***/ }), -/***/ 52911: +/***/ 9531: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupBatchSessionUseCase = void 0; -const setup_batch_policy_1 = __nccwpck_require__(2886); +const setup_batch_policy_1 = __nccwpck_require__(52214); /** One coordinator for both presentations; a retry requires another review and fresh write preflight. */ class SetupBatchSessionUseCase { constructor(ports) { @@ -63228,18 +63228,18 @@ exports.SetupBatchSessionUseCase = SetupBatchSessionUseCase; /***/ }), -/***/ 71899: +/***/ 67438: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupCredentialsUseCase = void 0; -const setup_credential_binding_policy_1 = __nccwpck_require__(22770); -const application_error_1 = __nccwpck_require__(1889); -const setup_workflow_pat_identity_mismatch_error_1 = __nccwpck_require__(35608); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); +const setup_credential_binding_policy_1 = __nccwpck_require__(24663); +const application_error_1 = __nccwpck_require__(75999); +const setup_workflow_pat_identity_mismatch_error_1 = __nccwpck_require__(20805); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); /** Coordinates secret collection and validation without placing secret values in config files. */ class SetupCredentialsUseCase { constructor(prompt, validation, secrets, remoteHealth, tokenPermissions, permissionPresenter, workflowIdentity, trustedRemoteHealth) { @@ -63540,14 +63540,14 @@ function isAcceptedCredentialCheck(requirement, check) { /***/ }), -/***/ 81740: +/***/ 8419: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupJourneyUseCase = void 0; -const setup_journey_policy_1 = __nccwpck_require__(37300); +const setup_journey_policy_1 = __nccwpck_require__(53289); /** Tracks semantic milestones, independently of the CLI's rendering. */ class SetupJourneyUseCase { constructor(repository, presenter, priorSessionMutation = false) { @@ -63610,16 +63610,16 @@ exports.SetupJourneyUseCase = SetupJourneyUseCase; /***/ }), -/***/ 75063: +/***/ 41644: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupQuestionnaireController = void 0; -const setup_questionnaire_policy_1 = __nccwpck_require__(79825); -const application_error_1 = __nccwpck_require__(1889); -const setup_terminal_choice_policy_1 = __nccwpck_require__(32855); +const setup_questionnaire_policy_1 = __nccwpck_require__(6009); +const application_error_1 = __nccwpck_require__(75999); +const setup_terminal_choice_policy_1 = __nccwpck_require__(64662); class SetupQuestionnaireController { constructor(terminal, renderer) { this.terminal = terminal; @@ -63721,7 +63721,7 @@ function toEvent(input) { /***/ }), -/***/ 39179: +/***/ 70102: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -63842,14 +63842,14 @@ exports.SetupSessionCoordinator = SetupSessionCoordinator; /***/ }), -/***/ 55695: +/***/ 11797: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupTokenPermissionsUseCase = void 0; -const setup_token_permission_evidence_policy_1 = __nccwpck_require__(48617); +const setup_token_permission_evidence_policy_1 = __nccwpck_require__(65640); /** Validates PAT identity first, then runs scoped capability probes. */ class SetupTokenPermissionsUseCase { constructor(credentials, permissions, onProgress) { @@ -63922,7 +63922,7 @@ exports.SetupTokenPermissionsUseCase = SetupTokenPermissionsUseCase; /***/ }), -/***/ 91610: +/***/ 43433: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -63930,20 +63930,20 @@ exports.SetupTokenPermissionsUseCase = SetupTokenPermissionsUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupWizardUseCase = void 0; exports.buildInitialSetupConfiguration = buildInitialSetupConfiguration; -const setup_runner_policy_1 = __nccwpck_require__(70801); -const setup_remote_facts_policy_1 = __nccwpck_require__(49505); -const application_error_1 = __nccwpck_require__(1889); -const setup_configuration_policy_1 = __nccwpck_require__(58409); -const setup_questionnaire_policy_1 = __nccwpck_require__(79825); -const setup_configuration_clone_policy_1 = __nccwpck_require__(57097); -const setup_doctor_message_catalog_1 = __nccwpck_require__(80653); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const setup_project_selection_policy_1 = __nccwpck_require__(59068); -const setup_token_permission_policy_1 = __nccwpck_require__(32450); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); -const setup_organization_import_policy_1 = __nccwpck_require__(87045); -const setup_organization_variable_bindings_1 = __nccwpck_require__(86665); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); +const setup_runner_policy_1 = __nccwpck_require__(91027); +const setup_remote_facts_policy_1 = __nccwpck_require__(92567); +const application_error_1 = __nccwpck_require__(75999); +const setup_configuration_policy_1 = __nccwpck_require__(56637); +const setup_questionnaire_policy_1 = __nccwpck_require__(6009); +const setup_configuration_clone_policy_1 = __nccwpck_require__(85881); +const setup_doctor_message_catalog_1 = __nccwpck_require__(80226); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const setup_project_selection_policy_1 = __nccwpck_require__(73750); +const setup_token_permission_policy_1 = __nccwpck_require__(99590); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); +const setup_organization_import_policy_1 = __nccwpck_require__(97024); +const setup_organization_variable_bindings_1 = __nccwpck_require__(19698); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); class SetupWizardUseCase { constructor(dependencies) { this.dependencies = dependencies; @@ -64348,14 +64348,14 @@ function buildInitialSetupConfiguration(request) { /***/ }), -/***/ 5816: +/***/ 35697: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.VerifyGuidedWorkflowPatIdentityUseCase = void 0; -const setup_workflow_pat_identity_mismatch_error_1 = __nccwpck_require__(35608); +const setup_workflow_pat_identity_mismatch_error_1 = __nccwpck_require__(20805); /** Binds a guided runtime PAT to the bot account chosen before token entry. */ class VerifyGuidedWorkflowPatIdentityUseCase { constructor(identities) { @@ -64374,15 +64374,15 @@ exports.VerifyGuidedWorkflowPatIdentityUseCase = VerifyGuidedWorkflowPatIdentity /***/ }), -/***/ 95397: +/***/ 23388: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.VerifySetupPatBootstrapUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const setup_pat_creation_url_policy_1 = __nccwpck_require__(66277); +const application_error_1 = __nccwpck_require__(75999); +const setup_pat_creation_url_policy_1 = __nccwpck_require__(54718); /** Verify identity/account first, then complete displayed write transactions before planning. */ class VerifySetupPatBootstrapUseCase { constructor(ports) { @@ -64430,17 +64430,17 @@ exports.VerifySetupPatBootstrapUseCase = VerifySetupPatBootstrapUseCase; /***/ }), -/***/ 45234: +/***/ 5303: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.VerifyWebSetupApplyUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const setup_interaction_cancelled_error_1 = __nccwpck_require__(79987); -const setup_remote_facts_policy_1 = __nccwpck_require__(49505); -const setup_runner_policy_1 = __nccwpck_require__(70801); +const application_error_1 = __nccwpck_require__(75999); +const setup_interaction_cancelled_error_1 = __nccwpck_require__(38313); +const setup_remote_facts_policy_1 = __nccwpck_require__(92567); +const setup_runner_policy_1 = __nccwpck_require__(91027); /** Authorizes one web Apply against the facts the operator actually reviewed. */ class VerifyWebSetupApplyUseCase { constructor(ports) { @@ -64510,19 +64510,19 @@ exports.VerifyWebSetupApplyUseCase = VerifyWebSetupApplyUseCase; /***/ }), -/***/ 97206: +/***/ 73572: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SingleActionUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const single_action_workflow_1 = __nccwpck_require__(60484); -const think_workflow_1 = __nccwpck_require__(84106); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const push_single_action_contexts_1 = __nccwpck_require__(68843); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const single_action_workflow_1 = __nccwpck_require__(6130); +const think_workflow_1 = __nccwpck_require__(36450); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const push_single_action_contexts_1 = __nccwpck_require__(47841); class SingleActionUseCase { constructor(publishGithubActionUseCase, createReleaseUseCase, createTagUseCase, thinkUseCase, initialSetupUseCase, checkProgressUseCase, detectPotentialProblemsUseCase, recommendStepsUseCase, closeInactiveIssuesUseCase, actorAuthorizationPort, publishIssueCommentUseCase, observeBranchSyncUseCase, deploymentOrchestrationUseCase) { this.publishGithubActionUseCase = publishGithubActionUseCase; @@ -64615,16 +64615,16 @@ function isAgentBackedSingleAction(param) { /***/ }), -/***/ 60484: +/***/ 6130: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runSingleActionWorkflow = runSingleActionWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); async function runSingleActionWorkflow(dispatch, taskId, ports) { if (dispatch.kind === 'invalid') { (0, logging_ports_1.logDebugInfo)(`Single action is not valid: ${dispatch.action}. Skipping.`); @@ -64678,24 +64678,24 @@ function singleActionFailure(action, taskId, error) { /***/ }), -/***/ 7062: +/***/ 4658: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.analyzeBugbotRevision = analyzeBugbotRevision; -const bugbot_reconciliation_policy_1 = __nccwpck_require__(55390); -const logging_ports_1 = __nccwpck_require__(97793); -const limit_comments_1 = __nccwpck_require__(47233); -const finding_1 = __nccwpck_require__(71592); -const build_bugbot_prompt_1 = __nccwpck_require__(63670); -const prepare_bugbot_findings_1 = __nccwpck_require__(83131); -const query_bugbot_findings_1 = __nccwpck_require__(79678); -const bugbot_resolution_eligibility_policy_1 = __nccwpck_require__(53031); -const bounded_concurrency_policy_1 = __nccwpck_require__(93783); -const bugbot_partition_aggregation_1 = __nccwpck_require__(6831); -const application_error_1 = __nccwpck_require__(1889); +const bugbot_reconciliation_policy_1 = __nccwpck_require__(78128); +const logging_ports_1 = __nccwpck_require__(6152); +const limit_comments_1 = __nccwpck_require__(31643); +const finding_1 = __nccwpck_require__(31011); +const build_bugbot_prompt_1 = __nccwpck_require__(52483); +const prepare_bugbot_findings_1 = __nccwpck_require__(85016); +const query_bugbot_findings_1 = __nccwpck_require__(13059); +const bugbot_resolution_eligibility_policy_1 = __nccwpck_require__(89189); +const bounded_concurrency_policy_1 = __nccwpck_require__(35596); +const bugbot_partition_aggregation_1 = __nccwpck_require__(84575); +const application_error_1 = __nccwpck_require__(75999); /** Pure analysis phase: query, validate, normalize, deduplicate and reconcile; never mutates the SCM. */ async function analyzeBugbotRevision(execution, context, dependencies) { dependencies.telemetry.observeContext(context); @@ -64777,17 +64777,17 @@ function suppressDismissedFindings(execution, context, prepared) { /***/ }), -/***/ 60798: +/***/ 20793: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyDetectedFindings = applyDetectedFindings; -const mark_findings_resolved_use_case_1 = __nccwpck_require__(7458); -const publish_findings_use_case_1 = __nccwpck_require__(77714); -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const mark_findings_resolved_use_case_1 = __nccwpck_require__(96963); +const publish_findings_use_case_1 = __nccwpck_require__(88442); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const pull_request_review_errors_1 = __nccwpck_require__(46445); async function applyDetectedFindings(operation, context, prepared, publicationPorts, resolutionPorts, catalog) { try { await (0, publish_findings_use_case_1.publishFindings)({ @@ -64821,7 +64821,7 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo /***/ }), -/***/ 64609: +/***/ 98158: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -64829,8 +64829,8 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runBugbotAutofixCommitAndPush = runBugbotAutofixCommitAndPush; exports.runUserRequestCommitAndPush = runUserRequestCommitAndPush; -const commit_message_policy_1 = __nccwpck_require__(44070); -const commit_and_push_workflow_1 = __nccwpck_require__(55203); +const commit_message_policy_1 = __nccwpck_require__(85518); +const commit_and_push_workflow_1 = __nccwpck_require__(53708); async function runBugbotAutofixCommitAndPush(context, options, gitCommitPort) { const branch = options?.branchOverride ?? context.branch; return (0, commit_and_push_workflow_1.runCommitAndPushWorkflow)(context, { @@ -64855,17 +64855,17 @@ async function runUserRequestCommitAndPush(context, options, gitCommitPort) { /***/ }), -/***/ 86050: +/***/ 79698: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.finalizeBugbotAutofix = finalizeBugbotAutofix; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); async function finalizeBugbotAutofix(context, idsToFix, workspacePathsBefore, branchCheckedOut, responseText, gitCommitPort) { if (!responseText) { (0, logging_ports_1.logError)('Bugbot autofix: no response from configured build agent.'); @@ -64896,21 +64896,21 @@ function failure(semanticError) { /***/ }), -/***/ 27829: +/***/ 67170: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareBugbotAutofix = prepareBugbotAutofix; -const result_1 = __nccwpck_require__(99917); -const finding_1 = __nccwpck_require__(71592); -const build_bugbot_fix_prompt_1 = __nccwpck_require__(70732); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const logging_ports_1 = __nccwpck_require__(97793); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const finding_1 = __nccwpck_require__(31011); +const build_bugbot_fix_prompt_1 = __nccwpck_require__(89819); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const logging_ports_1 = __nccwpck_require__(6152); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); async function prepareBugbotAutofix(operation, targetFindingIds, userComment, providedContext, branchOverride, contextPorts, gitCommitPort) { const canonicalHint = providedContext?.canonicalPullRequest; const targetBranch = branchOverride?.trim() || canonicalHint?.headRef; @@ -64973,14 +64973,14 @@ function failure(semanticError) { /***/ }), -/***/ 73970: +/***/ 45446: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotAutofixUseCase = void 0; -const bugbot_autofix_workflow_1 = __nccwpck_require__(77959); +const bugbot_autofix_workflow_1 = __nccwpck_require__(69600); /** Application boundary for safe, agent-driven remediation of Bugbot findings. */ class BugbotAutofixUseCase { constructor(aiRepository, contextPorts, gitCommitPort) { @@ -65002,20 +65002,20 @@ exports.BugbotAutofixUseCase = BugbotAutofixUseCase; /***/ }), -/***/ 77959: +/***/ 69600: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runBugbotAutofixWorkflow = runBugbotAutofixWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const bugbot_autofix_postflight_1 = __nccwpck_require__(86050); -const bugbot_autofix_preflight_1 = __nccwpck_require__(27829); -const application_error_1 = __nccwpck_require__(1889); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const bugbot_autofix_postflight_1 = __nccwpck_require__(79698); +const bugbot_autofix_preflight_1 = __nccwpck_require__(67170); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = 'BugbotAutofixUseCase'; /** Coordinates preflight, agent execution and postflight workspace safety. */ async function runBugbotAutofixWorkflow(param, dependencies) { @@ -65058,14 +65058,14 @@ function newResultFailure(semanticError) { /***/ }), -/***/ 29868: +/***/ 98299: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectBugbotContextRequest = projectBugbotContextRequest; -const positive_integer_policy_1 = __nccwpck_require__(20889); +const positive_integer_policy_1 = __nccwpck_require__(19879); function projectBugbotContextRequest(context, options) { const issueNumber = (0, positive_integer_policy_1.parsePositiveSafeInteger)(options?.issueNumberOverride ?? context.target.issueNumber); const pullRequestNumber = (0, positive_integer_policy_1.parsePositiveSafeInteger)(options?.pullRequestNumberOverride @@ -65099,7 +65099,7 @@ function projectBugbotContextRequest(context, options) { /***/ }), -/***/ 27015: +/***/ 62946: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65107,11 +65107,11 @@ function projectBugbotContextRequest(context, options) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.parseBugbotFindingComments = parseBugbotFindingComments; exports.collectPreviousBugbotFindings = collectPreviousBugbotFindings; -const build_bugbot_fix_prompt_1 = __nccwpck_require__(70732); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const finding_1 = __nccwpck_require__(71592); -const github_user_policy_1 = __nccwpck_require__(84900); -const review_state_1 = __nccwpck_require__(47220); +const build_bugbot_fix_prompt_1 = __nccwpck_require__(89819); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const finding_1 = __nccwpck_require__(31011); +const github_user_policy_1 = __nccwpck_require__(84403); +const review_state_1 = __nccwpck_require__(79200); function parseBugbotFindingComments(issueComments, pullRequestCommentsByNumber, trustedAuthorLogin, reviewThreadStatesByPullRequest = new Map()) { const existingByFindingId = parseIssueFindingMarkers(issueComments, trustedAuthorLogin); const pullRequestFindings = parsePullRequestFindingMarkers(pullRequestCommentsByNumber, trustedAuthorLogin, reviewThreadStatesByPullRequest); @@ -65232,7 +65232,7 @@ function collectPreviousBugbotFindings(issueComments, existingByFindingId, prFin /***/ }), -/***/ 90862: +/***/ 25734: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -65271,7 +65271,7 @@ function canRunDoUserRequest(payload) { /***/ }), -/***/ 6831: +/***/ 84575: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65279,7 +65279,7 @@ function canRunDoUserRequest(payload) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_AGGREGATE_PARTITION_FINDINGS = void 0; exports.aggregateBugbotPartitionResponses = aggregateBugbotPartitionResponses; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); const MAX_PARTITION_FINDINGS_PER_RESPONSE = 200; exports.MAX_AGGREGATE_PARTITION_FINDINGS = 2000; const MAX_OWNER_RESOLUTIONS = 500; @@ -65332,7 +65332,7 @@ function invalidAggregate(message) { /***/ }), -/***/ 27537: +/***/ 3346: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65340,8 +65340,8 @@ function invalidAggregate(message) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_PREVIOUS_FINDINGS_BLOCK_LENGTH = exports.MAX_PREVIOUS_FINDINGS = void 0; exports.buildPreviousFindingsContext = buildPreviousFindingsContext; -const untrusted_content_1 = __nccwpck_require__(30127); -const build_bugbot_fix_prompt_1 = __nccwpck_require__(70732); +const untrusted_content_1 = __nccwpck_require__(67057); +const build_bugbot_fix_prompt_1 = __nccwpck_require__(89819); exports.MAX_PREVIOUS_FINDINGS = 100; exports.MAX_PREVIOUS_FINDINGS_BLOCK_LENGTH = 48000; function buildPreviousFindingsContext(previousFindings) { @@ -65402,7 +65402,7 @@ function timestamp(value) { /***/ }), -/***/ 51970: +/***/ 50536: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65412,9 +65412,9 @@ exports.buildReviewDiffBlock = buildReviewDiffBlock; exports.buildReviewDiffContext = buildReviewDiffContext; exports.buildReviewConversationBlock = buildReviewConversationBlock; exports.buildReviewConversationContext = buildReviewConversationContext; -const github_user_policy_1 = __nccwpck_require__(84900); -const untrusted_content_1 = __nccwpck_require__(30127); -const bugbot_diff_partition_policy_1 = __nccwpck_require__(74008); +const github_user_policy_1 = __nccwpck_require__(84403); +const untrusted_content_1 = __nccwpck_require__(67057); +const bugbot_diff_partition_policy_1 = __nccwpck_require__(31601); const MAX_CONVERSATION_LENGTH = 24000; const MAX_CONVERSATION_ITEMS = 50; const MAX_CONVERSATION_ITEM_LENGTH = 4000; @@ -65501,7 +65501,7 @@ function isBot(author, botLogin) { /***/ }), -/***/ 1415: +/***/ 14307: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -65524,7 +65524,7 @@ async function hasNewerBugbotRevision(context, ports) { /***/ }), -/***/ 67737: +/***/ 16660: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65536,7 +65536,7 @@ exports.withBugbotReviewOverrides = withBugbotReviewOverrides; exports.projectBugbotFixIntentContext = projectBugbotFixIntentContext; exports.projectBugbotAutofixOperationContext = projectBugbotAutofixOperationContext; exports.projectBugbotCommitContext = projectBugbotCommitContext; -const positive_integer_policy_1 = __nccwpck_require__(20889); +const positive_integer_policy_1 = __nccwpck_require__(19879); /** Copies only the non-secret facts required to select canonical Bugbot context. */ function projectBugbotContextSelectionContext(source) { const reviewConfiguration = source.ai.getBugbotReviewConfiguration(); @@ -65682,7 +65682,7 @@ function normalizeExpectedHeadSha(eventName, inputs) { /***/ }), -/***/ 21706: +/***/ 25011: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65690,7 +65690,7 @@ function normalizeExpectedHeadSha(eventName, inputs) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_BUGBOT_RULES_LENGTH = exports.MAX_BUGBOT_RULE_LENGTH = void 0; exports.buildBugbotReviewRuleSet = buildBugbotReviewRuleSet; -const untrusted_content_1 = __nccwpck_require__(30127); +const untrusted_content_1 = __nccwpck_require__(67057); exports.MAX_BUGBOT_RULE_LENGTH = 30000; exports.MAX_BUGBOT_RULES_LENGTH = 100000; function buildBugbotReviewRuleSet(organizationRules, repositoryRules) { @@ -65743,14 +65743,14 @@ function deduplicateRules(rules) { /***/ }), -/***/ 82658: +/***/ 46790: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotReviewTelemetry = void 0; -const bugbot_finding_status_policy_1 = __nccwpck_require__(10264); +const bugbot_finding_status_policy_1 = __nccwpck_require__(53822); const systemClock = { now: () => Date.now(), isoNow: () => new Date().toISOString(), @@ -65952,7 +65952,7 @@ function sanitizeMetricName(value) { /***/ }), -/***/ 35361: +/***/ 18799: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65963,9 +65963,9 @@ function sanitizeMetricName(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildBugbotFixIntentPrompt = buildBugbotFixIntentPrompt; -const prompts_1 = __nccwpck_require__(10966); -const project_context_instruction_1 = __nccwpck_require__(55527); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); +const prompts_1 = __nccwpck_require__(69518); +const project_context_instruction_1 = __nccwpck_require__(63907); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); const MAX_TITLE_LENGTH = 200; const MAX_FILE_LENGTH = 256; function safeForPrompt(s, maxLen) { @@ -66015,7 +66015,7 @@ function buildParentBlock(parentCommentBody) { /***/ }), -/***/ 70732: +/***/ 89819: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66024,10 +66024,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_FINDING_BODY_LENGTH = void 0; exports.truncateFindingBody = truncateFindingBody; exports.buildBugbotFixPrompt = buildBugbotFixPrompt; -const prompts_1 = __nccwpck_require__(10966); -const project_context_instruction_1 = __nccwpck_require__(55527); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); -const untrusted_content_1 = __nccwpck_require__(30127); +const prompts_1 = __nccwpck_require__(69518); +const project_context_instruction_1 = __nccwpck_require__(63907); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); +const untrusted_content_1 = __nccwpck_require__(67057); /** Maximum characters for a single finding's full comment body to avoid prompt bloat and token limits. */ exports.MAX_FINDING_BODY_LENGTH = 12000; const TRUNCATION_SUFFIX = "\n\n[... truncated for length ...]"; @@ -66084,7 +66084,7 @@ function buildBugbotFixPrompt(param, context, targetFindingIds, userComment, ver /***/ }), -/***/ 63670: +/***/ 52483: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66098,10 +66098,10 @@ function buildBugbotFixPrompt(param, context, targetFindingIds, userComment, ver */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildBugbotPrompt = buildBugbotPrompt; -const prompts_1 = __nccwpck_require__(10966); -const project_context_instruction_1 = __nccwpck_require__(55527); -const review_configuration_1 = __nccwpck_require__(38595); -const file_ignore_policy_1 = __nccwpck_require__(38774); +const prompts_1 = __nccwpck_require__(69518); +const project_context_instruction_1 = __nccwpck_require__(63907); +const review_configuration_1 = __nccwpck_require__(3994); +const file_ignore_policy_1 = __nccwpck_require__(20542); const MAX_IGNORE_BLOCK_LENGTH = 2000; const GIT_OBJECT_ID = /^[0-9a-f]{7,64}$/i; function buildBugbotPrompt(param, context, assignment) { @@ -66223,20 +66223,20 @@ function normalizedObjectId(value) { /***/ }), -/***/ 71364: +/***/ 49629: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommitAndPushPreflight = runCommitAndPushPreflight; -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); -const git_branch_checkout_1 = __nccwpck_require__(37329); -const verify_command_policy_1 = __nccwpck_require__(23322); -const verify_command_runner_1 = __nccwpck_require__(50827); -const workspace_changes_1 = __nccwpck_require__(33363); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); +const git_branch_checkout_1 = __nccwpck_require__(68549); +const verify_command_policy_1 = __nccwpck_require__(96031); +const verify_command_runner_1 = __nccwpck_require__(57742); +const workspace_changes_1 = __nccwpck_require__(93370); async function runCommitAndPushPreflight(context, options, gitCommitPort) { if (!options.branch?.trim()) { return { status: "failure", error: "No branch to commit to." }; @@ -66291,16 +66291,16 @@ async function runVerification(context, gitCommitPort) { /***/ }), -/***/ 55203: +/***/ 53708: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommitAndPushWorkflow = runCommitAndPushWorkflow; -const logging_ports_1 = __nccwpck_require__(97793); -const commit_and_push_preflight_1 = __nccwpck_require__(71364); -const application_error_1 = __nccwpck_require__(1889); +const logging_ports_1 = __nccwpck_require__(6152); +const commit_and_push_preflight_1 = __nccwpck_require__(49629); +const application_error_1 = __nccwpck_require__(75999); async function runCommitAndPushWorkflow(context, options, gitCommitPort) { const preflight = await (0, commit_and_push_preflight_1.runCommitAndPushPreflight)(context, options, gitCommitPort); if (preflight.status === 'failure') { @@ -66336,16 +66336,16 @@ async function runCommitAndPushWorkflow(context, options, gitCommitPort) { /***/ }), -/***/ 98022: +/***/ 93455: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.commitAutofixAndResolveFindings = commitAutofixAndResolveFindings; -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_autofix_commit_1 = __nccwpck_require__(64609); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_autofix_commit_1 = __nccwpck_require__(98158); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); async function commitAutofixAndResolveFindings(context, payload, autofixResults, gitCommitPort, onCompleted) { const lastAutofix = autofixResults.at(-1); if (!lastAutofix?.success) { @@ -66380,7 +66380,7 @@ async function commitAutofixAndResolveFindings(context, payload, autofixResults, /***/ }), -/***/ 44070: +/***/ 85518: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -66434,18 +66434,18 @@ function buildUserRequestCommitMessage(issueNumber) { /***/ }), -/***/ 41729: +/***/ 43393: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.commitUserRequestIfSuccessful = commitUserRequestIfSuccessful; -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_autofix_commit_1 = __nccwpck_require__(64609); -const result_1 = __nccwpck_require__(99917); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const application_error_1 = __nccwpck_require__(1889); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_autofix_commit_1 = __nccwpck_require__(98158); +const result_1 = __nccwpck_require__(73817); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const application_error_1 = __nccwpck_require__(75999); async function commitUserRequestIfSuccessful(context, branchOverride, results, gitCommitPort) { if (!results.at(-1)?.success) { (0, logging_ports_1.logInfo)('Do user request did not succeed; skipping commit.'); @@ -66479,7 +66479,7 @@ async function commitUserRequestIfSuccessful(context, branchOverride, results, g /***/ }), -/***/ 57491: +/***/ 62908: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -66512,7 +66512,7 @@ function deduplicateFindings(findings) { /***/ }), -/***/ 24760: +/***/ 14796: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66521,7 +66521,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectBugbotCommentBody = selectBugbotCommentBody; exports.buildUnresolvedFindingSummaries = buildUnresolvedFindingSummaries; exports.parseBugbotFixIntentResponse = parseBugbotFixIntentResponse; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); /** Selects the user-authored comment that can trigger intent detection. */ function selectBugbotCommentBody(sources) { if (sources.issue.isIssueComment) @@ -66566,16 +66566,16 @@ function unique(values) { /***/ }), -/***/ 10401: +/***/ 76234: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DetectBugbotFixIntentUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const detect_bugbot_fix_intent_workflow_1 = __nccwpck_require__(1353); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const detect_bugbot_fix_intent_workflow_1 = __nccwpck_require__(88390); const TASK_ID = "DetectBugbotFixIntentUseCase"; /** Application boundary for detecting Bugbot fix intent in user comments. */ class DetectBugbotFixIntentUseCase { @@ -66597,23 +66597,23 @@ exports.DetectBugbotFixIntentUseCase = DetectBugbotFixIntentUseCase; /***/ }), -/***/ 1353: +/***/ 88390: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runDetectBugbotFixIntentWorkflow = runDetectBugbotFixIntentWorkflow; -const agent_1 = __nccwpck_require__(11066); -const agent_task_policy_1 = __nccwpck_require__(34816); -const logging_ports_1 = __nccwpck_require__(97793); -const result_1 = __nccwpck_require__(99917); -const copilot_command_1 = __nccwpck_require__(28057); -const build_bugbot_fix_intent_prompt_1 = __nccwpck_require__(35361); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const schema_1 = __nccwpck_require__(54744); -const detect_bugbot_fix_intent_policy_1 = __nccwpck_require__(24760); +const agent_1 = __nccwpck_require__(79937); +const agent_task_policy_1 = __nccwpck_require__(85712); +const logging_ports_1 = __nccwpck_require__(6152); +const result_1 = __nccwpck_require__(73817); +const copilot_command_1 = __nccwpck_require__(11771); +const build_bugbot_fix_intent_prompt_1 = __nccwpck_require__(18799); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const schema_1 = __nccwpck_require__(16808); +const detect_bugbot_fix_intent_policy_1 = __nccwpck_require__(14796); const TASK_ID = "DetectBugbotFixIntentUseCase"; /** Detects whether a comment requests a finding fix, repository change, or read-only review. */ async function runDetectBugbotFixIntentWorkflow(param, ports) { @@ -66750,21 +66750,21 @@ async function resolveParentCommentBody(param, contextPorts) { /***/ }), -/***/ 48256: +/***/ 37685: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DismissBugbotFindingsUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const mark_findings_resolved_workflow_1 = __nccwpck_require__(62320); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const result_1 = __nccwpck_require__(73817); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const mark_findings_resolved_workflow_1 = __nccwpck_require__(65916); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); /** Dismisses only findings present in the current persisted Bugbot context. */ class DismissBugbotFindingsUseCase { constructor(dependencies) { @@ -66837,14 +66837,14 @@ async function loadDismissContext(operation, ports) { /***/ }), -/***/ 47233: +/***/ 31643: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyCommentLimit = applyCommentLimit; -const bugbot_constants_1 = __nccwpck_require__(77194); +const bugbot_constants_1 = __nccwpck_require__(51389); /** * Applies the max-comments limit: returns the first N findings to publish individually, * and overflow count + titles for a single "revisar en local" summary comment. @@ -66865,7 +66865,7 @@ function applyCommentLimit(findings, maxComments = bugbot_constants_1.BUGBOT_MAX /***/ }), -/***/ 11187: +/***/ 4050: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66873,16 +66873,16 @@ function applyCommentLimit(findings, maxComments = bugbot_constants_1.BUGBOT_MAX Object.defineProperty(exports, "__esModule", ({ value: true })); exports.preflightBugbotContext = preflightBugbotContext; exports.loadBugbotContext = loadBugbotContext; -const application_error_1 = __nccwpck_require__(1889); -const bounded_concurrency_policy_1 = __nccwpck_require__(93783); -const context_1 = __nccwpck_require__(8442); -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_finding_context_1 = __nccwpck_require__(27015); -const bugbot_previous_findings_context_1 = __nccwpck_require__(27537); -const bugbot_diff_partition_policy_1 = __nccwpck_require__(74008); -const bugbot_review_context_1 = __nccwpck_require__(51970); -const file_ignore_policy_1 = __nccwpck_require__(38774); -const bugbot_review_rules_1 = __nccwpck_require__(21706); +const application_error_1 = __nccwpck_require__(75999); +const bounded_concurrency_policy_1 = __nccwpck_require__(35596); +const context_1 = __nccwpck_require__(14712); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_finding_context_1 = __nccwpck_require__(62946); +const bugbot_previous_findings_context_1 = __nccwpck_require__(3346); +const bugbot_diff_partition_policy_1 = __nccwpck_require__(31601); +const bugbot_review_context_1 = __nccwpck_require__(50536); +const file_ignore_policy_1 = __nccwpck_require__(20542); +const bugbot_review_rules_1 = __nccwpck_require__(25011); /** Resolves and validates the provider-owned PR identity without loading review context. */ async function preflightBugbotContext(request, ports) { const selection = await selectCanonicalPullRequest(request, ports); @@ -67051,14 +67051,14 @@ function toPrContext(identity, snapshot) { /***/ }), -/***/ 76490: +/***/ 44861: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.loadBugbotReconciliationSnapshot = loadBugbotReconciliationSnapshot; -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); /** * Acquires one coherent final snapshot around two head guards. Surface reads * run concurrently, while the second guard rejects data collected across a @@ -67149,32 +67149,32 @@ function stateOf(result) { /***/ }), -/***/ 7458: +/***/ 96963: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = void 0; -var mark_findings_resolved_workflow_1 = __nccwpck_require__(62320); +var mark_findings_resolved_workflow_1 = __nccwpck_require__(65916); Object.defineProperty(exports, "markFindingsResolved", ({ enumerable: true, get: function () { return mark_findings_resolved_workflow_1.markFindingsResolved; } })); /***/ }), -/***/ 62320: +/***/ 65916: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = markFindingsResolved; -const logging_ports_1 = __nccwpck_require__(97793); -const resolve_issue_finding_1 = __nccwpck_require__(78269); -const resolve_pull_request_finding_1 = __nccwpck_require__(46024); -const review_state_1 = __nccwpck_require__(47220); -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const application_error_1 = __nccwpck_require__(1889); +const logging_ports_1 = __nccwpck_require__(6152); +const resolve_issue_finding_1 = __nccwpck_require__(35300); +const resolve_pull_request_finding_1 = __nccwpck_require__(64567); +const review_state_1 = __nccwpck_require__(79200); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const application_error_1 = __nccwpck_require__(75999); async function markFindingsResolved(param) { const errors = []; for (const [findingId, existing] of Object.entries(param.context.existingByFindingId)) { @@ -67255,7 +67255,7 @@ function addResolutionError(errors, destination, findingId, cause) { /***/ }), -/***/ 72146: +/***/ 70124: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -67318,14 +67318,14 @@ function resolveFindingPathForPr(findingFile, prFiles) { /***/ }), -/***/ 83131: +/***/ 85016: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareBugbotFindings = prepareBugbotFindings; -const prepare_bugbot_findings_policy_1 = __nccwpck_require__(57286); +const prepare_bugbot_findings_policy_1 = __nccwpck_require__(3496); function prepareBugbotFindings(response, ignorePatterns, minSeverityValue, maxComments, maxAgentFindings) { const normalized = (0, prepare_bugbot_findings_policy_1.normalizeBugbotResponse)(response, maxAgentFindings); return normalized === undefined @@ -67340,7 +67340,7 @@ function prepareBugbotFindings(response, ignorePatterns, minSeverityValue, maxCo /***/ }), -/***/ 57286: +/***/ 3496: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -67349,14 +67349,14 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MIN_AGENT_FINDING_CONFIDENCE = exports.MAX_AGENT_RESOLVED_FINDINGS = exports.MAX_AGENT_FINDINGS = void 0; exports.normalizeBugbotResponse = normalizeBugbotResponse; exports.prepareFindings = prepareFindings; -const deduplicate_findings_1 = __nccwpck_require__(57491); -const file_ignore_policy_1 = __nccwpck_require__(38774); -const limit_comments_1 = __nccwpck_require__(47233); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const path_validation_1 = __nccwpck_require__(72146); -const severity_1 = __nccwpck_require__(11135); -const finding_identity_1 = __nccwpck_require__(9248); -const sensitive_text_1 = __nccwpck_require__(57472); +const deduplicate_findings_1 = __nccwpck_require__(62908); +const file_ignore_policy_1 = __nccwpck_require__(20542); +const limit_comments_1 = __nccwpck_require__(31643); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const path_validation_1 = __nccwpck_require__(70124); +const severity_1 = __nccwpck_require__(14626); +const finding_identity_1 = __nccwpck_require__(91853); +const sensitive_text_1 = __nccwpck_require__(47122); /** Hard cap for model-controlled arrays before any filtering or publication. */ exports.MAX_AGENT_FINDINGS = 500; exports.MAX_AGENT_RESOLVED_FINDINGS = 500; @@ -67489,7 +67489,7 @@ function isRecord(value) { /***/ }), -/***/ 77714: +/***/ 88442: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -67500,11 +67500,11 @@ function isRecord(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishFindings = publishFindings; -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const finding_1 = __nccwpck_require__(71592); -const publish_issue_finding_comment_1 = __nccwpck_require__(67793); -const publish_pr_review_comments_1 = __nccwpck_require__(19504); -const publish_overflow_comment_1 = __nccwpck_require__(75231); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const finding_1 = __nccwpck_require__(31011); +const publish_issue_finding_comment_1 = __nccwpck_require__(84950); +const publish_pr_review_comments_1 = __nccwpck_require__(50352); +const publish_overflow_comment_1 = __nccwpck_require__(10974); async function publishFindings(param) { const { operation, context, findings, commitSha, overflowCount = 0, overflowTitles = [], ports, catalog } = param; const { existingByFindingId, canonicalPullRequest, prContext } = context; @@ -67541,15 +67541,15 @@ async function publishFindings(param) { /***/ }), -/***/ 67793: +/***/ 84950: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishIssueFindingComment = publishIssueFindingComment; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const logging_ports_1 = __nccwpck_require__(97793); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const logging_ports_1 = __nccwpck_require__(6152); async function publishIssueFindingComment(repository, issueNumber, finding, existing, commitSha, catalog) { const body = (0, bugbot_finding_marker_policy_1.buildCommentBody)(finding, false, undefined, { catalog }); const options = commitSha ? { commitSha } : undefined; @@ -67565,16 +67565,16 @@ async function publishIssueFindingComment(repository, issueNumber, finding, exis /***/ }), -/***/ 75231: +/***/ 10974: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishOverflowComment = publishOverflowComment; -const logging_ports_1 = __nccwpck_require__(97793); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const logging_ports_1 = __nccwpck_require__(6152); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); async function publishOverflowComment(repository, issueNumber, overflowCount, overflowTitles, commitSha, catalog = (0, bugbot_message_catalog_1.resolveStaticBugbotCatalog)('en-US')) { if (overflowCount <= 0) return; @@ -67594,20 +67594,20 @@ ${catalog.message('bugbot.overflow.body', { count: `**${overflowCount}**` }, ove /***/ }), -/***/ 19504: +/***/ 50352: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentPublisher = void 0; -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const path_validation_1 = __nccwpck_require__(72146); -const logging_ports_1 = __nccwpck_require__(97793); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const bugbot_review_presentation_policy_1 = __nccwpck_require__(94649); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const path_validation_1 = __nccwpck_require__(70124); +const logging_ports_1 = __nccwpck_require__(6152); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const bugbot_review_presentation_policy_1 = __nccwpck_require__(43799); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); class PullRequestReviewCommentPublisher { constructor(options) { this.options = options; @@ -67766,7 +67766,7 @@ function sanitizeSummaryText(value, maximum) { /***/ }), -/***/ 79678: +/***/ 13059: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -67774,11 +67774,11 @@ function sanitizeSummaryText(value, maximum) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.queryBugbotFindings = queryBugbotFindings; exports.queryBugbotPartitionFindings = queryBugbotPartitionFindings; -const agent_task_policy_1 = __nccwpck_require__(34816); -const schema_1 = __nccwpck_require__(54744); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); +const agent_task_policy_1 = __nccwpck_require__(85712); +const schema_1 = __nccwpck_require__(16808); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); const MAX_PARTITION_QUERY_ATTEMPTS = 3; function bugbotQueryOptions(schema) { return (0, agent_output_locale_policy_1.productFacingAgentQueryOptions)('bugbot-review', schema); @@ -67831,20 +67831,20 @@ async function queryBugbotPartitionFindings(repository, configuration, prompt, t /***/ }), -/***/ 80398: +/***/ 57515: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileBugbotReviewState = reconcileBugbotReviewState; -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const review_projection_1 = __nccwpck_require__(25952); -const bugbot_reconciliation_policy_1 = __nccwpck_require__(55390); -const bugbot_provider_projection_policy_1 = __nccwpck_require__(33245); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const load_bugbot_reconciliation_snapshot_use_case_1 = __nccwpck_require__(76490); -const synchronize_bugbot_review_presentation_use_case_1 = __nccwpck_require__(31210); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const review_projection_1 = __nccwpck_require__(80859); +const bugbot_reconciliation_policy_1 = __nccwpck_require__(78128); +const bugbot_provider_projection_policy_1 = __nccwpck_require__(85821); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const load_bugbot_reconciliation_snapshot_use_case_1 = __nccwpck_require__(44861); +const synchronize_bugbot_review_presentation_use_case_1 = __nccwpck_require__(44491); /** * Orchestrates final Bugbot reconciliation. Provider acquisition, pure state * planning, and presentation mutations are deliberately owned by dedicated @@ -67911,15 +67911,15 @@ function toSafeOperationMessage(error) { /***/ }), -/***/ 52971: +/***/ 17437: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RememberBugbotRuleUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); /** Stores an explicitly approved, repository-versioned Bugbot rule. */ class RememberBugbotRuleUseCase { constructor(rules) { @@ -67954,14 +67954,14 @@ exports.RememberBugbotRuleUseCase = RememberBugbotRuleUseCase; /***/ }), -/***/ 78269: +/***/ 35300: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveIssueFinding = resolveIssueFinding; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); async function resolveIssueFinding(repository, resolution, catalog) { const body = resolution.comment.body; const marker = (0, bugbot_finding_marker_policy_1.parseMarker)(body).find((candidate) => candidate.findingId === resolution.findingId); @@ -67978,15 +67978,15 @@ async function resolveIssueFinding(repository, resolution, catalog) { /***/ }), -/***/ 46024: +/***/ 64567: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolvePullRequestFinding = resolvePullRequestFinding; -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); async function resolvePullRequestFinding(repository, resolution, catalog) { const comments = await repository.listPullRequestReviewComments(resolution.pullRequestNumber); const comment = comments.find((candidate) => candidate.identity === resolution.commentIdentity); @@ -68015,7 +68015,7 @@ async function resolvePullRequestFinding(repository, resolution, catalog) { /***/ }), -/***/ 32668: +/***/ 59828: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -68061,7 +68061,7 @@ function sanitizeUserCommentForPrompt(raw) { /***/ }), -/***/ 54744: +/***/ 16808: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -68073,8 +68073,8 @@ function sanitizeUserCommentForPrompt(raw) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BUGBOT_FIX_INTENT_RESPONSE_SCHEMA = exports.BUGBOT_PARTITION_RESPONSE_SCHEMA = exports.BUGBOT_RESPONSE_SCHEMA = void 0; exports.buildBugbotPartitionResponseSchema = buildBugbotPartitionResponseSchema; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); /** Detection returns findings and explicit lifecycle changes for prior finding IDs. */ exports.BUGBOT_RESPONSE_SCHEMA = { type: 'object', @@ -68211,7 +68211,7 @@ exports.BUGBOT_FIX_INTENT_RESPONSE_SCHEMA = { /***/ }), -/***/ 11135: +/***/ 14626: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -68248,19 +68248,19 @@ function meetsMinSeverity(findingSeverity, minSeverity) { /***/ }), -/***/ 31210: +/***/ 44491: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.synchronizeBugbotReviewPresentation = synchronizeBugbotReviewPresentation; -const application_error_1 = __nccwpck_require__(1889); -const bugbot_review_presentation_policy_1 = __nccwpck_require__(94649); -const bugbot_review_ownership_policy_1 = __nccwpck_require__(51686); -const review_projection_1 = __nccwpck_require__(25952); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_review_presentation_policy_1 = __nccwpck_require__(43799); +const bugbot_review_ownership_policy_1 = __nccwpck_require__(83288); +const review_projection_1 = __nccwpck_require__(80859); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); const REVIEW_UPDATE_BATCH_SIZE = 20; const MAX_REVIEW_UPDATES_PER_RUN = 100; const REVIEW_UPDATE_CONCURRENCY = 4; @@ -68440,7 +68440,7 @@ async function mapWithConcurrency(values, concurrency, operation) { /***/ }), -/***/ 23322: +/***/ 96031: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -68482,7 +68482,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_VERIFY_COMMANDS = void 0; exports.parseVerifyCommand = parseVerifyCommand; exports.limitVerifyCommands = limitVerifyCommands; -const shellQuote = __importStar(__nccwpck_require__(11817)); +const shellQuote = __importStar(__nccwpck_require__(18108)); exports.MAX_VERIFY_COMMANDS = 20; function parseVerifyCommand(cmd) { const trimmed = cmd.trim(); @@ -68508,17 +68508,17 @@ function limitVerifyCommands(commands) { /***/ }), -/***/ 50827: +/***/ 57742: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runVerifyCommands = runVerifyCommands; -const logging_ports_1 = __nccwpck_require__(97793); -const verify_command_policy_1 = __nccwpck_require__(23322); -const verification_runtime_policy_1 = __nccwpck_require__(88201); -const verification_setup_policy_1 = __nccwpck_require__(90620); +const logging_ports_1 = __nccwpck_require__(6152); +const verify_command_policy_1 = __nccwpck_require__(96031); +const verification_runtime_policy_1 = __nccwpck_require__(89347); +const verification_setup_policy_1 = __nccwpck_require__(65326); async function runVerifyCommands(commands, execute) { for (const command of commands) { const result = await executeVerifyCommand(command, execute); @@ -68573,7 +68573,7 @@ function isSensitiveArgumentName(argument) { /***/ }), -/***/ 33363: +/***/ 93370: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -68652,16 +68652,16 @@ async function hasWorkspaceChanges(gitCommitPort) { /***/ }), -/***/ 82845: +/***/ 28356: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckChangesIssueSizeUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const check_changes_issue_size_workflow_1 = __nccwpck_require__(94655); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const check_changes_issue_size_workflow_1 = __nccwpck_require__(43250); class CheckChangesIssueSizeUseCase { constructor(projectBoardCommandPort, issueRepository, pullRequestRepository, branchChangeSizePort, projectMembershipQueryPort) { this.projectBoardCommandPort = projectBoardCommandPort; @@ -68687,17 +68687,17 @@ exports.CheckChangesIssueSizeUseCase = CheckChangesIssueSizeUseCase; /***/ }), -/***/ 94655: +/***/ 43250: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCheckChangesIssueSize = runCheckChangesIssueSize; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const update_change_size_labels_1 = __nccwpck_require__(7474); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const update_change_size_labels_1 = __nccwpck_require__(51200); +const application_error_1 = __nccwpck_require__(75999); async function runCheckChangesIssueSize(param, taskId, dependencies) { try { const baseBranch = param.baseBranch; @@ -68760,14 +68760,14 @@ function logSize(size, githubSize, reason, currentLabel) { /***/ }), -/***/ 19827: +/***/ 6287: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DetectPotentialProblemsUseCase = void 0; -const detect_potential_problems_workflow_1 = __nccwpck_require__(58282); +const detect_potential_problems_workflow_1 = __nccwpck_require__(37033); /** Application boundary for detecting, publishing and resolving Bugbot findings. */ class DetectPotentialProblemsUseCase { constructor(aiRepository, scm, telemetryPort, catalogResolver) { @@ -68791,30 +68791,30 @@ exports.DetectPotentialProblemsUseCase = DetectPotentialProblemsUseCase; /***/ }), -/***/ 58282: +/***/ 37033: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runDetectPotentialProblemsWorkflow = runDetectPotentialProblemsWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const task_emoji_1 = __nccwpck_require__(8353); -const logging_ports_1 = __nccwpck_require__(97793); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const apply_detected_findings_1 = __nccwpck_require__(60798); -const bugbot_finding_status_policy_1 = __nccwpck_require__(10264); -const bugbot_review_telemetry_1 = __nccwpck_require__(82658); -const analyze_bugbot_revision_use_case_1 = __nccwpck_require__(7062); -const bugbot_review_freshness_1 = __nccwpck_require__(1415); -const reconcile_bugbot_review_state_use_case_1 = __nccwpck_require__(80398); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_event_ownership_policy_1 = __nccwpck_require__(22322); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); -const bugbot_partition_completion_policy_1 = __nccwpck_require__(54151); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const task_emoji_1 = __nccwpck_require__(46103); +const logging_ports_1 = __nccwpck_require__(6152); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const apply_detected_findings_1 = __nccwpck_require__(20793); +const bugbot_finding_status_policy_1 = __nccwpck_require__(53822); +const bugbot_review_telemetry_1 = __nccwpck_require__(46790); +const analyze_bugbot_revision_use_case_1 = __nccwpck_require__(4658); +const bugbot_review_freshness_1 = __nccwpck_require__(14307); +const reconcile_bugbot_review_state_use_case_1 = __nccwpck_require__(57515); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_event_ownership_policy_1 = __nccwpck_require__(52771); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); +const bugbot_partition_completion_policy_1 = __nccwpck_require__(57555); const TASK_ID = 'DetectPotentialProblemsUseCase'; /** Coordinates Bugbot context, analysis and finding publication behind application ports. */ async function runDetectPotentialProblemsWorkflow(reviewContext, dependencies) { @@ -69148,15 +69148,15 @@ function resolvePublicationCatalog(operation, dependencies, publishesToPullReque /***/ }), -/***/ 37329: +/***/ 68549: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.checkoutBranch = checkoutBranch; -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); const STASH_MESSAGE = 'bugbot-autofix-before-checkout'; async function hasUncommittedChanges(port) { let output = ''; @@ -69224,16 +69224,16 @@ async function checkedGit(port, args) { /***/ }), -/***/ 95998: +/***/ 33276: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.NotifyNewCommitOnIssueUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const notify_new_commit_on_issue_workflow_1 = __nccwpck_require__(61461); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const notify_new_commit_on_issue_workflow_1 = __nccwpck_require__(46101); class NotifyNewCommitOnIssueUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -69249,16 +69249,16 @@ exports.NotifyNewCommitOnIssueUseCase = NotifyNewCommitOnIssueUseCase; /***/ }), -/***/ 61461: +/***/ 46101: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runNotifyNewCommitOnIssueWorkflow = runNotifyNewCommitOnIssueWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); async function runNotifyNewCommitOnIssueWorkflow(param, taskId, issueRepository) { const result = []; try { @@ -69286,7 +69286,7 @@ async function runNotifyNewCommitOnIssueWorkflow(param, taskId, issueRepository) /***/ }), -/***/ 7474: +/***/ 51200: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -69338,7 +69338,7 @@ function sameLabels(current, next) { /***/ }), -/***/ 82028: +/***/ 19004: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -69350,15 +69350,15 @@ function sameLabels(current, next) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DoUserRequestUseCase = void 0; -const agent_1 = __nccwpck_require__(11066); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const result_1 = __nccwpck_require__(99917); -const project_context_instruction_1 = __nccwpck_require__(55527); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); +const agent_1 = __nccwpck_require__(79937); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const result_1 = __nccwpck_require__(73817); +const project_context_instruction_1 = __nccwpck_require__(63907); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = "DoUserRequestUseCase"; class DoUserRequestUseCase { constructor(aiRepository, gitCommitPort) { @@ -69455,7 +69455,7 @@ function failure(error) { /***/ }), -/***/ 20135: +/***/ 24243: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -69464,9 +69464,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_AUTOMATED_CHANGED_PATHS = void 0; exports.prepareWorkspaceMutation = prepareWorkspaceMutation; exports.finalizeWorkspaceMutation = finalizeWorkspaceMutation; -const application_error_1 = __nccwpck_require__(1889); -const git_branch_checkout_1 = __nccwpck_require__(37329); -const workspace_changes_1 = __nccwpck_require__(33363); +const application_error_1 = __nccwpck_require__(75999); +const git_branch_checkout_1 = __nccwpck_require__(68549); +const workspace_changes_1 = __nccwpck_require__(93370); exports.MAX_AUTOMATED_CHANGED_PATHS = 100; /** Establishes a clean and deterministic repository boundary before an agent may mutate files. */ async function prepareWorkspaceMutation(gitCommitPort, options) { @@ -69520,15 +69520,15 @@ async function inspectWorkspace(gitCommitPort, phase) { /***/ }), -/***/ 37113: +/***/ 72063: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.extractStructuredAnswer = extractStructuredAnswer; -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const application_error_1 = __nccwpck_require__(1889); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const application_error_1 = __nccwpck_require__(75999); function extractStructuredAnswer(response, targetLocale) { if (response == null) return ''; @@ -69543,16 +69543,16 @@ function extractStructuredAnswer(response, targetLocale) { /***/ }), -/***/ 89969: +/***/ 18846: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckPermissionsUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const check_permissions_workflow_1 = __nccwpck_require__(61273); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const check_permissions_workflow_1 = __nccwpck_require__(17102); class CheckPermissionsUseCase { constructor(organizationMembersPort) { this.organizationMembersPort = organizationMembersPort; @@ -69570,7 +69570,7 @@ exports.CheckPermissionsUseCase = CheckPermissionsUseCase; /***/ }), -/***/ 61273: +/***/ 17102: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -69578,9 +69578,9 @@ exports.CheckPermissionsUseCase = CheckPermissionsUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectCheckPermissionsContext = projectCheckPermissionsContext; exports.runCheckPermissionsWorkflow = runCheckPermissionsWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); function projectCheckPermissionsContext(source) { const issueTarget = source.isIssue; return Object.freeze({ @@ -69644,7 +69644,7 @@ function buildInactiveResult(param, taskId) { /***/ }), -/***/ 59013: +/***/ 72770: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -69653,16 +69653,16 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CommentLanguageTranslationWorkflow = exports.TRANSLATED_COMMENT_MARKER = void 0; exports.projectCommentLanguageRequest = projectCommentLanguageRequest; exports.getCommentLanguageAdaptationPayload = getCommentLanguageAdaptationPayload; -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const comment_translation_policy_1 = __nccwpck_require__(47336); -const locale_1 = __nccwpck_require__(52028); -const application_error_1 = __nccwpck_require__(1889); -var comment_translation_policy_2 = __nccwpck_require__(47336); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const comment_translation_policy_1 = __nccwpck_require__(27150); +const locale_1 = __nccwpck_require__(15386); +const application_error_1 = __nccwpck_require__(75999); +var comment_translation_policy_2 = __nccwpck_require__(27150); Object.defineProperty(exports, "TRANSLATED_COMMENT_MARKER", ({ enumerable: true, get: function () { return comment_translation_policy_2.TRANSLATED_COMMENT_MARKER; } })); function projectCommentLanguageRequest(source) { return Object.freeze({ @@ -69806,7 +69806,7 @@ function languageAdaptationPayload(status, targetLocale, interpretedComment, sou /***/ }), -/***/ 71313: +/***/ 56334: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -69850,7 +69850,7 @@ function toCamelCase(input) { /***/ }), -/***/ 87486: +/***/ 79544: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -69873,14 +69873,14 @@ async function cleanupDuplicateComment(context, comments, sourceIsCurrent) { /***/ }), -/***/ 54053: +/***/ 65440: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildCommitPrefix = buildCommitPrefix; -const commit_prefix_transform_policy_1 = __nccwpck_require__(71313); +const commit_prefix_transform_policy_1 = __nccwpck_require__(56334); function buildCommitPrefix(branchName, transforms, onUnknownTransform) { return transforms .split(',') @@ -69891,18 +69891,18 @@ function buildCommitPrefix(branchName, transforms, onUnknownTransform) { /***/ }), -/***/ 60883: +/***/ 59946: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GetHotfixVersionUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class GetHotfixVersionUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -69983,18 +69983,18 @@ function isPositiveIssueNumber(value) { /***/ }), -/***/ 69804: +/***/ 64410: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GetReleaseTypeUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class GetReleaseTypeUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -70064,18 +70064,18 @@ function isPositiveIssueNumber(value) { /***/ }), -/***/ 6769: +/***/ 70587: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GetReleaseVersionUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class GetReleaseVersionUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -70146,7 +70146,7 @@ function isPositiveIssueNumber(value) { /***/ }), -/***/ 63457: +/***/ 89064: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -70155,10 +70155,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectIssueContentLinkContext = projectIssueContentLinkContext; exports.projectPullRequestContentLinkContext = projectPullRequestContentLinkContext; exports.runProjectContentLinkWorkflow = runProjectContentLinkWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); function projectIssueContentLinkContext(source) { return projectContext(source, 'issue', source.issue.number, source.project.getProjectColumnIssueCreated()); } @@ -70240,25 +70240,25 @@ function capitalize(value) { /***/ }), -/***/ 47041: +/***/ 40558: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runThinkAnswerWorkflow = runThinkAnswerWorkflow; -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const project_context_instruction_1 = __nccwpck_require__(55527); -const agent_answer_policy_1 = __nccwpck_require__(37113); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const recommend_steps_result_policy_1 = __nccwpck_require__(23139); -const recommend_steps_workflow_1 = __nccwpck_require__(3298); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const project_context_instruction_1 = __nccwpck_require__(63907); +const agent_answer_policy_1 = __nccwpck_require__(72063); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const recommend_steps_result_policy_1 = __nccwpck_require__(65928); +const recommend_steps_workflow_1 = __nccwpck_require__(77522); async function runThinkAnswerWorkflow(param, taskId, request, dependencies) { const issueDescription = await loadIssueDescription(request.issueNumberForContext, dependencies.issueDescriptionQueryPort); const contextBlock = issueDescription @@ -70355,7 +70355,7 @@ async function queryThinkAnswer(param, prompt, repository, targetLocale) { /***/ }), -/***/ 84440: +/***/ 59687: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -70378,7 +70378,7 @@ function extractMentionQuestion(commentBody, tokenUser) { /***/ }), -/***/ 9106: +/***/ 23995: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -70386,10 +70386,10 @@ function extractMentionQuestion(commentBody, tokenUser) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveThinkRequest = resolveThinkRequest; exports.buildExplicitCommandQuestion = buildExplicitCommandQuestion; -const copilot_command_1 = __nccwpck_require__(28057); -const copilot_comment_request_1 = __nccwpck_require__(16602); -const think_input_policy_1 = __nccwpck_require__(84440); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); +const copilot_command_1 = __nccwpck_require__(11771); +const copilot_comment_request_1 = __nccwpck_require__(86819); +const think_input_policy_1 = __nccwpck_require__(59687); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); /** Resolves the comment input and destination without performing I/O. */ function resolveThinkRequest(param) { const commentBody = (0, think_input_policy_1.getThinkCommentBody)({ @@ -70452,14 +70452,14 @@ function buildExplicitCommandQuestion(command) { /***/ }), -/***/ 13654: +/***/ 89255: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ThinkUseCase = void 0; -const think_workflow_1 = __nccwpck_require__(84106); +const think_workflow_1 = __nccwpck_require__(36450); class ThinkUseCase { constructor(issueDescriptionQueryPort, aiRepository) { this.issueDescriptionQueryPort = issueDescriptionQueryPort; @@ -70478,7 +70478,7 @@ exports.ThinkUseCase = ThinkUseCase; /***/ }), -/***/ 84106: +/***/ 36450: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -70486,14 +70486,14 @@ exports.ThinkUseCase = ThinkUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectThinkContext = projectThinkContext; exports.runThinkWorkflow = runThinkWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const think_request_policy_1 = __nccwpck_require__(9106); -const think_answer_workflow_1 = __nccwpck_require__(47041); -const agent_task_policy_1 = __nccwpck_require__(34816); -const application_error_1 = __nccwpck_require__(1889); -const locale_1 = __nccwpck_require__(52028); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const think_request_policy_1 = __nccwpck_require__(23995); +const think_answer_workflow_1 = __nccwpck_require__(40558); +const agent_task_policy_1 = __nccwpck_require__(85712); +const application_error_1 = __nccwpck_require__(75999); +const locale_1 = __nccwpck_require__(15386); function projectThinkContext(source) { const request = (0, think_request_policy_1.resolveThinkRequest)(source); const tokenUser = source.tokenUser?.trim(); @@ -70577,7 +70577,7 @@ function logSkipReason(reason, tokenUser) { /***/ }), -/***/ 59833: +/***/ 1725: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -70586,10 +70586,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_TRANSITION_NOTIFICATION_LINKS = exports.MAX_TRANSITION_NOTIFICATION_CHARACTERS = void 0; exports.reconcileTransitionNotification = reconcileTransitionNotification; exports.renderTransitionNotification = renderTransitionNotification; -const github_publication_1 = __nccwpck_require__(16812); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(87486); +const github_publication_1 = __nccwpck_require__(35793); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(79544); exports.MAX_TRANSITION_NOTIFICATION_CHARACTERS = 400; exports.MAX_TRANSITION_NOTIFICATION_LINKS = 2; /** Creates one immutable action notification per exact transition fingerprint. */ @@ -70676,16 +70676,16 @@ function outcome(effect, canonicalCommentId, duplicatesRemoved = 0, duplicatesCo /***/ }), -/***/ 32153: +/***/ 20556: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.UpdateTitleUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const update_title_workflow_1 = __nccwpck_require__(12039); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const update_title_workflow_1 = __nccwpck_require__(50029); class UpdateTitleUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -70710,7 +70710,7 @@ exports.UpdateTitleUseCase = UpdateTitleUseCase; /***/ }), -/***/ 12039: +/***/ 50029: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -70720,10 +70720,10 @@ exports.projectUpdateTitleContext = projectUpdateTitleContext; exports.runIssueTitleUpdate = runIssueTitleUpdate; exports.runPullRequestTitleUpdate = runPullRequestTitleUpdate; exports.titleUpdateFailure = titleUpdateFailure; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const pull_request_title_policy_1 = __nccwpck_require__(94675); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const pull_request_title_policy_1 = __nccwpck_require__(59756); function projectUpdateTitleContext(source) { if (source.isIssue) { return Object.freeze({ @@ -70833,14 +70833,14 @@ function skippedResult(taskId) { /***/ }), -/***/ 77732: +/***/ 10706: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AnswerIssueHelpUseCase = void 0; -const answer_issue_help_workflow_1 = __nccwpck_require__(70249); +const answer_issue_help_workflow_1 = __nccwpck_require__(86428); /** Application boundary for the initial response to question/help issues. */ class AnswerIssueHelpUseCase { constructor(aiRepository) { @@ -70858,25 +70858,25 @@ exports.AnswerIssueHelpUseCase = AnswerIssueHelpUseCase; /***/ }), -/***/ 70249: +/***/ 86428: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runAnswerIssueHelpWorkflow = runAnswerIssueHelpWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const project_context_instruction_1 = __nccwpck_require__(55527); -const task_emoji_1 = __nccwpck_require__(8353); -const agent_answer_policy_1 = __nccwpck_require__(37113); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const project_context_instruction_1 = __nccwpck_require__(63907); +const task_emoji_1 = __nccwpck_require__(46103); +const agent_answer_policy_1 = __nccwpck_require__(72063); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); const TASK_ID = 'AnswerIssueHelpUseCase'; /** Posts one contextual answer for a newly opened question/help issue. */ async function runAnswerIssueHelpWorkflow(param, dependencies) { @@ -70961,14 +70961,14 @@ function skipped() { /***/ }), -/***/ 75855: +/***/ 55523: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AssignMemberToIssueUseCase = void 0; -const assign_members_workflow_1 = __nccwpck_require__(88740); +const assign_members_workflow_1 = __nccwpck_require__(42343); /** Application boundary for assigning issue or pull-request members. */ class AssignMemberToIssueUseCase { constructor(issueRepository, projectRepository) { @@ -70988,18 +70988,18 @@ exports.AssignMemberToIssueUseCase = AssignMemberToIssueUseCase; /***/ }), -/***/ 88740: +/***/ 42343: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runAssignMembersWorkflow = runAssignMembersWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const assignee_assignment_policy_1 = __nccwpck_require__(13382); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const assignee_assignment_policy_1 = __nccwpck_require__(85918); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = 'AssignMemberToIssueUseCase'; /** Assigns the creator and remaining project members according to the pure assignment policy. */ async function runAssignMembersWorkflow(param, dependencies) { @@ -71062,14 +71062,14 @@ function assignmentResult(success, step) { /***/ }), -/***/ 40069: +/***/ 80174: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AssignReviewersToIssueUseCase = void 0; -const assign_reviewers_workflow_1 = __nccwpck_require__(15946); +const assign_reviewers_workflow_1 = __nccwpck_require__(97260); /** Application boundary for requesting the configured number of reviewers. */ class AssignReviewersToIssueUseCase { constructor(issueRepository, pullRequestRepository, projectRepository) { @@ -71091,19 +71091,19 @@ exports.AssignReviewersToIssueUseCase = AssignReviewersToIssueUseCase; /***/ }), -/***/ 15946: +/***/ 97260: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runAssignReviewersWorkflow = runAssignReviewersWorkflow; -const result_1 = __nccwpck_require__(99917); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const reviewer_assignment_policy_1 = __nccwpck_require__(44551); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const reviewer_assignment_policy_1 = __nccwpck_require__(88350); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = 'AssignReviewersToIssueUseCase'; /** Selects and requests reviewers without coupling the use-case boundary to GitHub. */ async function runAssignReviewersWorkflow(param, dependencies) { @@ -71183,7 +71183,7 @@ function failureResult(step) { /***/ }), -/***/ 61333: +/***/ 29988: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -71205,16 +71205,16 @@ function selectBranchPreparationStrategy(flags) { /***/ }), -/***/ 32086: +/***/ 19511: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckPriorityIssueSizeUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const priority_size_check_use_case_1 = __nccwpck_require__(14461); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const priority_size_check_use_case_1 = __nccwpck_require__(98060); class CheckPriorityIssueSizeUseCase { constructor(projectBoardPriorityPort) { this.projectBoardPriorityPort = projectBoardPriorityPort; @@ -71230,19 +71230,19 @@ exports.CheckPriorityIssueSizeUseCase = CheckPriorityIssueSizeUseCase; /***/ }), -/***/ 29162: +/***/ 46753: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CloseIssueAfterMergingUseCase = void 0; -const reconcile_issue_completion_metadata_1 = __nccwpck_require__(73082); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const result_1 = __nccwpck_require__(99917); -const issue_completion_1 = __nccwpck_require__(28272); -const application_error_1 = __nccwpck_require__(1889); -const positive_integer_policy_1 = __nccwpck_require__(20889); +const reconcile_issue_completion_metadata_1 = __nccwpck_require__(70614); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const result_1 = __nccwpck_require__(73817); +const issue_completion_1 = __nccwpck_require__(31147); +const application_error_1 = __nccwpck_require__(75999); +const positive_integer_policy_1 = __nccwpck_require__(19879); /** Native completion first, selective metadata second; retained effects survive partial failures. */ class CloseIssueAfterMergingUseCase { constructor(issues) { @@ -71307,17 +71307,17 @@ function stale() { /***/ }), -/***/ 34873: +/***/ 86675: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CloseNotAllowedIssueUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class CloseNotAllowedIssueUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -71368,18 +71368,18 @@ exports.CloseNotAllowedIssueUseCase = CloseNotAllowedIssueUseCase; /***/ }), -/***/ 8946: +/***/ 33445: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runDeployAddedWorkflow = runDeployAddedWorkflow; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const deploy_workflow_policy_1 = __nccwpck_require__(25643); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const deploy_workflow_policy_1 = __nccwpck_require__(8428); +const application_error_1 = __nccwpck_require__(75999); async function runDeployAddedWorkflow(param, taskId, branchWorkflowPort, moveIssueToInProgressUseCase) { const plan = (0, deploy_workflow_policy_1.resolveDeployWorkflowPlan)(param); if (!plan) @@ -71422,16 +71422,16 @@ async function runDeployAddedWorkflow(param, taskId, branchWorkflowPort, moveIss /***/ }), -/***/ 60664: +/***/ 27708: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeployAddedUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const deploy_added_workflow_1 = __nccwpck_require__(8946); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const deploy_added_workflow_1 = __nccwpck_require__(33445); class DeployAddedUseCase { constructor(branchWorkflowPort, moveIssueToInProgressUseCase) { this.branchWorkflowPort = branchWorkflowPort; @@ -71448,14 +71448,14 @@ exports.DeployAddedUseCase = DeployAddedUseCase; /***/ }), -/***/ 43618: +/***/ 34100: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.LinkIssueProjectUseCase = void 0; -const project_content_link_workflow_1 = __nccwpck_require__(63457); +const project_content_link_workflow_1 = __nccwpck_require__(89064); /** Application boundary for linking issues to configured ProjectV2 boards. */ class LinkIssueProjectUseCase { constructor(projectContentPort) { @@ -71471,17 +71471,17 @@ exports.LinkIssueProjectUseCase = LinkIssueProjectUseCase; /***/ }), -/***/ 40595: +/***/ 52309: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MoveIssueToInProgressUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class MoveIssueToInProgressUseCase { constructor(projectRepository) { this.projectRepository = projectRepository; @@ -71527,22 +71527,22 @@ exports.MoveIssueToInProgressUseCase = MoveIssueToInProgressUseCase; /***/ }), -/***/ 66701: +/***/ 67546: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PrepareBranchesUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const branch_preparation_strategy_1 = __nccwpck_require__(61333); -const prepare_managed_branch_1 = __nccwpck_require__(83340); -const prepare_hotfix_branch_1 = __nccwpck_require__(45200); -const prepare_release_branch_1 = __nccwpck_require__(19251); -const application_error_1 = __nccwpck_require__(1889); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const branch_preparation_strategy_1 = __nccwpck_require__(29988); +const prepare_managed_branch_1 = __nccwpck_require__(29928); +const prepare_hotfix_branch_1 = __nccwpck_require__(96318); +const prepare_release_branch_1 = __nccwpck_require__(83059); +const application_error_1 = __nccwpck_require__(75999); +const issue_workflow_context_1 = __nccwpck_require__(98005); class PrepareBranchesUseCase { constructor(branchListQueryPort, branchNamePort, remoteBranchSyncPort, commitTagQueryPort, linkedBranchCommandPort, branchPropagationDelayPort, moveIssueToInProgressUseCase) { this.branchListQueryPort = branchListQueryPort; @@ -71620,16 +71620,16 @@ exports.PrepareBranchesUseCase = PrepareBranchesUseCase; /***/ }), -/***/ 45200: +/***/ 96318: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareHotfixBranch = prepareHotfixBranch; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const issue_workflow_context_1 = __nccwpck_require__(98005); async function prepareHotfixBranch(param, commitTagQuery, linkedBranchCommand, branches, taskId) { const { hotfix } = param; if (hotfix.baseVersion === undefined || @@ -71689,20 +71689,20 @@ async function prepareHotfixBranch(param, commitTagQuery, linkedBranchCommand, b /***/ }), -/***/ 83340: +/***/ 29928: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareManagedBranch = prepareManagedBranch; -const result_1 = __nccwpck_require__(99917); -const branch_preparation_policy_1 = __nccwpck_require__(51843); -const managed_branch_result_policy_1 = __nccwpck_require__(49744); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const execute_script_use_case_1 = __nccwpck_require__(54053); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const branch_preparation_policy_1 = __nccwpck_require__(97307); +const managed_branch_result_policy_1 = __nccwpck_require__(55078); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const execute_script_use_case_1 = __nccwpck_require__(65440); +const issue_workflow_context_1 = __nccwpck_require__(98005); async function prepareManagedBranch(param, issueTitle, branches, taskId, dependencies) { (0, logging_ports_1.logDebugInfo)(`Branch type: ${param.managementBranch}`); const decision = (0, branch_preparation_policy_1.decideManagedBranchPreparation)({ @@ -71786,17 +71786,17 @@ async function buildConfiguredCommitPrefix(param, branchName) { /***/ }), -/***/ 19251: +/***/ 83059: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareReleaseBranch = prepareReleaseBranch; -const result_1 = __nccwpck_require__(99917); -const execute_script_use_case_1 = __nccwpck_require__(54053); -const logging_ports_1 = __nccwpck_require__(97793); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const execute_script_use_case_1 = __nccwpck_require__(65440); +const logging_ports_1 = __nccwpck_require__(6152); +const issue_workflow_context_1 = __nccwpck_require__(98005); async function prepareReleaseBranch(param, linkedBranchCommand, branches, taskId) { const { release } = param; if (release.version === undefined || release.branch === undefined) { @@ -71886,7 +71886,7 @@ function buildReleaseReminder(param, releaseUrl, developmentUrl, mainUrl) { /***/ }), -/***/ 14549: +/***/ 16530: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -71905,17 +71905,17 @@ function resolveGithubPriorityLabel(priority, labels) { /***/ }), -/***/ 14461: +/***/ 98060: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPrioritySizeCheck = runPrioritySizeCheck; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const priority_label_policy_1 = __nccwpck_require__(14549); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const priority_label_policy_1 = __nccwpck_require__(16530); +const application_error_1 = __nccwpck_require__(75999); async function runPrioritySizeCheck(param, taskId, projectRepository) { try { return await applyPriorityToProjects(param, taskId, projectRepository); @@ -71961,16 +71961,16 @@ async function applyPriorityToProjects(param, taskId, projectRepository) { /***/ }), -/***/ 52139: +/***/ 71836: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReconcileBranchReadinessUseCase = void 0; -const issue_start_policy_1 = __nccwpck_require__(59704); -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); +const issue_start_policy_1 = __nccwpck_require__(90332); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); /** Projects verified remote facts into the managed `branched` output label. */ class ReconcileBranchReadinessUseCase { constructor(linkedBranch, labels) { @@ -72044,7 +72044,7 @@ exports.ReconcileBranchReadinessUseCase = ReconcileBranchReadinessUseCase; /***/ }), -/***/ 97165: +/***/ 57836: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -72062,18 +72062,18 @@ function selectIssueBranchesToRemove(branches, issueNumber, branchTypes) { /***/ }), -/***/ 93132: +/***/ 15608: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RemoveIssueBranchesUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const remove_issue_branches_policy_1 = __nccwpck_require__(97165); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const remove_issue_branches_policy_1 = __nccwpck_require__(57836); +const application_error_1 = __nccwpck_require__(75999); /** * Remove any branch created for this issue */ @@ -72137,17 +72137,17 @@ async function removeIssueBranch(param, taskId, branchName, branchLifecyclePort) /***/ }), -/***/ 33081: +/***/ 67129: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RemoveNotNeededBranchesUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class RemoveNotNeededBranchesUseCase { constructor(branchLifecyclePort, branchNamePort) { this.branchLifecyclePort = branchLifecyclePort; @@ -72231,16 +72231,16 @@ exports.RemoveNotNeededBranchesUseCase = RemoveNotNeededBranchesUseCase; /***/ }), -/***/ 50561: +/***/ 27065: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ResumeIssueProjectUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const issue_start_policy_1 = __nccwpck_require__(59704); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const issue_start_policy_1 = __nccwpck_require__(90332); +const application_error_1 = __nccwpck_require__(75999); /** Restore active Project state before other field writes can retrigger native autoclose. */ class ResumeIssueProjectUseCase { constructor(native, projects) { @@ -72285,17 +72285,17 @@ exports.ResumeIssueProjectUseCase = ResumeIssueProjectUseCase; /***/ }), -/***/ 40425: +/***/ 38222: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.UpdateIssueTypeUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class UpdateIssueTypeUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -72328,7 +72328,7 @@ exports.UpdateIssueTypeUseCase = UpdateIssueTypeUseCase; /***/ }), -/***/ 55111: +/***/ 93152: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -72336,7 +72336,7 @@ exports.UpdateIssueTypeUseCase = UpdateIssueTypeUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckIssueCommentLanguageUseCase = void 0; exports.projectIssueCommentLanguageRequest = projectIssueCommentLanguageRequest; -const comment_language_translation_workflow_1 = __nccwpck_require__(59013); +const comment_language_translation_workflow_1 = __nccwpck_require__(72770); function projectIssueCommentLanguageRequest(source) { return (0, comment_language_translation_workflow_1.projectCommentLanguageRequest)({ commentBody: source.issue.commentBody, @@ -72364,16 +72364,16 @@ exports.CheckIssueCommentLanguageUseCase = CheckIssueCommentLanguageUseCase; /***/ }), -/***/ 73146: +/***/ 12738: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckPriorityPullRequestSizeUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const priority_size_check_use_case_1 = __nccwpck_require__(14461); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const priority_size_check_use_case_1 = __nccwpck_require__(98060); class CheckPriorityPullRequestSizeUseCase { constructor(projectBoardPriorityPort) { this.projectBoardPriorityPort = projectBoardPriorityPort; @@ -72389,18 +72389,18 @@ exports.CheckPriorityPullRequestSizeUseCase = CheckPriorityPullRequestSizeUseCas /***/ }), -/***/ 62249: +/***/ 38259: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.LinkPullRequestIssueUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const link_pull_request_issue_workflow_1 = __nccwpck_require__(46667); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const link_pull_request_issue_workflow_1 = __nccwpck_require__(19033); +const application_error_1 = __nccwpck_require__(75999); class LinkPullRequestIssueUseCase { constructor(pullRequestIssueLinkPort, eventualConsistencyDelayPort) { this.pullRequestIssueLinkPort = pullRequestIssueLinkPort; @@ -72457,7 +72457,7 @@ function describeRecovery(error) { /***/ }), -/***/ 46667: +/***/ 19033: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -72465,9 +72465,9 @@ function describeRecovery(error) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestIssueLinkOperationError = void 0; exports.runLinkPullRequestIssue = runLinkPullRequestIssue; -const result_1 = __nccwpck_require__(99917); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const deployment_configuration_1 = __nccwpck_require__(86193); +const result_1 = __nccwpck_require__(73817); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const deployment_configuration_1 = __nccwpck_require__(22495); const LINK_MARKER_PREFIX = '/iu; function resolveOpenBranchDependencies(issues, pullRequests) { const candidates = []; @@ -82400,14 +82400,14 @@ function uniqueValidDependencies(candidates) { /***/ }), -/***/ 35105: +/***/ 9627: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BranchDependencyRepository = void 0; -const branch_dependency_policy_1 = __nccwpck_require__(19657); +const branch_dependency_policy_1 = __nccwpck_require__(54874); const OPEN_DEPENDENCIES_QUERY = ` query BranchSyncDependencies($owner: String!, $repo: String!, $issuesCursor: String, $pullsCursor: String) { repository(owner: $owner, name: $repo) { @@ -82526,7 +82526,7 @@ function withCause(message, cause) { /***/ }), -/***/ 98162: +/***/ 77509: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -82551,7 +82551,7 @@ exports.DeploymentContinuationRepository = DeploymentContinuationRepository; /***/ }), -/***/ 9736: +/***/ 91985: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -82588,17 +82588,17 @@ exports.DeploymentPresentationRepository = DeploymentPresentationRepository; /***/ }), -/***/ 37303: +/***/ 3182: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeploymentStateRepositoryFactory = void 0; -const deployment_state_fence_1 = __nccwpck_require__(78892); -const config_1 = __nccwpck_require__(29657); -const configuration_handler_1 = __nccwpck_require__(64706); -const configuration_payload_policy_1 = __nccwpck_require__(69623); +const deployment_state_fence_1 = __nccwpck_require__(72369); +const config_1 = __nccwpck_require__(90450); +const configuration_handler_1 = __nccwpck_require__(40188); +const configuration_payload_policy_1 = __nccwpck_require__(58043); class DeploymentStateRepositoryFactory { constructor(issues) { this.issues = issues; @@ -82667,14 +82667,14 @@ function isRecord(value) { /***/ }), -/***/ 22985: +/***/ 85886: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubDeploymentGitRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); class GithubDeploymentGitRepository { constructor(clientProvider) { this.clientProvider = clientProvider; @@ -82787,14 +82787,14 @@ function isNotFound(error) { /***/ }), -/***/ 8464: +/***/ 30873: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.githubDeploymentMergeError = githubDeploymentMergeError; -const deployment_merge_effect_error_1 = __nccwpck_require__(90452); +const deployment_merge_effect_error_1 = __nccwpck_require__(72594); /** Never copy provider messages, request objects, headers, or arbitrary error types into public state. */ function githubDeploymentMergeError(action, cause) { const value = isRecord(cause) ? cause : {}; @@ -82828,16 +82828,16 @@ function isRecord(value) { /***/ }), -/***/ 35255: +/***/ 96483: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubManagedPullRequestRepository = void 0; -const managed_pull_request_1 = __nccwpck_require__(59565); -const github_deployment_merge_error_1 = __nccwpck_require__(8464); -const deployment_merge_effect_error_1 = __nccwpck_require__(90452); +const managed_pull_request_1 = __nccwpck_require__(95914); +const github_deployment_merge_error_1 = __nccwpck_require__(30873); +const deployment_merge_effect_error_1 = __nccwpck_require__(72594); class GithubManagedPullRequestRepository { constructor(clientProvider) { this.clientProvider = clientProvider; @@ -82954,7 +82954,7 @@ function mapPullRequest(value, owner, repository) { /***/ }), -/***/ 48660: +/***/ 33371: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -82991,7 +82991,7 @@ async function observePullRequestReadiness(client, owner, repository, pullReques /***/ }), -/***/ 52662: +/***/ 55527: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -83031,8 +83031,8 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubTargetMergeCapabilitiesInspector = void 0; -const yaml = __importStar(__nccwpck_require__(49278)); -const github_pull_request_readiness_query_1 = __nccwpck_require__(48660); +const yaml = __importStar(__nccwpck_require__(783)); +const github_pull_request_readiness_query_1 = __nccwpck_require__(33371); class GithubTargetMergeCapabilitiesInspector { constructor(clientProvider) { this.clientProvider = clientProvider; @@ -83614,7 +83614,7 @@ function isNotFound(error) { /***/ }), -/***/ 83506: +/***/ 26331: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -83654,11 +83654,11 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GitCliRepository = void 0; -const exec = __importStar(__nccwpck_require__(4750)); -const logger_1 = __nccwpck_require__(58738); -const version_policy_1 = __nccwpck_require__(36071); -const git_authentication_environment_1 = __nccwpck_require__(49964); -const application_error_1 = __nccwpck_require__(1889); +const exec = __importStar(__nccwpck_require__(18538)); +const logger_1 = __nccwpck_require__(91151); +const version_policy_1 = __nccwpck_require__(8381); +const git_authentication_environment_1 = __nccwpck_require__(16535); +const application_error_1 = __nccwpck_require__(75999); /** * Repository for Git operations executed via CLI (exec). * Isolated to allow unit tests with mocked @actions/exec. @@ -83757,7 +83757,7 @@ exports.GitCliRepository = GitCliRepository; /***/ }), -/***/ 47976: +/***/ 57628: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -83765,8 +83765,8 @@ exports.GitCliRepository = GitCliRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.inspectMissingCredentialHealthWorkflow = inspectMissingCredentialHealthWorkflow; exports.inspectCredentialHealthWorkflowAtRef = inspectCredentialHealthWorkflowAtRef; -const setup_workflow_catalog_1 = __nccwpck_require__(53376); -const github_error_policy_1 = __nccwpck_require__(67160); +const setup_workflow_catalog_1 = __nccwpck_require__(24596); +const github_error_policy_1 = __nccwpck_require__(58791); /** A workflow API 404 is confirmed absence only after two independent Contents reads. */ async function inspectMissingCredentialHealthWorkflow(getContent, owner, repository, ref) { const state = await inspectCredentialHealthWorkflowAtRef(getContent, owner, repository, ref); @@ -83804,7 +83804,7 @@ async function inspectCredentialHealthWorkflowAtRef(getContent, owner, repositor /***/ }), -/***/ 47947: +/***/ 81189: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -83829,16 +83829,16 @@ async function listCollection(client, method, parameters, key) { /***/ }), -/***/ 10618: +/***/ 71301: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubActionsResourceCommands = void 0; -const github_secret_encryption_1 = __nccwpck_require__(47654); -const github_actions_resource_collection_1 = __nccwpck_require__(47947); -const github_error_policy_1 = __nccwpck_require__(67160); +const github_secret_encryption_1 = __nccwpck_require__(83725); +const github_actions_resource_collection_1 = __nccwpck_require__(81189); +const github_error_policy_1 = __nccwpck_require__(58791); /** GitHub Actions Secret encryption and scope-preserving resource writes. */ class GithubActionsResourceCommands { constructor(githubClient) { @@ -84038,18 +84038,18 @@ function variableWriteFailure(name, scope, phase, error) { /***/ }), -/***/ 82410: +/***/ 96558: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubActionsResourceInspector = void 0; -const setup_workflow_catalog_1 = __nccwpck_require__(53376); -const deployment_configuration_1 = __nccwpck_require__(86193); -const github_error_policy_1 = __nccwpck_require__(67160); -const credential_health_workflow_visibility_1 = __nccwpck_require__(47976); -const github_actions_resource_collection_1 = __nccwpck_require__(47947); +const setup_workflow_catalog_1 = __nccwpck_require__(24596); +const deployment_configuration_1 = __nccwpck_require__(22495); +const github_error_policy_1 = __nccwpck_require__(58791); +const credential_health_workflow_visibility_1 = __nccwpck_require__(57628); +const github_actions_resource_collection_1 = __nccwpck_require__(81189); /** Read-only GitHub Actions metadata and effective repository inventory. */ class GithubActionsResourceInspector { constructor(githubClient) { @@ -84210,7 +84210,7 @@ function combineOrganizationAccess(secrets, variables) { /***/ }), -/***/ 67160: +/***/ 58791: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -84318,14 +84318,14 @@ function readHeader(headers, expected) { /***/ }), -/***/ 75297: +/***/ 2761: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.paginateCursor = paginateCursor; -const logger_1 = __nccwpck_require__(58738); +const logger_1 = __nccwpck_require__(91151); /** * Iterates cursor-based API pages while enforcing a finite boundary and a * valid cursor transition. Consumers can `break` early when they find the @@ -84356,7 +84356,7 @@ async function* paginateCursor(fetchPage, options = {}) { /***/ }), -/***/ 45621: +/***/ 44812: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -84386,7 +84386,7 @@ function requireObject(data, operation) { /***/ }), -/***/ 93841: +/***/ 25282: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -84426,11 +84426,11 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RuntimeDoctorRepository = void 0; -const github = __importStar(__nccwpck_require__(22644)); -const github_runtime_doctor_ports_1 = __nccwpck_require__(63737); -const pull_request_approval_repository_1 = __nccwpck_require__(79657); +const github = __importStar(__nccwpck_require__(78227)); +const github_runtime_doctor_ports_1 = __nccwpck_require__(64921); +const pull_request_approval_repository_1 = __nccwpck_require__(23001); const SHA = /^[a-f0-9]{40}$/u; -const github_runtime_doctor_1 = __nccwpck_require__(56756); +const github_runtime_doctor_1 = __nccwpck_require__(20413); /** SDK DTOs and diagnostics terminate here; no mutation, provisioning, or filesystem API. */ class RuntimeDoctorRepository { constructor(owner, repository, token) { @@ -84565,15 +84565,15 @@ function status(error) { /***/ }), -/***/ 70184: +/***/ 52644: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubPublicationSourceRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); -const git_object_id_1 = __nccwpck_require__(65534); +const application_error_1 = __nccwpck_require__(75999); +const git_object_id_1 = __nccwpck_require__(88623); /** Reads the authoritative branch head without exposing Octokit to application code. */ class GithubPublicationSourceRepository { constructor(clientProvider) { @@ -84597,14 +84597,14 @@ exports.GithubPublicationSourceRepository = GithubPublicationSourceRepository; /***/ }), -/***/ 16989: +/***/ 88593: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotIssueCommentQueryRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); /** Reads the newest Bugbot issue/PR conversation comments with a fixed two-page budget. */ class BugbotIssueCommentQueryRepository { constructor(githubClient) { @@ -84688,7 +84688,7 @@ exports.BugbotIssueCommentQueryRepository = BugbotIssueCommentQueryRepository; /***/ }), -/***/ 2197: +/***/ 82726: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -84708,7 +84708,7 @@ exports.BugbotIssueRepository = BugbotIssueRepository; /***/ }), -/***/ 7434: +/***/ 91153: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -84735,15 +84735,15 @@ exports.ExecutionIssueSetupRepository = ExecutionIssueSetupRepository; /***/ }), -/***/ 99814: +/***/ 75023: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueAssignmentRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); class IssueAssignmentRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -84782,7 +84782,7 @@ exports.IssueAssignmentRepository = IssueAssignmentRepository; /***/ }), -/***/ 95907: +/***/ 23231: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -84802,15 +84802,15 @@ exports.IssueClosureRepository = IssueClosureRepository; /***/ }), -/***/ 65701: +/***/ 70791: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueCompletionRepository = void 0; -const issue_completion_1 = __nccwpck_require__(28272); -const application_error_1 = __nccwpck_require__(1889); +const issue_completion_1 = __nccwpck_require__(31147); +const application_error_1 = __nccwpck_require__(75999); /** Exact repository/subject reads and selective writes. Never replaces a label inventory. */ class IssueCompletionRepository { constructor(client, binding) { @@ -84910,18 +84910,18 @@ function invalid() { /***/ }), -/***/ 9204: +/***/ 2313: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueContentRepository = void 0; -const comment_content_policy_1 = __nccwpck_require__(11965); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); -const github_error_policy_1 = __nccwpck_require__(67160); +const comment_content_policy_1 = __nccwpck_require__(77454); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); +const github_error_policy_1 = __nccwpck_require__(58791); class IssueContentRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -85050,14 +85050,14 @@ exports.IssueContentRepository = IssueContentRepository; /***/ }), -/***/ 71922: +/***/ 28868: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueInactivityRepository = void 0; -const github_pagination_policy_1 = __nccwpck_require__(45621); +const github_pagination_policy_1 = __nccwpck_require__(44812); /** Reads the provider's issue activity timestamp and waiting-state labels. */ class IssueInactivityRepository { constructor(githubClient) { @@ -85111,18 +85111,18 @@ function toSnapshot(issue) { /***/ }), -/***/ 71461: +/***/ 59699: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueLabelProvisioningRepository = void 0; -const initial_label_provisioning_policy_1 = __nccwpck_require__(47570); -const logger_1 = __nccwpck_require__(58738); -const github_error_policy_1 = __nccwpck_require__(67160); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); +const initial_label_provisioning_policy_1 = __nccwpck_require__(73160); +const logger_1 = __nccwpck_require__(91151); +const github_error_policy_1 = __nccwpck_require__(58791); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); class IssueLabelProvisioningRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -85188,16 +85188,16 @@ function mapLabelMutationError(name, error) { /***/ }), -/***/ 68335: +/***/ 45725: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueLabelRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); class IssueLabelRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -85239,14 +85239,14 @@ exports.IssueLabelRepository = IssueLabelRepository; /***/ }), -/***/ 49034: +/***/ 8346: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueLifecycleRepository = void 0; -const logger_1 = __nccwpck_require__(58738); +const logger_1 = __nccwpck_require__(91151); class IssueLifecycleRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -85271,16 +85271,16 @@ exports.IssueLifecycleRepository = IssueLifecycleRepository; /***/ }), -/***/ 47056: +/***/ 11333: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueMetadataRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const milestone_1 = __nccwpck_require__(73034); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const milestone_1 = __nccwpck_require__(2016); +const application_error_1 = __nccwpck_require__(75999); class IssueMetadataRepository { constructor(metadataClient, graphqlClient) { this.metadataClient = metadataClient; @@ -85358,7 +85358,7 @@ exports.IssueMetadataRepository = IssueMetadataRepository; /***/ }), -/***/ 77682: +/***/ 907: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85378,15 +85378,15 @@ exports.IssueNotificationRepository = IssueNotificationRepository; /***/ }), -/***/ 80825: +/***/ 66610: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueProgressLabelRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const progress_labels_1 = __nccwpck_require__(11696); +const logger_1 = __nccwpck_require__(91151); +const progress_labels_1 = __nccwpck_require__(97890); class IssueProgressLabelRepository { constructor(issueLabelRepository) { this.issueLabelRepository = issueLabelRepository; @@ -85408,7 +85408,7 @@ exports.IssueProgressLabelRepository = IssueProgressLabelRepository; /***/ }), -/***/ 91746: +/***/ 26674: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85431,17 +85431,17 @@ exports.IssueProgressTrackingRepository = IssueProgressTrackingRepository; /***/ }), -/***/ 78377: +/***/ 10121: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTitleRepository = void 0; -const issue_emoji_policy_1 = __nccwpck_require__(92806); -const pull_request_title_policy_1 = __nccwpck_require__(94675); -const issue_title_policy_1 = __nccwpck_require__(74529); -const issue_title_update_1 = __nccwpck_require__(41190); +const issue_emoji_policy_1 = __nccwpck_require__(81201); +const pull_request_title_policy_1 = __nccwpck_require__(59756); +const issue_title_policy_1 = __nccwpck_require__(83179); +const issue_title_update_1 = __nccwpck_require__(9229); class IssueTitleRepository { constructor(issueTitleClient, issueMetadataRepository) { this.issueTitleClient = issueTitleClient; @@ -85479,7 +85479,7 @@ exports.IssueTitleRepository = IssueTitleRepository; /***/ }), -/***/ 41190: +/***/ 9229: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -85487,8 +85487,8 @@ exports.IssueTitleRepository = IssueTitleRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.updateIssueTitle = updateIssueTitle; exports.withTitleUpdateLogging = withTitleUpdateLogging; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); async function updateIssueTitle(client, owner, repository, currentTitle, nextTitle, issueNumber, token) { if (nextTitle === currentTitle) return undefined; @@ -85509,16 +85509,16 @@ async function withTitleUpdateLogging(update) { /***/ }), -/***/ 69856: +/***/ 19118: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTypeAssignmentRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const issue_type_assignment_workflow_1 = __nccwpck_require__(16122); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const issue_type_assignment_workflow_1 = __nccwpck_require__(40102); +const application_error_1 = __nccwpck_require__(75999); class IssueTypeAssignmentRepository { constructor(getIssueId, graphqlClient) { this.getIssueId = getIssueId; @@ -85540,7 +85540,7 @@ exports.IssueTypeAssignmentRepository = IssueTypeAssignmentRepository; /***/ }), -/***/ 16122: +/***/ 40102: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -85548,8 +85548,8 @@ exports.IssueTypeAssignmentRepository = IssueTypeAssignmentRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTypeCreationSkippedError = void 0; exports.assignIssueType = assignIssueType; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); async function assignIssueType(getIssueId, client, owner, repository, issueNumber, selected, token) { (0, logger_1.logDebugInfo)(`Setting issue type for issue ${issueNumber} to ${selected.name}`); const issueId = await getIssueId(owner, repository, issueNumber, token); @@ -85620,7 +85620,7 @@ exports.IssueTypeCreationSkippedError = IssueTypeCreationSkippedError; /***/ }), -/***/ 10161: +/***/ 62726: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85645,7 +85645,7 @@ function configuredIssueTypes(issueTypes) { /***/ }), -/***/ 54147: +/***/ 89634: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -85653,10 +85653,10 @@ function configuredIssueTypes(issueTypes) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ensureIssueType = ensureIssueType; exports.ensureIssueTypes = ensureIssueTypes; -const logger_1 = __nccwpck_require__(58738); -const issue_type_configuration_1 = __nccwpck_require__(10161); -const issue_type_queries_1 = __nccwpck_require__(89904); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const issue_type_configuration_1 = __nccwpck_require__(62726); +const issue_type_queries_1 = __nccwpck_require__(73192); +const application_error_1 = __nccwpck_require__(75999); async function ensureIssueType(client, owner, name, description, color) { try { const existingTypes = await (0, issue_type_queries_1.listIssueTypes)(client, owner); @@ -85704,7 +85704,7 @@ function ensureConfiguredIssueType(client, owner, configured) { /***/ }), -/***/ 89904: +/***/ 73192: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85768,15 +85768,15 @@ async function createIssueType(client, owner, name, description, color) { /***/ }), -/***/ 34680: +/***/ 4858: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTypeRepository = void 0; -const issue_type_queries_1 = __nccwpck_require__(89904); -const issue_type_ensure_workflow_1 = __nccwpck_require__(54147); +const issue_type_queries_1 = __nccwpck_require__(73192); +const issue_type_ensure_workflow_1 = __nccwpck_require__(89634); class IssueTypeRepository { constructor(graphqlClient) { this.graphqlClient = graphqlClient; @@ -85791,7 +85791,7 @@ exports.IssueTypeRepository = IssueTypeRepository; /***/ }), -/***/ 92806: +/***/ 81201: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85831,7 +85831,7 @@ function firstMatchingEmoji(rules, labels) { /***/ }), -/***/ 74529: +/***/ 83179: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85885,16 +85885,16 @@ function normalizePullRequestSourceTitle(title, issueNumber) { /***/ }), -/***/ 5445: +/***/ 96711: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ActorAuthorizationRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const actor_modification_policy_1 = __nccwpck_require__(20951); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const actor_modification_policy_1 = __nccwpck_require__(34737); +const application_error_1 = __nccwpck_require__(75999); class ActorAuthorizationRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -85965,7 +85965,7 @@ function logUnlessNotFound(error, operation) { /***/ }), -/***/ 8826: +/***/ 11454: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -85996,7 +85996,7 @@ exports.AuthenticatedUserRepository = AuthenticatedUserRepository; /***/ }), -/***/ 27042: +/***/ 84916: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -86004,7 +86004,7 @@ exports.AuthenticatedUserRepository = AuthenticatedUserRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.listOrganizationTeams = listOrganizationTeams; exports.listOrganizationTeamMembers = listOrganizationTeamMembers; -const github_pagination_policy_1 = __nccwpck_require__(45621); +const github_pagination_policy_1 = __nccwpck_require__(44812); async function listOrganizationTeams(client, organization) { const teams = []; for await (const response of client.paginate.iterator(client.rest.teams.list, { @@ -86041,17 +86041,17 @@ function isRecord(value) { /***/ }), -/***/ 76503: +/***/ 845: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.OrganizationMembersRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const project_members_policy_1 = __nccwpck_require__(11641); -const organization_members_query_1 = __nccwpck_require__(27042); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const project_members_policy_1 = __nccwpck_require__(41370); +const organization_members_query_1 = __nccwpck_require__(84916); +const application_error_1 = __nccwpck_require__(75999); class OrganizationMembersRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -86099,15 +86099,15 @@ exports.OrganizationMembersRepository = OrganizationMembersRepository; /***/ }), -/***/ 92753: +/***/ 24958: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProgressDiffRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); +const application_error_1 = __nccwpck_require__(75999); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); const MAX_COMPARISON_FILES = 300; const STATUSES = new Set(['added', 'removed', 'modified', 'renamed', 'copied', 'changed', 'unchanged']); /** Reads exact GitHub objects, omitting generated bundle patches but retaining their file facts. */ @@ -86151,14 +86151,14 @@ function unavailable(code = 'provider.unavailable') { /***/ }), -/***/ 38121: +/***/ 98952: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProjectBoardCommandRepository = void 0; -const project_board_field_update_1 = __nccwpck_require__(54336); +const project_board_field_update_1 = __nccwpck_require__(31603); /** GitHub GraphQL adapter for ProjectV2 field mutations. */ class ProjectBoardCommandRepository { constructor(projectBoardContentQueryPort, graphqlClient) { @@ -86182,16 +86182,16 @@ exports.ProjectBoardCommandRepository = ProjectBoardCommandRepository; /***/ }), -/***/ 92939: +/***/ 73579: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getProjectBoardDetail = getProjectBoardDetail; -const logger_1 = __nccwpck_require__(58738); -const project_detail_1 = __nccwpck_require__(34967); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const project_detail_1 = __nccwpck_require__(33428); +const application_error_1 = __nccwpck_require__(75999); /** Reads a ProjectV2 without leaking GitHub's owner-specific GraphQL shape. */ async function getProjectBoardDetail(ownerTypeClient, graphqlClient, projectId, owner, token) { try { @@ -86255,7 +86255,7 @@ function validateProjectId(projectId) { /***/ }), -/***/ 54336: +/***/ 31603: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -86264,9 +86264,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setProjectBoardSingleSelectField = setProjectBoardSingleSelectField; exports.setProjectBoardSingleSelectFieldByItemId = setProjectBoardSingleSelectFieldByItemId; exports.initializeProjectBoardItemStatus = initializeProjectBoardItemStatus; -const project_board_provider_limits_1 = __nccwpck_require__(87071); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_adapter_1 = __nccwpck_require__(75297); +const project_board_provider_limits_1 = __nccwpck_require__(96997); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_adapter_1 = __nccwpck_require__(2761); const FIELD_QUERY = ` query($projectId: ID!, $after: String) { node(id: $projectId) { @@ -86460,7 +86460,7 @@ async function findProjectItem(client, project, itemId, fieldName) { /***/ }), -/***/ 62956: +/***/ 63552: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -86469,9 +86469,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getProjectItemId = getProjectItemId; exports.getProjectItemIdByContentId = getProjectItemIdByContentId; exports.isProjectContentLinked = isProjectContentLinked; -const project_board_provider_limits_1 = __nccwpck_require__(87071); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_adapter_1 = __nccwpck_require__(75297); +const project_board_provider_limits_1 = __nccwpck_require__(96997); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_adapter_1 = __nccwpck_require__(2761); const CONTENT_QUERY = ` query($owner: String!, $repo: String!, $number: Int!) { repository(owner: $owner, name: $repo) { @@ -86588,14 +86588,14 @@ async function findContentSideProjectItemId(client, project, contentId) { /***/ }), -/***/ 18445: +/***/ 79285: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProjectBoardLinkRepository = void 0; -const logger_1 = __nccwpck_require__(58738); +const logger_1 = __nccwpck_require__(91151); class ProjectBoardLinkRepository { constructor(projectBoardQueryPort, graphqlClient) { this.projectBoardQueryPort = projectBoardQueryPort; @@ -86622,15 +86622,15 @@ exports.ProjectBoardLinkRepository = ProjectBoardLinkRepository; /***/ }), -/***/ 68433: +/***/ 97301: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProjectBoardQueryRepository = void 0; -const project_board_detail_query_1 = __nccwpck_require__(92939); -const project_board_item_query_1 = __nccwpck_require__(62956); +const project_board_detail_query_1 = __nccwpck_require__(73579); +const project_board_item_query_1 = __nccwpck_require__(63552); class ProjectBoardQueryRepository { constructor(ownerTypeClient, graphqlClient) { this.ownerTypeClient = ownerTypeClient; @@ -86645,7 +86645,7 @@ exports.ProjectBoardQueryRepository = ProjectBoardQueryRepository; /***/ }), -/***/ 11641: +/***/ 41370: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -86684,7 +86684,7 @@ function selectAvailableMembers(members, currentMembers, requested) { /***/ }), -/***/ 41183: +/***/ 96710: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -86759,16 +86759,16 @@ function parseApprovalCoverageZip(value) { /***/ }), -/***/ 92917: +/***/ 9958: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readApprovalEvidence = readApprovalEvidence; -const application_error_1 = __nccwpck_require__(1889); -const approval_evidence_error_1 = __nccwpck_require__(55528); -const approval_evidence_diagnostic_1 = __nccwpck_require__(53086); +const application_error_1 = __nccwpck_require__(75999); +const approval_evidence_error_1 = __nccwpck_require__(50519); +const approval_evidence_diagnostic_1 = __nccwpck_require__(98205); /** Terminates provider exceptions; even unknown statuses never interpolate provider text. */ async function readApprovalEvidence(operation, read) { try { @@ -86794,7 +86794,7 @@ async function readApprovalEvidence(operation, read) { /***/ }), -/***/ 97192: +/***/ 55165: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -86825,14 +86825,14 @@ exports.BugbotPullRequestRepository = BugbotPullRequestRepository; /***/ }), -/***/ 12678: +/***/ 68742: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCurrentBaseRevision = readCurrentBaseRevision; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); /** PR base metadata can lag a parent push; read the exact native branch ref. */ async function readCurrentBaseRevision(port, target, baseRef) { if (typeof baseRef !== 'string' || baseRef.length === 0 || baseRef.length > 1024 @@ -86848,7 +86848,7 @@ async function readCurrentBaseRevision(port, target, baseRef) { /***/ }), -/***/ 79657: +/***/ 23001: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -86889,16 +86889,16 @@ var __importStar = (this && this.__importStar) || (function () { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestApprovalRepository = void 0; exports.readEffectiveApprovalPolicy = readEffectiveApprovalPolicy; -const approval_evidence_read_1 = __nccwpck_require__(92917); -const approval_evidence_error_1 = __nccwpck_require__(55528); -const application_error_1 = __nccwpck_require__(1889); -const current_base_revision_query_1 = __nccwpck_require__(12678); -const logging_ports_1 = __nccwpck_require__(97793); -const github = __importStar(__nccwpck_require__(22644)); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const approval_coverage_artifact_1 = __nccwpck_require__(41183); -const file_ignore_policy_1 = __nccwpck_require__(38774); -const pull_request_approval_presentation_policy_1 = __nccwpck_require__(69975); +const approval_evidence_read_1 = __nccwpck_require__(9958); +const approval_evidence_error_1 = __nccwpck_require__(50519); +const application_error_1 = __nccwpck_require__(75999); +const current_base_revision_query_1 = __nccwpck_require__(68742); +const logging_ports_1 = __nccwpck_require__(6152); +const github = __importStar(__nccwpck_require__(78227)); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const approval_coverage_artifact_1 = __nccwpck_require__(96710); +const file_ignore_policy_1 = __nccwpck_require__(20542); +const pull_request_approval_presentation_policy_1 = __nccwpck_require__(79017); /** GitHub DTOs terminate here. Every partial/forbidden read becomes non-authorizing evidence. */ class PullRequestApprovalRepository { constructor(token, settings) { @@ -87311,17 +87311,17 @@ function collectDiagnostic(diagnostics, cause) { /***/ }), -/***/ 76743: +/***/ 71564: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestChangesRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); class PullRequestChangesRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -87491,16 +87491,16 @@ exports.PullRequestChangesRepository = PullRequestChangesRepository; /***/ }), -/***/ 12356: +/***/ 24189: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestLifecycleRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); -const github_error_policy_1 = __nccwpck_require__(67160); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); +const github_error_policy_1 = __nccwpck_require__(58791); class PullRequestLifecycleRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -87729,16 +87729,16 @@ function toBugbotPullRequestIdentity(value) { /***/ }), -/***/ 7154: +/***/ 17120: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentCommandRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const github_pagination_policy_1 = __nccwpck_require__(45621); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const github_pagination_policy_1 = __nccwpck_require__(44812); class PullRequestReviewCommentCommandRepository { constructor(createClient, graphqlClient, queryClient) { this.createClient = createClient; @@ -87854,15 +87854,15 @@ exports.PullRequestReviewCommentCommandRepository = PullRequestReviewCommentComm /***/ }), -/***/ 82369: +/***/ 44085: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentQueryRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const github_pagination_policy_1 = __nccwpck_require__(45621); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const github_pagination_policy_1 = __nccwpck_require__(44812); function toReviewComment(comment) { if (typeof comment.node_id !== "string" || comment.node_id.length === 0) { throw new Error("Review comment identity is unavailable."); @@ -87997,14 +87997,14 @@ exports.PullRequestReviewCommentQueryRepository = PullRequestReviewCommentQueryR /***/ }), -/***/ 60004: +/***/ 54354: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.toPullRequestReviewOperationError = toPullRequestReviewOperationError; -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); /** Only safe HTTP metadata crosses the provider boundary; provider prose never does. */ function toPullRequestReviewOperationError(error, operation, context) { if (!error || typeof error !== 'object') @@ -88021,14 +88021,14 @@ function toPullRequestReviewOperationError(error, operation, context) { /***/ }), -/***/ 28874: +/***/ 2307: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findPullRequestReviewThread = findPullRequestReviewThread; -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); const THREADS_QUERY = ` query ($owner: String!, $repo: String!, $prNumber: Int!, $threadsAfter: String) { repository(owner: $owner, name: $repo) { @@ -88122,17 +88122,17 @@ function nextConnectionCursor(pageInfo, seenCursors) { /***/ }), -/***/ 22457: +/***/ 23314: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewThreadRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const logger_1 = __nccwpck_require__(58738); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const pull_request_review_thread_locator_1 = __nccwpck_require__(28874); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const logger_1 = __nccwpck_require__(91151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const pull_request_review_thread_locator_1 = __nccwpck_require__(2307); /** GitHub GraphQL adapter for locating and resolving a pull-request review thread. */ class PullRequestReviewThreadRepository { constructor(githubClient) { @@ -88304,15 +88304,15 @@ exports.PullRequestReviewThreadRepository = PullRequestReviewThreadRepository; /***/ }), -/***/ 99470: +/***/ 13779: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewerRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const github_pagination_policy_1 = __nccwpck_require__(45621); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const github_pagination_policy_1 = __nccwpck_require__(44812); const COMPLETED_REVIEW_STATES = new Set([ "APPROVED", "CHANGES_REQUESTED", @@ -88398,7 +88398,7 @@ exports.PullRequestReviewerRepository = PullRequestReviewerRepository; /***/ }), -/***/ 32780: +/***/ 1328: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -88438,8 +88438,8 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestStatusQueryRepository = void 0; -const current_base_revision_query_1 = __nccwpck_require__(12678); -const github = __importStar(__nccwpck_require__(22644)); +const current_base_revision_query_1 = __nccwpck_require__(68742); +const github = __importStar(__nccwpck_require__(78227)); const integer = (value) => Number.isSafeInteger(value) && value > 0; const sha = (value) => typeof value === 'string' && /^[a-f0-9]{40}$/u.test(value); /** Bounded native linkage and fresh identity reads. No mutations or provider DTOs cross this boundary. */ @@ -88495,15 +88495,15 @@ exports.PullRequestStatusQueryRepository = PullRequestStatusQueryRepository; /***/ }), -/***/ 15413: +/***/ 96578: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryDefaultBranchRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); class RepositoryDefaultBranchRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -88526,22 +88526,22 @@ exports.RepositoryDefaultBranchRepository = RepositoryDefaultBranchRepository; /***/ }), -/***/ 36974: +/***/ 42075: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryReleasePublicationRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const release_content_policy_1 = __nccwpck_require__(34388); -const release_transition_policy_1 = __nccwpck_require__(51782); -const release_tag_policy_1 = __nccwpck_require__(74183); -const repository_release_query_1 = __nccwpck_require__(54835); -const application_error_1 = __nccwpck_require__(1889); -const github_error_policy_1 = __nccwpck_require__(67160); -const repository_tag_query_1 = __nccwpck_require__(36542); -const deployment_publication_1 = __nccwpck_require__(22478); +const logger_1 = __nccwpck_require__(91151); +const release_content_policy_1 = __nccwpck_require__(56818); +const release_transition_policy_1 = __nccwpck_require__(27673); +const release_tag_policy_1 = __nccwpck_require__(62748); +const repository_release_query_1 = __nccwpck_require__(10766); +const application_error_1 = __nccwpck_require__(75999); +const github_error_policy_1 = __nccwpck_require__(58791); +const repository_tag_query_1 = __nccwpck_require__(46772); +const deployment_publication_1 = __nccwpck_require__(6912); class RepositoryReleasePublicationRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -88702,7 +88702,7 @@ function verifiedReleaseUrl(release, tag, expectedName, expectedBody, operationI /***/ }), -/***/ 54835: +/***/ 10766: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -88724,7 +88724,7 @@ async function listRepositoryReleases(client, owner, repository) { /***/ }), -/***/ 36542: +/***/ 46772: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -88732,8 +88732,8 @@ async function listRepositoryReleases(client, owner, repository) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findRepositoryTag = findRepositoryTag; exports.getRepositoryTagSha = getRepositoryTagSha; -const github_error_policy_1 = __nccwpck_require__(67160); -const release_tag_policy_1 = __nccwpck_require__(74183); +const github_error_policy_1 = __nccwpck_require__(58791); +const release_tag_policy_1 = __nccwpck_require__(62748); async function findRepositoryTag(client, owner, repository, tag) { try { const { data } = await client.rest.git.getRef({ owner, repo: repository, ref: (0, release_tag_policy_1.tagReference)(tag) }); @@ -88762,17 +88762,17 @@ async function getRepositoryTagSha(client, owner, repository, tag) { /***/ }), -/***/ 46389: +/***/ 58717: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryTagRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const release_tag_policy_1 = __nccwpck_require__(74183); -const repository_tag_query_1 = __nccwpck_require__(36542); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const release_tag_policy_1 = __nccwpck_require__(62748); +const repository_tag_query_1 = __nccwpck_require__(46772); +const application_error_1 = __nccwpck_require__(75999); class RepositoryTagRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -88872,15 +88872,15 @@ exports.RepositoryTagRepository = RepositoryTagRepository; /***/ }), -/***/ 54967: +/***/ 4385: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryVersionTagsQueryRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); -const version_policy_1 = __nccwpck_require__(36071); +const application_error_1 = __nccwpck_require__(75999); +const version_policy_1 = __nccwpck_require__(8381); /** Remote-only setup query: never fetches or rewrites local moving Action tags. */ class RepositoryVersionTagsQueryRepository { constructor(githubClient) { @@ -88910,7 +88910,7 @@ exports.RepositoryVersionTagsQueryRepository = RepositoryVersionTagsQueryReposit /***/ }), -/***/ 34388: +/***/ 56818: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -88934,7 +88934,7 @@ function hasReleaseContent(release) { /***/ }), -/***/ 74183: +/***/ 62748: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -88956,7 +88956,7 @@ function releaseName(version, title) { /***/ }), -/***/ 51782: +/***/ 27673: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -88974,15 +88974,15 @@ function releaseIdAsString(id) { /***/ }), -/***/ 37159: +/***/ 2879: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReplyRequestRepository = void 0; -const reply_request_digest_1 = __nccwpck_require__(73250); -const github_user_policy_1 = __nccwpck_require__(84900); +const reply_request_digest_1 = __nccwpck_require__(47971); +const github_user_policy_1 = __nccwpck_require__(84403); /** Provider identity and diagnostics terminate here. Requests forbid redirects. */ class ReplyRequestRepository { constructor(client, binding) { @@ -89026,15 +89026,15 @@ function record(value) { /***/ }), -/***/ 34761: +/***/ 28493: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositorySecretsCommandRepository = exports.RepositoryVariablesCommandRepository = exports.SetupRemoteConfigurationQueryRepository = exports.RepositoryVariablesQueryRepository = exports.RepositorySecretNamesQueryRepository = void 0; -const github_actions_resource_inspector_1 = __nccwpck_require__(82410); -const github_actions_resource_commands_1 = __nccwpck_require__(10618); +const github_actions_resource_inspector_1 = __nccwpck_require__(96558); +const github_actions_resource_commands_1 = __nccwpck_require__(71301); /** Read-only repository Secret metadata boundary. Secret values are never available. */ class RepositorySecretNamesQueryRepository { constructor(githubClient) { @@ -89101,7 +89101,7 @@ exports.RepositorySecretsCommandRepository = RepositorySecretsCommandRepository; /***/ }), -/***/ 16848: +/***/ 85885: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89180,15 +89180,15 @@ function sameRepository(value, binding) { /***/ }), -/***/ 31381: +/***/ 40941: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ActivePreviousWorkflowRunsRepository = void 0; -const workflow_status_1 = __nccwpck_require__(23807); -const workflow_runs_retry_1 = __nccwpck_require__(38720); +const workflow_status_1 = __nccwpck_require__(1462); +const workflow_runs_retry_1 = __nccwpck_require__(86434); const NO_OP_DELAY_PORT = { wait: async () => undefined }; const SYSTEM_CLOCK = { nowMilliseconds: () => Date.now() }; const SYSTEM_RANDOM = { next: () => Math.random() }; @@ -89265,7 +89265,7 @@ function isActivePreviousRun(run, query) { /***/ }), -/***/ 20887: +/***/ 29509: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89292,7 +89292,7 @@ exports.WorkflowDispatchRepository = WorkflowDispatchRepository; /***/ }), -/***/ 38720: +/***/ 86434: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -89300,7 +89300,7 @@ exports.WorkflowDispatchRepository = WorkflowDispatchRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.WorkflowQueueDeadlineError = exports.WORKFLOW_RUNS_RETRY_POLICY = void 0; exports.withWorkflowRunsRetry = withWorkflowRunsRetry; -const workflow_queue_policy_1 = __nccwpck_require__(59989); +const workflow_queue_policy_1 = __nccwpck_require__(43193); exports.WORKFLOW_RUNS_RETRY_POLICY = { maximumAttempts: 5, rateLimitMaximumAttempts: 5, @@ -89456,7 +89456,7 @@ function firstNumericValue(...values) { /***/ }), -/***/ 23807: +/***/ 1462: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89486,7 +89486,7 @@ exports.WORKFLOW_ACTIVE_STATUSES = [ /***/ }), -/***/ 66436: +/***/ 25911: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89513,7 +89513,7 @@ function resolveActionInput(additionalParams, actionInputs, key) { /***/ }), -/***/ 18773: +/***/ 89040: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89536,7 +89536,7 @@ function isAgentConfigurationReady(configuration) { /***/ }), -/***/ 52013: +/***/ 12253: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89554,7 +89554,7 @@ function workspaceModeForCapability(capability) { /***/ }), -/***/ 11975: +/***/ 28528: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89575,7 +89575,7 @@ exports.AgentResponseLengthFailure = AgentResponseLengthFailure; /***/ }), -/***/ 53086: +/***/ 98205: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89613,7 +89613,7 @@ exports.APPROVAL_EVIDENCE_REASONS = Object.freeze([ /***/ }), -/***/ 48721: +/***/ 51114: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89670,7 +89670,7 @@ function escapeRegExp(value) { /***/ }), -/***/ 70155: +/***/ 90981: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89693,7 +89693,7 @@ function admittedBranchSyncValidationCode(value) { /***/ }), -/***/ 8442: +/***/ 14712: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -89702,7 +89702,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectCanonicalBugbotPullRequest = selectCanonicalBugbotPullRequest; exports.summarizeBugbotCoverage = summarizeBugbotCoverage; exports.completeBugbotSourceCoverage = completeBugbotSourceCoverage; -const git_object_id_1 = __nccwpck_require__(65534); +const git_object_id_1 = __nccwpck_require__(88623); function selectCanonicalBugbotPullRequest(target, candidates, source) { if (source === "exact-head" && candidates.length === 0) return { kind: "none" }; @@ -89786,7 +89786,7 @@ function matchesConstrainedHead(target, candidate) { /***/ }), -/***/ 71592: +/***/ 31011: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89842,7 +89842,7 @@ function identitiesAreCompatible(existing, finding) { /***/ }), -/***/ 9248: +/***/ 91853: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89917,7 +89917,7 @@ function fnv1a(value) { /***/ }), -/***/ 93789: +/***/ 1811: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -89968,7 +89968,7 @@ function invalid(reason) { /***/ }), -/***/ 38595: +/***/ 3994: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90037,14 +90037,14 @@ function resolveBugbotReviewEffort(configured, complexity) { /***/ }), -/***/ 25952: +/***/ 80859: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildBugbotReviewProjection = buildBugbotReviewProjection; -const review_state_1 = __nccwpck_require__(47220); +const review_state_1 = __nccwpck_require__(79200); function buildBugbotReviewProjection(input) { const findings = [...input.findings].sort((left, right) => left.id.localeCompare(right.id)); const counts = (0, review_state_1.countBugbotFindingStates)(findings.map((finding) => finding.state)); @@ -90099,7 +90099,7 @@ function stableDigest(value) { /***/ }), -/***/ 47220: +/***/ 79200: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90173,7 +90173,7 @@ function countActionableBugbotFindings(counts) { /***/ }), -/***/ 11149: +/***/ 27089: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90241,7 +90241,7 @@ function isNewerCliVersion(installedVersion, publishedVersion) { /***/ }), -/***/ 31012: +/***/ 21565: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90260,7 +90260,7 @@ exports.CLOSED_ISSUE_REASONS = Object.freeze(['completed', 'not_planned', 'dupli /***/ }), -/***/ 11965: +/***/ 77454: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90283,7 +90283,7 @@ function hasVisibleCommentContent(value) { /***/ }), -/***/ 28057: +/***/ 11771: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90405,7 +90405,7 @@ function parseFindingIdentifiers(input) { /***/ }), -/***/ 16602: +/***/ 86819: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -90413,7 +90413,7 @@ function parseFindingIdentifiers(input) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.containsBotMention = containsBotMention; exports.isCopilotCommentRequest = isCopilotCommentRequest; -const copilot_command_1 = __nccwpck_require__(28057); +const copilot_command_1 = __nccwpck_require__(11771); /** Matches GitHub usernames case-insensitively without matching a larger username. */ function containsBotMention(commentBody, tokenUser) { const normalizedUser = tokenUser.trim().replace(/^@/u, ''); @@ -90434,7 +90434,7 @@ function isCopilotCommentRequest(commentBody, botLogin) { /***/ }), -/***/ 71962: +/***/ 72418: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -90559,7 +90559,7 @@ function lifecycleStateFromLabels(currentLabels, labels = exports.DEFAULT_COPILO /***/ }), -/***/ 18679: +/***/ 40221: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -90570,7 +90570,7 @@ exports.isHistoryCommand = isHistoryCommand; exports.readOperationEvidence = readOperationEvidence; exports.validateOperationEvidence = validateOperationEvidence; exports.buildOperationEvidenceMarker = buildOperationEvidenceMarker; -const git_object_id_1 = __nccwpck_require__(65534); +const git_object_id_1 = __nccwpck_require__(88623); exports.HISTORY_COMMANDS = ['sync-branch', 'remember', 'dismiss', 'implement', 'fix']; exports.OPERATION_OUTCOMES = ['applied', 'already-current', 'not-applied', 'blocked', 'partial', 'failed', 'unavailable']; exports.OPERATION_MARKER_PREFIX = '`; @@ -44671,7 +44671,7 @@ function shortSha(value) { /***/ }), -/***/ 62640: +/***/ 61833: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -44760,7 +44760,7 @@ function doctorWorkflowCondition(value, event) { /***/ }), -/***/ 7243: +/***/ 87989: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -44803,7 +44803,7 @@ function record(value) { /***/ }), -/***/ 38774: +/***/ 20542: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -44865,7 +44865,7 @@ function fileMatchesIgnorePatterns(filePath, ignorePatterns) { /***/ }), -/***/ 27104: +/***/ 72712: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44874,8 +44874,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.sanitizeAgentMarkdown = sanitizeAgentMarkdown; exports.sanitizePublishedError = sanitizePublishedError; exports.escapeHtml = escapeHtml; -const untrusted_content_1 = __nccwpck_require__(30127); -const secret_redaction_1 = __nccwpck_require__(11978); +const untrusted_content_1 = __nccwpck_require__(67057); +const secret_redaction_1 = __nccwpck_require__(254); /** * Model output is untrusted too. Keep useful Markdown, but neutralize the * GitHub automation surfaces that could create side effects when published. @@ -44918,14 +44918,14 @@ function neutralizeGithubControls(value) { /***/ }), -/***/ 50196: +/***/ 80765: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveGithubExecutionAdmission = resolveGithubExecutionAdmission; -const github_user_policy_1 = __nccwpck_require__(84900); +const github_user_policy_1 = __nccwpck_require__(84403); /** * Decides whether a GitHub Action should enter the mutation lifecycle. * @@ -44944,7 +44944,7 @@ function resolveGithubExecutionAdmission(input) { /***/ }), -/***/ 51599: +/***/ 99566: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -44953,18 +44953,18 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validDoctorConfiguration = validDoctorConfiguration; exports.doctorRepositoryPrerequisites = doctorRepositoryPrerequisites; exports.doctorWorkflowContracts = doctorWorkflowContracts; -const doctor_workflow_matrix_policy_1 = __nccwpck_require__(7243); -const github_runtime_doctor_1 = __nccwpck_require__(56756); -const doctor_workflow_condition_policy_1 = __nccwpck_require__(62640); -const js_yaml_1 = __nccwpck_require__(49278); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); +const doctor_workflow_matrix_policy_1 = __nccwpck_require__(87989); +const github_runtime_doctor_1 = __nccwpck_require__(20413); +const doctor_workflow_condition_policy_1 = __nccwpck_require__(61833); +const js_yaml_1 = __nccwpck_require__(783); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); // eslint-disable-next-line @typescript-eslint/no-require-imports -const { validateSddPrerequisiteDocuments } = __nccwpck_require__(81422); +const { validateSddPrerequisiteDocuments } = __nccwpck_require__(95990); // CommonJS keeps this pure policy usable by the standalone Node catalog validator. // eslint-disable-next-line @typescript-eslint/no-require-imports -const { matchesFieldBoundary } = __nccwpck_require__(1164); +const { matchesFieldBoundary } = __nccwpck_require__(66014); function validDoctorConfiguration(value) { if (!value || typeof value.preBranchSdd !== 'boolean' || typeof value.issueManagedBranches !== 'boolean' || !(0, github_runtime_doctor_1.isDoctorBranchReference)(value.dependencyBranch)) @@ -45135,7 +45135,7 @@ function completeFileSamples(read, paths) { /***/ }), -/***/ 3571: +/***/ 2808: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45143,8 +45143,8 @@ function completeFileSamples(read, paths) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.isGithubRuntimeDoctorProjection = isGithubRuntimeDoctorProjection; exports.formatGithubRuntimeDoctor = formatGithubRuntimeDoctor; -const github_runtime_doctor_1 = __nccwpck_require__(56756); -const publication_message_catalog_1 = __nccwpck_require__(92221); +const github_runtime_doctor_1 = __nccwpck_require__(20413); +const publication_message_catalog_1 = __nccwpck_require__(34223); const ACTIONS = ['configuration', 'workflow', 'retry', 'issue', 'specifications', 'branch', 'policy', 'declared']; const STATES = ['pass', 'warning', 'blocked', 'unavailable', 'not-applicable']; function isGithubRuntimeDoctorProjection(value) { @@ -45218,7 +45218,7 @@ function repositorySource(value) { /***/ }), -/***/ 39606: +/***/ 30203: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45226,7 +45226,7 @@ function repositorySource(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IMPLEMENTATION_REPLY_RESULT_ID = void 0; exports.readImplementationResult = readImplementationResult; -const result_1 = __nccwpck_require__(99917); +const result_1 = __nccwpck_require__(73817); exports.IMPLEMENTATION_REPLY_RESULT_ID = 'CommentAutomation.ImplementationReply'; /** A receipt proves the operation's outcome, not feature acceptance or completeness. */ function readImplementationResult(resultId, payload) { @@ -45246,7 +45246,7 @@ function readImplementationResult(resultId, payload) { /***/ }), -/***/ 20617: +/***/ 74902: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45255,8 +45255,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.INACTIVITY_CATALOG_DEFINITIONS = exports.SPANISH_INACTIVITY_DEFINITION = exports.ENGLISH_INACTIVITY_DEFINITION = exports.INACTIVITY_MESSAGE_IDS = void 0; exports.resolveStaticInactivityCatalog = resolveStaticInactivityCatalog; exports.resolveInactivityCatalog = resolveInactivityCatalog; -const message_catalog_1 = __nccwpck_require__(69292); -const resolved_message_catalog_policy_1 = __nccwpck_require__(1992); +const message_catalog_1 = __nccwpck_require__(27097); +const resolved_message_catalog_policy_1 = __nccwpck_require__(55069); exports.INACTIVITY_MESSAGE_IDS = Object.freeze([ 'inactivity.closure.heading', 'inactivity.closure.reason', @@ -45350,7 +45350,7 @@ async function resolveInactivityCatalog(locale, configuration, resolver) { /***/ }), -/***/ 59025: +/***/ 1572: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45358,7 +45358,7 @@ async function resolveInactivityCatalog(locale, configuration, resolver) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildInactivityClosureComment = buildInactivityClosureComment; exports.buildInactivitySummarySteps = buildInactivitySummarySteps; -const publication_identity_policy_1 = __nccwpck_require__(17167); +const publication_identity_policy_1 = __nccwpck_require__(45403); function buildInactivityClosureComment(input) { const digest = (0, publication_identity_policy_1.createSemanticDigest)({ updatedAt: input.candidate.updatedAt, @@ -45399,14 +45399,14 @@ function buildInactivitySummarySteps(input) { /***/ }), -/***/ 31293: +/***/ 14960: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectInactivityResultCounts = projectInactivityResultCounts; -const result_1 = __nccwpck_require__(99917); +const result_1 = __nccwpck_require__(73817); /** Projects scan evidence without exposing the capability's internal result or step prose. */ function projectInactivityResultCounts(results) { const scans = results.filter(result => result.id === 'CloseInactiveIssuesUseCase'); @@ -45428,16 +45428,16 @@ function isInactivityCount(value) { /***/ }), -/***/ 47570: +/***/ 73160: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildInitialLabelProvisioningPlan = buildInitialLabelProvisioningPlan; -const progress_labels_1 = __nccwpck_require__(11696); -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const issue_start_policy_1 = __nccwpck_require__(59704); +const progress_labels_1 = __nccwpck_require__(97890); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const issue_start_policy_1 = __nccwpck_require__(90332); const normalizeLabelName = (name) => name.trim().toLowerCase(); function configuredLabelDefinitions(labels) { const metadata = [ @@ -45521,15 +45521,15 @@ function buildInitialLabelProvisioningPlan(labels, existingLabelNames) { /***/ }), -/***/ 14047: +/***/ 61899: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveIssueCommentPublicationRequest = resolveIssueCommentPublicationRequest; -const comment_content_policy_1 = __nccwpck_require__(11965); -const input_keys_1 = __nccwpck_require__(27112); +const comment_content_policy_1 = __nccwpck_require__(77454); +const input_keys_1 = __nccwpck_require__(88539); function resolveIssueCommentPublicationRequest(input) { if (!(0, comment_content_policy_1.hasVisibleCommentContent)(input.message)) { return new Error(`${input_keys_1.INPUT_KEYS.SINGLE_ACTION_MESSAGE} must contain a visible message.`); @@ -45561,7 +45561,7 @@ function resolveMode(mode, commentId) { /***/ }), -/***/ 35045: +/***/ 34026: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45569,12 +45569,12 @@ function resolveMode(mode, commentId) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveLifecycleState = resolveLifecycleState; exports.readLifecycleExternalEvidence = readLifecycleExternalEvidence; -const git_object_id_1 = __nccwpck_require__(65534); -const result_1 = __nccwpck_require__(99917); -const bugbot_result_finding_state_projection_policy_1 = __nccwpck_require__(99362); -const bugbot_telemetry_projection_policy_1 = __nccwpck_require__(31724); -const review_state_1 = __nccwpck_require__(47220); -const implementation_result_policy_1 = __nccwpck_require__(39606); +const git_object_id_1 = __nccwpck_require__(88623); +const result_1 = __nccwpck_require__(73817); +const bugbot_result_finding_state_projection_policy_1 = __nccwpck_require__(98117); +const bugbot_telemetry_projection_policy_1 = __nccwpck_require__(43244); +const review_state_1 = __nccwpck_require__(79200); +const implementation_result_policy_1 = __nccwpck_require__(30203); /** Resolves the next lifecycle state from application facts, never from labels or API responses. */ function resolveLifecycleState(input) { if (!input.isIssue && !input.isPullRequest) @@ -45706,7 +45706,7 @@ function boundedBranchName(value) { /***/ }), -/***/ 17042: +/***/ 61736: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -45735,7 +45735,7 @@ function resolveLifecycleWaitingState(input) { /***/ }), -/***/ 49744: +/***/ 55078: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -45790,7 +45790,7 @@ function buildManagedBranchPresentation(input) { /***/ }), -/***/ 35785: +/***/ 56033: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45800,7 +45800,7 @@ exports.SPANISH_MERGE_QUEUE_MESSAGES = exports.ENGLISH_MERGE_QUEUE_MESSAGES = ex exports.renderMergeQueueReadinessFailure = renderMergeQueueReadinessFailure; exports.producerStateMessageId = producerStateMessageId; exports.boundedMergeQueueDiagnostic = boundedMergeQueueDiagnostic; -const sensitive_text_1 = __nccwpck_require__(57472); +const sensitive_text_1 = __nccwpck_require__(47122); exports.MERGE_QUEUE_MESSAGE_IDS = Object.freeze([ 'mergeQueue.readiness.failure', 'mergeQueue.readiness.incompleteEvidence', @@ -45923,7 +45923,7 @@ function boundedMergeQueueDiagnostic(value) { /***/ }), -/***/ 59296: +/***/ 70628: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -45932,7 +45932,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_PROGRESS_PARTITIONS = exports.MAX_PROGRESS_EVIDENCE_BYTES = void 0; exports.progressEvidenceTooLarge = progressEvidenceTooLarge; exports.partitionProgressDiff = partitionProgressDiff; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); exports.MAX_PROGRESS_EVIDENCE_BYTES = 256000; exports.MAX_PROGRESS_PARTITIONS = 16; function progressEvidenceTooLarge() { @@ -45972,7 +45972,7 @@ function partitionProgressDiff(baseSha, headSha, changes) { /***/ }), -/***/ 11696: +/***/ 97890: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -46006,7 +46006,7 @@ function progressPercentToColor(percent) { /***/ }), -/***/ 51545: +/***/ 30025: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46017,9 +46017,9 @@ exports.progressPartitionResponseSchema = progressPartitionResponseSchema; exports.parseProgressPartitionFacts = parseProgressPartitionFacts; exports.progressPartitionFactLimit = progressPartitionFactLimit; exports.aggregateProgressFacts = aggregateProgressFacts; -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); // Leaves space inside the unchanged 512 KiB runtime prompt ceiling. The caller // further subtracts the exact issue/prompt envelope before requesting facts. exports.MAX_PROGRESS_AGGREGATE_BYTES = 384000; @@ -46092,7 +46092,7 @@ function invalid() { /***/ }), -/***/ 17167: +/***/ 45403: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46109,7 +46109,7 @@ exports.buildPublicationTransitionMarker = buildPublicationTransitionMarker; exports.parsePublicationTransitionMarker = parsePublicationTransitionMarker; exports.buildDuplicateMarker = buildDuplicateMarker; const node_crypto_1 = __nccwpck_require__(6005); -const github_publication_1 = __nccwpck_require__(16812); +const github_publication_1 = __nccwpck_require__(35793); exports.PUBLICATION_SCHEMA = '1'; exports.PUBLICATION_MARKER_PREFIX = 'copilot:publication'; exports.PUBLICATION_DUPLICATE_MARKER_PREFIX = 'copilot:publication-duplicate'; @@ -46240,7 +46240,7 @@ function stableSerialize(value) { /***/ }), -/***/ 92221: +/***/ 34223: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -46251,9 +46251,9 @@ exports.publicationLocaleNeedsDynamicCatalog = publicationLocaleNeedsDynamicCata exports.resolveStaticPublicationCatalog = resolveStaticPublicationCatalog; exports.resolvePublicationCatalog = resolvePublicationCatalog; exports.toPublicationCatalog = toPublicationCatalog; -const message_catalog_1 = __nccwpck_require__(69292); -const locale_1 = __nccwpck_require__(52028); -const application_error_message_catalog_1 = __nccwpck_require__(47861); +const message_catalog_1 = __nccwpck_require__(27097); +const locale_1 = __nccwpck_require__(15386); +const application_error_message_catalog_1 = __nccwpck_require__(64809); const PUBLICATION_SURFACE_MESSAGE_IDS = Object.freeze([ 'publication.implementationPlan', 'publication.planReady', @@ -46998,7 +46998,7 @@ exports.SPANISH_PUBLICATION_CATALOG = toPublicationCatalog(Object.freeze({ /***/ }), -/***/ 45483: +/***/ 79719: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47010,8 +47010,8 @@ exports.buildDuplicateCompactionPublicationPayload = buildDuplicateCompactionPub exports.duplicateCompactionPublicationOutcomes = duplicateCompactionPublicationOutcomes; exports.buildTransitionPublicationPayload = buildTransitionPublicationPayload; exports.transitionPublicationOutcomes = transitionPublicationOutcomes; -const result_1 = __nccwpck_require__(99917); -const github_publication_1 = __nccwpck_require__(16812); +const result_1 = __nccwpck_require__(73817); +const github_publication_1 = __nccwpck_require__(35793); const MAX_REPORTED_COMMENT_IDS = 20; const MAX_REPORTED_TRANSITIONS = 20; /** Builds bounded evidence for a commit-derived result that was intentionally suppressed. */ @@ -47123,7 +47123,7 @@ function areOrderedUniquePositiveIntegers(values) { /***/ }), -/***/ 69975: +/***/ 79017: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -47242,7 +47242,7 @@ function escapeMarkdown(value) { /***/ }), -/***/ 80608: +/***/ 43268: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47250,7 +47250,7 @@ function escapeMarkdown(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_PULL_REQUEST_DESCRIPTION_LENGTH = void 0; exports.renderPullRequestDescriptionContent = renderPullRequestDescriptionContent; -const github_comment_publication_policy_1 = __nccwpck_require__(27104); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); exports.MAX_PULL_REQUEST_DESCRIPTION_LENGTH = 12000; const CONTENT_KEYS = Object.freeze([ 'outputLocale', @@ -47442,7 +47442,7 @@ function renderList(values) { /***/ }), -/***/ 79355: +/***/ 79794: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47451,8 +47451,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.unavailablePullRequestReadiness = unavailablePullRequestReadiness; exports.disabledPullRequestReadiness = disabledPullRequestReadiness; exports.projectPullRequestReadiness = projectPullRequestReadiness; -const pull_request_approval_1 = __nccwpck_require__(96191); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); +const pull_request_approval_1 = __nccwpck_require__(8024); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); const objectId = (value) => typeof value === 'string' && /^[a-f0-9]{40}$/u.test(value); function unavailablePullRequestReadiness(code = 'evidence-unavailable', action = 'retry') { return Object.freeze({ readiness: 'unavailable', mode: 'unavailable', headSha: '', baseSha: '', code, @@ -47527,7 +47527,7 @@ function projectPullRequestReadiness(rawPolicy, evidence, final) { /***/ }), -/***/ 56053: +/***/ 99448: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -47581,7 +47581,7 @@ function verifiedReadinessLink(snapshot, number) { /***/ }), -/***/ 94675: +/***/ 59756: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -47609,7 +47609,7 @@ function generatedPullRequestTitle(sourceTitle, sanitizedSubject, issueNumber, l /***/ }), -/***/ 33990: +/***/ 39410: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47649,7 +47649,7 @@ function createSha256(value) { /***/ }), -/***/ 24504: +/***/ 67402: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47661,9 +47661,9 @@ exports.renderRepositoryAgentArtifacts = renderRepositoryAgentArtifacts; exports.renderRepositoryAgentGuide = renderRepositoryAgentGuide; exports.renderRepositoryAgentSkill = renderRepositoryAgentSkill; exports.renderRepositoryAgentPointerBlock = renderRepositoryAgentPointerBlock; -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const issue_start_policy_1 = __nccwpck_require__(59704); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const issue_start_policy_1 = __nccwpck_require__(90332); exports.REPOSITORY_AGENT_PROFILE_PATH = '.copilot/repository-profile.json'; exports.REPOSITORY_AGENT_GUIDE_PATH = '.copilot/AGENT_GUIDE.md'; exports.REPOSITORY_AGENT_SKILL_PATH = '.agents/skills/copilot-repository-workflow/SKILL.md'; @@ -47835,7 +47835,7 @@ function renderRepositoryAgentPointerBlock() { /***/ }), -/***/ 1992: +/***/ 55069: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -47844,8 +47844,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.toResolvedMessageCatalogView = toResolvedMessageCatalogView; exports.resolveStaticMessageCatalogView = resolveStaticMessageCatalogView; exports.resolveMessageCatalogView = resolveMessageCatalogView; -const message_catalog_1 = __nccwpck_require__(69292); -const locale_1 = __nccwpck_require__(52028); +const message_catalog_1 = __nccwpck_require__(27097); +const locale_1 = __nccwpck_require__(15386); function toResolvedMessageCatalogView(resolved) { return Object.freeze({ locale: resolved.resolvedLocale, @@ -47911,15 +47911,15 @@ async function resolveMessageCatalogView(locale, ids, sourceCatalog, bundledCata /***/ }), -/***/ 96361: +/***/ 93427: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildRetiredProgressComment = buildRetiredProgressComment; -const publication_identity_policy_1 = __nccwpck_require__(17167); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); const archiveStart = ''; const archiveEnd = ''; const head = '(?:[a-f0-9]{40}|[a-f0-9]{64})'; @@ -47980,7 +47980,7 @@ function buildRetiredProgressComment(body, locale, reason) { /***/ }), -/***/ 44551: +/***/ 88350: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -48027,7 +48027,7 @@ function calculateReviewersStillNeeded(desiredCount, currentCount, confirmedCoun /***/ }), -/***/ 85365: +/***/ 81053: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -48061,7 +48061,7 @@ function renderSddAnalysisStatus(issueNumber, locale, reason) { /***/ }), -/***/ 29948: +/***/ 2230: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -48070,8 +48070,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SPANISH_SDD_DIFF_DEFINITION = exports.ENGLISH_SDD_DIFF_DEFINITION = exports.SDD_DIFF_MESSAGE_IDS = void 0; exports.resolveSddDiffCatalog = resolveSddDiffCatalog; exports.isSddDiffResolvedLocale = isSddDiffResolvedLocale; -const message_catalog_1 = __nccwpck_require__(69292); -const resolved_message_catalog_policy_1 = __nccwpck_require__(1992); +const message_catalog_1 = __nccwpck_require__(27097); +const resolved_message_catalog_policy_1 = __nccwpck_require__(55069); exports.SDD_DIFF_MESSAGE_IDS = Object.freeze([ 'sddDiff.heading', 'sddDiff.status', 'sddDiff.action', 'sddDiff.not-applicable', 'sddDiff.no-publication', 'sddDiff.initial-only', 'sddDiff.stale', 'sddDiff.pending-revision', 'sddDiff.invalid', 'sddDiff.unavailable', @@ -48149,14 +48149,14 @@ function isSddDiffResolvedLocale(value) { /***/ }), -/***/ 11594: +/***/ 63302: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.renderSddDiff = renderSddDiff; -const pre_branch_sdd_1 = __nccwpck_require__(56394); +const pre_branch_sdd_1 = __nccwpck_require__(34730); const STATES = ['not-applicable', 'no-publication', 'initial-only', 'stale', 'pending-revision', 'invalid', 'unavailable', 'ambiguous', 'bounded', 'compared']; const ACTIONS = Object.freeze({ 'not-applicable': 'sddDiff.none', 'no-publication': 'sddDiff.publish', 'initial-only': 'sddDiff.none', @@ -48253,7 +48253,7 @@ function escapeTitle(value) { /***/ }), -/***/ 81773: +/***/ 99167: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -48261,8 +48261,8 @@ function escapeTitle(value) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildSddIssueDigest = buildSddIssueDigest; const node_crypto_1 = __nccwpck_require__(6005); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const recommendation_policy_1 = __nccwpck_require__(33990); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const recommendation_policy_1 = __nccwpck_require__(39410); /** Producer and read-only queries use the same identity and immutable first base. */ function buildSddIssueDigest(context, baseSha) { return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify([ @@ -48274,15 +48274,15 @@ function buildSddIssueDigest(context, baseSha) { /***/ }), -/***/ 50681: +/***/ 56285: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectOwnedSddCard = selectOwnedSddCard; -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const publication_identity_policy_1 = __nccwpck_require__(17167); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const publication_identity_policy_1 = __nccwpck_require__(45403); /** The latest owned card is authoritative even when invalid; an older card cannot restore readiness. */ function selectOwnedSddCard(comments, issueNumber, trustedBotLogin) { const login = trustedBotLogin.trim().toLowerCase(); @@ -48338,7 +48338,7 @@ function isOtherOwnedPublication(body, issueNumber) { /***/ }), -/***/ 11756: +/***/ 6853: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -48347,8 +48347,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.initialSddStatus = initialSddStatus; exports.projectSddStatus = projectSddStatus; exports.formatSddStatus = formatSddStatus; -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); /** Uses the admitted workflow/start policy; output labels cannot establish eligibility. */ function initialSddStatus(context, labels) { if (!context.admittedKind || typeof context.issueManagedBranches !== 'boolean' || typeof context.preBranchSdd !== 'boolean') { @@ -48448,7 +48448,7 @@ function safeIssueUrl(value, issueNumber, identity) { /***/ }), -/***/ 78334: +/***/ 81985: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -48460,24 +48460,24 @@ exports.hasOwnedPrimaryIssuePublication = hasOwnedPrimaryIssuePublication; exports.selectSemanticReplyIntents = selectSemanticReplyIntents; exports.renderSemanticReply = renderSemanticReply; exports.renderSemanticStatus = renderSemanticStatus; -const sdd_diff_message_catalog_1 = __nccwpck_require__(29948); -const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(3571); -const copilot_operation_1 = __nccwpck_require__(18679); -const copilot_history_presentation_policy_1 = __nccwpck_require__(41063); -const copilot_history_projection_policy_1 = __nccwpck_require__(67091); -const github_publication_1 = __nccwpck_require__(16812); -const github_user_policy_1 = __nccwpck_require__(84900); -const result_1 = __nccwpck_require__(99917); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const publication_message_catalog_1 = __nccwpck_require__(92221); -const copilot_interaction_policy_1 = __nccwpck_require__(52113); -const status_command_policy_1 = __nccwpck_require__(33849); -const comment_translation_policy_1 = __nccwpck_require__(47336); -const application_error_presentation_policy_1 = __nccwpck_require__(95982); -const git_object_id_1 = __nccwpck_require__(65534); -const implementation_result_policy_1 = __nccwpck_require__(39606); -const implementation_plan_1 = __nccwpck_require__(8768); +const sdd_diff_message_catalog_1 = __nccwpck_require__(2230); +const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(2808); +const copilot_operation_1 = __nccwpck_require__(40221); +const copilot_history_presentation_policy_1 = __nccwpck_require__(55507); +const copilot_history_projection_policy_1 = __nccwpck_require__(99186); +const github_publication_1 = __nccwpck_require__(35793); +const github_user_policy_1 = __nccwpck_require__(84403); +const result_1 = __nccwpck_require__(73817); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const publication_message_catalog_1 = __nccwpck_require__(34223); +const copilot_interaction_policy_1 = __nccwpck_require__(90108); +const status_command_policy_1 = __nccwpck_require__(3449); +const comment_translation_policy_1 = __nccwpck_require__(27150); +const application_error_presentation_policy_1 = __nccwpck_require__(95067); +const git_object_id_1 = __nccwpck_require__(88623); +const implementation_result_policy_1 = __nccwpck_require__(30203); +const implementation_plan_1 = __nccwpck_require__(77001); function selectSemanticStatusIntents(context) { return Object.freeze(context.results.flatMap(result => { if (!result.executed || !result.success) @@ -48994,7 +48994,7 @@ function operationMarker(intent) { /***/ }), -/***/ 2886: +/***/ 52214: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49009,8 +49009,8 @@ exports.assertSetupBatchOperationMatchesPlan = assertSetupBatchOperationMatchesP exports.isSetupBatchInstallationReceipt = isSetupBatchInstallationReceipt; exports.parseSetupBatchOperation = parseSetupBatchOperation; exports.validSetupBatchAssetPath = validSetupBatchAssetPath; -const setup_batch_1 = __nccwpck_require__(48421); -const setup_verification_action_1 = __nccwpck_require__(29549); +const setup_batch_1 = __nccwpck_require__(88308); +const setup_verification_action_1 = __nccwpck_require__(33156); const uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u; const sha = /^[a-f0-9]{40}$/u; const digest = /^[a-f0-9]{64}$/u; @@ -49132,7 +49132,7 @@ function exact(value, keys) { return Object.keys(value).length === keys.length & /***/ }), -/***/ 6736: +/***/ 23381: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49144,14 +49144,14 @@ exports.createDefaultSetupStorageConfiguration = createDefaultSetupStorageConfig exports.createDefaultSetupConfiguration = createDefaultSetupConfiguration; exports.mergeSetupConfiguration = mergeSetupConfiguration; exports.normalizeSetupConfigurationLocales = normalizeSetupConfigurationLocales; -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const agent_1 = __nccwpck_require__(18773); -const issue_inactivity_1 = __nccwpck_require__(15236); -const deployment_configuration_1 = __nccwpck_require__(86193); -const locale_1 = __nccwpck_require__(52028); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const setup_runner_1 = __nccwpck_require__(34512); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const agent_1 = __nccwpck_require__(89040); +const issue_inactivity_1 = __nccwpck_require__(38572); +const deployment_configuration_1 = __nccwpck_require__(22495); +const locale_1 = __nccwpck_require__(15386); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const setup_runner_1 = __nccwpck_require__(94301); exports.SETUP_AGENT_TASKS = [ 'planner', 'findings', @@ -49360,7 +49360,7 @@ function normalizeSetupConfigurationLocales(configuration) { /***/ }), -/***/ 69620: +/***/ 87770: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49371,17 +49371,17 @@ exports.buildSetupPlan = buildSetupPlan; exports.setupPlanGuardPaths = setupPlanGuardPaths; exports.buildSetupRepositoryVariables = buildSetupRepositoryVariables; exports.buildSetupActionInputs = buildSetupActionInputs; -const pull_request_description_1 = __nccwpck_require__(8324); -const setup_workflow_catalog_1 = __nccwpck_require__(53376); -const setup_configuration_defaults_1 = __nccwpck_require__(6736); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); +const pull_request_description_1 = __nccwpck_require__(45315); +const setup_workflow_catalog_1 = __nccwpck_require__(24596); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); Object.defineProperty(exports, "buildSetupCredentialRequirements", ({ enumerable: true, get: function () { return setup_credential_requirement_policy_1.buildSetupCredentialRequirements; } })); -const locale_1 = __nccwpck_require__(52028); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const setup_verification_action_1 = __nccwpck_require__(29549); -const repository_agent_guidance_policy_1 = __nccwpck_require__(24504); +const locale_1 = __nccwpck_require__(15386); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const setup_verification_action_1 = __nccwpck_require__(33156); +const repository_agent_guidance_policy_1 = __nccwpck_require__(67402); function buildSetupPlan(configuration, mergeQueueReadiness = [], approvalReadiness = []) { const workflowFiles = (0, setup_workflow_catalog_1.enabledSetupWorkflowFiles)((0, setup_issue_workflow_policy_1.effectiveIssueWorkflowFeatures)(configuration)) .filter(file => file !== 'copilot_pull_request_approval.yml' || configuration.pullRequestApproval.mode !== 'off'); @@ -49668,7 +49668,7 @@ function unique(values) { /***/ }), -/***/ 58409: +/***/ 56637: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -49689,16 +49689,16 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) { }; Object.defineProperty(exports, "__esModule", ({ value: true })); /** Public setup-policy boundary. Each concern is implemented in a focused policy module. */ -__exportStar(__nccwpck_require__(6736), exports); -__exportStar(__nccwpck_require__(69620), exports); -__exportStar(__nccwpck_require__(14845), exports); -__exportStar(__nccwpck_require__(62784), exports); -__exportStar(__nccwpck_require__(63312), exports); +__exportStar(__nccwpck_require__(23381), exports); +__exportStar(__nccwpck_require__(87770), exports); +__exportStar(__nccwpck_require__(2554), exports); +__exportStar(__nccwpck_require__(13339), exports); +__exportStar(__nccwpck_require__(81182), exports); /***/ }), -/***/ 14845: +/***/ 2554: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -49719,7 +49719,7 @@ exports.validateSetupManagedResourceInventory = validateSetupManagedResourceInve exports.setupWorkflowPatStorageNotice = setupWorkflowPatStorageNotice; exports.usesOrganizationStorage = usesOrganizationStorage; exports.validateStorageConfiguration = validateStorageConfiguration; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); function resolveSetupResourceScope(policy, name) { return policy.overrides[name] ?? policy.defaultScope; } @@ -49952,24 +49952,24 @@ function mergeStoragePolicy(base, override) { /***/ }), -/***/ 62784: +/***/ 13339: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validateSetupConfiguration = validateSetupConfiguration; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); -const agent_configuration_validation_policy_1 = __nccwpck_require__(17220); -const setup_configuration_storage_policy_1 = __nccwpck_require__(14845); -const issue_inactivity_1 = __nccwpck_require__(15236); -const deployment_configuration_1 = __nccwpck_require__(86193); -const locale_1 = __nccwpck_require__(52028); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const setup_project_selection_policy_1 = __nccwpck_require__(59068); -const setup_runner_policy_1 = __nccwpck_require__(70801); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); +const agent_configuration_validation_policy_1 = __nccwpck_require__(60596); +const setup_configuration_storage_policy_1 = __nccwpck_require__(2554); +const issue_inactivity_1 = __nccwpck_require__(38572); +const deployment_configuration_1 = __nccwpck_require__(22495); +const locale_1 = __nccwpck_require__(15386); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const setup_project_selection_policy_1 = __nccwpck_require__(73750); +const setup_runner_policy_1 = __nccwpck_require__(91027); function validateSetupConfiguration(configuration, options = {}) { const errors = []; errors.push(...(0, setup_runner_policy_1.validateSetupRunners)(configuration.runners)); @@ -50142,14 +50142,14 @@ function validateLocale(errors, label, value, optional) { /***/ }), -/***/ 56161: +/***/ 43562: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildSetupCredentialRequirements = buildSetupCredentialRequirements; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); const SECRET_BY_MODEL_PROVIDER = { openai: 'OPENAI_API_KEY', anthropic: 'ANTHROPIC_API_KEY', @@ -50257,7 +50257,7 @@ function uniqueDefined(current, next) { /***/ }), -/***/ 5660: +/***/ 67323: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50265,7 +50265,7 @@ function uniqueDefined(current, next) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectedInitialLabels = selectedInitialLabels; exports.selectedInitialIssueTypes = selectedInitialIssueTypes; -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); /** Removes workflow-specific resources that are not part of the effective profile. */ function selectedInitialLabels(labels, configuration) { if (!configuration) @@ -50324,7 +50324,7 @@ function selectedInitialIssueTypes(issueTypes, configuration) { /***/ }), -/***/ 63312: +/***/ 81182: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50335,7 +50335,7 @@ exports.effectiveIssueWorkflowFeatures = effectiveIssueWorkflowFeatures; exports.effectiveIssueWorkflowLabels = effectiveIssueWorkflowLabels; exports.effectiveIssueFormLabels = effectiveIssueFormLabels; exports.setupNeedsInitialVersion = setupNeedsInitialVersion; -const issue_workflow_profile_1 = __nccwpck_require__(65360); +const issue_workflow_profile_1 = __nccwpck_require__(26744); /** Applies feature switches to the explicit issue workflow selection. */ function effectiveIssueWorkflowProfile(configuration) { const configured = configuration.issueWorkflows?.enabled ?? issue_workflow_profile_1.ISSUE_WORKFLOW_KINDS; @@ -50392,7 +50392,7 @@ function setupNeedsInitialVersion(configuration) { /***/ }), -/***/ 86665: +/***/ 19698: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50400,7 +50400,7 @@ function setupNeedsInitialVersion(configuration) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SETUP_ORGANIZATION_VARIABLE_BINDINGS = void 0; exports.setupOrganizationExplicitQuestionIds = setupOrganizationExplicitQuestionIds; -const setup_configuration_defaults_1 = __nccwpck_require__(6736); +const setup_configuration_defaults_1 = __nccwpck_require__(23381); const repositoryFields = [ ['MAIN_BRANCH', 'mainBranch'], ['DEVELOPMENT_BRANCH', 'developmentBranch'], ['FEATURE_TREE', 'featureTree'], ['BUGFIX_TREE', 'bugfixTree'], @@ -50461,7 +50461,7 @@ function setupOrganizationExplicitQuestionIds(overrides) { /***/ }), -/***/ 20994: +/***/ 63882: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50471,10 +50471,10 @@ exports.normalizeSetupStoredEmptyList = normalizeSetupStoredEmptyList; exports.buildSetupOrganizationReuseVariables = buildSetupOrganizationReuseVariables; exports.planSetupOrganizationVariableReuse = planSetupOrganizationVariableReuse; exports.configureSetupOrganizationReuseStorage = configureSetupOrganizationReuseStorage; -const setup_credential_requirement_policy_1 = __nccwpck_require__(56161); -const setup_configuration_plan_1 = __nccwpck_require__(69620); -const setup_organization_variable_bindings_1 = __nccwpck_require__(86665); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); +const setup_credential_requirement_policy_1 = __nccwpck_require__(43562); +const setup_configuration_plan_1 = __nccwpck_require__(87770); +const setup_organization_variable_bindings_1 = __nccwpck_require__(19698); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); const node_util_1 = __nccwpck_require__(47261); /** Nonempty separators are native empty lists, including on older Action versions. */ const emptyLists = { @@ -50586,7 +50586,7 @@ function inventory(variables) { /***/ }), -/***/ 59068: +/***/ 73750: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50660,7 +50660,7 @@ function validateDiscoveredProjectStatuses(configuration, discovery) { /***/ }), -/***/ 49505: +/***/ 92567: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -50727,7 +50727,7 @@ function setupSecretRevisionSnapshot(remote) { /***/ }), -/***/ 70801: +/***/ 91027: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50743,8 +50743,8 @@ exports.reusableSetupRunnerDefaults = reusableSetupRunnerDefaults; exports.setupRunnerRole = setupRunnerRole; exports.selectedSetupRunsOn = selectedSetupRunsOn; exports.setupRunnerReadiness = setupRunnerReadiness; -const setup_runner_1 = __nccwpck_require__(34512); -const sensitive_text_1 = __nccwpck_require__(57472); +const setup_runner_1 = __nccwpck_require__(94301); +const sensitive_text_1 = __nccwpck_require__(47122); const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value); const exact = (value, keys) => Object.keys(value).every(key => keys.includes(key)); const literal = (value, empty = false) => typeof value === 'string' && value.length <= 100 @@ -50909,7 +50909,7 @@ function setupRunnerReadiness(route, inventory) { /***/ }), -/***/ 33849: +/***/ 3449: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -50919,14 +50919,14 @@ exports.buildCopilotStatusSnapshot = buildCopilotStatusSnapshot; exports.buildCopilotStatusResult = buildCopilotStatusResult; exports.formatCopilotStatus = formatCopilotStatus; exports.projectCurrentNativeStatus = projectCurrentNativeStatus; -const pull_request_readiness_status_policy_1 = __nccwpck_require__(56053); -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const sdd_status_policy_1 = __nccwpck_require__(11756); -const result_1 = __nccwpck_require__(99917); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const bugbot_result_finding_state_projection_policy_1 = __nccwpck_require__(99362); -const publication_message_catalog_1 = __nccwpck_require__(92221); +const pull_request_readiness_status_policy_1 = __nccwpck_require__(99448); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const sdd_status_policy_1 = __nccwpck_require__(6853); +const result_1 = __nccwpck_require__(73817); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const bugbot_result_finding_state_projection_policy_1 = __nccwpck_require__(98117); +const publication_message_catalog_1 = __nccwpck_require__(34223); /** Builds a read-only status snapshot from the facts already loaded by setup. */ function buildCopilotStatusSnapshot(execution) { const issueLabels = [...(execution.labels?.currentIssueLabels ?? [])]; @@ -51059,7 +51059,7 @@ function projectCurrentNativeStatus(status, facts) { /***/ }), -/***/ 88201: +/***/ 89347: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51140,7 +51140,7 @@ function verificationRuntimeMatches(required, observed) { /***/ }), -/***/ 90620: +/***/ 65326: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51192,7 +51192,7 @@ function parseVerificationSetupResult(value) { /***/ }), -/***/ 59989: +/***/ 43193: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51221,7 +51221,7 @@ function calculateJitteredWorkflowDelay(baseDelayMilliseconds, randomValue, poli /***/ }), -/***/ 57046: +/***/ 31811: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51238,7 +51238,7 @@ exports.AGENT_EXECUTION_OUTPUT_DIAGNOSTICS = [ /***/ }), -/***/ 63737: +/***/ 64921: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51253,7 +51253,7 @@ exports.DOCTOR_REPOSITORY_PATHS = [ /***/ }), -/***/ 97793: +/***/ 6152: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51316,7 +51316,7 @@ function setGlobalLoggerDebug(debug, isRemote = false) { /***/ }), -/***/ 62151: +/***/ 46445: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51374,7 +51374,7 @@ function toPullRequestReviewOperationError(error, operation, context) { /***/ }), -/***/ 77387: +/***/ 94752: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51404,7 +51404,7 @@ function bindSddEvidenceReadPorts(ports) { /***/ }), -/***/ 63512: +/***/ 26509: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -51416,16 +51416,16 @@ exports.DISABLED_VERIFICATION_SETUP = Object.freeze({ kind: 'disabled' }); /***/ }), -/***/ 85130: +/***/ 84387: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeploymentMergeEffects = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_merge_effect_error_1 = __nccwpck_require__(90452); -const managed_pull_request_1 = __nccwpck_require__(59565); +const application_error_1 = __nccwpck_require__(75999); +const deployment_merge_effect_error_1 = __nccwpck_require__(72594); +const managed_pull_request_1 = __nccwpck_require__(95914); /** Applies current policy, with one bounded re-observation after a typed readiness rejection. */ class DeploymentMergeEffects { constructor(pullRequests) { @@ -51501,7 +51501,7 @@ function assertSamePullRequest(expected, current) { /***/ }), -/***/ 38233: +/***/ 77658: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -51516,14 +51516,14 @@ exports.deploymentSuccess = deploymentSuccess; exports.blockedDeploymentResult = blockedDeploymentResult; exports.shouldRecordUnexpectedFailure = shouldRecordUnexpectedFailure; exports.semanticCleanupError = semanticCleanupError; -const application_error_1 = __nccwpck_require__(1889); -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_presentation_policy_1 = __nccwpck_require__(77857); -const deployment_message_catalog_1 = __nccwpck_require__(21090); -const deployment_operation_1 = __nccwpck_require__(10915); -const merge_queue_readiness_1 = __nccwpck_require__(86918); -const result_1 = __nccwpck_require__(99917); -const deployment_merge_effects_1 = __nccwpck_require__(85130); +const application_error_1 = __nccwpck_require__(75999); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_presentation_policy_1 = __nccwpck_require__(83221); +const deployment_message_catalog_1 = __nccwpck_require__(79364); +const deployment_operation_1 = __nccwpck_require__(92730); +const merge_queue_readiness_1 = __nccwpck_require__(12515); +const result_1 = __nccwpck_require__(73817); +const deployment_merge_effects_1 = __nccwpck_require__(84387); exports.DEPLOYMENT_ORCHESTRATION_TASK_ID = "DeploymentOrchestrationUseCase"; class DeploymentOrchestrationRuntime { constructor(dependencies, stateBoundary) { @@ -51793,16 +51793,16 @@ function failureCategory(operation) { /***/ }), -/***/ 8563: +/***/ 27827: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SupersededDeploymentInvocationError = exports.DeploymentStateBoundary = void 0; -const deployment_state_fence_1 = __nccwpck_require__(78892); -const deployment_lifecycle_policy_1 = __nccwpck_require__(39578); -const application_error_1 = __nccwpck_require__(1889); +const deployment_state_fence_1 = __nccwpck_require__(72369); +const deployment_lifecycle_policy_1 = __nccwpck_require__(54037); +const application_error_1 = __nccwpck_require__(75999); class DeploymentStateBoundary { constructor(state, labels) { this.state = state; @@ -51882,14 +51882,14 @@ exports.SupersededDeploymentInvocationError = SupersededDeploymentInvocationErro /***/ }), -/***/ 1980: +/***/ 41601: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckProgressUseCase = void 0; -const check_progress_workflow_1 = __nccwpck_require__(88755); +const check_progress_workflow_1 = __nccwpck_require__(94343); /** Application boundary for assessing and publishing issue progress. */ class CheckProgressUseCase { constructor(issueDescriptionQueryPort, issueLabelsPort, issueProgressPort, branchRepository, pullRequestRepository, aiRepository, publicationSourceQuery, progressDiffQuery) { @@ -51921,21 +51921,21 @@ exports.CheckProgressUseCase = CheckProgressUseCase; /***/ }), -/***/ 88755: +/***/ 94343: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCheckProgressWorkflow = runCheckProgressWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const sync_progress_labels_to_open_pull_requests_1 = __nccwpck_require__(55198); -const progress_summary_builder_1 = __nccwpck_require__(42351); -const progress_analysis_workflow_1 = __nccwpck_require__(41135); -const application_error_1 = __nccwpck_require__(1889); -const publication_outcome_policy_1 = __nccwpck_require__(45483); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const sync_progress_labels_to_open_pull_requests_1 = __nccwpck_require__(18277); +const progress_summary_builder_1 = __nccwpck_require__(62721); +const progress_analysis_workflow_1 = __nccwpck_require__(88729); +const application_error_1 = __nccwpck_require__(75999); +const publication_outcome_policy_1 = __nccwpck_require__(79719); /** Publishes a completed progress assessment after the analysis workflow succeeds. */ async function runCheckProgressWorkflow(param, taskId, dependencies) { (0, logging_ports_1.logInfo)(`${(0, task_emoji_1.getTaskEmoji)(taskId)} Executing ${taskId}.`); @@ -52049,14 +52049,14 @@ function logProgressAssessment(progress, summary, reasoning, remaining) { /***/ }), -/***/ 38028: +/***/ 84579: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CloseInactiveIssuesUseCase = void 0; -const close_inactive_issues_workflow_1 = __nccwpck_require__(80159); +const close_inactive_issues_workflow_1 = __nccwpck_require__(86288); /** Application boundary for the scheduled inactivity-maintenance action. */ class CloseInactiveIssuesUseCase { constructor(issueQueryPort, issueClosurePort, clock, catalogResolver) { @@ -52080,19 +52080,19 @@ exports.CloseInactiveIssuesUseCase = CloseInactiveIssuesUseCase; /***/ }), -/***/ 80159: +/***/ 86288: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCloseInactiveIssuesWorkflow = runCloseInactiveIssuesWorkflow; -const result_1 = __nccwpck_require__(99917); -const issue_inactivity_1 = __nccwpck_require__(15236); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const inactivity_message_catalog_1 = __nccwpck_require__(20617); -const inactivity_notification_policy_1 = __nccwpck_require__(59025); +const result_1 = __nccwpck_require__(73817); +const issue_inactivity_1 = __nccwpck_require__(38572); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const inactivity_message_catalog_1 = __nccwpck_require__(74902); +const inactivity_notification_policy_1 = __nccwpck_require__(1572); const TASK_ID = 'CloseInactiveIssuesUseCase'; /** Scans waiting issues and closes only candidates that remain inactive. */ async function runCloseInactiveIssuesWorkflow(param, dependencies) { @@ -52246,7 +52246,7 @@ function unique(values) { /***/ }), -/***/ 3685: +/***/ 76549: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -52255,8 +52255,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.validateReleaseInput = validateReleaseInput; exports.normalizeVersion = normalizeVersion; exports.versionForRelease = versionForRelease; -const input_keys_1 = __nccwpck_require__(27112); -const application_error_1 = __nccwpck_require__(1889); +const input_keys_1 = __nccwpck_require__(88539); +const application_error_1 = __nccwpck_require__(75999); const SEMVER_PATTERN = /^\d+(\.\d+){0,2}$/; function validateReleaseInput(input) { if (!input.version.length) @@ -52284,16 +52284,16 @@ function versionForRelease(version) { /***/ }), -/***/ 86222: +/***/ 25258: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CreateReleaseUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const create_release_workflow_1 = __nccwpck_require__(98684); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const create_release_workflow_1 = __nccwpck_require__(75138); class CreateReleaseUseCase { constructor(repositoryReleasePort) { this.repositoryReleasePort = repositoryReleasePort; @@ -52309,18 +52309,18 @@ exports.CreateReleaseUseCase = CreateReleaseUseCase; /***/ }), -/***/ 98684: +/***/ 75138: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCreateRelease = runCreateRelease; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const create_release_policy_1 = __nccwpck_require__(3685); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const create_release_policy_1 = __nccwpck_require__(76549); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); +const application_error_1 = __nccwpck_require__(75999); async function runCreateRelease(param, taskId, repositoryReleasePort) { const operation = param.operation; const continuationError = (0, deployment_continuation_guard_1.validateDeploymentContinuation)(operation, param.requestedOperationId, ["publishing"], param.requestedVersion); @@ -52371,16 +52371,16 @@ function failureResult(taskId, message, code) { /***/ }), -/***/ 54522: +/***/ 22120: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CreateTagUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const create_tag_workflow_1 = __nccwpck_require__(89893); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const create_tag_workflow_1 = __nccwpck_require__(23539); class CreateTagUseCase { constructor(repositoryReleasePort) { this.repositoryReleasePort = repositoryReleasePort; @@ -52396,17 +52396,17 @@ exports.CreateTagUseCase = CreateTagUseCase; /***/ }), -/***/ 89893: +/***/ 23539: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCreateTag = runCreateTag; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); +const application_error_1 = __nccwpck_require__(75999); async function runCreateTag(param, taskId, repositoryTagPort) { const validationFailure = validateTagInput(param, taskId); if (validationFailure) @@ -52446,14 +52446,14 @@ function noTagResult(taskId, tagName) { /***/ }), -/***/ 40810: +/***/ 28399: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AcceptPromotionHandler = void 0; -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class AcceptPromotionHandler { constructor(runtime) { this.runtime = runtime; @@ -52508,18 +52508,18 @@ function matchesPromotion(operation, pullRequest) { /***/ }), -/***/ 76203: +/***/ 46361: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ConfirmPublicationHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_operation_1 = __nccwpck_require__(10915); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); +const application_error_1 = __nccwpck_require__(75999); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_operation_1 = __nccwpck_require__(92730); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); class ConfirmPublicationHandler { constructor(runtime, reconciliation) { this.runtime = runtime; @@ -52616,17 +52616,17 @@ function requireProductionSha(operation) { /***/ }), -/***/ 24638: +/***/ 85138: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ContinueDeploymentHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_operation_1 = __nccwpck_require__(10915); -const managed_pull_request_1 = __nccwpck_require__(59565); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const application_error_1 = __nccwpck_require__(75999); +const deployment_operation_1 = __nccwpck_require__(92730); +const managed_pull_request_1 = __nccwpck_require__(95914); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class ContinueDeploymentHandler { constructor(runtime, acceptPromotion, reconciliation) { this.runtime = runtime; @@ -52702,17 +52702,17 @@ function assertSameRepository(context, pullRequest) { /***/ }), -/***/ 34630: +/***/ 43877: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PreparePromotionHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_operation_1 = __nccwpck_require__(10915); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const application_error_1 = __nccwpck_require__(75999); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_operation_1 = __nccwpck_require__(92730); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class PreparePromotionHandler { constructor(runtime, acceptPromotion) { this.runtime = runtime; @@ -52869,17 +52869,17 @@ function pendingPromotion(operation, pullRequest) { /***/ }), -/***/ 6091: +/***/ 3344: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReconciliationHandler = void 0; -const deployment_plan_policy_1 = __nccwpck_require__(82273); -const deployment_operation_1 = __nccwpck_require__(10915); -const managed_pull_request_1 = __nccwpck_require__(59565); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const deployment_plan_policy_1 = __nccwpck_require__(8352); +const deployment_operation_1 = __nccwpck_require__(92730); +const managed_pull_request_1 = __nccwpck_require__(95914); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class ReconciliationHandler { constructor(runtime) { this.runtime = runtime; @@ -53041,17 +53041,17 @@ exports.ReconciliationHandler = ReconciliationHandler; /***/ }), -/***/ 47708: +/***/ 66571: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RecordFailureHandler = void 0; -const application_error_1 = __nccwpck_require__(1889); -const result_1 = __nccwpck_require__(99917); -const deployment_operation_1 = __nccwpck_require__(10915); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); +const application_error_1 = __nccwpck_require__(75999); +const result_1 = __nccwpck_require__(73817); +const deployment_operation_1 = __nccwpck_require__(92730); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); class RecordFailureHandler { constructor(runtime) { this.runtime = runtime; @@ -53090,23 +53090,23 @@ function failureCategory(phase) { /***/ }), -/***/ 54934: +/***/ 36850: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeploymentOrchestrationUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const deployment_orchestration_runtime_1 = __nccwpck_require__(38233); -const deployment_state_boundary_1 = __nccwpck_require__(8563); -const result_1 = __nccwpck_require__(99917); -const accept_promotion_handler_1 = __nccwpck_require__(40810); -const confirm_publication_handler_1 = __nccwpck_require__(76203); -const continue_deployment_handler_1 = __nccwpck_require__(24638); -const prepare_promotion_handler_1 = __nccwpck_require__(34630); -const reconciliation_handler_1 = __nccwpck_require__(6091); -const record_failure_handler_1 = __nccwpck_require__(47708); +const application_error_1 = __nccwpck_require__(75999); +const deployment_orchestration_runtime_1 = __nccwpck_require__(77658); +const deployment_state_boundary_1 = __nccwpck_require__(27827); +const result_1 = __nccwpck_require__(73817); +const accept_promotion_handler_1 = __nccwpck_require__(28399); +const confirm_publication_handler_1 = __nccwpck_require__(46361); +const continue_deployment_handler_1 = __nccwpck_require__(85138); +const prepare_promotion_handler_1 = __nccwpck_require__(43877); +const reconciliation_handler_1 = __nccwpck_require__(3344); +const record_failure_handler_1 = __nccwpck_require__(66571); class DeploymentOrchestrationUseCase { constructor(dependencies) { this.taskId = deployment_orchestration_runtime_1.DEPLOYMENT_ORCHESTRATION_TASK_ID; @@ -53163,14 +53163,14 @@ exports.DeploymentOrchestrationUseCase = DeploymentOrchestrationUseCase; /***/ }), -/***/ 86429: +/***/ 38575: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findIssueBranch = findIssueBranch; -const logging_ports_1 = __nccwpck_require__(97793); +const logging_ports_1 = __nccwpck_require__(6152); async function findIssueBranch(param, repository) { if (param.pushedBranch) return param.pushedBranch; @@ -53188,14 +53188,14 @@ async function findIssueBranch(param, repository) { /***/ }), -/***/ 98239: +/***/ 84837: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.InitialSetupUseCase = void 0; -const initial_setup_workflow_1 = __nccwpck_require__(42347); +const initial_setup_workflow_1 = __nccwpck_require__(18079); /** Application boundary for provisioning a repository for Copilot automation. */ class InitialSetupUseCase { constructor(authenticatedUserPort, initialLabelProvisioningPort, issueTypeProvisioningPort, latestTagQueryPort, repositoryDefaultBranchPort, repositoryTagPort, setupWorkspacePort, setupRepositoryVariablesPort, setupRepositorySecretsPort, setupRemoteConfigurationReadPort, progress) { @@ -53233,22 +53233,22 @@ exports.InitialSetupUseCase = InitialSetupUseCase; /***/ }), -/***/ 42347: +/***/ 18079: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runInitialSetupWorkflow = runInitialSetupWorkflow; -const result_1 = __nccwpck_require__(99917); -const version_policy_1 = __nccwpck_require__(36071); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const setup_resource_provisioning_1 = __nccwpck_require__(72108); -const application_error_1 = __nccwpck_require__(1889); -const setup_issue_workflow_policy_1 = __nccwpck_require__(63312); -const setup_issue_resource_policy_1 = __nccwpck_require__(5660); -const setup_configuration_policy_1 = __nccwpck_require__(58409); +const result_1 = __nccwpck_require__(73817); +const version_policy_1 = __nccwpck_require__(8381); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const setup_resource_provisioning_1 = __nccwpck_require__(94894); +const application_error_1 = __nccwpck_require__(75999); +const setup_issue_workflow_policy_1 = __nccwpck_require__(81182); +const setup_issue_resource_policy_1 = __nccwpck_require__(67323); +const setup_configuration_policy_1 = __nccwpck_require__(56637); const TASK_ID = 'InitialSetupUseCase'; /** Runs repository setup as an ordered application workflow with explicit port dependencies. */ async function runInitialSetupWorkflow(request, dependencies) { @@ -53508,7 +53508,7 @@ function variableFailureError(failure) { /***/ }), -/***/ 98322: +/***/ 28121: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53599,22 +53599,22 @@ function projectEvidence(source) { /***/ }), -/***/ 83257: +/***/ 84542: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ObserveBranchSyncUseCase = void 0; -const publication_identity_policy_1 = __nccwpck_require__(17167); -const result_1 = __nccwpck_require__(99917); -const branch_sync_notification_policy_1 = __nccwpck_require__(13754); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const branch_sync_message_catalog_1 = __nccwpck_require__(23142); -const transition_notification_workflow_1 = __nccwpck_require__(59833); -const publication_outcome_policy_1 = __nccwpck_require__(45483); -const application_error_2 = __nccwpck_require__(1889); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const result_1 = __nccwpck_require__(73817); +const branch_sync_notification_policy_1 = __nccwpck_require__(79895); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const branch_sync_message_catalog_1 = __nccwpck_require__(89245); +const transition_notification_workflow_1 = __nccwpck_require__(1725); +const publication_outcome_policy_1 = __nccwpck_require__(79719); +const application_error_2 = __nccwpck_require__(75999); const TASK_ID = "ObserveBranchSyncUseCase"; /** * Cheap push-time observer. It only queries branch relationships/comparisons @@ -53789,27 +53789,27 @@ function failure(message, cause, payload) { /***/ }), -/***/ 41135: +/***/ 88729: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.analyzeProgress = analyzeProgress; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const find_issue_branch_1 = __nccwpck_require__(86429); -const progress_prerequisite_policy_1 = __nccwpck_require__(73684); -const progress_response_1 = __nccwpck_require__(11680); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const summarize_progress_diff_workflow_1 = __nccwpck_require__(47423); -const agent_execution_plan_1 = __nccwpck_require__(52013); -const progress_partition_response_policy_1 = __nccwpck_require__(51545); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const find_issue_branch_1 = __nccwpck_require__(38575); +const progress_prerequisite_policy_1 = __nccwpck_require__(31001); +const progress_response_1 = __nccwpck_require__(64264); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const summarize_progress_diff_workflow_1 = __nccwpck_require__(79582); +const agent_execution_plan_1 = __nccwpck_require__(12253); +const progress_partition_response_policy_1 = __nccwpck_require__(30025); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); /** Loads progress context and asks the configured agent for an assessment. */ async function analyzeProgress(param, taskId, dependencies) { const issueNumber = param.issueNumber; @@ -53905,7 +53905,7 @@ function failure(taskId, message, code) { /***/ }), -/***/ 73684: +/***/ 31001: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -53931,7 +53931,7 @@ function validateProgressPrerequisites(input) { /***/ }), -/***/ 11680: +/***/ 64264: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -53939,8 +53939,8 @@ function validateProgressPrerequisites(input) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PROGRESS_RESPONSE_SCHEMA = void 0; exports.parseProgressResponse = parseProgressResponse; -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const application_error_1 = __nccwpck_require__(1889); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const application_error_1 = __nccwpck_require__(75999); exports.PROGRESS_RESPONSE_SCHEMA = { type: 'object', properties: { @@ -53970,7 +53970,7 @@ function parseProgressResponse(response, targetLocale) { /***/ }), -/***/ 42351: +/***/ 62721: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -54002,16 +54002,16 @@ function buildProgressSummaryMessage({ summary, progress, remaining, reasoning } /***/ }), -/***/ 56702: +/***/ 68891: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PublishGithubActionUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const publish_github_action_workflow_1 = __nccwpck_require__(22075); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const publish_github_action_workflow_1 = __nccwpck_require__(63037); class PublishGithubActionUseCase { constructor(repositoryTagPort, repositoryReleasePort) { this.repositoryTagPort = repositoryTagPort; @@ -54028,18 +54028,18 @@ exports.PublishGithubActionUseCase = PublishGithubActionUseCase; /***/ }), -/***/ 22075: +/***/ 63037: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPublishGithubAction = runPublishGithubAction; -const result_1 = __nccwpck_require__(99917); -const input_keys_1 = __nccwpck_require__(27112); -const logging_ports_1 = __nccwpck_require__(97793); -const deployment_continuation_guard_1 = __nccwpck_require__(17521); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const input_keys_1 = __nccwpck_require__(88539); +const logging_ports_1 = __nccwpck_require__(6152); +const deployment_continuation_guard_1 = __nccwpck_require__(1779); +const application_error_1 = __nccwpck_require__(75999); async function runPublishGithubAction(param, taskId, repositoryTagPort, repositoryReleasePort) { const validationFailure = validateVersion(param, taskId); if (validationFailure) @@ -54084,16 +54084,16 @@ function failureResult(taskId, sourceTag, targetTag) { /***/ }), -/***/ 10562: +/***/ 61313: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PublishIssueCommentUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const publish_issue_comment_workflow_1 = __nccwpck_require__(84095); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const publish_issue_comment_workflow_1 = __nccwpck_require__(30626); /** Application boundary for creating or updating a specific issue comment. */ class PublishIssueCommentUseCase { constructor(issueCommentPort) { @@ -54110,16 +54110,16 @@ exports.PublishIssueCommentUseCase = PublishIssueCommentUseCase; /***/ }), -/***/ 84095: +/***/ 30626: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPublishIssueComment = runPublishIssueComment; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); async function runPublishIssueComment(param, taskId, issueCommentPort) { if (param.kind === 'invalid') { return [new result_1.Result({ @@ -54168,7 +54168,7 @@ function appendCommentContent(previous, addition) { /***/ }), -/***/ 23139: +/***/ 65928: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -54176,12 +54176,12 @@ function appendCommentContent(previous, addition) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildRecommendationResult = buildRecommendationResult; exports.extractImplementationPlan = extractImplementationPlan; -const result_1 = __nccwpck_require__(99917); -const recommendation_policy_1 = __nccwpck_require__(33990); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const implementation_plan_1 = __nccwpck_require__(8768); +const result_1 = __nccwpck_require__(73817); +const recommendation_policy_1 = __nccwpck_require__(39410); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const implementation_plan_1 = __nccwpck_require__(77001); function buildRecommendationResult(param, taskId, response, issueDescriptionFingerprint, previousRecommendation, issueNumber) { const extracted = extractImplementationPlan(response, param.targetLocale); if (!extracted) { @@ -54268,14 +54268,14 @@ function hasOnlyResponseKeys(payload) { /***/ }), -/***/ 32484: +/***/ 73746: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RecommendStepsUseCase = void 0; -const recommend_steps_workflow_1 = __nccwpck_require__(3298); +const recommend_steps_workflow_1 = __nccwpck_require__(77522); /** Application boundary for generating non-duplicated implementation guidance. */ class RecommendStepsUseCase { constructor(issueDescriptionQueryPort, aiRepository) { @@ -54295,7 +54295,7 @@ exports.RecommendStepsUseCase = RecommendStepsUseCase; /***/ }), -/***/ 3298: +/***/ 77522: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -54303,19 +54303,19 @@ exports.RecommendStepsUseCase = RecommendStepsUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runRecommendStepsWorkflow = runRecommendStepsWorkflow; exports.queryImplementationPlan = queryImplementationPlan; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const recommendation_policy_1 = __nccwpck_require__(33990); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const project_context_instruction_1 = __nccwpck_require__(55527); -const task_emoji_1 = __nccwpck_require__(8353); -const recommend_steps_result_policy_1 = __nccwpck_require__(23139); -const application_error_1 = __nccwpck_require__(1889); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const implementation_plan_1 = __nccwpck_require__(8768); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const recommendation_policy_1 = __nccwpck_require__(39410); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const project_context_instruction_1 = __nccwpck_require__(63907); +const task_emoji_1 = __nccwpck_require__(46103); +const recommend_steps_result_policy_1 = __nccwpck_require__(65928); +const application_error_1 = __nccwpck_require__(75999); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const implementation_plan_1 = __nccwpck_require__(77001); /** Runs the recommendation policy and agent interaction for an issue. */ async function runRecommendStepsWorkflow(param, taskId, dependencies) { (0, logging_ports_1.logInfo)(`${(0, task_emoji_1.getTaskEmoji)(taskId)} Executing ${taskId}.`); @@ -54413,17 +54413,17 @@ function failure(taskId, message, code) { /***/ }), -/***/ 30842: +/***/ 49050: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReconcileClosedIssueMetadataUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const reconcile_issue_completion_metadata_1 = __nccwpck_require__(73082); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const reconcile_issue_completion_metadata_1 = __nccwpck_require__(70614); /** Selective completion repair from fresh native facts; no native state authority. */ class ReconcileClosedIssueMetadataUseCase { constructor(issues) { @@ -54458,7 +54458,7 @@ function stale() { /***/ }), -/***/ 35318: +/***/ 11687: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -54481,7 +54481,7 @@ exports.ReconcileClosedIssueUseCase = ReconcileClosedIssueUseCase; /***/ }), -/***/ 73082: +/***/ 70614: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -54489,9 +54489,9 @@ exports.ReconcileClosedIssueUseCase = ReconcileClosedIssueUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.completionRepairProgress = void 0; exports.reconcileIssueCompletionMetadata = reconcileIssueCompletionMetadata; -const application_error_1 = __nccwpck_require__(1889); -const issue_completion_1 = __nccwpck_require__(28272); -const closed_issue_reconciliation_1 = __nccwpck_require__(31012); +const application_error_1 = __nccwpck_require__(75999); +const issue_completion_1 = __nccwpck_require__(31147); +const closed_issue_reconciliation_1 = __nccwpck_require__(21565); const completionRepairProgress = () => ({ nativeClosed: false, labelsChanged: 0, phase: 'identity', state: 'unavailable', reason: 'unavailable', remaining: 0 }); exports.completionRepairProgress = completionRepairProgress; @@ -54559,22 +54559,22 @@ async function reconcileIssueCompletionMetadata(target, number, configuration, p /***/ }), -/***/ 77535: +/***/ 74111: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RetireBranchSyncUseCase = void 0; -const verify_closed_issue_card_retirement_1 = __nccwpck_require__(68606); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const closed_issue_reconciliation_1 = __nccwpck_require__(31012); -const result_1 = __nccwpck_require__(99917); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const branch_sync_notification_policy_1 = __nccwpck_require__(13754); -const branch_sync_message_catalog_1 = __nccwpck_require__(23142); -const application_error_1 = __nccwpck_require__(1889); +const verify_closed_issue_card_retirement_1 = __nccwpck_require__(78813); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const closed_issue_reconciliation_1 = __nccwpck_require__(21565); +const result_1 = __nccwpck_require__(73817); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const branch_sync_notification_policy_1 = __nccwpck_require__(79895); +const branch_sync_message_catalog_1 = __nccwpck_require__(89245); +const application_error_1 = __nccwpck_require__(75999); /** Retire existing owned status cards only; no create/delete, labels, Git or agent authority. */ class RetireBranchSyncUseCase { constructor(issues, comments, cardFreshness) { @@ -54665,7 +54665,7 @@ function stale() { /***/ }), -/***/ 50831: +/***/ 11529: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -54688,21 +54688,21 @@ exports.RetireClosedIssueCardsUseCase = RetireClosedIssueCardsUseCase; /***/ }), -/***/ 7427: +/***/ 17025: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RetireProgressUseCase = void 0; -const verify_closed_issue_card_retirement_1 = __nccwpck_require__(68606); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const closed_issue_reconciliation_1 = __nccwpck_require__(31012); -const result_1 = __nccwpck_require__(99917); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const retired_progress_presentation_policy_1 = __nccwpck_require__(96361); -const application_error_1 = __nccwpck_require__(1889); +const verify_closed_issue_card_retirement_1 = __nccwpck_require__(78813); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const closed_issue_reconciliation_1 = __nccwpck_require__(21565); +const result_1 = __nccwpck_require__(73817); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const retired_progress_presentation_policy_1 = __nccwpck_require__(93427); +const application_error_1 = __nccwpck_require__(75999); /** Retire existing owned status cards only; no create/delete, labels, Git or agent authority. */ class RetireProgressUseCase { constructor(issues, comments, cardFreshness) { @@ -54791,7 +54791,7 @@ function stale() { /***/ }), -/***/ 72108: +/***/ 94894: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -54802,12 +54802,12 @@ exports.ensureRepositoryVariables = ensureRepositoryVariables; exports.ensureRepositorySecrets = ensureRepositorySecrets; exports.resolveRemoteConfiguration = resolveRemoteConfiguration; exports.groupSetupResources = groupSetupResources; -const setup_remote_facts_policy_1 = __nccwpck_require__(49505); -const setup_runner_policy_1 = __nccwpck_require__(70801); -const setup_configuration_policy_1 = __nccwpck_require__(58409); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(20994); +const setup_remote_facts_policy_1 = __nccwpck_require__(92567); +const setup_runner_policy_1 = __nccwpck_require__(91027); +const setup_configuration_policy_1 = __nccwpck_require__(56637); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const setup_organization_variable_reuse_policy_1 = __nccwpck_require__(63882); exports.VARIABLE_PROVISIONING_UNAVAILABLE = 'GitHub Actions Variable provisioning is unavailable; no Variables were changed.'; exports.SECRET_PROVISIONING_UNAVAILABLE = 'GitHub Actions Secret provisioning is unavailable; no Secrets were changed.'; async function ensureRepositoryVariables(context, dependencies, setupConfiguration, remoteConfiguration) { @@ -55040,19 +55040,19 @@ async function upsertSecretGroups(context, port, groups) { /***/ }), -/***/ 47423: +/***/ 79582: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.summarizeProgressDiff = summarizeProgressDiff; -const agent_task_policy_1 = __nccwpck_require__(34816); -const progress_partition_response_policy_1 = __nccwpck_require__(51545); -const agent_execution_plan_1 = __nccwpck_require__(52013); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const logging_ports_1 = __nccwpck_require__(97793); +const agent_task_policy_1 = __nccwpck_require__(85712); +const progress_partition_response_policy_1 = __nccwpck_require__(30025); +const agent_execution_plan_1 = __nccwpck_require__(12253); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const logging_ports_1 = __nccwpck_require__(6152); /** Collects every part before exposing one aggregate to the final assessment. No mutation capability. */ async function summarizeProgressDiff(diff, context, issueDescription, agent, aggregateBudget) { if (diff.kind !== 'partitioned') @@ -55084,15 +55084,15 @@ immutableComparison: ${partition.evidence}`); /***/ }), -/***/ 55198: +/***/ 18277: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.syncProgressLabelsToOpenPullRequests = syncProgressLabelsToOpenPullRequests; -const progress_labels_1 = __nccwpck_require__(11696); -const logging_ports_1 = __nccwpck_require__(97793); +const progress_labels_1 = __nccwpck_require__(97890); +const logging_ports_1 = __nccwpck_require__(6152); async function syncProgressLabelsToOpenPullRequests(branch, progress, issueRepository, pullRequestRepository) { const roundedProgress = Math.min(100, Math.max(0, Math.round(progress / 5) * 5)); const newProgressLabel = `${roundedProgress}%`; @@ -55111,16 +55111,16 @@ async function syncProgressLabelsToOpenPullRequests(branch, progress, issueRepos /***/ }), -/***/ 64084: +/***/ 44880: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SynchronizeAgentActivityUseCase = void 0; -const agent_activity_label_policy_1 = __nccwpck_require__(69965); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const agent_activity_label_policy_1 = __nccwpck_require__(79966); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); /** * Maintains the temporary agent-activity label around a complete route. * Cleanup is deliberately best-effort so a label outage never hides the @@ -55173,20 +55173,20 @@ function sameLabels(left, right) { /***/ }), -/***/ 60832: +/***/ 18032: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SynchronizeLifecycleStateUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const lifecycle_state_policy_1 = __nccwpck_require__(35045); -const lifecycle_waiting_state_policy_1 = __nccwpck_require__(17042); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const lifecycle_synchronization_context_1 = __nccwpck_require__(98322); +const result_1 = __nccwpck_require__(73817); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const lifecycle_state_policy_1 = __nccwpck_require__(34026); +const lifecycle_waiting_state_policy_1 = __nccwpck_require__(61736); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const lifecycle_synchronization_context_1 = __nccwpck_require__(28121); /** Reconciles one state label from immutable facts and bound provider authority. */ class SynchronizeLifecycleStateUseCase { constructor(issueLabelsPort, pullRequestHeadShaPort) { @@ -55305,15 +55305,15 @@ function sameLabels(left, right) { /***/ }), -/***/ 68606: +/***/ 78813: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.verifyClosedIssueCardRetirement = verifyClosedIssueCardRetirement; -const reply_request_digest_1 = __nccwpck_require__(73250); -const application_error_1 = __nccwpck_require__(1889); +const reply_request_digest_1 = __nccwpck_require__(47971); +const application_error_1 = __nccwpck_require__(75999); /** Adopt another invocation only after the exact final owned body and native closure are fresh. */ async function verifyClosedIssueCardRetirement(input) { const witness = (body) => Object.freeze({ surface: 'issue-comment', @@ -55347,16 +55347,16 @@ async function verifyClosedIssueCardRetirement(input) { /***/ }), -/***/ 68375: +/***/ 4643: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runBranchSyncCommand = runBranchSyncCommand; -const result_1 = __nccwpck_require__(99917); -const branch_sync_command_1 = __nccwpck_require__(48721); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const branch_sync_command_1 = __nccwpck_require__(51114); +const application_error_1 = __nccwpck_require__(75999); /** Authorizes and runs an explicit or natural-language branch synchronization request. */ async function runBranchSyncCommand(context, options, args, authorization) { const parsed = (0, branch_sync_command_1.parseBranchSyncCommandArguments)(args); @@ -55392,7 +55392,7 @@ function unauthorized(taskId) { /***/ }), -/***/ 43913: +/***/ 82113: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -55403,10 +55403,10 @@ exports.branchSyncConflictEligibilityFailure = branchSyncConflictEligibilityFail exports.completedBranchSyncResult = completedBranchSyncResult; exports.unavailableBranchSyncResult = unavailableBranchSyncResult; exports.failedBranchSyncResult = failedBranchSyncResult; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const workspace_changes_1 = __nccwpck_require__(33363); -const application_error_1 = __nccwpck_require__(1889); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const workspace_changes_1 = __nccwpck_require__(93370); +const application_error_1 = __nccwpck_require__(75999); exports.BRANCH_SYNC_TASK_ID = "SyncBranchUseCase"; const MAX_AGENT_CONFLICT_PATHS = 20; function branchSyncConflictEligibilityFailure(preparation, useAgent, agentConfiguration) { @@ -55474,19 +55474,19 @@ function failedBranchSyncResult(reason, cause, recovery) { /***/ }), -/***/ 97905: +/***/ 392: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SyncBranchUseCase = void 0; -const branch_sync_validation_1 = __nccwpck_require__(70155); -const branch_sync_conflicts_1 = __nccwpck_require__(49328); -const logging_ports_1 = __nccwpck_require__(97793); -const verify_command_policy_1 = __nccwpck_require__(23322); -const verify_command_runner_1 = __nccwpck_require__(50827); -const branch_sync_execution_policy_1 = __nccwpck_require__(43913); +const branch_sync_validation_1 = __nccwpck_require__(90981); +const branch_sync_conflicts_1 = __nccwpck_require__(84434); +const logging_ports_1 = __nccwpck_require__(6152); +const verify_command_policy_1 = __nccwpck_require__(96031); +const verify_command_runner_1 = __nccwpck_require__(57742); +const branch_sync_execution_policy_1 = __nccwpck_require__(82113); /** Performs a race-safe parent-to-child merge and invokes the fixer only for eligible conflicts. */ class SyncBranchUseCase { constructor(dependencies, workspace, fixer, authenticatedUser, git) { @@ -55619,20 +55619,20 @@ function validationRecovery(code) { /***/ }), -/***/ 29908: +/***/ 42442: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommentAutomationAction = runCommentAutomationAction; -const result_1 = __nccwpck_require__(99917); -const implementation_result_policy_1 = __nccwpck_require__(39606); -const commit_autofix_and_resolve_workflow_1 = __nccwpck_require__(98022); -const commit_user_request_workflow_1 = __nccwpck_require__(41729); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const comment_mutation_target_workflow_1 = __nccwpck_require__(63049); +const result_1 = __nccwpck_require__(73817); +const implementation_result_policy_1 = __nccwpck_require__(30203); +const commit_autofix_and_resolve_workflow_1 = __nccwpck_require__(93455); +const commit_user_request_workflow_1 = __nccwpck_require__(43393); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const comment_mutation_target_workflow_1 = __nccwpck_require__(81324); /** Runs the selected mutating action and returns any result records it produces. */ async function runCommentAutomationAction(param, options, route, intentPayload) { if (route === "review") @@ -55763,7 +55763,7 @@ async function runDoUserRequestAction(param, options, intentPayload) { /***/ }), -/***/ 39723: +/***/ 63134: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -55771,20 +55771,20 @@ async function runDoUserRequestAction(param, options, intentPayload) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runExplicitCommentCommand = runExplicitCommentCommand; exports.invalidCommentCommandResult = invalidCommentCommandResult; -const sdd_diff_presentation_policy_1 = __nccwpck_require__(11594); -const sdd_diff_message_catalog_1 = __nccwpck_require__(29948); -const read_copilot_doctor_workflow_1 = __nccwpck_require__(97584); -const read_copilot_history_workflow_1 = __nccwpck_require__(11603); -const result_1 = __nccwpck_require__(99917); -const read_copilot_status_workflow_1 = __nccwpck_require__(28724); -const copilot_interaction_policy_1 = __nccwpck_require__(52113); -const review_command_1 = __nccwpck_require__(93789); -const commit_user_request_workflow_1 = __nccwpck_require__(41729); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const branch_sync_comment_command_1 = __nccwpck_require__(68375); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const comment_mutation_target_workflow_1 = __nccwpck_require__(63049); +const sdd_diff_presentation_policy_1 = __nccwpck_require__(63302); +const sdd_diff_message_catalog_1 = __nccwpck_require__(2230); +const read_copilot_doctor_workflow_1 = __nccwpck_require__(12416); +const read_copilot_history_workflow_1 = __nccwpck_require__(8140); +const result_1 = __nccwpck_require__(73817); +const read_copilot_status_workflow_1 = __nccwpck_require__(57206); +const copilot_interaction_policy_1 = __nccwpck_require__(90108); +const review_command_1 = __nccwpck_require__(1811); +const commit_user_request_workflow_1 = __nccwpck_require__(43393); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const branch_sync_comment_command_1 = __nccwpck_require__(4643); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const comment_mutation_target_workflow_1 = __nccwpck_require__(81324); const LEARNED_BUGBOT_RULE_PATH = '.copilot/BUGBOT.learned.md'; /** Executes deterministic /copilot commands without routing them through intent detection. */ async function runExplicitCommentCommand(param, options, command, actorAuthorizationPort) { @@ -55986,16 +55986,16 @@ function invalidCommentCommandResult(taskId, reason) { /***/ }), -/***/ 10261: +/***/ 46187: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.completeCommentAutomation = completeCommentAutomation; -const bugbot_fix_intent_payload_1 = __nccwpck_require__(90862); -const logging_ports_1 = __nccwpck_require__(97793); -const comment_automation_action_workflow_1 = __nccwpck_require__(29908); +const bugbot_fix_intent_payload_1 = __nccwpck_require__(25734); +const logging_ports_1 = __nccwpck_require__(6152); +const comment_automation_action_workflow_1 = __nccwpck_require__(42442); async function completeCommentAutomation(param, options, decision) { logUnauthorizedActionSkip(decision); if (decision.route === 'think') { @@ -56015,7 +56015,7 @@ function logUnauthorizedActionSkip(decision) { /***/ }), -/***/ 90059: +/***/ 37055: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -56023,15 +56023,15 @@ function logUnauthorizedActionSkip(decision) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectCommentAutomationContext = projectCommentAutomationContext; exports.withCommentLanguageAdaptation = withCommentLanguageAdaptation; -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const status_command_policy_1 = __nccwpck_require__(33849); -const comment_language_translation_workflow_1 = __nccwpck_require__(59013); -const think_workflow_1 = __nccwpck_require__(84106); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const push_single_action_contexts_1 = __nccwpck_require__(68843); -const think_request_policy_1 = __nccwpck_require__(9106); -const think_input_policy_1 = __nccwpck_require__(84440); -const copilot_command_1 = __nccwpck_require__(28057); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const status_command_policy_1 = __nccwpck_require__(3449); +const comment_language_translation_workflow_1 = __nccwpck_require__(72770); +const think_workflow_1 = __nccwpck_require__(36450); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const push_single_action_contexts_1 = __nccwpck_require__(47841); +const think_request_policy_1 = __nccwpck_require__(23995); +const think_input_policy_1 = __nccwpck_require__(59687); +const copilot_command_1 = __nccwpck_require__(11771); function projectCommentAutomationContext(source, language, userComment) { const review = (0, bugbot_review_operation_context_1.projectBugbotReviewOperationContext)(source); return Object.freeze({ @@ -56152,18 +56152,18 @@ function projectSddDiffRequest(source) { /***/ }), -/***/ 19742: +/***/ 46175: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveCommentAutomationDecision = resolveCommentAutomationDecision; -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_fix_intent_payload_1 = __nccwpck_require__(90862); -const comment_automation_route_policy_1 = __nccwpck_require__(22503); -const copilot_comment_request_1 = __nccwpck_require__(16602); -const copilot_command_1 = __nccwpck_require__(28057); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_fix_intent_payload_1 = __nccwpck_require__(25734); +const comment_automation_route_policy_1 = __nccwpck_require__(47058); +const copilot_comment_request_1 = __nccwpck_require__(86819); +const copilot_command_1 = __nccwpck_require__(11771); async function resolveCommentAutomationDecision(param, options, actorAuthorizationPort) { (0, logging_ports_1.logInfo)("Running bugbot fix intent detection (before Think)."); const intentResults = await options.intentUseCase.invoke(param.bugbot.fixIntent); @@ -56192,15 +56192,15 @@ function logIntent(intentPayload) { /***/ }), -/***/ 83353: +/***/ 10554: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runNaturalLanguageCommentAutomation = runNaturalLanguageCommentAutomation; -const comment_automation_decision_workflow_1 = __nccwpck_require__(19742); -const comment_automation_completion_workflow_1 = __nccwpck_require__(10261); +const comment_automation_decision_workflow_1 = __nccwpck_require__(46175); +const comment_automation_completion_workflow_1 = __nccwpck_require__(46187); /** Runs the natural-language comment pipeline after deterministic commands are excluded. */ async function runNaturalLanguageCommentAutomation(param, options, actorAuthorizationPort, languageResults) { const decision = await (0, comment_automation_decision_workflow_1.resolveCommentAutomationDecision)(param, options, actorAuthorizationPort); @@ -56214,14 +56214,14 @@ async function runNaturalLanguageCommentAutomation(param, options, actorAuthoriz /***/ }), -/***/ 22503: +/***/ 47058: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveCommentAutomationRoute = resolveCommentAutomationRoute; -const bugbot_fix_intent_payload_1 = __nccwpck_require__(90862); +const bugbot_fix_intent_payload_1 = __nccwpck_require__(25734); function resolveCommentAutomationRoute(payload, allowedToModifyFiles, botMentioned = false, explicitMutationCommand = false) { if (!botMentioned && !explicitMutationCommand) return 'think'; @@ -56239,24 +56239,24 @@ function resolveCommentAutomationRoute(payload, allowedToModifyFiles, botMention /***/ }), -/***/ 29792: +/***/ 9661: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommentAutomation = runCommentAutomation; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const copilot_comment_request_1 = __nccwpck_require__(16602); -const copilot_command_1 = __nccwpck_require__(28057); -const comment_automation_command_workflow_1 = __nccwpck_require__(39723); -const comment_automation_natural_language_workflow_1 = __nccwpck_require__(83353); -const application_error_1 = __nccwpck_require__(1889); -const branch_sync_command_1 = __nccwpck_require__(48721); -const branch_sync_comment_command_1 = __nccwpck_require__(68375); -const comment_automation_context_1 = __nccwpck_require__(90059); -const comment_language_translation_workflow_1 = __nccwpck_require__(59013); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const copilot_comment_request_1 = __nccwpck_require__(86819); +const copilot_command_1 = __nccwpck_require__(11771); +const comment_automation_command_workflow_1 = __nccwpck_require__(63134); +const comment_automation_natural_language_workflow_1 = __nccwpck_require__(10554); +const application_error_1 = __nccwpck_require__(75999); +const branch_sync_command_1 = __nccwpck_require__(51114); +const branch_sync_comment_command_1 = __nccwpck_require__(4643); +const comment_automation_context_1 = __nccwpck_require__(37055); +const comment_language_translation_workflow_1 = __nccwpck_require__(72770); async function runCommentAutomation(initialParam, options, actorAuthorizationPort) { (0, logging_ports_1.logInfo)(`${options.taskId} started.`); let languageResults = []; @@ -56325,17 +56325,17 @@ async function runCommentAutomation(initialParam, options, actorAuthorizationPor /***/ }), -/***/ 63049: +/***/ 81324: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveCommentMutationBranch = resolveCommentMutationBranch; -const application_error_1 = __nccwpck_require__(1889); -const git_object_id_1 = __nccwpck_require__(65534); -const context_1 = __nccwpck_require__(8442); -const bugbot_context_request_1 = __nccwpck_require__(29868); +const application_error_1 = __nccwpck_require__(75999); +const git_object_id_1 = __nccwpck_require__(88623); +const context_1 = __nccwpck_require__(14712); +const bugbot_context_request_1 = __nccwpck_require__(98299); async function resolveCommentMutationBranch(param, options) { const operation = param.bugbot.fixIntent; if (!operation.target.isPullRequest) { @@ -56373,19 +56373,19 @@ async function resolveCommentMutationBranch(param, options) { /***/ }), -/***/ 58699: +/***/ 28001: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CommitUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const push_single_action_contexts_1 = __nccwpck_require__(68843); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const push_single_action_contexts_1 = __nccwpck_require__(47841); class CommitUseCase { constructor(notifyNewCommitUseCase, checkChangesIssueSizeUseCase, detectPotentialProblemsUseCase, checkProgressUseCase, actorAuthorizationPort) { this.notifyNewCommitUseCase = notifyNewCommitUseCase; @@ -56439,18 +56439,18 @@ exports.CommitUseCase = CommitUseCase; /***/ }), -/***/ 20038: +/***/ 71813: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ExecutionBranchVersionResolver = void 0; -const result_1 = __nccwpck_require__(99917); -const version_resolution_application_policy_1 = __nccwpck_require__(84631); -const version_resolution_outcome_policy_1 = __nccwpck_require__(48002); -const version_resolution_result_policy_1 = __nccwpck_require__(31533); -const version_resolution_policy_1 = __nccwpck_require__(87882); +const result_1 = __nccwpck_require__(73817); +const version_resolution_application_policy_1 = __nccwpck_require__(40231); +const version_resolution_outcome_policy_1 = __nccwpck_require__(43496); +const version_resolution_result_policy_1 = __nccwpck_require__(11730); +const version_resolution_policy_1 = __nccwpck_require__(92373); class ExecutionBranchVersionResolver { constructor(latestTagQueryPort, getReleaseVersion, getReleaseType, getHotfixVersion) { this.latestTagQueryPort = latestTagQueryPort; @@ -56548,7 +56548,7 @@ function unchanged(context) { /***/ }), -/***/ 84443: +/***/ 63436: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -56556,9 +56556,9 @@ function unchanged(context) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveEventIssueNumber = resolveEventIssueNumber; exports.resolveSingleActionIssueNumber = resolveSingleActionIssueNumber; -const positive_integer_policy_1 = __nccwpck_require__(20889); -const action_types_1 = __nccwpck_require__(78468); -const title_utils_1 = __nccwpck_require__(36183); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const action_types_1 = __nccwpck_require__(19625); +const title_utils_1 = __nccwpck_require__(46267); function resolveEventIssueNumber(context) { let issueNumber; if (context.isIssue) @@ -56657,14 +56657,14 @@ function currentSingleAction(context) { /***/ }), -/***/ 30220: +/***/ 90972: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveExecutionIssueNumber = resolveExecutionIssueNumber; -const execution_issue_number_policy_1 = __nccwpck_require__(84443); +const execution_issue_number_policy_1 = __nccwpck_require__(63436); async function resolveExecutionIssueNumber(context, issueRepository) { if (!context.isSingleAction && context.isPullRequest && ['issue_comment', 'pull_request_review_comment'].includes(context.eventName) @@ -56685,15 +56685,15 @@ async function resolveExecutionIssueNumber(context, issueRepository) { /***/ }), -/***/ 73547: +/***/ 3599: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ResolveGithubExecutionAdmissionUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const github_execution_admission_policy_1 = __nccwpck_require__(50196); +const application_error_1 = __nccwpck_require__(75999); +const github_execution_admission_policy_1 = __nccwpck_require__(80765); class ResolveGithubExecutionAdmissionUseCase { constructor(authenticatedUserPort) { this.authenticatedUserPort = authenticatedUserPort; @@ -56720,14 +56720,14 @@ exports.ResolveGithubExecutionAdmissionUseCase = ResolveGithubExecutionAdmission /***/ }), -/***/ 20380: +/***/ 88512: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupExecutionUseCase = void 0; -const setup_execution_workflow_1 = __nccwpck_require__(21595); +const setup_execution_workflow_1 = __nccwpck_require__(42285); class SetupExecutionUseCase { constructor(issueSetupPort, organizationSetupPort, configurationPort, branchVersionResolver) { this.issueSetupPort = issueSetupPort; @@ -56750,19 +56750,19 @@ exports.SetupExecutionUseCase = SetupExecutionUseCase; /***/ }), -/***/ 21595: +/***/ 42285: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runSetupExecution = runSetupExecution; -const application_error_1 = __nccwpck_require__(1889); -const action_types_1 = __nccwpck_require__(78468); -const previous_branch_state_policy_1 = __nccwpck_require__(890); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const logging_ports_1 = __nccwpck_require__(97793); -const resolve_execution_issue_number_1 = __nccwpck_require__(30220); +const application_error_1 = __nccwpck_require__(75999); +const action_types_1 = __nccwpck_require__(19625); +const previous_branch_state_policy_1 = __nccwpck_require__(43630); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const logging_ports_1 = __nccwpck_require__(6152); +const resolve_execution_issue_number_1 = __nccwpck_require__(90972); async function runSetupExecution(context, dependencies) { (0, logging_ports_1.setGlobalLoggerDebug)(context.debug, context.local); const tokenUser = await loadTokenUser(context, dependencies.organizationSetupPort); @@ -56930,22 +56930,22 @@ function positiveIssueNumberOrUndefined(value) { /***/ }), -/***/ 96349: +/***/ 72042: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueCommentUseCase = void 0; -const comment_automation_command_workflow_1 = __nccwpck_require__(39723); -const read_copilot_history_workflow_1 = __nccwpck_require__(11603); -const result_1 = __nccwpck_require__(99917); -const comment_automation_use_case_1 = __nccwpck_require__(29792); -const check_issue_comment_language_use_case_1 = __nccwpck_require__(55111); -const comment_automation_context_1 = __nccwpck_require__(90059); -const pull_request_workflow_context_1 = __nccwpck_require__(12372); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const copilot_command_1 = __nccwpck_require__(28057); +const comment_automation_command_workflow_1 = __nccwpck_require__(63134); +const read_copilot_history_workflow_1 = __nccwpck_require__(8140); +const result_1 = __nccwpck_require__(73817); +const comment_automation_use_case_1 = __nccwpck_require__(9661); +const check_issue_comment_language_use_case_1 = __nccwpck_require__(93152); +const comment_automation_context_1 = __nccwpck_require__(37055); +const pull_request_workflow_context_1 = __nccwpck_require__(73447); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const copilot_command_1 = __nccwpck_require__(11771); class IssueCommentUseCase { constructor(languageUseCase, intentUseCase, thinkUseCase, autofixUseCase, doUserRequestUseCase, actorAuthorizationPort, bugbotGitMutationPort, dismissBugbotFindingsUseCase, reviewPotentialProblemsUseCase, updatePullRequestDescriptionUseCase, rememberBugbotRuleUseCase, syncBranchUseCase, preBranchSddContinuation, rememberBranchPorts, statusReadPorts, historyReadPort, sddQueryPort, sddDiffQueryPort, nativeStatusReadPort, doctorReadPorts) { this.languageUseCase = languageUseCase; @@ -57034,24 +57034,24 @@ exports.IssueCommentUseCase = IssueCommentUseCase; /***/ }), -/***/ 12: +/***/ 65281: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const issue_workflow_1 = __nccwpck_require__(99026); -const check_permissions_workflow_1 = __nccwpck_require__(61273); -const update_title_workflow_1 = __nccwpck_require__(12039); -const project_content_link_workflow_1 = __nccwpck_require__(63457); -const issue_workflow_context_1 = __nccwpck_require__(85450); -const push_single_action_contexts_1 = __nccwpck_require__(68843); -const issue_start_policy_1 = __nccwpck_require__(59704); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const issue_workflow_1 = __nccwpck_require__(661); +const check_permissions_workflow_1 = __nccwpck_require__(17102); +const update_title_workflow_1 = __nccwpck_require__(50029); +const project_content_link_workflow_1 = __nccwpck_require__(89064); +const issue_workflow_context_1 = __nccwpck_require__(98005); +const push_single_action_contexts_1 = __nccwpck_require__(47841); +const issue_start_policy_1 = __nccwpck_require__(90332); class IssueUseCase { constructor(recommendStepsUseCase, answerIssueHelpUseCase, workflowSteps, issueCommentQueryPort, actorAuthorizationPort, preBranchSddGate) { this.recommendStepsUseCase = recommendStepsUseCase; @@ -57199,18 +57199,18 @@ function applyBranchConfigurationPatch(param, patch) { /***/ }), -/***/ 99026: +/***/ 661: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runIssueWorkflow = runIssueWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const copilot_interaction_policy_1 = __nccwpck_require__(52113); -const semantic_result_publication_policy_1 = __nccwpck_require__(78334); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const copilot_interaction_policy_1 = __nccwpck_require__(90108); +const semantic_result_publication_policy_1 = __nccwpck_require__(81985); +const application_error_1 = __nccwpck_require__(75999); /** Coordinates issue lifecycle steps in their required sequential order. */ async function runIssueWorkflow(context, taskId, ports) { const results = []; @@ -57372,7 +57372,7 @@ function issueWorkflowOutcome(results, branchConfigurationPatch, recommendationS /***/ }), -/***/ 85450: +/***/ 98005: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -57382,7 +57382,7 @@ exports.branchPreparationOutcome = branchPreparationOutcome; exports.projectIssueWorkflowStepContexts = projectIssueWorkflowStepContexts; exports.projectAssignmentContext = projectAssignmentContext; exports.copyProjects = copyProjects; -const issue_start_policy_1 = __nccwpck_require__(59704); +const issue_start_policy_1 = __nccwpck_require__(90332); function branchPreparationOutcome(results, configurationPatch = {}) { return Object.freeze({ results: Object.freeze([...results]), @@ -57536,7 +57536,7 @@ function selectIssueType(source) { /***/ }), -/***/ 5869: +/***/ 99961: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -57544,11 +57544,11 @@ function selectIssueType(source) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ResolveMessageCatalogUseCase = void 0; exports.buildCatalogResponseSchema = buildCatalogResponseSchema; -const agent_task_policy_1 = __nccwpck_require__(34816); -const message_catalog_1 = __nccwpck_require__(69292); -const locale_1 = __nccwpck_require__(52028); -const localize_message_catalog_1 = __nccwpck_require__(64868); -const logging_ports_1 = __nccwpck_require__(97793); +const agent_task_policy_1 = __nccwpck_require__(85712); +const message_catalog_1 = __nccwpck_require__(27097); +const locale_1 = __nccwpck_require__(15386); +const localize_message_catalog_1 = __nccwpck_require__(64005); +const logging_ports_1 = __nccwpck_require__(6152); class ResolveMessageCatalogUseCase { constructor(language) { this.language = language; @@ -57682,17 +57682,17 @@ function buildCatalogResponseSchema(source, ids, targetLocale = 'en-US') { /***/ }), -/***/ 26771: +/***/ 36169: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ObservePullRequestApprovalUseCase = void 0; -const application_error_1 = __nccwpck_require__(1889); -const approval_evidence_error_1 = __nccwpck_require__(55528); -const pull_request_approval_1 = __nccwpck_require__(96191); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); +const application_error_1 = __nccwpck_require__(75999); +const approval_evidence_error_1 = __nccwpck_require__(50519); +const pull_request_approval_1 = __nccwpck_require__(8024); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); /** Read-first replay and exact-revision guard around the non-atomic GitHub review API. */ class ObservePullRequestApprovalUseCase { constructor(port) { @@ -57835,20 +57835,20 @@ function evidenceFailure(cause, operation = 'evidence') { /***/ }), -/***/ 68595: +/***/ 29415: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentUseCase = void 0; -const comment_automation_command_workflow_1 = __nccwpck_require__(39723); -const copilot_command_1 = __nccwpck_require__(28057); -const read_copilot_history_workflow_1 = __nccwpck_require__(11603); -const comment_automation_use_case_1 = __nccwpck_require__(29792); -const check_pull_request_comment_language_use_case_1 = __nccwpck_require__(92546); -const comment_automation_context_1 = __nccwpck_require__(90059); -const pull_request_workflow_context_1 = __nccwpck_require__(12372); +const comment_automation_command_workflow_1 = __nccwpck_require__(63134); +const copilot_command_1 = __nccwpck_require__(11771); +const read_copilot_history_workflow_1 = __nccwpck_require__(8140); +const comment_automation_use_case_1 = __nccwpck_require__(9661); +const check_pull_request_comment_language_use_case_1 = __nccwpck_require__(21729); +const comment_automation_context_1 = __nccwpck_require__(37055); +const pull_request_workflow_context_1 = __nccwpck_require__(73447); class PullRequestReviewCommentUseCase { constructor(languageUseCase, intentUseCase, thinkUseCase, autofixUseCase, doUserRequestUseCase, actorAuthorizationPort, bugbotGitMutationPort, dismissBugbotFindingsUseCase, reviewPotentialProblemsUseCase, updatePullRequestDescriptionUseCase, rememberBugbotRuleUseCase, syncBranchUseCase, rememberBranchPorts, statusReadPorts, historyReadPort, sddDiffQueryPort, nativeStatusReadPort, doctorReadPorts) { this.languageUseCase = languageUseCase; @@ -57921,20 +57921,20 @@ exports.PullRequestReviewCommentUseCase = PullRequestReviewCommentUseCase; /***/ }), -/***/ 86023: +/***/ 27259: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const pull_request_workflow_1 = __nccwpck_require__(61286); -const update_title_workflow_1 = __nccwpck_require__(12039); -const project_content_link_workflow_1 = __nccwpck_require__(63457); -const pull_request_workflow_context_1 = __nccwpck_require__(12372); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const pull_request_workflow_1 = __nccwpck_require__(95238); +const update_title_workflow_1 = __nccwpck_require__(50029); +const project_content_link_workflow_1 = __nccwpck_require__(89064); +const pull_request_workflow_context_1 = __nccwpck_require__(73447); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); class PullRequestUseCase { constructor(updatePullRequestDescriptionUseCase, workflowSteps, reviewPotentialProblemsUseCase, actorAuthorizationPort) { this.updatePullRequestDescriptionUseCase = updatePullRequestDescriptionUseCase; @@ -57989,16 +57989,16 @@ function projectPullRequestWorkflowRouteContext(param) { /***/ }), -/***/ 61286: +/***/ 95238: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPullRequestWorkflow = runPullRequestWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); /** Coordinates pull-request lifecycle actions while preserving their sequential order. */ async function runPullRequestWorkflow(context, taskId, ports) { try { @@ -58083,7 +58083,7 @@ function logPullRequestState(context) { /***/ }), -/***/ 12372: +/***/ 73447: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -58091,8 +58091,8 @@ function logPullRequestState(context) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectPullRequestWorkflowStepContexts = projectPullRequestWorkflowStepContexts; exports.projectPullRequestDescriptionContext = projectPullRequestDescriptionContext; -const copilot_lifecycle_1 = __nccwpck_require__(71962); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const copilot_lifecycle_1 = __nccwpck_require__(72418); +const issue_workflow_context_1 = __nccwpck_require__(98005); function projectPullRequestWorkflowStepContexts(source) { const projects = (0, issue_workflow_context_1.copyProjects)(source.project.getProjects()); return Object.freeze({ @@ -58163,7 +58163,7 @@ function projectPullRequestDescriptionContext(source) { /***/ }), -/***/ 68843: +/***/ 47841: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -58182,9 +58182,9 @@ exports.projectChangeSizeContext = projectChangeSizeContext; exports.projectInitialSetupContext = projectInitialSetupContext; exports.projectIssueCommentActionContext = projectIssueCommentActionContext; exports.projectAgentActivityContext = projectAgentActivityContext; -const recommendation_state_1 = __nccwpck_require__(44113); -const issue_comment_publication_policy_1 = __nccwpck_require__(14047); -const git_object_id_1 = __nccwpck_require__(65534); +const recommendation_state_1 = __nccwpck_require__(68514); +const issue_comment_publication_policy_1 = __nccwpck_require__(61899); +const git_object_id_1 = __nccwpck_require__(88623); function projectDeploymentPublicationContext(source) { return Object.freeze({ requestedOperationId: source.singleAction.operationId, @@ -58418,22 +58418,22 @@ function deepFreezeCopy(value) { /***/ }), -/***/ 97584: +/***/ 12416: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCopilotDoctor = readCopilotDoctor; -const result_1 = __nccwpck_require__(99917); -const github_runtime_doctor_1 = __nccwpck_require__(56756); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const issue_start_policy_1 = __nccwpck_require__(59704); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const context_1 = __nccwpck_require__(8442); -const github_runtime_doctor_policy_1 = __nccwpck_require__(51599); -const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(3571); -const bugbot_context_request_1 = __nccwpck_require__(29868); +const result_1 = __nccwpck_require__(73817); +const github_runtime_doctor_1 = __nccwpck_require__(20413); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const issue_start_policy_1 = __nccwpck_require__(90332); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const context_1 = __nccwpck_require__(14712); +const github_runtime_doctor_policy_1 = __nccwpck_require__(99566); +const github_runtime_doctor_presentation_policy_1 = __nccwpck_require__(2808); +const bugbot_context_request_1 = __nccwpck_require__(98299); async function readCopilotDoctor(param, taskId, ports) { const repositoryId = (0, positive_integer_policy_1.parsePositiveSafeInteger)(param.bugbot.review.repository.id); const isPull = param.status.target === 'pull-request'; @@ -58536,15 +58536,15 @@ function doctorResult(taskId, report, serverOrigin, revision, owner, repository) /***/ }), -/***/ 11603: +/***/ 8140: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCopilotHistory = readCopilotHistory; -const result_1 = __nccwpck_require__(99917); -const copilot_history_policy_1 = __nccwpck_require__(44359); +const result_1 = __nccwpck_require__(73817); +const copilot_history_policy_1 = __nccwpck_require__(14335); /** A failed read cannot prove empty history or an operation failure. */ async function readCopilotHistory(request, ports) { let history = request.generalConversation ? copilot_history_policy_1.HISTORY_UNAVAILABLE : copilot_history_policy_1.HISTORY_UNSUPPORTED_SURFACE; @@ -58577,17 +58577,17 @@ async function readCopilotHistory(request, ports) { /***/ }), -/***/ 28724: +/***/ 57206: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCopilotStatus = readCopilotStatus; -const sdd_status_policy_1 = __nccwpck_require__(11756); -const status_command_policy_1 = __nccwpck_require__(33849); -const read_pull_request_status_readiness_workflow_1 = __nccwpck_require__(48006); -const application_error_1 = __nccwpck_require__(1889); +const sdd_status_policy_1 = __nccwpck_require__(6853); +const status_command_policy_1 = __nccwpck_require__(3449); +const read_pull_request_status_readiness_workflow_1 = __nccwpck_require__(18874); +const application_error_1 = __nccwpck_require__(75999); /** Shared read-only status path combines current native state with PR readiness evidence. */ async function readCopilotStatus(param, taskId, ports, sddQuery, nativeStatus) { let initialIssue; @@ -58653,21 +58653,21 @@ async function fenceNativeIssue(port, original) { /***/ }), -/***/ 48006: +/***/ 18874: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readPullRequestStatusReadiness = readPullRequestStatusReadiness; -const status_command_policy_1 = __nccwpck_require__(33849); -const bugbot_status_count_marker_policy_1 = __nccwpck_require__(37427); -const bugbot_review_ownership_policy_1 = __nccwpck_require__(51686); -const bugbot_review_presentation_policy_1 = __nccwpck_require__(94649); -const context_1 = __nccwpck_require__(8442); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const pull_request_readiness_policy_1 = __nccwpck_require__(79355); +const status_command_policy_1 = __nccwpck_require__(3449); +const bugbot_status_count_marker_policy_1 = __nccwpck_require__(8654); +const bugbot_review_ownership_policy_1 = __nccwpck_require__(83288); +const bugbot_review_presentation_policy_1 = __nccwpck_require__(43799); +const context_1 = __nccwpck_require__(14712); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const pull_request_readiness_policy_1 = __nccwpck_require__(79794); const positive = (value) => Number.isSafeInteger(value) && value > 0; const sha = (value) => typeof value === 'string' && /^[a-f0-9]{40}$/u.test(value); /** Independent reads retain verified facts. Unknown identity or freshness never becomes a clean snapshot. */ @@ -58847,16 +58847,16 @@ async function readPullRequestStatusReadiness(param, taskId, ports) { /***/ }), -/***/ 56461: +/***/ 93454: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.draftSddMarkdown = draftSddMarkdown; -const application_error_1 = __nccwpck_require__(1889); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const agent_response_length_failure_1 = __nccwpck_require__(11975); +const application_error_1 = __nccwpck_require__(75999); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const agent_response_length_failure_1 = __nccwpck_require__(28528); /** Size and typed format failures share one regeneration; the writer still validates every candidate. */ async function draftSddMarkdown(agent, configuration, plan, prompt, validate) { const maximum = plan.action === 'update' ? pre_branch_sdd_1.SDD_MAX_UPDATE_CHARACTERS : pre_branch_sdd_1.SDD_MAX_DRAFT_CHARACTERS; @@ -58918,22 +58918,22 @@ async function draftSddMarkdown(agent, configuration, plan, prompt, validate) { /***/ }), -/***/ 2776: +/***/ 29475: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PreBranchSddGateUseCase = void 0; -const sdd_issue_identity_policy_1 = __nccwpck_require__(81773); -const result_1 = __nccwpck_require__(99917); -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const recommendation_policy_1 = __nccwpck_require__(33990); -const logging_ports_1 = __nccwpck_require__(97793); -const sdd_analysis_status_policy_1 = __nccwpck_require__(85365); -const application_error_1 = __nccwpck_require__(1889); -const pre_branch_sdd_draft_workflow_1 = __nccwpck_require__(56461); +const sdd_issue_identity_policy_1 = __nccwpck_require__(99167); +const result_1 = __nccwpck_require__(73817); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const recommendation_policy_1 = __nccwpck_require__(39410); +const logging_ports_1 = __nccwpck_require__(6152); +const sdd_analysis_status_policy_1 = __nccwpck_require__(81053); +const application_error_1 = __nccwpck_require__(75999); +const pre_branch_sdd_draft_workflow_1 = __nccwpck_require__(93454); const ANALYSIS_SCHEMA = { type: 'object', properties: { @@ -59278,16 +59278,16 @@ function canonicalIssueUrl(context) { /***/ }), -/***/ 81101: +/***/ 48684: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SddDiffQueryUseCase = void 0; -const issue_start_policy_1 = __nccwpck_require__(59704); -const issue_workflow_profile_1 = __nccwpck_require__(65360); -const pre_branch_sdd_diff_1 = __nccwpck_require__(57493); +const issue_start_policy_1 = __nccwpck_require__(90332); +const issue_workflow_profile_1 = __nccwpck_require__(26744); +const pre_branch_sdd_diff_1 = __nccwpck_require__(28558); /** Structural comparison over shared verified evidence, with no writer/model capability. */ class SddDiffQueryUseCase { constructor(ports) { @@ -59476,7 +59476,7 @@ function associationProof(links) { /***/ }), -/***/ 28491: +/***/ 39893: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -59484,11 +59484,11 @@ function associationProof(links) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SddEvidenceQueryUseCase = void 0; const node_crypto_1 = __nccwpck_require__(6005); -const issue_start_policy_1 = __nccwpck_require__(59704); -const pre_branch_sdd_1 = __nccwpck_require__(56394); -const sdd_evidence_read_ports_1 = __nccwpck_require__(77387); -const sdd_issue_identity_policy_1 = __nccwpck_require__(81773); -const sdd_query_card_policy_1 = __nccwpck_require__(50681); +const issue_start_policy_1 = __nccwpck_require__(90332); +const pre_branch_sdd_1 = __nccwpck_require__(34730); +const sdd_evidence_read_ports_1 = __nccwpck_require__(94752); +const sdd_issue_identity_policy_1 = __nccwpck_require__(99167); +const sdd_query_card_policy_1 = __nccwpck_require__(56285); const MAX_AUTHORIZATION_LOOKUPS = 16; /** Reads gate authority and immutable publication evidence without any mutation or model capability. */ class SddEvidenceQueryUseCase { @@ -59698,19 +59698,19 @@ function canonicalLabels(labels) { return JSON.stringify([...new Set(labels.map( /***/ }), -/***/ 97206: +/***/ 73572: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SingleActionUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const single_action_workflow_1 = __nccwpck_require__(60484); -const think_workflow_1 = __nccwpck_require__(84106); -const bugbot_review_operation_context_1 = __nccwpck_require__(67737); -const push_single_action_contexts_1 = __nccwpck_require__(68843); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const single_action_workflow_1 = __nccwpck_require__(6130); +const think_workflow_1 = __nccwpck_require__(36450); +const bugbot_review_operation_context_1 = __nccwpck_require__(16660); +const push_single_action_contexts_1 = __nccwpck_require__(47841); class SingleActionUseCase { constructor(publishGithubActionUseCase, createReleaseUseCase, createTagUseCase, thinkUseCase, initialSetupUseCase, checkProgressUseCase, detectPotentialProblemsUseCase, recommendStepsUseCase, closeInactiveIssuesUseCase, actorAuthorizationPort, publishIssueCommentUseCase, observeBranchSyncUseCase, deploymentOrchestrationUseCase) { this.publishGithubActionUseCase = publishGithubActionUseCase; @@ -59803,16 +59803,16 @@ function isAgentBackedSingleAction(param) { /***/ }), -/***/ 60484: +/***/ 6130: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runSingleActionWorkflow = runSingleActionWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); async function runSingleActionWorkflow(dispatch, taskId, ports) { if (dispatch.kind === 'invalid') { (0, logging_ports_1.logDebugInfo)(`Single action is not valid: ${dispatch.action}. Skipping.`); @@ -59866,24 +59866,24 @@ function singleActionFailure(action, taskId, error) { /***/ }), -/***/ 7062: +/***/ 4658: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.analyzeBugbotRevision = analyzeBugbotRevision; -const bugbot_reconciliation_policy_1 = __nccwpck_require__(55390); -const logging_ports_1 = __nccwpck_require__(97793); -const limit_comments_1 = __nccwpck_require__(47233); -const finding_1 = __nccwpck_require__(71592); -const build_bugbot_prompt_1 = __nccwpck_require__(63670); -const prepare_bugbot_findings_1 = __nccwpck_require__(83131); -const query_bugbot_findings_1 = __nccwpck_require__(79678); -const bugbot_resolution_eligibility_policy_1 = __nccwpck_require__(53031); -const bounded_concurrency_policy_1 = __nccwpck_require__(93783); -const bugbot_partition_aggregation_1 = __nccwpck_require__(6831); -const application_error_1 = __nccwpck_require__(1889); +const bugbot_reconciliation_policy_1 = __nccwpck_require__(78128); +const logging_ports_1 = __nccwpck_require__(6152); +const limit_comments_1 = __nccwpck_require__(31643); +const finding_1 = __nccwpck_require__(31011); +const build_bugbot_prompt_1 = __nccwpck_require__(52483); +const prepare_bugbot_findings_1 = __nccwpck_require__(85016); +const query_bugbot_findings_1 = __nccwpck_require__(13059); +const bugbot_resolution_eligibility_policy_1 = __nccwpck_require__(89189); +const bounded_concurrency_policy_1 = __nccwpck_require__(35596); +const bugbot_partition_aggregation_1 = __nccwpck_require__(84575); +const application_error_1 = __nccwpck_require__(75999); /** Pure analysis phase: query, validate, normalize, deduplicate and reconcile; never mutates the SCM. */ async function analyzeBugbotRevision(execution, context, dependencies) { dependencies.telemetry.observeContext(context); @@ -59965,17 +59965,17 @@ function suppressDismissedFindings(execution, context, prepared) { /***/ }), -/***/ 60798: +/***/ 20793: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyDetectedFindings = applyDetectedFindings; -const mark_findings_resolved_use_case_1 = __nccwpck_require__(7458); -const publish_findings_use_case_1 = __nccwpck_require__(77714); -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const mark_findings_resolved_use_case_1 = __nccwpck_require__(96963); +const publish_findings_use_case_1 = __nccwpck_require__(88442); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const pull_request_review_errors_1 = __nccwpck_require__(46445); async function applyDetectedFindings(operation, context, prepared, publicationPorts, resolutionPorts, catalog) { try { await (0, publish_findings_use_case_1.publishFindings)({ @@ -60009,7 +60009,7 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo /***/ }), -/***/ 64609: +/***/ 98158: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60017,8 +60017,8 @@ async function applyDetectedFindings(operation, context, prepared, publicationPo Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runBugbotAutofixCommitAndPush = runBugbotAutofixCommitAndPush; exports.runUserRequestCommitAndPush = runUserRequestCommitAndPush; -const commit_message_policy_1 = __nccwpck_require__(44070); -const commit_and_push_workflow_1 = __nccwpck_require__(55203); +const commit_message_policy_1 = __nccwpck_require__(85518); +const commit_and_push_workflow_1 = __nccwpck_require__(53708); async function runBugbotAutofixCommitAndPush(context, options, gitCommitPort) { const branch = options?.branchOverride ?? context.branch; return (0, commit_and_push_workflow_1.runCommitAndPushWorkflow)(context, { @@ -60043,17 +60043,17 @@ async function runUserRequestCommitAndPush(context, options, gitCommitPort) { /***/ }), -/***/ 86050: +/***/ 79698: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.finalizeBugbotAutofix = finalizeBugbotAutofix; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); async function finalizeBugbotAutofix(context, idsToFix, workspacePathsBefore, branchCheckedOut, responseText, gitCommitPort) { if (!responseText) { (0, logging_ports_1.logError)('Bugbot autofix: no response from configured build agent.'); @@ -60084,21 +60084,21 @@ function failure(semanticError) { /***/ }), -/***/ 27829: +/***/ 67170: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareBugbotAutofix = prepareBugbotAutofix; -const result_1 = __nccwpck_require__(99917); -const finding_1 = __nccwpck_require__(71592); -const build_bugbot_fix_prompt_1 = __nccwpck_require__(70732); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const logging_ports_1 = __nccwpck_require__(97793); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const finding_1 = __nccwpck_require__(31011); +const build_bugbot_fix_prompt_1 = __nccwpck_require__(89819); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const logging_ports_1 = __nccwpck_require__(6152); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); async function prepareBugbotAutofix(operation, targetFindingIds, userComment, providedContext, branchOverride, contextPorts, gitCommitPort) { const canonicalHint = providedContext?.canonicalPullRequest; const targetBranch = branchOverride?.trim() || canonicalHint?.headRef; @@ -60161,14 +60161,14 @@ function failure(semanticError) { /***/ }), -/***/ 73970: +/***/ 45446: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotAutofixUseCase = void 0; -const bugbot_autofix_workflow_1 = __nccwpck_require__(77959); +const bugbot_autofix_workflow_1 = __nccwpck_require__(69600); /** Application boundary for safe, agent-driven remediation of Bugbot findings. */ class BugbotAutofixUseCase { constructor(aiRepository, contextPorts, gitCommitPort) { @@ -60190,20 +60190,20 @@ exports.BugbotAutofixUseCase = BugbotAutofixUseCase; /***/ }), -/***/ 77959: +/***/ 69600: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runBugbotAutofixWorkflow = runBugbotAutofixWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const bugbot_autofix_postflight_1 = __nccwpck_require__(86050); -const bugbot_autofix_preflight_1 = __nccwpck_require__(27829); -const application_error_1 = __nccwpck_require__(1889); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const bugbot_autofix_postflight_1 = __nccwpck_require__(79698); +const bugbot_autofix_preflight_1 = __nccwpck_require__(67170); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = 'BugbotAutofixUseCase'; /** Coordinates preflight, agent execution and postflight workspace safety. */ async function runBugbotAutofixWorkflow(param, dependencies) { @@ -60246,14 +60246,14 @@ function newResultFailure(semanticError) { /***/ }), -/***/ 29868: +/***/ 98299: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectBugbotContextRequest = projectBugbotContextRequest; -const positive_integer_policy_1 = __nccwpck_require__(20889); +const positive_integer_policy_1 = __nccwpck_require__(19879); function projectBugbotContextRequest(context, options) { const issueNumber = (0, positive_integer_policy_1.parsePositiveSafeInteger)(options?.issueNumberOverride ?? context.target.issueNumber); const pullRequestNumber = (0, positive_integer_policy_1.parsePositiveSafeInteger)(options?.pullRequestNumberOverride @@ -60287,7 +60287,7 @@ function projectBugbotContextRequest(context, options) { /***/ }), -/***/ 27015: +/***/ 62946: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60295,11 +60295,11 @@ function projectBugbotContextRequest(context, options) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.parseBugbotFindingComments = parseBugbotFindingComments; exports.collectPreviousBugbotFindings = collectPreviousBugbotFindings; -const build_bugbot_fix_prompt_1 = __nccwpck_require__(70732); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const finding_1 = __nccwpck_require__(71592); -const github_user_policy_1 = __nccwpck_require__(84900); -const review_state_1 = __nccwpck_require__(47220); +const build_bugbot_fix_prompt_1 = __nccwpck_require__(89819); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const finding_1 = __nccwpck_require__(31011); +const github_user_policy_1 = __nccwpck_require__(84403); +const review_state_1 = __nccwpck_require__(79200); function parseBugbotFindingComments(issueComments, pullRequestCommentsByNumber, trustedAuthorLogin, reviewThreadStatesByPullRequest = new Map()) { const existingByFindingId = parseIssueFindingMarkers(issueComments, trustedAuthorLogin); const pullRequestFindings = parsePullRequestFindingMarkers(pullRequestCommentsByNumber, trustedAuthorLogin, reviewThreadStatesByPullRequest); @@ -60420,7 +60420,7 @@ function collectPreviousBugbotFindings(issueComments, existingByFindingId, prFin /***/ }), -/***/ 90862: +/***/ 25734: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -60459,7 +60459,7 @@ function canRunDoUserRequest(payload) { /***/ }), -/***/ 6831: +/***/ 84575: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60467,7 +60467,7 @@ function canRunDoUserRequest(payload) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_AGGREGATE_PARTITION_FINDINGS = void 0; exports.aggregateBugbotPartitionResponses = aggregateBugbotPartitionResponses; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); const MAX_PARTITION_FINDINGS_PER_RESPONSE = 200; exports.MAX_AGGREGATE_PARTITION_FINDINGS = 2000; const MAX_OWNER_RESOLUTIONS = 500; @@ -60520,7 +60520,7 @@ function invalidAggregate(message) { /***/ }), -/***/ 27537: +/***/ 3346: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60528,8 +60528,8 @@ function invalidAggregate(message) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_PREVIOUS_FINDINGS_BLOCK_LENGTH = exports.MAX_PREVIOUS_FINDINGS = void 0; exports.buildPreviousFindingsContext = buildPreviousFindingsContext; -const untrusted_content_1 = __nccwpck_require__(30127); -const build_bugbot_fix_prompt_1 = __nccwpck_require__(70732); +const untrusted_content_1 = __nccwpck_require__(67057); +const build_bugbot_fix_prompt_1 = __nccwpck_require__(89819); exports.MAX_PREVIOUS_FINDINGS = 100; exports.MAX_PREVIOUS_FINDINGS_BLOCK_LENGTH = 48000; function buildPreviousFindingsContext(previousFindings) { @@ -60590,7 +60590,7 @@ function timestamp(value) { /***/ }), -/***/ 51970: +/***/ 50536: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60600,9 +60600,9 @@ exports.buildReviewDiffBlock = buildReviewDiffBlock; exports.buildReviewDiffContext = buildReviewDiffContext; exports.buildReviewConversationBlock = buildReviewConversationBlock; exports.buildReviewConversationContext = buildReviewConversationContext; -const github_user_policy_1 = __nccwpck_require__(84900); -const untrusted_content_1 = __nccwpck_require__(30127); -const bugbot_diff_partition_policy_1 = __nccwpck_require__(74008); +const github_user_policy_1 = __nccwpck_require__(84403); +const untrusted_content_1 = __nccwpck_require__(67057); +const bugbot_diff_partition_policy_1 = __nccwpck_require__(31601); const MAX_CONVERSATION_LENGTH = 24000; const MAX_CONVERSATION_ITEMS = 50; const MAX_CONVERSATION_ITEM_LENGTH = 4000; @@ -60689,7 +60689,7 @@ function isBot(author, botLogin) { /***/ }), -/***/ 1415: +/***/ 14307: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -60712,7 +60712,7 @@ async function hasNewerBugbotRevision(context, ports) { /***/ }), -/***/ 67737: +/***/ 16660: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60724,7 +60724,7 @@ exports.withBugbotReviewOverrides = withBugbotReviewOverrides; exports.projectBugbotFixIntentContext = projectBugbotFixIntentContext; exports.projectBugbotAutofixOperationContext = projectBugbotAutofixOperationContext; exports.projectBugbotCommitContext = projectBugbotCommitContext; -const positive_integer_policy_1 = __nccwpck_require__(20889); +const positive_integer_policy_1 = __nccwpck_require__(19879); /** Copies only the non-secret facts required to select canonical Bugbot context. */ function projectBugbotContextSelectionContext(source) { const reviewConfiguration = source.ai.getBugbotReviewConfiguration(); @@ -60870,7 +60870,7 @@ function normalizeExpectedHeadSha(eventName, inputs) { /***/ }), -/***/ 21706: +/***/ 25011: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -60878,7 +60878,7 @@ function normalizeExpectedHeadSha(eventName, inputs) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_BUGBOT_RULES_LENGTH = exports.MAX_BUGBOT_RULE_LENGTH = void 0; exports.buildBugbotReviewRuleSet = buildBugbotReviewRuleSet; -const untrusted_content_1 = __nccwpck_require__(30127); +const untrusted_content_1 = __nccwpck_require__(67057); exports.MAX_BUGBOT_RULE_LENGTH = 30000; exports.MAX_BUGBOT_RULES_LENGTH = 100000; function buildBugbotReviewRuleSet(organizationRules, repositoryRules) { @@ -60931,14 +60931,14 @@ function deduplicateRules(rules) { /***/ }), -/***/ 82658: +/***/ 46790: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotReviewTelemetry = void 0; -const bugbot_finding_status_policy_1 = __nccwpck_require__(10264); +const bugbot_finding_status_policy_1 = __nccwpck_require__(53822); const systemClock = { now: () => Date.now(), isoNow: () => new Date().toISOString(), @@ -61140,7 +61140,7 @@ function sanitizeMetricName(value) { /***/ }), -/***/ 35361: +/***/ 18799: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -61151,9 +61151,9 @@ function sanitizeMetricName(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildBugbotFixIntentPrompt = buildBugbotFixIntentPrompt; -const prompts_1 = __nccwpck_require__(10966); -const project_context_instruction_1 = __nccwpck_require__(55527); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); +const prompts_1 = __nccwpck_require__(69518); +const project_context_instruction_1 = __nccwpck_require__(63907); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); const MAX_TITLE_LENGTH = 200; const MAX_FILE_LENGTH = 256; function safeForPrompt(s, maxLen) { @@ -61203,7 +61203,7 @@ function buildParentBlock(parentCommentBody) { /***/ }), -/***/ 70732: +/***/ 89819: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -61212,10 +61212,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_FINDING_BODY_LENGTH = void 0; exports.truncateFindingBody = truncateFindingBody; exports.buildBugbotFixPrompt = buildBugbotFixPrompt; -const prompts_1 = __nccwpck_require__(10966); -const project_context_instruction_1 = __nccwpck_require__(55527); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); -const untrusted_content_1 = __nccwpck_require__(30127); +const prompts_1 = __nccwpck_require__(69518); +const project_context_instruction_1 = __nccwpck_require__(63907); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); +const untrusted_content_1 = __nccwpck_require__(67057); /** Maximum characters for a single finding's full comment body to avoid prompt bloat and token limits. */ exports.MAX_FINDING_BODY_LENGTH = 12000; const TRUNCATION_SUFFIX = "\n\n[... truncated for length ...]"; @@ -61272,7 +61272,7 @@ function buildBugbotFixPrompt(param, context, targetFindingIds, userComment, ver /***/ }), -/***/ 63670: +/***/ 52483: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -61286,10 +61286,10 @@ function buildBugbotFixPrompt(param, context, targetFindingIds, userComment, ver */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildBugbotPrompt = buildBugbotPrompt; -const prompts_1 = __nccwpck_require__(10966); -const project_context_instruction_1 = __nccwpck_require__(55527); -const review_configuration_1 = __nccwpck_require__(38595); -const file_ignore_policy_1 = __nccwpck_require__(38774); +const prompts_1 = __nccwpck_require__(69518); +const project_context_instruction_1 = __nccwpck_require__(63907); +const review_configuration_1 = __nccwpck_require__(3994); +const file_ignore_policy_1 = __nccwpck_require__(20542); const MAX_IGNORE_BLOCK_LENGTH = 2000; const GIT_OBJECT_ID = /^[0-9a-f]{7,64}$/i; function buildBugbotPrompt(param, context, assignment) { @@ -61411,20 +61411,20 @@ function normalizedObjectId(value) { /***/ }), -/***/ 71364: +/***/ 49629: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommitAndPushPreflight = runCommitAndPushPreflight; -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); -const git_branch_checkout_1 = __nccwpck_require__(37329); -const verify_command_policy_1 = __nccwpck_require__(23322); -const verify_command_runner_1 = __nccwpck_require__(50827); -const workspace_changes_1 = __nccwpck_require__(33363); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); +const git_branch_checkout_1 = __nccwpck_require__(68549); +const verify_command_policy_1 = __nccwpck_require__(96031); +const verify_command_runner_1 = __nccwpck_require__(57742); +const workspace_changes_1 = __nccwpck_require__(93370); async function runCommitAndPushPreflight(context, options, gitCommitPort) { if (!options.branch?.trim()) { return { status: "failure", error: "No branch to commit to." }; @@ -61479,16 +61479,16 @@ async function runVerification(context, gitCommitPort) { /***/ }), -/***/ 55203: +/***/ 53708: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCommitAndPushWorkflow = runCommitAndPushWorkflow; -const logging_ports_1 = __nccwpck_require__(97793); -const commit_and_push_preflight_1 = __nccwpck_require__(71364); -const application_error_1 = __nccwpck_require__(1889); +const logging_ports_1 = __nccwpck_require__(6152); +const commit_and_push_preflight_1 = __nccwpck_require__(49629); +const application_error_1 = __nccwpck_require__(75999); async function runCommitAndPushWorkflow(context, options, gitCommitPort) { const preflight = await (0, commit_and_push_preflight_1.runCommitAndPushPreflight)(context, options, gitCommitPort); if (preflight.status === 'failure') { @@ -61524,16 +61524,16 @@ async function runCommitAndPushWorkflow(context, options, gitCommitPort) { /***/ }), -/***/ 98022: +/***/ 93455: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.commitAutofixAndResolveFindings = commitAutofixAndResolveFindings; -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_autofix_commit_1 = __nccwpck_require__(64609); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_autofix_commit_1 = __nccwpck_require__(98158); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); async function commitAutofixAndResolveFindings(context, payload, autofixResults, gitCommitPort, onCompleted) { const lastAutofix = autofixResults.at(-1); if (!lastAutofix?.success) { @@ -61568,7 +61568,7 @@ async function commitAutofixAndResolveFindings(context, payload, autofixResults, /***/ }), -/***/ 44070: +/***/ 85518: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -61622,18 +61622,18 @@ function buildUserRequestCommitMessage(issueNumber) { /***/ }), -/***/ 41729: +/***/ 43393: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.commitUserRequestIfSuccessful = commitUserRequestIfSuccessful; -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_autofix_commit_1 = __nccwpck_require__(64609); -const result_1 = __nccwpck_require__(99917); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const application_error_1 = __nccwpck_require__(1889); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_autofix_commit_1 = __nccwpck_require__(98158); +const result_1 = __nccwpck_require__(73817); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const application_error_1 = __nccwpck_require__(75999); async function commitUserRequestIfSuccessful(context, branchOverride, results, gitCommitPort) { if (!results.at(-1)?.success) { (0, logging_ports_1.logInfo)('Do user request did not succeed; skipping commit.'); @@ -61667,7 +61667,7 @@ async function commitUserRequestIfSuccessful(context, branchOverride, results, g /***/ }), -/***/ 57491: +/***/ 62908: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -61700,7 +61700,7 @@ function deduplicateFindings(findings) { /***/ }), -/***/ 24760: +/***/ 14796: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -61709,7 +61709,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectBugbotCommentBody = selectBugbotCommentBody; exports.buildUnresolvedFindingSummaries = buildUnresolvedFindingSummaries; exports.parseBugbotFixIntentResponse = parseBugbotFixIntentResponse; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); /** Selects the user-authored comment that can trigger intent detection. */ function selectBugbotCommentBody(sources) { if (sources.issue.isIssueComment) @@ -61754,16 +61754,16 @@ function unique(values) { /***/ }), -/***/ 10401: +/***/ 76234: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DetectBugbotFixIntentUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const detect_bugbot_fix_intent_workflow_1 = __nccwpck_require__(1353); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const detect_bugbot_fix_intent_workflow_1 = __nccwpck_require__(88390); const TASK_ID = "DetectBugbotFixIntentUseCase"; /** Application boundary for detecting Bugbot fix intent in user comments. */ class DetectBugbotFixIntentUseCase { @@ -61785,23 +61785,23 @@ exports.DetectBugbotFixIntentUseCase = DetectBugbotFixIntentUseCase; /***/ }), -/***/ 1353: +/***/ 88390: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runDetectBugbotFixIntentWorkflow = runDetectBugbotFixIntentWorkflow; -const agent_1 = __nccwpck_require__(11066); -const agent_task_policy_1 = __nccwpck_require__(34816); -const logging_ports_1 = __nccwpck_require__(97793); -const result_1 = __nccwpck_require__(99917); -const copilot_command_1 = __nccwpck_require__(28057); -const build_bugbot_fix_intent_prompt_1 = __nccwpck_require__(35361); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const schema_1 = __nccwpck_require__(54744); -const detect_bugbot_fix_intent_policy_1 = __nccwpck_require__(24760); +const agent_1 = __nccwpck_require__(79937); +const agent_task_policy_1 = __nccwpck_require__(85712); +const logging_ports_1 = __nccwpck_require__(6152); +const result_1 = __nccwpck_require__(73817); +const copilot_command_1 = __nccwpck_require__(11771); +const build_bugbot_fix_intent_prompt_1 = __nccwpck_require__(18799); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const schema_1 = __nccwpck_require__(16808); +const detect_bugbot_fix_intent_policy_1 = __nccwpck_require__(14796); const TASK_ID = "DetectBugbotFixIntentUseCase"; /** Detects whether a comment requests a finding fix, repository change, or read-only review. */ async function runDetectBugbotFixIntentWorkflow(param, ports) { @@ -61938,21 +61938,21 @@ async function resolveParentCommentBody(param, contextPorts) { /***/ }), -/***/ 48256: +/***/ 37685: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DismissBugbotFindingsUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const mark_findings_resolved_workflow_1 = __nccwpck_require__(62320); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const result_1 = __nccwpck_require__(73817); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const mark_findings_resolved_workflow_1 = __nccwpck_require__(65916); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); /** Dismisses only findings present in the current persisted Bugbot context. */ class DismissBugbotFindingsUseCase { constructor(dependencies) { @@ -62025,14 +62025,14 @@ async function loadDismissContext(operation, ports) { /***/ }), -/***/ 47233: +/***/ 31643: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.applyCommentLimit = applyCommentLimit; -const bugbot_constants_1 = __nccwpck_require__(77194); +const bugbot_constants_1 = __nccwpck_require__(51389); /** * Applies the max-comments limit: returns the first N findings to publish individually, * and overflow count + titles for a single "revisar en local" summary comment. @@ -62053,7 +62053,7 @@ function applyCommentLimit(findings, maxComments = bugbot_constants_1.BUGBOT_MAX /***/ }), -/***/ 11187: +/***/ 4050: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -62061,16 +62061,16 @@ function applyCommentLimit(findings, maxComments = bugbot_constants_1.BUGBOT_MAX Object.defineProperty(exports, "__esModule", ({ value: true })); exports.preflightBugbotContext = preflightBugbotContext; exports.loadBugbotContext = loadBugbotContext; -const application_error_1 = __nccwpck_require__(1889); -const bounded_concurrency_policy_1 = __nccwpck_require__(93783); -const context_1 = __nccwpck_require__(8442); -const logging_ports_1 = __nccwpck_require__(97793); -const bugbot_finding_context_1 = __nccwpck_require__(27015); -const bugbot_previous_findings_context_1 = __nccwpck_require__(27537); -const bugbot_diff_partition_policy_1 = __nccwpck_require__(74008); -const bugbot_review_context_1 = __nccwpck_require__(51970); -const file_ignore_policy_1 = __nccwpck_require__(38774); -const bugbot_review_rules_1 = __nccwpck_require__(21706); +const application_error_1 = __nccwpck_require__(75999); +const bounded_concurrency_policy_1 = __nccwpck_require__(35596); +const context_1 = __nccwpck_require__(14712); +const logging_ports_1 = __nccwpck_require__(6152); +const bugbot_finding_context_1 = __nccwpck_require__(62946); +const bugbot_previous_findings_context_1 = __nccwpck_require__(3346); +const bugbot_diff_partition_policy_1 = __nccwpck_require__(31601); +const bugbot_review_context_1 = __nccwpck_require__(50536); +const file_ignore_policy_1 = __nccwpck_require__(20542); +const bugbot_review_rules_1 = __nccwpck_require__(25011); /** Resolves and validates the provider-owned PR identity without loading review context. */ async function preflightBugbotContext(request, ports) { const selection = await selectCanonicalPullRequest(request, ports); @@ -62239,14 +62239,14 @@ function toPrContext(identity, snapshot) { /***/ }), -/***/ 76490: +/***/ 44861: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.loadBugbotReconciliationSnapshot = loadBugbotReconciliationSnapshot; -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); /** * Acquires one coherent final snapshot around two head guards. Surface reads * run concurrently, while the second guard rejects data collected across a @@ -62337,32 +62337,32 @@ function stateOf(result) { /***/ }), -/***/ 7458: +/***/ 96963: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = void 0; -var mark_findings_resolved_workflow_1 = __nccwpck_require__(62320); +var mark_findings_resolved_workflow_1 = __nccwpck_require__(65916); Object.defineProperty(exports, "markFindingsResolved", ({ enumerable: true, get: function () { return mark_findings_resolved_workflow_1.markFindingsResolved; } })); /***/ }), -/***/ 62320: +/***/ 65916: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.markFindingsResolved = markFindingsResolved; -const logging_ports_1 = __nccwpck_require__(97793); -const resolve_issue_finding_1 = __nccwpck_require__(78269); -const resolve_pull_request_finding_1 = __nccwpck_require__(46024); -const review_state_1 = __nccwpck_require__(47220); -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const application_error_1 = __nccwpck_require__(1889); +const logging_ports_1 = __nccwpck_require__(6152); +const resolve_issue_finding_1 = __nccwpck_require__(35300); +const resolve_pull_request_finding_1 = __nccwpck_require__(64567); +const review_state_1 = __nccwpck_require__(79200); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const application_error_1 = __nccwpck_require__(75999); async function markFindingsResolved(param) { const errors = []; for (const [findingId, existing] of Object.entries(param.context.existingByFindingId)) { @@ -62443,7 +62443,7 @@ function addResolutionError(errors, destination, findingId, cause) { /***/ }), -/***/ 72146: +/***/ 70124: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -62506,14 +62506,14 @@ function resolveFindingPathForPr(findingFile, prFiles) { /***/ }), -/***/ 83131: +/***/ 85016: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareBugbotFindings = prepareBugbotFindings; -const prepare_bugbot_findings_policy_1 = __nccwpck_require__(57286); +const prepare_bugbot_findings_policy_1 = __nccwpck_require__(3496); function prepareBugbotFindings(response, ignorePatterns, minSeverityValue, maxComments, maxAgentFindings) { const normalized = (0, prepare_bugbot_findings_policy_1.normalizeBugbotResponse)(response, maxAgentFindings); return normalized === undefined @@ -62528,7 +62528,7 @@ function prepareBugbotFindings(response, ignorePatterns, minSeverityValue, maxCo /***/ }), -/***/ 57286: +/***/ 3496: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -62537,14 +62537,14 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MIN_AGENT_FINDING_CONFIDENCE = exports.MAX_AGENT_RESOLVED_FINDINGS = exports.MAX_AGENT_FINDINGS = void 0; exports.normalizeBugbotResponse = normalizeBugbotResponse; exports.prepareFindings = prepareFindings; -const deduplicate_findings_1 = __nccwpck_require__(57491); -const file_ignore_policy_1 = __nccwpck_require__(38774); -const limit_comments_1 = __nccwpck_require__(47233); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const path_validation_1 = __nccwpck_require__(72146); -const severity_1 = __nccwpck_require__(11135); -const finding_identity_1 = __nccwpck_require__(9248); -const sensitive_text_1 = __nccwpck_require__(57472); +const deduplicate_findings_1 = __nccwpck_require__(62908); +const file_ignore_policy_1 = __nccwpck_require__(20542); +const limit_comments_1 = __nccwpck_require__(31643); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const path_validation_1 = __nccwpck_require__(70124); +const severity_1 = __nccwpck_require__(14626); +const finding_identity_1 = __nccwpck_require__(91853); +const sensitive_text_1 = __nccwpck_require__(47122); /** Hard cap for model-controlled arrays before any filtering or publication. */ exports.MAX_AGENT_FINDINGS = 500; exports.MAX_AGENT_RESOLVED_FINDINGS = 500; @@ -62677,7 +62677,7 @@ function isRecord(value) { /***/ }), -/***/ 77714: +/***/ 88442: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -62688,11 +62688,11 @@ function isRecord(value) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishFindings = publishFindings; -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const finding_1 = __nccwpck_require__(71592); -const publish_issue_finding_comment_1 = __nccwpck_require__(67793); -const publish_pr_review_comments_1 = __nccwpck_require__(19504); -const publish_overflow_comment_1 = __nccwpck_require__(75231); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const finding_1 = __nccwpck_require__(31011); +const publish_issue_finding_comment_1 = __nccwpck_require__(84950); +const publish_pr_review_comments_1 = __nccwpck_require__(50352); +const publish_overflow_comment_1 = __nccwpck_require__(10974); async function publishFindings(param) { const { operation, context, findings, commitSha, overflowCount = 0, overflowTitles = [], ports, catalog } = param; const { existingByFindingId, canonicalPullRequest, prContext } = context; @@ -62729,15 +62729,15 @@ async function publishFindings(param) { /***/ }), -/***/ 67793: +/***/ 84950: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishIssueFindingComment = publishIssueFindingComment; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const logging_ports_1 = __nccwpck_require__(97793); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const logging_ports_1 = __nccwpck_require__(6152); async function publishIssueFindingComment(repository, issueNumber, finding, existing, commitSha, catalog) { const body = (0, bugbot_finding_marker_policy_1.buildCommentBody)(finding, false, undefined, { catalog }); const options = commitSha ? { commitSha } : undefined; @@ -62753,16 +62753,16 @@ async function publishIssueFindingComment(repository, issueNumber, finding, exis /***/ }), -/***/ 75231: +/***/ 10974: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.publishOverflowComment = publishOverflowComment; -const logging_ports_1 = __nccwpck_require__(97793); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const logging_ports_1 = __nccwpck_require__(6152); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); async function publishOverflowComment(repository, issueNumber, overflowCount, overflowTitles, commitSha, catalog = (0, bugbot_message_catalog_1.resolveStaticBugbotCatalog)('en-US')) { if (overflowCount <= 0) return; @@ -62782,20 +62782,20 @@ ${catalog.message('bugbot.overflow.body', { count: `**${overflowCount}**` }, ove /***/ }), -/***/ 19504: +/***/ 50352: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentPublisher = void 0; -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const path_validation_1 = __nccwpck_require__(72146); -const logging_ports_1 = __nccwpck_require__(97793); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const bugbot_review_presentation_policy_1 = __nccwpck_require__(94649); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const path_validation_1 = __nccwpck_require__(70124); +const logging_ports_1 = __nccwpck_require__(6152); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const bugbot_review_presentation_policy_1 = __nccwpck_require__(43799); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); class PullRequestReviewCommentPublisher { constructor(options) { this.options = options; @@ -62954,7 +62954,7 @@ function sanitizeSummaryText(value, maximum) { /***/ }), -/***/ 79678: +/***/ 13059: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -62962,11 +62962,11 @@ function sanitizeSummaryText(value, maximum) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.queryBugbotFindings = queryBugbotFindings; exports.queryBugbotPartitionFindings = queryBugbotPartitionFindings; -const agent_task_policy_1 = __nccwpck_require__(34816); -const schema_1 = __nccwpck_require__(54744); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); +const agent_task_policy_1 = __nccwpck_require__(85712); +const schema_1 = __nccwpck_require__(16808); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); const MAX_PARTITION_QUERY_ATTEMPTS = 3; function bugbotQueryOptions(schema) { return (0, agent_output_locale_policy_1.productFacingAgentQueryOptions)('bugbot-review', schema); @@ -63019,20 +63019,20 @@ async function queryBugbotPartitionFindings(repository, configuration, prompt, t /***/ }), -/***/ 80398: +/***/ 57515: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileBugbotReviewState = reconcileBugbotReviewState; -const bugbot_mutation_error_1 = __nccwpck_require__(37020); -const review_projection_1 = __nccwpck_require__(25952); -const bugbot_reconciliation_policy_1 = __nccwpck_require__(55390); -const bugbot_provider_projection_policy_1 = __nccwpck_require__(33245); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const load_bugbot_reconciliation_snapshot_use_case_1 = __nccwpck_require__(76490); -const synchronize_bugbot_review_presentation_use_case_1 = __nccwpck_require__(31210); +const bugbot_mutation_error_1 = __nccwpck_require__(82937); +const review_projection_1 = __nccwpck_require__(80859); +const bugbot_reconciliation_policy_1 = __nccwpck_require__(78128); +const bugbot_provider_projection_policy_1 = __nccwpck_require__(85821); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const load_bugbot_reconciliation_snapshot_use_case_1 = __nccwpck_require__(44861); +const synchronize_bugbot_review_presentation_use_case_1 = __nccwpck_require__(44491); /** * Orchestrates final Bugbot reconciliation. Provider acquisition, pure state * planning, and presentation mutations are deliberately owned by dedicated @@ -63099,15 +63099,15 @@ function toSafeOperationMessage(error) { /***/ }), -/***/ 52971: +/***/ 17437: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RememberBugbotRuleUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); /** Stores an explicitly approved, repository-versioned Bugbot rule. */ class RememberBugbotRuleUseCase { constructor(rules) { @@ -63142,14 +63142,14 @@ exports.RememberBugbotRuleUseCase = RememberBugbotRuleUseCase; /***/ }), -/***/ 78269: +/***/ 35300: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveIssueFinding = resolveIssueFinding; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); async function resolveIssueFinding(repository, resolution, catalog) { const body = resolution.comment.body; const marker = (0, bugbot_finding_marker_policy_1.parseMarker)(body).find((candidate) => candidate.findingId === resolution.findingId); @@ -63166,15 +63166,15 @@ async function resolveIssueFinding(repository, resolution, catalog) { /***/ }), -/***/ 46024: +/***/ 64567: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolvePullRequestFinding = resolvePullRequestFinding; -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); async function resolvePullRequestFinding(repository, resolution, catalog) { const comments = await repository.listPullRequestReviewComments(resolution.pullRequestNumber); const comment = comments.find((candidate) => candidate.identity === resolution.commentIdentity); @@ -63203,7 +63203,7 @@ async function resolvePullRequestFinding(repository, resolution, catalog) { /***/ }), -/***/ 32668: +/***/ 59828: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -63249,7 +63249,7 @@ function sanitizeUserCommentForPrompt(raw) { /***/ }), -/***/ 54744: +/***/ 16808: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -63261,8 +63261,8 @@ function sanitizeUserCommentForPrompt(raw) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BUGBOT_FIX_INTENT_RESPONSE_SCHEMA = exports.BUGBOT_PARTITION_RESPONSE_SCHEMA = exports.BUGBOT_RESPONSE_SCHEMA = void 0; exports.buildBugbotPartitionResponseSchema = buildBugbotPartitionResponseSchema; -const bugbot_finding_marker_policy_1 = __nccwpck_require__(68304); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); +const bugbot_finding_marker_policy_1 = __nccwpck_require__(98024); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); /** Detection returns findings and explicit lifecycle changes for prior finding IDs. */ exports.BUGBOT_RESPONSE_SCHEMA = { type: 'object', @@ -63399,7 +63399,7 @@ exports.BUGBOT_FIX_INTENT_RESPONSE_SCHEMA = { /***/ }), -/***/ 11135: +/***/ 14626: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -63436,19 +63436,19 @@ function meetsMinSeverity(findingSeverity, minSeverity) { /***/ }), -/***/ 31210: +/***/ 44491: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.synchronizeBugbotReviewPresentation = synchronizeBugbotReviewPresentation; -const application_error_1 = __nccwpck_require__(1889); -const bugbot_review_presentation_policy_1 = __nccwpck_require__(94649); -const bugbot_review_ownership_policy_1 = __nccwpck_require__(51686); -const review_projection_1 = __nccwpck_require__(25952); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_review_presentation_policy_1 = __nccwpck_require__(43799); +const bugbot_review_ownership_policy_1 = __nccwpck_require__(83288); +const review_projection_1 = __nccwpck_require__(80859); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); const REVIEW_UPDATE_BATCH_SIZE = 20; const MAX_REVIEW_UPDATES_PER_RUN = 100; const REVIEW_UPDATE_CONCURRENCY = 4; @@ -63628,7 +63628,7 @@ async function mapWithConcurrency(values, concurrency, operation) { /***/ }), -/***/ 23322: +/***/ 96031: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -63670,7 +63670,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_VERIFY_COMMANDS = void 0; exports.parseVerifyCommand = parseVerifyCommand; exports.limitVerifyCommands = limitVerifyCommands; -const shellQuote = __importStar(__nccwpck_require__(11817)); +const shellQuote = __importStar(__nccwpck_require__(18108)); exports.MAX_VERIFY_COMMANDS = 20; function parseVerifyCommand(cmd) { const trimmed = cmd.trim(); @@ -63696,17 +63696,17 @@ function limitVerifyCommands(commands) { /***/ }), -/***/ 50827: +/***/ 57742: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runVerifyCommands = runVerifyCommands; -const logging_ports_1 = __nccwpck_require__(97793); -const verify_command_policy_1 = __nccwpck_require__(23322); -const verification_runtime_policy_1 = __nccwpck_require__(88201); -const verification_setup_policy_1 = __nccwpck_require__(90620); +const logging_ports_1 = __nccwpck_require__(6152); +const verify_command_policy_1 = __nccwpck_require__(96031); +const verification_runtime_policy_1 = __nccwpck_require__(89347); +const verification_setup_policy_1 = __nccwpck_require__(65326); async function runVerifyCommands(commands, execute) { for (const command of commands) { const result = await executeVerifyCommand(command, execute); @@ -63761,7 +63761,7 @@ function isSensitiveArgumentName(argument) { /***/ }), -/***/ 33363: +/***/ 93370: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -63840,16 +63840,16 @@ async function hasWorkspaceChanges(gitCommitPort) { /***/ }), -/***/ 82845: +/***/ 28356: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckChangesIssueSizeUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const check_changes_issue_size_workflow_1 = __nccwpck_require__(94655); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const check_changes_issue_size_workflow_1 = __nccwpck_require__(43250); class CheckChangesIssueSizeUseCase { constructor(projectBoardCommandPort, issueRepository, pullRequestRepository, branchChangeSizePort, projectMembershipQueryPort) { this.projectBoardCommandPort = projectBoardCommandPort; @@ -63875,17 +63875,17 @@ exports.CheckChangesIssueSizeUseCase = CheckChangesIssueSizeUseCase; /***/ }), -/***/ 94655: +/***/ 43250: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runCheckChangesIssueSize = runCheckChangesIssueSize; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const update_change_size_labels_1 = __nccwpck_require__(7474); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const update_change_size_labels_1 = __nccwpck_require__(51200); +const application_error_1 = __nccwpck_require__(75999); async function runCheckChangesIssueSize(param, taskId, dependencies) { try { const baseBranch = param.baseBranch; @@ -63948,14 +63948,14 @@ function logSize(size, githubSize, reason, currentLabel) { /***/ }), -/***/ 19827: +/***/ 6287: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DetectPotentialProblemsUseCase = void 0; -const detect_potential_problems_workflow_1 = __nccwpck_require__(58282); +const detect_potential_problems_workflow_1 = __nccwpck_require__(37033); /** Application boundary for detecting, publishing and resolving Bugbot findings. */ class DetectPotentialProblemsUseCase { constructor(aiRepository, scm, telemetryPort, catalogResolver) { @@ -63979,30 +63979,30 @@ exports.DetectPotentialProblemsUseCase = DetectPotentialProblemsUseCase; /***/ }), -/***/ 58282: +/***/ 37033: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runDetectPotentialProblemsWorkflow = runDetectPotentialProblemsWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const task_emoji_1 = __nccwpck_require__(8353); -const logging_ports_1 = __nccwpck_require__(97793); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const load_bugbot_context_use_case_1 = __nccwpck_require__(11187); -const bugbot_context_request_1 = __nccwpck_require__(29868); -const apply_detected_findings_1 = __nccwpck_require__(60798); -const bugbot_finding_status_policy_1 = __nccwpck_require__(10264); -const bugbot_review_telemetry_1 = __nccwpck_require__(82658); -const analyze_bugbot_revision_use_case_1 = __nccwpck_require__(7062); -const bugbot_review_freshness_1 = __nccwpck_require__(1415); -const reconcile_bugbot_review_state_use_case_1 = __nccwpck_require__(80398); -const application_error_1 = __nccwpck_require__(1889); -const bugbot_event_ownership_policy_1 = __nccwpck_require__(22322); -const bugbot_message_catalog_1 = __nccwpck_require__(61164); -const bugbot_partition_completion_policy_1 = __nccwpck_require__(54151); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const task_emoji_1 = __nccwpck_require__(46103); +const logging_ports_1 = __nccwpck_require__(6152); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const load_bugbot_context_use_case_1 = __nccwpck_require__(4050); +const bugbot_context_request_1 = __nccwpck_require__(98299); +const apply_detected_findings_1 = __nccwpck_require__(20793); +const bugbot_finding_status_policy_1 = __nccwpck_require__(53822); +const bugbot_review_telemetry_1 = __nccwpck_require__(46790); +const analyze_bugbot_revision_use_case_1 = __nccwpck_require__(4658); +const bugbot_review_freshness_1 = __nccwpck_require__(14307); +const reconcile_bugbot_review_state_use_case_1 = __nccwpck_require__(57515); +const application_error_1 = __nccwpck_require__(75999); +const bugbot_event_ownership_policy_1 = __nccwpck_require__(52771); +const bugbot_message_catalog_1 = __nccwpck_require__(7406); +const bugbot_partition_completion_policy_1 = __nccwpck_require__(57555); const TASK_ID = 'DetectPotentialProblemsUseCase'; /** Coordinates Bugbot context, analysis and finding publication behind application ports. */ async function runDetectPotentialProblemsWorkflow(reviewContext, dependencies) { @@ -64336,15 +64336,15 @@ function resolvePublicationCatalog(operation, dependencies, publishesToPullReque /***/ }), -/***/ 37329: +/***/ 68549: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.checkoutBranch = checkoutBranch; -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); const STASH_MESSAGE = 'bugbot-autofix-before-checkout'; async function hasUncommittedChanges(port) { let output = ''; @@ -64412,16 +64412,16 @@ async function checkedGit(port, args) { /***/ }), -/***/ 95998: +/***/ 33276: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.NotifyNewCommitOnIssueUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const notify_new_commit_on_issue_workflow_1 = __nccwpck_require__(61461); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const notify_new_commit_on_issue_workflow_1 = __nccwpck_require__(46101); class NotifyNewCommitOnIssueUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -64437,16 +64437,16 @@ exports.NotifyNewCommitOnIssueUseCase = NotifyNewCommitOnIssueUseCase; /***/ }), -/***/ 61461: +/***/ 46101: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runNotifyNewCommitOnIssueWorkflow = runNotifyNewCommitOnIssueWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); async function runNotifyNewCommitOnIssueWorkflow(param, taskId, issueRepository) { const result = []; try { @@ -64474,7 +64474,7 @@ async function runNotifyNewCommitOnIssueWorkflow(param, taskId, issueRepository) /***/ }), -/***/ 7474: +/***/ 51200: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -64526,7 +64526,7 @@ function sameLabels(current, next) { /***/ }), -/***/ 82028: +/***/ 19004: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -64538,15 +64538,15 @@ function sameLabels(current, next) { */ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DoUserRequestUseCase = void 0; -const agent_1 = __nccwpck_require__(11066); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const result_1 = __nccwpck_require__(99917); -const project_context_instruction_1 = __nccwpck_require__(55527); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); -const workspace_mutation_guard_1 = __nccwpck_require__(20135); -const application_error_1 = __nccwpck_require__(1889); +const agent_1 = __nccwpck_require__(79937); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const result_1 = __nccwpck_require__(73817); +const project_context_instruction_1 = __nccwpck_require__(63907); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); +const workspace_mutation_guard_1 = __nccwpck_require__(24243); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = "DoUserRequestUseCase"; class DoUserRequestUseCase { constructor(aiRepository, gitCommitPort) { @@ -64643,7 +64643,7 @@ function failure(error) { /***/ }), -/***/ 20135: +/***/ 24243: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -64652,9 +64652,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_AUTOMATED_CHANGED_PATHS = void 0; exports.prepareWorkspaceMutation = prepareWorkspaceMutation; exports.finalizeWorkspaceMutation = finalizeWorkspaceMutation; -const application_error_1 = __nccwpck_require__(1889); -const git_branch_checkout_1 = __nccwpck_require__(37329); -const workspace_changes_1 = __nccwpck_require__(33363); +const application_error_1 = __nccwpck_require__(75999); +const git_branch_checkout_1 = __nccwpck_require__(68549); +const workspace_changes_1 = __nccwpck_require__(93370); exports.MAX_AUTOMATED_CHANGED_PATHS = 100; /** Establishes a clean and deterministic repository boundary before an agent may mutate files. */ async function prepareWorkspaceMutation(gitCommitPort, options) { @@ -64708,15 +64708,15 @@ async function inspectWorkspace(gitCommitPort, phase) { /***/ }), -/***/ 37113: +/***/ 72063: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.extractStructuredAnswer = extractStructuredAnswer; -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const application_error_1 = __nccwpck_require__(1889); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const application_error_1 = __nccwpck_require__(75999); function extractStructuredAnswer(response, targetLocale) { if (response == null) return ''; @@ -64731,16 +64731,16 @@ function extractStructuredAnswer(response, targetLocale) { /***/ }), -/***/ 89969: +/***/ 18846: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckPermissionsUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const check_permissions_workflow_1 = __nccwpck_require__(61273); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const check_permissions_workflow_1 = __nccwpck_require__(17102); class CheckPermissionsUseCase { constructor(organizationMembersPort) { this.organizationMembersPort = organizationMembersPort; @@ -64758,7 +64758,7 @@ exports.CheckPermissionsUseCase = CheckPermissionsUseCase; /***/ }), -/***/ 61273: +/***/ 17102: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -64766,9 +64766,9 @@ exports.CheckPermissionsUseCase = CheckPermissionsUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectCheckPermissionsContext = projectCheckPermissionsContext; exports.runCheckPermissionsWorkflow = runCheckPermissionsWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); function projectCheckPermissionsContext(source) { const issueTarget = source.isIssue; return Object.freeze({ @@ -64832,7 +64832,7 @@ function buildInactiveResult(param, taskId) { /***/ }), -/***/ 59013: +/***/ 72770: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -64841,16 +64841,16 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CommentLanguageTranslationWorkflow = exports.TRANSLATED_COMMENT_MARKER = void 0; exports.projectCommentLanguageRequest = projectCommentLanguageRequest; exports.getCommentLanguageAdaptationPayload = getCommentLanguageAdaptationPayload; -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const comment_translation_policy_1 = __nccwpck_require__(47336); -const locale_1 = __nccwpck_require__(52028); -const application_error_1 = __nccwpck_require__(1889); -var comment_translation_policy_2 = __nccwpck_require__(47336); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const comment_translation_policy_1 = __nccwpck_require__(27150); +const locale_1 = __nccwpck_require__(15386); +const application_error_1 = __nccwpck_require__(75999); +var comment_translation_policy_2 = __nccwpck_require__(27150); Object.defineProperty(exports, "TRANSLATED_COMMENT_MARKER", ({ enumerable: true, get: function () { return comment_translation_policy_2.TRANSLATED_COMMENT_MARKER; } })); function projectCommentLanguageRequest(source) { return Object.freeze({ @@ -64994,7 +64994,7 @@ function languageAdaptationPayload(status, targetLocale, interpretedComment, sou /***/ }), -/***/ 71313: +/***/ 56334: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -65038,7 +65038,7 @@ function toCamelCase(input) { /***/ }), -/***/ 87486: +/***/ 79544: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -65061,14 +65061,14 @@ async function cleanupDuplicateComment(context, comments, sourceIsCurrent) { /***/ }), -/***/ 54053: +/***/ 65440: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildCommitPrefix = buildCommitPrefix; -const commit_prefix_transform_policy_1 = __nccwpck_require__(71313); +const commit_prefix_transform_policy_1 = __nccwpck_require__(56334); function buildCommitPrefix(branchName, transforms, onUnknownTransform) { return transforms .split(',') @@ -65079,18 +65079,18 @@ function buildCommitPrefix(branchName, transforms, onUnknownTransform) { /***/ }), -/***/ 60883: +/***/ 59946: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GetHotfixVersionUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class GetHotfixVersionUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -65171,18 +65171,18 @@ function isPositiveIssueNumber(value) { /***/ }), -/***/ 69804: +/***/ 64410: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GetReleaseTypeUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class GetReleaseTypeUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -65252,18 +65252,18 @@ function isPositiveIssueNumber(value) { /***/ }), -/***/ 6769: +/***/ 70587: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GetReleaseVersionUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class GetReleaseVersionUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -65334,7 +65334,7 @@ function isPositiveIssueNumber(value) { /***/ }), -/***/ 63457: +/***/ 89064: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65343,10 +65343,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectIssueContentLinkContext = projectIssueContentLinkContext; exports.projectPullRequestContentLinkContext = projectPullRequestContentLinkContext; exports.runProjectContentLinkWorkflow = runProjectContentLinkWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); function projectIssueContentLinkContext(source) { return projectContext(source, 'issue', source.issue.number, source.project.getProjectColumnIssueCreated()); } @@ -65428,16 +65428,16 @@ function capitalize(value) { /***/ }), -/***/ 93987: +/***/ 58684: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PublishResultUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const publish_resume_workflow_1 = __nccwpck_require__(88490); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const publish_resume_workflow_1 = __nccwpck_require__(55340); class PublishResultUseCase { constructor(comments, catalogResolver, sourceQuery, requestRead) { this.comments = comments; @@ -65456,7 +65456,7 @@ exports.PublishResultUseCase = PublishResultUseCase; /***/ }), -/***/ 88490: +/***/ 55340: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65464,16 +65464,16 @@ exports.PublishResultUseCase = PublishResultUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectPublishResultContext = projectPublishResultContext; exports.runPublishResume = runPublishResume; -const reply_request_digest_1 = __nccwpck_require__(73250); -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const semantic_result_publication_policy_1 = __nccwpck_require__(78334); -const application_error_1 = __nccwpck_require__(1889); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const reply_publication_workflow_1 = __nccwpck_require__(99249); -const status_card_publication_workflow_1 = __nccwpck_require__(53032); -const publication_message_catalog_1 = __nccwpck_require__(92221); -const publication_outcome_policy_1 = __nccwpck_require__(45483); +const reply_request_digest_1 = __nccwpck_require__(47971); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const semantic_result_publication_policy_1 = __nccwpck_require__(81985); +const application_error_1 = __nccwpck_require__(75999); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const reply_publication_workflow_1 = __nccwpck_require__(22824); +const status_card_publication_workflow_1 = __nccwpck_require__(62963); +const publication_message_catalog_1 = __nccwpck_require__(34223); +const publication_outcome_policy_1 = __nccwpck_require__(79719); function projectPublishResultContext(source) { const target = publicationTarget(source); const requestSource = requestSnapshot(source, target); @@ -65634,19 +65634,19 @@ function requestSnapshot(source, target) { /***/ }), -/***/ 99249: +/***/ 22824: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileReply = reconcileReply; -const github_publication_1 = __nccwpck_require__(16812); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const publication_message_catalog_1 = __nccwpck_require__(92221); -const semantic_result_publication_policy_1 = __nccwpck_require__(78334); -const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(87486); +const github_publication_1 = __nccwpck_require__(35793); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const publication_message_catalog_1 = __nccwpck_require__(34223); +const semantic_result_publication_policy_1 = __nccwpck_require__(81985); +const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(79544); /** Publishes trusted correlated replies and refreshes verified read-only projections. */ async function reconcileReply(context, comments, requestRead) { if (!context.botLogin.trim()) @@ -65753,20 +65753,20 @@ function duplicatePointer(context, canonicalCommentId) { /***/ }), -/***/ 53032: +/***/ 62963: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.reconcileStatusCard = reconcileStatusCard; -const github_publication_1 = __nccwpck_require__(16812); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const publication_message_catalog_1 = __nccwpck_require__(92221); -const semantic_result_publication_policy_1 = __nccwpck_require__(78334); -const application_error_1 = __nccwpck_require__(1889); -const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(87486); +const github_publication_1 = __nccwpck_require__(35793); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const publication_message_catalog_1 = __nccwpck_require__(34223); +const semantic_result_publication_policy_1 = __nccwpck_require__(81985); +const application_error_1 = __nccwpck_require__(75999); +const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(79544); async function reconcileStatusCard(context, comments, sourceQuery) { if (!context.botLogin.trim()) return unchangedOutcome(); @@ -65879,7 +65879,7 @@ function duplicatePointer(context, canonicalCommentId) { /***/ }), -/***/ 49352: +/***/ 84375: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -65887,9 +65887,9 @@ function duplicatePointer(context, canonicalCommentId) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.StoreConfigurationUseCase = void 0; exports.projectConfigurationPersistenceContext = projectConfigurationPersistenceContext; -const application_error_1 = __nccwpck_require__(1889); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); +const application_error_1 = __nccwpck_require__(75999); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); function projectConfigurationPersistenceContext(source) { const issueNumber = resolveWriteIssueNumber(source); if (issueNumber === undefined) @@ -65963,25 +65963,25 @@ function clonePlainValue(value) { /***/ }), -/***/ 47041: +/***/ 40558: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runThinkAnswerWorkflow = runThinkAnswerWorkflow; -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const project_context_instruction_1 = __nccwpck_require__(55527); -const agent_answer_policy_1 = __nccwpck_require__(37113); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); -const recommend_steps_result_policy_1 = __nccwpck_require__(23139); -const recommend_steps_workflow_1 = __nccwpck_require__(3298); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const project_context_instruction_1 = __nccwpck_require__(63907); +const agent_answer_policy_1 = __nccwpck_require__(72063); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); +const recommend_steps_result_policy_1 = __nccwpck_require__(65928); +const recommend_steps_workflow_1 = __nccwpck_require__(77522); async function runThinkAnswerWorkflow(param, taskId, request, dependencies) { const issueDescription = await loadIssueDescription(request.issueNumberForContext, dependencies.issueDescriptionQueryPort); const contextBlock = issueDescription @@ -66078,7 +66078,7 @@ async function queryThinkAnswer(param, prompt, repository, targetLocale) { /***/ }), -/***/ 84440: +/***/ 59687: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -66101,7 +66101,7 @@ function extractMentionQuestion(commentBody, tokenUser) { /***/ }), -/***/ 9106: +/***/ 23995: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66109,10 +66109,10 @@ function extractMentionQuestion(commentBody, tokenUser) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.resolveThinkRequest = resolveThinkRequest; exports.buildExplicitCommandQuestion = buildExplicitCommandQuestion; -const copilot_command_1 = __nccwpck_require__(28057); -const copilot_comment_request_1 = __nccwpck_require__(16602); -const think_input_policy_1 = __nccwpck_require__(84440); -const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(32668); +const copilot_command_1 = __nccwpck_require__(11771); +const copilot_comment_request_1 = __nccwpck_require__(86819); +const think_input_policy_1 = __nccwpck_require__(59687); +const sanitize_user_comment_for_prompt_1 = __nccwpck_require__(59828); /** Resolves the comment input and destination without performing I/O. */ function resolveThinkRequest(param) { const commentBody = (0, think_input_policy_1.getThinkCommentBody)({ @@ -66175,14 +66175,14 @@ function buildExplicitCommandQuestion(command) { /***/ }), -/***/ 13654: +/***/ 89255: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ThinkUseCase = void 0; -const think_workflow_1 = __nccwpck_require__(84106); +const think_workflow_1 = __nccwpck_require__(36450); class ThinkUseCase { constructor(issueDescriptionQueryPort, aiRepository) { this.issueDescriptionQueryPort = issueDescriptionQueryPort; @@ -66201,7 +66201,7 @@ exports.ThinkUseCase = ThinkUseCase; /***/ }), -/***/ 84106: +/***/ 36450: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66209,14 +66209,14 @@ exports.ThinkUseCase = ThinkUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.projectThinkContext = projectThinkContext; exports.runThinkWorkflow = runThinkWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const think_request_policy_1 = __nccwpck_require__(9106); -const think_answer_workflow_1 = __nccwpck_require__(47041); -const agent_task_policy_1 = __nccwpck_require__(34816); -const application_error_1 = __nccwpck_require__(1889); -const locale_1 = __nccwpck_require__(52028); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const think_request_policy_1 = __nccwpck_require__(23995); +const think_answer_workflow_1 = __nccwpck_require__(40558); +const agent_task_policy_1 = __nccwpck_require__(85712); +const application_error_1 = __nccwpck_require__(75999); +const locale_1 = __nccwpck_require__(15386); function projectThinkContext(source) { const request = (0, think_request_policy_1.resolveThinkRequest)(source); const tokenUser = source.tokenUser?.trim(); @@ -66300,7 +66300,7 @@ function logSkipReason(reason, tokenUser) { /***/ }), -/***/ 59833: +/***/ 1725: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66309,10 +66309,10 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MAX_TRANSITION_NOTIFICATION_LINKS = exports.MAX_TRANSITION_NOTIFICATION_CHARACTERS = void 0; exports.reconcileTransitionNotification = reconcileTransitionNotification; exports.renderTransitionNotification = renderTransitionNotification; -const github_publication_1 = __nccwpck_require__(16812); -const github_user_policy_1 = __nccwpck_require__(84900); -const publication_identity_policy_1 = __nccwpck_require__(17167); -const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(87486); +const github_publication_1 = __nccwpck_require__(35793); +const github_user_policy_1 = __nccwpck_require__(84403); +const publication_identity_policy_1 = __nccwpck_require__(45403); +const duplicate_comment_cleanup_workflow_1 = __nccwpck_require__(79544); exports.MAX_TRANSITION_NOTIFICATION_CHARACTERS = 400; exports.MAX_TRANSITION_NOTIFICATION_LINKS = 2; /** Creates one immutable action notification per exact transition fingerprint. */ @@ -66399,16 +66399,16 @@ function outcome(effect, canonicalCommentId, duplicatesRemoved = 0, duplicatesCo /***/ }), -/***/ 32153: +/***/ 20556: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.UpdateTitleUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const update_title_workflow_1 = __nccwpck_require__(12039); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const update_title_workflow_1 = __nccwpck_require__(50029); class UpdateTitleUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -66433,7 +66433,7 @@ exports.UpdateTitleUseCase = UpdateTitleUseCase; /***/ }), -/***/ 12039: +/***/ 50029: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -66443,10 +66443,10 @@ exports.projectUpdateTitleContext = projectUpdateTitleContext; exports.runIssueTitleUpdate = runIssueTitleUpdate; exports.runPullRequestTitleUpdate = runPullRequestTitleUpdate; exports.titleUpdateFailure = titleUpdateFailure; -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const pull_request_title_policy_1 = __nccwpck_require__(94675); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const pull_request_title_policy_1 = __nccwpck_require__(59756); function projectUpdateTitleContext(source) { if (source.isIssue) { return Object.freeze({ @@ -66556,14 +66556,14 @@ function skippedResult(taskId) { /***/ }), -/***/ 77732: +/***/ 10706: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AnswerIssueHelpUseCase = void 0; -const answer_issue_help_workflow_1 = __nccwpck_require__(70249); +const answer_issue_help_workflow_1 = __nccwpck_require__(86428); /** Application boundary for the initial response to question/help issues. */ class AnswerIssueHelpUseCase { constructor(aiRepository) { @@ -66581,25 +66581,25 @@ exports.AnswerIssueHelpUseCase = AnswerIssueHelpUseCase; /***/ }), -/***/ 70249: +/***/ 86428: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runAnswerIssueHelpWorkflow = runAnswerIssueHelpWorkflow; -const agent_1 = __nccwpck_require__(11066); -const result_1 = __nccwpck_require__(99917); -const agent_task_policy_1 = __nccwpck_require__(34816); -const agent_response_schemas_1 = __nccwpck_require__(49561); -const prompts_1 = __nccwpck_require__(10966); -const logging_ports_1 = __nccwpck_require__(97793); -const project_context_instruction_1 = __nccwpck_require__(55527); -const task_emoji_1 = __nccwpck_require__(8353); -const agent_answer_policy_1 = __nccwpck_require__(37113); -const github_comment_publication_policy_1 = __nccwpck_require__(27104); -const application_error_1 = __nccwpck_require__(1889); -const agent_output_locale_policy_1 = __nccwpck_require__(48114); +const agent_1 = __nccwpck_require__(79937); +const result_1 = __nccwpck_require__(73817); +const agent_task_policy_1 = __nccwpck_require__(85712); +const agent_response_schemas_1 = __nccwpck_require__(25603); +const prompts_1 = __nccwpck_require__(69518); +const logging_ports_1 = __nccwpck_require__(6152); +const project_context_instruction_1 = __nccwpck_require__(63907); +const task_emoji_1 = __nccwpck_require__(46103); +const agent_answer_policy_1 = __nccwpck_require__(72063); +const github_comment_publication_policy_1 = __nccwpck_require__(72712); +const application_error_1 = __nccwpck_require__(75999); +const agent_output_locale_policy_1 = __nccwpck_require__(30601); const TASK_ID = 'AnswerIssueHelpUseCase'; /** Posts one contextual answer for a newly opened question/help issue. */ async function runAnswerIssueHelpWorkflow(param, dependencies) { @@ -66684,14 +66684,14 @@ function skipped() { /***/ }), -/***/ 75855: +/***/ 55523: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AssignMemberToIssueUseCase = void 0; -const assign_members_workflow_1 = __nccwpck_require__(88740); +const assign_members_workflow_1 = __nccwpck_require__(42343); /** Application boundary for assigning issue or pull-request members. */ class AssignMemberToIssueUseCase { constructor(issueRepository, projectRepository) { @@ -66711,18 +66711,18 @@ exports.AssignMemberToIssueUseCase = AssignMemberToIssueUseCase; /***/ }), -/***/ 88740: +/***/ 42343: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runAssignMembersWorkflow = runAssignMembersWorkflow; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const assignee_assignment_policy_1 = __nccwpck_require__(13382); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const assignee_assignment_policy_1 = __nccwpck_require__(85918); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = 'AssignMemberToIssueUseCase'; /** Assigns the creator and remaining project members according to the pure assignment policy. */ async function runAssignMembersWorkflow(param, dependencies) { @@ -66785,14 +66785,14 @@ function assignmentResult(success, step) { /***/ }), -/***/ 40069: +/***/ 80174: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.AssignReviewersToIssueUseCase = void 0; -const assign_reviewers_workflow_1 = __nccwpck_require__(15946); +const assign_reviewers_workflow_1 = __nccwpck_require__(97260); /** Application boundary for requesting the configured number of reviewers. */ class AssignReviewersToIssueUseCase { constructor(issueRepository, pullRequestRepository, projectRepository) { @@ -66814,19 +66814,19 @@ exports.AssignReviewersToIssueUseCase = AssignReviewersToIssueUseCase; /***/ }), -/***/ 15946: +/***/ 97260: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runAssignReviewersWorkflow = runAssignReviewersWorkflow; -const result_1 = __nccwpck_require__(99917); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const reviewer_assignment_policy_1 = __nccwpck_require__(44551); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const reviewer_assignment_policy_1 = __nccwpck_require__(88350); +const application_error_1 = __nccwpck_require__(75999); const TASK_ID = 'AssignReviewersToIssueUseCase'; /** Selects and requests reviewers without coupling the use-case boundary to GitHub. */ async function runAssignReviewersWorkflow(param, dependencies) { @@ -66906,7 +66906,7 @@ function failureResult(step) { /***/ }), -/***/ 61333: +/***/ 29988: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -66928,16 +66928,16 @@ function selectBranchPreparationStrategy(flags) { /***/ }), -/***/ 32086: +/***/ 19511: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckPriorityIssueSizeUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const priority_size_check_use_case_1 = __nccwpck_require__(14461); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const priority_size_check_use_case_1 = __nccwpck_require__(98060); class CheckPriorityIssueSizeUseCase { constructor(projectBoardPriorityPort) { this.projectBoardPriorityPort = projectBoardPriorityPort; @@ -66953,19 +66953,19 @@ exports.CheckPriorityIssueSizeUseCase = CheckPriorityIssueSizeUseCase; /***/ }), -/***/ 29162: +/***/ 46753: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CloseIssueAfterMergingUseCase = void 0; -const reconcile_issue_completion_metadata_1 = __nccwpck_require__(73082); -const closed_issue_reconciliation_error_1 = __nccwpck_require__(90102); -const result_1 = __nccwpck_require__(99917); -const issue_completion_1 = __nccwpck_require__(28272); -const application_error_1 = __nccwpck_require__(1889); -const positive_integer_policy_1 = __nccwpck_require__(20889); +const reconcile_issue_completion_metadata_1 = __nccwpck_require__(70614); +const closed_issue_reconciliation_error_1 = __nccwpck_require__(12183); +const result_1 = __nccwpck_require__(73817); +const issue_completion_1 = __nccwpck_require__(31147); +const application_error_1 = __nccwpck_require__(75999); +const positive_integer_policy_1 = __nccwpck_require__(19879); /** Native completion first, selective metadata second; retained effects survive partial failures. */ class CloseIssueAfterMergingUseCase { constructor(issues) { @@ -67030,17 +67030,17 @@ function stale() { /***/ }), -/***/ 34873: +/***/ 86675: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CloseNotAllowedIssueUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class CloseNotAllowedIssueUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -67091,18 +67091,18 @@ exports.CloseNotAllowedIssueUseCase = CloseNotAllowedIssueUseCase; /***/ }), -/***/ 8946: +/***/ 33445: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runDeployAddedWorkflow = runDeployAddedWorkflow; -const result_1 = __nccwpck_require__(99917); -const content_utils_1 = __nccwpck_require__(88469); -const logging_ports_1 = __nccwpck_require__(97793); -const deploy_workflow_policy_1 = __nccwpck_require__(25643); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const content_utils_1 = __nccwpck_require__(92816); +const logging_ports_1 = __nccwpck_require__(6152); +const deploy_workflow_policy_1 = __nccwpck_require__(8428); +const application_error_1 = __nccwpck_require__(75999); async function runDeployAddedWorkflow(param, taskId, branchWorkflowPort, moveIssueToInProgressUseCase) { const plan = (0, deploy_workflow_policy_1.resolveDeployWorkflowPlan)(param); if (!plan) @@ -67145,16 +67145,16 @@ async function runDeployAddedWorkflow(param, taskId, branchWorkflowPort, moveIss /***/ }), -/***/ 60664: +/***/ 27708: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeployAddedUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const deploy_added_workflow_1 = __nccwpck_require__(8946); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const deploy_added_workflow_1 = __nccwpck_require__(33445); class DeployAddedUseCase { constructor(branchWorkflowPort, moveIssueToInProgressUseCase) { this.branchWorkflowPort = branchWorkflowPort; @@ -67171,14 +67171,14 @@ exports.DeployAddedUseCase = DeployAddedUseCase; /***/ }), -/***/ 43618: +/***/ 34100: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.LinkIssueProjectUseCase = void 0; -const project_content_link_workflow_1 = __nccwpck_require__(63457); +const project_content_link_workflow_1 = __nccwpck_require__(89064); /** Application boundary for linking issues to configured ProjectV2 boards. */ class LinkIssueProjectUseCase { constructor(projectContentPort) { @@ -67194,17 +67194,17 @@ exports.LinkIssueProjectUseCase = LinkIssueProjectUseCase; /***/ }), -/***/ 40595: +/***/ 52309: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.MoveIssueToInProgressUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class MoveIssueToInProgressUseCase { constructor(projectRepository) { this.projectRepository = projectRepository; @@ -67250,22 +67250,22 @@ exports.MoveIssueToInProgressUseCase = MoveIssueToInProgressUseCase; /***/ }), -/***/ 66701: +/***/ 67546: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PrepareBranchesUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const branch_preparation_strategy_1 = __nccwpck_require__(61333); -const prepare_managed_branch_1 = __nccwpck_require__(83340); -const prepare_hotfix_branch_1 = __nccwpck_require__(45200); -const prepare_release_branch_1 = __nccwpck_require__(19251); -const application_error_1 = __nccwpck_require__(1889); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const branch_preparation_strategy_1 = __nccwpck_require__(29988); +const prepare_managed_branch_1 = __nccwpck_require__(29928); +const prepare_hotfix_branch_1 = __nccwpck_require__(96318); +const prepare_release_branch_1 = __nccwpck_require__(83059); +const application_error_1 = __nccwpck_require__(75999); +const issue_workflow_context_1 = __nccwpck_require__(98005); class PrepareBranchesUseCase { constructor(branchListQueryPort, branchNamePort, remoteBranchSyncPort, commitTagQueryPort, linkedBranchCommandPort, branchPropagationDelayPort, moveIssueToInProgressUseCase) { this.branchListQueryPort = branchListQueryPort; @@ -67343,16 +67343,16 @@ exports.PrepareBranchesUseCase = PrepareBranchesUseCase; /***/ }), -/***/ 45200: +/***/ 96318: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareHotfixBranch = prepareHotfixBranch; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const issue_workflow_context_1 = __nccwpck_require__(98005); async function prepareHotfixBranch(param, commitTagQuery, linkedBranchCommand, branches, taskId) { const { hotfix } = param; if (hotfix.baseVersion === undefined || @@ -67412,20 +67412,20 @@ async function prepareHotfixBranch(param, commitTagQuery, linkedBranchCommand, b /***/ }), -/***/ 83340: +/***/ 29928: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareManagedBranch = prepareManagedBranch; -const result_1 = __nccwpck_require__(99917); -const branch_preparation_policy_1 = __nccwpck_require__(51843); -const managed_branch_result_policy_1 = __nccwpck_require__(49744); -const logging_ports_1 = __nccwpck_require__(97793); -const application_error_1 = __nccwpck_require__(1889); -const execute_script_use_case_1 = __nccwpck_require__(54053); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const branch_preparation_policy_1 = __nccwpck_require__(97307); +const managed_branch_result_policy_1 = __nccwpck_require__(55078); +const logging_ports_1 = __nccwpck_require__(6152); +const application_error_1 = __nccwpck_require__(75999); +const execute_script_use_case_1 = __nccwpck_require__(65440); +const issue_workflow_context_1 = __nccwpck_require__(98005); async function prepareManagedBranch(param, issueTitle, branches, taskId, dependencies) { (0, logging_ports_1.logDebugInfo)(`Branch type: ${param.managementBranch}`); const decision = (0, branch_preparation_policy_1.decideManagedBranchPreparation)({ @@ -67509,17 +67509,17 @@ async function buildConfiguredCommitPrefix(param, branchName) { /***/ }), -/***/ 19251: +/***/ 83059: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.prepareReleaseBranch = prepareReleaseBranch; -const result_1 = __nccwpck_require__(99917); -const execute_script_use_case_1 = __nccwpck_require__(54053); -const logging_ports_1 = __nccwpck_require__(97793); -const issue_workflow_context_1 = __nccwpck_require__(85450); +const result_1 = __nccwpck_require__(73817); +const execute_script_use_case_1 = __nccwpck_require__(65440); +const logging_ports_1 = __nccwpck_require__(6152); +const issue_workflow_context_1 = __nccwpck_require__(98005); async function prepareReleaseBranch(param, linkedBranchCommand, branches, taskId) { const { release } = param; if (release.version === undefined || release.branch === undefined) { @@ -67609,7 +67609,7 @@ function buildReleaseReminder(param, releaseUrl, developmentUrl, mainUrl) { /***/ }), -/***/ 14549: +/***/ 16530: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -67628,17 +67628,17 @@ function resolveGithubPriorityLabel(priority, labels) { /***/ }), -/***/ 14461: +/***/ 98060: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.runPrioritySizeCheck = runPrioritySizeCheck; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const priority_label_policy_1 = __nccwpck_require__(14549); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const priority_label_policy_1 = __nccwpck_require__(16530); +const application_error_1 = __nccwpck_require__(75999); async function runPrioritySizeCheck(param, taskId, projectRepository) { try { return await applyPriorityToProjects(param, taskId, projectRepository); @@ -67684,16 +67684,16 @@ async function applyPriorityToProjects(param, taskId, projectRepository) { /***/ }), -/***/ 52139: +/***/ 71836: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReconcileBranchReadinessUseCase = void 0; -const issue_start_policy_1 = __nccwpck_require__(59704); -const result_1 = __nccwpck_require__(99917); -const application_error_1 = __nccwpck_require__(1889); +const issue_start_policy_1 = __nccwpck_require__(90332); +const result_1 = __nccwpck_require__(73817); +const application_error_1 = __nccwpck_require__(75999); /** Projects verified remote facts into the managed `branched` output label. */ class ReconcileBranchReadinessUseCase { constructor(linkedBranch, labels) { @@ -67767,7 +67767,7 @@ exports.ReconcileBranchReadinessUseCase = ReconcileBranchReadinessUseCase; /***/ }), -/***/ 97165: +/***/ 57836: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -67785,18 +67785,18 @@ function selectIssueBranchesToRemove(branches, issueNumber, branchTypes) { /***/ }), -/***/ 93132: +/***/ 15608: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RemoveIssueBranchesUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const remove_issue_branches_policy_1 = __nccwpck_require__(97165); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const remove_issue_branches_policy_1 = __nccwpck_require__(57836); +const application_error_1 = __nccwpck_require__(75999); /** * Remove any branch created for this issue */ @@ -67860,17 +67860,17 @@ async function removeIssueBranch(param, taskId, branchName, branchLifecyclePort) /***/ }), -/***/ 33081: +/***/ 67129: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RemoveNotNeededBranchesUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class RemoveNotNeededBranchesUseCase { constructor(branchLifecyclePort, branchNamePort) { this.branchLifecyclePort = branchLifecyclePort; @@ -67954,16 +67954,16 @@ exports.RemoveNotNeededBranchesUseCase = RemoveNotNeededBranchesUseCase; /***/ }), -/***/ 50561: +/***/ 27065: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ResumeIssueProjectUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const issue_start_policy_1 = __nccwpck_require__(59704); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const issue_start_policy_1 = __nccwpck_require__(90332); +const application_error_1 = __nccwpck_require__(75999); /** Restore active Project state before other field writes can retrigger native autoclose. */ class ResumeIssueProjectUseCase { constructor(native, projects) { @@ -68008,17 +68008,17 @@ exports.ResumeIssueProjectUseCase = ResumeIssueProjectUseCase; /***/ }), -/***/ 40425: +/***/ 38222: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.UpdateIssueTypeUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const application_error_1 = __nccwpck_require__(75999); class UpdateIssueTypeUseCase { constructor(issueRepository) { this.issueRepository = issueRepository; @@ -68051,7 +68051,7 @@ exports.UpdateIssueTypeUseCase = UpdateIssueTypeUseCase; /***/ }), -/***/ 55111: +/***/ 93152: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -68059,7 +68059,7 @@ exports.UpdateIssueTypeUseCase = UpdateIssueTypeUseCase; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckIssueCommentLanguageUseCase = void 0; exports.projectIssueCommentLanguageRequest = projectIssueCommentLanguageRequest; -const comment_language_translation_workflow_1 = __nccwpck_require__(59013); +const comment_language_translation_workflow_1 = __nccwpck_require__(72770); function projectIssueCommentLanguageRequest(source) { return (0, comment_language_translation_workflow_1.projectCommentLanguageRequest)({ commentBody: source.issue.commentBody, @@ -68087,16 +68087,16 @@ exports.CheckIssueCommentLanguageUseCase = CheckIssueCommentLanguageUseCase; /***/ }), -/***/ 73146: +/***/ 12738: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.CheckPriorityPullRequestSizeUseCase = void 0; -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const priority_size_check_use_case_1 = __nccwpck_require__(14461); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const priority_size_check_use_case_1 = __nccwpck_require__(98060); class CheckPriorityPullRequestSizeUseCase { constructor(projectBoardPriorityPort) { this.projectBoardPriorityPort = projectBoardPriorityPort; @@ -68112,18 +68112,18 @@ exports.CheckPriorityPullRequestSizeUseCase = CheckPriorityPullRequestSizeUseCas /***/ }), -/***/ 62249: +/***/ 38259: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.LinkPullRequestIssueUseCase = void 0; -const result_1 = __nccwpck_require__(99917); -const logging_ports_1 = __nccwpck_require__(97793); -const task_emoji_1 = __nccwpck_require__(8353); -const link_pull_request_issue_workflow_1 = __nccwpck_require__(46667); -const application_error_1 = __nccwpck_require__(1889); +const result_1 = __nccwpck_require__(73817); +const logging_ports_1 = __nccwpck_require__(6152); +const task_emoji_1 = __nccwpck_require__(46103); +const link_pull_request_issue_workflow_1 = __nccwpck_require__(19033); +const application_error_1 = __nccwpck_require__(75999); class LinkPullRequestIssueUseCase { constructor(pullRequestIssueLinkPort, eventualConsistencyDelayPort) { this.pullRequestIssueLinkPort = pullRequestIssueLinkPort; @@ -68180,7 +68180,7 @@ function describeRecovery(error) { /***/ }), -/***/ 46667: +/***/ 19033: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -68188,9 +68188,9 @@ function describeRecovery(error) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestIssueLinkOperationError = void 0; exports.runLinkPullRequestIssue = runLinkPullRequestIssue; -const result_1 = __nccwpck_require__(99917); -const positive_integer_policy_1 = __nccwpck_require__(20889); -const deployment_configuration_1 = __nccwpck_require__(86193); +const result_1 = __nccwpck_require__(73817); +const positive_integer_policy_1 = __nccwpck_require__(19879); +const deployment_configuration_1 = __nccwpck_require__(22495); const LINK_MARKER_PREFIX = '/iu; function resolveOpenBranchDependencies(issues, pullRequests) { const candidates = []; @@ -72880,14 +72880,14 @@ function uniqueValidDependencies(candidates) { /***/ }), -/***/ 35105: +/***/ 9627: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BranchDependencyRepository = void 0; -const branch_dependency_policy_1 = __nccwpck_require__(19657); +const branch_dependency_policy_1 = __nccwpck_require__(54874); const OPEN_DEPENDENCIES_QUERY = ` query BranchSyncDependencies($owner: String!, $repo: String!, $issuesCursor: String, $pullsCursor: String) { repository(owner: $owner, name: $repo) { @@ -73006,7 +73006,7 @@ function withCause(message, cause) { /***/ }), -/***/ 78396: +/***/ 92351: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -73038,7 +73038,7 @@ exports.CopilotEvidenceRepository = CopilotEvidenceRepository; /***/ }), -/***/ 98162: +/***/ 77509: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -73063,7 +73063,7 @@ exports.DeploymentContinuationRepository = DeploymentContinuationRepository; /***/ }), -/***/ 9736: +/***/ 91985: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -73100,17 +73100,17 @@ exports.DeploymentPresentationRepository = DeploymentPresentationRepository; /***/ }), -/***/ 37303: +/***/ 3182: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.DeploymentStateRepositoryFactory = void 0; -const deployment_state_fence_1 = __nccwpck_require__(78892); -const config_1 = __nccwpck_require__(29657); -const configuration_handler_1 = __nccwpck_require__(64706); -const configuration_payload_policy_1 = __nccwpck_require__(69623); +const deployment_state_fence_1 = __nccwpck_require__(72369); +const config_1 = __nccwpck_require__(90450); +const configuration_handler_1 = __nccwpck_require__(40188); +const configuration_payload_policy_1 = __nccwpck_require__(58043); class DeploymentStateRepositoryFactory { constructor(issues) { this.issues = issues; @@ -73179,14 +73179,14 @@ function isRecord(value) { /***/ }), -/***/ 22985: +/***/ 85886: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubDeploymentGitRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); class GithubDeploymentGitRepository { constructor(clientProvider) { this.clientProvider = clientProvider; @@ -73299,14 +73299,14 @@ function isNotFound(error) { /***/ }), -/***/ 8464: +/***/ 30873: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.githubDeploymentMergeError = githubDeploymentMergeError; -const deployment_merge_effect_error_1 = __nccwpck_require__(90452); +const deployment_merge_effect_error_1 = __nccwpck_require__(72594); /** Never copy provider messages, request objects, headers, or arbitrary error types into public state. */ function githubDeploymentMergeError(action, cause) { const value = isRecord(cause) ? cause : {}; @@ -73340,16 +73340,16 @@ function isRecord(value) { /***/ }), -/***/ 35255: +/***/ 96483: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubManagedPullRequestRepository = void 0; -const managed_pull_request_1 = __nccwpck_require__(59565); -const github_deployment_merge_error_1 = __nccwpck_require__(8464); -const deployment_merge_effect_error_1 = __nccwpck_require__(90452); +const managed_pull_request_1 = __nccwpck_require__(95914); +const github_deployment_merge_error_1 = __nccwpck_require__(30873); +const deployment_merge_effect_error_1 = __nccwpck_require__(72594); class GithubManagedPullRequestRepository { constructor(clientProvider) { this.clientProvider = clientProvider; @@ -73466,7 +73466,7 @@ function mapPullRequest(value, owner, repository) { /***/ }), -/***/ 48660: +/***/ 33371: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -73503,7 +73503,7 @@ async function observePullRequestReadiness(client, owner, repository, pullReques /***/ }), -/***/ 52662: +/***/ 55527: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -73543,8 +73543,8 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubTargetMergeCapabilitiesInspector = void 0; -const yaml = __importStar(__nccwpck_require__(49278)); -const github_pull_request_readiness_query_1 = __nccwpck_require__(48660); +const yaml = __importStar(__nccwpck_require__(783)); +const github_pull_request_readiness_query_1 = __nccwpck_require__(33371); class GithubTargetMergeCapabilitiesInspector { constructor(clientProvider) { this.clientProvider = clientProvider; @@ -74126,7 +74126,7 @@ function isNotFound(error) { /***/ }), -/***/ 83506: +/***/ 26331: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -74166,11 +74166,11 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GitCliRepository = void 0; -const exec = __importStar(__nccwpck_require__(4750)); -const logger_1 = __nccwpck_require__(58738); -const version_policy_1 = __nccwpck_require__(36071); -const git_authentication_environment_1 = __nccwpck_require__(49964); -const application_error_1 = __nccwpck_require__(1889); +const exec = __importStar(__nccwpck_require__(18538)); +const logger_1 = __nccwpck_require__(91151); +const version_policy_1 = __nccwpck_require__(8381); +const git_authentication_environment_1 = __nccwpck_require__(16535); +const application_error_1 = __nccwpck_require__(75999); /** * Repository for Git operations executed via CLI (exec). * Isolated to allow unit tests with mocked @actions/exec. @@ -74269,7 +74269,7 @@ exports.GitCliRepository = GitCliRepository; /***/ }), -/***/ 47976: +/***/ 57628: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -74277,8 +74277,8 @@ exports.GitCliRepository = GitCliRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.inspectMissingCredentialHealthWorkflow = inspectMissingCredentialHealthWorkflow; exports.inspectCredentialHealthWorkflowAtRef = inspectCredentialHealthWorkflowAtRef; -const setup_workflow_catalog_1 = __nccwpck_require__(53376); -const github_error_policy_1 = __nccwpck_require__(67160); +const setup_workflow_catalog_1 = __nccwpck_require__(24596); +const github_error_policy_1 = __nccwpck_require__(58791); /** A workflow API 404 is confirmed absence only after two independent Contents reads. */ async function inspectMissingCredentialHealthWorkflow(getContent, owner, repository, ref) { const state = await inspectCredentialHealthWorkflowAtRef(getContent, owner, repository, ref); @@ -74316,7 +74316,7 @@ async function inspectCredentialHealthWorkflowAtRef(getContent, owner, repositor /***/ }), -/***/ 47947: +/***/ 81189: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -74341,16 +74341,16 @@ async function listCollection(client, method, parameters, key) { /***/ }), -/***/ 10618: +/***/ 71301: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubActionsResourceCommands = void 0; -const github_secret_encryption_1 = __nccwpck_require__(47654); -const github_actions_resource_collection_1 = __nccwpck_require__(47947); -const github_error_policy_1 = __nccwpck_require__(67160); +const github_secret_encryption_1 = __nccwpck_require__(83725); +const github_actions_resource_collection_1 = __nccwpck_require__(81189); +const github_error_policy_1 = __nccwpck_require__(58791); /** GitHub Actions Secret encryption and scope-preserving resource writes. */ class GithubActionsResourceCommands { constructor(githubClient) { @@ -74550,18 +74550,18 @@ function variableWriteFailure(name, scope, phase, error) { /***/ }), -/***/ 82410: +/***/ 96558: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubActionsResourceInspector = void 0; -const setup_workflow_catalog_1 = __nccwpck_require__(53376); -const deployment_configuration_1 = __nccwpck_require__(86193); -const github_error_policy_1 = __nccwpck_require__(67160); -const credential_health_workflow_visibility_1 = __nccwpck_require__(47976); -const github_actions_resource_collection_1 = __nccwpck_require__(47947); +const setup_workflow_catalog_1 = __nccwpck_require__(24596); +const deployment_configuration_1 = __nccwpck_require__(22495); +const github_error_policy_1 = __nccwpck_require__(58791); +const credential_health_workflow_visibility_1 = __nccwpck_require__(57628); +const github_actions_resource_collection_1 = __nccwpck_require__(81189); /** Read-only GitHub Actions metadata and effective repository inventory. */ class GithubActionsResourceInspector { constructor(githubClient) { @@ -74722,7 +74722,7 @@ function combineOrganizationAccess(secrets, variables) { /***/ }), -/***/ 67160: +/***/ 58791: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -74830,14 +74830,14 @@ function readHeader(headers, expected) { /***/ }), -/***/ 75297: +/***/ 2761: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.paginateCursor = paginateCursor; -const logger_1 = __nccwpck_require__(58738); +const logger_1 = __nccwpck_require__(91151); /** * Iterates cursor-based API pages while enforcing a finite boundary and a * valid cursor transition. Consumers can `break` early when they find the @@ -74868,7 +74868,7 @@ async function* paginateCursor(fetchPage, options = {}) { /***/ }), -/***/ 45621: +/***/ 44812: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -74898,7 +74898,7 @@ function requireObject(data, operation) { /***/ }), -/***/ 93841: +/***/ 25282: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -74938,11 +74938,11 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RuntimeDoctorRepository = void 0; -const github = __importStar(__nccwpck_require__(22644)); -const github_runtime_doctor_ports_1 = __nccwpck_require__(63737); -const pull_request_approval_repository_1 = __nccwpck_require__(79657); +const github = __importStar(__nccwpck_require__(78227)); +const github_runtime_doctor_ports_1 = __nccwpck_require__(64921); +const pull_request_approval_repository_1 = __nccwpck_require__(23001); const SHA = /^[a-f0-9]{40}$/u; -const github_runtime_doctor_1 = __nccwpck_require__(56756); +const github_runtime_doctor_1 = __nccwpck_require__(20413); /** SDK DTOs and diagnostics terminate here; no mutation, provisioning, or filesystem API. */ class RuntimeDoctorRepository { constructor(owner, repository, token) { @@ -75077,15 +75077,15 @@ function status(error) { /***/ }), -/***/ 70184: +/***/ 52644: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.GithubPublicationSourceRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); -const git_object_id_1 = __nccwpck_require__(65534); +const application_error_1 = __nccwpck_require__(75999); +const git_object_id_1 = __nccwpck_require__(88623); /** Reads the authoritative branch head without exposing Octokit to application code. */ class GithubPublicationSourceRepository { constructor(clientProvider) { @@ -75109,14 +75109,14 @@ exports.GithubPublicationSourceRepository = GithubPublicationSourceRepository; /***/ }), -/***/ 16989: +/***/ 88593: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.BugbotIssueCommentQueryRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); /** Reads the newest Bugbot issue/PR conversation comments with a fixed two-page budget. */ class BugbotIssueCommentQueryRepository { constructor(githubClient) { @@ -75200,7 +75200,7 @@ exports.BugbotIssueCommentQueryRepository = BugbotIssueCommentQueryRepository; /***/ }), -/***/ 2197: +/***/ 82726: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -75220,7 +75220,7 @@ exports.BugbotIssueRepository = BugbotIssueRepository; /***/ }), -/***/ 7434: +/***/ 91153: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -75247,15 +75247,15 @@ exports.ExecutionIssueSetupRepository = ExecutionIssueSetupRepository; /***/ }), -/***/ 99814: +/***/ 75023: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueAssignmentRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); class IssueAssignmentRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -75294,7 +75294,7 @@ exports.IssueAssignmentRepository = IssueAssignmentRepository; /***/ }), -/***/ 95907: +/***/ 23231: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -75314,15 +75314,15 @@ exports.IssueClosureRepository = IssueClosureRepository; /***/ }), -/***/ 65701: +/***/ 70791: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueCompletionRepository = void 0; -const issue_completion_1 = __nccwpck_require__(28272); -const application_error_1 = __nccwpck_require__(1889); +const issue_completion_1 = __nccwpck_require__(31147); +const application_error_1 = __nccwpck_require__(75999); /** Exact repository/subject reads and selective writes. Never replaces a label inventory. */ class IssueCompletionRepository { constructor(client, binding) { @@ -75422,18 +75422,18 @@ function invalid() { /***/ }), -/***/ 9204: +/***/ 2313: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueContentRepository = void 0; -const comment_content_policy_1 = __nccwpck_require__(11965); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); -const github_error_policy_1 = __nccwpck_require__(67160); +const comment_content_policy_1 = __nccwpck_require__(77454); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); +const github_error_policy_1 = __nccwpck_require__(58791); class IssueContentRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -75562,14 +75562,14 @@ exports.IssueContentRepository = IssueContentRepository; /***/ }), -/***/ 71922: +/***/ 28868: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueInactivityRepository = void 0; -const github_pagination_policy_1 = __nccwpck_require__(45621); +const github_pagination_policy_1 = __nccwpck_require__(44812); /** Reads the provider's issue activity timestamp and waiting-state labels. */ class IssueInactivityRepository { constructor(githubClient) { @@ -75623,18 +75623,18 @@ function toSnapshot(issue) { /***/ }), -/***/ 71461: +/***/ 59699: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueLabelProvisioningRepository = void 0; -const initial_label_provisioning_policy_1 = __nccwpck_require__(47570); -const logger_1 = __nccwpck_require__(58738); -const github_error_policy_1 = __nccwpck_require__(67160); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); +const initial_label_provisioning_policy_1 = __nccwpck_require__(73160); +const logger_1 = __nccwpck_require__(91151); +const github_error_policy_1 = __nccwpck_require__(58791); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); class IssueLabelProvisioningRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -75700,16 +75700,16 @@ function mapLabelMutationError(name, error) { /***/ }), -/***/ 68335: +/***/ 45725: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueLabelRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); class IssueLabelRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -75751,14 +75751,14 @@ exports.IssueLabelRepository = IssueLabelRepository; /***/ }), -/***/ 49034: +/***/ 8346: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueLifecycleRepository = void 0; -const logger_1 = __nccwpck_require__(58738); +const logger_1 = __nccwpck_require__(91151); class IssueLifecycleRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -75783,16 +75783,16 @@ exports.IssueLifecycleRepository = IssueLifecycleRepository; /***/ }), -/***/ 47056: +/***/ 11333: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueMetadataRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const milestone_1 = __nccwpck_require__(73034); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const milestone_1 = __nccwpck_require__(2016); +const application_error_1 = __nccwpck_require__(75999); class IssueMetadataRepository { constructor(metadataClient, graphqlClient) { this.metadataClient = metadataClient; @@ -75870,7 +75870,7 @@ exports.IssueMetadataRepository = IssueMetadataRepository; /***/ }), -/***/ 77682: +/***/ 907: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -75890,15 +75890,15 @@ exports.IssueNotificationRepository = IssueNotificationRepository; /***/ }), -/***/ 80825: +/***/ 66610: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueProgressLabelRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const progress_labels_1 = __nccwpck_require__(11696); +const logger_1 = __nccwpck_require__(91151); +const progress_labels_1 = __nccwpck_require__(97890); class IssueProgressLabelRepository { constructor(issueLabelRepository) { this.issueLabelRepository = issueLabelRepository; @@ -75920,7 +75920,7 @@ exports.IssueProgressLabelRepository = IssueProgressLabelRepository; /***/ }), -/***/ 91746: +/***/ 26674: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -75943,17 +75943,17 @@ exports.IssueProgressTrackingRepository = IssueProgressTrackingRepository; /***/ }), -/***/ 78377: +/***/ 10121: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTitleRepository = void 0; -const issue_emoji_policy_1 = __nccwpck_require__(92806); -const pull_request_title_policy_1 = __nccwpck_require__(94675); -const issue_title_policy_1 = __nccwpck_require__(74529); -const issue_title_update_1 = __nccwpck_require__(41190); +const issue_emoji_policy_1 = __nccwpck_require__(81201); +const pull_request_title_policy_1 = __nccwpck_require__(59756); +const issue_title_policy_1 = __nccwpck_require__(83179); +const issue_title_update_1 = __nccwpck_require__(9229); class IssueTitleRepository { constructor(issueTitleClient, issueMetadataRepository) { this.issueTitleClient = issueTitleClient; @@ -75991,7 +75991,7 @@ exports.IssueTitleRepository = IssueTitleRepository; /***/ }), -/***/ 41190: +/***/ 9229: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -75999,8 +75999,8 @@ exports.IssueTitleRepository = IssueTitleRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.updateIssueTitle = updateIssueTitle; exports.withTitleUpdateLogging = withTitleUpdateLogging; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); async function updateIssueTitle(client, owner, repository, currentTitle, nextTitle, issueNumber, token) { if (nextTitle === currentTitle) return undefined; @@ -76021,16 +76021,16 @@ async function withTitleUpdateLogging(update) { /***/ }), -/***/ 69856: +/***/ 19118: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTypeAssignmentRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const issue_type_assignment_workflow_1 = __nccwpck_require__(16122); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const issue_type_assignment_workflow_1 = __nccwpck_require__(40102); +const application_error_1 = __nccwpck_require__(75999); class IssueTypeAssignmentRepository { constructor(getIssueId, graphqlClient) { this.getIssueId = getIssueId; @@ -76052,7 +76052,7 @@ exports.IssueTypeAssignmentRepository = IssueTypeAssignmentRepository; /***/ }), -/***/ 16122: +/***/ 40102: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -76060,8 +76060,8 @@ exports.IssueTypeAssignmentRepository = IssueTypeAssignmentRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTypeCreationSkippedError = void 0; exports.assignIssueType = assignIssueType; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); async function assignIssueType(getIssueId, client, owner, repository, issueNumber, selected, token) { (0, logger_1.logDebugInfo)(`Setting issue type for issue ${issueNumber} to ${selected.name}`); const issueId = await getIssueId(owner, repository, issueNumber, token); @@ -76132,7 +76132,7 @@ exports.IssueTypeCreationSkippedError = IssueTypeCreationSkippedError; /***/ }), -/***/ 10161: +/***/ 62726: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -76157,7 +76157,7 @@ function configuredIssueTypes(issueTypes) { /***/ }), -/***/ 54147: +/***/ 89634: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -76165,10 +76165,10 @@ function configuredIssueTypes(issueTypes) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ensureIssueType = ensureIssueType; exports.ensureIssueTypes = ensureIssueTypes; -const logger_1 = __nccwpck_require__(58738); -const issue_type_configuration_1 = __nccwpck_require__(10161); -const issue_type_queries_1 = __nccwpck_require__(89904); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const issue_type_configuration_1 = __nccwpck_require__(62726); +const issue_type_queries_1 = __nccwpck_require__(73192); +const application_error_1 = __nccwpck_require__(75999); async function ensureIssueType(client, owner, name, description, color) { try { const existingTypes = await (0, issue_type_queries_1.listIssueTypes)(client, owner); @@ -76216,7 +76216,7 @@ function ensureConfiguredIssueType(client, owner, configured) { /***/ }), -/***/ 89904: +/***/ 73192: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -76280,15 +76280,15 @@ async function createIssueType(client, owner, name, description, color) { /***/ }), -/***/ 34680: +/***/ 4858: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.IssueTypeRepository = void 0; -const issue_type_queries_1 = __nccwpck_require__(89904); -const issue_type_ensure_workflow_1 = __nccwpck_require__(54147); +const issue_type_queries_1 = __nccwpck_require__(73192); +const issue_type_ensure_workflow_1 = __nccwpck_require__(89634); class IssueTypeRepository { constructor(graphqlClient) { this.graphqlClient = graphqlClient; @@ -76303,7 +76303,7 @@ exports.IssueTypeRepository = IssueTypeRepository; /***/ }), -/***/ 92806: +/***/ 81201: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -76343,7 +76343,7 @@ function firstMatchingEmoji(rules, labels) { /***/ }), -/***/ 74529: +/***/ 83179: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -76397,16 +76397,16 @@ function normalizePullRequestSourceTitle(title, issueNumber) { /***/ }), -/***/ 5445: +/***/ 96711: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ActorAuthorizationRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const actor_modification_policy_1 = __nccwpck_require__(20951); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const actor_modification_policy_1 = __nccwpck_require__(34737); +const application_error_1 = __nccwpck_require__(75999); class ActorAuthorizationRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -76477,7 +76477,7 @@ function logUnlessNotFound(error, operation) { /***/ }), -/***/ 8826: +/***/ 11454: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -76508,7 +76508,7 @@ exports.AuthenticatedUserRepository = AuthenticatedUserRepository; /***/ }), -/***/ 27042: +/***/ 84916: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -76516,7 +76516,7 @@ exports.AuthenticatedUserRepository = AuthenticatedUserRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.listOrganizationTeams = listOrganizationTeams; exports.listOrganizationTeamMembers = listOrganizationTeamMembers; -const github_pagination_policy_1 = __nccwpck_require__(45621); +const github_pagination_policy_1 = __nccwpck_require__(44812); async function listOrganizationTeams(client, organization) { const teams = []; for await (const response of client.paginate.iterator(client.rest.teams.list, { @@ -76553,17 +76553,17 @@ function isRecord(value) { /***/ }), -/***/ 76503: +/***/ 845: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.OrganizationMembersRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const project_members_policy_1 = __nccwpck_require__(11641); -const organization_members_query_1 = __nccwpck_require__(27042); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const project_members_policy_1 = __nccwpck_require__(41370); +const organization_members_query_1 = __nccwpck_require__(84916); +const application_error_1 = __nccwpck_require__(75999); class OrganizationMembersRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -76611,15 +76611,15 @@ exports.OrganizationMembersRepository = OrganizationMembersRepository; /***/ }), -/***/ 92753: +/***/ 24958: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProgressDiffRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); -const progress_diff_partition_policy_1 = __nccwpck_require__(59296); +const application_error_1 = __nccwpck_require__(75999); +const progress_diff_partition_policy_1 = __nccwpck_require__(70628); const MAX_COMPARISON_FILES = 300; const STATUSES = new Set(['added', 'removed', 'modified', 'renamed', 'copied', 'changed', 'unchanged']); /** Reads exact GitHub objects, omitting generated bundle patches but retaining their file facts. */ @@ -76663,14 +76663,14 @@ function unavailable(code = 'provider.unavailable') { /***/ }), -/***/ 38121: +/***/ 98952: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProjectBoardCommandRepository = void 0; -const project_board_field_update_1 = __nccwpck_require__(54336); +const project_board_field_update_1 = __nccwpck_require__(31603); /** GitHub GraphQL adapter for ProjectV2 field mutations. */ class ProjectBoardCommandRepository { constructor(projectBoardContentQueryPort, graphqlClient) { @@ -76694,16 +76694,16 @@ exports.ProjectBoardCommandRepository = ProjectBoardCommandRepository; /***/ }), -/***/ 92939: +/***/ 73579: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getProjectBoardDetail = getProjectBoardDetail; -const logger_1 = __nccwpck_require__(58738); -const project_detail_1 = __nccwpck_require__(34967); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const project_detail_1 = __nccwpck_require__(33428); +const application_error_1 = __nccwpck_require__(75999); /** Reads a ProjectV2 without leaking GitHub's owner-specific GraphQL shape. */ async function getProjectBoardDetail(ownerTypeClient, graphqlClient, projectId, owner, token) { try { @@ -76767,7 +76767,7 @@ function validateProjectId(projectId) { /***/ }), -/***/ 54336: +/***/ 31603: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -76776,9 +76776,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.setProjectBoardSingleSelectField = setProjectBoardSingleSelectField; exports.setProjectBoardSingleSelectFieldByItemId = setProjectBoardSingleSelectFieldByItemId; exports.initializeProjectBoardItemStatus = initializeProjectBoardItemStatus; -const project_board_provider_limits_1 = __nccwpck_require__(87071); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_adapter_1 = __nccwpck_require__(75297); +const project_board_provider_limits_1 = __nccwpck_require__(96997); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_adapter_1 = __nccwpck_require__(2761); const FIELD_QUERY = ` query($projectId: ID!, $after: String) { node(id: $projectId) { @@ -76972,7 +76972,7 @@ async function findProjectItem(client, project, itemId, fieldName) { /***/ }), -/***/ 62956: +/***/ 63552: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -76981,9 +76981,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getProjectItemId = getProjectItemId; exports.getProjectItemIdByContentId = getProjectItemIdByContentId; exports.isProjectContentLinked = isProjectContentLinked; -const project_board_provider_limits_1 = __nccwpck_require__(87071); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_adapter_1 = __nccwpck_require__(75297); +const project_board_provider_limits_1 = __nccwpck_require__(96997); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_adapter_1 = __nccwpck_require__(2761); const CONTENT_QUERY = ` query($owner: String!, $repo: String!, $number: Int!) { repository(owner: $owner, name: $repo) { @@ -77100,14 +77100,14 @@ async function findContentSideProjectItemId(client, project, contentId) { /***/ }), -/***/ 18445: +/***/ 79285: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProjectBoardLinkRepository = void 0; -const logger_1 = __nccwpck_require__(58738); +const logger_1 = __nccwpck_require__(91151); class ProjectBoardLinkRepository { constructor(projectBoardQueryPort, graphqlClient) { this.projectBoardQueryPort = projectBoardQueryPort; @@ -77134,15 +77134,15 @@ exports.ProjectBoardLinkRepository = ProjectBoardLinkRepository; /***/ }), -/***/ 68433: +/***/ 97301: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ProjectBoardQueryRepository = void 0; -const project_board_detail_query_1 = __nccwpck_require__(92939); -const project_board_item_query_1 = __nccwpck_require__(62956); +const project_board_detail_query_1 = __nccwpck_require__(73579); +const project_board_item_query_1 = __nccwpck_require__(63552); class ProjectBoardQueryRepository { constructor(ownerTypeClient, graphqlClient) { this.ownerTypeClient = ownerTypeClient; @@ -77157,7 +77157,7 @@ exports.ProjectBoardQueryRepository = ProjectBoardQueryRepository; /***/ }), -/***/ 11641: +/***/ 41370: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -77196,7 +77196,7 @@ function selectAvailableMembers(members, currentMembers, requested) { /***/ }), -/***/ 41183: +/***/ 96710: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -77271,16 +77271,16 @@ function parseApprovalCoverageZip(value) { /***/ }), -/***/ 92917: +/***/ 9958: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readApprovalEvidence = readApprovalEvidence; -const application_error_1 = __nccwpck_require__(1889); -const approval_evidence_error_1 = __nccwpck_require__(55528); -const approval_evidence_diagnostic_1 = __nccwpck_require__(53086); +const application_error_1 = __nccwpck_require__(75999); +const approval_evidence_error_1 = __nccwpck_require__(50519); +const approval_evidence_diagnostic_1 = __nccwpck_require__(98205); /** Terminates provider exceptions; even unknown statuses never interpolate provider text. */ async function readApprovalEvidence(operation, read) { try { @@ -77306,7 +77306,7 @@ async function readApprovalEvidence(operation, read) { /***/ }), -/***/ 97192: +/***/ 55165: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -77337,14 +77337,14 @@ exports.BugbotPullRequestRepository = BugbotPullRequestRepository; /***/ }), -/***/ 12678: +/***/ 68742: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.readCurrentBaseRevision = readCurrentBaseRevision; -const application_error_1 = __nccwpck_require__(1889); +const application_error_1 = __nccwpck_require__(75999); /** PR base metadata can lag a parent push; read the exact native branch ref. */ async function readCurrentBaseRevision(port, target, baseRef) { if (typeof baseRef !== 'string' || baseRef.length === 0 || baseRef.length > 1024 @@ -77360,7 +77360,7 @@ async function readCurrentBaseRevision(port, target, baseRef) { /***/ }), -/***/ 79657: +/***/ 23001: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -77401,16 +77401,16 @@ var __importStar = (this && this.__importStar) || (function () { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestApprovalRepository = void 0; exports.readEffectiveApprovalPolicy = readEffectiveApprovalPolicy; -const approval_evidence_read_1 = __nccwpck_require__(92917); -const approval_evidence_error_1 = __nccwpck_require__(55528); -const application_error_1 = __nccwpck_require__(1889); -const current_base_revision_query_1 = __nccwpck_require__(12678); -const logging_ports_1 = __nccwpck_require__(97793); -const github = __importStar(__nccwpck_require__(22644)); -const pull_request_approval_policy_1 = __nccwpck_require__(81372); -const approval_coverage_artifact_1 = __nccwpck_require__(41183); -const file_ignore_policy_1 = __nccwpck_require__(38774); -const pull_request_approval_presentation_policy_1 = __nccwpck_require__(69975); +const approval_evidence_read_1 = __nccwpck_require__(9958); +const approval_evidence_error_1 = __nccwpck_require__(50519); +const application_error_1 = __nccwpck_require__(75999); +const current_base_revision_query_1 = __nccwpck_require__(68742); +const logging_ports_1 = __nccwpck_require__(6152); +const github = __importStar(__nccwpck_require__(78227)); +const pull_request_approval_policy_1 = __nccwpck_require__(98820); +const approval_coverage_artifact_1 = __nccwpck_require__(96710); +const file_ignore_policy_1 = __nccwpck_require__(20542); +const pull_request_approval_presentation_policy_1 = __nccwpck_require__(79017); /** GitHub DTOs terminate here. Every partial/forbidden read becomes non-authorizing evidence. */ class PullRequestApprovalRepository { constructor(token, settings) { @@ -77823,17 +77823,17 @@ function collectDiagnostic(diagnostics, cause) { /***/ }), -/***/ 76743: +/***/ 71564: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestChangesRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const logger_1 = __nccwpck_require__(58738); -const github_pagination_policy_1 = __nccwpck_require__(45621); -const application_error_1 = __nccwpck_require__(1889); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const logger_1 = __nccwpck_require__(91151); +const github_pagination_policy_1 = __nccwpck_require__(44812); +const application_error_1 = __nccwpck_require__(75999); class PullRequestChangesRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -78003,16 +78003,16 @@ exports.PullRequestChangesRepository = PullRequestChangesRepository; /***/ }), -/***/ 12356: +/***/ 24189: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestLifecycleRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); -const github_error_policy_1 = __nccwpck_require__(67160); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); +const github_error_policy_1 = __nccwpck_require__(58791); class PullRequestLifecycleRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -78241,16 +78241,16 @@ function toBugbotPullRequestIdentity(value) { /***/ }), -/***/ 7154: +/***/ 17120: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentCommandRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const github_pagination_policy_1 = __nccwpck_require__(45621); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const github_pagination_policy_1 = __nccwpck_require__(44812); class PullRequestReviewCommentCommandRepository { constructor(createClient, graphqlClient, queryClient) { this.createClient = createClient; @@ -78366,15 +78366,15 @@ exports.PullRequestReviewCommentCommandRepository = PullRequestReviewCommentComm /***/ }), -/***/ 82369: +/***/ 44085: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewCommentQueryRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const github_pagination_policy_1 = __nccwpck_require__(45621); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const github_pagination_policy_1 = __nccwpck_require__(44812); function toReviewComment(comment) { if (typeof comment.node_id !== "string" || comment.node_id.length === 0) { throw new Error("Review comment identity is unavailable."); @@ -78509,14 +78509,14 @@ exports.PullRequestReviewCommentQueryRepository = PullRequestReviewCommentQueryR /***/ }), -/***/ 60004: +/***/ 54354: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.toPullRequestReviewOperationError = toPullRequestReviewOperationError; -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); /** Only safe HTTP metadata crosses the provider boundary; provider prose never does. */ function toPullRequestReviewOperationError(error, operation, context) { if (!error || typeof error !== 'object') @@ -78533,14 +78533,14 @@ function toPullRequestReviewOperationError(error, operation, context) { /***/ }), -/***/ 28874: +/***/ 2307: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findPullRequestReviewThread = findPullRequestReviewThread; -const pull_request_review_errors_1 = __nccwpck_require__(62151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); const THREADS_QUERY = ` query ($owner: String!, $repo: String!, $prNumber: Int!, $threadsAfter: String) { repository(owner: $owner, name: $repo) { @@ -78634,17 +78634,17 @@ function nextConnectionCursor(pageInfo, seenCursors) { /***/ }), -/***/ 22457: +/***/ 23314: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewThreadRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const logger_1 = __nccwpck_require__(58738); -const pull_request_review_errors_1 = __nccwpck_require__(62151); -const pull_request_review_thread_locator_1 = __nccwpck_require__(28874); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const logger_1 = __nccwpck_require__(91151); +const pull_request_review_errors_1 = __nccwpck_require__(46445); +const pull_request_review_thread_locator_1 = __nccwpck_require__(2307); /** GitHub GraphQL adapter for locating and resolving a pull-request review thread. */ class PullRequestReviewThreadRepository { constructor(githubClient) { @@ -78816,15 +78816,15 @@ exports.PullRequestReviewThreadRepository = PullRequestReviewThreadRepository; /***/ }), -/***/ 99470: +/***/ 13779: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestReviewerRepository = void 0; -const pull_request_review_error_metadata_1 = __nccwpck_require__(60004); -const github_pagination_policy_1 = __nccwpck_require__(45621); +const pull_request_review_error_metadata_1 = __nccwpck_require__(54354); +const github_pagination_policy_1 = __nccwpck_require__(44812); const COMPLETED_REVIEW_STATES = new Set([ "APPROVED", "CHANGES_REQUESTED", @@ -78910,7 +78910,7 @@ exports.PullRequestReviewerRepository = PullRequestReviewerRepository; /***/ }), -/***/ 32780: +/***/ 1328: /***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; @@ -78950,8 +78950,8 @@ var __importStar = (this && this.__importStar) || (function () { })(); Object.defineProperty(exports, "__esModule", ({ value: true })); exports.PullRequestStatusQueryRepository = void 0; -const current_base_revision_query_1 = __nccwpck_require__(12678); -const github = __importStar(__nccwpck_require__(22644)); +const current_base_revision_query_1 = __nccwpck_require__(68742); +const github = __importStar(__nccwpck_require__(78227)); const integer = (value) => Number.isSafeInteger(value) && value > 0; const sha = (value) => typeof value === 'string' && /^[a-f0-9]{40}$/u.test(value); /** Bounded native linkage and fresh identity reads. No mutations or provider DTOs cross this boundary. */ @@ -79007,15 +79007,15 @@ exports.PullRequestStatusQueryRepository = PullRequestStatusQueryRepository; /***/ }), -/***/ 15413: +/***/ 96578: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryDefaultBranchRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const application_error_1 = __nccwpck_require__(75999); class RepositoryDefaultBranchRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -79038,22 +79038,22 @@ exports.RepositoryDefaultBranchRepository = RepositoryDefaultBranchRepository; /***/ }), -/***/ 36974: +/***/ 42075: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryReleasePublicationRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const release_content_policy_1 = __nccwpck_require__(34388); -const release_transition_policy_1 = __nccwpck_require__(51782); -const release_tag_policy_1 = __nccwpck_require__(74183); -const repository_release_query_1 = __nccwpck_require__(54835); -const application_error_1 = __nccwpck_require__(1889); -const github_error_policy_1 = __nccwpck_require__(67160); -const repository_tag_query_1 = __nccwpck_require__(36542); -const deployment_publication_1 = __nccwpck_require__(22478); +const logger_1 = __nccwpck_require__(91151); +const release_content_policy_1 = __nccwpck_require__(56818); +const release_transition_policy_1 = __nccwpck_require__(27673); +const release_tag_policy_1 = __nccwpck_require__(62748); +const repository_release_query_1 = __nccwpck_require__(10766); +const application_error_1 = __nccwpck_require__(75999); +const github_error_policy_1 = __nccwpck_require__(58791); +const repository_tag_query_1 = __nccwpck_require__(46772); +const deployment_publication_1 = __nccwpck_require__(6912); class RepositoryReleasePublicationRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -79214,7 +79214,7 @@ function verifiedReleaseUrl(release, tag, expectedName, expectedBody, operationI /***/ }), -/***/ 54835: +/***/ 10766: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79236,7 +79236,7 @@ async function listRepositoryReleases(client, owner, repository) { /***/ }), -/***/ 36542: +/***/ 46772: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -79244,8 +79244,8 @@ async function listRepositoryReleases(client, owner, repository) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findRepositoryTag = findRepositoryTag; exports.getRepositoryTagSha = getRepositoryTagSha; -const github_error_policy_1 = __nccwpck_require__(67160); -const release_tag_policy_1 = __nccwpck_require__(74183); +const github_error_policy_1 = __nccwpck_require__(58791); +const release_tag_policy_1 = __nccwpck_require__(62748); async function findRepositoryTag(client, owner, repository, tag) { try { const { data } = await client.rest.git.getRef({ owner, repo: repository, ref: (0, release_tag_policy_1.tagReference)(tag) }); @@ -79274,17 +79274,17 @@ async function getRepositoryTagSha(client, owner, repository, tag) { /***/ }), -/***/ 46389: +/***/ 58717: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryTagRepository = void 0; -const logger_1 = __nccwpck_require__(58738); -const release_tag_policy_1 = __nccwpck_require__(74183); -const repository_tag_query_1 = __nccwpck_require__(36542); -const application_error_1 = __nccwpck_require__(1889); +const logger_1 = __nccwpck_require__(91151); +const release_tag_policy_1 = __nccwpck_require__(62748); +const repository_tag_query_1 = __nccwpck_require__(46772); +const application_error_1 = __nccwpck_require__(75999); class RepositoryTagRepository { constructor(githubClient) { this.githubClient = githubClient; @@ -79384,15 +79384,15 @@ exports.RepositoryTagRepository = RepositoryTagRepository; /***/ }), -/***/ 54967: +/***/ 4385: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositoryVersionTagsQueryRepository = void 0; -const application_error_1 = __nccwpck_require__(1889); -const version_policy_1 = __nccwpck_require__(36071); +const application_error_1 = __nccwpck_require__(75999); +const version_policy_1 = __nccwpck_require__(8381); /** Remote-only setup query: never fetches or rewrites local moving Action tags. */ class RepositoryVersionTagsQueryRepository { constructor(githubClient) { @@ -79422,7 +79422,7 @@ exports.RepositoryVersionTagsQueryRepository = RepositoryVersionTagsQueryReposit /***/ }), -/***/ 34388: +/***/ 56818: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79446,7 +79446,7 @@ function hasReleaseContent(release) { /***/ }), -/***/ 74183: +/***/ 62748: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79468,7 +79468,7 @@ function releaseName(version, title) { /***/ }), -/***/ 51782: +/***/ 27673: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79486,15 +79486,15 @@ function releaseIdAsString(id) { /***/ }), -/***/ 37159: +/***/ 2879: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ReplyRequestRepository = void 0; -const reply_request_digest_1 = __nccwpck_require__(73250); -const github_user_policy_1 = __nccwpck_require__(84900); +const reply_request_digest_1 = __nccwpck_require__(47971); +const github_user_policy_1 = __nccwpck_require__(84403); /** Provider identity and diagnostics terminate here. Requests forbid redirects. */ class ReplyRequestRepository { constructor(client, binding) { @@ -79538,15 +79538,15 @@ function record(value) { /***/ }), -/***/ 34761: +/***/ 28493: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.RepositorySecretsCommandRepository = exports.RepositoryVariablesCommandRepository = exports.SetupRemoteConfigurationQueryRepository = exports.RepositoryVariablesQueryRepository = exports.RepositorySecretNamesQueryRepository = void 0; -const github_actions_resource_inspector_1 = __nccwpck_require__(82410); -const github_actions_resource_commands_1 = __nccwpck_require__(10618); +const github_actions_resource_inspector_1 = __nccwpck_require__(96558); +const github_actions_resource_commands_1 = __nccwpck_require__(71301); /** Read-only repository Secret metadata boundary. Secret values are never available. */ class RepositorySecretNamesQueryRepository { constructor(githubClient) { @@ -79613,7 +79613,7 @@ exports.RepositorySecretsCommandRepository = RepositorySecretsCommandRepository; /***/ }), -/***/ 16848: +/***/ 85885: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79692,15 +79692,15 @@ function sameRepository(value, binding) { /***/ }), -/***/ 31381: +/***/ 40941: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.ActivePreviousWorkflowRunsRepository = void 0; -const workflow_status_1 = __nccwpck_require__(23807); -const workflow_runs_retry_1 = __nccwpck_require__(38720); +const workflow_status_1 = __nccwpck_require__(1462); +const workflow_runs_retry_1 = __nccwpck_require__(86434); const NO_OP_DELAY_PORT = { wait: async () => undefined }; const SYSTEM_CLOCK = { nowMilliseconds: () => Date.now() }; const SYSTEM_RANDOM = { next: () => Math.random() }; @@ -79777,7 +79777,7 @@ function isActivePreviousRun(run, query) { /***/ }), -/***/ 20887: +/***/ 29509: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79804,7 +79804,7 @@ exports.WorkflowDispatchRepository = WorkflowDispatchRepository; /***/ }), -/***/ 38720: +/***/ 86434: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -79812,7 +79812,7 @@ exports.WorkflowDispatchRepository = WorkflowDispatchRepository; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.WorkflowQueueDeadlineError = exports.WORKFLOW_RUNS_RETRY_POLICY = void 0; exports.withWorkflowRunsRetry = withWorkflowRunsRetry; -const workflow_queue_policy_1 = __nccwpck_require__(59989); +const workflow_queue_policy_1 = __nccwpck_require__(43193); exports.WORKFLOW_RUNS_RETRY_POLICY = { maximumAttempts: 5, rateLimitMaximumAttempts: 5, @@ -79968,7 +79968,7 @@ function firstNumericValue(...values) { /***/ }), -/***/ 23807: +/***/ 1462: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -79998,7 +79998,7 @@ exports.WORKFLOW_ACTIVE_STATUSES = [ /***/ }), -/***/ 66436: +/***/ 25911: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80025,7 +80025,7 @@ function resolveActionInput(additionalParams, actionInputs, key) { /***/ }), -/***/ 18773: +/***/ 89040: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80048,7 +80048,7 @@ function isAgentConfigurationReady(configuration) { /***/ }), -/***/ 52013: +/***/ 12253: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80066,7 +80066,7 @@ function workspaceModeForCapability(capability) { /***/ }), -/***/ 11975: +/***/ 28528: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80087,7 +80087,7 @@ exports.AgentResponseLengthFailure = AgentResponseLengthFailure; /***/ }), -/***/ 53086: +/***/ 98205: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80125,7 +80125,7 @@ exports.APPROVAL_EVIDENCE_REASONS = Object.freeze([ /***/ }), -/***/ 48721: +/***/ 51114: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80182,7 +80182,7 @@ function escapeRegExp(value) { /***/ }), -/***/ 70155: +/***/ 90981: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80205,7 +80205,7 @@ function admittedBranchSyncValidationCode(value) { /***/ }), -/***/ 8442: +/***/ 14712: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -80214,7 +80214,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true })); exports.selectCanonicalBugbotPullRequest = selectCanonicalBugbotPullRequest; exports.summarizeBugbotCoverage = summarizeBugbotCoverage; exports.completeBugbotSourceCoverage = completeBugbotSourceCoverage; -const git_object_id_1 = __nccwpck_require__(65534); +const git_object_id_1 = __nccwpck_require__(88623); function selectCanonicalBugbotPullRequest(target, candidates, source) { if (source === "exact-head" && candidates.length === 0) return { kind: "none" }; @@ -80298,7 +80298,7 @@ function matchesConstrainedHead(target, candidate) { /***/ }), -/***/ 71592: +/***/ 31011: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80354,7 +80354,7 @@ function identitiesAreCompatible(existing, finding) { /***/ }), -/***/ 9248: +/***/ 91853: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80429,7 +80429,7 @@ function fnv1a(value) { /***/ }), -/***/ 93789: +/***/ 1811: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80480,7 +80480,7 @@ function invalid(reason) { /***/ }), -/***/ 38595: +/***/ 3994: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80549,14 +80549,14 @@ function resolveBugbotReviewEffort(configured, complexity) { /***/ }), -/***/ 25952: +/***/ 80859: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.buildBugbotReviewProjection = buildBugbotReviewProjection; -const review_state_1 = __nccwpck_require__(47220); +const review_state_1 = __nccwpck_require__(79200); function buildBugbotReviewProjection(input) { const findings = [...input.findings].sort((left, right) => left.id.localeCompare(right.id)); const counts = (0, review_state_1.countBugbotFindingStates)(findings.map((finding) => finding.state)); @@ -80611,7 +80611,7 @@ function stableDigest(value) { /***/ }), -/***/ 47220: +/***/ 79200: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80685,7 +80685,7 @@ function countActionableBugbotFindings(counts) { /***/ }), -/***/ 31012: +/***/ 21565: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80704,7 +80704,7 @@ exports.CLOSED_ISSUE_REASONS = Object.freeze(['completed', 'not_planned', 'dupli /***/ }), -/***/ 11965: +/***/ 77454: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80727,7 +80727,7 @@ function hasVisibleCommentContent(value) { /***/ }), -/***/ 28057: +/***/ 11771: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -80849,7 +80849,7 @@ function parseFindingIdentifiers(input) { /***/ }), -/***/ 16602: +/***/ 86819: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -80857,7 +80857,7 @@ function parseFindingIdentifiers(input) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.containsBotMention = containsBotMention; exports.isCopilotCommentRequest = isCopilotCommentRequest; -const copilot_command_1 = __nccwpck_require__(28057); +const copilot_command_1 = __nccwpck_require__(11771); /** Matches GitHub usernames case-insensitively without matching a larger username. */ function containsBotMention(commentBody, tokenUser) { const normalizedUser = tokenUser.trim().replace(/^@/u, ''); @@ -80878,7 +80878,7 @@ function isCopilotCommentRequest(commentBody, botLogin) { /***/ }), -/***/ 71962: +/***/ 72418: /***/ ((__unused_webpack_module, exports) => { "use strict"; @@ -81003,7 +81003,7 @@ function lifecycleStateFromLabels(currentLabels, labels = exports.DEFAULT_COPILO /***/ }), -/***/ 18679: +/***/ 40221: /***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; @@ -81014,7 +81014,7 @@ exports.isHistoryCommand = isHistoryCommand; exports.readOperationEvidence = readOperationEvidence; exports.validateOperationEvidence = validateOperationEvidence; exports.buildOperationEvidenceMarker = buildOperationEvidenceMarker; -const git_object_id_1 = __nccwpck_require__(65534); +const git_object_id_1 = __nccwpck_require__(88623); exports.HISTORY_COMMANDS = ['sync-branch', 'remember', 'dismiss', 'implement', 'fix']; exports.OPERATION_OUTCOMES = ['applied', 'already-current', 'not-applied', 'blocked', 'partial', 'failed', 'unavailable']; exports.OPERATION_MARKER_PREFIX = '', title: 'Dashboard state', state: 'unknown' }], + }), 'en-US', links); + expect(body).not.toContain(''); + expect(body).toContain('@\u200bteam'); + }); + it('renders Spanish product copy while keeping machine markers neutral', () => { const body = renderBugbotStatusCard(projection(['fixed']), 'es-ES', links); expect(body).toContain('## Bugbot: revisión completada'); diff --git a/src/application/policies/bugbot_review_presentation_policy.ts b/src/application/policies/bugbot_review_presentation_policy.ts index 0cb301dd4..9f53ed369 100644 --- a/src/application/policies/bugbot_review_presentation_policy.ts +++ b/src/application/policies/bugbot_review_presentation_policy.ts @@ -235,9 +235,12 @@ function normalizeHistoricalSnapshot( function renderFindingRow(finding: BugbotProjectedFinding): string { const label = sanitizeAgentMarkdown(finding.title || finding.id, 500).replace(/[\r\n]+/gu, ' '); const state = stateLabel(finding.state); + const identity = finding.state === 'unknown' + ? ` — ${sanitizeAgentMarkdown(finding.id, 200).replace(/[\r\n]+/gu, ' ')}` + : ''; return finding.url - ? `- ${state} — [${label}](${finding.url})` - : `- ${state} — ${label}`; + ? `- ${state} — [${label}](${finding.url})${identity}` + : `- ${state} — ${label}${identity}`; } function stateLabel(state: BugbotFindingState): string { diff --git a/src/application/usecases/steps/commit/bugbot/__tests__/analyze_bugbot_revision_use_case.test.ts b/src/application/usecases/steps/commit/bugbot/__tests__/analyze_bugbot_revision_use_case.test.ts index 0ff7acb7b..496480ae0 100644 --- a/src/application/usecases/steps/commit/bugbot/__tests__/analyze_bugbot_revision_use_case.test.ts +++ b/src/application/usecases/steps/commit/bugbot/__tests__/analyze_bugbot_revision_use_case.test.ts @@ -1,4 +1,5 @@ import { DEFAULT_BUGBOT_REVIEW_CONFIGURATION } from '../../../../../../domain/bugbot/review_configuration'; +import { prepareBugbotFindings } from '../prepare_bugbot_findings'; import { analyzeBugbotRevision } from '../analyze_bugbot_revision_use_case'; import { BugbotReviewTelemetry } from '../bugbot_review_telemetry'; import type { BugbotReviewOperationContext } from '../bugbot_review_operation_context'; @@ -89,6 +90,25 @@ function attestedResponse(prompt: string, ordinal: number, resolved: unknown[] = } describe('analyzeBugbotRevision partition execution', () => { + it('folds partition reports for one retained identity before applying the comment limit', async () => { + const partitions = [partition(1, 2), partition(2, 2)]; + const reports = [1, 2].map((ordinal) => ({ id: `new-${ordinal}`, title: `Changed title ${ordinal}`, + description: 'Same retained defect', file: `src/${ordinal}.ts`, line: ordinal, + category: 'correctness', symbol: 'storedData', codeSnippet: 'return data.total > 0;' })); + const previous = prepareBugbotFindings({ findings: [reports[0]] }, [], 'low', 20)!.toPublish[0]; + const loaded = context(partitions); + loaded.existingByFindingId = { retained: { pullRequest: { commentIdentity: 'PRRC_1', pullRequestNumber: 7, + resolved: false, semanticFingerprint: previous.semanticFingerprint } } }; + const query = jest.fn(({ prompt }: { prompt: string }) => Promise.resolve({ + ...attestedResponse(prompt, 1), findings: [...reports, { id: 'independent', title: 'Independent bug', description: 'Other defect' }], + })); + const execution = { ...operation(), analysis: { ...operation().analysis, commentLimit: 2 } }; + const prepared = await analyzeBugbotRevision(execution, loaded, { agent: { query }, telemetry: new BugbotReviewTelemetry(execution) }); + expect(prepared?.activeFindings?.map((finding) => finding.id)).toEqual(['retained', 'independent']); + expect(prepared?.toPublish).toHaveLength(2); + expect(prepared?.overflowCount).toBe(0); + }); + it('runs every partition with maximum concurrency two and aggregates once in plan order', async () => { const partitions = [partition(1, 3), partition(2, 3), partition(3, 3)]; const pending: Array<() => void> = []; diff --git a/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts b/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts new file mode 100644 index 000000000..71623e19c --- /dev/null +++ b/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts @@ -0,0 +1,175 @@ +import { buildCommentBody, parseMarker } from '../../../../../policies/bugbot_finding_marker_policy'; +import { toPullRequestReviewOperationError } from '../../../../../../data/repository/pull_request/pull_request_review_error_metadata'; +import { DEFAULT_BUGBOT_REVIEW_CONFIGURATION } from '../../../../../../domain/bugbot/review_configuration'; +import type { PullRequestReviewComment, PullRequestReviewSummary } from '../../../../../ports/pull_request_review_comment_ports'; +import { analyzeBugbotRevision } from '../analyze_bugbot_revision_use_case'; +import { applyDetectedFindings } from '../apply_detected_findings'; +import { parseBugbotFindingComments } from '../bugbot_finding_context'; +import { BugbotReviewTelemetry } from '../bugbot_review_telemetry'; +import { prepareBugbotFindings } from '../prepare_bugbot_findings'; +import { publishFindings } from '../publish_findings_use_case'; +import { reconcileBugbotReviewState } from '../reconcile_bugbot_review_state_use_case'; +import type { BugbotReviewOperationContext } from '../bugbot_review_operation_context'; +import type { BugbotContext } from '../types'; + +const head = 'a'.repeat(40); +const oldId = 'ui/src/model.ts:73:operations-empty'; +const raw = { id: oldId, title: 'Recent operations can be mislabeled as an empty dashboard', + description: 'Stored operations must make the dashboard nonempty.', file: 'ui/src/model.ts', line: 73, + category: 'correctness', symbol: 'hasStoredData', codeSnippet: 'return snapshot.total > 0;' }; +const old = prepareBugbotFindings({ findings: [raw] }, [], 'low', 20)!.toPublish[0]; +const current = { ...raw, id: 'ui/src/model.ts:72:empty-state-ignores-stored-records', line: 72, + title: 'Stored operations and library entries are classified as empty' }; +const operation: BugbotReviewOperationContext = { + repository: { owner: 'org', name: 'repo' }, + target: { issueNumber: -1, isPullRequest: true, pullRequestNumber: 1, headBranch: 'feature', + commitBranch: 'feature', baseBranch: 'develop', pullRequestAction: 'synchronize', draft: false }, + trigger: { kind: 'pull_request', headOwner: 'org' }, trustedAuthorLogin: 'bugbot', + ignorePatterns: [], organizationRules: [], locale: { issue: 'en-US', pullRequest: 'en-US' }, + analysis: { agentConfiguration: { provider: 'codex', model: 'reviewer' }, minimumSeverity: 'low', + commentLimit: 20, reviewConfiguration: DEFAULT_BUGBOT_REVIEW_CONFIGURATION }, +}; + +function harness(resolved = false) { + const comments: PullRequestReviewComment[] = [{ id: 1, identity: 'PRRC_1', authorLogin: 'bugbot', + parentReviewIdentity: '77', url: 'https://github.com/org/repo/pull/1#discussion_r1', + body: buildCommentBody(old, resolved) }]; + const thread = { resolved, resolvedByLogin: 'bugbot' }; + const reviews: PullRequestReviewSummary[] = [{ identity: '77', authorLogin: 'bugbot', commitId: head, + body: '## 🤖 Bugbot review snapshot\n\nOriginal report.' }]; + const status: Array<{ id: number; body: string; user: { login: string } }> = []; + const createReviewWithComments = jest.fn(); + const updatePullRequestReviewComment = jest.fn(async (_identity: string, body: string) => { comments[0].body = body; }); + const unresolvePullRequestReviewThread = jest.fn(async () => { thread.resolved = false; }); + const resolvePullRequestReviewThread = jest.fn(async () => { thread.resolved = true; }); + const publication = { issueComments: { addComment: jest.fn(), updateComment: jest.fn() }, + pullRequestComments: { createReviewWithComments, updatePullRequestReviewComment, unresolvePullRequestReviewThread } }; + const resolution = { issueComments: { updateComment: jest.fn() }, pullRequestComments: { + listPullRequestReviewComments: async () => comments, updatePullRequestReviewComment, + unresolvePullRequestReviewThread, resolvePullRequestReviewThread } }; + const load = (): BugbotContext => ({ + existingByFindingId: parseBugbotFindingComments([], new Map([[1, comments]]), 'bugbot', + new Map([[1, { PRRC_1: thread }]])).existingByFindingId, + issueComments: [], selectionReason: 'event', coverage: { status: 'complete', sources: [] }, + eligibleResolutionIds: new Set([oldId]), previousFindingsBlock: '', + unresolvedFindingsWithBody: [{ id: oldId, fullBody: comments[0].body! }], + canonicalPullRequest: { number: 1, state: 'open', draft: false, baseRepository: { owner: 'org', name: 'repo' }, + headRepositoryOwner: 'org', headRef: 'feature', headSha: head }, + prContext: { prHeadSha: head, prFiles: [{ filename: raw.file, status: 'modified' }], + pathToFirstDiffLine: { [raw.file]: 72 }, pathToDiffLocations: { [raw.file]: [{ line: 72, side: 'RIGHT' }] } }, + }); + const reconcile = (loadedContext: BugbotContext, findings = [current], errors: readonly Error[] = []) => + reconcileBugbotReviewState({ + target: { pullRequestNumber: 1, analyzedHeadSha: head, trustedAuthorLogin: 'bugbot', locale: 'en-US' }, + loadedContext, + activeFindings: prepareBugbotFindings({ findings }, [], 'low', 20)!.toPublish, + mutationErrors: errors, + snapshotPorts: { + getPullRequestHeadSha: async () => head, + listPullRequestReviewComments: async () => comments, + listPullRequestReviewThreadStates: async () => ({ PRRC_1: thread }), + listPullRequestReviews: async () => reviews, + listIssueComments: async () => status, + navigationForPullRequest: () => ({ pullRequestUrl: 'https://github.com/org/repo/pull/1', + commitUrl: `https://github.com/org/repo/commit/${head}` }), + }, + presentationPorts: { + comments: { + addComment: async (_pr, body) => { status.push({ id: 2, body, user: { login: 'bugbot' } }); }, + updateComment: async (_pr, _id, body) => { status[0].body = body; }, + }, + updatePullRequestReview: async (_pr, _id, body) => { reviews[0].body = body; }, + }, + }); + return { comments, thread, publication, resolution, load, reconcile, status }; +} + +it('replays a changed title/location through publication, final projection and a fresh recheck without an orphan', async () => { + const test = harness(); + const query = jest.fn().mockResolvedValue({ outputLocale: 'en-US', findings: [current], + resolved_findings: [{ id: oldId, resolution: 'fixed' }] }); + const run = async () => { + const loaded = test.load(); + const prepared = (await analyzeBugbotRevision(operation, loaded, { + agent: { query }, telemetry: new BugbotReviewTelemetry(operation), + }))!; + expect(prepared.toPublish[0].id).toBe(oldId); + expect(prepared.resolvedFindingIds.size).toBe(0); + expect(await applyDetectedFindings(operation, loaded, prepared, test.publication, test.resolution)).toEqual([]); + return test.reconcile(loaded); + }; + const first = await run(); + const second = await run(); + expect(first.projection.findings).toEqual([expect.objectContaining({ id: oldId, title: current.title, + state: 'open', url: 'https://github.com/org/repo/pull/1#discussion_r1', parentReviewIdentity: '77' })]); + expect(first.projection.counts.unknown).toBe(0); + expect(first.errors).toEqual([]); + expect(second.projection.digest).toBe(first.projection.digest); + expect(second.statusCardOperation).toBe('unchanged'); + expect(test.publication.pullRequestComments.createReviewWithComments).not.toHaveBeenCalled(); + expect(test.comments).toHaveLength(1); + expect(test.status).toHaveLength(1); + expect(parseMarker(test.comments[0].body)[0].findingId).toBe(oldId); +}); + +it('keeps the durable marker when publication is called directly with a replacement model ID', async () => { + const test = harness(); + const findings = prepareBugbotFindings({ findings: [current, { ...current, id: 'duplicate' }] }, [], 'low', 20)!.toPublish; + await publishFindings({ operation, context: test.load(), findings, ports: test.publication }); + expect(test.publication.pullRequestComments.updatePullRequestReviewComment).toHaveBeenCalledTimes(1); + expect(parseMarker(test.comments[0].body)[0].findingId).toBe(oldId); + expect(test.publication.pullRequestComments.createReviewWithComments).not.toHaveBeenCalled(); +}); + +it('preserves a human dismissal when the same finding is reported under a new ID', async () => { + const test = harness(); + test.thread.resolved = true; + test.thread.resolvedByLogin = 'maintainer'; + const loaded = test.load(); + const prepared = (await analyzeBugbotRevision(operation, loaded, { + agent: { query: jest.fn().mockResolvedValue({ outputLocale: 'en-US', findings: [current], resolved_findings: [] }) }, + telemetry: new BugbotReviewTelemetry(operation), + }))!; + expect(prepared.toPublish).toEqual([]); + expect(prepared.activeFindings).toEqual([]); + expect(await applyDetectedFindings(operation, loaded, prepared, test.publication, test.resolution)).toEqual([]); + expect(parseMarker(test.comments[0].body)[0]).toMatchObject({ findingId: oldId, resolution: 'dismissed' }); + expect(test.publication.pullRequestComments.unresolvePullRequestReviewThread).not.toHaveBeenCalled(); +}); + +it.each(['update-comment', 'unresolve-thread'] as const)('retains identity and safe diagnostics after %s fails and converges on retry', async (failedOperation) => { + const test = harness(failedOperation === 'unresolve-thread'); + const mutation = failedOperation === 'update-comment' + ? test.publication.pullRequestComments.updatePullRequestReviewComment + : test.publication.pullRequestComments.unresolvePullRequestReviewThread; + mutation.mockRejectedValueOnce(toPullRequestReviewOperationError({ status: 503, + response: { headers: { 'x-github-request-id': 'AB12:34CD' }, data: 'PRIVATE_PROVIDER_BODY' } }, failedOperation)); + const loaded = test.load(); + const prepared = prepareBugbotFindings({ findings: [current] }, [], 'low', 20)!; + const errors = await applyDetectedFindings(operation, loaded, prepared, test.publication, test.resolution); + expect(errors).toHaveLength(1); + expect(errors[0]).toMatchObject({ diagnostic: { operation: failedOperation, findingId: oldId, providerStatus: 'http-503' } }); + const partial = await test.reconcile(loaded, [current], errors); + expect(partial.projection.findings).toHaveLength(1); + expect(partial.projection.findings[0].id).toBe(oldId); + expect(partial.projection.outcome).toBe('partial'); + expect(JSON.stringify(partial)).not.toContain('PRIVATE_PROVIDER_BODY'); + const refreshed = test.load(); + expect(await applyDetectedFindings(operation, refreshed, prepared, test.publication, test.resolution)).toEqual([]); + const retry = await test.reconcile(refreshed); + expect(retry.projection.outcome).toBe('complete'); + expect(retry.projection.counts.open).toBe(1); + expect(retry.projection.counts.unknown).toBe(0); + expect(test.publication.pullRequestComments.createReviewWithComments).not.toHaveBeenCalled(); +}); + +it('retains one unknown with its exact durable ID when the provider truly omits the comment', async () => { + const test = harness(); + const loaded = test.load(); + test.comments.length = 0; + const report = await test.reconcile(loaded); + expect(report.projection.findings).toEqual([expect.objectContaining({ id: oldId, state: 'unknown' })]); + expect(report.projection.counts.unknown).toBe(1); + expect(test.status[0].body).toContain(oldId); + expect(report.errors).toHaveLength(1); +}); diff --git a/src/application/usecases/steps/commit/bugbot/__tests__/publish_findings_use_case.test.ts b/src/application/usecases/steps/commit/bugbot/__tests__/publish_findings_use_case.test.ts index 6c046bedf..0a545babd 100644 --- a/src/application/usecases/steps/commit/bugbot/__tests__/publish_findings_use_case.test.ts +++ b/src/application/usecases/steps/commit/bugbot/__tests__/publish_findings_use_case.test.ts @@ -112,6 +112,29 @@ describe("publishFindings", () => { mockUpdatePullRequestReview.mockReset().mockResolvedValue(undefined); }); + it('keeps the trusted issue finding ID when its location fingerprint matches a new model ID', async () => { + await publishFindings({ operation: baseOperation, + context: baseContext({ existingByFindingId: { original: { issue: { + commentId: 100, resolved: false, fingerprint: 'fp-11111111', + } } } }), findings: [finding({ id: 'replacement' })] }); + expect(mockUpdateComment).toHaveBeenCalledWith(42, 100, + expect.stringContaining('finding_id:"original"'), undefined); + expect(mockAddComment).not.toHaveBeenCalled(); + }); + + it('falls back to a file comment for an impossible current-line anchor without sending that line', async () => { + await publishFindings({ operation: baseOperation, + context: baseContext({ prContext: { prHeadSha: 'sha1', + prFiles: [{ filename: 'src/spotify.py', status: 'modified' }], pathToFirstDiffLine: { 'src/spotify.py': 72 }, + pathToDiffLocations: { 'src/spotify.py': [{ line: 72, side: 'RIGHT' }] } } }), + findings: [finding({ file: 'src/spotify.py', line: 669, endLine: 670, suggestedCode: 'unsafe suggestion' })] }); + const draft = mockCreateReviewWithComments.mock.calls[0][3][0]; + expect(draft).toMatchObject({ path: 'src/spotify.py', subjectType: 'file' }); + expect(draft).not.toHaveProperty('line'); + expect(draft).not.toHaveProperty('startLine'); + expect(draft.body).not.toContain('```suggestion'); + }); + it("adds issue comment for new finding", async () => { await publishFindings({ operation: baseOperation, diff --git a/src/application/usecases/steps/commit/bugbot/analyze_bugbot_revision_use_case.ts b/src/application/usecases/steps/commit/bugbot/analyze_bugbot_revision_use_case.ts index f2832abf8..f89147234 100644 --- a/src/application/usecases/steps/commit/bugbot/analyze_bugbot_revision_use_case.ts +++ b/src/application/usecases/steps/commit/bugbot/analyze_bugbot_revision_use_case.ts @@ -3,7 +3,7 @@ import { reconcileResolvedFindingIds } from '../../../../policies/bugbot_reconci import { logInfo } from '../../../../ports/logging_ports'; import { applyCommentLimit } from './limit_comments'; import type { BugbotContext } from './types'; -import { findExistingFindingInfo } from '../../../../../domain/bugbot/finding'; +import { findExistingFindingInfo, retainExistingFindingIds } from '../../../../../domain/bugbot/finding'; import { buildBugbotPrompt } from './build_bugbot_prompt'; import { prepareBugbotFindings } from './prepare_bugbot_findings'; import type { PreparedBugbotFindings } from './prepare_bugbot_findings'; @@ -134,7 +134,10 @@ function suppressDismissedFindings( context: BugbotContext, prepared: PreparedBugbotFindings, ): PreparedBugbotFindings { - const activeFindings = (prepared.activeFindings ?? prepared.toPublish).filter((finding) => { + const activeFindings = retainExistingFindingIds( + prepared.activeFindings ?? prepared.toPublish, + context.existingByFindingId, + ).filter((finding) => { const existing = findExistingFindingInfo(context.existingByFindingId, finding); return existing?.issue?.resolution !== 'dismissed' && existing?.pullRequest?.resolution !== 'dismissed'; }); diff --git a/src/application/usecases/steps/commit/bugbot/bugbot_previous_findings_context.ts b/src/application/usecases/steps/commit/bugbot/bugbot_previous_findings_context.ts index aaf245699..ee4f960e0 100644 --- a/src/application/usecases/steps/commit/bugbot/bugbot_previous_findings_context.ts +++ b/src/application/usecases/steps/commit/bugbot/bugbot_previous_findings_context.ts @@ -27,6 +27,7 @@ export function buildPreviousFindingsContext( `; const suffix = ` **Your task 2:** For each finding above, analyze the current code and decide: +- Trace the original failure precondition through current callers, validation helpers and effective configuration, including modules outside the original anchor. A retained finding is not proof that its old explanation is still true. Reuse its exact id if reporting the same defect again; do not create a second report for it. - If the problem **still exists** (same code or same issue present): do **not** include it in \`resolved_findings\`. - If the problem **no longer applies** (e.g. that code was removed or refactored away): include \`{ "id": "", "resolution": "obsolete" }\` in \`resolved_findings\`. - If the problem **has been fixed** (code was changed and the issue is resolved): include \`{ "id": "", "resolution": "fixed" }\` in \`resolved_findings\`. diff --git a/src/application/usecases/steps/commit/bugbot/publish_findings_use_case.ts b/src/application/usecases/steps/commit/bugbot/publish_findings_use_case.ts index 3c3633258..cdc57457e 100644 --- a/src/application/usecases/steps/commit/bugbot/publish_findings_use_case.ts +++ b/src/application/usecases/steps/commit/bugbot/publish_findings_use_case.ts @@ -8,6 +8,7 @@ import type { BugbotFindingPublicationPorts } from "../../../../../application/p import type { BugbotContext } from "./types"; import { findExistingFindingInfo, + retainExistingFindingIds, type BugbotFinding, } from "../../../../../domain/bugbot/finding"; import { publishIssueFindingComment } from "./publish_issue_finding_comment"; @@ -46,7 +47,7 @@ export async function publishFindings(param: PublishFindingsParam): Promise 0 && !reviewPublisher) { await publishIssueFindingComment( ports.issueComments, diff --git a/src/application/usecases/steps/commit/bugbot/reconcile_bugbot_review_state_use_case.ts b/src/application/usecases/steps/commit/bugbot/reconcile_bugbot_review_state_use_case.ts index ecbfa0869..6bc782d88 100644 --- a/src/application/usecases/steps/commit/bugbot/reconcile_bugbot_review_state_use_case.ts +++ b/src/application/usecases/steps/commit/bugbot/reconcile_bugbot_review_state_use_case.ts @@ -3,7 +3,7 @@ import type { BugbotPresentationReport, BugbotReconciliationTarget, } from '../../../../contracts/bugbot_reconciliation'; -import type { BugbotFinding } from '../../../../../domain/bugbot/finding'; +import { retainExistingFindingIds, type BugbotFinding } from '../../../../../domain/bugbot/finding'; import { buildBugbotReviewProjection } from '../../../../../domain/bugbot/review_projection'; import { buildBugbotReconciliationPlan, @@ -62,6 +62,14 @@ export async function reconcileBugbotReviewState(input: { } const snapshot = snapshotResult.snapshot; + const activeFindings = retainExistingFindingIds( + input.activeFindings, + input.loadedContext.existingByFindingId, + ); + const expectedPublishedFindings = retainExistingFindingIds( + input.expectedPublishedFindings ?? input.activeFindings, + input.loadedContext.existingByFindingId, + ); const diagnostics = [ ...(input.mutationErrors ?? []).map((error) => error instanceof BugbotMutationError ? { code: 'finding-mutation-failed' as const, mutation: error.diagnostic } @@ -74,7 +82,7 @@ export async function reconcileBugbotReviewState(input: { const providerProjection = projectBugbotProviderEvidence({ snapshot, trustedAuthorLogin: input.target.trustedAuthorLogin, - activeFindings: input.activeFindings, + activeFindings, existingByFindingId: input.loadedContext.existingByFindingId, }); const plan = buildBugbotReconciliationPlan({ @@ -86,9 +94,8 @@ export async function reconcileBugbotReviewState(input: { extractTitleFromBody(fullBody) || id, ]), ), - activeFindings: input.activeFindings, - expectedPublishedFindings: - input.expectedPublishedFindings ?? input.activeFindings, + activeFindings, + expectedPublishedFindings, diagnostics, coverage: input.loadedContext.coverage, }); diff --git a/src/domain/bugbot/__tests__/finding.test.ts b/src/domain/bugbot/__tests__/finding.test.ts index 0d64b409f..6fe0059b0 100644 --- a/src/domain/bugbot/__tests__/finding.test.ts +++ b/src/domain/bugbot/__tests__/finding.test.ts @@ -1,9 +1,48 @@ import { findExistingFindingInfo, + findExistingFindingMatch, + retainExistingFindingIds, isExistingFindingFullyResolved, } from '../finding'; describe('finding identity reconciliation', () => { + const retained = { pullRequest: { commentIdentity: 'PRRC_old', pullRequestNumber: 2, + resolved: false, fingerprint: 'fp-11111111', semanticFingerprint: 'sf-11111111' } }; + const report = { id: 'new', title: 'New title', description: 'Still defective', + fingerprint: 'fp-22222222', semanticFingerprint: 'sf-11111111' }; + + it('returns the durable key as well as the matched destination', () => { + expect(findExistingFindingMatch({ old: retained }, report)).toEqual({ id: 'old', info: retained }); + }); + + it('preserves the durable ID and current evidence without mutating the model response', () => { + expect(retainExistingFindingIds([report], { old: retained })).toEqual([{ ...report, id: 'old' }]); + expect(report.id).toBe('new'); + }); + + it('folds multiple reports only when they uniquely match one retained finding', () => { + const duplicate = { ...report, id: 'another', title: 'Rephrased' }; + expect(retainExistingFindingIds([report, duplicate], { old: retained })).toEqual([{ ...report, id: 'old' }]); + }); + + it('keeps unmatched and ambiguous reports independent rather than choosing a destination', () => { + const reports = [report, { ...report, id: 'another' }]; + expect(retainExistingFindingIds(reports, {})).toEqual(reports); + expect(retainExistingFindingIds(reports, { first: retained, second: retained })).toEqual(reports); + }); + + it('does not choose the first location match or bypass ambiguity with a semantic fallback', () => { + const other = { issue: { commentId: 3, resolved: false, fingerprint: 'fp-11111111' } }; + expect(findExistingFindingMatch({ first: retained, second: other }, { + ...report, fingerprint: 'fp-11111111', + })).toBeUndefined(); + }); + + it('retains a compatible direct ID even when another record has similar semantics', () => { + const direct = { ...report, id: 'old' }; + expect(retainExistingFindingIds([direct], { old: retained, second: retained })[0]).toBe(direct); + }); + it('requires a compatible local identity before trusting an exact model id', () => { const exact = { issue: { commentId: 1, resolved: false, fingerprint: 'fp-11111111' } }; const fallback = { pullRequest: { commentIdentity: 'review-1', pullRequestNumber: 2, resolved: false, fingerprint: 'fp-22222222' } }; diff --git a/src/domain/bugbot/finding.ts b/src/domain/bugbot/finding.ts index 683524a15..bc9347fa0 100644 --- a/src/domain/bugbot/finding.ts +++ b/src/domain/bugbot/finding.ts @@ -81,22 +81,55 @@ export function findExistingFindingInfo( existingByFindingId: ExistingByFindingId, finding: Pick, ): ExistingFindingInfo | undefined { + return findExistingFindingMatch(existingByFindingId, finding)?.info; +} + +/** A match carries its durable key so updating a comment cannot re-key it. */ +export function findExistingFindingMatch( + existingByFindingId: ExistingByFindingId, + finding: Pick, +): { id: string; info: ExistingFindingInfo } | undefined { const direct = existingByFindingId[finding.id]; - if (direct && identitiesAreCompatible(direct, finding)) return direct; - const candidates = Object.values(existingByFindingId); + if (direct && identitiesAreCompatible(direct, finding)) return { id: finding.id, info: direct }; + const candidates = Object.entries(existingByFindingId); if (finding.fingerprint) { - const locationMatch = candidates.find((candidate) => + const locationMatches = candidates.filter(([, candidate]) => candidate.issue?.fingerprint === finding.fingerprint || candidate.pullRequest?.fingerprint === finding.fingerprint, ); - if (locationMatch) return locationMatch; + if (locationMatches.length > 0) return uniqueFindingMatch(locationMatches); } if (!finding.semanticFingerprint) return undefined; - const semanticMatches = candidates.filter((candidate) => + const semanticMatches = candidates.filter(([, candidate]) => candidate.issue?.semanticFingerprint === finding.semanticFingerprint || candidate.pullRequest?.semanticFingerprint === finding.semanticFingerprint, ); - return semanticMatches.length === 1 ? semanticMatches[0] : undefined; + return uniqueFindingMatch(semanticMatches); +} + +/** + * Preserve trusted IDs across title/location changes, before limits, publication + * and final projection. Multiple reports of one uniquely matched durable finding + * share one record; unmatched or ambiguous reports remain independent evidence. + */ +export function retainExistingFindingIds( + findings: readonly BugbotFinding[], + existingByFindingId: ExistingByFindingId, +): BugbotFinding[] { + const retained = new Set(); + return findings.flatMap((finding) => { + const match = findExistingFindingMatch(existingByFindingId, finding); + if (!match) return [finding]; + if (retained.has(match.id)) return []; + retained.add(match.id); + return [finding.id === match.id ? finding : { ...finding, id: match.id }]; + }); +} + +function uniqueFindingMatch( + matches: Array<[string, ExistingFindingInfo]>, +): { id: string; info: ExistingFindingInfo } | undefined { + return matches.length === 1 ? { id: matches[0][0], info: matches[0][1] } : undefined; } function identitiesAreCompatible( diff --git a/src/prompts/__tests__/bugbot.test.ts b/src/prompts/__tests__/bugbot.test.ts index 8d5575ee1..0ca9ef71d 100644 --- a/src/prompts/__tests__/bugbot.test.ts +++ b/src/prompts/__tests__/bugbot.test.ts @@ -27,6 +27,11 @@ describe('getBugbotPrompt', () => { expect(prompt).toContain('Context coverage'); expect(prompt).toContain('findings'); expect(prompt).toContain('resolved_findings'); + expect(prompt).toContain('Read effective repository configuration and inherited library/protocol defaults'); + expect(prompt).toContain('Trace short-circuit guards, validation helpers and the actual caller/render path'); + expect(prompt).toContain('Recompute arithmetic and check cited line numbers'); + expect(prompt).toContain('withdraw the finding entirely'); + expect(prompt).toContain('Report a confirmed failure when those protections are absent'); expect(prompt).toContain('outputLocale` exactly as `de-DE'); expect(prompt).not.toContain('{{'); }); diff --git a/src/prompts/bugbot.ts b/src/prompts/bugbot.ts index 102a805f4..f5589a43d 100644 --- a/src/prompts/bugbot.ts +++ b/src/prompts/bugbot.ts @@ -3,6 +3,8 @@ */ import { fillTemplate } from './fill'; +export const BUGBOT_FINDING_GROUNDING_INSTRUCTION = 'Before returning a finding, try to disprove it against the exact reviewed source. Read effective repository configuration and inherited library/protocol defaults before inferring behavior from a missing command flag. Trace short-circuit guards, validation helpers and the actual caller/render path before claiming that an unsafe branch is reachable or that separate call sites coexist. Recompute arithmetic and check cited line numbers against the current file/diff. If your evidence refutes the alleged defect, withdraw the finding entirely; do not publish a contradictory or self-refuting report. These checks apply equally to low/info severity. Report a confirmed failure when those protections are absent; do not assume they exist.'; + const TEMPLATE = `You are analyzing the latest code changes for potential bugs and issues. Write every human-readable finding title, description, evidence, and suggestion in {{targetLocale}}. Preserve identifiers, code, symbols, paths, refs, commands, and URLs verbatim. Echo \`outputLocale\` exactly as \`{{targetLocale}}\`. @@ -38,6 +40,8 @@ For every finding: - include the nearest stable \`symbol\` and a minimal exact \`codeSnippet\` when available so the finding can survive rebases, line movement, and file renames. - when a fix is a safe replacement of exactly the reported line range, include only the replacement text in \`suggestedCode\`; otherwise omit it. +${BUGBOT_FINDING_GROUNDING_INSTRUCTION} + Return every finding field required by the response schema. Use null for file, line, endLine, severity, confidence, category, evidence, suggestion, symbol, codeSnippet, or suggestedCode when that value does not safely apply. Only include files outside the ignore list. {{previousBlock}} diff --git a/src/tooling/__tests__/bugbot_benchmark.test.ts b/src/tooling/__tests__/bugbot_benchmark.test.ts index c014a9544..08954acb2 100644 --- a/src/tooling/__tests__/bugbot_benchmark.test.ts +++ b/src/tooling/__tests__/bugbot_benchmark.test.ts @@ -6,6 +6,33 @@ import { evaluateBugbotBenchmark, loadBugbotBenchmark, loadBugbotPredictions } f describe('versioned Bugbot benchmark', () => { const root = join(__dirname, '..', '..', '..'); + it.each([ + 'py-coverage-config-branch', 'py-http10-reconnect', 'docs-correct-regression-total', + 'py-short-circuit-unhashable', 'py-helper-retry-validation', 'ts-exclusive-render-branches', + ])('treats a reported source/verdict mismatch as a false positive: %s', async (id) => { + const corpus = await loadBugbotBenchmark(join(root, 'quality/bugbot/corpus.v1.json')); + const item = corpus.cases.find((item) => item.id === id)!; + expect(item.expected).toEqual([]); + const result = evaluateBugbotBenchmark({ schemaVersion: 1, cases: [item] }, { + schemaVersion: 1, predictions: { [id]: [{ title: 'Unsupported defect', file: item.file, line: 1, confidence: 0.99 }] }, + }); + expect(result.metrics.falsePositives).toBe(1); + expect(result.violations).toEqual(expect.arrayContaining([expect.stringContaining('precision')])); + }); + + it.each(['py-short-circuit-unsafe-order', 'ts-composed-duplicate-ids'])( + 'still requires the positive control with a reachable defect: %s', async (id) => { + const corpus = await loadBugbotBenchmark(join(root, 'quality/bugbot/corpus.v1.json')); + const item = corpus.cases.find((item) => item.id === id)!; + expect(item.expected).toHaveLength(1); + const result = evaluateBugbotBenchmark({ schemaVersion: 1, cases: [item] }, { + schemaVersion: 1, predictions: { [id]: [] }, + }); + expect(result.metrics.falseNegatives).toBe(1); + expect(result.violations).toEqual(expect.arrayContaining([expect.stringContaining('recall')])); + }, + ); + it('loads the multilingual ground-truth corpus and passes its reference contract', async () => { const corpus = await loadBugbotBenchmark(join(root, 'quality/bugbot/corpus.v1.json')); const predictions = await loadBugbotPredictions(join(root, 'quality/bugbot/reference-predictions.v1.json')); diff --git a/src/tooling/bugbot_benchmark_runner.ts b/src/tooling/bugbot_benchmark_runner.ts index f0fc56aa7..64b51d493 100644 --- a/src/tooling/bugbot_benchmark_runner.ts +++ b/src/tooling/bugbot_benchmark_runner.ts @@ -5,6 +5,7 @@ import type { BugbotBenchmarkCorpus, BugbotBenchmarkPredictions, BugbotBenchmark import type { BugbotEvalFinding } from './bugbot_quality_eval'; import { renderUntrustedField, UNTRUSTED_CONTENT_POLICY } from '../domain/security/untrusted_content'; import { normalizeBugbotResponse } from '../application/usecases/steps/commit/bugbot/prepare_bugbot_findings_policy'; +import { BUGBOT_FINDING_GROUNDING_INSTRUCTION } from '../prompts/bugbot'; const MAX_BENCHMARK_CASES = 200; @@ -38,6 +39,8 @@ export function buildBugbotBenchmarkPrompt(testCase: BugbotBenchmarkCase): strin You are running a controlled Bugbot quality benchmark. Review only the supplied synthetic diff. Report actionable defects caused by added or changed code; do not report style, pre-existing issues, or speculative concerns. Return an empty findings array when the change is safe. +${BUGBOT_FINDING_GROUNDING_INSTRUCTION} + Language: ${testCase.language} Repository-relative file: ${testCase.file} First displayed line: ${testCase.startLine} From c02a600a80bc3a7a15d3a9da086301d36789bb4f Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Wed, 21 Oct 2026 22:19:06 +0200 Subject: [PATCH 38/44] bugfix-655-bugbot-reconciliation-retains-an-orphan-unknown-finding-alongside-duplicate-semantic-reports: preserve colliding reports and render unknown IDs as code --- build/api/index.js | 45 +++++++++++++---- build/api/src/domain/bugbot/finding.d.ts | 7 --- build/cli/index.js | 45 +++++++++++++---- build/github_action/index.js | 45 +++++++++++++---- docs/bugbot/finding-publication.mdx | 2 + specs/bugbot-review-state-reconciliation.md | 16 +++++++ .../bugbot_review_presentation_policy.test.ts | 11 ++++- .../bugbot_review_presentation_policy.ts | 11 ++++- .../__tests__/finding_identity_replay.test.ts | 48 ++++++++++++++++--- ...le_bugbot_review_state_integration.test.ts | 12 ++++- src/domain/bugbot/__tests__/finding.test.ts | 29 +++++++++++ src/domain/bugbot/finding.ts | 20 +++++++- 12 files changed, 246 insertions(+), 45 deletions(-) diff --git a/build/api/index.js b/build/api/index.js index c58c1fe38..46e8d4d35 100644 --- a/build/api/index.js +++ b/build/api/index.js @@ -1695,12 +1695,21 @@ function renderFindingRow(finding) { const label = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.title || finding.id, 500).replace(/[\r\n]+/gu, ' '); const state = stateLabel(finding.state); const identity = finding.state === 'unknown' - ? ` — ${(0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.id, 200).replace(/[\r\n]+/gu, ' ')}` + ? ` — ${renderFindingId(finding.id)}` : ''; return finding.url ? `- ${state} — [${label}](${finding.url})${identity}` : `- ${state} — ${label}${identity}`; } +function renderFindingId(value) { + const id = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(value, 200).replace(/[\r\n]+/gu, ' '); + // A delimiter longer than every embedded backtick run keeps links, images + // and HTML inert even when the marker permits arbitrary Markdown punctuation. + let delimiter = '`'; + while (id.includes(delimiter)) + delimiter += '`'; + return `${delimiter} ${id} ${delimiter}`; +} function stateLabel(state) { return `[ ] ${state}`; } @@ -5741,9 +5750,14 @@ function matchesConstrainedHead(target, candidate) { /***/ }), /***/ 1011: -/***/ ((__unused_webpack_module, exports) => { +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved; +exports.findExistingFindingInfo = findExistingFindingInfo; +exports.findExistingFindingMatch = findExistingFindingMatch; +exports.retainExistingFindingIds = retainExistingFindingIds; /** * Provider-neutral Bugbot finding and durable identity contracts. * @@ -5751,11 +5765,7 @@ function matchesConstrainedHead(target, candidate) { * them in the domain prevents policies from depending on a particular use-case * folder and gives every adapter one stable semantic vocabulary. */ -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved; -exports.findExistingFindingInfo = findExistingFindingInfo; -exports.findExistingFindingMatch = findExistingFindingMatch; -exports.retainExistingFindingIds = retainExistingFindingIds; +const finding_identity_1 = __nccwpck_require__(1853); function isExistingFindingFullyResolved(finding) { const destinations = [finding.issue, finding.pullRequest].filter((destination) => destination != null); return (destinations.length > 0 && @@ -5790,13 +5800,30 @@ function findExistingFindingMatch(existingByFindingId, finding) { */ function retainExistingFindingIds(findings, existingByFindingId) { const retained = new Set(); + const durableIds = new Set(Object.keys(existingByFindingId)); + // Reserve the whole input up front so a generated ID cannot take another + // report's ID, including one that occurs later in the response. + const reservedIds = new Set([...durableIds, ...findings.map((finding) => finding.id)]); + const emittedIds = new Set(); return findings.flatMap((finding) => { const match = findExistingFindingMatch(existingByFindingId, finding); - if (!match) - return [finding]; + if (!match) { + let id = finding.id; + if (durableIds.has(id) || emittedIds.has(id)) { + const base = `candidate-${(0, finding_identity_1.buildFindingFingerprint)(finding)}`; + id = base; + let suffix = 0; + while (reservedIds.has(id)) + id = `${base}-${++suffix}`; + reservedIds.add(id); + } + emittedIds.add(id); + return [id === finding.id ? finding : { ...finding, id }]; + } if (retained.has(match.id)) return []; retained.add(match.id); + emittedIds.add(match.id); return [finding.id === match.id ? finding : { ...finding, id: match.id }]; }); } diff --git a/build/api/src/domain/bugbot/finding.d.ts b/build/api/src/domain/bugbot/finding.d.ts index 8c272e578..97380ce35 100644 --- a/build/api/src/domain/bugbot/finding.d.ts +++ b/build/api/src/domain/bugbot/finding.d.ts @@ -1,10 +1,3 @@ -/** - * Provider-neutral Bugbot finding and durable identity contracts. - * - * These types are shared by analysis, reconciliation, and publication. Keeping - * them in the domain prevents policies from depending on a particular use-case - * folder and gives every adapter one stable semantic vocabulary. - */ export interface BugbotFinding { id: string; title: string; diff --git a/build/cli/index.js b/build/cli/index.js index a65631f22..81eaa6c34 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -41701,12 +41701,21 @@ function renderFindingRow(finding) { const label = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.title || finding.id, 500).replace(/[\r\n]+/gu, ' '); const state = stateLabel(finding.state); const identity = finding.state === 'unknown' - ? ` — ${(0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.id, 200).replace(/[\r\n]+/gu, ' ')}` + ? ` — ${renderFindingId(finding.id)}` : ''; return finding.url ? `- ${state} — [${label}](${finding.url})${identity}` : `- ${state} — ${label}${identity}`; } +function renderFindingId(value) { + const id = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(value, 200).replace(/[\r\n]+/gu, ' '); + // A delimiter longer than every embedded backtick run keeps links, images + // and HTML inert even when the marker permits arbitrary Markdown punctuation. + let delimiter = '`'; + while (id.includes(delimiter)) + delimiter += '`'; + return `${delimiter} ${id} ${delimiter}`; +} function stateLabel(state) { return `[ ] ${state}`; } @@ -89863,10 +89872,15 @@ function matchesConstrainedHead(target, candidate) { /***/ }), /***/ 31011: -/***/ ((__unused_webpack_module, exports) => { +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved; +exports.findExistingFindingInfo = findExistingFindingInfo; +exports.findExistingFindingMatch = findExistingFindingMatch; +exports.retainExistingFindingIds = retainExistingFindingIds; /** * Provider-neutral Bugbot finding and durable identity contracts. * @@ -89874,11 +89888,7 @@ function matchesConstrainedHead(target, candidate) { * them in the domain prevents policies from depending on a particular use-case * folder and gives every adapter one stable semantic vocabulary. */ -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved; -exports.findExistingFindingInfo = findExistingFindingInfo; -exports.findExistingFindingMatch = findExistingFindingMatch; -exports.retainExistingFindingIds = retainExistingFindingIds; +const finding_identity_1 = __nccwpck_require__(91853); function isExistingFindingFullyResolved(finding) { const destinations = [finding.issue, finding.pullRequest].filter((destination) => destination != null); return (destinations.length > 0 && @@ -89913,13 +89923,30 @@ function findExistingFindingMatch(existingByFindingId, finding) { */ function retainExistingFindingIds(findings, existingByFindingId) { const retained = new Set(); + const durableIds = new Set(Object.keys(existingByFindingId)); + // Reserve the whole input up front so a generated ID cannot take another + // report's ID, including one that occurs later in the response. + const reservedIds = new Set([...durableIds, ...findings.map((finding) => finding.id)]); + const emittedIds = new Set(); return findings.flatMap((finding) => { const match = findExistingFindingMatch(existingByFindingId, finding); - if (!match) - return [finding]; + if (!match) { + let id = finding.id; + if (durableIds.has(id) || emittedIds.has(id)) { + const base = `candidate-${(0, finding_identity_1.buildFindingFingerprint)(finding)}`; + id = base; + let suffix = 0; + while (reservedIds.has(id)) + id = `${base}-${++suffix}`; + reservedIds.add(id); + } + emittedIds.add(id); + return [id === finding.id ? finding : { ...finding, id }]; + } if (retained.has(match.id)) return []; retained.add(match.id); + emittedIds.add(match.id); return [finding.id === match.id ? finding : { ...finding, id: match.id }]; }); } diff --git a/build/github_action/index.js b/build/github_action/index.js index f0c6c0116..1addc7cdf 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -42988,12 +42988,21 @@ function renderFindingRow(finding) { const label = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.title || finding.id, 500).replace(/[\r\n]+/gu, ' '); const state = stateLabel(finding.state); const identity = finding.state === 'unknown' - ? ` — ${(0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(finding.id, 200).replace(/[\r\n]+/gu, ' ')}` + ? ` — ${renderFindingId(finding.id)}` : ''; return finding.url ? `- ${state} — [${label}](${finding.url})${identity}` : `- ${state} — ${label}${identity}`; } +function renderFindingId(value) { + const id = (0, github_comment_publication_policy_1.sanitizeAgentMarkdown)(value, 200).replace(/[\r\n]+/gu, ' '); + // A delimiter longer than every embedded backtick run keeps links, images + // and HTML inert even when the marker permits arbitrary Markdown punctuation. + let delimiter = '`'; + while (id.includes(delimiter)) + delimiter += '`'; + return `${delimiter} ${id} ${delimiter}`; +} function stateLabel(state) { return `[ ] ${state}`; } @@ -80375,10 +80384,15 @@ function matchesConstrainedHead(target, candidate) { /***/ }), /***/ 31011: -/***/ ((__unused_webpack_module, exports) => { +/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { "use strict"; +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved; +exports.findExistingFindingInfo = findExistingFindingInfo; +exports.findExistingFindingMatch = findExistingFindingMatch; +exports.retainExistingFindingIds = retainExistingFindingIds; /** * Provider-neutral Bugbot finding and durable identity contracts. * @@ -80386,11 +80400,7 @@ function matchesConstrainedHead(target, candidate) { * them in the domain prevents policies from depending on a particular use-case * folder and gives every adapter one stable semantic vocabulary. */ -Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.isExistingFindingFullyResolved = isExistingFindingFullyResolved; -exports.findExistingFindingInfo = findExistingFindingInfo; -exports.findExistingFindingMatch = findExistingFindingMatch; -exports.retainExistingFindingIds = retainExistingFindingIds; +const finding_identity_1 = __nccwpck_require__(91853); function isExistingFindingFullyResolved(finding) { const destinations = [finding.issue, finding.pullRequest].filter((destination) => destination != null); return (destinations.length > 0 && @@ -80425,13 +80435,30 @@ function findExistingFindingMatch(existingByFindingId, finding) { */ function retainExistingFindingIds(findings, existingByFindingId) { const retained = new Set(); + const durableIds = new Set(Object.keys(existingByFindingId)); + // Reserve the whole input up front so a generated ID cannot take another + // report's ID, including one that occurs later in the response. + const reservedIds = new Set([...durableIds, ...findings.map((finding) => finding.id)]); + const emittedIds = new Set(); return findings.flatMap((finding) => { const match = findExistingFindingMatch(existingByFindingId, finding); - if (!match) - return [finding]; + if (!match) { + let id = finding.id; + if (durableIds.has(id) || emittedIds.has(id)) { + const base = `candidate-${(0, finding_identity_1.buildFindingFingerprint)(finding)}`; + id = base; + let suffix = 0; + while (reservedIds.has(id)) + id = `${base}-${++suffix}`; + reservedIds.add(id); + } + emittedIds.add(id); + return [id === finding.id ? finding : { ...finding, id }]; + } if (retained.has(match.id)) return []; retained.add(match.id); + emittedIds.add(match.id); return [finding.id === match.id ? finding : { ...finding, id: match.id }]; }); } diff --git a/docs/bugbot/finding-publication.mdx b/docs/bugbot/finding-publication.mdx index a30d94f86..89c55ec18 100644 --- a/docs/bugbot/finding-publication.mdx +++ b/docs/bugbot/finding-publication.mdx @@ -37,5 +37,7 @@ use that same ID, so a changed model ID cannot leave an extra unknown record. Multiple current reports of that uniquely matched identity consume one comment slot. Ambiguous location or semantic matches retain separate evidence; Bugbot does not select the first provider result or resolve a suspected duplicate. +An unrelated report that reuses another finding's ID receives a short local +collision-free ID so both concerns retain separate evidence and threads. Publication MUST complete before a finding is marked resolved. Within each reopen or resolution transition the marker is updated before the native thread, making retries convergent. After mutation, Bugbot MUST re-read provider state; invalid responses, unsafe paths, malformed identifiers, missing expected publications, or publication failures are terminal for that finding and MUST NOT produce a false resolved state. diff --git a/specs/bugbot-review-state-reconciliation.md b/specs/bugbot-review-state-reconciliation.md index 5eba82222..8cee3fc89 100644 --- a/specs/bugbot-review-state-reconciliation.md +++ b/specs/bugbot-review-state-reconciliation.md @@ -1779,3 +1779,19 @@ limits. Definition of Done: these cases, coverage budgets, full suite, architecture, specification/catalog, documentation, generated bundle/package gates and current-head PR CI/review pass. Synthetic fixtures do not establish a specific historical consumer API cause or live model-quality improvement. + +PR #658 review corrections: preserving a matched key MUST NOT let an incompatible +model report reuse that key and overwrite its evidence in downstream maps. Reserve +all durable and input IDs before allocation. Incompatible reports that collide +with a durable or already-emitted ID receive a short locally computed fingerprint +ID with a deterministic unused suffix; matched records retain their durable key. +Reapplying normalization and a fresh provider recheck MUST preserve both reports +and reuse both native threads. Reserve generated IDs against later input IDs too. + +Unknown IDs MUST render as literal code text, with a delimiter longer than any +embedded backtick run. Links, images and HTML in an ID cannot create navigation +or markup. GitHub's GFM renderer verified the malicious link/image/backtick/HTML +fixture as one inert code span. Add **six distinct cases** to this SDD's budget: +four domain collision/order/replay/reservation cases, one publication-to-projection +two-thread replay and one Markdown-injection case. Existing coverage thresholds +and all publication, identity and recovery rules remain required. diff --git a/src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts b/src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts index 43d1480a5..0eb718624 100644 --- a/src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts +++ b/src/application/policies/__tests__/bugbot_review_presentation_policy.test.ts @@ -77,7 +77,7 @@ describe('Bugbot review presentation', () => { pullRequestNumber: 358, analyzedHeadSha: head, coverage: completeCoverage, findings: [{ id: 'src/model.ts:73:operations-empty', title: 'Dashboard state', state: 'unknown' }], }), locale, links); - expect(body).toContain('Dashboard state — src/model.ts:73:operations-empty'); + expect(body).toContain('Dashboard state — ` src/model.ts:73:operations-empty `'); expect(body).toContain('/copilot recheck'); }); @@ -90,6 +90,15 @@ describe('Bugbot review presentation', () => { expect(body).toContain('@\u200bteam'); }); + it('renders Markdown links, images, HTML and backticks in unknown IDs as inert code text', () => { + const body = renderBugbotStatusCard(buildBugbotReviewProjection({ + pullRequestNumber: 358, analyzedHeadSha: head, coverage: completeCoverage, + findings: [{ id: '![review](https://example.com) `x` ', + title: 'Dashboard state', state: 'unknown' }], + }), 'en-US', links); + expect(body).toContain(' — `` ![review](https://example.com) `x` ``'); + }); + it('renders Spanish product copy while keeping machine markers neutral', () => { const body = renderBugbotStatusCard(projection(['fixed']), 'es-ES', links); expect(body).toContain('## Bugbot: revisión completada'); diff --git a/src/application/policies/bugbot_review_presentation_policy.ts b/src/application/policies/bugbot_review_presentation_policy.ts index 9f53ed369..ab019e729 100644 --- a/src/application/policies/bugbot_review_presentation_policy.ts +++ b/src/application/policies/bugbot_review_presentation_policy.ts @@ -236,13 +236,22 @@ function renderFindingRow(finding: BugbotProjectedFinding): string { const label = sanitizeAgentMarkdown(finding.title || finding.id, 500).replace(/[\r\n]+/gu, ' '); const state = stateLabel(finding.state); const identity = finding.state === 'unknown' - ? ` — ${sanitizeAgentMarkdown(finding.id, 200).replace(/[\r\n]+/gu, ' ')}` + ? ` — ${renderFindingId(finding.id)}` : ''; return finding.url ? `- ${state} — [${label}](${finding.url})${identity}` : `- ${state} — ${label}${identity}`; } +function renderFindingId(value: string): string { + const id = sanitizeAgentMarkdown(value, 200).replace(/[\r\n]+/gu, ' '); + // A delimiter longer than every embedded backtick run keeps links, images + // and HTML inert even when the marker permits arbitrary Markdown punctuation. + let delimiter = '`'; + while (id.includes(delimiter)) delimiter += '`'; + return `${delimiter} ${id} ${delimiter}`; +} + function stateLabel(state: BugbotFindingState): string { return `[ ] ${state}`; } diff --git a/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts b/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts index 71623e19c..f8743d6c4 100644 --- a/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts +++ b/src/application/usecases/steps/commit/bugbot/__tests__/finding_identity_replay.test.ts @@ -1,7 +1,7 @@ import { buildCommentBody, parseMarker } from '../../../../../policies/bugbot_finding_marker_policy'; import { toPullRequestReviewOperationError } from '../../../../../../data/repository/pull_request/pull_request_review_error_metadata'; import { DEFAULT_BUGBOT_REVIEW_CONFIGURATION } from '../../../../../../domain/bugbot/review_configuration'; -import type { PullRequestReviewComment, PullRequestReviewSummary } from '../../../../../ports/pull_request_review_comment_ports'; +import type { PullRequestReviewComment, PullRequestReviewCommentDraft, PullRequestReviewSummary } from '../../../../../ports/pull_request_review_comment_ports'; import { analyzeBugbotRevision } from '../analyze_bugbot_revision_use_case'; import { applyDetectedFindings } from '../apply_detected_findings'; import { parseBugbotFindingComments } from '../bugbot_finding_context'; @@ -38,8 +38,18 @@ function harness(resolved = false) { const reviews: PullRequestReviewSummary[] = [{ identity: '77', authorLogin: 'bugbot', commitId: head, body: '## 🤖 Bugbot review snapshot\n\nOriginal report.' }]; const status: Array<{ id: number; body: string; user: { login: string } }> = []; - const createReviewWithComments = jest.fn(); - const updatePullRequestReviewComment = jest.fn(async (_identity: string, body: string) => { comments[0].body = body; }); + const createReviewWithComments = jest.fn(async (_pr: number, _head: string, body: string, drafts: PullRequestReviewCommentDraft[]) => { + reviews.push({ identity: '88', authorLogin: 'bugbot', commitId: head, body }); + for (const draft of drafts) { + const id = comments.length + 1; + comments.push({ id, identity: `PRRC_${id}`, authorLogin: 'bugbot', parentReviewIdentity: '88', + body: draft.body, url: `https://github.com/org/repo/pull/1#discussion_r${id}` }); + } + return { identity: '88' }; + }); + const updatePullRequestReviewComment = jest.fn(async (identity: string, body: string) => { + comments.find((comment) => comment.identity === identity)!.body = body; + }); const unresolvePullRequestReviewThread = jest.fn(async () => { thread.resolved = false; }); const resolvePullRequestReviewThread = jest.fn(async () => { thread.resolved = true; }); const publication = { issueComments: { addComment: jest.fn(), updateComment: jest.fn() }, @@ -47,9 +57,11 @@ function harness(resolved = false) { const resolution = { issueComments: { updateComment: jest.fn() }, pullRequestComments: { listPullRequestReviewComments: async () => comments, updatePullRequestReviewComment, unresolvePullRequestReviewThread, resolvePullRequestReviewThread } }; + const threads = () => Object.fromEntries(comments.map((comment) => [comment.identity, + comment.identity === 'PRRC_1' ? thread : { resolved: false }])); const load = (): BugbotContext => ({ existingByFindingId: parseBugbotFindingComments([], new Map([[1, comments]]), 'bugbot', - new Map([[1, { PRRC_1: thread }]])).existingByFindingId, + new Map([[1, threads()]])).existingByFindingId, issueComments: [], selectionReason: 'event', coverage: { status: 'complete', sources: [] }, eligibleResolutionIds: new Set([oldId]), previousFindingsBlock: '', unresolvedFindingsWithBody: [{ id: oldId, fullBody: comments[0].body! }], @@ -67,7 +79,7 @@ function harness(resolved = false) { snapshotPorts: { getPullRequestHeadSha: async () => head, listPullRequestReviewComments: async () => comments, - listPullRequestReviewThreadStates: async () => ({ PRRC_1: thread }), + listPullRequestReviewThreadStates: async () => threads(), listPullRequestReviews: async () => reviews, listIssueComments: async () => status, navigationForPullRequest: () => ({ pullRequestUrl: 'https://github.com/org/repo/pull/1', @@ -78,7 +90,7 @@ function harness(resolved = false) { addComment: async (_pr, body) => { status.push({ id: 2, body, user: { login: 'bugbot' } }); }, updateComment: async (_pr, _id, body) => { status[0].body = body; }, }, - updatePullRequestReview: async (_pr, _id, body) => { reviews[0].body = body; }, + updatePullRequestReview: async (_pr, id, body) => { reviews.find((review) => review.identity === id)!.body = body; }, }, }); return { comments, thread, publication, resolution, load, reconcile, status }; @@ -121,6 +133,30 @@ it('keeps the durable marker when publication is called directly with a replacem expect(test.publication.pullRequestComments.createReviewWithComments).not.toHaveBeenCalled(); }); +it('publishes and projects an incompatible colliding ID as a separate finding and reuses both threads on recheck', async () => { + const test = harness(); + const unrelated = { ...current, id: oldId, title: 'Unrelated lease defect', file: 'src/copy.ts', + symbol: 'schedule', codeSnippet: 'retry(now)' }; + const findings = [current, unrelated]; + const run = async () => { + const loaded = test.load(); + await publishFindings({ operation, context: loaded, + findings: prepareBugbotFindings({ findings }, [], 'low', 20)!.toPublish, ports: test.publication }); + return test.reconcile(loaded, findings); + }; + const first = await run(); + expect(first.projection.findings).toHaveLength(2); + expect(new Set(first.projection.findings.map((finding) => finding.id)).size).toBe(2); + expect(first.projection.counts.open).toBe(2); + expect(first.projection.counts.unknown).toBe(0); + expect(first.projection.findings.map((finding) => finding.title)).toEqual(expect.arrayContaining([current.title, unrelated.title])); + const second = await run(); + expect(second.projection.findings).toEqual(first.projection.findings); + expect(second.projection.digest).toBe(first.projection.digest); + expect(test.comments).toHaveLength(2); + expect(test.publication.pullRequestComments.createReviewWithComments).toHaveBeenCalledTimes(1); +}); + it('preserves a human dismissal when the same finding is reported under a new ID', async () => { const test = harness(); test.thread.resolved = true; diff --git a/src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts b/src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts index f8bd1061b..5cb2bfb1a 100644 --- a/src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts +++ b/src/application/usecases/steps/commit/bugbot/__tests__/reconcile_bugbot_review_state_integration.test.ts @@ -40,6 +40,8 @@ function context(existingResolved = false): BugbotContext { threadResolved: true, resolution: 'fixed', parentReviewIdentity: '77', + fingerprint: 'fp-11111111', + semanticFingerprint: 'sf-11111111', }, }, } @@ -74,6 +76,8 @@ function finding(): BugbotFinding { description: 'Retry can publish twice.', file: 'src/a.ts', line: 1, + fingerprint: 'fp-11111111', + semanticFingerprint: 'sf-11111111', }; } @@ -442,6 +446,8 @@ describe('Bugbot review reconciliation integration', () => { commentIdentity: 'PRRC_missing', pullRequestNumber: 358, resolved: false, + fingerprint: 'fp-11111111', + semanticFingerprint: 'sf-11111111', }, }, }, @@ -565,7 +571,8 @@ describe('Bugbot review reconciliation integration', () => { const loadedContext: BugbotContext = { ...context(), existingByFindingId: { - 'finding-1': { issue: { commentId: 10, resolved: false } }, + 'finding-1': { issue: { commentId: 10, resolved: false, + fingerprint: 'fp-11111111', semanticFingerprint: 'sf-11111111' } }, }, }; const test = harness({ @@ -687,7 +694,8 @@ describe('Bugbot review reconciliation integration', () => { ...context(), existingByFindingId: { 'finding-1': { - issue: { commentId: 10, resolved: true, resolution: 'fixed' }, + issue: { commentId: 10, resolved: true, resolution: 'fixed', + fingerprint: 'fp-11111111', semanticFingerprint: 'sf-11111111' }, }, }, }; diff --git a/src/domain/bugbot/__tests__/finding.test.ts b/src/domain/bugbot/__tests__/finding.test.ts index 6fe0059b0..c4d9a8b70 100644 --- a/src/domain/bugbot/__tests__/finding.test.ts +++ b/src/domain/bugbot/__tests__/finding.test.ts @@ -4,6 +4,7 @@ import { retainExistingFindingIds, isExistingFindingFullyResolved, } from '../finding'; +import { buildFindingFingerprint } from '../finding_identity'; describe('finding identity reconciliation', () => { const retained = { pullRequest: { commentIdentity: 'PRRC_old', pullRequestNumber: 2, @@ -43,6 +44,34 @@ describe('finding identity reconciliation', () => { expect(retainExistingFindingIds([direct], { old: retained, second: retained })[0]).toBe(direct); }); + it.each([false, true])('keeps an incompatible report from taking a retained ID in either order (%s)', (reverse) => { + const incompatible = { id: 'old', title: 'Other defect', description: 'An unrelated failure', + file: 'other.ts', fingerprint: 'fp-33333333', semanticFingerprint: 'sf-33333333' }; + const reports = reverse ? [incompatible, report] : [report, incompatible]; + const result = retainExistingFindingIds(reports, { old: retained }); + expect(new Set(result.map((finding) => finding.id)).size).toBe(2); + expect(result.find((finding) => finding.title === report.title)?.id).toBe('old'); + expect(result.find((finding) => finding.title === incompatible.title)?.id).toBe(`candidate-${buildFindingFingerprint(incompatible)}`); + expect(retainExistingFindingIds(result, { old: retained })).toEqual(result); + }); + + it('preserves different unmatched reports sharing one model ID without colliding with later input IDs', () => { + const first = { ...report, semanticFingerprint: undefined }; + const second = { ...first, title: 'Other defect' }; + const reserved = { ...first, id: `candidate-${buildFindingFingerprint(second)}`, title: 'Third defect' }; + const result = retainExistingFindingIds([first, second, reserved], {}); + expect(result.map((finding) => finding.id)).toEqual([first.id, `${reserved.id}-1`, reserved.id]); + expect(result.map((finding) => finding.title)).toEqual([first.title, second.title, reserved.title]); + }); + + it('reserves generated suffixes and existing durable IDs before allocating a collision ID', () => { + const incompatible = { ...report, id: 'old', semanticFingerprint: undefined }; + const base = `candidate-${buildFindingFingerprint(incompatible)}`; + const result = retainExistingFindingIds([incompatible], { old: retained, [base]: {}, [`${base}-1`]: {} }); + expect(result[0].id).toBe(`${base}-2`); + expect(result[0].id.length).toBeLessThanOrEqual(200); + }); + it('requires a compatible local identity before trusting an exact model id', () => { const exact = { issue: { commentId: 1, resolved: false, fingerprint: 'fp-11111111' } }; const fallback = { pullRequest: { commentIdentity: 'review-1', pullRequestNumber: 2, resolved: false, fingerprint: 'fp-22222222' } }; diff --git a/src/domain/bugbot/finding.ts b/src/domain/bugbot/finding.ts index bc9347fa0..974a4e416 100644 --- a/src/domain/bugbot/finding.ts +++ b/src/domain/bugbot/finding.ts @@ -5,6 +5,7 @@ * them in the domain prevents policies from depending on a particular use-case * folder and gives every adapter one stable semantic vocabulary. */ +import { buildFindingFingerprint } from './finding_identity'; export interface BugbotFinding { id: string; @@ -117,11 +118,28 @@ export function retainExistingFindingIds( existingByFindingId: ExistingByFindingId, ): BugbotFinding[] { const retained = new Set(); + const durableIds = new Set(Object.keys(existingByFindingId)); + // Reserve the whole input up front so a generated ID cannot take another + // report's ID, including one that occurs later in the response. + const reservedIds = new Set([...durableIds, ...findings.map((finding) => finding.id)]); + const emittedIds = new Set(); return findings.flatMap((finding) => { const match = findExistingFindingMatch(existingByFindingId, finding); - if (!match) return [finding]; + if (!match) { + let id = finding.id; + if (durableIds.has(id) || emittedIds.has(id)) { + const base = `candidate-${buildFindingFingerprint(finding)}`; + id = base; + let suffix = 0; + while (reservedIds.has(id)) id = `${base}-${++suffix}`; + reservedIds.add(id); + } + emittedIds.add(id); + return [id === finding.id ? finding : { ...finding, id }]; + } if (retained.has(match.id)) return []; retained.add(match.id); + emittedIds.add(match.id); return [finding.id === match.id ? finding : { ...finding, id: match.id }]; }); } From c9d2749579da4bbc3da125d8181d0f3b32e97d57 Mon Sep 17 00:00:00 2001 From: vypbot Date: Wed, 21 Oct 2026 23:24:32 +0200 Subject: [PATCH 39/44] release-3.10.0: prepare release 3.10.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a13b15e2..c4ff15a8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vypdev/copilot", - "version": "3.9.3", + "version": "3.10.0", "packageManager": "pnpm@10.12.4", "pnpm": { "overrides": { From 9e0ee54b2946b8703d34d999c576ea3718d5c89d Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Thu, 22 Oct 2026 00:08:15 +0200 Subject: [PATCH 40/44] fix(release): validate proposed paths and literal configuration markers Refs #661. Address the two actionable findings from the superseded promotion review and preserve supported stored configuration records. --- build/cli/index.js | 108 +++++++++++++++++- build/github_action/index.js | 108 +++++++++++++++++- docs/issues/pre-branch-sdds.mdx | 3 + .../operations/troubleshooting.mdx | 8 ++ specs/CATALOG.md | 4 +- specs/catalog.json | 1 + .../execution-error-and-context-hardening.md | 33 ++++++ specs/pre-branch-sdd-gate.md | 15 ++- specs/repository-verification-setup-hooks.md | 8 +- .../__tests__/sdd_draft_consistency.test.ts | 18 +++ src/domain/sdd_draft_consistency.ts | 1 + .../untrusted_command_environment.test.ts | 7 ++ .../__tests__/configuration_recovery.test.ts | 104 +++++++++++++++++ .../description/configuration_handler.ts | 16 ++- .../description/configuration_markers.ts | 72 ++++++++++++ 15 files changed, 494 insertions(+), 12 deletions(-) create mode 100644 src/manager/description/configuration_markers.ts diff --git a/build/cli/index.js b/build/cli/index.js index 81eaa6c34..d73e2df5c 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -93506,6 +93506,8 @@ function validatePaths(source, inventory, sddPath) { if (change === 'create') { if (inventory.files.has(file) || inventory.directories.has(file)) fail('repository-path'); + if ([...proposed].some(other => file.startsWith(`${other}/`) || other.startsWith(`${file}/`))) + fail('repository-path'); const segments = file.split('/'); if (segments.some((_, index) => inventory.files.has(segments.slice(0, index + 1).join('/')) || inventory.blocked.has(segments.slice(0, index + 1).join('/')))) fail('repository-path'); @@ -104288,9 +104290,22 @@ const logger_1 = __nccwpck_require__(91151); const issue_content_interface_1 = __nccwpck_require__(60608); const configuration_payload_policy_1 = __nccwpck_require__(58043); const application_error_1 = __nccwpck_require__(75999); +const configuration_markers_1 = __nccwpck_require__(4586); class ConfigurationHandler extends issue_content_interface_1.IssueContentInterface { constructor() { super(...arguments); + this.getContent = (description) => { + const block = (0, configuration_markers_1.readConfigurationBlock)(description); + return block.kind === 'present' ? block.content : undefined; + }; + this.updateContent = (description, content) => { + if (description === undefined || content === undefined) + return undefined; + const updated = (0, configuration_markers_1.writeConfigurationBlock)(description, content); + if (updated === undefined) + (0, logger_1.logError)('The content has a problem with open-close tags: stored configuration.'); + return updated; + }; this.update = async (query, context) => { const storedRaw = await this.internalGetter(query); return this.internalUpdate(query, (0, configuration_payload_policy_1.buildConfigurationPayload)(context, storedRaw)); @@ -104310,8 +104325,7 @@ class ConfigurationHandler extends issue_content_interface_1.IssueContentInterfa try { const config = this.getContent(description); if (config === undefined) { - if (description?.includes('')) { + if ((0, configuration_markers_1.readConfigurationBlock)(description).kind === 'invalid') { throw new Error('Stored configuration markers are inconsistent.'); } return undefined; @@ -104347,6 +104361,96 @@ class ConfigurationHandler extends issue_content_interface_1.IssueContentInterfa exports.ConfigurationHandler = ConfigurationHandler; +/***/ }), + +/***/ 4586: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.CONFIGURATION_END = exports.CONFIGURATION_START = void 0; +exports.readConfigurationBlock = readConfigurationBlock; +exports.writeConfigurationBlock = writeConfigurationBlock; +exports.CONFIGURATION_START = ''; +/** Owned delimiters begin a line; ordinary mentions are not state. Complete legacy fenced records remain readable. */ +function readConfigurationBlock(description) { + if (description === undefined) + return { kind: 'absent' }; + let fence; + let fencedMarker = false; + let fencedStart; + let nestedFencedStart = false; + let start; + let contentStart = 0; + let block; + let offset = 0; + for (const line of description.match(/[^\n]*(?:\n|$)/gu) ?? []) { + const text = line.replace(/\r?\n$/u, ''); + const starts = /^ {0,3}[ \t]*$/u.test(text); + const boundary = /^ {0,3}(`{3,}|~{3,})(.*)$/u.exec(text); + if (fence) { + fencedMarker || (fencedMarker = starts || ends); + if (starts) { + if (fencedStart !== undefined) + nestedFencedStart = true; + else + fencedStart = offset + text.indexOf(exports.CONFIGURATION_START); + } + const end = text.indexOf(exports.CONFIGURATION_END); + if (fencedStart !== undefined && end >= 0 && !text.slice(end + exports.CONFIGURATION_END.length).trim()) { + if (block || nestedFencedStart) + return { kind: 'invalid' }; + block = { kind: 'present', start: fencedStart, end: offset + end + exports.CONFIGURATION_END.length, + content: description.slice(fencedStart + exports.CONFIGURATION_START.length, offset + end) }; + fencedStart = undefined; + } + if (boundary && boundary[1][0] === fence[0] && boundary[1].length >= fence.length && !boundary[2].trim()) { + fence = undefined; + fencedMarker = false; + fencedStart = undefined; + nestedFencedStart = false; + } + } + else if (start !== undefined || starts) { + if (starts) { + if (start !== undefined || block) + return { kind: 'invalid' }; + start = offset + text.indexOf(exports.CONFIGURATION_START); + contentStart = start + exports.CONFIGURATION_START.length; + } + const end = text.indexOf(exports.CONFIGURATION_END); + if (end >= 0 && !text.slice(end + exports.CONFIGURATION_END.length).trim()) { + block = { kind: 'present', start: start, end: offset + end + exports.CONFIGURATION_END.length, + content: description.slice(contentStart, offset + end) }; + start = undefined; + } + } + else if (ends) + return { kind: 'invalid' }; + else if (boundary && (boundary[1][0] !== '`' || !boundary[2].includes('`'))) + fence = boundary[1]; + offset += line.length; + } + // A legacy block behind an unclosed fence is ambiguous: never silently discard its state. + if (start !== undefined || fence && fencedMarker) + return { kind: 'invalid' }; + return block ?? { kind: 'absent', ...(fence ? { closingFence: fence } : {}) }; +} +function writeConfigurationBlock(description, content) { + const block = readConfigurationBlock(description); + if (block.kind === 'invalid') + return undefined; + const replacement = `${exports.CONFIGURATION_START}\n${content}\n${exports.CONFIGURATION_END}`; + if (block.kind === 'present') + return description.slice(0, block.start) + replacement + description.slice(block.end); + // Closing an otherwise empty dangling example preserves its rendered text and keeps new state outside it. + return `${description}\n\n${block.closingFence ? `${block.closingFence}\n\n` : ''}${replacement}`; +} + + /***/ }), /***/ 58043: diff --git a/build/github_action/index.js b/build/github_action/index.js index 1addc7cdf..3f4ba22d8 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -83950,6 +83950,8 @@ function validatePaths(source, inventory, sddPath) { if (change === 'create') { if (inventory.files.has(file) || inventory.directories.has(file)) fail('repository-path'); + if ([...proposed].some(other => file.startsWith(`${other}/`) || other.startsWith(`${file}/`))) + fail('repository-path'); const segments = file.split('/'); if (segments.some((_, index) => inventory.files.has(segments.slice(0, index + 1).join('/')) || inventory.blocked.has(segments.slice(0, index + 1).join('/')))) fail('repository-path'); @@ -90876,9 +90878,22 @@ const logger_1 = __nccwpck_require__(91151); const issue_content_interface_1 = __nccwpck_require__(60608); const configuration_payload_policy_1 = __nccwpck_require__(58043); const application_error_1 = __nccwpck_require__(75999); +const configuration_markers_1 = __nccwpck_require__(4586); class ConfigurationHandler extends issue_content_interface_1.IssueContentInterface { constructor() { super(...arguments); + this.getContent = (description) => { + const block = (0, configuration_markers_1.readConfigurationBlock)(description); + return block.kind === 'present' ? block.content : undefined; + }; + this.updateContent = (description, content) => { + if (description === undefined || content === undefined) + return undefined; + const updated = (0, configuration_markers_1.writeConfigurationBlock)(description, content); + if (updated === undefined) + (0, logger_1.logError)('The content has a problem with open-close tags: stored configuration.'); + return updated; + }; this.update = async (query, context) => { const storedRaw = await this.internalGetter(query); return this.internalUpdate(query, (0, configuration_payload_policy_1.buildConfigurationPayload)(context, storedRaw)); @@ -90898,8 +90913,7 @@ class ConfigurationHandler extends issue_content_interface_1.IssueContentInterfa try { const config = this.getContent(description); if (config === undefined) { - if (description?.includes('')) { + if ((0, configuration_markers_1.readConfigurationBlock)(description).kind === 'invalid') { throw new Error('Stored configuration markers are inconsistent.'); } return undefined; @@ -90935,6 +90949,96 @@ class ConfigurationHandler extends issue_content_interface_1.IssueContentInterfa exports.ConfigurationHandler = ConfigurationHandler; +/***/ }), + +/***/ 4586: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.CONFIGURATION_END = exports.CONFIGURATION_START = void 0; +exports.readConfigurationBlock = readConfigurationBlock; +exports.writeConfigurationBlock = writeConfigurationBlock; +exports.CONFIGURATION_START = ''; +/** Owned delimiters begin a line; ordinary mentions are not state. Complete legacy fenced records remain readable. */ +function readConfigurationBlock(description) { + if (description === undefined) + return { kind: 'absent' }; + let fence; + let fencedMarker = false; + let fencedStart; + let nestedFencedStart = false; + let start; + let contentStart = 0; + let block; + let offset = 0; + for (const line of description.match(/[^\n]*(?:\n|$)/gu) ?? []) { + const text = line.replace(/\r?\n$/u, ''); + const starts = /^ {0,3}[ \t]*$/u.test(text); + const boundary = /^ {0,3}(`{3,}|~{3,})(.*)$/u.exec(text); + if (fence) { + fencedMarker || (fencedMarker = starts || ends); + if (starts) { + if (fencedStart !== undefined) + nestedFencedStart = true; + else + fencedStart = offset + text.indexOf(exports.CONFIGURATION_START); + } + const end = text.indexOf(exports.CONFIGURATION_END); + if (fencedStart !== undefined && end >= 0 && !text.slice(end + exports.CONFIGURATION_END.length).trim()) { + if (block || nestedFencedStart) + return { kind: 'invalid' }; + block = { kind: 'present', start: fencedStart, end: offset + end + exports.CONFIGURATION_END.length, + content: description.slice(fencedStart + exports.CONFIGURATION_START.length, offset + end) }; + fencedStart = undefined; + } + if (boundary && boundary[1][0] === fence[0] && boundary[1].length >= fence.length && !boundary[2].trim()) { + fence = undefined; + fencedMarker = false; + fencedStart = undefined; + nestedFencedStart = false; + } + } + else if (start !== undefined || starts) { + if (starts) { + if (start !== undefined || block) + return { kind: 'invalid' }; + start = offset + text.indexOf(exports.CONFIGURATION_START); + contentStart = start + exports.CONFIGURATION_START.length; + } + const end = text.indexOf(exports.CONFIGURATION_END); + if (end >= 0 && !text.slice(end + exports.CONFIGURATION_END.length).trim()) { + block = { kind: 'present', start: start, end: offset + end + exports.CONFIGURATION_END.length, + content: description.slice(contentStart, offset + end) }; + start = undefined; + } + } + else if (ends) + return { kind: 'invalid' }; + else if (boundary && (boundary[1][0] !== '`' || !boundary[2].includes('`'))) + fence = boundary[1]; + offset += line.length; + } + // A legacy block behind an unclosed fence is ambiguous: never silently discard its state. + if (start !== undefined || fence && fencedMarker) + return { kind: 'invalid' }; + return block ?? { kind: 'absent', ...(fence ? { closingFence: fence } : {}) }; +} +function writeConfigurationBlock(description, content) { + const block = readConfigurationBlock(description); + if (block.kind === 'invalid') + return undefined; + const replacement = `${exports.CONFIGURATION_START}\n${content}\n${exports.CONFIGURATION_END}`; + if (block.kind === 'present') + return description.slice(0, block.start) + replacement + description.slice(block.end); + // Closing an otherwise empty dangling example preserves its rendered text and keeps new state outside it. + return `${description}\n\n${block.closingFence ? `${block.closingFence}\n\n` : ''}${replacement}`; +} + + /***/ }), /***/ 58043: diff --git a/docs/issues/pre-branch-sdds.mdx b/docs/issues/pre-branch-sdds.mdx index 88893f0c8..ffb335860 100644 --- a/docs/issues/pre-branch-sdds.mdx +++ b/docs/issues/pre-branch-sdds.mdx @@ -196,6 +196,9 @@ choose distinct full IDs, reconcile each area's cases, repair both directions of the mappings, or correct the paths and explicitly proposed files. No further generation or publication occurs in that run. Review the named contract and retry the same issue workflow; answered questions and historical commits remain. +Proposed files must also be compatible with one another: a file cannot be the +parent directory of another proposed file, in either declaration order or at +any nesting depth. Sibling files and distinct pathname prefixes remain valid. All validation and freshness checks still apply. If the second draft still fails, no draft is published; existing answers and SDDs are retained. Retry with a proportional change or an approved companion specification. diff --git a/docs/security-operations/operations/troubleshooting.mdx b/docs/security-operations/operations/troubleshooting.mdx index b48a1c140..f21ba8a50 100644 --- a/docs/security-operations/operations/troubleshooting.mdx +++ b/docs/security-operations/operations/troubleshooting.mdx @@ -563,6 +563,14 @@ will fail again. The failed read does not change the body or stored state. | Missing schema, unsupported version, malformed JSON/value or incomplete delimiters | Stored state cannot be trusted | A maintainer must review it before retrying. | | Valid current-schema block | Supported state | Continue through normal validation; this is not a reset instruction. | +An ordinary inline mention or closed code example containing only an opening or +closing marker is not stored state and does not cause a configuration error. +Complete legacy blocks inside code fences still undergo strict validation; +avoid reproducing complete live delimiter pairs in examples. Multiple complete +blocks or potential state behind an unclosed fence require maintainer review, +so Copilot never silently discards one record or chooses between conflicting +records. Reads and updates preserve the human description around the owned block. + Recovery is manual and depends on what the block owns: 1. Preserve the original body using GitHub history or a copy before editing. diff --git a/specs/CATALOG.md b/specs/CATALOG.md index 6818dabd1..fec86054c 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -14,7 +14,7 @@ debt or convert unknown historic intent into a design decision. | `release-orchestration` | Implemented | Release and hotfix promotion, publication, bounded merge readiness recovery, and receipt-verified reconciliation without republication | [Configurable production-first release orchestration](./configurable-release-orchestration.md) + 2 companion | 59 paths · 2026-10-16 | | `merge-queue-readiness` | Implemented | Fail-closed validation of required checks and merge-group workflow support; optional manual-only RepoWise analysis with independent CI and verified required-check migration; cached RepoWise exports and bounded full-history secret processing with truthful completeness and resource evidence | [Merge queue readiness and effective target rules](./merge-queue-readiness.md) | 29 paths · 2026-10-21 | | `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 70 paths · 2026-10-21 | -| `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 104 paths · 2026-10-21 | +| `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 105 paths · 2026-10-21 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | | `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 5 companion | 328 paths · 2026-10-20 | | `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 2 companion | 247 paths · 2026-10-21 | @@ -85,7 +85,7 @@ debt or convert unknown historic intent into a design decision. - Specifications: [`specs/execution-admission-queue-and-publication.md`](./execution-admission-queue-and-publication.md) · [`specs/execution-error-and-context-hardening.md`](./execution-error-and-context-hardening.md) · [`specs/execution-boundary-closure-audit.md`](./execution-boundary-closure-audit.md) · [`specs/push-and-single-action-context-hardening.md`](./push-and-single-action-context-hardening.md) - Workflows: [`.github/workflows/copilot_issue.yml`](../.github/workflows/copilot_issue.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_pull_request.yml`](../.github/workflows/copilot_pull_request.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) · [`.github/workflows/copilot_commit.yml`](../.github/workflows/copilot_commit.yml) - Entrypoints: [`src/actions/github_action.ts`](../src/actions/github_action.ts) · [`src/actions/common_action.ts`](../src/actions/common_action.ts) -- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/validate-coverage-budgets.cjs`](../scripts/validate-coverage-budgets.cjs) · [`src/actions/main_run_lifecycle.ts`](../src/actions/main_run_lifecycle.ts) · [`src/actions/main_run_route.ts`](../src/actions/main_run_route.ts) · [`src/actions/github_action_completion.ts`](../src/actions/github_action_completion.ts) · [`src/api.ts`](../src/api.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/errors/application_error.ts`](../src/application/errors/application_error.ts) · [`src/application/errors/application_error_context.ts`](../src/application/errors/application_error_context.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/application/policies/application_error_presentation_policy.ts`](../src/application/policies/application_error_presentation_policy.ts) · [`src/application/policies/bugbot_result_finding_state_projection_policy.ts`](../src/application/policies/bugbot_result_finding_state_projection_policy.ts) · [`src/application/policies/bugbot_telemetry_projection_policy.ts`](../src/application/policies/bugbot_telemetry_projection_policy.ts) · [`src/application/policies/action_summary_policy.ts`](../src/application/policies/action_summary_policy.ts) · [`src/application/policies/copilot_evidence_policy.ts`](../src/application/policies/copilot_evidence_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/policies/github_execution_admission_policy.ts`](../src/application/policies/github_execution_admission_policy.ts) · [`src/application/policies/workflow_queue_policy.ts`](../src/application/policies/workflow_queue_policy.ts) · [`src/application/usecases/actions/lifecycle_synchronization_context.ts`](../src/application/usecases/actions/lifecycle_synchronization_context.ts) · [`src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts`](../src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts) · [`src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts`](../src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts) · [`src/application/policies/semantic_result_publication_policy.ts`](../src/application/policies/semantic_result_publication_policy.ts) · [`src/application/usecases/steps/common/status_card_publication_workflow.ts`](../src/application/usecases/steps/common/status_card_publication_workflow.ts) · [`src/application/usecases/comment_automation_context.ts`](../src/application/usecases/comment_automation_context.ts) · [`src/application/usecases/issue_workflow_context.ts`](../src/application/usecases/issue_workflow_context.ts) · [`src/application/usecases/pull_request_workflow_context.ts`](../src/application/usecases/pull_request_workflow_context.ts) · [`src/application/usecases/push_single_action_contexts.ts`](../src/application/usecases/push_single_action_contexts.ts) · [`src/application/usecases/steps/common/check_permissions_workflow.ts`](../src/application/usecases/steps/common/check_permissions_workflow.ts) · [`src/application/usecases/steps/common/comment_language_translation_workflow.ts`](../src/application/usecases/steps/common/comment_language_translation_workflow.ts) · [`src/application/usecases/steps/common/think_workflow.ts`](../src/application/usecases/steps/common/think_workflow.ts) · [`src/application/usecases/steps/common/update_title_workflow.ts`](../src/application/usecases/steps/common/update_title_workflow.ts) · [`src/application/usecases/steps/common/project_content_link_workflow.ts`](../src/application/usecases/steps/common/project_content_link_workflow.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`src/application/usecases/steps/common/store_configuration_use_case.ts`](../src/application/usecases/steps/common/store_configuration_use_case.ts) · [`src/infrastructure/composition/shared_capability_port_binding.ts`](../src/infrastructure/composition/shared_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_capability_port_binding.ts`](../src/infrastructure/composition/lifecycle_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_state_composition_root.ts`](../src/infrastructure/composition/lifecycle_state_composition_root.ts) · [`src/infrastructure/composition/push_single_action_capability_port_binding.ts`](../src/infrastructure/composition/push_single_action_capability_port_binding.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/application/policies/configuration_persistence_policy.ts`](../src/application/policies/configuration_persistence_policy.ts) · [`src/application/ports/project_board_query_ports.ts`](../src/application/ports/project_board_query_ports.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts) · [`src/application/usecases/steps/commit/update_change_size_labels.ts`](../src/application/usecases/steps/commit/update_change_size_labels.ts) · [`src/data/repository/project/project_board_item_query.ts`](../src/data/repository/project/project_board_item_query.ts) · [`src/infrastructure/composition/change_size_project_membership_composition_root.ts`](../src/infrastructure/composition/change_size_project_membership_composition_root.ts) · [`src/manager/description/configuration_handler.ts`](../src/manager/description/configuration_handler.ts) · [`src/data/repository/issue/issue_content_repository.ts`](../src/data/repository/issue/issue_content_repository.ts) · [`src/data/repository/github/github_error_policy.ts`](../src/data/repository/github/github_error_policy.ts) +- Core code: [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/validate-coverage-budgets.cjs`](../scripts/validate-coverage-budgets.cjs) · [`src/actions/main_run_lifecycle.ts`](../src/actions/main_run_lifecycle.ts) · [`src/actions/main_run_route.ts`](../src/actions/main_run_route.ts) · [`src/actions/github_action_completion.ts`](../src/actions/github_action_completion.ts) · [`src/api.ts`](../src/api.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/errors/application_error.ts`](../src/application/errors/application_error.ts) · [`src/application/errors/application_error_context.ts`](../src/application/errors/application_error_context.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/application/policies/application_error_presentation_policy.ts`](../src/application/policies/application_error_presentation_policy.ts) · [`src/application/policies/bugbot_result_finding_state_projection_policy.ts`](../src/application/policies/bugbot_result_finding_state_projection_policy.ts) · [`src/application/policies/bugbot_telemetry_projection_policy.ts`](../src/application/policies/bugbot_telemetry_projection_policy.ts) · [`src/application/policies/action_summary_policy.ts`](../src/application/policies/action_summary_policy.ts) · [`src/application/policies/copilot_evidence_policy.ts`](../src/application/policies/copilot_evidence_policy.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/application/policies/status_command_policy.ts`](../src/application/policies/status_command_policy.ts) · [`src/application/policies/github_execution_admission_policy.ts`](../src/application/policies/github_execution_admission_policy.ts) · [`src/application/policies/workflow_queue_policy.ts`](../src/application/policies/workflow_queue_policy.ts) · [`src/application/usecases/actions/lifecycle_synchronization_context.ts`](../src/application/usecases/actions/lifecycle_synchronization_context.ts) · [`src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts`](../src/application/usecases/actions/synchronize_lifecycle_state_use_case.ts) · [`src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts`](../src/application/usecases/steps/commit/bugbot/bugbot_review_operation_context.ts) · [`src/application/policies/semantic_result_publication_policy.ts`](../src/application/policies/semantic_result_publication_policy.ts) · [`src/application/usecases/steps/common/status_card_publication_workflow.ts`](../src/application/usecases/steps/common/status_card_publication_workflow.ts) · [`src/application/usecases/comment_automation_context.ts`](../src/application/usecases/comment_automation_context.ts) · [`src/application/usecases/issue_workflow_context.ts`](../src/application/usecases/issue_workflow_context.ts) · [`src/application/usecases/pull_request_workflow_context.ts`](../src/application/usecases/pull_request_workflow_context.ts) · [`src/application/usecases/push_single_action_contexts.ts`](../src/application/usecases/push_single_action_contexts.ts) · [`src/application/usecases/steps/common/check_permissions_workflow.ts`](../src/application/usecases/steps/common/check_permissions_workflow.ts) · [`src/application/usecases/steps/common/comment_language_translation_workflow.ts`](../src/application/usecases/steps/common/comment_language_translation_workflow.ts) · [`src/application/usecases/steps/common/think_workflow.ts`](../src/application/usecases/steps/common/think_workflow.ts) · [`src/application/usecases/steps/common/update_title_workflow.ts`](../src/application/usecases/steps/common/update_title_workflow.ts) · [`src/application/usecases/steps/common/project_content_link_workflow.ts`](../src/application/usecases/steps/common/project_content_link_workflow.ts) · [`src/application/usecases/steps/common/publish_resume_workflow.ts`](../src/application/usecases/steps/common/publish_resume_workflow.ts) · [`src/application/usecases/steps/common/store_configuration_use_case.ts`](../src/application/usecases/steps/common/store_configuration_use_case.ts) · [`src/infrastructure/composition/shared_capability_port_binding.ts`](../src/infrastructure/composition/shared_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_capability_port_binding.ts`](../src/infrastructure/composition/lifecycle_capability_port_binding.ts) · [`src/infrastructure/composition/lifecycle_state_composition_root.ts`](../src/infrastructure/composition/lifecycle_state_composition_root.ts) · [`src/infrastructure/composition/push_single_action_capability_port_binding.ts`](../src/infrastructure/composition/push_single_action_capability_port_binding.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/application/policies/configuration_persistence_policy.ts`](../src/application/policies/configuration_persistence_policy.ts) · [`src/application/ports/project_board_query_ports.ts`](../src/application/ports/project_board_query_ports.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_use_case.ts) · [`src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts`](../src/application/usecases/steps/commit/check_changes_issue_size_workflow.ts) · [`src/application/usecases/steps/commit/update_change_size_labels.ts`](../src/application/usecases/steps/commit/update_change_size_labels.ts) · [`src/data/repository/project/project_board_item_query.ts`](../src/data/repository/project/project_board_item_query.ts) · [`src/infrastructure/composition/change_size_project_membership_composition_root.ts`](../src/infrastructure/composition/change_size_project_membership_composition_root.ts) · [`src/manager/description/configuration_handler.ts`](../src/manager/description/configuration_handler.ts) · [`src/manager/description/configuration_markers.ts`](../src/manager/description/configuration_markers.ts) · [`src/data/repository/issue/issue_content_repository.ts`](../src/data/repository/issue/issue_content_repository.ts) · [`src/data/repository/github/github_error_policy.ts`](../src/data/repository/github/github_error_policy.ts) - Tests: [`src/tooling/__tests__/coverage_budget_validator.test.ts`](../src/tooling/__tests__/coverage_budget_validator.test.ts) · [`src/__tests__/api.test.ts`](../src/__tests__/api.test.ts) · [`src/actions/__tests__/github_action.test.ts`](../src/actions/__tests__/github_action.test.ts) · [`src/actions/__tests__/github_action_completion.test.ts`](../src/actions/__tests__/github_action_completion.test.ts) · [`src/application/errors/__tests__/application_error.test.ts`](../src/application/errors/__tests__/application_error.test.ts) · [`src/application/policies/__tests__/application_error_message_catalog.test.ts`](../src/application/policies/__tests__/application_error_message_catalog.test.ts) · [`src/application/policies/__tests__/application_error_presentation_policy.test.ts`](../src/application/policies/__tests__/application_error_presentation_policy.test.ts) · [`src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_result_finding_state_projection_policy.test.ts) · [`src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts`](../src/application/policies/__tests__/bugbot_telemetry_projection_policy.test.ts) · [`src/application/policies/__tests__/action_summary_policy.test.ts`](../src/application/policies/__tests__/action_summary_policy.test.ts) · [`src/application/policies/__tests__/copilot_evidence_policy.test.ts`](../src/application/policies/__tests__/copilot_evidence_policy.test.ts) · [`src/application/policies/__tests__/lifecycle_state_policy.test.ts`](../src/application/policies/__tests__/lifecycle_state_policy.test.ts) · [`src/application/policies/__tests__/status_command_policy.test.ts`](../src/application/policies/__tests__/status_command_policy.test.ts) · [`src/application/usecases/actions/__tests__/lifecycle_synchronization_context.test.ts`](../src/application/usecases/actions/__tests__/lifecycle_synchronization_context.test.ts) · [`src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts`](../src/application/usecases/actions/__tests__/synchronize_lifecycle_state_use_case.test.ts) · [`src/application/usecases/actions/__tests__/lifecycle_event_replay.integration.test.ts`](../src/application/usecases/actions/__tests__/lifecycle_event_replay.integration.test.ts) · [`src/architecture/__tests__/execution_import_ratchet.test.ts`](../src/architecture/__tests__/execution_import_ratchet.test.ts) · [`src/architecture/__tests__/raw_error_logging_boundaries.test.ts`](../src/architecture/__tests__/raw_error_logging_boundaries.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/bugbot_review_operation_context.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/bugbot_review_operation_context.test.ts) · [`src/application/usecases/steps/common/__tests__/shared_capability_context_projection.test.ts`](../src/application/usecases/steps/common/__tests__/shared_capability_context_projection.test.ts) · [`src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts`](../src/application/usecases/steps/common/__tests__/publish_resume_use_case.test.ts) · [`src/infrastructure/composition/__tests__/shared_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/shared_capability_port_binding.test.ts) · [`src/application/usecases/__tests__/issue_pull_request_context_projection.test.ts`](../src/application/usecases/__tests__/issue_pull_request_context_projection.test.ts) · [`src/infrastructure/composition/__tests__/lifecycle_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/lifecycle_capability_port_binding.test.ts) · [`src/infrastructure/composition/__tests__/lifecycle_state_composition_root.test.ts`](../src/infrastructure/composition/__tests__/lifecycle_state_composition_root.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/usecases/__tests__/single_action_workflow.test.ts`](../src/application/usecases/__tests__/single_action_workflow.test.ts) · [`src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts) · [`src/application/usecases/execution/__tests__/resolve_github_execution_admission_use_case.test.ts`](../src/application/usecases/execution/__tests__/resolve_github_execution_admission_use_case.test.ts) · [`src/application/usecases/workflow/__tests__/wait_for_previous_workflow_runs_use_case.test.ts`](../src/application/usecases/workflow/__tests__/wait_for_previous_workflow_runs_use_case.test.ts) · [`src/application/policies/__tests__/configuration_persistence_policy.test.ts`](../src/application/policies/__tests__/configuration_persistence_policy.test.ts) · [`src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts`](../src/application/usecases/steps/commit/__tests__/check_changes_issue_size_use_case.test.ts) · [`src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts`](../src/application/usecases/steps/commit/__tests__/update_change_size_labels.test.ts) · [`src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts`](../src/data/repository/project/__tests__/project_board_visibility_recovery.test.ts) · [`src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts`](../src/infrastructure/composition/__tests__/change_size_project_membership_composition_root.test.ts) · [`src/manager/description/__tests__/configuration_recovery.test.ts`](../src/manager/description/__tests__/configuration_recovery.test.ts) · [`src/manager/description/__tests__/configuration_handler.test.ts`](../src/manager/description/__tests__/configuration_handler.test.ts) · [`src/data/repository/issue/__tests__/issue_content_repository.test.ts`](../src/data/repository/issue/__tests__/issue_content_repository.test.ts) - User documentation: [`docs/overview.mdx`](../docs/overview.mdx) · [`docs/bugbot/programmatic-api.mdx`](../docs/bugbot/programmatic-api.mdx) · [`docs/security-operations/operations/error-reference.mdx`](../docs/security-operations/operations/error-reference.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/bugbot/quality-observability.mdx`](../docs/bugbot/quality-observability.mdx) · [`docs/bugbot/failure-scenarios.mdx`](../docs/bugbot/failure-scenarios.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/issues/assignees-and-projects.mdx`](../docs/issues/assignees-and-projects.mdx) · [`docs/configuration.mdx`](../docs/configuration.mdx) diff --git a/specs/catalog.json b/specs/catalog.json index 0f567c8ab..35802a0b4 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -598,6 +598,7 @@ "src/data/repository/project/project_board_item_query.ts", "src/infrastructure/composition/change_size_project_membership_composition_root.ts", "src/manager/description/configuration_handler.ts", + "src/manager/description/configuration_markers.ts", "src/data/repository/issue/issue_content_repository.ts", "src/data/repository/github/github_error_policy.ts" ], diff --git a/specs/execution-error-and-context-hardening.md b/specs/execution-error-and-context-hardening.md index f245e17b0..d19bb0d58 100644 --- a/specs/execution-error-and-context-hardening.md +++ b/specs/execution-error-and-context-hardening.md @@ -906,3 +906,36 @@ catalog evidence and generated catalog. The implementation sequence is closed facts/reader, final boundary and localization, adapter mapping, deterministic tests, docs/catalog, then validation. Done requires all acceptance rows to pass, generated evidence to be current and strict rejection to remain intact. + +### Literal configuration marker mentions: release review #660 (2026-10-21) + +Finding 4342237487 exposed a false configuration error for an ordinary mention +of one delimiter. The description-format adapter MUST distinguish such prose, +inline/indented quotes and closed, unpaired code examples from actual state. +Actual delimiters begin a line with at most three spaces. A complete legacy +record inside a code fence MUST retain strict parsing, not become absent: this +preserves the previous reader's state ownership and existing recovery guidance. +Multiple complete records, incomplete actual delimiters and potential state +behind an unclosed fence MUST fail closed without provider writes or state loss. +JSON backticks, CRLF records and single-line records beginning a line remain +supported. No payload schema, permission, locale, setting or reset is added. + +Both reading and persistence MUST use the same description-format policy in +src/manager/description/configuration_markers.ts. A first write appends state +after literal mentions without altering the human prefix; it closes a dangling +code example with no existing record before appending owned metadata. An update +replaces only the verified owned span. Generic non-configuration content blocks +retain their existing adapter. The existing configuration.invalid diagnosis, +nonretryability and maintainer recovery UI apply to ambiguous state. Rollback +selects the prior reader while preserving description history and state. + +The additional floor is **21 distinct cases** in configuration_recovery.test.ts: +nine ordinary mention/unpaired fence variants, six legacy/format/selection +boundaries, three actual malformed/duplicate/ambiguous-state guards and three +write/read preservation journeys. Every rejection asserts no provider write; +write cases preserve the original human text and read the resulting supported +state. Changed format policy targets at least 95% lines and 90% branches, with +the existing global quality gates unchanged. These tests establish this format +boundary rather than provider runtime readiness. Update troubleshooting, catalog +evidence and generated catalog, then pass focused/full tests, type/lint, +documentation/specification checks and rebuilt package gates before release. diff --git a/specs/pre-branch-sdd-gate.md b/specs/pre-branch-sdd-gate.md index 6d3b354bc..6823b7f4f 100644 --- a/specs/pre-branch-sdd-gate.md +++ b/specs/pre-branch-sdd-gate.md @@ -1227,16 +1227,16 @@ headings, mobile/screen-reader behavior and closed sanitized content. Rejected Markdown, case IDs, paths and diagnostic text MUST NOT enter repair instructions or public messages. There is no additional card, label, credential or setting. -The amendment has a minimum **120 distinct cases**, separate from earlier floors: +The amendment has a minimum **126 distinct cases**, separate from earlier floors: | Area | Minimum distinct cases | Behaviors/risks covered | |---|---:|---| -| Pure consistency policy | 89 | Owner collisions and aliases, hidden/malformed inventories, invalid/valid fence and comment boundaries, offsetting budgets, reciprocal mappings, immutable/proposed paths and relative URL components, portable layouts and bounded ranges | +| Pure consistency policy | 95 | Owner collisions and aliases, hidden/malformed inventories, invalid/valid fence and comment boundaries, offsetting budgets, reciprocal mappings, immutable/proposed paths and relative URL components, mutually incompatible proposed paths, portable layouts and bounded ranges | | Application and bounded draft workflow | 9 | All-owner reads, missing/oversized context, blocked publication, four closed repairs and corrected-draft revalidation | | Publication replay boundaries | 5 | Minimum/maximum candidate lengths, normalized outer whitespace, retained prefix and exact recomposition | | Real Git workspace | 13 | Each reported contradiction and falsely closed code block blocks publication; valid relative-link queries resolve immutable/proposed evidence; ignores uncommitted evidence, preserves the owner and removes scratch worktrees | | Localized recovery | 4 | All four closed variants render English/Spanish retained state without runtime acceptance claims | -| **Total** | **120** | Existing cases are not recounted | +| **Total** | **126** | Existing cases are not recounted | Repository coverage thresholds remain mandatory; new pure policy targets at least 95% lines, with negative/boundary branch fixtures. Tests use deterministic @@ -1299,3 +1299,12 @@ cannot make a missing, invalidly encoded or unsafe pathname valid. Seven pure and two real Git update/companion cases cover existing/proposed paths, combined query/fragment destinations and negative evidence. These nine cases raise the floor from 111 to 120; docs/issues/pre-branch-sdds.mdx documents the URL behavior. + +Release PR #660 finding 4342237483 requires all proposed files to be compatible +with one another as well as the immutable tree. A proposed regular file MUST +NOT also be an ancestor of another proposed file, independent of table order +or nesting depth. Six additional pure cases reject both orders at direct and +deeper depths and accept siblings and distinct pathname prefixes. They raise +the pure floor to 95 and the amendment total to 126. Existing closed path +diagnostics, one-repair budget, immutable evidence and no-publication behavior +remain unchanged; the pre-branch SDD guide documents this boundary. diff --git a/specs/repository-verification-setup-hooks.md b/specs/repository-verification-setup-hooks.md index 8bc3851e2..0b2d95d1f 100644 --- a/specs/repository-verification-setup-hooks.md +++ b/specs/repository-verification-setup-hooks.md @@ -105,13 +105,19 @@ Text equivalent: Copilot prepares the candidate, pauses, the runner executes tru 1. Composition MUST capture immutable trusted Git objects before candidate mutation. The action directory is limited to 32 regular files, 64 KiB per file and 256 KiB total. Its root metadata MUST be `action.yml`, valid composite YAML with 1–32 steps. Asset paths MUST use portable ASCII letters/digits/underscore/dot/dash/slash, at most 200 characters, without empty/parent segments or Windows reserved names. Symlinks, submodules, unsafe paths and nested local `uses` actions are rejected. Native external actions and reviewed auxiliary scripts are supported. 2. At the existing verifier boundary, a private same-job worker MUST retain the admitted call stack. Generated workflows do not rerun the full operation to continue it. 3. The worker MUST bind HEAD, symbolic branch, index, tracked changes and publishable untracked contents. Git observations are bounded to 16 MiB, 256 untracked files and 16 MiB aggregate untracked contents; oversized candidates fail closed. Ignored dependency caches are excluded. -4. The trusted snapshot MUST be staged at the reserved local metadata path `.git/copilot-verification-setup`, outside publishable candidate files. Native execution requires the normal directory-based `.git` checkout produced by generated `actions/checkout` steps. The candidate's consumer action directory MUST never be rewritten. Staging MUST persist until native post steps finish. Runner state MUST retain the initial source SHA and digest of all captured file paths, bytes and modes. Before each composite post phase, a trusted Copilot post step MUST use its initially pinned absolute Git executable to restore that exact snapshot from Git objects at the pinned SHA and verify the saved digest, never a moved branch or candidate file. An unknown preexisting staging directory MUST fail closed without being overwritten. +4. The trusted snapshot MUST be staged at the reserved local metadata path `.git/copilot-verification-setup`, outside publishable candidate files. Native execution requires the normal directory-based `.git` checkout produced by generated `actions/checkout` steps. The candidate's consumer action directory MUST never be rewritten. Staging MUST persist until native post steps finish. Runner state MUST retain the initial source SHA and digest of all captured file paths, bytes and modes. Before each runner-managed aggregate composite post phase, a trusted Copilot post step MUST use its initially pinned absolute Git executable to restore that exact snapshot from Git objects at the pinned SHA and verify the saved digest, never a moved branch or candidate file. This aggregate phase contains the nested actions' post hooks; it is not a composite YAML `post` key or a restoration between individual nested hooks. An unknown preexisting staging directory MUST fail closed without being overwritten. 5. The continuation MUST match the session, current request, run, attempt, job and workspace. Duplicate/stale responses fail closed. The candidate identity MUST still match. 6. Only new existing PATH directories within the workspace, private HOME or trusted tool cache, and an approved JAVA_HOME, MAY reach the verifier. The existing closed 16-KiB result validation and eight-directory ceiling remain in force. 7. Runtime preflight and the configured command MUST execute in that same fresh environment. Basename resolution MUST use its validated PATH, preserving virtual-environment invocation paths rather than the worker PATH or canonical binary target. Subsequent commands repeat setup with a new HOME and the current manifests. ### 6.2 Alternative paths +GitHub's [accepted runner lifecycle ADR](https://github.com/actions/runner/blob/main/docs/adrs/1144-composite-actions.md#prepost-steps-in-nested-actions) +defines the aggregate post step and reverse ordering used above. The trusted +worker output channel belongs to Copilot; repository verification processes +receive the closed environment without GitHub file-command or worker-session +paths. Same-user filesystem access remains the explicit §11 operator boundary. + Disabled setup preserves existing behavior. Enabled setup without native workflow support, including local CLI verification, MUST fail closed with an explanation to update workflows and run in GitHub Actions. Snapshot errors are deferred on routes that do not verify. No automatic setup retry or shared readiness cache is permitted. ### 6.3 State machine diff --git a/src/domain/__tests__/sdd_draft_consistency.test.ts b/src/domain/__tests__/sdd_draft_consistency.test.ts index 03920e81e..035f5044e 100644 --- a/src/domain/__tests__/sdd_draft_consistency.test.ts +++ b/src/domain/__tests__/sdd_draft_consistency.test.ts @@ -158,6 +158,24 @@ describe('generated SDD consistency', () => { expect(() => validate(markdown)).not.toThrow(); }); + it.each([ + ['docs/new.md', 'docs/new.md/child.md'], + ['docs/new.md/child.md', 'docs/new.md'], + ['docs/new.md', 'docs/new.md/nested/child.md'], + ['docs/new.md/nested/child.md', 'docs/new.md'], + ])('rejects incompatible proposed files %s and %s in either declaration order', (first, second) => { + const markdown = sddConsistencyFixture().replace('| docs/payments.mdx | update |', `| ${first} | create |\n| ${second} | create |`); + expect(() => validate(markdown)).toThrow(expect.objectContaining({ reason: 'repository-path' })); + }); + + it.each([ + ['docs/new/first.md', 'docs/new/second.md'], + ['docs/new.md', 'docs/new.mdx/child.md'], + ])('accepts compatible proposed files %s and %s', (first, second) => { + const markdown = sddConsistencyFixture().replace('| docs/payments.mdx | update |', `| ${first} | create |\n| ${second} | create |`); + expect(() => validate(markdown)).not.toThrow(); + }); + it.each([ '../docs/payments.mdx?view=compact', '../docs/payments.mdx?view=compact#intro', './change.md?draft=1', '?view=compact', ])('resolves the repository pathname of relative destination %s without its query or fragment', href => { diff --git a/src/domain/sdd_draft_consistency.ts b/src/domain/sdd_draft_consistency.ts index e92ab6fd8..060c4d176 100644 --- a/src/domain/sdd_draft_consistency.ts +++ b/src/domain/sdd_draft_consistency.ts @@ -177,6 +177,7 @@ function validatePaths(source: string, inventory: SddRepositoryInventory, sddPat seen.add(file); if (change === 'create') { if (inventory.files.has(file) || inventory.directories.has(file)) fail('repository-path'); + if ([...proposed].some(other => file.startsWith(`${other}/`) || other.startsWith(`${file}/`))) fail('repository-path'); const segments = file.split('/'); if (segments.some((_, index) => inventory.files.has(segments.slice(0, index + 1).join('/')) || inventory.blocked.has(segments.slice(0, index + 1).join('/')))) fail('repository-path'); proposed.add(file); diff --git a/src/infrastructure/__tests__/untrusted_command_environment.test.ts b/src/infrastructure/__tests__/untrusted_command_environment.test.ts index 936e2ec43..be59eb163 100644 --- a/src/infrastructure/__tests__/untrusted_command_environment.test.ts +++ b/src/infrastructure/__tests__/untrusted_command_environment.test.ts @@ -3,6 +3,13 @@ import { join } from 'node:path'; import { prepareUntrustedCommandEnvironment } from '../untrusted_command_environment'; describe('prepareUntrustedCommandEnvironment', () => { + it('does not pass trusted worker or GitHub file-command channels to repository commands', () => { + const channels = ['GITHUB_OUTPUT', 'GITHUB_ENV', 'GITHUB_PATH', 'GITHUB_STEP_SUMMARY', 'COPILOT_NATIVE_WORKER_SESSION']; + const runtime = prepareUntrustedCommandEnvironment(Object.fromEntries(channels.map(name => [name, '/private/trusted-channel']))); + try { + for (const name of channels) expect(runtime.environment).not.toHaveProperty(name); + } finally { runtime.cleanup(); } + }); it('keeps nested temporary work inside the isolated profile and removes it with that profile', () => { const runtime = prepareUntrustedCommandEnvironment({ TMP: 'host-temp', TEMP: 'host-temp', TMPDIR: 'host-temp', RUNNER_TEMP: 'host-runner' }); const home = runtime.environment.HOME; diff --git a/src/manager/description/__tests__/configuration_recovery.test.ts b/src/manager/description/__tests__/configuration_recovery.test.ts index a72a05c31..e62fae82e 100644 --- a/src/manager/description/__tests__/configuration_recovery.test.ts +++ b/src/manager/description/__tests__/configuration_recovery.test.ts @@ -5,6 +5,7 @@ import { renderApplicationErrorText } from '../../../application/policies/applic import { resolveStaticApplicationErrorCatalog } from '../../../application/policies/application_error_message_catalog'; import { runSetupExecution } from '../../../application/usecases/execution/setup_execution_workflow'; import type { SetupExecutionContext } from '../../../application/usecases/execution/setup_execution_contracts'; +import type { ConfigurationPersistenceContext } from '../../../application/ports/configuration_store_ports'; jest.mock('../../../utils/logger', () => ({ logError: jest.fn() })); @@ -57,6 +58,109 @@ describe('stored configuration diagnostics and recovery (#635)', () => { expect(f.updateDescription).not.toHaveBeenCalled(); }); + it.each([ + 'The opening token is ``.', + 'Explain in this issue.', + '> ', + ' ', + ])('does not treat an ordinary marker mention as stored state: %s', async body => { + const f = fixture(body); + await expect(f.handler.get(query)).resolves.toBeUndefined(); + expect(f.updateDescription).not.toHaveBeenCalled(); + }); + + it.each([ + ['```md', '```'], ['~~~md', '~~~'], ['````md', '`````'], + ])('ignores a closed %s configuration example', async (open, close) => { + const f = fixture(`${open}\n'); + await expect(f.handler.get(query)).resolves.toMatchObject({ branchType: 'feature' }); + }); + it('continues reading supported state without rewriting it', async () => { const f = fixture(block('{"schemaVersion":3,"branchType":"feature","workingBranch":"feature/42-work"}')); await expect(f.handler.get(query)).resolves.toMatchObject({ schemaVersion: 3, workingBranch: 'feature/42-work' }); diff --git a/src/manager/description/configuration_handler.ts b/src/manager/description/configuration_handler.ts index 67735a917..d9b27f04e 100644 --- a/src/manager/description/configuration_handler.ts +++ b/src/manager/description/configuration_handler.ts @@ -5,6 +5,7 @@ import { logError } from "../../utils/logger"; import { IssueContentInterface } from "./base/issue_content_interface"; import { buildConfigurationPayload } from './configuration_payload_policy'; import { toApplicationError, type ApplicationErrorRecovery } from '../../application/errors/application_error'; +import { readConfigurationBlock, writeConfigurationBlock } from './configuration_markers'; export class ConfigurationHandler extends IssueContentInterface { @@ -16,6 +17,18 @@ export class ConfigurationHandler extends IssueContentInterface { return false; } + override getContent = (description: string | undefined): string | undefined => { + const block = readConfigurationBlock(description); + return block.kind === 'present' ? block.content : undefined; + }; + + override updateContent = (description: string | undefined, content: string | undefined): string | undefined => { + if (description === undefined || content === undefined) return undefined; + const updated = writeConfigurationBlock(description, content); + if (updated === undefined) logError('The content has a problem with open-close tags: stored configuration.'); + return updated; + }; + update = async (query: ExecutionConfigurationQuery, context: ConfigurationPersistenceContext) => { const storedRaw = await this.internalGetter(query); return this.internalUpdate(query, buildConfigurationPayload(context, storedRaw)); @@ -41,8 +54,7 @@ export class ConfigurationHandler extends IssueContentInterface { try { const config = this.getContent(description); if (config === undefined) { - if (description?.includes('')) { + if (readConfigurationBlock(description).kind === 'invalid') { throw new Error('Stored configuration markers are inconsistent.'); } return undefined; diff --git a/src/manager/description/configuration_markers.ts b/src/manager/description/configuration_markers.ts new file mode 100644 index 000000000..ec949ef1b --- /dev/null +++ b/src/manager/description/configuration_markers.ts @@ -0,0 +1,72 @@ +export const CONFIGURATION_START = ''; + +type ConfigurationBlock = + | { readonly kind: 'absent'; readonly closingFence?: string } + | { readonly kind: 'invalid' } + | { readonly kind: 'present'; readonly start: number; readonly end: number; readonly content: string }; + +/** Owned delimiters begin a line; ordinary mentions are not state. Complete legacy fenced records remain readable. */ +export function readConfigurationBlock(description: string | undefined): ConfigurationBlock { + if (description === undefined) return { kind: 'absent' }; + let fence: string | undefined; + let fencedMarker = false; + let fencedStart: number | undefined; + let nestedFencedStart = false; + let start: number | undefined; + let contentStart = 0; + let block: Extract | undefined; + let offset = 0; + for (const line of description.match(/[^\n]*(?:\n|$)/gu) ?? []) { + const text = line.replace(/\r?\n$/u, ''); + const starts = /^ {0,3}[ \t]*$/u.test(text); + const boundary = /^ {0,3}(`{3,}|~{3,})(.*)$/u.exec(text); + if (fence) { + fencedMarker ||= starts || ends; + if (starts) { + if (fencedStart !== undefined) nestedFencedStart = true; + else fencedStart = offset + text.indexOf(CONFIGURATION_START); + } + const end = text.indexOf(CONFIGURATION_END); + if (fencedStart !== undefined && end >= 0 && !text.slice(end + CONFIGURATION_END.length).trim()) { + if (block || nestedFencedStart) return { kind: 'invalid' }; + block = { kind: 'present', start: fencedStart, end: offset + end + CONFIGURATION_END.length, + content: description.slice(fencedStart + CONFIGURATION_START.length, offset + end) }; + fencedStart = undefined; + } + if (boundary && boundary[1][0] === fence[0] && boundary[1].length >= fence.length && !boundary[2].trim()) { + fence = undefined; + fencedMarker = false; + fencedStart = undefined; + nestedFencedStart = false; + } + } else if (start !== undefined || starts) { + if (starts) { + if (start !== undefined || block) return { kind: 'invalid' }; + start = offset + text.indexOf(CONFIGURATION_START); + contentStart = start + CONFIGURATION_START.length; + } + const end = text.indexOf(CONFIGURATION_END); + if (end >= 0 && !text.slice(end + CONFIGURATION_END.length).trim()) { + block = { kind: 'present', start: start!, end: offset + end + CONFIGURATION_END.length, + content: description.slice(contentStart, offset + end) }; + start = undefined; + } + } else if (ends) return { kind: 'invalid' }; + else if (boundary && (boundary[1][0] !== '`' || !boundary[2].includes('`'))) fence = boundary[1]; + offset += line.length; + } + // A legacy block behind an unclosed fence is ambiguous: never silently discard its state. + if (start !== undefined || fence && fencedMarker) return { kind: 'invalid' }; + return block ?? { kind: 'absent', ...(fence ? { closingFence: fence } : {}) }; +} + +export function writeConfigurationBlock(description: string, content: string): string | undefined { + const block = readConfigurationBlock(description); + if (block.kind === 'invalid') return undefined; + const replacement = `${CONFIGURATION_START}\n${content}\n${CONFIGURATION_END}`; + if (block.kind === 'present') return description.slice(0, block.start) + replacement + description.slice(block.end); + // Closing an otherwise empty dangling example preserves its rendered text and keeps new state outside it. + return `${description}\n\n${block.closingFence ? `${block.closingFence}\n\n` : ''}${replacement}`; +} From 9dfe8fac44702d215764c594d1907a8a8783ece6 Mon Sep 17 00:00:00 2001 From: vypbot Date: Thu, 22 Oct 2026 01:04:03 +0200 Subject: [PATCH 41/44] docs(sdd): specify issue contract in specs/copilot-comment-workflow-coordinator.md --- specs/CATALOG.md | 4 +- specs/catalog.json | 3 +- specs/copilot-comment-workflow-coordinator.md | 348 ++++++++++++++++++ 3 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 specs/copilot-comment-workflow-coordinator.md diff --git a/specs/CATALOG.md b/specs/CATALOG.md index 6818dabd1..9193ecba3 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -16,7 +16,7 @@ debt or convert unknown historic intent into a design decision. | `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 70 paths · 2026-10-21 | | `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 104 paths · 2026-10-21 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | -| `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 5 companion | 328 paths · 2026-10-20 | +| `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 6 companion | 328 paths · 2026-10-20 | | `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 2 companion | 247 paths · 2026-10-21 | | `guided-bot-pat-onboarding` | Proposed | Guide creation of the persistent workflow PAT, verify bot identity and grants, recover explicitly from wrong-account input within the session, and install the approved Actions Secret | [Guided bot PAT onboarding](./guided-bot-pat-onboarding.md) | 39 paths · 2026-10-07 | | `temporary-setup-operator-authorization` | Proposed | Guide creation of the one-run operator PAT through GitHub's official form, verify final setup access, and report user-owned deletion accurately | [Assisted setup PAT creation](./temporary-setup-operator-authorization.md) | 36 paths · 2026-10-18 | @@ -104,7 +104,7 @@ debt or convert unknown historic intent into a design decision. - Owner: Copilot maintainers - Last verified: 2026-10-20 -- Specifications: [`specs/setup-configuration-credentials-and-doctor.md`](./setup-configuration-credentials-and-doctor.md) · [`specs/setup-doctor-architecture-hardening.md`](./setup-doctor-architecture-hardening.md) · [`specs/setup-pat-permission-guidance-and-verification.md`](./setup-pat-permission-guidance-and-verification.md) · [`specs/github-runtime-doctor-command.md`](./github-runtime-doctor-command.md) · [`specs/organization-configuration-reuse-and-batch-setup.md`](./organization-configuration-reuse-and-batch-setup.md) · [`specs/setup-runner-profiles-and-installation-parity.md`](./setup-runner-profiles-and-installation-parity.md) +- Specifications: [`specs/setup-configuration-credentials-and-doctor.md`](./setup-configuration-credentials-and-doctor.md) · [`specs/setup-doctor-architecture-hardening.md`](./setup-doctor-architecture-hardening.md) · [`specs/setup-pat-permission-guidance-and-verification.md`](./setup-pat-permission-guidance-and-verification.md) · [`specs/github-runtime-doctor-command.md`](./github-runtime-doctor-command.md) · [`specs/organization-configuration-reuse-and-batch-setup.md`](./organization-configuration-reuse-and-batch-setup.md) · [`specs/setup-runner-profiles-and-installation-parity.md`](./setup-runner-profiles-and-installation-parity.md) · [`specs/copilot-comment-workflow-coordinator.md`](./copilot-comment-workflow-coordinator.md) - Workflows: [`setup/workflows/agent-cli-provisioning.yml`](../setup/workflows/agent-cli-provisioning.yml) · [`setup/workflows/copilot_credential_health.yml`](../setup/workflows/copilot_credential_health.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) · [`.github/workflows/agent-cli-provisioning.yml`](../.github/workflows/agent-cli-provisioning.yml) · [`.github/workflows/copilot_credential_health.yml`](../.github/workflows/copilot_credential_health.yml) · [`.github/workflows/copilot_commit.yml`](../.github/workflows/copilot_commit.yml) · [`.github/workflows/copilot_branch_sync.yml`](../.github/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_commit.yml`](../setup/workflows/copilot_commit.yml) · [`setup/workflows/copilot_branch_sync.yml`](../setup/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_issue_comment.yml`](../setup/workflows/copilot_issue_comment.yml) · [`setup/workflows/copilot_pull_request_comment.yml`](../setup/workflows/copilot_pull_request_comment.yml) - Entrypoints: [`src/cli/commands/setup.ts`](../src/cli/commands/setup.ts) · [`src/cli/commands/doctor.ts`](../src/cli/commands/doctor.ts) · [`src/application/usecases/issue_comment_use_case.ts`](../src/application/usecases/issue_comment_use_case.ts) · [`src/application/usecases/pull_request_review_comment_use_case.ts`](../src/application/usecases/pull_request_review_comment_use_case.ts) - Core code: [`src/domain/setup.ts`](../src/domain/setup.ts) · [`src/domain/setup_questionnaire.ts`](../src/domain/setup_questionnaire.ts) · [`src/domain/setup_token_permissions.ts`](../src/domain/setup_token_permissions.ts) · [`src/application/ports/setup_terminal_ports.ts`](../src/application/ports/setup_terminal_ports.ts) · [`src/application/ports/setup_wizard_ports.ts`](../src/application/ports/setup_wizard_ports.ts) · [`src/application/ports/branch_tag_ports.ts`](../src/application/ports/branch_tag_ports.ts) · [`src/application/policies/setup_issue_workflow_policy.ts`](../src/application/policies/setup_issue_workflow_policy.ts) · [`src/data/repository/release/repository_version_tags_query_repository.ts`](../src/data/repository/release/repository_version_tags_query_repository.ts) · [`src/application/ports/setup_token_permission_ports.ts`](../src/application/ports/setup_token_permission_ports.ts) · [`src/application/policies/setup_token_permission_evidence_policy.ts`](../src/application/policies/setup_token_permission_evidence_policy.ts) · [`src/application/policies/setup_token_permission_policy.ts`](../src/application/policies/setup_token_permission_policy.ts) · [`src/application/policies/setup_questionnaire_policy.ts`](../src/application/policies/setup_questionnaire_policy.ts) · [`src/application/policies/setup_configuration_plan.ts`](../src/application/policies/setup_configuration_plan.ts) · [`src/application/policies/merge_setup_overrides_policy.ts`](../src/application/policies/merge_setup_overrides_policy.ts) · [`src/application/policies/setup_configuration_storage_policy.ts`](../src/application/policies/setup_configuration_storage_policy.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/application/policies/setup_doctor_report_policy.ts`](../src/application/policies/setup_doctor_report_policy.ts) · [`src/application/policies/setup_journey_policy.ts`](../src/application/policies/setup_journey_policy.ts) · [`src/application/policies/setup_permission_summary_policy.ts`](../src/application/policies/setup_permission_summary_policy.ts) · [`src/application/usecases/setup/setup_wizard_use_case.ts`](../src/application/usecases/setup/setup_wizard_use_case.ts) · [`src/application/usecases/setup/setup_journey_use_case.ts`](../src/application/usecases/setup/setup_journey_use_case.ts) · [`src/application/usecases/setup/setup_session_coordinator.ts`](../src/application/usecases/setup/setup_session_coordinator.ts) · [`src/application/usecases/setup/setup_questionnaire_controller.ts`](../src/application/usecases/setup/setup_questionnaire_controller.ts) · [`src/application/usecases/setup/setup_credentials_use_case.ts`](../src/application/usecases/setup/setup_credentials_use_case.ts) · [`src/application/usecases/setup/setup_token_permissions_use_case.ts`](../src/application/usecases/setup/setup_token_permissions_use_case.ts) · [`src/application/usecases/setup/doctor_use_case.ts`](../src/application/usecases/setup/doctor_use_case.ts) · [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) · [`src/application/usecases/actions/initial_setup_workflow.ts`](../src/application/usecases/actions/initial_setup_workflow.ts) · [`src/application/usecases/actions/setup_resource_provisioning.ts`](../src/application/usecases/actions/setup_resource_provisioning.ts) · [`src/application/ports/message_catalog_ports.ts`](../src/application/ports/message_catalog_ports.ts) · [`src/application/usecases/localization/resolve_message_catalog_use_case.ts`](../src/application/usecases/localization/resolve_message_catalog_use_case.ts) · [`src/application/policies/setup_configuration_validation.ts`](../src/application/policies/setup_configuration_validation.ts) · [`src/infrastructure/setup_workspace_adapter.ts`](../src/infrastructure/setup_workspace_adapter.ts) · [`src/data/repository/repository_variables_repository.ts`](../src/data/repository/repository_variables_repository.ts) · [`src/infrastructure/github/ports/github_repository_variables_protocol.ts`](../src/infrastructure/github/ports/github_repository_variables_protocol.ts) · [`src/infrastructure/setup_remote_credential_health_adapter.ts`](../src/infrastructure/setup_remote_credential_health_adapter.ts) · [`src/infrastructure/setup_credential_validation_adapter.ts`](../src/infrastructure/setup_credential_validation_adapter.ts) · [`src/infrastructure/setup_token_permission_query_adapter.ts`](../src/infrastructure/setup_token_permission_query_adapter.ts) · [`src/infrastructure/setup_permission_actions_probe.ts`](../src/infrastructure/setup_permission_actions_probe.ts) · [`src/infrastructure/setup_permission_issue_probe.ts`](../src/infrastructure/setup_permission_issue_probe.ts) · [`src/infrastructure/setup_permission_issue_cleanup.ts`](../src/infrastructure/setup_permission_issue_cleanup.ts) · [`src/infrastructure/setup_permission_probe_journal.ts`](../src/infrastructure/setup_permission_probe_journal.ts) · [`src/infrastructure/setup_permission_probe_transaction.ts`](../src/infrastructure/setup_permission_probe_transaction.ts) · [`src/infrastructure/setup_permission_resource_probes.ts`](../src/infrastructure/setup_permission_resource_probes.ts) · [`src/infrastructure/setup_projects_probe_page_policy.ts`](../src/infrastructure/setup_projects_probe_page_policy.ts) · [`src/cli/setup_terminal_driver.ts`](../src/cli/setup_terminal_driver.ts) · [`src/cli/setup_question_renderer.ts`](../src/cli/setup_question_renderer.ts) · [`src/cli/setup_journey_presenter.ts`](../src/cli/setup_journey_presenter.ts) · [`src/cli/setup_plan_presenter.ts`](../src/cli/setup_plan_presenter.ts) · [`src/cli/setup_doctor_presenter.ts`](../src/cli/setup_doctor_presenter.ts) · [`src/cli/setup_prompt_rendering.ts`](../src/cli/setup_prompt_rendering.ts) · [`src/cli/setup_credential_prompt_adapter.ts`](../src/cli/setup_credential_prompt_adapter.ts) · [`src/cli/setup_credential_collection.ts`](../src/cli/setup_credential_collection.ts) · [`src/cli/commands/setup_execution.ts`](../src/cli/commands/setup_execution.ts) · [`src/cli/setup_token_permission_presenter.ts`](../src/cli/setup_token_permission_presenter.ts) · [`src/infrastructure/composition/setup_credentials_composition_root.ts`](../src/infrastructure/composition/setup_credentials_composition_root.ts) · [`src/infrastructure/composition/setup_token_permissions_composition_root.ts`](../src/infrastructure/composition/setup_token_permissions_composition_root.ts) · [`src/infrastructure/composition/setup_doctor_composition_root.ts`](../src/infrastructure/composition/setup_doctor_composition_root.ts) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/documentation_pat_exception_policy.cjs`](../scripts/documentation_pat_exception_policy.cjs) · [`scripts/validate-documentation-contract.cjs`](../scripts/validate-documentation-contract.cjs) · [`src/infrastructure/http_deadline.ts`](../src/infrastructure/http_deadline.ts) · [`src/infrastructure/setup_permission_denial.ts`](../src/infrastructure/setup_permission_denial.ts) · [`src/infrastructure/setup_permission_read_probe.ts`](../src/infrastructure/setup_permission_read_probe.ts) · [`src/infrastructure/setup_permission_read_evidence.ts`](../src/infrastructure/setup_permission_read_evidence.ts) · [`src/infrastructure/setup_permission_read_shape.ts`](../src/infrastructure/setup_permission_read_shape.ts) · [`src/infrastructure/setup_permission_projects_read.ts`](../src/infrastructure/setup_permission_projects_read.ts) · [`src/infrastructure/setup_permission_projects_access.ts`](../src/infrastructure/setup_permission_projects_access.ts) · [`src/infrastructure/setup_permission_workflow_cleanup.ts`](../src/infrastructure/setup_permission_workflow_cleanup.ts) · [`src/infrastructure/setup_permission_project_cleanup.ts`](../src/infrastructure/setup_permission_project_cleanup.ts) · [`src/infrastructure/setup_permission_probe_http.ts`](../src/infrastructure/setup_permission_probe_http.ts) · [`src/infrastructure/setup_permission_pull_request_probe.ts`](../src/infrastructure/setup_permission_pull_request_probe.ts) · [`src/infrastructure/git_authentication_environment.ts`](../src/infrastructure/git_authentication_environment.ts) · [`src/actions/github_action_input.ts`](../src/actions/github_action_input.ts) · [`src/infrastructure/setup_github_identity_query_adapter.ts`](../src/infrastructure/setup_github_identity_query_adapter.ts) · [`src/infrastructure/github_secret_encryption.ts`](../src/infrastructure/github_secret_encryption.ts) · [`src/infrastructure/setup_permission_organization_owner.ts`](../src/infrastructure/setup_permission_organization_owner.ts) · [`src/data/repository/github/github_actions_resource_inspector.ts`](../src/data/repository/github/github_actions_resource_inspector.ts) · [`src/data/repository/github/github_actions_resource_commands.ts`](../src/data/repository/github/github_actions_resource_commands.ts) · [`src/data/repository/github/github_actions_resource_collection.ts`](../src/data/repository/github/github_actions_resource_collection.ts) · [`src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts`](../src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts) · [`src/cli/setup_workflow_pat_storage_copy.ts`](../src/cli/setup_workflow_pat_storage_copy.ts) · [`src/cli/commands/setup_policy.ts`](../src/cli/commands/setup_policy.ts) · [`src/application/usecases/execution/execution_issue_number_policy.ts`](../src/application/usecases/execution/execution_issue_number_policy.ts) · [`src/application/usecases/execution/setup_execution_workflow.ts`](../src/application/usecases/execution/setup_execution_workflow.ts) · [`src/domain/github_runtime_doctor.ts`](../src/domain/github_runtime_doctor.ts) · [`src/domain/copilot_command.ts`](../src/domain/copilot_command.ts) · [`src/application/usecases/comment_automation_command_workflow.ts`](../src/application/usecases/comment_automation_command_workflow.ts) · [`src/application/policies/copilot_interaction_policy.ts`](../src/application/policies/copilot_interaction_policy.ts) · [`src/application/policies/publication_message_catalog.ts`](../src/application/policies/publication_message_catalog.ts) · [`src/application/ports/github_runtime_doctor_ports.ts`](../src/application/ports/github_runtime_doctor_ports.ts) · [`src/application/policies/github_runtime_doctor_policy.ts`](../src/application/policies/github_runtime_doctor_policy.ts) · [`src/application/policies/doctor_workflow_condition_policy.ts`](../src/application/policies/doctor_workflow_condition_policy.ts) · [`src/application/policies/github_runtime_doctor_presentation_policy.ts`](../src/application/policies/github_runtime_doctor_presentation_policy.ts) · [`src/application/usecases/read_copilot_doctor_workflow.ts`](../src/application/usecases/read_copilot_doctor_workflow.ts) · [`src/data/repository/github/runtime_doctor_repository.ts`](../src/data/repository/github/runtime_doctor_repository.ts) · [`src/infrastructure/composition/github_runtime_doctor_composition_root.ts`](../src/infrastructure/composition/github_runtime_doctor_composition_root.ts) · [`src/application/policies/agent_activity_policy.ts`](../src/application/policies/agent_activity_policy.ts) · [`src/application/policies/doctor_workflow_matrix_policy.ts`](../src/application/policies/doctor_workflow_matrix_policy.ts) · [`src/application/contracts/setup_batch_view.ts`](../src/application/contracts/setup_batch_view.ts) · [`src/application/policies/issue_resource_input_policy.ts`](../src/application/policies/issue_resource_input_policy.ts) · [`src/application/policies/setup_batch_access_policy.ts`](../src/application/policies/setup_batch_access_policy.ts) · [`src/application/policies/setup_batch_policy.ts`](../src/application/policies/setup_batch_policy.ts) · [`src/application/policies/setup_batch_retry_policy.ts`](../src/application/policies/setup_batch_retry_policy.ts) · [`src/application/policies/setup_batch_selection_policy.ts`](../src/application/policies/setup_batch_selection_policy.ts) · [`src/application/policies/setup_batch_view_policy.ts`](../src/application/policies/setup_batch_view_policy.ts) · [`src/application/policies/setup_credential_binding_policy.ts`](../src/application/policies/setup_credential_binding_policy.ts) · [`src/application/policies/setup_organization_import_policy.ts`](../src/application/policies/setup_organization_import_policy.ts) · [`src/application/policies/setup_organization_variable_bindings.ts`](../src/application/policies/setup_organization_variable_bindings.ts) · [`src/application/policies/setup_organization_variable_reuse_policy.ts`](../src/application/policies/setup_organization_variable_reuse_policy.ts) · [`src/application/ports/setup_batch_ports.ts`](../src/application/ports/setup_batch_ports.ts) · [`src/application/usecases/setup/apply_setup_batch_use_case.ts`](../src/application/usecases/setup/apply_setup_batch_use_case.ts) · [`src/application/usecases/setup/configure_setup_batch_target_use_case.ts`](../src/application/usecases/setup/configure_setup_batch_target_use_case.ts) · [`src/application/usecases/setup/prepare_setup_batch_use_case.ts`](../src/application/usecases/setup/prepare_setup_batch_use_case.ts) · [`src/application/usecases/setup/select_setup_batch_targets_use_case.ts`](../src/application/usecases/setup/select_setup_batch_targets_use_case.ts) · [`src/application/usecases/setup/setup_batch_session_use_case.ts`](../src/application/usecases/setup/setup_batch_session_use_case.ts) · [`src/cli/setup_batch_adapter.ts`](../src/cli/setup_batch_adapter.ts) · [`src/cli/setup_source_adapter.ts`](../src/cli/setup_source_adapter.ts) · [`src/domain/setup_batch.ts`](../src/domain/setup_batch.ts) · [`src/domain/setup_credential_health.ts`](../src/domain/setup_credential_health.ts) · [`src/domain/setup_organization_reuse.ts`](../src/domain/setup_organization_reuse.ts) · [`src/infrastructure/composition/setup_batch_composition_root.ts`](../src/infrastructure/composition/setup_batch_composition_root.ts) · [`src/infrastructure/github/ports/github_setup_batch_protocol.ts`](../src/infrastructure/github/ports/github_setup_batch_protocol.ts) · [`src/infrastructure/github/ports/github_trusted_credential_health_protocol.ts`](../src/infrastructure/github/ports/github_trusted_credential_health_protocol.ts) · [`src/infrastructure/setup_batch_github_apply_adapter.ts`](../src/infrastructure/setup_batch_github_apply_adapter.ts) · [`src/infrastructure/setup_batch_github_read_adapter.ts`](../src/infrastructure/setup_batch_github_read_adapter.ts) · [`src/infrastructure/setup_batch_journal_adapter.ts`](../src/infrastructure/setup_batch_journal_adapter.ts) · [`src/infrastructure/setup_batch_workspace_adapter.ts`](../src/infrastructure/setup_batch_workspace_adapter.ts) · [`src/infrastructure/setup_trusted_credential_health_adapter.ts`](../src/infrastructure/setup_trusted_credential_health_adapter.ts) · [`src/application/policies/setup_remote_facts_policy.ts`](../src/application/policies/setup_remote_facts_policy.ts) · [`src/cli/setup_confirmation_adapter.ts`](../src/cli/setup_confirmation_adapter.ts) · [`src/cli/web_setup_adapters.ts`](../src/cli/web_setup_adapters.ts) · [`scripts/validate-agent-documentation.cjs`](../scripts/validate-agent-documentation.cjs) · [`src/utils/setup_workflow_upgrade.ts`](../src/utils/setup_workflow_upgrade.ts) · [`src/domain/setup_runner.ts`](../src/domain/setup_runner.ts) · [`src/application/policies/setup_runner_policy.ts`](../src/application/policies/setup_runner_policy.ts) · [`src/application/policies/setup_runner_question_policy.ts`](../src/application/policies/setup_runner_question_policy.ts) · [`src/application/policies/setup_runner_guidance_policy.ts`](../src/application/policies/setup_runner_guidance_policy.ts) · [`src/application/ports/setup_runner_ports.ts`](../src/application/ports/setup_runner_ports.ts) · [`src/infrastructure/setup_runner_discovery_adapter.ts`](../src/infrastructure/setup_runner_discovery_adapter.ts) · [`src/infrastructure/composition/setup_runner_composition_root.ts`](../src/infrastructure/composition/setup_runner_composition_root.ts) · [`src/utils/setup_installation_review.ts`](../src/utils/setup_installation_review.ts) · [`src/cli/setup_installation_review_presenter.ts`](../src/cli/setup_installation_review_presenter.ts) · [`src/application/policies/setup_runner_installation_summary_policy.ts`](../src/application/policies/setup_runner_installation_summary_policy.ts) · [`src/utils/setup_files.ts`](../src/utils/setup_files.ts) · [`src/domain/specification_catalog_path_policy.cjs`](../src/domain/specification_catalog_path_policy.cjs) · [`src/domain/sdd_prerequisite_policy.cjs`](../src/domain/sdd_prerequisite_policy.cjs) · [`src/application/contracts/setup_documentation.ts`](../src/application/contracts/setup_documentation.ts) · [`src/application/policies/setup_question_documentation_policy.ts`](../src/application/policies/setup_question_documentation_policy.ts) · [`web/src/components/SetupHelp.svelte`](../web/src/components/SetupHelp.svelte) · [`web/src/components/CompletedSetupHelp.svelte`](../web/src/components/CompletedSetupHelp.svelte) · [`src/application/policies/verification_runtime_policy.ts`](../src/application/policies/verification_runtime_policy.ts) · [`src/infrastructure/verification_runtime_manifest.ts`](../src/infrastructure/verification_runtime_manifest.ts) · [`src/infrastructure/verification_runtime_preflight.ts`](../src/infrastructure/verification_runtime_preflight.ts) · [`src/infrastructure/untrusted_command_environment.ts`](../src/infrastructure/untrusted_command_environment.ts) · [`src/application/ports/git_ports.ts`](../src/application/ports/git_ports.ts) · [`src/application/ports/bugbot_git_ports.ts`](../src/application/ports/bugbot_git_ports.ts) · [`src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts`](../src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts) · [`src/application/usecases/steps/commit/bugbot/verify_command_runner.ts`](../src/application/usecases/steps/commit/bugbot/verify_command_runner.ts) · [`src/cli/setup_config_file.ts`](../src/cli/setup_config_file.ts) diff --git a/specs/catalog.json b/specs/catalog.json index 0f567c8ab..ff5fdc794 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -760,7 +760,8 @@ "specs/setup-pat-permission-guidance-and-verification.md", "specs/github-runtime-doctor-command.md", "specs/organization-configuration-reuse-and-batch-setup.md", - "specs/setup-runner-profiles-and-installation-parity.md" + "specs/setup-runner-profiles-and-installation-parity.md", + "specs/copilot-comment-workflow-coordinator.md" ], "workflows": [ "setup/workflows/agent-cli-provisioning.yml", diff --git a/specs/copilot-comment-workflow-coordinator.md b/specs/copilot-comment-workflow-coordinator.md new file mode 100644 index 000000000..99df52d25 --- /dev/null +++ b/specs/copilot-comment-workflow-coordinator.md @@ -0,0 +1,348 @@ +# Copilot Comment Workflow Coordinator + +- Status: Draft +- Date: 2026-10-22 +- Catalog capability ID: setup-and-doctor +- Last verified: not applicable +- Owners: Copilot maintainers +- Scope: Centralize native issue-comment and pull-request-review-comment verification coordination in one versioned Copilot reusable workflow and specify safe consumer setup migration. +- Related issues/PRs: [Issue #662](https://github.com/vypdev/copilot/issues/662); related delivered work #647/#652 and #656/#657; dependent release #661 (3.10.0). +- Required review gates: product UX, architecture, testing, documentation, security/operations +- Open decisions blocking readiness: none + +## 1. Executive summary + +This companion specification defines one Copilot-owned reusable workflow for the complete native verification lifecycle used by issue-comment and pull-request-review-comment callbacks. Repository callbacks and setup templates call one versioned workflow instead of copying twenty setup/continue pairs and cleanup steps. The reusable workflow owns one job, so the existing native per-step timeout and same-job candidate environment remain intact. + +The safety rule is that only admitted, trusted verification work may reach the worker, and continuations verify the existing candidate without rerunning the agent or business operation. Secrets remain explicit and narrowly scoped; project setup receives no provider credentials or PAT inputs. + +```text +Comment callback -> versioned Copilot reusable workflow -> same-job Copilot Action and trusted dependency setup -> continuation and guarded publication -> reverse native post cleanup +``` + +## 2. Problem, current behavior, and evidence + +### 2.1 Problem + +Repository maintainers and Copilot maintainers must review and upgrade duplicated callback orchestration. The native dependency setup has twenty statically declared setup/continue pairs plus final cleanup, adding 579 lines to each distributed callback and duplicating those lines in source workflows. A generated composite coordinator cannot preserve the native per-step timeout because GitHub rejects `timeout-minutes` within composite steps. + +### 2.2 Current behavior + +1. Issue-comment and pull-request-review-comment callbacks admit events using existing bot, fork, and eligibility gates. +2. A native Copilot Action step runs with explicitly supplied configuration and credentials. +3. Native setup/continue steps prepare dependencies, preserve candidate identity, and wait for worker readiness. +4. Verification and publication guards run without rerunning the agent or business operation. +5. Native post actions clean up setup state in reverse order. + +The issue identifies these as current behavior and requires their preservation. Exact implementation-level names and current card text must be confirmed from the owning specifications and workflow evidence during implementation. + +### 2.3 Evidence + +- Code/workflow/documentation references: current comment callbacks and setup templates are catalogued under `setup-and-doctor`; existing setup owner is `specs/setup-runner-profiles-and-installation-parity.md`. The existing native verification owner remains `specs/repository-verification-setup-hooks.md` under `branch-synchronization`; implementation must retain that ownership and add a cross-reference. Catalog paths establish current locations only, not future runtime support. +- Incidents or concrete examples: twenty statically declared setup/continue pairs plus cleanup; 579 added lines per distributed comment callback. +- External primary sources: [GitHub runner action schema](https://github.com/actions/runner/blob/main/src/Runner.Worker/action_yaml.json); [same-repository self-reference announcement](https://github.blog/changelog/2026-07-30-reference-same-repository-actions-with-self-repository-syntax/). +- Unknowns: none block this design. Exact supported GitHub.com/runner/action-policy conditions must be documented and validated against the platform at implementation time. + +### 2.4 Retrospective classification (as-built baselines only) + +Not applicable: this is a prospective specification, not a reconstruction of an implemented baseline. + +## 3. Actors, surfaces, and terminology + +| Actor | Goal | Entry point | Visible surfaces | +|---|---|---|---| +| Repository maintainer | Install and upgrade compact comment callbacks safely | Setup or workflow maintenance | Workflow files, checks, setup preview and Apply | +| Comment author | Receive existing verification behavior | Issue or review comment | Existing result cards and linked run | +| Copilot operator | Diagnose a failed or incomplete verification | Workflow run | Job Summary, logs, issue/PR state | +| Copilot maintainer | Own central coordination and compatibility | Reusable workflow release | Versioned workflow, tests, docs, release notes | + +A **callback** is the repository-owned workflow triggered by a supported comment event. The **coordinator** is the Copilot reusable workflow that owns all native lifecycle phases in one job. **Candidate** means the existing admitted worker/candidate identity and environment; it is carried through continuation rather than recreated. **Trusted project setup** is the repository-owned composite dependency action. **Source callback** means a callback in Copilot itself and uses an exact same-commit self-repository workflow reference. **Installed callback** means a consumer callback and uses `vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3`. + +## 4. Goals + +### 4.1 Goals + +1. Reduce each source and setup comment callback to at most 35 lines while centralizing all native phases in one reusable workflow. +2. Preserve existing admission, verification, publication, result-card, timeout, identity, credential, and cleanup behavior. +3. Let setup preview and Apply show the same runner route and safely recognize known reusable callers during configuration maintenance. +4. Provide actionable, reviewed migration for custom bootstrap steps without silently deleting them. + +### 4.2 Non-goals + +1. Replacing the repository-owned dependency action with a non-composite action. +2. Dispatching candidate setup to another job or rerunning the agent/business operation to continue verification. +3. Removing time limits or changing verification/publication semantics. +4. Publishing minor release #661 as part of this specification; it remains dependent on this work and its final-head review/checks. + +### 4.3 Fixed product/safety invariants + +1. Preserve admission and bot/fork gates, Variable and Secret semantics, twenty setup boundaries, five-minute native setup cancellation, 300-second worker readiness, and 120-minute job budget. +2. Preserve candidate identity, trusted-main Action pinning, credential-free verifier profiles, one-use continuations, and reverse native post cleanup. +3. Keep named Secrets explicit; provider credentials are scoped to the initial Copilot step. No unrestricted secrets inheritance and no provider credential/PAT inputs to project setup. +4. Unknown inputs, unsupported source identity, malformed runner JSON, and dependent expressions fail closed. +5. Do not drop custom bootstrap steps. Require reviewed migration with a concrete recovery path. +6. Require GitHub.com same-repository self-reference support and runner 2.336.0 or newer; the inspected source runner is 2.337.0. Repository Actions policy must allow the required references. + +## 5. Current versus proposed product journey + +| Stage | Current | Proposed | User/operator effect | +|---|---|---|---| +| Callback maintenance | Setup/continue orchestration is copied into callbacks and source workflows | Callback calls one versioned coordinator | Smaller review surface and centralized upgrades | +| Native job execution | Native phases run in callback job | Reusable workflow owns one job and all native phases | Per-step timeout and candidate environment remain available | +| Setup migration | Existing routes and custom bootstrap need to be recognized | Preview and Apply expose the same route; known reusable callers are recognized; custom steps require reviewed migration | No inferred runner access or silent loss of bootstrap | +| Upgrade | Consumers carry duplicated orchestration | Installed callback pins `@v3`; source callback uses exact same-commit self reference | Coordinator upgrades are explicit and reviewable | + +```mermaid +flowchart LR + C[Comment callback] --> W[Versioned Copilot reusable workflow] + W --> A[Same-commit Copilot Action] + A --> S[Trusted project composite setup] + S --> V[Continuation, verification and publication guards] + V --> P[Native reverse post cleanup] +``` + +Text equivalent: comment callback -> one-job reusable coordinator -> same-commit Copilot Action and trusted setup in the same job -> guarded continuation/publication -> reverse native cleanup. + +## 6. Functional behavior and state model + +### 6.1 Happy path + +1. The callback applies the existing event admission and bot/fork gates, then calls the coordinator with only supported named inputs and explicit named Secrets. +2. Source callbacks reference the workflow at the exact same-commit self repository revision. Installed callbacks reference `vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3`. +3. The coordinator resolves supported runner routing and executes one job containing the Copilot Action, trusted project composite setup, continuation, verifier/publication guards, and native post cleanup. +4. Continuation consumes the one-use token and existing candidate identity; it does not rerun the agent or business operation. +5. Existing result cards and publication behavior remain unchanged. + +### 6.2 Alternative paths + +- Disabled, read-only, dry-run, and no-op modes retain their current behavior and do not gain side effects through centralization. +- Existing scalar, label, and group runner routes are retained or explicitly replaced during migration; preview and Apply display the same route. +- Unsupported runner configuration or callback identity fails closed with actionable recovery guidance. +- GitHub.com/runner/Actions-policy prerequisites not met: the callback cannot execute the coordinator; report a clear setup/operator error and link to prerequisites and remediation. +- Custom bootstrap steps: migration pauses for review and provides a documented recovery path; no step is silently discarded. + +### 6.3 State machine + +| State | Entered when | User-visible meaning | Allowed next states | Recovery/owner | +|---|---|---|---|---| +| Not admitted | Existing gates reject event | No verification run is started | Terminal | Existing callback behavior | +| Admitted | Event passes existing gates | Verification is starting | Running, failed | Coordinator/operator | +| Running | Native setup and worker proceed | Existing verification is in progress | Verifying, failed, canceled | Coordinator/operator | +| Verifying | One-use continuation resumes existing candidate | Existing candidate is checked | Published, failed, canceled | Coordinator/operator | +| Published | Existing publication guard allows result | Existing result is available | Terminal | Existing publication behavior | +| Failed/canceled | Guard, timeout, platform, or execution failure | Verification did not complete or was blocked | Retry only under existing policy | Operator uses run diagnostics and recovery docs | + +Duplicate and stale events remain subject to existing admission and one-use continuation semantics. Canceled setup runs retain native post cleanup. No continuation re-executes the agent/business operation. + +## 7. User-facing configuration + +| Input | Type | Recommended default | Allowed values/range | Scope/persistence | +|---|---|---|---|---| +| Installed coordinator ref | Workflow reference | `v3` | Reviewed supported version tags | Callback source, committed and upgraded explicitly | +| Source coordinator ref | Workflow reference | Exact same-commit self-repository reference | Exact caller commit only | Source workflow invocation | +| Runner route | Existing scalar/label/group route representation | Preserve configured route | Valid existing route values; malformed JSON and dependent expressions rejected | Repository setup configuration | +| Coordinator secrets | Named Secret bindings | Existing explicit named bindings | Only supported named Secrets | Passed to coordinator; provider credential scope remains initial Copilot step | +| Job budget | Fixed duration | 120 minutes | Not configurable by consumer | Coordinator job | +| Native setup timeout | Fixed duration | 5 minutes per native setup step | Not configurable by consumer | Coordinator step | +| Worker readiness | Fixed duration | 300 seconds | Not configurable by consumer | Coordinator wait | + +Validation MUST reject unknown workflow inputs, malformed runner JSON, dependent expressions, and unsupported source identity. Route handling MUST preserve existing valid scalar/label/group semantics. Configuration preview and Apply MUST expose identical effective routing. Recommended configuration uses the installed `@v3` reference and existing validated route; the source-workflow alternative uses the exact same-commit self reference. Correctness limits, gates, credential scope, and timeout budgets are not configurable. Existing Variable and Secret behavior is preserved; operation-time snapshot/reread behavior must match the current owning contract. + +## 8. Clean Architecture + +### 8.1 Responsibilities and dependency direction + +| Layer/boundary | Owns | Must not own/import | +|---|---|---| +| Domain/pure policy | Known workflow identity, input allowlist, route recognition and validation decisions | GitHub SDK or workflow runtime DTOs | +| Application | Setup preview/Apply and maintenance decisions; immutable semantic inputs/outputs | Concrete runner or GitHub process concerns | +| Adapters/data | Mapping repository configuration and workflow facts into semantic contracts | Product policy or inferred permissions | +| Infrastructure/composition | Reusable workflow wiring, native steps, secrets mapping, runner execution | Decisions that weaken invariant gates | +| Entrypoints | Compact event callback, existing admission and coordinator invocation | Duplicated orchestration | +| Presentation | Setup preview/Apply route display and actionable migration guidance | Mutations or runner-route inference | + +```mermaid +flowchart LR + E[Comment callback] --> W[Reusable workflow entrypoint] + W --> N[Native same-job phases] + A[Setup application policy] --> P[Known-workflow and route policy] + I[Repository/workflow adapters] --> A + A --> U[Preview and Apply presentation] + N --> X[GitHub Actions and trusted composite] +``` + +### 8.2 Contracts, state, and trust boundaries + +- Pure decisions: accepted coordinator identity/version, known reusable caller recognition, supported inputs, and valid runner-route shape. +- Application contracts: setup preview and Apply expose the same effective route and migration outcome; unsupported facts produce explicit errors. +- Semantic ports: read workflow identity/configuration and apply only validated setup changes. +- Durable state/schema ownership: existing repository Variables, Secrets, workflow files, and continuation state retain their existing owners and schemas. +- Concurrency/idempotency strategy: preserve existing admission, one-use continuation, candidate identity, and publication guards. +- Trusted and untrusted inputs: issue/comment payloads, repository configuration, expressions, and workflow inputs are untrusted until validated; only supported named values cross the coordinator boundary. +- Provider error mapping: distinguish unsupported platform/reference/policy from workflow execution failure and provide actionable setup/operator recovery. + +### 8.3 Executable architecture constraints + +A pure known-workflow contract MUST target 100% branch coverage. Automated checks MUST parse workflow YAML and verify one-job native ownership, allowed inputs/Secrets, source and installed reference forms, timeout placement, callback line limits, setup route parity, and absence of unrestricted secrets inheritance or credential/PAT setup inputs. Dependency/contract checks MUST ensure pure policy does not import provider SDKs and setup presentation does not mutate configuration. + +## 9. UI/UX and content contract + +### 9.1 Information hierarchy + +Existing result cards remain unchanged and continue to show current status, completed facts, next transition, action requirement, impact, and inspectable links before technical details. Setup migration guidance leads with the route that will be applied and any human action required. + +### 9.2 Representative primary view + +The coordinator does not introduce a new issue/review card. Existing cards are normative and must be preserved byte/semantically as established by the verification owner. Setup preview should communicate the concrete effective route and migration decision: + +```markdown +## Comment workflow setup preview + +**Current status:** Ready to apply the Copilot comment workflow update. + +**Runner route:** `labels: [self-hosted, linux]` + +**Action required:** Review the listed custom bootstrap migration before applying. + +## Changes + +- [x] The callback will call Copilot's comment coordinator at `v3`. +- [x] The configured runner route is preserved in preview and Apply. +- [ ] Custom bootstrap step requires maintainer review. + +## What happens next + +Apply the reviewed workflow update, then inspect the first run's checks and Job Summary. +``` + +Variants: pending/no action reports that no run is required; action required links to migration review; blocked/failed identifies impact, cause, action, retained configuration and run link; partially complete states which setup files changed and which remain untouched; completed links to the applied workflow and verification run. No new comment or notification is emitted solely for coordinator adoption. + +### 9.3 Issue, PR, and comment behavior + +- Deterministic titles and purpose: preserve the existing result-card titles and purposes exactly. +- What merge/close/retry will do: preserve current callback semantics; rerun/retry follows existing admission and does not resume by rerunning the agent through the continuation path. +- Durable marker and idempotent update policy: retain existing markers and one-use continuation policy. +- Comment/notification budget: no additional comments or notifications due to centralization. +- Labels and checks as supplemental state: preserve existing checks and publication guards. +- Direct links and navigation: existing issue/PR and workflow-run links remain descriptive and usable. + +### 9.4 Accessibility, localization, and responsive behavior + +Preserve the existing locale and fallback contract of result cards. New setup guidance uses plain text, descriptive links, semantic headings and short lists; it remains readable on narrow screens and in light/dark themes. Escape untrusted values and do not render configuration as executable Markdown, mentions, HTML markers, commands, or arbitrary URLs. Diagrams have adjacent text equivalents. + +## 10. Failure, recovery, and cleanup + +| Failure/partial state | User impact | Retained facts | Automatic retry | Required action | Cleanup | +|---|---|---|---|---|---| +| Unsupported ref, runner, or Actions policy | Callback cannot start coordinator | Existing configuration and callback remain | No | Meet documented GitHub.com, runner 2.336.0+, and policy prerequisites | No setup state created | +| Unknown input or malformed route JSON | Setup/run fails closed | Original configuration retained | No | Correct supported input/route; inspect preview | No inferred permissions/routes | +| Setup step times out | Verification cannot continue | Candidate and prior facts remain subject to existing semantics | Existing policy only | Inspect failed step and retry through supported entrypoint | Native reverse post cleanup | +| Worker readiness exceeds 300 seconds | Verification is blocked | Candidate identity retained where existing runtime permits | Existing policy only | Inspect run and use documented recovery | Native cleanup | +| Job reaches 120-minute budget | Job is canceled | Completed facts and logs retained | Existing policy only | Inspect timeout location before retry | Native post cleanup runs where platform permits | +| Custom bootstrap migration is unreviewed | Setup Apply is blocked | Existing workflow/configuration retained | No | Review migration and apply explicitly | No silent deletion | +| Publication guard rejects result | No result is published | Verification evidence retained | No automatic publication retry beyond current contract | Follow existing operator guidance | Setup cleanup completes | + +Errors follow impact -> cause -> action -> retained state and must not claim successful prior effects failed. + +## 11. Security, permissions, and privacy + +1. Preserve existing event admission, bot/fork gates, and least-privilege permissions. Coordinator permissions must be explicit and no broader than the existing native callback contract. +2. Treat workflow inputs, event data, repository configuration, route JSON, and expressions as untrusted. Reject unknown or ambiguous values; never infer runner access. +3. Named Secrets remain explicit. Do not use unrestricted secrets inheritance. Provider credentials are scoped to the initial Copilot step and must not be passed to project setup. +4. Preserve trusted-main Action pinning, candidate identity, credential-free verifier profiles, one-use continuations, and guarded publication. Logs and summaries must not expose Secret values or sensitive environment data. + +## 12. Observability and operational UX + +- User-facing state: existing cards and checks remain the source of verification outcome. +- Job Summary/operator evidence: identify callback type, coordinator version/ref, admitted phase, setup/continuation outcome, verifier/publication guard outcome, and cleanup status without secret values. +- Logs, metrics, and correlation: preserve existing run/event/candidate correlation identifiers and sanitize untrusted fields. +- Pending external dependency versus workflow failure: distinguish platform prerequisite/reference rejection from native step failure. +- Rate-limit/retry behavior: preserve existing provider retry behavior and bounds. +- Noise/comment budget: centralization adds no comments or notifications. + +## 13. Compatibility, migration, rollout, and rollback + +Source callbacks use the exact same-commit self-repository workflow reference. Installed callbacks use `vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3`. The coordinator uses GitHub's self-repository Action reference so an exact caller SHA cannot drift to another Action version. Require GitHub.com support, runner 2.336.0 or later, and compatible Actions policy; document these prerequisites and how to upgrade the pinned workflow ref. + +Migration MUST preserve source-only jobs and consumer Action bytes and auxiliary assets. Setup MUST retain or explicitly replace existing scalar/label/group routes, display the same route in preview and Apply, and recognize known reusable callers during maintenance. Unknown inputs, unsupported source identity, malformed runner JSON, and dependent expressions fail closed. Custom bootstrap steps require reviewed migration and actionable recovery. Rollout follows the Action-managed issue branch and reviewed PR lifecycle; do not create, rename, or force-push managed branches manually. Keep unrelated release-review changes out absent concrete dependency. Release #661 remains unpublished until this dependency and its final-head checks/review are complete. Rollback restores the prior callback workflow and configuration while preserving existing candidate and result facts; no irreversible effect is introduced by the coordinator itself. + +## 14. Testing strategy and numeric budget + +Minimum additional risk-derived floor: 40 distinct cases shared once across both capabilities; do not double count a case because both callback types use it. + +| Area | Minimum distinct cases | Behaviors/risks covered | +|---|---:|---| +| Workflow/security mutations | 16 | Admission/bot/fork gates; explicit secrets; no inherit-all; credential scope; trusted pin; timeouts; one job; same-job candidate; continuation; cleanup; publication guards; input rejection | +| Routing/migration/idempotency | 12 | Scalar/label/group routes; preview/Apply parity; known caller recognition; malformed JSON; dependent expressions; custom bootstrap review; source-only jobs; assets/bytes; replay and one-use semantics | +| Configuration inspection/identity/credential scope | 12 | Known workflow contract; supported source identity; installed ref; unknown input; unsupported runner/platform/policy; Variable/Secret semantics; credential boundary; failure recovery | +| **Total** | **40** | No double counting | + +Repository coverage gates remain in force. Changed modules meet existing thresholds; new pure known-workflow policy targets 100% branch coverage. Tests parse workflow structure rather than grep prose, and cover both callback entrypoints against shared coordinator contracts. Use deterministic fixtures and fakes without real waits or live services. Preserve and extend golden result-card fixtures with semantic assertions. Manual UX evidence reviews setup preview/Apply parity and existing result cards at narrow width and light/dark themes. Full implementation validation includes all repository validators, full coverage, package/build smoke, and real native acceptance on Linux, Windows, and macOS. + +## 15. Documentation and discoverability + +| Audience | Artifact/page | Required content | Validation/navigation | +|---|---|---|---| +| User | `docs/issues/comment-commands.mdx` | Existing result behavior and run links remain unchanged | Documentation link/contract checks | +| Setup owner | `docs/setup-web.mdx`, `docs/configuration.mdx`, `docs/configuration-checklist.mdx` | Coordinator installation, route preview/Apply parity, supported inputs and secrets | Fixtures and documentation validators | +| Operator | `docs/security-operations/operations/verification.mdx`, `docs/security-operations/operations/troubleshooting.mdx` | Prerequisites, failure states, timeout/cleanup, recovery | Operator decision-tree review | +| Contributor | `docs/development/architecture.mdx`, `specs/copilot-comment-workflow-coordinator.md`, both existing owning specs | Boundaries, workflow contracts, pinned-ref upgrades, migration | Architecture and specification validation | + +Update user/operator/upgrade documentation, tests, generated bundles, catalog evidence, and `specs/CATALOG.md` together. Document GitHub.com, runner 2.336.0+, Actions-policy prerequisites and pinned-ref upgrades. Cross-reference the branch-synchronization verification SDD without changing its ownership. Keep examples synchronized with contract fixtures. + +## 16. Acceptance scenarios + +1. Given an admitted issue-comment event, when its callback invokes the installed coordinator, then the existing result and publication behavior completes through one job with the same candidate and cleanup semantics. +2. Given a source callback, when it invokes the coordinator, then the workflow reference resolves to the exact same commit and the Action reference cannot drift. +3. Given a setup with a scalar, label, or group route, when preview and Apply run, then both show and apply the same route. +4. Given malformed runner JSON, dependent expressions, an unknown input, or unsupported source identity, when setup or workflow validation occurs, then it fails closed and gives actionable recovery without inferring permissions. +5. Given a worker continuation, when verification resumes, then the one-use continuation verifies the existing candidate and does not rerun the agent or business operation. +6. Given a native setup timeout, worker readiness timeout, or job timeout, when the run stops, then the configured five-minute, 300-second, and 120-minute limits apply and reverse native post cleanup runs where supported. +7. Given provider Secrets, when the coordinator runs, then named Secrets are explicit, provider credentials reach only the initial Copilot step, and project setup receives no provider/PAT input. +8. Given custom bootstrap steps, when setup migration is previewed, then Apply requires reviewed migration and presents actionable recovery without silently dropping steps. +9. Given disabled, read-only, dry-run, or no-op configuration, when the callback executes, then existing semantics and user-facing cards are retained. +10. Given GitHub.com or runner/Actions-policy prerequisites are unmet, when the callback is invoked, then failure is clear and points to prerequisite remediation. +11. Given the documentation and generated bundles are updated, when repository validation runs, then specification/catalog, workflow, coverage, package/build, and cross-platform native acceptance gates are satisfied. + +## 17. Requirements traceability + +| Requirement | Policy/use case/adapter/presentation | Test or evidence | Documentation | +|---|---|---|---| +| Central coordinator and one-job native lifecycle | Workflow composition | Workflow structure contracts; 16 workflow/security cases | Architecture and verification docs | +| Exact source and installed references | Entrypoint/workflow adapter | Ref identity contract cases | Upgrade guide | +| Preserve route and migration behavior | Setup policy and preview/Apply | 12 routing/migration/idempotency cases | Setup/configuration docs | +| Credential and trust boundaries | Workflow inputs and Secret mapping | 12 identity/credential cases plus security mutations | Security credentials and operations docs | +| Existing behavior and result cards | Existing verification owner and presentation | Golden and semantic compatibility assertions | Comment commands and verification docs | +| Platform prerequisites and recovery | Infrastructure/operator guidance | Platform/ref failure contracts | Troubleshooting and upgrade docs | + +## 18. Implementation sequence + +1. Record workflow input/Secret contracts, supported source identity, runner route rules, and architecture checks. +2. Implement pure known-workflow/input/route policy and achieve full branch coverage. +3. Update setup preview/Apply and configuration maintenance recognition with migration outcomes. +4. Implement the central reusable workflow with all native phases and contract tests. +5. Migrate source and setup callbacks, preserving source-only jobs, Action bytes/assets, and custom bootstrap through reviewed migration. +6. Update both owning specifications by cross-reference/change, catalog evidence, generated bundles, user/operator/upgrade docs, and fixtures together. +7. Run repository validators, full coverage, package/build smoke, and real native acceptance on Linux, Windows, and macOS; obtain review and final-head checks before release dependency proceeds. + +## 19. Definition of Done + +- [ ] Source and setup comment callbacks are each at most 35 lines and one central workflow owns all native phases. +- [ ] Existing admission, bot/fork gates, Variable/Secret semantics, time limits, candidate identity, pinning, verifier profiles, continuation, publication, cards, and cleanup are preserved. +- [ ] No unrestricted secrets inheritance or provider/PAT inputs to project setup; named Secret scope is verified. +- [ ] Setup preview and Apply expose identical routes; known callers are recognized; malformed/unknown/ambiguous inputs fail closed. +- [ ] Custom bootstrap steps have reviewed migration and actionable recovery; source-only jobs, consumer Action bytes, and auxiliary assets are preserved. +- [ ] GitHub.com, runner, Actions-policy prerequisites and pinned-ref upgrades are documented. +- [ ] Numeric 40-case budget passes, existing coverage gates remain, and new pure known-workflow contract has full branch coverage. +- [ ] Linux, Windows, and macOS native acceptance, repository validators, full coverage, and package/build smoke pass. +- [ ] User/setup/operator/contributor and upgrade documentation, owning-spec cross-references, generated bundles, catalog evidence, and `specs/CATALOG.md` are current; `pnpm run validate:specifications` passes. +- [ ] Existing result cards pass UX review; failure, migration, security, cleanup, and accessibility requirements are satisfied. +- [ ] Final-head checks and review are complete before dependent release #661 is published. +- [ ] No readiness-blocking decision remains unresolved. + +## 20. References and decisions + +- Primary sources: [GitHub runner action schema](https://github.com/actions/runner/blob/main/src/Runner.Worker/action_yaml.json); [GitHub same-repository self-reference announcement](https://github.blog/changelog/2026-07-30-reference-same-repository-actions-with-self-repository-syntax/). +- Related specs/ADRs/issues/PRs: [Issue #662](https://github.com/vypdev/copilot/issues/662); existing setup owner `specs/setup-runner-profiles-and-installation-parity.md` under `setup-and-doctor`; existing verification owner `specs/repository-verification-setup-hooks.md` under `branch-synchronization`; #647/#652 and #656/#657; dependent release #661. +- Decisions and rejected alternatives: one reusable workflow owns the complete job; generated orchestration in every consumer rejected for duplication/review cost; composite coordinator rejected because it cannot preserve native per-step cancellation; another candidate setup job rejected because it breaks same-job worker/candidate environment; removing time limits is outside scope. Maintainer approved a concise new companion at `specs/copilot-comment-workflow-coordinator.md` under `setup-and-doctor`. +- Follow-up work explicitly outside this spec: publishing release #661 before this issue's implementation and final-head checks/review; unrelated release-review corrections without a concrete dependency. \ No newline at end of file From 805385a0d17282604ed6fb0b6ef58de15482fa9b Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Thu, 22 Oct 2026 01:15:42 +0200 Subject: [PATCH 42/44] chore: centralize comment workflow coordination (#662) Keep native setup, continuations and cleanup in one reusable workflow, preserve setup routing and configuration inspection, and document compatible upgrades. --- .github/workflows/copilot_comment_runtime.yml | 738 ++++++++++++++++++ .github/workflows/copilot_issue_comment.yml | 710 +---------------- .../copilot_pull_request_comment.yml | 710 +---------------- build/cli/index.js | 132 +++- build/github_action/index.js | 89 ++- docs/configuration-checklist.mdx | 4 + docs/configuration.mdx | 7 + docs/development/architecture.mdx | 10 + docs/issues/comment-commands.mdx | 6 + .../operations/upgrade-rollback.mdx | 30 +- .../operations/verification.mdx | 32 +- .../security/self-hosted-runners.mdx | 6 + docs/setup-web.mdx | 5 + ...generate-native-verification-workflows.cjs | 82 +- scripts/validate-comment-workflows.cjs | 33 + scripts/validate-workflow-contract.cjs | 54 +- setup/workflows/copilot_issue_comment.yml | 704 +---------------- .../copilot_pull_request_comment.yml | 704 +---------------- specs/CATALOG.md | 14 +- specs/catalog.json | 20 +- specs/repository-verification-setup-hooks.md | 32 +- ...runner-profiles-and-installation-parity.md | 29 + .../copilot_comment_workflow.test.ts | 35 + src/domain/copilot_comment_workflow.ts | 39 + .../native_verification_workflow.test.ts | 105 ++- ...setup_management_workspace_adapter.test.ts | 34 + .../verification_setup_configuration.test.ts | 13 +- .../copilot_comment_inputs.json | 72 ++ .../setup_management_workspace_adapter.ts | 19 +- .../validate_workflow_contract.test.ts | 29 +- .../verification_runtime_guidance.test.ts | 8 +- .../setup_runner_installation.test.ts | 10 + .../__tests__/setup_workflow_upgrade.test.ts | 43 + src/utils/setup_installation_review.ts | 3 +- src/utils/setup_workflow_upgrade.ts | 24 + 35 files changed, 1720 insertions(+), 2865 deletions(-) create mode 100644 .github/workflows/copilot_comment_runtime.yml create mode 100644 scripts/validate-comment-workflows.cjs create mode 100644 src/domain/__tests__/copilot_comment_workflow.test.ts create mode 100644 src/domain/copilot_comment_workflow.ts create mode 100644 src/infrastructure/copilot_comment_inputs.json diff --git a/.github/workflows/copilot_comment_runtime.yml b/.github/workflows/copilot_comment_runtime.yml new file mode 100644 index 000000000..b17c4d3a3 --- /dev/null +++ b/.github/workflows/copilot_comment_runtime.yml @@ -0,0 +1,738 @@ +# Generated by scripts/generate-native-verification-workflows.cjs +name: Copilot - Comment Runtime +'on': + workflow_call: + inputs: + runs-on: + description: JSON runner labels or group retained by setup. + type: string + default: '"ubuntu-latest"' + issue-managed-branches: + description: Optional issue-managed-branches override; otherwise use the caller repository Variable. + type: string + default: '' + pre-branch-sdd: + description: Optional pre-branch-sdd override; otherwise use the caller repository Variable. + type: string + default: '' + ai-ignore-files: + description: Optional ai-ignore-files override; otherwise use the caller repository Variable. + type: string + default: '' + prepare-source-verification: + description: Retain Copilot source-repository verification prerequisites; ignored in consumer repositories. + type: boolean + default: false + secrets: + PAT: + required: false + OPENCODE_API_KEY: + required: false + OPENAI_API_KEY: + required: false + ANTHROPIC_API_KEY: + required: false + GOOGLE_API_KEY: + required: false + OPENROUTER_API_KEY: + required: false + CURSOR_API_KEY: + required: false + CODEX_API_KEY: + required: false +jobs: + copilot: + name: Copilot + if: ${{ (vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN) && (github.event_name == 'issue_comment' || (github.event_name == 'pull_request_review_comment' && github.event.pull_request.head.repo.full_name == github.repository)) }} + runs-on: ${{ fromJSON(inputs.runs-on) }} + timeout-minutes: 120 + permissions: + checks: write + contents: read + env: + COPILOT_PREPARE_VERIFICATION: ${{ github.repository == 'vypdev/copilot' && inputs.prepare-source-verification && vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS != '' && ((contains(github.event.comment.body, '/copilot') && ((contains(github.event.comment.body, 'sync-branch') && !contains(github.event.comment.body, '--dry-run')) || contains(github.event.comment.body, 'implement') || contains(github.event.comment.body, 'fix') || contains(github.event.comment.body, 'remember'))) || (vars.COPILOT_BOT_LOGIN != '' && contains(github.event.comment.body, format('@{0}', vars.COPILOT_BOT_LOGIN)) && !contains(github.event.comment.body, '--dry-run'))) }} + steps: + - name: Checkout Repository + uses: actions/checkout@v5 + with: + persist-credentials: false + fetch-depth: 0 + - name: Prepare repository pnpm + if: env.COPILOT_PREPARE_VERIFICATION == 'true' + uses: pnpm/action-setup@v5 + with: + version: 10.12.4 + standalone: false + dest: ${{ runner.temp }}/setup-pnpm-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }} + - name: Prepare repository Node + if: env.COPILOT_PREPARE_VERIFICATION == 'true' + uses: actions/setup-node@v7 + with: + node-version: 24.x + - name: Install repository verification dependencies + if: env.COPILOT_PREPARE_VERIFICATION == 'true' + run: pnpm install --frozen-lockfile --ignore-scripts + shell: bash + - name: Run Copilot + id: copilot + uses: $/ + with: &ref_0 + repository-locale: ${{ vars.REPOSITORY_LOCALE || 'en-US' }} + issues-locale: ${{ vars.ISSUES_LOCALE || '' }} + pull-requests-locale: ${{ vars.PULL_REQUESTS_LOCALE || '' }} + ai-ignore-files: ${{ inputs.ai-ignore-files || vars.AI_IGNORE_FILES || 'build/*' }} + debug: ${{ vars.DEBUG }} + main-branch: ${{ vars.MAIN_BRANCH || 'master' }} + development-branch: ${{ vars.DEVELOPMENT_BRANCH || 'develop' }} + feature-tree: ${{ vars.FEATURE_TREE || 'feature' }} + bugfix-tree: ${{ vars.BUGFIX_TREE || 'bugfix' }} + hotfix-tree: ${{ vars.HOTFIX_TREE || 'hotfix' }} + release-tree: ${{ vars.RELEASE_TREE || 'release' }} + docs-tree: ${{ vars.DOCS_TREE || 'docs' }} + chore-tree: ${{ vars.CHORE_TREE || 'chore' }} + issue-managed-branches: ${{ inputs.issue-managed-branches || vars.ISSUE_MANAGED_BRANCHES || 'true' }} + pre-branch-sdd: ${{ inputs.pre-branch-sdd || vars.PRE_BRANCH_SDD || 'false' }} + verification-setup: ${{ vars.VERIFICATION_SETUP || 'false' }} + issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} + reopen-issue-on-push: ${{ vars.REOPEN_ISSUE_ON_PUSH || 'true' }} + desired-assignees-count: ${{ vars.DESIRED_ASSIGNEES_COUNT || '1' }} + desired-reviewers-count: ${{ vars.DESIRED_REVIEWERS_COUNT || '1' }} + commit-prefix-transforms: ${{ vars.COMMIT_PREFIX_TRANSFORMS || 'replace-slash' }} + ai-pull-request-description-mode: ${{ vars.AI_PULL_REQUEST_DESCRIPTION_MODE || 'replace' }} + ai-members-only: ${{ vars.AI_MEMBERS_ONLY || 'false' }} + ai-include-reasoning: ${{ vars.AI_INCLUDE_REASONING || 'false' }} + bugbot-severity: ${{ vars.BUGBOT_SEVERITY || 'low' }} + bugbot-comment-limit: ${{ vars.BUGBOT_COMMENT_LIMIT || '20' }} + bugbot-fix-verify-commands: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }} + bugbot-dry-run: ${{ vars.BUGBOT_DRY_RUN || 'false' }} + bugbot-effort: ${{ vars.BUGBOT_EFFORT || 'smart' }} + bugbot-review-drafts: ${{ vars.BUGBOT_REVIEW_DRAFTS || 'false' }} + bugbot-trace-rules: ${{ vars.BUGBOT_TRACE_RULES || 'false' }} + bugbot-suggested-changes: ${{ vars.BUGBOT_SUGGESTED_CHANGES || 'true' }} + bugbot-telemetry: ${{ vars.BUGBOT_TELEMETRY || 'true' }} + bugbot-fail-on-unresolved: ${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || 'false' }} + bugbot-organization-rules: ${{ vars.BUGBOT_ORGANIZATION_RULES }} + project-column-issue-created: ${{ vars.PROJECT_COLUMN_ISSUE_CREATED || 'Todo' }} + project-column-pull-request-created: ${{ vars.PROJECT_COLUMN_PULL_REQUEST_CREATED || 'In Progress' }} + project-column-issue-in-progress: ${{ vars.PROJECT_COLUMN_ISSUE_IN_PROGRESS || 'In Progress' }} + project-column-pull-request-in-progress: ${{ vars.PROJECT_COLUMN_PULL_REQUEST_IN_PROGRESS || 'In Progress' }} + agent-provider: ${{ vars.AGENT_PROVIDER || 'codex' }} + agent-model-provider: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} + agent-model: ${{ vars.AGENT_MODEL || 'gpt-6-luna' }} + agent-effort: ${{ vars.AGENT_EFFORT }} + agent-executable: ${{ vars.AGENT_EXECUTABLE }} + findings-provider: ${{ vars.FINDINGS_PROVIDER }} + findings-model-provider: ${{ vars.FINDINGS_MODEL_PROVIDER }} + findings-model: ${{ vars.FINDINGS_MODEL }} + findings-effort: ${{ vars.FINDINGS_EFFORT }} + findings-executable: ${{ vars.FINDINGS_EXECUTABLE }} + fixer-provider: ${{ vars.FIXER_PROVIDER }} + fixer-model-provider: ${{ vars.FIXER_MODEL_PROVIDER }} + fixer-model: ${{ vars.FIXER_MODEL }} + fixer-effort: ${{ vars.FIXER_EFFORT }} + fixer-executable: ${{ vars.FIXER_EXECUTABLE }} + planner-provider: ${{ vars.PLANNER_PROVIDER }} + planner-model-provider: ${{ vars.PLANNER_MODEL_PROVIDER }} + planner-model: ${{ vars.PLANNER_MODEL }} + planner-effort: ${{ vars.PLANNER_EFFORT }} + planner-executable: ${{ vars.PLANNER_EXECUTABLE }} + reviewer-provider: ${{ vars.REVIEWER_PROVIDER }} + reviewer-model-provider: ${{ vars.REVIEWER_MODEL_PROVIDER }} + reviewer-model: ${{ vars.REVIEWER_MODEL }} + reviewer-effort: ${{ vars.REVIEWER_EFFORT }} + reviewer-executable: ${{ vars.REVIEWER_EXECUTABLE }} + tester-provider: ${{ vars.TESTER_PROVIDER }} + tester-model-provider: ${{ vars.TESTER_MODEL_PROVIDER }} + tester-model: ${{ vars.TESTER_MODEL }} + tester-effort: ${{ vars.TESTER_EFFORT }} + tester-executable: ${{ vars.TESTER_EXECUTABLE }} + project-ids: ${{ vars.PROJECT_IDS }} + token: ${{ secrets.PAT }} + env: + COPILOT_NATIVE_PHASE: prepare + AGENT_PROVIDER: ${{ vars.AGENT_PROVIDER || 'codex' }} + AGENT_MODEL_PROVIDER: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} + AGENT_MODEL: ${{ vars.AGENT_MODEL }} + AGENT_EFFORT: ${{ vars.AGENT_EFFORT }} + AGENT_EXECUTABLE: ${{ vars.AGENT_EXECUTABLE }} + AGENT_ALLOWED_MODEL_PROVIDERS: ${{ vars.AGENT_ALLOWED_MODEL_PROVIDERS || 'openai' }} + AGENT_ALLOWED_MODELS: ${{ vars.AGENT_ALLOWED_MODELS || 'openai/gpt-6-luna' }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + CURSOR_API_KEY: ${{ (vars.AGENT_PROVIDER == 'cursor' || vars.FINDINGS_PROVIDER == 'cursor' || vars.FIXER_PROVIDER == 'cursor' || vars.PLANNER_PROVIDER == 'cursor' || vars.REVIEWER_PROVIDER == 'cursor' || vars.TESTER_PROVIDER == 'cursor') && secrets.CURSOR_API_KEY || '' }} + CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} + COPILOT_EVIDENCE_TOKEN: ${{ github.token }} + - name: Prepare repository verification 1 + id: verification_setup_1 + if: ${{ !cancelled() && steps.copilot.outcome == 'success' && steps.copilot.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.copilot.outputs.verification-home }} + USERPROFILE: ${{ steps.copilot.outputs.verification-userprofile }} + APPDATA: ${{ steps.copilot.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.copilot.outputs.verification-localappdata }} + PATH: ${{ steps.copilot.outputs.verification-path }} + JAVA_HOME: ${{ steps.copilot.outputs.verification-java_home }} + TMP: ${{ steps.copilot.outputs.verification-tmp }} + TEMP: ${{ steps.copilot.outputs.verification-temp }} + TMPDIR: ${{ steps.copilot.outputs.verification-tmpdir }} + - name: Continue repository verification 1 + id: verification_continue_1 + if: ${{ always() && steps.copilot.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.copilot.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_1.outcome }} + - name: Prepare repository verification 2 + id: verification_setup_2 + if: ${{ !cancelled() && steps.verification_continue_1.outcome == 'success' && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_1.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_1.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_1.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_1.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_1.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_1.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_1.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_1.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_1.outputs.verification-tmpdir }} + - name: Continue repository verification 2 + id: verification_continue_2 + if: ${{ always() && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_1.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_2.outcome }} + - name: Prepare repository verification 3 + id: verification_setup_3 + if: ${{ !cancelled() && steps.verification_continue_2.outcome == 'success' && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_2.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_2.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_2.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_2.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_2.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_2.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_2.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_2.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_2.outputs.verification-tmpdir }} + - name: Continue repository verification 3 + id: verification_continue_3 + if: ${{ always() && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_2.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_3.outcome }} + - name: Prepare repository verification 4 + id: verification_setup_4 + if: ${{ !cancelled() && steps.verification_continue_3.outcome == 'success' && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_3.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_3.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_3.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_3.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_3.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_3.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_3.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_3.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_3.outputs.verification-tmpdir }} + - name: Continue repository verification 4 + id: verification_continue_4 + if: ${{ always() && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_3.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_4.outcome }} + - name: Prepare repository verification 5 + id: verification_setup_5 + if: ${{ !cancelled() && steps.verification_continue_4.outcome == 'success' && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_4.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_4.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_4.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_4.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_4.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_4.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_4.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_4.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_4.outputs.verification-tmpdir }} + - name: Continue repository verification 5 + id: verification_continue_5 + if: ${{ always() && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_4.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_5.outcome }} + - name: Prepare repository verification 6 + id: verification_setup_6 + if: ${{ !cancelled() && steps.verification_continue_5.outcome == 'success' && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_5.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_5.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_5.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_5.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_5.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_5.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_5.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_5.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_5.outputs.verification-tmpdir }} + - name: Continue repository verification 6 + id: verification_continue_6 + if: ${{ always() && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_5.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_6.outcome }} + - name: Prepare repository verification 7 + id: verification_setup_7 + if: ${{ !cancelled() && steps.verification_continue_6.outcome == 'success' && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_6.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_6.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_6.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_6.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_6.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_6.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_6.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_6.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_6.outputs.verification-tmpdir }} + - name: Continue repository verification 7 + id: verification_continue_7 + if: ${{ always() && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_6.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_7.outcome }} + - name: Prepare repository verification 8 + id: verification_setup_8 + if: ${{ !cancelled() && steps.verification_continue_7.outcome == 'success' && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_7.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_7.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_7.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_7.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_7.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_7.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_7.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_7.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_7.outputs.verification-tmpdir }} + - name: Continue repository verification 8 + id: verification_continue_8 + if: ${{ always() && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_7.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_8.outcome }} + - name: Prepare repository verification 9 + id: verification_setup_9 + if: ${{ !cancelled() && steps.verification_continue_8.outcome == 'success' && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_8.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_8.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_8.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_8.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_8.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_8.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_8.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_8.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_8.outputs.verification-tmpdir }} + - name: Continue repository verification 9 + id: verification_continue_9 + if: ${{ always() && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_8.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_9.outcome }} + - name: Prepare repository verification 10 + id: verification_setup_10 + if: ${{ !cancelled() && steps.verification_continue_9.outcome == 'success' && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_9.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_9.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_9.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_9.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_9.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_9.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_9.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_9.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_9.outputs.verification-tmpdir }} + - name: Continue repository verification 10 + id: verification_continue_10 + if: ${{ always() && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_9.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_10.outcome }} + - name: Prepare repository verification 11 + id: verification_setup_11 + if: ${{ !cancelled() && steps.verification_continue_10.outcome == 'success' && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_10.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_10.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_10.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_10.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_10.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_10.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_10.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_10.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_10.outputs.verification-tmpdir }} + - name: Continue repository verification 11 + id: verification_continue_11 + if: ${{ always() && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_10.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_11.outcome }} + - name: Prepare repository verification 12 + id: verification_setup_12 + if: ${{ !cancelled() && steps.verification_continue_11.outcome == 'success' && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_11.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_11.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_11.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_11.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_11.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_11.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_11.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_11.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_11.outputs.verification-tmpdir }} + - name: Continue repository verification 12 + id: verification_continue_12 + if: ${{ always() && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_11.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_12.outcome }} + - name: Prepare repository verification 13 + id: verification_setup_13 + if: ${{ !cancelled() && steps.verification_continue_12.outcome == 'success' && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_12.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_12.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_12.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_12.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_12.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_12.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_12.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_12.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_12.outputs.verification-tmpdir }} + - name: Continue repository verification 13 + id: verification_continue_13 + if: ${{ always() && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_12.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_13.outcome }} + - name: Prepare repository verification 14 + id: verification_setup_14 + if: ${{ !cancelled() && steps.verification_continue_13.outcome == 'success' && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_13.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_13.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_13.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_13.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_13.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_13.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_13.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_13.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_13.outputs.verification-tmpdir }} + - name: Continue repository verification 14 + id: verification_continue_14 + if: ${{ always() && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_13.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_14.outcome }} + - name: Prepare repository verification 15 + id: verification_setup_15 + if: ${{ !cancelled() && steps.verification_continue_14.outcome == 'success' && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_14.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_14.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_14.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_14.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_14.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_14.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_14.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_14.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_14.outputs.verification-tmpdir }} + - name: Continue repository verification 15 + id: verification_continue_15 + if: ${{ always() && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_14.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_15.outcome }} + - name: Prepare repository verification 16 + id: verification_setup_16 + if: ${{ !cancelled() && steps.verification_continue_15.outcome == 'success' && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_15.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_15.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_15.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_15.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_15.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_15.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_15.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_15.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_15.outputs.verification-tmpdir }} + - name: Continue repository verification 16 + id: verification_continue_16 + if: ${{ always() && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_15.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_16.outcome }} + - name: Prepare repository verification 17 + id: verification_setup_17 + if: ${{ !cancelled() && steps.verification_continue_16.outcome == 'success' && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_16.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_16.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_16.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_16.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_16.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_16.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_16.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_16.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_16.outputs.verification-tmpdir }} + - name: Continue repository verification 17 + id: verification_continue_17 + if: ${{ always() && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_16.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_17.outcome }} + - name: Prepare repository verification 18 + id: verification_setup_18 + if: ${{ !cancelled() && steps.verification_continue_17.outcome == 'success' && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_17.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_17.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_17.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_17.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_17.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_17.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_17.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_17.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_17.outputs.verification-tmpdir }} + - name: Continue repository verification 18 + id: verification_continue_18 + if: ${{ always() && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_17.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_18.outcome }} + - name: Prepare repository verification 19 + id: verification_setup_19 + if: ${{ !cancelled() && steps.verification_continue_18.outcome == 'success' && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_18.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_18.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_18.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_18.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_18.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_18.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_18.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_18.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_18.outputs.verification-tmpdir }} + - name: Continue repository verification 19 + id: verification_continue_19 + if: ${{ always() && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_18.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_19.outcome }} + - name: Prepare repository verification 20 + id: verification_setup_20 + if: ${{ !cancelled() && steps.verification_continue_19.outcome == 'success' && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} + uses: ./.git/copilot-verification-setup + timeout-minutes: 5 + env: + HOME: ${{ steps.verification_continue_19.outputs.verification-home }} + USERPROFILE: ${{ steps.verification_continue_19.outputs.verification-userprofile }} + APPDATA: ${{ steps.verification_continue_19.outputs.verification-appdata }} + LOCALAPPDATA: ${{ steps.verification_continue_19.outputs.verification-localappdata }} + PATH: ${{ steps.verification_continue_19.outputs.verification-path }} + JAVA_HOME: ${{ steps.verification_continue_19.outputs.verification-java_home }} + TMP: ${{ steps.verification_continue_19.outputs.verification-tmp }} + TEMP: ${{ steps.verification_continue_19.outputs.verification-temp }} + TMPDIR: ${{ steps.verification_continue_19.outputs.verification-tmpdir }} + - name: Continue repository verification 20 + id: verification_continue_20 + if: ${{ always() && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: continue + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} + COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_19.outputs.verification-request }} + COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_20.outcome }} + - name: Complete repository verification + id: verification_complete + if: ${{ always() && steps.copilot.outputs.verification-ticket != '' }} + uses: $/ + with: *ref_0 + env: + COPILOT_NATIVE_PHASE: finish + COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} + COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} + COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} + COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} diff --git a/.github/workflows/copilot_issue_comment.yml b/.github/workflows/copilot_issue_comment.yml index b8a567d2d..2cc07d44c 100644 --- a/.github/workflows/copilot_issue_comment.yml +++ b/.github/workflows/copilot_issue_comment.yml @@ -1,694 +1,32 @@ +# Generated by scripts/generate-native-verification-workflows.cjs +# Project runtimes: .copilot/verification-prerequisites.json +# Dependencies: .github/actions/copilot-verification-setup/action.yml +# https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites name: Copilot - Issue Comment - -on: +'on': issue_comment: - types: [created, edited] - + types: + - created + - edited jobs: copilot-issues: if: ${{ vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN }} - name: Copilot - Issue Comment - runs-on: [self-hosted, codex, Linux] - timeout-minutes: 120 + uses: $/.github/workflows/copilot_comment_runtime.yml permissions: checks: write contents: read - env: - # Preparation covers parser whitespace and mentions; authorization stays in the Action. - COPILOT_PREPARE_VERIFICATION: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS != '' && ((contains(github.event.comment.body, '/copilot') && ((contains(github.event.comment.body, 'sync-branch') && !contains(github.event.comment.body, '--dry-run')) || contains(github.event.comment.body, 'implement') || contains(github.event.comment.body, 'fix') || contains(github.event.comment.body, 'remember'))) || (vars.COPILOT_BOT_LOGIN != '' && contains(github.event.comment.body, format('@{0}', vars.COPILOT_BOT_LOGIN)) && !contains(github.event.comment.body, '--dry-run'))) }} - steps: - - name: Checkout Repository - uses: actions/checkout@v5 - with: - persist-credentials: false - fetch-depth: 0 - - - name: Prepare repository pnpm - if: env.COPILOT_PREPARE_VERIFICATION == 'true' - uses: pnpm/action-setup@v5 - with: - version: 10.12.4 - standalone: false - dest: ${{ runner.temp }}/setup-pnpm-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }} - - - name: Prepare repository Node - if: env.COPILOT_PREPARE_VERIFICATION == 'true' - uses: actions/setup-node@v7 - with: - node-version: '24.x' - - - name: Install repository verification dependencies - if: env.COPILOT_PREPARE_VERIFICATION == 'true' - shell: bash - run: pnpm install --frozen-lockfile --ignore-scripts - - - name: Snapshot the Copilot runtime before candidate changes - id: prepare_native_runtime - run: node scripts/prepare-native-source-action.cjs - shell: bash - - - uses: ./../.copilot-native-runtime - id: copilot - with: &copilot-inputs - repository-locale: ${{ vars.REPOSITORY_LOCALE || 'en-US' }} - issues-locale: ${{ vars.ISSUES_LOCALE || '' }} - pull-requests-locale: ${{ vars.PULL_REQUESTS_LOCALE || '' }} - issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} - issue-managed-branches: true - pre-branch-sdd: true - verification-setup: ${{ vars.VERIFICATION_SETUP || 'false' }} - ai-ignore-files: build/*,specs/CATALOG.md - debug: ${{ vars.DEBUG }} - agent-provider: ${{ vars.AGENT_PROVIDER || 'codex' }} - agent-model-provider: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - agent-model: ${{ vars.AGENT_MODEL || 'gpt-6-luna' }} - agent-effort: ${{ vars.AGENT_EFFORT }} - agent-executable: ${{ vars.AGENT_EXECUTABLE }} - findings-provider: ${{ vars.FINDINGS_PROVIDER }} - findings-model-provider: ${{ vars.FINDINGS_MODEL_PROVIDER }} - findings-model: ${{ vars.FINDINGS_MODEL }} - findings-effort: ${{ vars.FINDINGS_EFFORT }} - findings-executable: ${{ vars.FINDINGS_EXECUTABLE }} - fixer-provider: ${{ vars.FIXER_PROVIDER }} - fixer-model-provider: ${{ vars.FIXER_MODEL_PROVIDER }} - fixer-model: ${{ vars.FIXER_MODEL }} - fixer-effort: ${{ vars.FIXER_EFFORT }} - fixer-executable: ${{ vars.FIXER_EXECUTABLE }} - planner-provider: ${{ vars.PLANNER_PROVIDER }} - planner-model-provider: ${{ vars.PLANNER_MODEL_PROVIDER }} - planner-model: ${{ vars.PLANNER_MODEL }} - planner-effort: ${{ vars.PLANNER_EFFORT }} - planner-executable: ${{ vars.PLANNER_EXECUTABLE }} - reviewer-provider: ${{ vars.REVIEWER_PROVIDER }} - reviewer-model-provider: ${{ vars.REVIEWER_MODEL_PROVIDER }} - reviewer-model: ${{ vars.REVIEWER_MODEL }} - reviewer-effort: ${{ vars.REVIEWER_EFFORT }} - reviewer-executable: ${{ vars.REVIEWER_EXECUTABLE }} - tester-provider: ${{ vars.TESTER_PROVIDER }} - tester-model-provider: ${{ vars.TESTER_MODEL_PROVIDER }} - tester-model: ${{ vars.TESTER_MODEL }} - tester-effort: ${{ vars.TESTER_EFFORT }} - tester-executable: ${{ vars.TESTER_EXECUTABLE }} - project-ids: ${{ vars.PROJECT_IDS }} - token: ${{ secrets.PAT }} - bugbot-fix-verify-commands: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }} - bugbot-dry-run: ${{ vars.BUGBOT_DRY_RUN || 'false' }} - bugbot-effort: ${{ vars.BUGBOT_EFFORT || 'smart' }} - bugbot-review-drafts: ${{ vars.BUGBOT_REVIEW_DRAFTS || 'false' }} - bugbot-trace-rules: ${{ vars.BUGBOT_TRACE_RULES || 'false' }} - bugbot-suggested-changes: ${{ vars.BUGBOT_SUGGESTED_CHANGES || 'true' }} - bugbot-telemetry: ${{ vars.BUGBOT_TELEMETRY || 'true' }} - bugbot-fail-on-unresolved: ${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || 'false' }} - bugbot-organization-rules: ${{ vars.BUGBOT_ORGANIZATION_RULES }} - env: - COPILOT_NATIVE_PHASE: prepare - COPILOT_NATIVE_RUNTIME_CACHE: ${{ steps.prepare_native_runtime.outputs.path }} - AGENT_PROVIDER: ${{ vars.AGENT_PROVIDER || 'codex' }} - AGENT_MODEL_PROVIDER: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - AGENT_MODEL: ${{ vars.AGENT_MODEL }} - AGENT_EFFORT: ${{ vars.AGENT_EFFORT }} - AGENT_ALLOWED_MODEL_PROVIDERS: ${{ vars.AGENT_ALLOWED_MODEL_PROVIDERS || 'openai' }} - AGENT_ALLOWED_MODELS: ${{ vars.AGENT_ALLOWED_MODELS || 'openai/gpt-6-luna' }} - AGENT_EXECUTABLE: ${{ vars.AGENT_EXECUTABLE }} - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} - OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - CURSOR_API_KEY: ${{ (vars.AGENT_PROVIDER == 'cursor' || vars.FINDINGS_PROVIDER == 'cursor' || vars.FIXER_PROVIDER == 'cursor' || vars.PLANNER_PROVIDER == 'cursor' || vars.REVIEWER_PROVIDER == 'cursor' || vars.TESTER_PROVIDER == 'cursor') && secrets.CURSOR_API_KEY || '' }} - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} - COPILOT_EVIDENCE_TOKEN: ${{ github.token }} - - # copilot:native-verification:start - - name: Prepare repository verification 1 - id: verification_setup_1 - if: ${{ !cancelled() && steps.copilot.outcome == 'success' && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.copilot.outputs.verification-home }} - USERPROFILE: ${{ steps.copilot.outputs.verification-userprofile }} - APPDATA: ${{ steps.copilot.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.copilot.outputs.verification-localappdata }} - PATH: ${{ steps.copilot.outputs.verification-path }} - JAVA_HOME: ${{ steps.copilot.outputs.verification-java_home }} - TMP: ${{ steps.copilot.outputs.verification-tmp }} - TEMP: ${{ steps.copilot.outputs.verification-temp }} - TMPDIR: ${{ steps.copilot.outputs.verification-tmpdir }} - - name: Continue repository verification 1 - id: verification_continue_1 - if: ${{ always() && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.copilot.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_1.outcome }} - - name: Prepare repository verification 2 - id: verification_setup_2 - if: ${{ !cancelled() && steps.verification_continue_1.outcome == 'success' && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_1.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_1.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_1.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_1.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_1.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_1.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_1.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_1.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_1.outputs.verification-tmpdir }} - - name: Continue repository verification 2 - id: verification_continue_2 - if: ${{ always() && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_1.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_2.outcome }} - - name: Prepare repository verification 3 - id: verification_setup_3 - if: ${{ !cancelled() && steps.verification_continue_2.outcome == 'success' && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_2.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_2.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_2.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_2.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_2.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_2.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_2.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_2.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_2.outputs.verification-tmpdir }} - - name: Continue repository verification 3 - id: verification_continue_3 - if: ${{ always() && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_2.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_3.outcome }} - - name: Prepare repository verification 4 - id: verification_setup_4 - if: ${{ !cancelled() && steps.verification_continue_3.outcome == 'success' && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_3.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_3.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_3.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_3.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_3.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_3.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_3.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_3.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_3.outputs.verification-tmpdir }} - - name: Continue repository verification 4 - id: verification_continue_4 - if: ${{ always() && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_3.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_4.outcome }} - - name: Prepare repository verification 5 - id: verification_setup_5 - if: ${{ !cancelled() && steps.verification_continue_4.outcome == 'success' && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_4.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_4.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_4.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_4.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_4.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_4.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_4.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_4.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_4.outputs.verification-tmpdir }} - - name: Continue repository verification 5 - id: verification_continue_5 - if: ${{ always() && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_4.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_5.outcome }} - - name: Prepare repository verification 6 - id: verification_setup_6 - if: ${{ !cancelled() && steps.verification_continue_5.outcome == 'success' && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_5.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_5.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_5.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_5.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_5.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_5.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_5.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_5.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_5.outputs.verification-tmpdir }} - - name: Continue repository verification 6 - id: verification_continue_6 - if: ${{ always() && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_5.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_6.outcome }} - - name: Prepare repository verification 7 - id: verification_setup_7 - if: ${{ !cancelled() && steps.verification_continue_6.outcome == 'success' && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_6.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_6.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_6.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_6.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_6.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_6.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_6.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_6.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_6.outputs.verification-tmpdir }} - - name: Continue repository verification 7 - id: verification_continue_7 - if: ${{ always() && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_6.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_7.outcome }} - - name: Prepare repository verification 8 - id: verification_setup_8 - if: ${{ !cancelled() && steps.verification_continue_7.outcome == 'success' && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_7.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_7.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_7.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_7.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_7.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_7.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_7.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_7.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_7.outputs.verification-tmpdir }} - - name: Continue repository verification 8 - id: verification_continue_8 - if: ${{ always() && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_7.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_8.outcome }} - - name: Prepare repository verification 9 - id: verification_setup_9 - if: ${{ !cancelled() && steps.verification_continue_8.outcome == 'success' && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_8.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_8.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_8.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_8.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_8.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_8.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_8.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_8.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_8.outputs.verification-tmpdir }} - - name: Continue repository verification 9 - id: verification_continue_9 - if: ${{ always() && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_8.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_9.outcome }} - - name: Prepare repository verification 10 - id: verification_setup_10 - if: ${{ !cancelled() && steps.verification_continue_9.outcome == 'success' && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_9.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_9.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_9.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_9.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_9.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_9.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_9.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_9.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_9.outputs.verification-tmpdir }} - - name: Continue repository verification 10 - id: verification_continue_10 - if: ${{ always() && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_9.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_10.outcome }} - - name: Prepare repository verification 11 - id: verification_setup_11 - if: ${{ !cancelled() && steps.verification_continue_10.outcome == 'success' && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_10.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_10.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_10.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_10.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_10.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_10.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_10.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_10.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_10.outputs.verification-tmpdir }} - - name: Continue repository verification 11 - id: verification_continue_11 - if: ${{ always() && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_10.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_11.outcome }} - - name: Prepare repository verification 12 - id: verification_setup_12 - if: ${{ !cancelled() && steps.verification_continue_11.outcome == 'success' && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_11.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_11.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_11.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_11.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_11.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_11.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_11.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_11.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_11.outputs.verification-tmpdir }} - - name: Continue repository verification 12 - id: verification_continue_12 - if: ${{ always() && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_11.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_12.outcome }} - - name: Prepare repository verification 13 - id: verification_setup_13 - if: ${{ !cancelled() && steps.verification_continue_12.outcome == 'success' && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_12.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_12.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_12.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_12.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_12.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_12.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_12.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_12.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_12.outputs.verification-tmpdir }} - - name: Continue repository verification 13 - id: verification_continue_13 - if: ${{ always() && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_12.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_13.outcome }} - - name: Prepare repository verification 14 - id: verification_setup_14 - if: ${{ !cancelled() && steps.verification_continue_13.outcome == 'success' && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_13.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_13.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_13.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_13.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_13.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_13.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_13.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_13.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_13.outputs.verification-tmpdir }} - - name: Continue repository verification 14 - id: verification_continue_14 - if: ${{ always() && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_13.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_14.outcome }} - - name: Prepare repository verification 15 - id: verification_setup_15 - if: ${{ !cancelled() && steps.verification_continue_14.outcome == 'success' && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_14.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_14.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_14.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_14.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_14.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_14.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_14.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_14.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_14.outputs.verification-tmpdir }} - - name: Continue repository verification 15 - id: verification_continue_15 - if: ${{ always() && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_14.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_15.outcome }} - - name: Prepare repository verification 16 - id: verification_setup_16 - if: ${{ !cancelled() && steps.verification_continue_15.outcome == 'success' && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_15.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_15.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_15.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_15.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_15.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_15.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_15.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_15.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_15.outputs.verification-tmpdir }} - - name: Continue repository verification 16 - id: verification_continue_16 - if: ${{ always() && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_15.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_16.outcome }} - - name: Prepare repository verification 17 - id: verification_setup_17 - if: ${{ !cancelled() && steps.verification_continue_16.outcome == 'success' && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_16.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_16.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_16.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_16.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_16.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_16.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_16.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_16.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_16.outputs.verification-tmpdir }} - - name: Continue repository verification 17 - id: verification_continue_17 - if: ${{ always() && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_16.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_17.outcome }} - - name: Prepare repository verification 18 - id: verification_setup_18 - if: ${{ !cancelled() && steps.verification_continue_17.outcome == 'success' && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_17.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_17.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_17.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_17.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_17.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_17.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_17.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_17.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_17.outputs.verification-tmpdir }} - - name: Continue repository verification 18 - id: verification_continue_18 - if: ${{ always() && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_17.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_18.outcome }} - - name: Prepare repository verification 19 - id: verification_setup_19 - if: ${{ !cancelled() && steps.verification_continue_18.outcome == 'success' && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_18.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_18.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_18.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_18.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_18.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_18.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_18.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_18.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_18.outputs.verification-tmpdir }} - - name: Continue repository verification 19 - id: verification_continue_19 - if: ${{ always() && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_18.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_19.outcome }} - - name: Prepare repository verification 20 - id: verification_setup_20 - if: ${{ !cancelled() && steps.verification_continue_19.outcome == 'success' && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_19.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_19.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_19.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_19.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_19.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_19.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_19.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_19.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_19.outputs.verification-tmpdir }} - - name: Continue repository verification 20 - id: verification_continue_20 - if: ${{ always() && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_19.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_20.outcome }} - - name: Complete repository verification - id: verification_complete - if: ${{ always() && steps.copilot.outputs.verification-ticket != '' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: finish - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - # copilot:native-verification:end + with: + runs-on: '["self-hosted","codex","Linux"]' + issue-managed-branches: 'true' + pre-branch-sdd: 'true' + ai-ignore-files: build/*,specs/CATALOG.md + prepare-source-verification: true + secrets: + PAT: ${{ secrets.PAT }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} + CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} diff --git a/.github/workflows/copilot_pull_request_comment.yml b/.github/workflows/copilot_pull_request_comment.yml index b3e5f1f38..77b1e3694 100644 --- a/.github/workflows/copilot_pull_request_comment.yml +++ b/.github/workflows/copilot_pull_request_comment.yml @@ -1,694 +1,32 @@ +# Generated by scripts/generate-native-verification-workflows.cjs +# Project runtimes: .copilot/verification-prerequisites.json +# Dependencies: .github/actions/copilot-verification-setup/action.yml +# https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites name: Copilot - Pull Request Comment - -on: +'on': pull_request_review_comment: - types: [created, edited] - + types: + - created + - edited jobs: copilot-pull-requests: if: ${{ (vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN) && github.event.pull_request.head.repo.full_name == github.repository }} - name: Copilot - Pull Request Comment - runs-on: [self-hosted, codex, Linux] - timeout-minutes: 120 + uses: $/.github/workflows/copilot_comment_runtime.yml permissions: checks: write contents: read - env: - # Preparation covers parser whitespace and mentions; authorization stays in the Action. - COPILOT_PREPARE_VERIFICATION: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS != '' && ((contains(github.event.comment.body, '/copilot') && ((contains(github.event.comment.body, 'sync-branch') && !contains(github.event.comment.body, '--dry-run')) || contains(github.event.comment.body, 'implement') || contains(github.event.comment.body, 'fix') || contains(github.event.comment.body, 'remember'))) || (vars.COPILOT_BOT_LOGIN != '' && contains(github.event.comment.body, format('@{0}', vars.COPILOT_BOT_LOGIN)) && !contains(github.event.comment.body, '--dry-run'))) }} - steps: - - name: Checkout Repository - uses: actions/checkout@v5 - with: - persist-credentials: false - fetch-depth: 0 - - - name: Prepare repository pnpm - if: env.COPILOT_PREPARE_VERIFICATION == 'true' - uses: pnpm/action-setup@v5 - with: - version: 10.12.4 - standalone: false - dest: ${{ runner.temp }}/setup-pnpm-${{ github.run_id }}-${{ github.run_attempt }}-${{ github.job }} - - - name: Prepare repository Node - if: env.COPILOT_PREPARE_VERIFICATION == 'true' - uses: actions/setup-node@v7 - with: - node-version: '24.x' - - - name: Install repository verification dependencies - if: env.COPILOT_PREPARE_VERIFICATION == 'true' - shell: bash - run: pnpm install --frozen-lockfile --ignore-scripts - - - name: Snapshot the Copilot runtime before candidate changes - id: prepare_native_runtime - run: node scripts/prepare-native-source-action.cjs - shell: bash - - - uses: ./../.copilot-native-runtime - id: copilot - with: &copilot-inputs - repository-locale: ${{ vars.REPOSITORY_LOCALE || 'en-US' }} - issues-locale: ${{ vars.ISSUES_LOCALE || '' }} - pull-requests-locale: ${{ vars.PULL_REQUESTS_LOCALE || '' }} - issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} - issue-managed-branches: true - pre-branch-sdd: true - verification-setup: ${{ vars.VERIFICATION_SETUP || 'false' }} - ai-ignore-files: build/*,specs/CATALOG.md - debug: ${{ vars.DEBUG }} - agent-provider: ${{ vars.AGENT_PROVIDER || 'codex' }} - agent-model-provider: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - agent-model: ${{ vars.AGENT_MODEL || 'gpt-6-luna' }} - agent-effort: ${{ vars.AGENT_EFFORT }} - agent-executable: ${{ vars.AGENT_EXECUTABLE }} - findings-provider: ${{ vars.FINDINGS_PROVIDER }} - findings-model-provider: ${{ vars.FINDINGS_MODEL_PROVIDER }} - findings-model: ${{ vars.FINDINGS_MODEL }} - findings-effort: ${{ vars.FINDINGS_EFFORT }} - findings-executable: ${{ vars.FINDINGS_EXECUTABLE }} - fixer-provider: ${{ vars.FIXER_PROVIDER }} - fixer-model-provider: ${{ vars.FIXER_MODEL_PROVIDER }} - fixer-model: ${{ vars.FIXER_MODEL }} - fixer-effort: ${{ vars.FIXER_EFFORT }} - fixer-executable: ${{ vars.FIXER_EXECUTABLE }} - reviewer-provider: ${{ vars.REVIEWER_PROVIDER }} - reviewer-model-provider: ${{ vars.REVIEWER_MODEL_PROVIDER }} - reviewer-model: ${{ vars.REVIEWER_MODEL }} - reviewer-effort: ${{ vars.REVIEWER_EFFORT }} - reviewer-executable: ${{ vars.REVIEWER_EXECUTABLE }} - planner-provider: ${{ vars.PLANNER_PROVIDER }} - planner-model-provider: ${{ vars.PLANNER_MODEL_PROVIDER }} - planner-model: ${{ vars.PLANNER_MODEL }} - planner-effort: ${{ vars.PLANNER_EFFORT }} - planner-executable: ${{ vars.PLANNER_EXECUTABLE }} - tester-provider: ${{ vars.TESTER_PROVIDER }} - tester-model-provider: ${{ vars.TESTER_MODEL_PROVIDER }} - tester-model: ${{ vars.TESTER_MODEL }} - tester-effort: ${{ vars.TESTER_EFFORT }} - tester-executable: ${{ vars.TESTER_EXECUTABLE }} - project-ids: ${{ vars.PROJECT_IDS }} - token: ${{ secrets.PAT }} - bugbot-fix-verify-commands: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }} - bugbot-dry-run: ${{ vars.BUGBOT_DRY_RUN || 'false' }} - bugbot-effort: ${{ vars.BUGBOT_EFFORT || 'smart' }} - bugbot-review-drafts: ${{ vars.BUGBOT_REVIEW_DRAFTS || 'false' }} - bugbot-trace-rules: ${{ vars.BUGBOT_TRACE_RULES || 'false' }} - bugbot-suggested-changes: ${{ vars.BUGBOT_SUGGESTED_CHANGES || 'true' }} - bugbot-telemetry: ${{ vars.BUGBOT_TELEMETRY || 'true' }} - bugbot-fail-on-unresolved: ${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || 'false' }} - bugbot-organization-rules: ${{ vars.BUGBOT_ORGANIZATION_RULES }} - env: - COPILOT_NATIVE_PHASE: prepare - COPILOT_NATIVE_RUNTIME_CACHE: ${{ steps.prepare_native_runtime.outputs.path }} - AGENT_PROVIDER: ${{ vars.AGENT_PROVIDER || 'codex' }} - AGENT_MODEL_PROVIDER: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - AGENT_MODEL: ${{ vars.AGENT_MODEL }} - AGENT_EFFORT: ${{ vars.AGENT_EFFORT }} - AGENT_ALLOWED_MODEL_PROVIDERS: ${{ vars.AGENT_ALLOWED_MODEL_PROVIDERS || 'openai' }} - AGENT_ALLOWED_MODELS: ${{ vars.AGENT_ALLOWED_MODELS || 'openai/gpt-6-luna' }} - AGENT_EXECUTABLE: ${{ vars.AGENT_EXECUTABLE }} - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} - OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - CURSOR_API_KEY: ${{ (vars.AGENT_PROVIDER == 'cursor' || vars.FINDINGS_PROVIDER == 'cursor' || vars.FIXER_PROVIDER == 'cursor' || vars.PLANNER_PROVIDER == 'cursor' || vars.REVIEWER_PROVIDER == 'cursor' || vars.TESTER_PROVIDER == 'cursor') && secrets.CURSOR_API_KEY || '' }} - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} - COPILOT_EVIDENCE_TOKEN: ${{ github.token }} - - # copilot:native-verification:start - - name: Prepare repository verification 1 - id: verification_setup_1 - if: ${{ !cancelled() && steps.copilot.outcome == 'success' && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.copilot.outputs.verification-home }} - USERPROFILE: ${{ steps.copilot.outputs.verification-userprofile }} - APPDATA: ${{ steps.copilot.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.copilot.outputs.verification-localappdata }} - PATH: ${{ steps.copilot.outputs.verification-path }} - JAVA_HOME: ${{ steps.copilot.outputs.verification-java_home }} - TMP: ${{ steps.copilot.outputs.verification-tmp }} - TEMP: ${{ steps.copilot.outputs.verification-temp }} - TMPDIR: ${{ steps.copilot.outputs.verification-tmpdir }} - - name: Continue repository verification 1 - id: verification_continue_1 - if: ${{ always() && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.copilot.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_1.outcome }} - - name: Prepare repository verification 2 - id: verification_setup_2 - if: ${{ !cancelled() && steps.verification_continue_1.outcome == 'success' && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_1.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_1.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_1.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_1.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_1.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_1.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_1.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_1.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_1.outputs.verification-tmpdir }} - - name: Continue repository verification 2 - id: verification_continue_2 - if: ${{ always() && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_1.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_2.outcome }} - - name: Prepare repository verification 3 - id: verification_setup_3 - if: ${{ !cancelled() && steps.verification_continue_2.outcome == 'success' && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_2.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_2.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_2.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_2.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_2.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_2.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_2.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_2.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_2.outputs.verification-tmpdir }} - - name: Continue repository verification 3 - id: verification_continue_3 - if: ${{ always() && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_2.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_3.outcome }} - - name: Prepare repository verification 4 - id: verification_setup_4 - if: ${{ !cancelled() && steps.verification_continue_3.outcome == 'success' && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_3.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_3.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_3.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_3.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_3.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_3.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_3.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_3.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_3.outputs.verification-tmpdir }} - - name: Continue repository verification 4 - id: verification_continue_4 - if: ${{ always() && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_3.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_4.outcome }} - - name: Prepare repository verification 5 - id: verification_setup_5 - if: ${{ !cancelled() && steps.verification_continue_4.outcome == 'success' && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_4.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_4.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_4.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_4.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_4.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_4.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_4.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_4.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_4.outputs.verification-tmpdir }} - - name: Continue repository verification 5 - id: verification_continue_5 - if: ${{ always() && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_4.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_5.outcome }} - - name: Prepare repository verification 6 - id: verification_setup_6 - if: ${{ !cancelled() && steps.verification_continue_5.outcome == 'success' && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_5.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_5.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_5.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_5.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_5.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_5.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_5.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_5.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_5.outputs.verification-tmpdir }} - - name: Continue repository verification 6 - id: verification_continue_6 - if: ${{ always() && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_5.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_6.outcome }} - - name: Prepare repository verification 7 - id: verification_setup_7 - if: ${{ !cancelled() && steps.verification_continue_6.outcome == 'success' && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_6.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_6.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_6.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_6.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_6.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_6.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_6.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_6.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_6.outputs.verification-tmpdir }} - - name: Continue repository verification 7 - id: verification_continue_7 - if: ${{ always() && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_6.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_7.outcome }} - - name: Prepare repository verification 8 - id: verification_setup_8 - if: ${{ !cancelled() && steps.verification_continue_7.outcome == 'success' && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_7.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_7.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_7.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_7.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_7.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_7.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_7.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_7.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_7.outputs.verification-tmpdir }} - - name: Continue repository verification 8 - id: verification_continue_8 - if: ${{ always() && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_7.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_8.outcome }} - - name: Prepare repository verification 9 - id: verification_setup_9 - if: ${{ !cancelled() && steps.verification_continue_8.outcome == 'success' && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_8.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_8.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_8.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_8.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_8.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_8.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_8.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_8.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_8.outputs.verification-tmpdir }} - - name: Continue repository verification 9 - id: verification_continue_9 - if: ${{ always() && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_8.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_9.outcome }} - - name: Prepare repository verification 10 - id: verification_setup_10 - if: ${{ !cancelled() && steps.verification_continue_9.outcome == 'success' && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_9.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_9.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_9.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_9.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_9.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_9.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_9.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_9.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_9.outputs.verification-tmpdir }} - - name: Continue repository verification 10 - id: verification_continue_10 - if: ${{ always() && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_9.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_10.outcome }} - - name: Prepare repository verification 11 - id: verification_setup_11 - if: ${{ !cancelled() && steps.verification_continue_10.outcome == 'success' && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_10.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_10.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_10.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_10.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_10.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_10.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_10.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_10.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_10.outputs.verification-tmpdir }} - - name: Continue repository verification 11 - id: verification_continue_11 - if: ${{ always() && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_10.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_11.outcome }} - - name: Prepare repository verification 12 - id: verification_setup_12 - if: ${{ !cancelled() && steps.verification_continue_11.outcome == 'success' && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_11.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_11.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_11.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_11.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_11.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_11.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_11.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_11.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_11.outputs.verification-tmpdir }} - - name: Continue repository verification 12 - id: verification_continue_12 - if: ${{ always() && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_11.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_12.outcome }} - - name: Prepare repository verification 13 - id: verification_setup_13 - if: ${{ !cancelled() && steps.verification_continue_12.outcome == 'success' && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_12.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_12.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_12.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_12.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_12.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_12.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_12.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_12.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_12.outputs.verification-tmpdir }} - - name: Continue repository verification 13 - id: verification_continue_13 - if: ${{ always() && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_12.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_13.outcome }} - - name: Prepare repository verification 14 - id: verification_setup_14 - if: ${{ !cancelled() && steps.verification_continue_13.outcome == 'success' && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_13.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_13.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_13.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_13.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_13.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_13.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_13.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_13.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_13.outputs.verification-tmpdir }} - - name: Continue repository verification 14 - id: verification_continue_14 - if: ${{ always() && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_13.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_14.outcome }} - - name: Prepare repository verification 15 - id: verification_setup_15 - if: ${{ !cancelled() && steps.verification_continue_14.outcome == 'success' && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_14.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_14.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_14.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_14.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_14.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_14.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_14.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_14.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_14.outputs.verification-tmpdir }} - - name: Continue repository verification 15 - id: verification_continue_15 - if: ${{ always() && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_14.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_15.outcome }} - - name: Prepare repository verification 16 - id: verification_setup_16 - if: ${{ !cancelled() && steps.verification_continue_15.outcome == 'success' && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_15.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_15.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_15.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_15.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_15.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_15.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_15.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_15.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_15.outputs.verification-tmpdir }} - - name: Continue repository verification 16 - id: verification_continue_16 - if: ${{ always() && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_15.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_16.outcome }} - - name: Prepare repository verification 17 - id: verification_setup_17 - if: ${{ !cancelled() && steps.verification_continue_16.outcome == 'success' && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_16.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_16.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_16.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_16.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_16.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_16.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_16.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_16.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_16.outputs.verification-tmpdir }} - - name: Continue repository verification 17 - id: verification_continue_17 - if: ${{ always() && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_16.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_17.outcome }} - - name: Prepare repository verification 18 - id: verification_setup_18 - if: ${{ !cancelled() && steps.verification_continue_17.outcome == 'success' && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_17.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_17.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_17.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_17.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_17.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_17.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_17.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_17.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_17.outputs.verification-tmpdir }} - - name: Continue repository verification 18 - id: verification_continue_18 - if: ${{ always() && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_17.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_18.outcome }} - - name: Prepare repository verification 19 - id: verification_setup_19 - if: ${{ !cancelled() && steps.verification_continue_18.outcome == 'success' && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_18.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_18.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_18.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_18.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_18.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_18.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_18.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_18.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_18.outputs.verification-tmpdir }} - - name: Continue repository verification 19 - id: verification_continue_19 - if: ${{ always() && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_18.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_19.outcome }} - - name: Prepare repository verification 20 - id: verification_setup_20 - if: ${{ !cancelled() && steps.verification_continue_19.outcome == 'success' && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_19.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_19.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_19.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_19.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_19.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_19.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_19.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_19.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_19.outputs.verification-tmpdir }} - - name: Continue repository verification 20 - id: verification_continue_20 - if: ${{ always() && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_19.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_20.outcome }} - - name: Complete repository verification - id: verification_complete - if: ${{ always() && steps.copilot.outputs.verification-ticket != '' }} - uses: ./../.copilot-native-runtime - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: finish - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - # copilot:native-verification:end + with: + runs-on: '["self-hosted","codex","Linux"]' + issue-managed-branches: 'true' + pre-branch-sdd: 'true' + ai-ignore-files: build/*,specs/CATALOG.md + prepare-source-verification: true + secrets: + PAT: ${{ secrets.PAT }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} + CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} diff --git a/build/cli/index.js b/build/cli/index.js index 81eaa6c34..d559704ad 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -90561,6 +90561,63 @@ function isCopilotCommentRequest(commentBody, botLogin) { } +/***/ }), + +/***/ 33430: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.COPILOT_COMMENT_REMOTE_WORKFLOW = exports.COPILOT_COMMENT_SELF_WORKFLOW = exports.COPILOT_COMMENT_RUNTIME = void 0; +exports.isCopilotCommentWorkflow = isCopilotCommentWorkflow; +exports.isCopilotCommentRunner = isCopilotCommentRunner; +exports.copilotCommentRunner = copilotCommentRunner; +/** The comment coordinator is a versioned Copilot workflow, not an arbitrary reusable job. */ +exports.COPILOT_COMMENT_RUNTIME = 'copilot_comment_runtime.yml'; +exports.COPILOT_COMMENT_SELF_WORKFLOW = `$/.github/workflows/${exports.COPILOT_COMMENT_RUNTIME}`; +exports.COPILOT_COMMENT_REMOTE_WORKFLOW = `vypdev/copilot/.github/workflows/${exports.COPILOT_COMMENT_RUNTIME}@v3`; +function isCopilotCommentWorkflow(value) { + return typeof value === 'string' && (value === exports.COPILOT_COMMENT_SELF_WORKFLOW + || /^vypdev\/copilot\/\.github\/workflows\/copilot_comment_runtime\.yml@(?:v3(?:\.[0-9]+\.[0-9]+)?|[a-f0-9]{40})$/u.test(value)); +} +const literal = (value) => typeof value === 'string' && value.length > 0 && value.length <= 100 + && value === value.trim() && !/[\p{Cc}\p{Cf}${}<>]/u.test(value); +const labels = (value) => literal(value) || Array.isArray(value) && value.length > 0 && value.length <= 10 + && value.every(literal) && new Set(value.map(label => label.toLowerCase())).size === value.length; +/** Runner routing is literal data; expressions need their original full workflow reviewed. */ +function isCopilotCommentRunner(value) { + if (labels(value)) + return true; + if (!value || typeof value !== 'object' || Array.isArray(value)) + return false; + const route = value; + const keys = Object.keys(route); + return keys.length > 0 && (route.group !== undefined || route.labels !== undefined) + && keys.every(key => key === 'group' || key === 'labels') + && (route.group === undefined || literal(route.group)) + && (route.labels === undefined || labels(route.labels)); +} +function copilotCommentRunner(job) { + if (!job || !isCopilotCommentWorkflow(job.uses)) + return job?.['runs-on']; + const inputs = job.with; + if (typeof inputs?.['runs-on'] !== 'string') + throw new Error('Comment workflow runner JSON is unavailable; review the workflow separately.'); + try { + if (inputs['runs-on'].length > 16000) + throw new Error('Runner JSON exceeds its bound.'); + const route = JSON.parse(inputs['runs-on']); + if (!isCopilotCommentRunner(route)) + throw new Error('Unsupported execution route.'); + return route; + } + catch { + throw new Error('Comment workflow runner JSON is invalid; review the workflow separately.'); + } +} + + /***/ }), /***/ 72418: @@ -100421,10 +100478,13 @@ exports.SetupGithubIdentityQueryAdapter = SetupGithubIdentityQueryAdapter; /***/ }), /***/ 75545: -/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => { +/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) { "use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.SetupManagementWorkspaceAdapter = void 0; const node_fs_1 = __nccwpck_require__(87561); @@ -100432,6 +100492,8 @@ const node_path_1 = __nccwpck_require__(49411); const node_crypto_1 = __nccwpck_require__(6005); const js_yaml_1 = __nccwpck_require__(783); const sensitive_text_1 = __nccwpck_require__(47122); +const copilot_comment_workflow_1 = __nccwpck_require__(33430); +const copilot_comment_inputs_json_1 = __importDefault(__nccwpck_require__(78593)); const object = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {}; const digest = (source) => (0, node_crypto_1.createHash)('sha256').update(source).digest('hex'); function readDocument(path) { @@ -100522,13 +100584,29 @@ class SetupManagementWorkspaceAdapter { inspectWorkflow(file, localAction) { const { source, document } = readDocument((0, node_path_1.join)(this.root, '.github', 'workflows', file)); const steps = workflowSteps(document); - const knownLocalAction = steps.some(({ step }) => step.uses === './') ? Boolean(localAction()) : false; - return steps.flatMap(({ job, step }) => { - if (!this.isCopilotStep(step, knownLocalAction)) - return []; - const inputs = Object.entries(object(step.with)).flatMap(([name, value]) => installedInput(name, value)); - return [{ file, action: step.uses, digest: digest(source), environmentScoped: environmentScoped(document, job, step), inputs }]; + const calls = Object.values(object(document.jobs)).map(object).filter(job => (0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(job.uses)); + if (calls.some(job => job.uses === copilot_comment_workflow_1.COPILOT_COMMENT_SELF_WORKFLOW) && !localAction()) + throw new Error('Unverified source comment workflow.'); + const reusable = calls.map(job => { + const overrides = object(job.with); + if (Object.keys(overrides).some(key => !['runs-on', 'issue-managed-branches', 'pre-branch-sdd', 'ai-ignore-files', 'prepare-source-verification'].includes(key))) + throw new Error('Unknown comment workflow input.'); + const bindings = { ...copilot_comment_inputs_json_1.default }; + for (const name of ['issue-managed-branches', 'pre-branch-sdd', 'ai-ignore-files']) { + if (overrides[name] !== undefined && overrides[name] !== '') + bindings[name] = overrides[name]; + } + return { file, action: job.uses === copilot_comment_workflow_1.COPILOT_COMMENT_SELF_WORKFLOW ? './' : `vypdev/copilot@${String(job.uses).split('@').at(-1)}`, + digest: digest(source), environmentScoped: environmentScoped(document, job, {}), + inputs: Object.entries(bindings).flatMap(([name, value]) => installedInput(name, value)) }; }); + const knownLocalAction = steps.some(({ step }) => step.uses === './') ? Boolean(localAction()) : false; + return [...reusable, ...steps.flatMap(({ job, step }) => { + if (!this.isCopilotStep(step, knownLocalAction)) + return []; + const inputs = Object.entries(object(step.with)).flatMap(([name, value]) => installedInput(name, value)); + return [{ file, action: step.uses, digest: digest(source), environmentScoped: environmentScoped(document, job, step), inputs }]; + })]; } isCopilotStep(step, knownLocalAction) { if (typeof step.uses !== 'string') @@ -106805,6 +106883,7 @@ const sensitive_text_1 = __nccwpck_require__(47122); const repository_agent_guidance_policy_1 = __nccwpck_require__(67402); const setup_verification_action_1 = __nccwpck_require__(33156); const setup_verification_action_2 = __nccwpck_require__(12471); +const copilot_comment_workflow_1 = __nccwpck_require__(33430); exports.SETUP_RUNNER_SNAPSHOT = '.copilot/runner-profile.json'; const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined; @@ -106870,7 +106949,7 @@ function inspectSetupInstallation(root, configuration, setup = (0, node_path_1.j if (!parsedJobs) throw new Error('Workflow jobs are unavailable for review.'); for (const [job, raw] of Object.entries(parsedJobs)) { - const runsOn = object(raw)?.['runs-on']; + const runsOn = (0, copilot_comment_workflow_1.copilotCommentRunner)(object(raw)); if (runsOn === undefined) continue; // reusable workflow calls have no runner jobs.push({ file, job, role: (0, setup_runner_policy_1.setupRunnerRole)(file, job) ?? 'validation', @@ -106977,6 +107056,7 @@ const js_yaml_1 = __nccwpck_require__(783); const node_util_1 = __nccwpck_require__(47261); const setup_runner_policy_1 = __nccwpck_require__(91027); const action_types_1 = __nccwpck_require__(19625); +const copilot_comment_workflow_1 = __nccwpck_require__(33430); const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined; const document = (value) => { try { @@ -106998,6 +107078,8 @@ const runner = (value) => labels(value) || !!object(value) && (object(value).labels === undefined || labels(object(value).labels)); const copilotCommands = new Set(Object.values(action_types_1.ACTIONS)); const callsRootAction = (jobs) => !!jobs && Object.values(jobs).some(job => { + if (object(job)?.uses === copilot_comment_workflow_1.COPILOT_COMMENT_SELF_WORKFLOW) + return true; const steps = object(job)?.steps; return Array.isArray(steps) && steps.some(step => { const invocation = object(step); @@ -107060,6 +107142,32 @@ function renderSetupWorkflowUpgrade(template, existing, selection) { const templateJobs = object(document(template)?.jobs); if (!previousJobs || !templateJobs) throw new Error('Workflow jobs cannot be inspected; review the workflow separately.'); + if (Object.values(templateJobs).some(job => (0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(object(job)?.uses))) { + const parsed = document(template); + const jobs = object(parsed.jobs); + let changed = false; + for (const [name, value] of Object.entries(jobs)) { + const job = object(value); + if (!(0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(job.uses)) + throw new Error('Mixed comment workflow jobs require separate workflow review before setup.'); + const previousJob = object(previousJobs[name]); + if (Array.isArray(previousJob?.steps) && previousJob.steps.some(raw => { + const uses = object(raw)?.uses; + return typeof uses !== 'string' || !(uses.startsWith('actions/checkout@') + || /^vypdev\/copilot@[^\s]+$/u.test(uses) || uses === './.git/copilot-verification-setup'); + })) + throw new Error('Custom comment job steps require migration to the reviewed repository verification setup action before switching to the reusable workflow. Review the workflow separately.'); + const retained = (0, setup_runner_policy_1.selectedSetupRunsOn)(selection?.runners, selection && (0, setup_runner_policy_1.setupRunnerRole)(selection.file, name)) + ?? (0, copilot_comment_workflow_1.copilotCommentRunner)(previousJob) ?? (0, copilot_comment_workflow_1.copilotCommentRunner)(job); + if (!runner(retained)) + throw new Error('Existing runner selection is invalid; review the workflow separately.'); + if (JSON.stringify(retained).includes('${{') && existing !== template) + throw new Error('Dynamic runner selection requires separate workflow review before setup.'); + changed || (changed = !(0, node_util_1.isDeepStrictEqual)(retained, (0, copilot_comment_workflow_1.copilotCommentRunner)(job))); + job.with = { ...object(job.with), 'runs-on': JSON.stringify(retained) }; + } + return changed ? (0, js_yaml_1.dump)(parsed, { noRefs: true, lineWidth: -1 }) : template; + } const lines = template.split('\n'); let job = ''; let insideJobs = false; @@ -118890,6 +118998,14 @@ module.exports = JSON.parse('{"single":{"topLeft":"┌","top":"─","topRight":" "use strict"; module.exports = JSON.parse('{"revision":"2026-10-02.standalone.1","providers":{"codex":{"executable":"codex","reviewedVersion":"codex-cli 0.156.1","legacyNpmPackage":"@openai/codex","installation":{"unixScript":"https://chatgpt.com/codex/install.sh","windowsScript":"https://chatgpt.com/codex/install.ps1"}},"opencode":{"executable":"opencode","reviewedVersion":"1.18.3","legacyNpmPackage":"opencode-ai","installation":{"unixScript":"https://opencode.ai/install","windowsReleaseApi":"https://api.github.com/repos/anomalyco/opencode/releases/latest"}},"cursor":{"executable":"agent","reviewedVersion":"2026.09.10-fd3934a","installation":{"unixScript":"https://cursor.com/install","windowsScript":"https://cursor.com/install?win32=true"}}}}'); +/***/ }), + +/***/ 78593: +/***/ ((module) => { + +"use strict"; +module.exports = JSON.parse('{"repository-locale":"${{ vars.REPOSITORY_LOCALE || \'en-US\' }}","issues-locale":"${{ vars.ISSUES_LOCALE || \'\' }}","pull-requests-locale":"${{ vars.PULL_REQUESTS_LOCALE || \'\' }}","ai-ignore-files":"${{ vars.AI_IGNORE_FILES || \'build/*\' }}","debug":"${{ vars.DEBUG }}","main-branch":"${{ vars.MAIN_BRANCH || \'master\' }}","development-branch":"${{ vars.DEVELOPMENT_BRANCH || \'develop\' }}","feature-tree":"${{ vars.FEATURE_TREE || \'feature\' }}","bugfix-tree":"${{ vars.BUGFIX_TREE || \'bugfix\' }}","hotfix-tree":"${{ vars.HOTFIX_TREE || \'hotfix\' }}","release-tree":"${{ vars.RELEASE_TREE || \'release\' }}","docs-tree":"${{ vars.DOCS_TREE || \'docs\' }}","chore-tree":"${{ vars.CHORE_TREE || \'chore\' }}","issue-managed-branches":"${{ vars.ISSUE_MANAGED_BRANCHES || \'true\' }}","pre-branch-sdd":"${{ vars.PRE_BRANCH_SDD || \'false\' }}","verification-setup":"${{ vars.VERIFICATION_SETUP || \'false\' }}","issue-workflow-profile":"${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || \'\' }}","reopen-issue-on-push":"${{ vars.REOPEN_ISSUE_ON_PUSH || \'true\' }}","desired-assignees-count":"${{ vars.DESIRED_ASSIGNEES_COUNT || \'1\' }}","desired-reviewers-count":"${{ vars.DESIRED_REVIEWERS_COUNT || \'1\' }}","commit-prefix-transforms":"${{ vars.COMMIT_PREFIX_TRANSFORMS || \'replace-slash\' }}","ai-pull-request-description-mode":"${{ vars.AI_PULL_REQUEST_DESCRIPTION_MODE || \'replace\' }}","ai-members-only":"${{ vars.AI_MEMBERS_ONLY || \'false\' }}","ai-include-reasoning":"${{ vars.AI_INCLUDE_REASONING || \'false\' }}","bugbot-severity":"${{ vars.BUGBOT_SEVERITY || \'low\' }}","bugbot-comment-limit":"${{ vars.BUGBOT_COMMENT_LIMIT || \'20\' }}","bugbot-fix-verify-commands":"${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }}","bugbot-dry-run":"${{ vars.BUGBOT_DRY_RUN || \'false\' }}","bugbot-effort":"${{ vars.BUGBOT_EFFORT || \'smart\' }}","bugbot-review-drafts":"${{ vars.BUGBOT_REVIEW_DRAFTS || \'false\' }}","bugbot-trace-rules":"${{ vars.BUGBOT_TRACE_RULES || \'false\' }}","bugbot-suggested-changes":"${{ vars.BUGBOT_SUGGESTED_CHANGES || \'true\' }}","bugbot-telemetry":"${{ vars.BUGBOT_TELEMETRY || \'true\' }}","bugbot-fail-on-unresolved":"${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || \'false\' }}","bugbot-organization-rules":"${{ vars.BUGBOT_ORGANIZATION_RULES }}","project-column-issue-created":"${{ vars.PROJECT_COLUMN_ISSUE_CREATED || \'Todo\' }}","project-column-pull-request-created":"${{ vars.PROJECT_COLUMN_PULL_REQUEST_CREATED || \'In Progress\' }}","project-column-issue-in-progress":"${{ vars.PROJECT_COLUMN_ISSUE_IN_PROGRESS || \'In Progress\' }}","project-column-pull-request-in-progress":"${{ vars.PROJECT_COLUMN_PULL_REQUEST_IN_PROGRESS || \'In Progress\' }}","agent-provider":"${{ vars.AGENT_PROVIDER || \'codex\' }}","agent-model-provider":"${{ vars.AGENT_MODEL_PROVIDER || \'openai\' }}","agent-model":"${{ vars.AGENT_MODEL || \'gpt-6-luna\' }}","agent-effort":"${{ vars.AGENT_EFFORT }}","agent-executable":"${{ vars.AGENT_EXECUTABLE }}","findings-provider":"${{ vars.FINDINGS_PROVIDER }}","findings-model-provider":"${{ vars.FINDINGS_MODEL_PROVIDER }}","findings-model":"${{ vars.FINDINGS_MODEL }}","findings-effort":"${{ vars.FINDINGS_EFFORT }}","findings-executable":"${{ vars.FINDINGS_EXECUTABLE }}","fixer-provider":"${{ vars.FIXER_PROVIDER }}","fixer-model-provider":"${{ vars.FIXER_MODEL_PROVIDER }}","fixer-model":"${{ vars.FIXER_MODEL }}","fixer-effort":"${{ vars.FIXER_EFFORT }}","fixer-executable":"${{ vars.FIXER_EXECUTABLE }}","planner-provider":"${{ vars.PLANNER_PROVIDER }}","planner-model-provider":"${{ vars.PLANNER_MODEL_PROVIDER }}","planner-model":"${{ vars.PLANNER_MODEL }}","planner-effort":"${{ vars.PLANNER_EFFORT }}","planner-executable":"${{ vars.PLANNER_EXECUTABLE }}","reviewer-provider":"${{ vars.REVIEWER_PROVIDER }}","reviewer-model-provider":"${{ vars.REVIEWER_MODEL_PROVIDER }}","reviewer-model":"${{ vars.REVIEWER_MODEL }}","reviewer-effort":"${{ vars.REVIEWER_EFFORT }}","reviewer-executable":"${{ vars.REVIEWER_EXECUTABLE }}","tester-provider":"${{ vars.TESTER_PROVIDER }}","tester-model-provider":"${{ vars.TESTER_MODEL_PROVIDER }}","tester-model":"${{ vars.TESTER_MODEL }}","tester-effort":"${{ vars.TESTER_EFFORT }}","tester-executable":"${{ vars.TESTER_EXECUTABLE }}","project-ids":"${{ vars.PROJECT_IDS }}"}'); + /***/ }) /******/ }); diff --git a/build/github_action/index.js b/build/github_action/index.js index 1addc7cdf..94e9f073a 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -81005,6 +81005,63 @@ function isCopilotCommentRequest(commentBody, botLogin) { } +/***/ }), + +/***/ 33430: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.COPILOT_COMMENT_REMOTE_WORKFLOW = exports.COPILOT_COMMENT_SELF_WORKFLOW = exports.COPILOT_COMMENT_RUNTIME = void 0; +exports.isCopilotCommentWorkflow = isCopilotCommentWorkflow; +exports.isCopilotCommentRunner = isCopilotCommentRunner; +exports.copilotCommentRunner = copilotCommentRunner; +/** The comment coordinator is a versioned Copilot workflow, not an arbitrary reusable job. */ +exports.COPILOT_COMMENT_RUNTIME = 'copilot_comment_runtime.yml'; +exports.COPILOT_COMMENT_SELF_WORKFLOW = `$/.github/workflows/${exports.COPILOT_COMMENT_RUNTIME}`; +exports.COPILOT_COMMENT_REMOTE_WORKFLOW = `vypdev/copilot/.github/workflows/${exports.COPILOT_COMMENT_RUNTIME}@v3`; +function isCopilotCommentWorkflow(value) { + return typeof value === 'string' && (value === exports.COPILOT_COMMENT_SELF_WORKFLOW + || /^vypdev\/copilot\/\.github\/workflows\/copilot_comment_runtime\.yml@(?:v3(?:\.[0-9]+\.[0-9]+)?|[a-f0-9]{40})$/u.test(value)); +} +const literal = (value) => typeof value === 'string' && value.length > 0 && value.length <= 100 + && value === value.trim() && !/[\p{Cc}\p{Cf}${}<>]/u.test(value); +const labels = (value) => literal(value) || Array.isArray(value) && value.length > 0 && value.length <= 10 + && value.every(literal) && new Set(value.map(label => label.toLowerCase())).size === value.length; +/** Runner routing is literal data; expressions need their original full workflow reviewed. */ +function isCopilotCommentRunner(value) { + if (labels(value)) + return true; + if (!value || typeof value !== 'object' || Array.isArray(value)) + return false; + const route = value; + const keys = Object.keys(route); + return keys.length > 0 && (route.group !== undefined || route.labels !== undefined) + && keys.every(key => key === 'group' || key === 'labels') + && (route.group === undefined || literal(route.group)) + && (route.labels === undefined || labels(route.labels)); +} +function copilotCommentRunner(job) { + if (!job || !isCopilotCommentWorkflow(job.uses)) + return job?.['runs-on']; + const inputs = job.with; + if (typeof inputs?.['runs-on'] !== 'string') + throw new Error('Comment workflow runner JSON is unavailable; review the workflow separately.'); + try { + if (inputs['runs-on'].length > 16000) + throw new Error('Runner JSON exceeds its bound.'); + const route = JSON.parse(inputs['runs-on']); + if (!isCopilotCommentRunner(route)) + throw new Error('Unsupported execution route.'); + return route; + } + catch { + throw new Error('Comment workflow runner JSON is invalid; review the workflow separately.'); + } +} + + /***/ }), /***/ 72418: @@ -92895,6 +92952,7 @@ const sensitive_text_1 = __nccwpck_require__(47122); const repository_agent_guidance_policy_1 = __nccwpck_require__(67402); const setup_verification_action_1 = __nccwpck_require__(33156); const setup_verification_action_2 = __nccwpck_require__(12471); +const copilot_comment_workflow_1 = __nccwpck_require__(33430); exports.SETUP_RUNNER_SNAPSHOT = '.copilot/runner-profile.json'; const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined; @@ -92960,7 +93018,7 @@ function inspectSetupInstallation(root, configuration, setup = (0, node_path_1.j if (!parsedJobs) throw new Error('Workflow jobs are unavailable for review.'); for (const [job, raw] of Object.entries(parsedJobs)) { - const runsOn = object(raw)?.['runs-on']; + const runsOn = (0, copilot_comment_workflow_1.copilotCommentRunner)(object(raw)); if (runsOn === undefined) continue; // reusable workflow calls have no runner jobs.push({ file, job, role: (0, setup_runner_policy_1.setupRunnerRole)(file, job) ?? 'validation', @@ -93067,6 +93125,7 @@ const js_yaml_1 = __nccwpck_require__(783); const node_util_1 = __nccwpck_require__(47261); const setup_runner_policy_1 = __nccwpck_require__(91027); const action_types_1 = __nccwpck_require__(19625); +const copilot_comment_workflow_1 = __nccwpck_require__(33430); const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : undefined; const document = (value) => { try { @@ -93088,6 +93147,8 @@ const runner = (value) => labels(value) || !!object(value) && (object(value).labels === undefined || labels(object(value).labels)); const copilotCommands = new Set(Object.values(action_types_1.ACTIONS)); const callsRootAction = (jobs) => !!jobs && Object.values(jobs).some(job => { + if (object(job)?.uses === copilot_comment_workflow_1.COPILOT_COMMENT_SELF_WORKFLOW) + return true; const steps = object(job)?.steps; return Array.isArray(steps) && steps.some(step => { const invocation = object(step); @@ -93150,6 +93211,32 @@ function renderSetupWorkflowUpgrade(template, existing, selection) { const templateJobs = object(document(template)?.jobs); if (!previousJobs || !templateJobs) throw new Error('Workflow jobs cannot be inspected; review the workflow separately.'); + if (Object.values(templateJobs).some(job => (0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(object(job)?.uses))) { + const parsed = document(template); + const jobs = object(parsed.jobs); + let changed = false; + for (const [name, value] of Object.entries(jobs)) { + const job = object(value); + if (!(0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(job.uses)) + throw new Error('Mixed comment workflow jobs require separate workflow review before setup.'); + const previousJob = object(previousJobs[name]); + if (Array.isArray(previousJob?.steps) && previousJob.steps.some(raw => { + const uses = object(raw)?.uses; + return typeof uses !== 'string' || !(uses.startsWith('actions/checkout@') + || /^vypdev\/copilot@[^\s]+$/u.test(uses) || uses === './.git/copilot-verification-setup'); + })) + throw new Error('Custom comment job steps require migration to the reviewed repository verification setup action before switching to the reusable workflow. Review the workflow separately.'); + const retained = (0, setup_runner_policy_1.selectedSetupRunsOn)(selection?.runners, selection && (0, setup_runner_policy_1.setupRunnerRole)(selection.file, name)) + ?? (0, copilot_comment_workflow_1.copilotCommentRunner)(previousJob) ?? (0, copilot_comment_workflow_1.copilotCommentRunner)(job); + if (!runner(retained)) + throw new Error('Existing runner selection is invalid; review the workflow separately.'); + if (JSON.stringify(retained).includes('${{') && existing !== template) + throw new Error('Dynamic runner selection requires separate workflow review before setup.'); + changed || (changed = !(0, node_util_1.isDeepStrictEqual)(retained, (0, copilot_comment_workflow_1.copilotCommentRunner)(job))); + job.with = { ...object(job.with), 'runs-on': JSON.stringify(retained) }; + } + return changed ? (0, js_yaml_1.dump)(parsed, { noRefs: true, lineWidth: -1 }) : template; + } const lines = template.split('\n'); let job = ''; let insideJobs = false; diff --git a/docs/configuration-checklist.mdx b/docs/configuration-checklist.mdx index f1f0f5d08..027b117e0 100644 --- a/docs/configuration-checklist.mdx +++ b/docs/configuration-checklist.mdx @@ -4,6 +4,10 @@ description: Required checks before enabling Copilot automation. --- # Configuration checklist +For compact comment callbacks, verify runner 2.336.0+, platform support and the +Actions policy for Copilot's reusable coordinator. Review the retained runner and +any custom bootstrap migration using the [upgrade guide](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository). + Before enabling repository verification or automated fixes, provision required project runtimes in **each** executing job and add the reviewed [runtime declaration](/security-operations/operations/verification#repository-verification-prerequisites). diff --git a/docs/configuration.mdx b/docs/configuration.mdx index 1b19107ca..57924342c 100644 --- a/docs/configuration.mdx +++ b/docs/configuration.mdx @@ -5,6 +5,13 @@ description: Detailed configuration options for Copilot # Configuration Options +The generated comment callbacks delegate their whole job to +`vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3`. The coordinator +reads this repository's existing Variables and explicitly forwarded Secrets; +project setup remains isolated from provider/PAT inputs. Setup stores the reviewed +runner route as JSON in the call's `with.runs-on`, including label arrays and group +objects. See [verification and coordinator configuration](/security-operations/operations/verification#repository-owned-setup). + For a new installation, use [web setup](/setup-web). To configure a specific outcome, start with the [goal guides](/guides); they connect setup choices, runtime configuration and verification. This page is the input and scope reference. Copilot provides extensive configuration options to customize your workflow. Use the tabs below to jump to the category you need. diff --git a/docs/development/architecture.mdx b/docs/development/architecture.mdx index 4f1071274..1407ee2db 100644 --- a/docs/development/architecture.mdx +++ b/docs/development/architecture.mdx @@ -4,6 +4,16 @@ description: Clean Architecture boundaries for agent execution and workflow auto --- # Architecture +Issue/review comment callbacks are compact entrypoints into the Copilot-owned +`copilot_comment_runtime.yml` reusable workflow. One job owns the existing native +worker, project composite setup, continuations and reverse post cleanup. Internal +`uses: $/` references bind all runtime phases to the called workflow commit. The +pure known-workflow/runner contract lives in `copilot_comment_workflow.ts`; existing +setup adapters retain YAML/filesystem inspection, preview/Apply and migration. +Safe Variable/default bindings are shared by the workflow generator and maintenance +reader. See the [coordinator SDD](https://github.com/vypdev/copilot/blob/develop/specs/copilot-comment-workflow-coordinator.md) +and [operational contract](/security-operations/operations/verification#repository-owned-setup). + Verification setup onboarding uses the shared repository questionnaire and the existing `repository.verificationSetup` boolean. The package supplies a native composite starter under `setup/actions/`; the filesystem adapter inspects only diff --git a/docs/issues/comment-commands.mdx b/docs/issues/comment-commands.mdx index cc42960d2..4e1c285ef 100644 --- a/docs/issues/comment-commands.mdx +++ b/docs/issues/comment-commands.mdx @@ -5,6 +5,12 @@ description: Use @vypbot from issues and pull requests for help, analysis, plann # Comment commands +Generated comment workflows call one Copilot-owned coordinator. The command, +project dependency setup, verification and cleanup still run in the same job; +inspect the comment run's nested `Copilot` job for preparation/continuation logs. +Command permissions and result cards retain their existing behavior. See +[repository setup and verification](/security-operations/operations/verification#repository-owned-setup). + Branchless help requests stay on the read-only answer route even when natural language classification suggests a repository task. File changes require an authoritative branch from a supported surface, such as a PR review comment; diff --git a/docs/security-operations/operations/upgrade-rollback.mdx b/docs/security-operations/operations/upgrade-rollback.mdx index 81dddede7..c2076e69f 100644 --- a/docs/security-operations/operations/upgrade-rollback.mdx +++ b/docs/security-operations/operations/upgrade-rollback.mdx @@ -43,8 +43,8 @@ Copilot has three separate versioned layers: | Layer | What changes it | What still needs review | |---|---|---| | Installed CLI | `copilot upgrade` or an explicit npm/pnpm package version | The CLI prepares local files; it does not rewrite committed workflows merely by upgrading | -| Remote Action reference | The Copilot `uses` references in committed workflows | `@v3` follows the published major tag; an exact version or commit SHA stays pinned until explicitly changed | -| Generated workflow files | An approved `copilot setup --update-workflows` run | New jobs, inputs and native continuation steps must be committed, reviewed and merged | +| Remote Copilot reference | Action and reusable-workflow `uses` references in committed workflows | `@v3` follows the published major tag; an exact version or commit SHA stays pinned until explicitly changed | +| Generated workflow files | An approved `copilot setup --update-workflows` run | New jobs, inputs and coordinator calls must be committed, reviewed and merged | Moving a tag does not add steps to an old YAML file. Upgrading the CLI does not change the Action references in Git. A merge into `develop` is not a package or @@ -72,6 +72,18 @@ copilot setup --web --dry-run **3. Regenerate and review workflows.** +Before upgrading the comment callbacks, update self-hosted GitHub Actions runners +to **2.336.0+**. The centralized coordinator uses GitHub.com's self-repository +references to keep its internal Action on the exact selected workflow commit. +Verify platform support before adopting this format on other GitHub deployments. +Check that the repository/organization Actions policy permits the published +`vypdev/copilot/.github/workflows/copilot_comment_runtime.yml` reusable workflow +at your selected ref, as well as the existing Copilot Action. +If the existing comment jobs have custom dependency/bootstrap steps, migrate them +into the reviewed repository setup action before replacing those jobs; setup +blocks silently dropping them. Keep the prior reviewed callbacks until this is +ready. See [repository-owned setup](/security-operations/operations/verification#repository-owned-setup). + Apply a reviewed workflow upgrade: ```bash @@ -83,9 +95,14 @@ verification setup question disabled for this preparation pass. Review the displayed create/preserve result and changes before approval. The installer creates `.github/actions/copilot-verification-setup/action.yml` only if absent; existing action bytes and auxiliary files are preserved through upgrades. -Generated workflows use `vypdev/copilot@v3`. If your repository pins versions -or SHAs, review **every** Copilot `uses` reference, including native -continuation/post steps, and apply the same chosen compatible published ref. +Generated comment callbacks use +`vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3`; other generated +callbacks continue using `vypdev/copilot@v3`. The coordinator owns setup, +continuations and cleanup in one job, keeping consumer YAML compact. If your +repository pins versions or SHAs, update the reusable-workflow and remaining +Action references to the chosen compatible published release. You do not edit +the internal `uses: $/` references: GitHub pins them to the called workflow commit. +The reviewed runner route is retained in the comment call's `with.runs-on` JSON. Workflow backups are retained under `.copilot/setup-backups/`. **4. Customize and merge on trusted main.** @@ -110,7 +127,8 @@ repository: Setup writes `VERIFICATION_SETUP` only when Variable management is enabled and follows the reviewed storage/reuse policy. With `--skip-variables`, update the effective Variable manually. Confirm that generated workflows pass the -`verification-setup` input and that the trusted action has been customized. +`VERIFICATION_SETUP` Variable through the coordinator (or the direct Action's +`verification-setup` input), and that the trusted action has been customized. Choose **Customize** when changing an existing repository Variable; **Reuse** keeps existing values. If an organization value must differ for this project, select `VERIFICATION_SETUP` in the repository Variable overrides and review the diff --git a/docs/security-operations/operations/verification.mdx b/docs/security-operations/operations/verification.mdx index 4235f05d9..43210a048 100644 --- a/docs/security-operations/operations/verification.mdx +++ b/docs/security-operations/operations/verification.mdx @@ -125,6 +125,26 @@ Each repository can prepare its dependencies in a native composite action, witho editing generated Copilot workflows. GitHub Actions executes the YAML's `uses` and `run` steps in the same job where Copilot verifies the candidate. +The generated issue-comment and PR-review-comment workflows call +`vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3`. This reusable +workflow keeps the complete job inside Copilot: checkout, the admitted operation, +project setup, verification continuations and native cleanup. Consumer callbacks +contain one call; they do not copy the twenty possible continuation slots. +Your dependency action stays in your own repository. + +The coordinator reads the caller repository's existing Variables and receives +only the named Secrets forwarded by the generated callback. Provider credentials +remain scoped to the initial Copilot step. The project setup action receives the +existing private runtime environment. Setup retains the selected runner in the +call's `with.runs-on` JSON string, including self-hosted labels and runner groups. + +GitHub Actions runner **2.336.0 or newer** is required: the coordinator's `uses: $/` +references load Copilot from the exact reusable-workflow commit, including a +consumer's pinned SHA, outside the mutable project checkout. This is supported on +GitHub.com; verify equivalent platform support before adopting it elsewhere. +See [GitHub's self-repository reference announcement](https://github.blog/changelog/2026-07-30-reference-same-repository-actions-with-self-repository-syntax/). +The existing five-minute setup limit and 120-minute job budget remain in force. + ```mermaid flowchart LR A[Copilot prepares changes] --> B[Repository composite installs dependencies] @@ -148,8 +168,8 @@ apply the existing publication guards. A separate CI job does not prepare this j your project's reviewed runtime and dependency setup; no language, version or install command is inferred, and setup does not execute the action. 3. Update the generated comment workflows with `copilot setup --update-workflows` - and review the complete diff. They need the native setup and continuation - steps; an older callback cannot execute YAML. Review the action, auxiliary + and review the complete diff. They need the reusable coordinator call; an older + callback without native support cannot execute YAML. Review the action, auxiliary scripts and workflows onto the configured `main-branch` (`MAIN_BRANCH`, normally production). Candidate or model changes cannot replace the trusted action. 4. Enable the same question in the terminal/web assistant, or set non-secret @@ -182,6 +202,14 @@ procedure](/security-operations/operations/upgrade-rollback#upgrade-an-existing- This repository's `setup_platform_smoke.yml` is internal CI and is not installed in consumer projects. +If your old comment job contains custom bootstrap steps, keep that reviewed +workflow until you move those steps into the trusted project setup action and +review its activation. A job that calls a reusable workflow cannot also declare +its own steps. Setup blocks that migration rather than silently removing custom +preparation; it also blocks malformed runner JSON or dependent runner expressions +that require separate workflow review. Plain generated callbacks and previously +upgraded callbacks retain their static runner selection automatically. + Copilot captures the complete action directory from an immutable trusted Git SHA before candidate changes. The trusted origin ref must be available locally; generated comment workflows use a full checkout. The runner executes that snapshot diff --git a/docs/security-operations/security/self-hosted-runners.mdx b/docs/security-operations/security/self-hosted-runners.mdx index ec0aec513..a5b54e990 100644 --- a/docs/security-operations/security/self-hosted-runners.mdx +++ b/docs/security-operations/security/self-hosted-runners.mdx @@ -14,6 +14,12 @@ A self-hosted runner that can access agent credentials MUST be dedicated or isol - audit runner labels and permissions; - keep local session files outside repository workspaces. +The compact Copilot comment callbacks require GitHub Actions runner **2.336.0+** +and platform support for self-repository references. Their reusable coordinator +keeps the Action on the called workflow's exact commit. Setup retains self-hosted +labels and groups in the call's `with.runs-on` JSON; it does not change group +access or prove capacity. See [comment workflow upgrades](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository). + A shared persistent runner is not equivalent to an ephemeral trusted runner. The self-hosted platform smoke uses the local pnpm store without exporting a diff --git a/docs/setup-web.mdx b/docs/setup-web.mdx index 36e7a02c1..75db6586b 100644 --- a/docs/setup-web.mdx +++ b/docs/setup-web.mdx @@ -5,6 +5,11 @@ description: Install Copilot with the local browser assistant, then verify a rea This is the recommended interactive installation path. The assistant runs on your computer and prepares the selected workflows and GitHub resources. You review the plan before permission checks or installation changes begin. +Comment callbacks call Copilot's reusable coordinator, keeping dependency setup, +verification and cleanup in one job. Existing runner labels/groups remain visible +in review. Check runner/platform prerequisites and migrate custom bootstrap before +adopting this format; follow the [existing repository upgrade guide](/security-operations/operations/upgrade-rollback#upgrade-an-existing-copilot-repository). + The assistant keeps tutorial, first-workflow and troubleshooting links available throughout the session. They open in another tab and retain your answers. Each question also links to its own reference and has a **Why this matters** explanation. See [Use the documentation](/using-the-docs) for version selection and offline help. ## Before you start diff --git a/scripts/generate-native-verification-workflows.cjs b/scripts/generate-native-verification-workflows.cjs index b8110af05..d47081f62 100644 --- a/scripts/generate-native-verification-workflows.cjs +++ b/scripts/generate-native-verification-workflows.cjs @@ -5,8 +5,12 @@ const yaml = require('js-yaml'); const MAX_REQUESTS = 20; const ACTION = './.git/copilot-verification-setup'; const { SOURCE_ACTION } = require('./prepare-native-source-action.cjs'); -const MARKER = ' # copilot:native-verification:start'; const CALLBACKS = ['copilot_issue_comment.yml', 'copilot_pull_request_comment.yml']; +const { COPILOT_COMMENT_RUNTIME: RUNTIME, COPILOT_COMMENT_REMOTE_WORKFLOW: REMOTE_WORKFLOW, COPILOT_COMMENT_SELF_WORKFLOW: SELF_WORKFLOW } = require('../src/domain/copilot_comment_workflow.ts'); +const SELF_ACTION = '$/'; +const SECRET_NAMES = ['PAT', 'OPENCODE_API_KEY', 'OPENAI_API_KEY', 'ANTHROPIC_API_KEY', 'GOOGLE_API_KEY', 'OPENROUTER_API_KEY', 'CURSOR_API_KEY', 'CODEX_API_KEY']; +const BINDINGS = require('../src/infrastructure/copilot_comment_inputs.json'); +const expr = value => '${{ ' + value + ' }}'; function phaseSteps(action, inputAlias = 'copilot-inputs', id = 'copilot') { const steps = []; @@ -38,26 +42,62 @@ function renderSteps(action, alias = 'copilot-inputs', id = 'copilot') { .split('\n').map(line => line ? ` ${line}` : '').join('\n'); } -function generate(file) { - let text = fs.readFileSync(file, 'utf8').split(MARKER)[0].trimEnd() + '\n'; - const action = file.startsWith('setup/') ? 'vypdev/copilot@v3' : SOURCE_ACTION; - if (!file.startsWith('setup/')) { - text = text.replace(' - uses: ./\n', ` - name: Snapshot the Copilot runtime before candidate changes\n id: prepare_native_runtime\n run: node scripts/prepare-native-source-action.cjs\n shell: bash\n\n - uses: ${SOURCE_ACTION}\n`); - if (!text.includes(' COPILOT_NATIVE_RUNTIME_CACHE:')) text = text.replace(' COPILOT_NATIVE_PHASE: prepare\n', ' COPILOT_NATIVE_PHASE: prepare\n COPILOT_NATIVE_RUNTIME_CACHE: ${{ steps.prepare_native_runtime.outputs.path }}\n'); +function commentWorkflow(file, source = false) { + const pr = path.basename(file) === CALLBACKS[1]; + return { + name: `Copilot - ${pr ? 'Pull Request' : 'Issue'} Comment`, + on: { [pr ? 'pull_request_review_comment' : 'issue_comment']: { types: ['created', 'edited'] } }, + jobs: { [pr ? 'copilot-pull-requests' : 'copilot-issues']: { + if: expr(pr ? "(vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN) && github.event.pull_request.head.repo.full_name == github.repository" : "vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN"), + uses: source ? SELF_WORKFLOW : REMOTE_WORKFLOW, + permissions: { checks: 'write', contents: 'read' }, + with: { 'runs-on': JSON.stringify(source ? ['self-hosted', 'codex', 'Linux'] : 'ubuntu-latest'), + ...(source ? { 'issue-managed-branches': 'true', 'pre-branch-sdd': 'true', 'ai-ignore-files': 'build/*,specs/CATALOG.md', 'prepare-source-verification': true } : {}) }, + secrets: Object.fromEntries(SECRET_NAMES.map(name => [name, expr(`secrets.${name}`)])), + } }, + }; +} + +function runtimeWorkflow() { + const inputs = { ...BINDINGS, token: expr('secrets.PAT') }; + for (const key of ['issue-managed-branches', 'pre-branch-sdd', 'ai-ignore-files']) { + inputs[key] = BINDINGS[key].replace('${{ ', '${{ inputs.' + key + ' || '); + } + const initial = { name: 'Run Copilot', id: 'copilot', uses: SELF_ACTION, with: inputs, + env: { COPILOT_NATIVE_PHASE: 'prepare', + ...Object.fromEntries(['PROVIDER', 'MODEL_PROVIDER', 'MODEL', 'EFFORT', 'EXECUTABLE'].map(name => ['AGENT_' + name, expr('vars.AGENT_' + name + (name === 'PROVIDER' ? " || 'codex'" : name === 'MODEL_PROVIDER' ? " || 'openai'" : ''))])), + AGENT_ALLOWED_MODEL_PROVIDERS: expr("vars.AGENT_ALLOWED_MODEL_PROVIDERS || 'openai'"), + AGENT_ALLOWED_MODELS: expr("vars.AGENT_ALLOWED_MODELS || 'openai/gpt-6-luna'"), + ...Object.fromEntries(SECRET_NAMES.filter(name => name !== 'PAT').map(name => [name, expr('secrets.' + name)])), + COPILOT_EVIDENCE_TOKEN: expr('github.token') } }; + initial.env.CURSOR_API_KEY = expr("(vars.AGENT_PROVIDER == 'cursor' || vars.FINDINGS_PROVIDER == 'cursor' || vars.FIXER_PROVIDER == 'cursor' || vars.PLANNER_PROVIDER == 'cursor' || vars.REVIEWER_PROVIDER == 'cursor' || vars.TESTER_PROVIDER == 'cursor') && secrets.CURSOR_API_KEY || ''"); + const preparation = "env.COPILOT_PREPARE_VERIFICATION == 'true'"; + const steps = [ + { name: 'Checkout Repository', uses: 'actions/checkout@v5', with: { 'persist-credentials': false, 'fetch-depth': 0 } }, + { name: 'Prepare repository pnpm', if: preparation, uses: 'pnpm/action-setup@v5', with: { version: '10.12.4', standalone: false, dest: expr('runner.temp') + '/setup-pnpm-' + expr('github.run_id') + '-' + expr('github.run_attempt') + '-' + expr('github.job') } }, + { name: 'Prepare repository Node', if: preparation, uses: 'actions/setup-node@v7', with: { 'node-version': '24.x' } }, + { name: 'Install repository verification dependencies', if: preparation, run: 'pnpm install --frozen-lockfile --ignore-scripts', shell: 'bash' }, + initial, + ...phaseSteps(SELF_ACTION).map(step => ({ ...step, ...(step.with ? { with: inputs } : {}) })), + ]; + return { name: 'Copilot - Comment Runtime', on: { workflow_call: { + inputs: { 'runs-on': { description: 'JSON runner labels or group retained by setup.', type: 'string', default: '"ubuntu-latest"' }, + ...Object.fromEntries(['issue-managed-branches', 'pre-branch-sdd', 'ai-ignore-files'].map(key => [key, { description: `Optional ${key} override; otherwise use the caller repository Variable.`, type: 'string', default: '' }])), + 'prepare-source-verification': { description: 'Retain Copilot source-repository verification prerequisites; ignored in consumer repositories.', type: 'boolean', default: false } }, + secrets: Object.fromEntries(SECRET_NAMES.map(name => [name, { required: false }])) } }, + jobs: { copilot: { name: 'Copilot', + if: expr("(vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN) && (github.event_name == 'issue_comment' || (github.event_name == 'pull_request_review_comment' && github.event.pull_request.head.repo.full_name == github.repository))"), + 'runs-on': expr("fromJSON(inputs.runs-on)"), 'timeout-minutes': 120, + permissions: { checks: 'write', contents: 'read' }, + env: { COPILOT_PREPARE_VERIFICATION: expr("github.repository == 'vypdev/copilot' && inputs.prepare-source-verification && vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS != '' && ((contains(github.event.comment.body, '/copilot') && ((contains(github.event.comment.body, 'sync-branch') && !contains(github.event.comment.body, '--dry-run')) || contains(github.event.comment.body, 'implement') || contains(github.event.comment.body, 'fix') || contains(github.event.comment.body, 'remember'))) || (vars.COPILOT_BOT_LOGIN != '' && contains(github.event.comment.body, format('@{0}', vars.COPILOT_BOT_LOGIN)) && !contains(github.event.comment.body, '--dry-run')))" ) }, steps } } }; +} + +function generate() { + for (const directory of ['.github/workflows', 'setup/workflows']) for (const file of CALLBACKS) { + fs.writeFileSync(path.join(directory, file), '# Generated by scripts/generate-native-verification-workflows.cjs\n# Project runtimes: .copilot/verification-prerequisites.json\n# Dependencies: .github/actions/copilot-verification-setup/action.yml\n# https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites\n' + yaml.dump(commentWorkflow(file, directory.startsWith('.github')), { lineWidth: -1, noRefs: true })); } - const start = ` - uses: ${action}\n`; - text = text.replace(/(?: id: copilot\n)+/g, ''); - if (text.includes(start)) text = text.replace(start, ` - uses: ${action}\n id: copilot\n`); - text = text.replace(' with:\n debug:', ' with: &copilot-inputs\n debug:'); - // Distributed templates start with agent inputs rather than debug. - const index = text.indexOf(' id: copilot\n'); - const before = text.slice(0, index); - let operation = text.slice(index); - operation = operation.replace(' with:\n', ' with: &copilot-inputs\n'); - if (!operation.includes(' COPILOT_NATIVE_PHASE: prepare')) operation = operation.replace(' env:\n', ' env:\n COPILOT_NATIVE_PHASE: prepare\n'); - text = before + operation; - fs.writeFileSync(file, `${text}\n${MARKER}\n${renderSteps(action)} # copilot:native-verification:end\n`); + fs.writeFileSync(path.join('.github/workflows', RUNTIME), '# Generated by scripts/generate-native-verification-workflows.cjs\n' + yaml.dump(runtimeWorkflow(), { lineWidth: -1 })); } -if (require.main === module) for (const directory of ['.github/workflows', 'setup/workflows']) for (const file of CALLBACKS) generate(path.join(directory, file)); -module.exports = { MAX_REQUESTS, ACTION, SOURCE_ACTION, CALLBACKS, phaseSteps, renderSteps }; +if (require.main === module) generate(); +module.exports = { MAX_REQUESTS, ACTION, SOURCE_ACTION, CALLBACKS, RUNTIME, SELF_ACTION, REMOTE_WORKFLOW, SELF_WORKFLOW, SECRET_NAMES, BINDINGS, phaseSteps, renderSteps, commentWorkflow, runtimeWorkflow, generate }; diff --git a/scripts/validate-comment-workflows.cjs b/scripts/validate-comment-workflows.cjs new file mode 100644 index 000000000..e40c8dfd5 --- /dev/null +++ b/scripts/validate-comment-workflows.cjs @@ -0,0 +1,33 @@ +const path = require('node:path'); +const { isDeepStrictEqual } = require('node:util'); +const contract = require('./generate-native-verification-workflows.cjs'); +const { copilotCommentRunner, isCopilotCommentRunner } = require('../src/domain/copilot_comment_workflow.ts'); + +function assertCommentWorkflowCaller(file, workflow) { + const source = !file.replaceAll(path.sep, '/').includes('/setup/workflows/'); + const expected = contract.commentWorkflow(path.basename(file), source); + const expectedJob = Object.values(expected.jobs)[0]; + const actualJob = Object.values(workflow.jobs ?? {})[0]; + let route; + try { route = copilotCommentRunner(actualJob); } catch { /* Fixed contract error below. */ } + if (!isCopilotCommentRunner(route)) throw new Error(`${file} native comment runner must be reviewed literal JSON.`); + if (source) { + const labels = typeof route === 'string' || Array.isArray(route) ? route : route.labels; + if (!Array.isArray(labels) || !['self-hosted', 'codex'].every(label => labels.includes(label))) throw new Error(`${file} native source comment caller must retain its self-hosted codex role.`); + } + expectedJob.with['runs-on'] = actualJob.with['runs-on']; + if (actualJob?.if !== expectedJob.if) { + throw new Error(`${file} native comment caller must keep its required bot actor and same-repository PR gate.`); + } + if (!isDeepStrictEqual(workflow, expected)) { + throw new Error(`${file} must pass consistent policy to the native comment coordinator, retaining only its event, bot/fork gate, reviewed runner, scoped Secrets and least-privilege permissions.`); + } +} + +function assertCommentWorkflowRuntime(file, workflow) { + if (!isDeepStrictEqual(workflow, contract.runtimeWorkflow())) { + throw new Error(`${file} must retain the canonical native comment runtime: same-commit Action, input bindings, isolated setup/continue/finish steps, timeout and cleanup.`); + } +} + +module.exports = { assertCommentWorkflowCaller, assertCommentWorkflowRuntime }; diff --git a/scripts/validate-workflow-contract.cjs b/scripts/validate-workflow-contract.cjs index 93bd54194..8bcae2918 100644 --- a/scripts/validate-workflow-contract.cjs +++ b/scripts/validate-workflow-contract.cjs @@ -3,6 +3,8 @@ const { readFileSync, readdirSync } = require('node:fs'); const path = require('node:path'); const yaml = require('js-yaml'); +const commentContract = require('./generate-native-verification-workflows.cjs'); +const { assertCommentWorkflowCaller, assertCommentWorkflowRuntime } = require('./validate-comment-workflows.cjs'); const repositoryRoot = path.resolve(__dirname, '..'); const workflowDirectories = [ @@ -113,6 +115,7 @@ const AGENT_ROLE_INPUTS = Object.freeze(Object.fromEntries( ]]), )); const WORKFLOW_AGENT_ROLES = Object.freeze({ + 'copilot_comment_runtime.yml': ['findings', 'fixer', 'planner', 'reviewer', 'tester'], 'copilot_issue.yml': ['planner'], 'copilot_pull_request.yml': ['planner', 'reviewer'], 'copilot_pull_request_review_state.yml': ['planner', 'reviewer'], @@ -145,6 +148,7 @@ function relativeWorkflow(file) { } function expectedCopilotAction(relativeFile) { + if (path.basename(relativeFile) === commentContract.RUNTIME) return commentContract.SELF_ACTION; if (relativeFile.startsWith('setup/workflows/')) return DISTRIBUTED_COPILOT_ACTION; const native = require('./generate-native-verification-workflows.cjs'); return native.CALLBACKS.includes(path.basename(relativeFile)) ? native.SOURCE_ACTION : './'; @@ -152,7 +156,7 @@ function expectedCopilotAction(relativeFile) { function isCopilotAction(step) { return typeof step?.uses === 'string' - && (step.uses === './' || step.uses === './../.copilot-native-runtime' || /(?:^|\/)copilot@/.test(step.uses)); + && (step.uses === '$/' || step.uses === './' || step.uses === './../.copilot-native-runtime' || /(?:^|\/)copilot@/.test(step.uses)); } function shouldPersistCheckoutCredentials(relativeFile, jobId) { @@ -183,7 +187,7 @@ function assertMajorActionReferences(file, workflow) { } continue; } - if (uses.startsWith('./') || uses.startsWith('docker://')) continue; + if (uses.startsWith('./') || uses.startsWith('$/') || uses.startsWith('docker://')) continue; if (!MAJOR_ACTION_REFERENCE.test(uses)) { throw new Error(`${relativeFile} job ${jobId} action ${uses} must use a major version tag such as owner/action@v1.`); } @@ -340,6 +344,8 @@ function assertPlatformHistoryCheckout(relativeFile, job) { function assertRunner(file, workflow) { const relativeFile = relativeWorkflow(file); + if (path.basename(file) === commentContract.RUNTIME) return assertCommentWorkflowRuntime(file, workflow); + if (commentContract.CALLBACKS.includes(path.basename(file))) return assertCommentWorkflowCaller(file, workflow); if (relativeFile === '.github/workflows/setup_platform_smoke.yml') { const jobIds = Object.keys(workflow.jobs ?? {}).sort(); if (JSON.stringify(jobIds) !== JSON.stringify(['setup-platform-smoke', 'setup-self-hosted-codex-smoke', 'upload-windows-coverage', 'windows-startup-probe'])) { @@ -565,7 +571,7 @@ function assertAgentInstallationPrerequisites(file, workflow) { for (const [jobId, job] of Object.entries(workflow.jobs ?? {})) { const steps = job.steps ?? []; for (const step of steps) { - const repositoryVerificationStep = ['.github/workflows/copilot_issue_comment.yml', '.github/workflows/copilot_pull_request_comment.yml'].includes(relativeFile) + const repositoryVerificationStep = ['.github/workflows/copilot_issue_comment.yml', '.github/workflows/copilot_pull_request_comment.yml', '.github/workflows/copilot_comment_runtime.yml'].includes(relativeFile) && step.if === "env.COPILOT_PREPARE_VERIFICATION == 'true'" && ((step.name === 'Prepare repository Node' && step.uses === 'actions/setup-node@v7' && step.with?.['node-version'] === '24.x') || (step.name === 'Prepare repository pnpm' && step.uses === 'pnpm/action-setup@v5' && step.with?.version === '10.12.4') @@ -596,7 +602,7 @@ function assertAgentWorkflowPermissions(file, workflow) { const relativeFile = relativeWorkflow(file); if (!WORKFLOW_AGENT_ROLES[path.basename(file)]) return; const reviewEvidenceWorkflow = ['copilot_pull_request.yml', 'copilot_pull_request_review_state.yml', - 'copilot_issue_comment.yml', 'copilot_pull_request_comment.yml'].includes(path.basename(file)); + 'copilot_issue_comment.yml', 'copilot_pull_request_comment.yml', 'copilot_comment_runtime.yml'].includes(path.basename(file)); const expectedPermissions = reviewEvidenceWorkflow ? { checks: 'write', contents: 'read' } : { contents: 'read' }; @@ -609,6 +615,10 @@ function assertAgentWorkflowPermissions(file, workflow) { || expectedKeys.some(key => permissions[key] !== expectedPermissions[key])) { throw new Error(`${relativeFile} job ${jobId} must grant GITHUB_TOKEN exactly ${expectedKeys.map(key => `${key}: ${expectedPermissions[key]}`).join(', ')}; mutations use the explicit PAT.`); } + if (commentContract.CALLBACKS.includes(path.basename(file)) && job.uses) { + assertCommentWorkflowCaller(file, workflow); + continue; + } if (reviewEvidenceWorkflow && !(job.steps ?? []).some(step => isCopilotAction(step) && step?.env?.COPILOT_EVIDENCE_TOKEN === '${{ github.token }}')) { throw new Error(`${relativeFile} job ${jobId} must scope COPILOT_EVIDENCE_TOKEN to the Action step for exact-head review Checks.`); @@ -1306,6 +1316,7 @@ function assertQueueWorkflow(file, workflow) { if (BOT_GATED_WORKFLOW_FILES.has(manifest.file) && queueJob.if !== expectedBotGate) { throw new Error(`${relativeFile} queue job ${manifest.jobId} must use the required bot actor${FORK_GATED_WORKFLOW_FILES.has(manifest.file) ? ' and same-repository PR' : ''} gate.`); } + if (commentContract.CALLBACKS.includes(manifest.file)) return assertCommentWorkflowCaller(file, workflow); if (typeof queueJob['timeout-minutes'] !== 'number' || queueJob['timeout-minutes'] < MIN_QUEUE_JOB_TIMEOUT_MINUTES) { throw new Error(`${relativeFile} queue job ${manifest.jobId} must have timeout-minutes >= ${MIN_QUEUE_JOB_TIMEOUT_MINUTES}.`); @@ -1386,6 +1397,7 @@ function assertIssueWorkflowProfileInput(file, workflow) { function assertIssueBranchConfigurationInputs(file, workflow) { if (!WORKFLOW_AGENT_ROLES[path.basename(file)]) return; + if (commentContract.CALLBACKS.includes(path.basename(file))) return assertCommentWorkflowCaller(file, workflow); const relativeFile = relativeWorkflow(file); const distributed = relativeFile.startsWith('setup/workflows/'); const branches = JSON.parse(readFileSync(path.join(repositoryRoot, '.copilot/repository-profile.json'), 'utf8')).branches; @@ -1410,27 +1422,27 @@ function assertIssueBranchConfigurationInputs(file, workflow) { function assertNativeVerificationWorkflow(file, workflow) { const contract = require('./generate-native-verification-workflows.cjs'); - if (!contract.CALLBACKS.includes(path.basename(file))) return; - const relativeFile = relativeWorkflow(file); - const action = expectedCopilotAction(relativeFile); - const jobs = Object.values(workflow.jobs ?? {}).filter(job => (job.steps ?? []).some(step => step.id === 'copilot')); - if (jobs.length !== 1) throw new Error(`${relativeFile} must have exactly one native verification operation.`); - const steps = jobs[0].steps; - const start = steps.findIndex(step => step.id === 'copilot'); - const original = steps[start]; - if (!relativeFile.startsWith('setup/workflows/')) { - const snapshot = steps[start - 1]; - if (snapshot?.id !== 'prepare_native_runtime' || snapshot.run !== 'node scripts/prepare-native-source-action.cjs' - || original.env?.COPILOT_NATIVE_RUNTIME_CACHE !== '${{ steps.prepare_native_runtime.outputs.path }}') throw new Error(`${relativeFile} must snapshot its Action runtime before candidate changes.`); - } - if (original.uses !== action || original.env?.COPILOT_NATIVE_PHASE !== 'prepare') throw new Error(`${relativeFile} must prepare the admitted native operation.`); - const expected = contract.phaseSteps(action).map(step => ({ ...step, ...(step.with ? { with: original.with } : {}) })); - const actual = steps.slice(start + 1); - if (JSON.stringify(actual) !== JSON.stringify(expected)) throw new Error(`${relativeFile} must retain the exact bounded native setup/continuation contract, runtime-only environment, timeout and completion cleanup.`); + if (path.basename(file) === contract.RUNTIME) return assertCommentWorkflowRuntime(file, workflow); + if (contract.CALLBACKS.includes(path.basename(file))) return assertCommentWorkflowCaller(file, workflow); + } function validateWorkflow(file, workflow) { if (!workflow || typeof workflow !== 'object') throw new Error('workflow document is empty.'); + if (commentContract.CALLBACKS.includes(path.basename(file))) { + assertCommentWorkflowCaller(file, workflow); + assertDirectEventTriggers(file, workflow); + return; + } + if (path.basename(file) === commentContract.RUNTIME) { + assertCommentWorkflowRuntime(file, workflow); + assertCopilotActionInputs(file, workflow); + assertNoJobLevelSecrets(file, workflow); + assertAgentWorkflowPermissions(file, workflow); + assertAgentInputs(file, workflow); + assertRepositoryLocaleInputs(file, workflow); + return; + } assertNativeVerificationWorkflow(file, workflow); assertManualRepoWiseWorkflow(file, workflow); assertDirectEventTriggers(file, workflow); diff --git a/setup/workflows/copilot_issue_comment.yml b/setup/workflows/copilot_issue_comment.yml index ea8c42d0a..dd360d03e 100644 --- a/setup/workflows/copilot_issue_comment.yml +++ b/setup/workflows/copilot_issue_comment.yml @@ -1,692 +1,28 @@ +# Generated by scripts/generate-native-verification-workflows.cjs +# Project runtimes: .copilot/verification-prerequisites.json +# Dependencies: .github/actions/copilot-verification-setup/action.yml +# https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites name: Copilot - Issue Comment - -on: +'on': issue_comment: - types: [created, edited] - + types: + - created + - edited jobs: copilot-issues: if: ${{ vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN }} - name: Copilot - Issue Comment - runs-on: ubuntu-latest - timeout-minutes: 120 + uses: vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3 permissions: checks: write contents: read - steps: - - name: Checkout Repository - uses: actions/checkout@v5 - with: - persist-credentials: false - fetch-depth: 0 - - # Before Copilot, provision project runtimes/dependencies in this same job when - # repository verification is configured. A separate CI job does not prepare it. - # Declare reviewed versions in .copilot/verification-prerequisites.json. - # Optional trusted-main setup: VERIFICATION_SETUP=true and .github/actions/copilot-verification-setup/action.yml. - # https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites - - uses: vypdev/copilot@v3 - id: copilot - with: &copilot-inputs - repository-locale: ${{ vars.REPOSITORY_LOCALE || 'en-US' }} - issues-locale: ${{ vars.ISSUES_LOCALE || '' }} - pull-requests-locale: ${{ vars.PULL_REQUESTS_LOCALE || '' }} - ai-ignore-files: ${{ vars.AI_IGNORE_FILES || 'build/*' }} - debug: ${{ vars.DEBUG }} - main-branch: ${{ vars.MAIN_BRANCH || 'master' }} - development-branch: ${{ vars.DEVELOPMENT_BRANCH || 'develop' }} - feature-tree: ${{ vars.FEATURE_TREE || 'feature' }} - bugfix-tree: ${{ vars.BUGFIX_TREE || 'bugfix' }} - hotfix-tree: ${{ vars.HOTFIX_TREE || 'hotfix' }} - release-tree: ${{ vars.RELEASE_TREE || 'release' }} - docs-tree: ${{ vars.DOCS_TREE || 'docs' }} - chore-tree: ${{ vars.CHORE_TREE || 'chore' }} - issue-managed-branches: ${{ vars.ISSUE_MANAGED_BRANCHES || 'true' }} - pre-branch-sdd: ${{ vars.PRE_BRANCH_SDD || 'false' }} - verification-setup: ${{ vars.VERIFICATION_SETUP || 'false' }} - issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} - reopen-issue-on-push: ${{ vars.REOPEN_ISSUE_ON_PUSH || 'true' }} - desired-assignees-count: ${{ vars.DESIRED_ASSIGNEES_COUNT || '1' }} - desired-reviewers-count: ${{ vars.DESIRED_REVIEWERS_COUNT || '1' }} - commit-prefix-transforms: ${{ vars.COMMIT_PREFIX_TRANSFORMS || 'replace-slash' }} - ai-pull-request-description-mode: ${{ vars.AI_PULL_REQUEST_DESCRIPTION_MODE || 'replace' }} - ai-members-only: ${{ vars.AI_MEMBERS_ONLY || 'false' }} - ai-include-reasoning: ${{ vars.AI_INCLUDE_REASONING || 'false' }} - bugbot-severity: ${{ vars.BUGBOT_SEVERITY || 'low' }} - bugbot-comment-limit: ${{ vars.BUGBOT_COMMENT_LIMIT || '20' }} - bugbot-fix-verify-commands: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }} - bugbot-dry-run: ${{ vars.BUGBOT_DRY_RUN || 'false' }} - bugbot-effort: ${{ vars.BUGBOT_EFFORT || 'smart' }} - bugbot-review-drafts: ${{ vars.BUGBOT_REVIEW_DRAFTS || 'false' }} - bugbot-trace-rules: ${{ vars.BUGBOT_TRACE_RULES || 'false' }} - bugbot-suggested-changes: ${{ vars.BUGBOT_SUGGESTED_CHANGES || 'true' }} - bugbot-telemetry: ${{ vars.BUGBOT_TELEMETRY || 'true' }} - bugbot-fail-on-unresolved: ${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || 'false' }} - bugbot-organization-rules: ${{ vars.BUGBOT_ORGANIZATION_RULES }} - project-column-issue-created: ${{ vars.PROJECT_COLUMN_ISSUE_CREATED || 'Todo' }} - project-column-pull-request-created: ${{ vars.PROJECT_COLUMN_PULL_REQUEST_CREATED || 'In Progress' }} - project-column-issue-in-progress: ${{ vars.PROJECT_COLUMN_ISSUE_IN_PROGRESS || 'In Progress' }} - project-column-pull-request-in-progress: ${{ vars.PROJECT_COLUMN_PULL_REQUEST_IN_PROGRESS || 'In Progress' }} - agent-provider: ${{ vars.AGENT_PROVIDER || 'codex' }} - agent-model-provider: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - agent-model: ${{ vars.AGENT_MODEL || 'gpt-6-luna' }} - agent-effort: ${{ vars.AGENT_EFFORT }} - agent-executable: ${{ vars.AGENT_EXECUTABLE }} - findings-provider: ${{ vars.FINDINGS_PROVIDER }} - findings-model-provider: ${{ vars.FINDINGS_MODEL_PROVIDER }} - findings-model: ${{ vars.FINDINGS_MODEL }} - findings-effort: ${{ vars.FINDINGS_EFFORT }} - findings-executable: ${{ vars.FINDINGS_EXECUTABLE }} - fixer-provider: ${{ vars.FIXER_PROVIDER }} - fixer-model-provider: ${{ vars.FIXER_MODEL_PROVIDER }} - fixer-model: ${{ vars.FIXER_MODEL }} - fixer-effort: ${{ vars.FIXER_EFFORT }} - fixer-executable: ${{ vars.FIXER_EXECUTABLE }} - planner-provider: ${{ vars.PLANNER_PROVIDER }} - planner-model-provider: ${{ vars.PLANNER_MODEL_PROVIDER }} - planner-model: ${{ vars.PLANNER_MODEL }} - planner-effort: ${{ vars.PLANNER_EFFORT }} - planner-executable: ${{ vars.PLANNER_EXECUTABLE }} - reviewer-provider: ${{ vars.REVIEWER_PROVIDER }} - reviewer-model-provider: ${{ vars.REVIEWER_MODEL_PROVIDER }} - reviewer-model: ${{ vars.REVIEWER_MODEL }} - reviewer-effort: ${{ vars.REVIEWER_EFFORT }} - reviewer-executable: ${{ vars.REVIEWER_EXECUTABLE }} - tester-provider: ${{ vars.TESTER_PROVIDER }} - tester-model-provider: ${{ vars.TESTER_MODEL_PROVIDER }} - tester-model: ${{ vars.TESTER_MODEL }} - tester-effort: ${{ vars.TESTER_EFFORT }} - tester-executable: ${{ vars.TESTER_EXECUTABLE }} - project-ids: ${{ vars.PROJECT_IDS }} - token: ${{ secrets.PAT }} - env: - COPILOT_NATIVE_PHASE: prepare - AGENT_PROVIDER: ${{ vars.AGENT_PROVIDER || 'codex' }} - AGENT_MODEL_PROVIDER: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - AGENT_MODEL: ${{ vars.AGENT_MODEL }} - AGENT_EFFORT: ${{ vars.AGENT_EFFORT }} - AGENT_ALLOWED_MODEL_PROVIDERS: ${{ vars.AGENT_ALLOWED_MODEL_PROVIDERS || 'openai' }} - AGENT_ALLOWED_MODELS: ${{ vars.AGENT_ALLOWED_MODELS || 'openai/gpt-6-luna' }} - AGENT_EXECUTABLE: ${{ vars.AGENT_EXECUTABLE }} - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} - OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - CURSOR_API_KEY: ${{ (vars.AGENT_PROVIDER == 'cursor' || vars.FINDINGS_PROVIDER == 'cursor' || vars.FIXER_PROVIDER == 'cursor' || vars.PLANNER_PROVIDER == 'cursor' || vars.REVIEWER_PROVIDER == 'cursor' || vars.TESTER_PROVIDER == 'cursor') && secrets.CURSOR_API_KEY || '' }} - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} - COPILOT_EVIDENCE_TOKEN: ${{ github.token }} - - # copilot:native-verification:start - - name: Prepare repository verification 1 - id: verification_setup_1 - if: ${{ !cancelled() && steps.copilot.outcome == 'success' && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.copilot.outputs.verification-home }} - USERPROFILE: ${{ steps.copilot.outputs.verification-userprofile }} - APPDATA: ${{ steps.copilot.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.copilot.outputs.verification-localappdata }} - PATH: ${{ steps.copilot.outputs.verification-path }} - JAVA_HOME: ${{ steps.copilot.outputs.verification-java_home }} - TMP: ${{ steps.copilot.outputs.verification-tmp }} - TEMP: ${{ steps.copilot.outputs.verification-temp }} - TMPDIR: ${{ steps.copilot.outputs.verification-tmpdir }} - - name: Continue repository verification 1 - id: verification_continue_1 - if: ${{ always() && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.copilot.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_1.outcome }} - - name: Prepare repository verification 2 - id: verification_setup_2 - if: ${{ !cancelled() && steps.verification_continue_1.outcome == 'success' && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_1.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_1.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_1.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_1.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_1.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_1.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_1.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_1.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_1.outputs.verification-tmpdir }} - - name: Continue repository verification 2 - id: verification_continue_2 - if: ${{ always() && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_1.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_2.outcome }} - - name: Prepare repository verification 3 - id: verification_setup_3 - if: ${{ !cancelled() && steps.verification_continue_2.outcome == 'success' && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_2.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_2.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_2.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_2.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_2.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_2.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_2.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_2.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_2.outputs.verification-tmpdir }} - - name: Continue repository verification 3 - id: verification_continue_3 - if: ${{ always() && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_2.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_3.outcome }} - - name: Prepare repository verification 4 - id: verification_setup_4 - if: ${{ !cancelled() && steps.verification_continue_3.outcome == 'success' && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_3.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_3.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_3.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_3.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_3.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_3.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_3.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_3.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_3.outputs.verification-tmpdir }} - - name: Continue repository verification 4 - id: verification_continue_4 - if: ${{ always() && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_3.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_4.outcome }} - - name: Prepare repository verification 5 - id: verification_setup_5 - if: ${{ !cancelled() && steps.verification_continue_4.outcome == 'success' && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_4.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_4.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_4.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_4.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_4.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_4.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_4.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_4.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_4.outputs.verification-tmpdir }} - - name: Continue repository verification 5 - id: verification_continue_5 - if: ${{ always() && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_4.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_5.outcome }} - - name: Prepare repository verification 6 - id: verification_setup_6 - if: ${{ !cancelled() && steps.verification_continue_5.outcome == 'success' && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_5.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_5.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_5.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_5.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_5.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_5.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_5.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_5.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_5.outputs.verification-tmpdir }} - - name: Continue repository verification 6 - id: verification_continue_6 - if: ${{ always() && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_5.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_6.outcome }} - - name: Prepare repository verification 7 - id: verification_setup_7 - if: ${{ !cancelled() && steps.verification_continue_6.outcome == 'success' && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_6.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_6.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_6.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_6.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_6.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_6.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_6.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_6.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_6.outputs.verification-tmpdir }} - - name: Continue repository verification 7 - id: verification_continue_7 - if: ${{ always() && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_6.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_7.outcome }} - - name: Prepare repository verification 8 - id: verification_setup_8 - if: ${{ !cancelled() && steps.verification_continue_7.outcome == 'success' && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_7.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_7.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_7.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_7.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_7.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_7.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_7.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_7.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_7.outputs.verification-tmpdir }} - - name: Continue repository verification 8 - id: verification_continue_8 - if: ${{ always() && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_7.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_8.outcome }} - - name: Prepare repository verification 9 - id: verification_setup_9 - if: ${{ !cancelled() && steps.verification_continue_8.outcome == 'success' && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_8.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_8.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_8.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_8.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_8.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_8.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_8.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_8.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_8.outputs.verification-tmpdir }} - - name: Continue repository verification 9 - id: verification_continue_9 - if: ${{ always() && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_8.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_9.outcome }} - - name: Prepare repository verification 10 - id: verification_setup_10 - if: ${{ !cancelled() && steps.verification_continue_9.outcome == 'success' && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_9.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_9.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_9.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_9.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_9.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_9.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_9.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_9.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_9.outputs.verification-tmpdir }} - - name: Continue repository verification 10 - id: verification_continue_10 - if: ${{ always() && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_9.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_10.outcome }} - - name: Prepare repository verification 11 - id: verification_setup_11 - if: ${{ !cancelled() && steps.verification_continue_10.outcome == 'success' && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_10.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_10.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_10.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_10.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_10.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_10.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_10.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_10.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_10.outputs.verification-tmpdir }} - - name: Continue repository verification 11 - id: verification_continue_11 - if: ${{ always() && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_10.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_11.outcome }} - - name: Prepare repository verification 12 - id: verification_setup_12 - if: ${{ !cancelled() && steps.verification_continue_11.outcome == 'success' && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_11.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_11.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_11.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_11.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_11.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_11.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_11.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_11.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_11.outputs.verification-tmpdir }} - - name: Continue repository verification 12 - id: verification_continue_12 - if: ${{ always() && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_11.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_12.outcome }} - - name: Prepare repository verification 13 - id: verification_setup_13 - if: ${{ !cancelled() && steps.verification_continue_12.outcome == 'success' && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_12.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_12.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_12.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_12.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_12.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_12.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_12.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_12.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_12.outputs.verification-tmpdir }} - - name: Continue repository verification 13 - id: verification_continue_13 - if: ${{ always() && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_12.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_13.outcome }} - - name: Prepare repository verification 14 - id: verification_setup_14 - if: ${{ !cancelled() && steps.verification_continue_13.outcome == 'success' && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_13.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_13.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_13.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_13.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_13.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_13.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_13.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_13.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_13.outputs.verification-tmpdir }} - - name: Continue repository verification 14 - id: verification_continue_14 - if: ${{ always() && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_13.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_14.outcome }} - - name: Prepare repository verification 15 - id: verification_setup_15 - if: ${{ !cancelled() && steps.verification_continue_14.outcome == 'success' && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_14.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_14.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_14.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_14.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_14.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_14.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_14.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_14.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_14.outputs.verification-tmpdir }} - - name: Continue repository verification 15 - id: verification_continue_15 - if: ${{ always() && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_14.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_15.outcome }} - - name: Prepare repository verification 16 - id: verification_setup_16 - if: ${{ !cancelled() && steps.verification_continue_15.outcome == 'success' && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_15.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_15.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_15.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_15.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_15.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_15.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_15.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_15.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_15.outputs.verification-tmpdir }} - - name: Continue repository verification 16 - id: verification_continue_16 - if: ${{ always() && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_15.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_16.outcome }} - - name: Prepare repository verification 17 - id: verification_setup_17 - if: ${{ !cancelled() && steps.verification_continue_16.outcome == 'success' && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_16.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_16.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_16.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_16.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_16.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_16.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_16.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_16.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_16.outputs.verification-tmpdir }} - - name: Continue repository verification 17 - id: verification_continue_17 - if: ${{ always() && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_16.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_17.outcome }} - - name: Prepare repository verification 18 - id: verification_setup_18 - if: ${{ !cancelled() && steps.verification_continue_17.outcome == 'success' && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_17.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_17.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_17.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_17.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_17.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_17.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_17.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_17.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_17.outputs.verification-tmpdir }} - - name: Continue repository verification 18 - id: verification_continue_18 - if: ${{ always() && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_17.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_18.outcome }} - - name: Prepare repository verification 19 - id: verification_setup_19 - if: ${{ !cancelled() && steps.verification_continue_18.outcome == 'success' && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_18.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_18.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_18.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_18.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_18.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_18.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_18.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_18.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_18.outputs.verification-tmpdir }} - - name: Continue repository verification 19 - id: verification_continue_19 - if: ${{ always() && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_18.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_19.outcome }} - - name: Prepare repository verification 20 - id: verification_setup_20 - if: ${{ !cancelled() && steps.verification_continue_19.outcome == 'success' && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_19.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_19.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_19.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_19.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_19.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_19.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_19.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_19.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_19.outputs.verification-tmpdir }} - - name: Continue repository verification 20 - id: verification_continue_20 - if: ${{ always() && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_19.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_20.outcome }} - - name: Complete repository verification - id: verification_complete - if: ${{ always() && steps.copilot.outputs.verification-ticket != '' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: finish - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - # copilot:native-verification:end + with: + runs-on: '"ubuntu-latest"' + secrets: + PAT: ${{ secrets.PAT }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} + CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} diff --git a/setup/workflows/copilot_pull_request_comment.yml b/setup/workflows/copilot_pull_request_comment.yml index c5e05f433..455fa34a6 100644 --- a/setup/workflows/copilot_pull_request_comment.yml +++ b/setup/workflows/copilot_pull_request_comment.yml @@ -1,692 +1,28 @@ +# Generated by scripts/generate-native-verification-workflows.cjs +# Project runtimes: .copilot/verification-prerequisites.json +# Dependencies: .github/actions/copilot-verification-setup/action.yml +# https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites name: Copilot - Pull Request Comment - -on: +'on': pull_request_review_comment: - types: [created, edited] - + types: + - created + - edited jobs: copilot-pull-requests: if: ${{ (vars.COPILOT_BOT_LOGIN == '' || github.actor != vars.COPILOT_BOT_LOGIN) && github.event.pull_request.head.repo.full_name == github.repository }} - name: Copilot - Pull Request Comment - runs-on: ubuntu-latest - timeout-minutes: 120 + uses: vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3 permissions: checks: write contents: read - steps: - - name: Checkout Repository - uses: actions/checkout@v5 - with: - persist-credentials: false - fetch-depth: 0 - - # Before Copilot, provision project runtimes/dependencies in this same job when - # repository verification is configured. A separate CI job does not prepare it. - # Declare reviewed versions in .copilot/verification-prerequisites.json. - # Optional trusted-main setup: VERIFICATION_SETUP=true and .github/actions/copilot-verification-setup/action.yml. - # https://docs.page/vypdev/copilot/security-operations/operations/verification#repository-verification-prerequisites - - uses: vypdev/copilot@v3 - id: copilot - with: &copilot-inputs - repository-locale: ${{ vars.REPOSITORY_LOCALE || 'en-US' }} - issues-locale: ${{ vars.ISSUES_LOCALE || '' }} - pull-requests-locale: ${{ vars.PULL_REQUESTS_LOCALE || '' }} - issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }} - ai-ignore-files: ${{ vars.AI_IGNORE_FILES || 'build/*' }} - debug: ${{ vars.DEBUG }} - main-branch: ${{ vars.MAIN_BRANCH || 'master' }} - development-branch: ${{ vars.DEVELOPMENT_BRANCH || 'develop' }} - feature-tree: ${{ vars.FEATURE_TREE || 'feature' }} - bugfix-tree: ${{ vars.BUGFIX_TREE || 'bugfix' }} - hotfix-tree: ${{ vars.HOTFIX_TREE || 'hotfix' }} - release-tree: ${{ vars.RELEASE_TREE || 'release' }} - docs-tree: ${{ vars.DOCS_TREE || 'docs' }} - chore-tree: ${{ vars.CHORE_TREE || 'chore' }} - issue-managed-branches: ${{ vars.ISSUE_MANAGED_BRANCHES || 'true' }} - pre-branch-sdd: ${{ vars.PRE_BRANCH_SDD || 'false' }} - verification-setup: ${{ vars.VERIFICATION_SETUP || 'false' }} - reopen-issue-on-push: ${{ vars.REOPEN_ISSUE_ON_PUSH || 'true' }} - desired-assignees-count: ${{ vars.DESIRED_ASSIGNEES_COUNT || '1' }} - desired-reviewers-count: ${{ vars.DESIRED_REVIEWERS_COUNT || '1' }} - commit-prefix-transforms: ${{ vars.COMMIT_PREFIX_TRANSFORMS || 'replace-slash' }} - ai-pull-request-description-mode: ${{ vars.AI_PULL_REQUEST_DESCRIPTION_MODE || 'replace' }} - ai-members-only: ${{ vars.AI_MEMBERS_ONLY || 'false' }} - ai-include-reasoning: ${{ vars.AI_INCLUDE_REASONING || 'false' }} - bugbot-severity: ${{ vars.BUGBOT_SEVERITY || 'low' }} - bugbot-comment-limit: ${{ vars.BUGBOT_COMMENT_LIMIT || '20' }} - bugbot-fix-verify-commands: ${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }} - bugbot-dry-run: ${{ vars.BUGBOT_DRY_RUN || 'false' }} - bugbot-effort: ${{ vars.BUGBOT_EFFORT || 'smart' }} - bugbot-review-drafts: ${{ vars.BUGBOT_REVIEW_DRAFTS || 'false' }} - bugbot-trace-rules: ${{ vars.BUGBOT_TRACE_RULES || 'false' }} - bugbot-suggested-changes: ${{ vars.BUGBOT_SUGGESTED_CHANGES || 'true' }} - bugbot-telemetry: ${{ vars.BUGBOT_TELEMETRY || 'true' }} - bugbot-fail-on-unresolved: ${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || 'false' }} - bugbot-organization-rules: ${{ vars.BUGBOT_ORGANIZATION_RULES }} - project-column-issue-created: ${{ vars.PROJECT_COLUMN_ISSUE_CREATED || 'Todo' }} - project-column-pull-request-created: ${{ vars.PROJECT_COLUMN_PULL_REQUEST_CREATED || 'In Progress' }} - project-column-issue-in-progress: ${{ vars.PROJECT_COLUMN_ISSUE_IN_PROGRESS || 'In Progress' }} - project-column-pull-request-in-progress: ${{ vars.PROJECT_COLUMN_PULL_REQUEST_IN_PROGRESS || 'In Progress' }} - agent-provider: ${{ vars.AGENT_PROVIDER || 'codex' }} - agent-model-provider: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - agent-model: ${{ vars.AGENT_MODEL || 'gpt-6-luna' }} - agent-effort: ${{ vars.AGENT_EFFORT }} - agent-executable: ${{ vars.AGENT_EXECUTABLE }} - findings-provider: ${{ vars.FINDINGS_PROVIDER }} - findings-model-provider: ${{ vars.FINDINGS_MODEL_PROVIDER }} - findings-model: ${{ vars.FINDINGS_MODEL }} - findings-effort: ${{ vars.FINDINGS_EFFORT }} - findings-executable: ${{ vars.FINDINGS_EXECUTABLE }} - fixer-provider: ${{ vars.FIXER_PROVIDER }} - fixer-model-provider: ${{ vars.FIXER_MODEL_PROVIDER }} - fixer-model: ${{ vars.FIXER_MODEL }} - fixer-effort: ${{ vars.FIXER_EFFORT }} - fixer-executable: ${{ vars.FIXER_EXECUTABLE }} - reviewer-provider: ${{ vars.REVIEWER_PROVIDER }} - reviewer-model-provider: ${{ vars.REVIEWER_MODEL_PROVIDER }} - reviewer-model: ${{ vars.REVIEWER_MODEL }} - reviewer-effort: ${{ vars.REVIEWER_EFFORT }} - reviewer-executable: ${{ vars.REVIEWER_EXECUTABLE }} - planner-provider: ${{ vars.PLANNER_PROVIDER }} - planner-model-provider: ${{ vars.PLANNER_MODEL_PROVIDER }} - planner-model: ${{ vars.PLANNER_MODEL }} - planner-effort: ${{ vars.PLANNER_EFFORT }} - planner-executable: ${{ vars.PLANNER_EXECUTABLE }} - tester-provider: ${{ vars.TESTER_PROVIDER }} - tester-model-provider: ${{ vars.TESTER_MODEL_PROVIDER }} - tester-model: ${{ vars.TESTER_MODEL }} - tester-effort: ${{ vars.TESTER_EFFORT }} - tester-executable: ${{ vars.TESTER_EXECUTABLE }} - project-ids: ${{ vars.PROJECT_IDS }} - token: ${{ secrets.PAT }} - env: - COPILOT_NATIVE_PHASE: prepare - AGENT_PROVIDER: ${{ vars.AGENT_PROVIDER || 'codex' }} - AGENT_MODEL_PROVIDER: ${{ vars.AGENT_MODEL_PROVIDER || 'openai' }} - AGENT_MODEL: ${{ vars.AGENT_MODEL }} - AGENT_EFFORT: ${{ vars.AGENT_EFFORT }} - AGENT_ALLOWED_MODEL_PROVIDERS: ${{ vars.AGENT_ALLOWED_MODEL_PROVIDERS || 'openai' }} - AGENT_ALLOWED_MODELS: ${{ vars.AGENT_ALLOWED_MODELS || 'openai/gpt-6-luna' }} - AGENT_EXECUTABLE: ${{ vars.AGENT_EXECUTABLE }} - OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} - OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - CURSOR_API_KEY: ${{ (vars.AGENT_PROVIDER == 'cursor' || vars.FINDINGS_PROVIDER == 'cursor' || vars.FIXER_PROVIDER == 'cursor' || vars.PLANNER_PROVIDER == 'cursor' || vars.REVIEWER_PROVIDER == 'cursor' || vars.TESTER_PROVIDER == 'cursor') && secrets.CURSOR_API_KEY || '' }} - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} - COPILOT_EVIDENCE_TOKEN: ${{ github.token }} - - # copilot:native-verification:start - - name: Prepare repository verification 1 - id: verification_setup_1 - if: ${{ !cancelled() && steps.copilot.outcome == 'success' && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.copilot.outputs.verification-home }} - USERPROFILE: ${{ steps.copilot.outputs.verification-userprofile }} - APPDATA: ${{ steps.copilot.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.copilot.outputs.verification-localappdata }} - PATH: ${{ steps.copilot.outputs.verification-path }} - JAVA_HOME: ${{ steps.copilot.outputs.verification-java_home }} - TMP: ${{ steps.copilot.outputs.verification-tmp }} - TEMP: ${{ steps.copilot.outputs.verification-temp }} - TMPDIR: ${{ steps.copilot.outputs.verification-tmpdir }} - - name: Continue repository verification 1 - id: verification_continue_1 - if: ${{ always() && steps.copilot.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.copilot.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_1.outcome }} - - name: Prepare repository verification 2 - id: verification_setup_2 - if: ${{ !cancelled() && steps.verification_continue_1.outcome == 'success' && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_1.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_1.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_1.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_1.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_1.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_1.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_1.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_1.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_1.outputs.verification-tmpdir }} - - name: Continue repository verification 2 - id: verification_continue_2 - if: ${{ always() && steps.verification_continue_1.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_1.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_2.outcome }} - - name: Prepare repository verification 3 - id: verification_setup_3 - if: ${{ !cancelled() && steps.verification_continue_2.outcome == 'success' && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_2.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_2.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_2.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_2.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_2.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_2.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_2.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_2.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_2.outputs.verification-tmpdir }} - - name: Continue repository verification 3 - id: verification_continue_3 - if: ${{ always() && steps.verification_continue_2.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_2.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_3.outcome }} - - name: Prepare repository verification 4 - id: verification_setup_4 - if: ${{ !cancelled() && steps.verification_continue_3.outcome == 'success' && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_3.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_3.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_3.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_3.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_3.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_3.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_3.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_3.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_3.outputs.verification-tmpdir }} - - name: Continue repository verification 4 - id: verification_continue_4 - if: ${{ always() && steps.verification_continue_3.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_3.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_4.outcome }} - - name: Prepare repository verification 5 - id: verification_setup_5 - if: ${{ !cancelled() && steps.verification_continue_4.outcome == 'success' && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_4.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_4.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_4.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_4.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_4.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_4.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_4.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_4.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_4.outputs.verification-tmpdir }} - - name: Continue repository verification 5 - id: verification_continue_5 - if: ${{ always() && steps.verification_continue_4.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_4.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_5.outcome }} - - name: Prepare repository verification 6 - id: verification_setup_6 - if: ${{ !cancelled() && steps.verification_continue_5.outcome == 'success' && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_5.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_5.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_5.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_5.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_5.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_5.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_5.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_5.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_5.outputs.verification-tmpdir }} - - name: Continue repository verification 6 - id: verification_continue_6 - if: ${{ always() && steps.verification_continue_5.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_5.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_6.outcome }} - - name: Prepare repository verification 7 - id: verification_setup_7 - if: ${{ !cancelled() && steps.verification_continue_6.outcome == 'success' && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_6.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_6.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_6.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_6.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_6.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_6.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_6.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_6.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_6.outputs.verification-tmpdir }} - - name: Continue repository verification 7 - id: verification_continue_7 - if: ${{ always() && steps.verification_continue_6.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_6.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_7.outcome }} - - name: Prepare repository verification 8 - id: verification_setup_8 - if: ${{ !cancelled() && steps.verification_continue_7.outcome == 'success' && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_7.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_7.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_7.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_7.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_7.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_7.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_7.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_7.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_7.outputs.verification-tmpdir }} - - name: Continue repository verification 8 - id: verification_continue_8 - if: ${{ always() && steps.verification_continue_7.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_7.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_8.outcome }} - - name: Prepare repository verification 9 - id: verification_setup_9 - if: ${{ !cancelled() && steps.verification_continue_8.outcome == 'success' && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_8.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_8.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_8.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_8.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_8.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_8.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_8.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_8.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_8.outputs.verification-tmpdir }} - - name: Continue repository verification 9 - id: verification_continue_9 - if: ${{ always() && steps.verification_continue_8.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_8.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_9.outcome }} - - name: Prepare repository verification 10 - id: verification_setup_10 - if: ${{ !cancelled() && steps.verification_continue_9.outcome == 'success' && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_9.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_9.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_9.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_9.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_9.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_9.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_9.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_9.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_9.outputs.verification-tmpdir }} - - name: Continue repository verification 10 - id: verification_continue_10 - if: ${{ always() && steps.verification_continue_9.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_9.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_10.outcome }} - - name: Prepare repository verification 11 - id: verification_setup_11 - if: ${{ !cancelled() && steps.verification_continue_10.outcome == 'success' && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_10.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_10.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_10.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_10.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_10.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_10.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_10.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_10.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_10.outputs.verification-tmpdir }} - - name: Continue repository verification 11 - id: verification_continue_11 - if: ${{ always() && steps.verification_continue_10.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_10.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_11.outcome }} - - name: Prepare repository verification 12 - id: verification_setup_12 - if: ${{ !cancelled() && steps.verification_continue_11.outcome == 'success' && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_11.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_11.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_11.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_11.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_11.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_11.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_11.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_11.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_11.outputs.verification-tmpdir }} - - name: Continue repository verification 12 - id: verification_continue_12 - if: ${{ always() && steps.verification_continue_11.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_11.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_12.outcome }} - - name: Prepare repository verification 13 - id: verification_setup_13 - if: ${{ !cancelled() && steps.verification_continue_12.outcome == 'success' && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_12.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_12.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_12.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_12.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_12.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_12.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_12.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_12.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_12.outputs.verification-tmpdir }} - - name: Continue repository verification 13 - id: verification_continue_13 - if: ${{ always() && steps.verification_continue_12.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_12.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_13.outcome }} - - name: Prepare repository verification 14 - id: verification_setup_14 - if: ${{ !cancelled() && steps.verification_continue_13.outcome == 'success' && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_13.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_13.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_13.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_13.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_13.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_13.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_13.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_13.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_13.outputs.verification-tmpdir }} - - name: Continue repository verification 14 - id: verification_continue_14 - if: ${{ always() && steps.verification_continue_13.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_13.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_14.outcome }} - - name: Prepare repository verification 15 - id: verification_setup_15 - if: ${{ !cancelled() && steps.verification_continue_14.outcome == 'success' && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_14.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_14.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_14.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_14.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_14.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_14.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_14.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_14.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_14.outputs.verification-tmpdir }} - - name: Continue repository verification 15 - id: verification_continue_15 - if: ${{ always() && steps.verification_continue_14.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_14.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_15.outcome }} - - name: Prepare repository verification 16 - id: verification_setup_16 - if: ${{ !cancelled() && steps.verification_continue_15.outcome == 'success' && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_15.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_15.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_15.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_15.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_15.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_15.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_15.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_15.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_15.outputs.verification-tmpdir }} - - name: Continue repository verification 16 - id: verification_continue_16 - if: ${{ always() && steps.verification_continue_15.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_15.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_16.outcome }} - - name: Prepare repository verification 17 - id: verification_setup_17 - if: ${{ !cancelled() && steps.verification_continue_16.outcome == 'success' && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_16.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_16.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_16.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_16.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_16.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_16.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_16.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_16.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_16.outputs.verification-tmpdir }} - - name: Continue repository verification 17 - id: verification_continue_17 - if: ${{ always() && steps.verification_continue_16.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_16.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_17.outcome }} - - name: Prepare repository verification 18 - id: verification_setup_18 - if: ${{ !cancelled() && steps.verification_continue_17.outcome == 'success' && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_17.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_17.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_17.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_17.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_17.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_17.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_17.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_17.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_17.outputs.verification-tmpdir }} - - name: Continue repository verification 18 - id: verification_continue_18 - if: ${{ always() && steps.verification_continue_17.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_17.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_18.outcome }} - - name: Prepare repository verification 19 - id: verification_setup_19 - if: ${{ !cancelled() && steps.verification_continue_18.outcome == 'success' && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_18.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_18.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_18.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_18.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_18.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_18.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_18.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_18.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_18.outputs.verification-tmpdir }} - - name: Continue repository verification 19 - id: verification_continue_19 - if: ${{ always() && steps.verification_continue_18.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_18.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_19.outcome }} - - name: Prepare repository verification 20 - id: verification_setup_20 - if: ${{ !cancelled() && steps.verification_continue_19.outcome == 'success' && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: ./.git/copilot-verification-setup - timeout-minutes: 5 - env: - HOME: ${{ steps.verification_continue_19.outputs.verification-home }} - USERPROFILE: ${{ steps.verification_continue_19.outputs.verification-userprofile }} - APPDATA: ${{ steps.verification_continue_19.outputs.verification-appdata }} - LOCALAPPDATA: ${{ steps.verification_continue_19.outputs.verification-localappdata }} - PATH: ${{ steps.verification_continue_19.outputs.verification-path }} - JAVA_HOME: ${{ steps.verification_continue_19.outputs.verification-java_home }} - TMP: ${{ steps.verification_continue_19.outputs.verification-tmp }} - TEMP: ${{ steps.verification_continue_19.outputs.verification-temp }} - TMPDIR: ${{ steps.verification_continue_19.outputs.verification-tmpdir }} - - name: Continue repository verification 20 - id: verification_continue_20 - if: ${{ always() && steps.verification_continue_19.outputs.verification-setup-pending == 'true' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: continue - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - COPILOT_NATIVE_REQUEST: ${{ steps.verification_continue_19.outputs.verification-request }} - COPILOT_NATIVE_OUTCOME: ${{ steps.verification_setup_20.outcome }} - - name: Complete repository verification - id: verification_complete - if: ${{ always() && steps.copilot.outputs.verification-ticket != '' }} - uses: vypdev/copilot@v3 - with: *copilot-inputs - env: - COPILOT_NATIVE_PHASE: finish - COPILOT_NATIVE_SOURCE: ${{ steps.copilot.outputs.verification-source }} - COPILOT_NATIVE_DIGEST: ${{ steps.copilot.outputs.verification-digest }} - COPILOT_NATIVE_GIT: ${{ steps.copilot.outputs.verification-git }} - COPILOT_NATIVE_TICKET: ${{ steps.copilot.outputs.verification-ticket }} - # copilot:native-verification:end + with: + runs-on: '"ubuntu-latest"' + secrets: + PAT: ${{ secrets.PAT }} + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} + CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} diff --git a/specs/CATALOG.md b/specs/CATALOG.md index 9193ecba3..14cfe2eaa 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -16,7 +16,7 @@ debt or convert unknown historic intent into a design decision. | `bugbot-review-state-reconciliation` | Implemented | Reconcile review snapshots, findings, threads, comments, and check conclusions | [Bugbot review-state reconciliation](./bugbot-review-state-reconciliation.md) | 70 paths · 2026-10-21 | | `execution-lifecycle` | Implemented | Shared GitHub Action lifecycle from event admission through durable user-facing results | [Execution admission, queueing, routing, and result publication](./execution-admission-queue-and-publication.md) + 3 companion | 104 paths · 2026-10-21 | | `architecture-quality-hardening` | Implemented | Close verified concurrency, error-contract, context-coupling, fan-out, setup/doctor, and provider-policy risks in dependency order | [Architecture quality and scalability hardening](./architecture-quality-and-scalability-hardening.md) + 1 companion | 72 paths · 2026-10-13 | -| `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 6 companion | 328 paths · 2026-10-20 | +| `setup-and-doctor` | Implemented | Plan, validate, provision, and audit a repository installation without exposing credentials | [Setup, configuration, credentials, and doctor](./setup-configuration-credentials-and-doctor.md) + 6 companion | 331 paths · 2026-10-20 | | `local-web-setup-assistant` | Proposed | Offer a packaged, loopback-only Svelte setup interface over the existing engine with four-language guidance, English CLI help, basic/custom first-run paths, editable question and plan review, source-labelled GitHub facts, assisted CI and Project evidence, role-separated PATs, and truthful itemized outcomes; inspect existing configuration and apply independent, scope-aware runtime adjustments with permission, drift and read-back verification | [Local web setup assistant](./local-web-setup-assistant.md) + 2 companion | 247 paths · 2026-10-21 | | `guided-bot-pat-onboarding` | Proposed | Guide creation of the persistent workflow PAT, verify bot identity and grants, recover explicitly from wrong-account input within the session, and install the approved Actions Secret | [Guided bot PAT onboarding](./guided-bot-pat-onboarding.md) | 39 paths · 2026-10-07 | | `temporary-setup-operator-authorization` | Proposed | Guide creation of the one-run operator PAT through GitHub's official form, verify final setup access, and report user-owned deletion accurately | [Assisted setup PAT creation](./temporary-setup-operator-authorization.md) | 36 paths · 2026-10-18 | @@ -24,7 +24,7 @@ debt or convert unknown historic intent into a design decision. | `managed-issue-lifecycle` | As-built baseline | Convert typed issues into traceable work branches, project state, and lifecycle state | [Managed issue and branch lifecycle](./managed-issue-and-branch-lifecycle.md) | 71 paths · 2026-10-20 | | `comment-automation` | Implemented | Admit only explicit commands or exact mentions, then route them while protecting repository mutations | [Comment automation and authorization](./comment-automation-and-authorization.md) | 79 paths · 2026-10-11 | | `bugbot-analysis-and-autofix` | Implemented | Select one canonical PR, exhaustively analyze its bounded diff partitions, publish stable findings atomically, and apply authorized verified fixes | [Bugbot analysis, finding publication, and autofix](./bugbot-analysis-publication-and-autofix.md) + 2 companion | 115 paths · 2026-10-21 | -| `branch-synchronization` | Implemented | Observe parent drift with one localized status card and transition-only notifications, then safely merge a parent branch into a linked working branch | [Branch synchronization and conflict recovery](./branch-synchronization-and-conflict-recovery.md) + 2 companion | 119 paths · 2026-10-21 | +| `branch-synchronization` | Implemented | Observe parent drift with one localized status card and transition-only notifications, then safely merge a parent branch into a linked working branch | [Branch synchronization and conflict recovery](./branch-synchronization-and-conflict-recovery.md) + 2 companion | 126 paths · 2026-10-21 | | `pull-request-lifecycle` | Implemented | Enrich linked and unlinked pull requests with safe issue linkage, projects, metadata, reviewers, concise descriptions, and distinct workflow evidence | [Pull request lifecycle and enrichment](./pull-request-lifecycle-and-enrichment.md) | 77 paths · 2026-10-20 | | `agent-runtime` | Implemented | Resolve, provision, authenticate, authorize, and execute only the agent roles reachable by a run | [Agent runtime, provider, model, and role routing](./agent-runtime-provider-and-model-routing.md) + 1 companion | 99 paths · 2026-10-17 | | `cli-and-single-actions` | As-built baseline | Expose bounded local commands and workflow-dispatched operations through the shared application core | [CLI and single-action execution](./cli-and-single-action-execution.md) | 44 paths · 2026-10-19 | @@ -107,8 +107,8 @@ debt or convert unknown historic intent into a design decision. - Specifications: [`specs/setup-configuration-credentials-and-doctor.md`](./setup-configuration-credentials-and-doctor.md) · [`specs/setup-doctor-architecture-hardening.md`](./setup-doctor-architecture-hardening.md) · [`specs/setup-pat-permission-guidance-and-verification.md`](./setup-pat-permission-guidance-and-verification.md) · [`specs/github-runtime-doctor-command.md`](./github-runtime-doctor-command.md) · [`specs/organization-configuration-reuse-and-batch-setup.md`](./organization-configuration-reuse-and-batch-setup.md) · [`specs/setup-runner-profiles-and-installation-parity.md`](./setup-runner-profiles-and-installation-parity.md) · [`specs/copilot-comment-workflow-coordinator.md`](./copilot-comment-workflow-coordinator.md) - Workflows: [`setup/workflows/agent-cli-provisioning.yml`](../setup/workflows/agent-cli-provisioning.yml) · [`setup/workflows/copilot_credential_health.yml`](../setup/workflows/copilot_credential_health.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) · [`.github/workflows/agent-cli-provisioning.yml`](../.github/workflows/agent-cli-provisioning.yml) · [`.github/workflows/copilot_credential_health.yml`](../.github/workflows/copilot_credential_health.yml) · [`.github/workflows/copilot_commit.yml`](../.github/workflows/copilot_commit.yml) · [`.github/workflows/copilot_branch_sync.yml`](../.github/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_commit.yml`](../setup/workflows/copilot_commit.yml) · [`setup/workflows/copilot_branch_sync.yml`](../setup/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_issue_comment.yml`](../setup/workflows/copilot_issue_comment.yml) · [`setup/workflows/copilot_pull_request_comment.yml`](../setup/workflows/copilot_pull_request_comment.yml) - Entrypoints: [`src/cli/commands/setup.ts`](../src/cli/commands/setup.ts) · [`src/cli/commands/doctor.ts`](../src/cli/commands/doctor.ts) · [`src/application/usecases/issue_comment_use_case.ts`](../src/application/usecases/issue_comment_use_case.ts) · [`src/application/usecases/pull_request_review_comment_use_case.ts`](../src/application/usecases/pull_request_review_comment_use_case.ts) -- Core code: [`src/domain/setup.ts`](../src/domain/setup.ts) · [`src/domain/setup_questionnaire.ts`](../src/domain/setup_questionnaire.ts) · [`src/domain/setup_token_permissions.ts`](../src/domain/setup_token_permissions.ts) · [`src/application/ports/setup_terminal_ports.ts`](../src/application/ports/setup_terminal_ports.ts) · [`src/application/ports/setup_wizard_ports.ts`](../src/application/ports/setup_wizard_ports.ts) · [`src/application/ports/branch_tag_ports.ts`](../src/application/ports/branch_tag_ports.ts) · [`src/application/policies/setup_issue_workflow_policy.ts`](../src/application/policies/setup_issue_workflow_policy.ts) · [`src/data/repository/release/repository_version_tags_query_repository.ts`](../src/data/repository/release/repository_version_tags_query_repository.ts) · [`src/application/ports/setup_token_permission_ports.ts`](../src/application/ports/setup_token_permission_ports.ts) · [`src/application/policies/setup_token_permission_evidence_policy.ts`](../src/application/policies/setup_token_permission_evidence_policy.ts) · [`src/application/policies/setup_token_permission_policy.ts`](../src/application/policies/setup_token_permission_policy.ts) · [`src/application/policies/setup_questionnaire_policy.ts`](../src/application/policies/setup_questionnaire_policy.ts) · [`src/application/policies/setup_configuration_plan.ts`](../src/application/policies/setup_configuration_plan.ts) · [`src/application/policies/merge_setup_overrides_policy.ts`](../src/application/policies/merge_setup_overrides_policy.ts) · [`src/application/policies/setup_configuration_storage_policy.ts`](../src/application/policies/setup_configuration_storage_policy.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/application/policies/setup_doctor_report_policy.ts`](../src/application/policies/setup_doctor_report_policy.ts) · [`src/application/policies/setup_journey_policy.ts`](../src/application/policies/setup_journey_policy.ts) · [`src/application/policies/setup_permission_summary_policy.ts`](../src/application/policies/setup_permission_summary_policy.ts) · [`src/application/usecases/setup/setup_wizard_use_case.ts`](../src/application/usecases/setup/setup_wizard_use_case.ts) · [`src/application/usecases/setup/setup_journey_use_case.ts`](../src/application/usecases/setup/setup_journey_use_case.ts) · [`src/application/usecases/setup/setup_session_coordinator.ts`](../src/application/usecases/setup/setup_session_coordinator.ts) · [`src/application/usecases/setup/setup_questionnaire_controller.ts`](../src/application/usecases/setup/setup_questionnaire_controller.ts) · [`src/application/usecases/setup/setup_credentials_use_case.ts`](../src/application/usecases/setup/setup_credentials_use_case.ts) · [`src/application/usecases/setup/setup_token_permissions_use_case.ts`](../src/application/usecases/setup/setup_token_permissions_use_case.ts) · [`src/application/usecases/setup/doctor_use_case.ts`](../src/application/usecases/setup/doctor_use_case.ts) · [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) · [`src/application/usecases/actions/initial_setup_workflow.ts`](../src/application/usecases/actions/initial_setup_workflow.ts) · [`src/application/usecases/actions/setup_resource_provisioning.ts`](../src/application/usecases/actions/setup_resource_provisioning.ts) · [`src/application/ports/message_catalog_ports.ts`](../src/application/ports/message_catalog_ports.ts) · [`src/application/usecases/localization/resolve_message_catalog_use_case.ts`](../src/application/usecases/localization/resolve_message_catalog_use_case.ts) · [`src/application/policies/setup_configuration_validation.ts`](../src/application/policies/setup_configuration_validation.ts) · [`src/infrastructure/setup_workspace_adapter.ts`](../src/infrastructure/setup_workspace_adapter.ts) · [`src/data/repository/repository_variables_repository.ts`](../src/data/repository/repository_variables_repository.ts) · [`src/infrastructure/github/ports/github_repository_variables_protocol.ts`](../src/infrastructure/github/ports/github_repository_variables_protocol.ts) · [`src/infrastructure/setup_remote_credential_health_adapter.ts`](../src/infrastructure/setup_remote_credential_health_adapter.ts) · [`src/infrastructure/setup_credential_validation_adapter.ts`](../src/infrastructure/setup_credential_validation_adapter.ts) · [`src/infrastructure/setup_token_permission_query_adapter.ts`](../src/infrastructure/setup_token_permission_query_adapter.ts) · [`src/infrastructure/setup_permission_actions_probe.ts`](../src/infrastructure/setup_permission_actions_probe.ts) · [`src/infrastructure/setup_permission_issue_probe.ts`](../src/infrastructure/setup_permission_issue_probe.ts) · [`src/infrastructure/setup_permission_issue_cleanup.ts`](../src/infrastructure/setup_permission_issue_cleanup.ts) · [`src/infrastructure/setup_permission_probe_journal.ts`](../src/infrastructure/setup_permission_probe_journal.ts) · [`src/infrastructure/setup_permission_probe_transaction.ts`](../src/infrastructure/setup_permission_probe_transaction.ts) · [`src/infrastructure/setup_permission_resource_probes.ts`](../src/infrastructure/setup_permission_resource_probes.ts) · [`src/infrastructure/setup_projects_probe_page_policy.ts`](../src/infrastructure/setup_projects_probe_page_policy.ts) · [`src/cli/setup_terminal_driver.ts`](../src/cli/setup_terminal_driver.ts) · [`src/cli/setup_question_renderer.ts`](../src/cli/setup_question_renderer.ts) · [`src/cli/setup_journey_presenter.ts`](../src/cli/setup_journey_presenter.ts) · [`src/cli/setup_plan_presenter.ts`](../src/cli/setup_plan_presenter.ts) · [`src/cli/setup_doctor_presenter.ts`](../src/cli/setup_doctor_presenter.ts) · [`src/cli/setup_prompt_rendering.ts`](../src/cli/setup_prompt_rendering.ts) · [`src/cli/setup_credential_prompt_adapter.ts`](../src/cli/setup_credential_prompt_adapter.ts) · [`src/cli/setup_credential_collection.ts`](../src/cli/setup_credential_collection.ts) · [`src/cli/commands/setup_execution.ts`](../src/cli/commands/setup_execution.ts) · [`src/cli/setup_token_permission_presenter.ts`](../src/cli/setup_token_permission_presenter.ts) · [`src/infrastructure/composition/setup_credentials_composition_root.ts`](../src/infrastructure/composition/setup_credentials_composition_root.ts) · [`src/infrastructure/composition/setup_token_permissions_composition_root.ts`](../src/infrastructure/composition/setup_token_permissions_composition_root.ts) · [`src/infrastructure/composition/setup_doctor_composition_root.ts`](../src/infrastructure/composition/setup_doctor_composition_root.ts) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/documentation_pat_exception_policy.cjs`](../scripts/documentation_pat_exception_policy.cjs) · [`scripts/validate-documentation-contract.cjs`](../scripts/validate-documentation-contract.cjs) · [`src/infrastructure/http_deadline.ts`](../src/infrastructure/http_deadline.ts) · [`src/infrastructure/setup_permission_denial.ts`](../src/infrastructure/setup_permission_denial.ts) · [`src/infrastructure/setup_permission_read_probe.ts`](../src/infrastructure/setup_permission_read_probe.ts) · [`src/infrastructure/setup_permission_read_evidence.ts`](../src/infrastructure/setup_permission_read_evidence.ts) · [`src/infrastructure/setup_permission_read_shape.ts`](../src/infrastructure/setup_permission_read_shape.ts) · [`src/infrastructure/setup_permission_projects_read.ts`](../src/infrastructure/setup_permission_projects_read.ts) · [`src/infrastructure/setup_permission_projects_access.ts`](../src/infrastructure/setup_permission_projects_access.ts) · [`src/infrastructure/setup_permission_workflow_cleanup.ts`](../src/infrastructure/setup_permission_workflow_cleanup.ts) · [`src/infrastructure/setup_permission_project_cleanup.ts`](../src/infrastructure/setup_permission_project_cleanup.ts) · [`src/infrastructure/setup_permission_probe_http.ts`](../src/infrastructure/setup_permission_probe_http.ts) · [`src/infrastructure/setup_permission_pull_request_probe.ts`](../src/infrastructure/setup_permission_pull_request_probe.ts) · [`src/infrastructure/git_authentication_environment.ts`](../src/infrastructure/git_authentication_environment.ts) · [`src/actions/github_action_input.ts`](../src/actions/github_action_input.ts) · [`src/infrastructure/setup_github_identity_query_adapter.ts`](../src/infrastructure/setup_github_identity_query_adapter.ts) · [`src/infrastructure/github_secret_encryption.ts`](../src/infrastructure/github_secret_encryption.ts) · [`src/infrastructure/setup_permission_organization_owner.ts`](../src/infrastructure/setup_permission_organization_owner.ts) · [`src/data/repository/github/github_actions_resource_inspector.ts`](../src/data/repository/github/github_actions_resource_inspector.ts) · [`src/data/repository/github/github_actions_resource_commands.ts`](../src/data/repository/github/github_actions_resource_commands.ts) · [`src/data/repository/github/github_actions_resource_collection.ts`](../src/data/repository/github/github_actions_resource_collection.ts) · [`src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts`](../src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts) · [`src/cli/setup_workflow_pat_storage_copy.ts`](../src/cli/setup_workflow_pat_storage_copy.ts) · [`src/cli/commands/setup_policy.ts`](../src/cli/commands/setup_policy.ts) · [`src/application/usecases/execution/execution_issue_number_policy.ts`](../src/application/usecases/execution/execution_issue_number_policy.ts) · [`src/application/usecases/execution/setup_execution_workflow.ts`](../src/application/usecases/execution/setup_execution_workflow.ts) · [`src/domain/github_runtime_doctor.ts`](../src/domain/github_runtime_doctor.ts) · [`src/domain/copilot_command.ts`](../src/domain/copilot_command.ts) · [`src/application/usecases/comment_automation_command_workflow.ts`](../src/application/usecases/comment_automation_command_workflow.ts) · [`src/application/policies/copilot_interaction_policy.ts`](../src/application/policies/copilot_interaction_policy.ts) · [`src/application/policies/publication_message_catalog.ts`](../src/application/policies/publication_message_catalog.ts) · [`src/application/ports/github_runtime_doctor_ports.ts`](../src/application/ports/github_runtime_doctor_ports.ts) · [`src/application/policies/github_runtime_doctor_policy.ts`](../src/application/policies/github_runtime_doctor_policy.ts) · [`src/application/policies/doctor_workflow_condition_policy.ts`](../src/application/policies/doctor_workflow_condition_policy.ts) · [`src/application/policies/github_runtime_doctor_presentation_policy.ts`](../src/application/policies/github_runtime_doctor_presentation_policy.ts) · [`src/application/usecases/read_copilot_doctor_workflow.ts`](../src/application/usecases/read_copilot_doctor_workflow.ts) · [`src/data/repository/github/runtime_doctor_repository.ts`](../src/data/repository/github/runtime_doctor_repository.ts) · [`src/infrastructure/composition/github_runtime_doctor_composition_root.ts`](../src/infrastructure/composition/github_runtime_doctor_composition_root.ts) · [`src/application/policies/agent_activity_policy.ts`](../src/application/policies/agent_activity_policy.ts) · [`src/application/policies/doctor_workflow_matrix_policy.ts`](../src/application/policies/doctor_workflow_matrix_policy.ts) · [`src/application/contracts/setup_batch_view.ts`](../src/application/contracts/setup_batch_view.ts) · [`src/application/policies/issue_resource_input_policy.ts`](../src/application/policies/issue_resource_input_policy.ts) · [`src/application/policies/setup_batch_access_policy.ts`](../src/application/policies/setup_batch_access_policy.ts) · [`src/application/policies/setup_batch_policy.ts`](../src/application/policies/setup_batch_policy.ts) · [`src/application/policies/setup_batch_retry_policy.ts`](../src/application/policies/setup_batch_retry_policy.ts) · [`src/application/policies/setup_batch_selection_policy.ts`](../src/application/policies/setup_batch_selection_policy.ts) · [`src/application/policies/setup_batch_view_policy.ts`](../src/application/policies/setup_batch_view_policy.ts) · [`src/application/policies/setup_credential_binding_policy.ts`](../src/application/policies/setup_credential_binding_policy.ts) · [`src/application/policies/setup_organization_import_policy.ts`](../src/application/policies/setup_organization_import_policy.ts) · [`src/application/policies/setup_organization_variable_bindings.ts`](../src/application/policies/setup_organization_variable_bindings.ts) · [`src/application/policies/setup_organization_variable_reuse_policy.ts`](../src/application/policies/setup_organization_variable_reuse_policy.ts) · [`src/application/ports/setup_batch_ports.ts`](../src/application/ports/setup_batch_ports.ts) · [`src/application/usecases/setup/apply_setup_batch_use_case.ts`](../src/application/usecases/setup/apply_setup_batch_use_case.ts) · [`src/application/usecases/setup/configure_setup_batch_target_use_case.ts`](../src/application/usecases/setup/configure_setup_batch_target_use_case.ts) · [`src/application/usecases/setup/prepare_setup_batch_use_case.ts`](../src/application/usecases/setup/prepare_setup_batch_use_case.ts) · [`src/application/usecases/setup/select_setup_batch_targets_use_case.ts`](../src/application/usecases/setup/select_setup_batch_targets_use_case.ts) · [`src/application/usecases/setup/setup_batch_session_use_case.ts`](../src/application/usecases/setup/setup_batch_session_use_case.ts) · [`src/cli/setup_batch_adapter.ts`](../src/cli/setup_batch_adapter.ts) · [`src/cli/setup_source_adapter.ts`](../src/cli/setup_source_adapter.ts) · [`src/domain/setup_batch.ts`](../src/domain/setup_batch.ts) · [`src/domain/setup_credential_health.ts`](../src/domain/setup_credential_health.ts) · [`src/domain/setup_organization_reuse.ts`](../src/domain/setup_organization_reuse.ts) · [`src/infrastructure/composition/setup_batch_composition_root.ts`](../src/infrastructure/composition/setup_batch_composition_root.ts) · [`src/infrastructure/github/ports/github_setup_batch_protocol.ts`](../src/infrastructure/github/ports/github_setup_batch_protocol.ts) · [`src/infrastructure/github/ports/github_trusted_credential_health_protocol.ts`](../src/infrastructure/github/ports/github_trusted_credential_health_protocol.ts) · [`src/infrastructure/setup_batch_github_apply_adapter.ts`](../src/infrastructure/setup_batch_github_apply_adapter.ts) · [`src/infrastructure/setup_batch_github_read_adapter.ts`](../src/infrastructure/setup_batch_github_read_adapter.ts) · [`src/infrastructure/setup_batch_journal_adapter.ts`](../src/infrastructure/setup_batch_journal_adapter.ts) · [`src/infrastructure/setup_batch_workspace_adapter.ts`](../src/infrastructure/setup_batch_workspace_adapter.ts) · [`src/infrastructure/setup_trusted_credential_health_adapter.ts`](../src/infrastructure/setup_trusted_credential_health_adapter.ts) · [`src/application/policies/setup_remote_facts_policy.ts`](../src/application/policies/setup_remote_facts_policy.ts) · [`src/cli/setup_confirmation_adapter.ts`](../src/cli/setup_confirmation_adapter.ts) · [`src/cli/web_setup_adapters.ts`](../src/cli/web_setup_adapters.ts) · [`scripts/validate-agent-documentation.cjs`](../scripts/validate-agent-documentation.cjs) · [`src/utils/setup_workflow_upgrade.ts`](../src/utils/setup_workflow_upgrade.ts) · [`src/domain/setup_runner.ts`](../src/domain/setup_runner.ts) · [`src/application/policies/setup_runner_policy.ts`](../src/application/policies/setup_runner_policy.ts) · [`src/application/policies/setup_runner_question_policy.ts`](../src/application/policies/setup_runner_question_policy.ts) · [`src/application/policies/setup_runner_guidance_policy.ts`](../src/application/policies/setup_runner_guidance_policy.ts) · [`src/application/ports/setup_runner_ports.ts`](../src/application/ports/setup_runner_ports.ts) · [`src/infrastructure/setup_runner_discovery_adapter.ts`](../src/infrastructure/setup_runner_discovery_adapter.ts) · [`src/infrastructure/composition/setup_runner_composition_root.ts`](../src/infrastructure/composition/setup_runner_composition_root.ts) · [`src/utils/setup_installation_review.ts`](../src/utils/setup_installation_review.ts) · [`src/cli/setup_installation_review_presenter.ts`](../src/cli/setup_installation_review_presenter.ts) · [`src/application/policies/setup_runner_installation_summary_policy.ts`](../src/application/policies/setup_runner_installation_summary_policy.ts) · [`src/utils/setup_files.ts`](../src/utils/setup_files.ts) · [`src/domain/specification_catalog_path_policy.cjs`](../src/domain/specification_catalog_path_policy.cjs) · [`src/domain/sdd_prerequisite_policy.cjs`](../src/domain/sdd_prerequisite_policy.cjs) · [`src/application/contracts/setup_documentation.ts`](../src/application/contracts/setup_documentation.ts) · [`src/application/policies/setup_question_documentation_policy.ts`](../src/application/policies/setup_question_documentation_policy.ts) · [`web/src/components/SetupHelp.svelte`](../web/src/components/SetupHelp.svelte) · [`web/src/components/CompletedSetupHelp.svelte`](../web/src/components/CompletedSetupHelp.svelte) · [`src/application/policies/verification_runtime_policy.ts`](../src/application/policies/verification_runtime_policy.ts) · [`src/infrastructure/verification_runtime_manifest.ts`](../src/infrastructure/verification_runtime_manifest.ts) · [`src/infrastructure/verification_runtime_preflight.ts`](../src/infrastructure/verification_runtime_preflight.ts) · [`src/infrastructure/untrusted_command_environment.ts`](../src/infrastructure/untrusted_command_environment.ts) · [`src/application/ports/git_ports.ts`](../src/application/ports/git_ports.ts) · [`src/application/ports/bugbot_git_ports.ts`](../src/application/ports/bugbot_git_ports.ts) · [`src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts`](../src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts) · [`src/application/usecases/steps/commit/bugbot/verify_command_runner.ts`](../src/application/usecases/steps/commit/bugbot/verify_command_runner.ts) · [`src/cli/setup_config_file.ts`](../src/cli/setup_config_file.ts) -- Tests: [`src/data/repository/__tests__/repository_version_tags_query_repository.test.ts`](../src/data/repository/__tests__/repository_version_tags_query_repository.test.ts) · [`src/cli/__tests__/setup_command_options.test.ts`](../src/cli/__tests__/setup_command_options.test.ts) · [`src/data/repository/__tests__/setup_variable_write_failures.test.ts`](../src/data/repository/__tests__/setup_variable_write_failures.test.ts) · [`src/infrastructure/composition/__tests__/initial_setup_composition_root.test.ts`](../src/infrastructure/composition/__tests__/initial_setup_composition_root.test.ts) · [`src/application/policies/__tests__/setup_questionnaire_policy.test.ts`](../src/application/policies/__tests__/setup_questionnaire_policy.test.ts) · [`src/application/policies/__tests__/setup_configuration_policy.test.ts`](../src/application/policies/__tests__/setup_configuration_policy.test.ts) · [`src/application/policies/__tests__/setup_token_permission_policy.test.ts`](../src/application/policies/__tests__/setup_token_permission_policy.test.ts) · [`src/application/policies/__tests__/setup_remote_facts_policy.test.ts`](../src/application/policies/__tests__/setup_remote_facts_policy.test.ts) · [`src/application/policies/__tests__/setup_doctor_message_catalog.test.ts`](../src/application/policies/__tests__/setup_doctor_message_catalog.test.ts) · [`src/application/policies/__tests__/setup_doctor_report_policy.test.ts`](../src/application/policies/__tests__/setup_doctor_report_policy.test.ts) · [`src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts`](../src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts) · [`src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts`](../src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts) · [`src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_token_permissions_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_token_permissions_use_case.test.ts) · [`src/application/usecases/setup/__tests__/doctor_use_case.test.ts`](../src/application/usecases/setup/__tests__/doctor_use_case.test.ts) · [`src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts`](../src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts) · [`src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts`](../src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts) · [`src/application/usecases/actions/__tests__/setup_resource_provisioning.test.ts`](../src/application/usecases/actions/__tests__/setup_resource_provisioning.test.ts) · [`src/infrastructure/__tests__/setup_workspace_adapter.test.ts`](../src/infrastructure/__tests__/setup_workspace_adapter.test.ts) · [`src/infrastructure/__tests__/setup_remote_credential_health_adapter.test.ts`](../src/infrastructure/__tests__/setup_remote_credential_health_adapter.test.ts) · [`src/infrastructure/__tests__/setup_token_permission_query_adapter.test.ts`](../src/infrastructure/__tests__/setup_token_permission_query_adapter.test.ts) · [`src/infrastructure/__tests__/setup_permission_resource_probes.test.ts`](../src/infrastructure/__tests__/setup_permission_resource_probes.test.ts) · [`src/infrastructure/__tests__/setup_projects_probe_page_policy.test.ts`](../src/infrastructure/__tests__/setup_projects_probe_page_policy.test.ts) · [`src/infrastructure/composition/__tests__/setup_token_permissions_composition_root.test.ts`](../src/infrastructure/composition/__tests__/setup_token_permissions_composition_root.test.ts) · [`src/data/repository/__tests__/repository_variables_repository.test.ts`](../src/data/repository/__tests__/repository_variables_repository.test.ts) · [`src/cli/__tests__/setup_presenters.test.ts`](../src/cli/__tests__/setup_presenters.test.ts) · [`src/cli/__tests__/setup_journey_presenter.test.ts`](../src/cli/__tests__/setup_journey_presenter.test.ts) · [`src/cli/__tests__/setup_prompt_rendering.test.ts`](../src/cli/__tests__/setup_prompt_rendering.test.ts) · [`src/cli/__tests__/setup_token_permission_presenter.test.ts`](../src/cli/__tests__/setup_token_permission_presenter.test.ts) · [`src/__tests__/cli.test.ts`](../src/__tests__/cli.test.ts) · [`src/cli/__tests__/setup_terminal_driver.test.ts`](../src/cli/__tests__/setup_terminal_driver.test.ts) · [`src/architecture/__tests__/setup_doctor_boundaries.test.ts`](../src/architecture/__tests__/setup_doctor_boundaries.test.ts) · [`src/tooling/__tests__/documentation_pat_exception_policy.test.ts`](../src/tooling/__tests__/documentation_pat_exception_policy.test.ts) · [`src/infrastructure/__tests__/setup_pat_audit.test.ts`](../src/infrastructure/__tests__/setup_pat_audit.test.ts) · [`src/infrastructure/__tests__/setup_permission_projects_access.test.ts`](../src/infrastructure/__tests__/setup_permission_projects_access.test.ts) · [`src/infrastructure/__tests__/setup_credential_validation_adapter.test.ts`](../src/infrastructure/__tests__/setup_credential_validation_adapter.test.ts) · [`src/infrastructure/__tests__/setup_github_identity_query_adapter.test.ts`](../src/infrastructure/__tests__/setup_github_identity_query_adapter.test.ts) · [`src/infrastructure/__tests__/git_commit_adapter.test.ts`](../src/infrastructure/__tests__/git_commit_adapter.test.ts) · [`src/actions/__tests__/github_action_input.test.ts`](../src/actions/__tests__/github_action_input.test.ts) · [`src/infrastructure/__tests__/setup_permission_cleanup_contract.test.ts`](../src/infrastructure/__tests__/setup_permission_cleanup_contract.test.ts) · [`src/infrastructure/__tests__/setup_permission_actions_cleanup_timing.test.ts`](../src/infrastructure/__tests__/setup_permission_actions_cleanup_timing.test.ts) · [`src/infrastructure/__tests__/setup_permission_operator_actions.test.ts`](../src/infrastructure/__tests__/setup_permission_operator_actions.test.ts) · [`src/infrastructure/__tests__/setup_permission_journal_contract.test.ts`](../src/infrastructure/__tests__/setup_permission_journal_contract.test.ts) · [`src/infrastructure/__tests__/setup_permission_audit_transactions.test.ts`](../src/infrastructure/__tests__/setup_permission_audit_transactions.test.ts) · [`src/infrastructure/__tests__/setup_permission_write_failures.test.ts`](../src/infrastructure/__tests__/setup_permission_write_failures.test.ts) · [`src/infrastructure/__tests__/setup_permission_resource_failures.test.ts`](../src/infrastructure/__tests__/setup_permission_resource_failures.test.ts) · [`src/infrastructure/__tests__/setup_permission_boundary_failures.test.ts`](../src/infrastructure/__tests__/setup_permission_boundary_failures.test.ts) · [`src/infrastructure/__tests__/github_secret_encryption.test.ts`](../src/infrastructure/__tests__/github_secret_encryption.test.ts) · [`src/infrastructure/__tests__/setup_permission_organization_owner.test.ts`](../src/infrastructure/__tests__/setup_permission_organization_owner.test.ts) · [`src/infrastructure/__tests__/setup_pat_bootstrap_transactions.test.ts`](../src/infrastructure/__tests__/setup_pat_bootstrap_transactions.test.ts) · [`src/data/repository/__tests__/repository_actions_sdk_contract.integration.test.ts`](../src/data/repository/__tests__/repository_actions_sdk_contract.integration.test.ts) · [`src/data/repository/__tests__/repository_actions_resource_edge_cases.test.ts`](../src/data/repository/__tests__/repository_actions_resource_edge_cases.test.ts) · [`src/data/repository/__tests__/repository_selected_resource_grants.test.ts`](../src/data/repository/__tests__/repository_selected_resource_grants.test.ts) · [`src/infrastructure/__tests__/setup_permission_read_contract.test.ts`](../src/infrastructure/__tests__/setup_permission_read_contract.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts) · [`src/data/repository/__tests__/setup_organization_pat_inventory.test.ts`](../src/data/repository/__tests__/setup_organization_pat_inventory.test.ts) · [`src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts`](../src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts) · [`src/actions/__tests__/local_setup_apply_contract.test.ts`](../src/actions/__tests__/local_setup_apply_contract.test.ts) · [`src/cli/commands/__tests__/setup_policy.test.ts`](../src/cli/commands/__tests__/setup_policy.test.ts) · [`src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts`](../src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts) · [`src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts`](../src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts) · [`src/domain/__tests__/github_runtime_doctor.test.ts`](../src/domain/__tests__/github_runtime_doctor.test.ts) · [`src/domain/__tests__/copilot_command.test.ts`](../src/domain/__tests__/copilot_command.test.ts) · [`src/application/usecases/__tests__/comment_automation_use_case.test.ts`](../src/application/usecases/__tests__/comment_automation_use_case.test.ts) · [`src/application/policies/__tests__/github_runtime_doctor_policy.test.ts`](../src/application/policies/__tests__/github_runtime_doctor_policy.test.ts) · [`src/application/policies/__tests__/doctor_workflow_condition_policy.test.ts`](../src/application/policies/__tests__/doctor_workflow_condition_policy.test.ts) · [`src/application/policies/__tests__/github_runtime_doctor_presentation_policy.test.ts`](../src/application/policies/__tests__/github_runtime_doctor_presentation_policy.test.ts) · [`src/application/usecases/__tests__/read_copilot_doctor_workflow.test.ts`](../src/application/usecases/__tests__/read_copilot_doctor_workflow.test.ts) · [`src/application/usecases/__tests__/runtime_doctor_security_integration.test.ts`](../src/application/usecases/__tests__/runtime_doctor_security_integration.test.ts) · [`src/data/repository/github/__tests__/runtime_doctor_repository.test.ts`](../src/data/repository/github/__tests__/runtime_doctor_repository.test.ts) · [`src/infrastructure/composition/__tests__/github_runtime_doctor_composition_root.test.ts`](../src/infrastructure/composition/__tests__/github_runtime_doctor_composition_root.test.ts) · [`src/application/policies/__tests__/runtime_doctor_agent_activity.test.ts`](../src/application/policies/__tests__/runtime_doctor_agent_activity.test.ts) · [`src/application/policies/__tests__/doctor_workflow_matrix_policy.test.ts`](../src/application/policies/__tests__/doctor_workflow_matrix_policy.test.ts) · [`src/application/policies/__tests__/setup_approval_operator_permissions.test.ts`](../src/application/policies/__tests__/setup_approval_operator_permissions.test.ts) · [`src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts`](../src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts) · [`src/application/policies/__tests__/setup_batch_permission_policy.test.ts`](../src/application/policies/__tests__/setup_batch_permission_policy.test.ts) · [`src/application/policies/__tests__/setup_batch_policy.test.ts`](../src/application/policies/__tests__/setup_batch_policy.test.ts) · [`src/application/policies/__tests__/setup_batch_retry_policy.test.ts`](../src/application/policies/__tests__/setup_batch_retry_policy.test.ts) · [`src/application/policies/__tests__/setup_batch_selection_policy.test.ts`](../src/application/policies/__tests__/setup_batch_selection_policy.test.ts) · [`src/application/policies/__tests__/setup_organization_approval_draft.test.ts`](../src/application/policies/__tests__/setup_organization_approval_draft.test.ts) · [`src/application/policies/__tests__/setup_organization_import_policy.test.ts`](../src/application/policies/__tests__/setup_organization_import_policy.test.ts) · [`src/application/policies/__tests__/setup_organization_import_safety.test.ts`](../src/application/policies/__tests__/setup_organization_import_safety.test.ts) · [`src/application/policies/__tests__/setup_organization_variable_reuse_policy.test.ts`](../src/application/policies/__tests__/setup_organization_variable_reuse_policy.test.ts) · [`src/application/usecases/actions/__tests__/setup_organization_reuse_provisioning.test.ts`](../src/application/usecases/actions/__tests__/setup_organization_reuse_provisioning.test.ts) · [`src/application/usecases/setup/__tests__/apply_setup_batch_use_case.test.ts`](../src/application/usecases/setup/__tests__/apply_setup_batch_use_case.test.ts) · [`src/application/usecases/setup/__tests__/select_setup_batch_targets_use_case.test.ts`](../src/application/usecases/setup/__tests__/select_setup_batch_targets_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_batch_flow.test.ts`](../src/application/usecases/setup/__tests__/setup_batch_flow.test.ts) · [`src/application/usecases/setup/__tests__/setup_organization_import_wizard.test.ts`](../src/application/usecases/setup/__tests__/setup_organization_import_wizard.test.ts) · [`src/application/usecases/setup/__tests__/setup_organization_secret_reuse.test.ts`](../src/application/usecases/setup/__tests__/setup_organization_secret_reuse.test.ts) · [`src/cli/__tests__/setup_source_adapter.test.ts`](../src/cli/__tests__/setup_source_adapter.test.ts) · [`src/cli/__tests__/web_setup_batch_components.test.ts`](../src/cli/__tests__/web_setup_batch_components.test.ts) · [`src/cli/__tests__/web_setup_batch_selection.test.ts`](../src/cli/__tests__/web_setup_batch_selection.test.ts) · [`src/infrastructure/__tests__/setup_batch_github_apply_adapter.test.ts`](../src/infrastructure/__tests__/setup_batch_github_apply_adapter.test.ts) · [`src/infrastructure/__tests__/setup_batch_github_read_adapter.test.ts`](../src/infrastructure/__tests__/setup_batch_github_read_adapter.test.ts) · [`src/infrastructure/__tests__/setup_batch_local_adapters.test.ts`](../src/infrastructure/__tests__/setup_batch_local_adapters.test.ts) · [`src/infrastructure/__tests__/setup_reuse_empty_collections.integration.test.ts`](../src/infrastructure/__tests__/setup_reuse_empty_collections.integration.test.ts) · [`src/infrastructure/__tests__/setup_trusted_credential_health_adapter.test.ts`](../src/infrastructure/__tests__/setup_trusted_credential_health_adapter.test.ts) · [`src/infrastructure/__tests__/setup_trusted_health_sdk_contract.integration.test.ts`](../src/infrastructure/__tests__/setup_trusted_health_sdk_contract.integration.test.ts) · [`src/application/policies/__tests__/setup_batch_access_and_view.test.ts`](../src/application/policies/__tests__/setup_batch_access_and_view.test.ts) · [`src/cli/__tests__/setup_batch_adapter.test.ts`](../src/cli/__tests__/setup_batch_adapter.test.ts) · [`src/infrastructure/__tests__/setup_batch_composition.test.ts`](../src/infrastructure/__tests__/setup_batch_composition.test.ts) · [`src/infrastructure/__tests__/setup_batch_guidance_compatibility.test.ts`](../src/infrastructure/__tests__/setup_batch_guidance_compatibility.test.ts) · [`src/utils/__tests__/setup_workflow_upgrade.test.ts`](../src/utils/__tests__/setup_workflow_upgrade.test.ts) · [`src/cli/__tests__/setup_pat_intent_adapter.test.ts`](../src/cli/__tests__/setup_pat_intent_adapter.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/policies/__tests__/setup_runner_policy.test.ts`](../src/application/policies/__tests__/setup_runner_policy.test.ts) · [`src/application/policies/__tests__/setup_runner_question_policy.test.ts`](../src/application/policies/__tests__/setup_runner_question_policy.test.ts) · [`src/infrastructure/__tests__/setup_runner_discovery_adapter.test.ts`](../src/infrastructure/__tests__/setup_runner_discovery_adapter.test.ts) · [`src/utils/__tests__/setup_runner_installation.test.ts`](../src/utils/__tests__/setup_runner_installation.test.ts) · [`src/cli/__tests__/web_setup_runner_components.test.ts`](../src/cli/__tests__/web_setup_runner_components.test.ts) · [`src/application/policies/__tests__/setup_runner_installation_summary_policy.test.ts`](../src/application/policies/__tests__/setup_runner_installation_summary_policy.test.ts) · [`src/application/usecases/setup/__tests__/setup_runner_planning.test.ts`](../src/application/usecases/setup/__tests__/setup_runner_planning.test.ts) · [`src/cli/__tests__/setup_runner_config_file.test.ts`](../src/cli/__tests__/setup_runner_config_file.test.ts) · [`src/infrastructure/__tests__/setup_runner_composition.test.ts`](../src/infrastructure/__tests__/setup_runner_composition.test.ts) · [`src/tooling/__tests__/setup_provisioning_workflow.test.ts`](../src/tooling/__tests__/setup_provisioning_workflow.test.ts) · [`src/infrastructure/__tests__/setup_sdd_prerequisites.test.ts`](../src/infrastructure/__tests__/setup_sdd_prerequisites.test.ts) · [`src/cli/__tests__/setup_documentation_navigation.test.ts`](../src/cli/__tests__/setup_documentation_navigation.test.ts) · [`src/application/policies/__tests__/setup_question_documentation_policy.test.ts`](../src/application/policies/__tests__/setup_question_documentation_policy.test.ts) · [`src/application/policies/__tests__/verification_runtime_policy.test.ts`](../src/application/policies/__tests__/verification_runtime_policy.test.ts) · [`src/infrastructure/__tests__/verification_runtime_preflight.test.ts`](../src/infrastructure/__tests__/verification_runtime_preflight.test.ts) · [`src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts`](../src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts) · [`src/infrastructure/__tests__/untrusted_command_environment.test.ts`](../src/infrastructure/__tests__/untrusted_command_environment.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts) · [`src/tooling/__tests__/verification_runtime_guidance.test.ts`](../src/tooling/__tests__/verification_runtime_guidance.test.ts) · [`src/infrastructure/__tests__/verification_setup_configuration.test.ts`](../src/infrastructure/__tests__/verification_setup_configuration.test.ts) +- Core code: [`src/domain/setup.ts`](../src/domain/setup.ts) · [`src/domain/setup_questionnaire.ts`](../src/domain/setup_questionnaire.ts) · [`src/domain/setup_token_permissions.ts`](../src/domain/setup_token_permissions.ts) · [`src/application/ports/setup_terminal_ports.ts`](../src/application/ports/setup_terminal_ports.ts) · [`src/application/ports/setup_wizard_ports.ts`](../src/application/ports/setup_wizard_ports.ts) · [`src/application/ports/branch_tag_ports.ts`](../src/application/ports/branch_tag_ports.ts) · [`src/application/policies/setup_issue_workflow_policy.ts`](../src/application/policies/setup_issue_workflow_policy.ts) · [`src/data/repository/release/repository_version_tags_query_repository.ts`](../src/data/repository/release/repository_version_tags_query_repository.ts) · [`src/application/ports/setup_token_permission_ports.ts`](../src/application/ports/setup_token_permission_ports.ts) · [`src/application/policies/setup_token_permission_evidence_policy.ts`](../src/application/policies/setup_token_permission_evidence_policy.ts) · [`src/application/policies/setup_token_permission_policy.ts`](../src/application/policies/setup_token_permission_policy.ts) · [`src/application/policies/setup_questionnaire_policy.ts`](../src/application/policies/setup_questionnaire_policy.ts) · [`src/application/policies/setup_configuration_plan.ts`](../src/application/policies/setup_configuration_plan.ts) · [`src/application/policies/merge_setup_overrides_policy.ts`](../src/application/policies/merge_setup_overrides_policy.ts) · [`src/application/policies/setup_configuration_storage_policy.ts`](../src/application/policies/setup_configuration_storage_policy.ts) · [`src/application/policies/setup_doctor_message_catalog.ts`](../src/application/policies/setup_doctor_message_catalog.ts) · [`src/application/policies/setup_doctor_report_policy.ts`](../src/application/policies/setup_doctor_report_policy.ts) · [`src/application/policies/setup_journey_policy.ts`](../src/application/policies/setup_journey_policy.ts) · [`src/application/policies/setup_permission_summary_policy.ts`](../src/application/policies/setup_permission_summary_policy.ts) · [`src/application/usecases/setup/setup_wizard_use_case.ts`](../src/application/usecases/setup/setup_wizard_use_case.ts) · [`src/application/usecases/setup/setup_journey_use_case.ts`](../src/application/usecases/setup/setup_journey_use_case.ts) · [`src/application/usecases/setup/setup_session_coordinator.ts`](../src/application/usecases/setup/setup_session_coordinator.ts) · [`src/application/usecases/setup/setup_questionnaire_controller.ts`](../src/application/usecases/setup/setup_questionnaire_controller.ts) · [`src/application/usecases/setup/setup_credentials_use_case.ts`](../src/application/usecases/setup/setup_credentials_use_case.ts) · [`src/application/usecases/setup/setup_token_permissions_use_case.ts`](../src/application/usecases/setup/setup_token_permissions_use_case.ts) · [`src/application/usecases/setup/doctor_use_case.ts`](../src/application/usecases/setup/doctor_use_case.ts) · [`src/application/usecases/setup/merge_queue_readiness_use_case.ts`](../src/application/usecases/setup/merge_queue_readiness_use_case.ts) · [`src/application/usecases/actions/initial_setup_workflow.ts`](../src/application/usecases/actions/initial_setup_workflow.ts) · [`src/application/usecases/actions/setup_resource_provisioning.ts`](../src/application/usecases/actions/setup_resource_provisioning.ts) · [`src/application/ports/message_catalog_ports.ts`](../src/application/ports/message_catalog_ports.ts) · [`src/application/usecases/localization/resolve_message_catalog_use_case.ts`](../src/application/usecases/localization/resolve_message_catalog_use_case.ts) · [`src/application/policies/setup_configuration_validation.ts`](../src/application/policies/setup_configuration_validation.ts) · [`src/infrastructure/setup_workspace_adapter.ts`](../src/infrastructure/setup_workspace_adapter.ts) · [`src/data/repository/repository_variables_repository.ts`](../src/data/repository/repository_variables_repository.ts) · [`src/infrastructure/github/ports/github_repository_variables_protocol.ts`](../src/infrastructure/github/ports/github_repository_variables_protocol.ts) · [`src/infrastructure/setup_remote_credential_health_adapter.ts`](../src/infrastructure/setup_remote_credential_health_adapter.ts) · [`src/infrastructure/setup_credential_validation_adapter.ts`](../src/infrastructure/setup_credential_validation_adapter.ts) · [`src/infrastructure/setup_token_permission_query_adapter.ts`](../src/infrastructure/setup_token_permission_query_adapter.ts) · [`src/infrastructure/setup_permission_actions_probe.ts`](../src/infrastructure/setup_permission_actions_probe.ts) · [`src/infrastructure/setup_permission_issue_probe.ts`](../src/infrastructure/setup_permission_issue_probe.ts) · [`src/infrastructure/setup_permission_issue_cleanup.ts`](../src/infrastructure/setup_permission_issue_cleanup.ts) · [`src/infrastructure/setup_permission_probe_journal.ts`](../src/infrastructure/setup_permission_probe_journal.ts) · [`src/infrastructure/setup_permission_probe_transaction.ts`](../src/infrastructure/setup_permission_probe_transaction.ts) · [`src/infrastructure/setup_permission_resource_probes.ts`](../src/infrastructure/setup_permission_resource_probes.ts) · [`src/infrastructure/setup_projects_probe_page_policy.ts`](../src/infrastructure/setup_projects_probe_page_policy.ts) · [`src/cli/setup_terminal_driver.ts`](../src/cli/setup_terminal_driver.ts) · [`src/cli/setup_question_renderer.ts`](../src/cli/setup_question_renderer.ts) · [`src/cli/setup_journey_presenter.ts`](../src/cli/setup_journey_presenter.ts) · [`src/cli/setup_plan_presenter.ts`](../src/cli/setup_plan_presenter.ts) · [`src/cli/setup_doctor_presenter.ts`](../src/cli/setup_doctor_presenter.ts) · [`src/cli/setup_prompt_rendering.ts`](../src/cli/setup_prompt_rendering.ts) · [`src/cli/setup_credential_prompt_adapter.ts`](../src/cli/setup_credential_prompt_adapter.ts) · [`src/cli/setup_credential_collection.ts`](../src/cli/setup_credential_collection.ts) · [`src/cli/commands/setup_execution.ts`](../src/cli/commands/setup_execution.ts) · [`src/cli/setup_token_permission_presenter.ts`](../src/cli/setup_token_permission_presenter.ts) · [`src/infrastructure/composition/setup_credentials_composition_root.ts`](../src/infrastructure/composition/setup_credentials_composition_root.ts) · [`src/infrastructure/composition/setup_token_permissions_composition_root.ts`](../src/infrastructure/composition/setup_token_permissions_composition_root.ts) · [`src/infrastructure/composition/setup_doctor_composition_root.ts`](../src/infrastructure/composition/setup_doctor_composition_root.ts) · [`scripts/coverage-budgets.json`](../scripts/coverage-budgets.json) · [`scripts/documentation_pat_exception_policy.cjs`](../scripts/documentation_pat_exception_policy.cjs) · [`scripts/validate-documentation-contract.cjs`](../scripts/validate-documentation-contract.cjs) · [`src/infrastructure/http_deadline.ts`](../src/infrastructure/http_deadline.ts) · [`src/infrastructure/setup_permission_denial.ts`](../src/infrastructure/setup_permission_denial.ts) · [`src/infrastructure/setup_permission_read_probe.ts`](../src/infrastructure/setup_permission_read_probe.ts) · [`src/infrastructure/setup_permission_read_evidence.ts`](../src/infrastructure/setup_permission_read_evidence.ts) · [`src/infrastructure/setup_permission_read_shape.ts`](../src/infrastructure/setup_permission_read_shape.ts) · [`src/infrastructure/setup_permission_projects_read.ts`](../src/infrastructure/setup_permission_projects_read.ts) · [`src/infrastructure/setup_permission_projects_access.ts`](../src/infrastructure/setup_permission_projects_access.ts) · [`src/infrastructure/setup_permission_workflow_cleanup.ts`](../src/infrastructure/setup_permission_workflow_cleanup.ts) · [`src/infrastructure/setup_permission_project_cleanup.ts`](../src/infrastructure/setup_permission_project_cleanup.ts) · [`src/infrastructure/setup_permission_probe_http.ts`](../src/infrastructure/setup_permission_probe_http.ts) · [`src/infrastructure/setup_permission_pull_request_probe.ts`](../src/infrastructure/setup_permission_pull_request_probe.ts) · [`src/infrastructure/git_authentication_environment.ts`](../src/infrastructure/git_authentication_environment.ts) · [`src/actions/github_action_input.ts`](../src/actions/github_action_input.ts) · [`src/infrastructure/setup_github_identity_query_adapter.ts`](../src/infrastructure/setup_github_identity_query_adapter.ts) · [`src/infrastructure/github_secret_encryption.ts`](../src/infrastructure/github_secret_encryption.ts) · [`src/infrastructure/setup_permission_organization_owner.ts`](../src/infrastructure/setup_permission_organization_owner.ts) · [`src/data/repository/github/github_actions_resource_inspector.ts`](../src/data/repository/github/github_actions_resource_inspector.ts) · [`src/data/repository/github/github_actions_resource_commands.ts`](../src/data/repository/github/github_actions_resource_commands.ts) · [`src/data/repository/github/github_actions_resource_collection.ts`](../src/data/repository/github/github_actions_resource_collection.ts) · [`src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts`](../src/application/usecases/setup/resolve_setup_workflow_pat_conflict_use_case.ts) · [`src/cli/setup_workflow_pat_storage_copy.ts`](../src/cli/setup_workflow_pat_storage_copy.ts) · [`src/cli/commands/setup_policy.ts`](../src/cli/commands/setup_policy.ts) · [`src/application/usecases/execution/execution_issue_number_policy.ts`](../src/application/usecases/execution/execution_issue_number_policy.ts) · [`src/application/usecases/execution/setup_execution_workflow.ts`](../src/application/usecases/execution/setup_execution_workflow.ts) · [`src/domain/github_runtime_doctor.ts`](../src/domain/github_runtime_doctor.ts) · [`src/domain/copilot_command.ts`](../src/domain/copilot_command.ts) · [`src/application/usecases/comment_automation_command_workflow.ts`](../src/application/usecases/comment_automation_command_workflow.ts) · [`src/application/policies/copilot_interaction_policy.ts`](../src/application/policies/copilot_interaction_policy.ts) · [`src/application/policies/publication_message_catalog.ts`](../src/application/policies/publication_message_catalog.ts) · [`src/application/ports/github_runtime_doctor_ports.ts`](../src/application/ports/github_runtime_doctor_ports.ts) · [`src/application/policies/github_runtime_doctor_policy.ts`](../src/application/policies/github_runtime_doctor_policy.ts) · [`src/application/policies/doctor_workflow_condition_policy.ts`](../src/application/policies/doctor_workflow_condition_policy.ts) · [`src/application/policies/github_runtime_doctor_presentation_policy.ts`](../src/application/policies/github_runtime_doctor_presentation_policy.ts) · [`src/application/usecases/read_copilot_doctor_workflow.ts`](../src/application/usecases/read_copilot_doctor_workflow.ts) · [`src/data/repository/github/runtime_doctor_repository.ts`](../src/data/repository/github/runtime_doctor_repository.ts) · [`src/infrastructure/composition/github_runtime_doctor_composition_root.ts`](../src/infrastructure/composition/github_runtime_doctor_composition_root.ts) · [`src/application/policies/agent_activity_policy.ts`](../src/application/policies/agent_activity_policy.ts) · [`src/application/policies/doctor_workflow_matrix_policy.ts`](../src/application/policies/doctor_workflow_matrix_policy.ts) · [`src/application/contracts/setup_batch_view.ts`](../src/application/contracts/setup_batch_view.ts) · [`src/application/policies/issue_resource_input_policy.ts`](../src/application/policies/issue_resource_input_policy.ts) · [`src/application/policies/setup_batch_access_policy.ts`](../src/application/policies/setup_batch_access_policy.ts) · [`src/application/policies/setup_batch_policy.ts`](../src/application/policies/setup_batch_policy.ts) · [`src/application/policies/setup_batch_retry_policy.ts`](../src/application/policies/setup_batch_retry_policy.ts) · [`src/application/policies/setup_batch_selection_policy.ts`](../src/application/policies/setup_batch_selection_policy.ts) · [`src/application/policies/setup_batch_view_policy.ts`](../src/application/policies/setup_batch_view_policy.ts) · [`src/application/policies/setup_credential_binding_policy.ts`](../src/application/policies/setup_credential_binding_policy.ts) · [`src/application/policies/setup_organization_import_policy.ts`](../src/application/policies/setup_organization_import_policy.ts) · [`src/application/policies/setup_organization_variable_bindings.ts`](../src/application/policies/setup_organization_variable_bindings.ts) · [`src/application/policies/setup_organization_variable_reuse_policy.ts`](../src/application/policies/setup_organization_variable_reuse_policy.ts) · [`src/application/ports/setup_batch_ports.ts`](../src/application/ports/setup_batch_ports.ts) · [`src/application/usecases/setup/apply_setup_batch_use_case.ts`](../src/application/usecases/setup/apply_setup_batch_use_case.ts) · [`src/application/usecases/setup/configure_setup_batch_target_use_case.ts`](../src/application/usecases/setup/configure_setup_batch_target_use_case.ts) · [`src/application/usecases/setup/prepare_setup_batch_use_case.ts`](../src/application/usecases/setup/prepare_setup_batch_use_case.ts) · [`src/application/usecases/setup/select_setup_batch_targets_use_case.ts`](../src/application/usecases/setup/select_setup_batch_targets_use_case.ts) · [`src/application/usecases/setup/setup_batch_session_use_case.ts`](../src/application/usecases/setup/setup_batch_session_use_case.ts) · [`src/cli/setup_batch_adapter.ts`](../src/cli/setup_batch_adapter.ts) · [`src/cli/setup_source_adapter.ts`](../src/cli/setup_source_adapter.ts) · [`src/domain/setup_batch.ts`](../src/domain/setup_batch.ts) · [`src/domain/setup_credential_health.ts`](../src/domain/setup_credential_health.ts) · [`src/domain/setup_organization_reuse.ts`](../src/domain/setup_organization_reuse.ts) · [`src/infrastructure/composition/setup_batch_composition_root.ts`](../src/infrastructure/composition/setup_batch_composition_root.ts) · [`src/infrastructure/github/ports/github_setup_batch_protocol.ts`](../src/infrastructure/github/ports/github_setup_batch_protocol.ts) · [`src/infrastructure/github/ports/github_trusted_credential_health_protocol.ts`](../src/infrastructure/github/ports/github_trusted_credential_health_protocol.ts) · [`src/infrastructure/setup_batch_github_apply_adapter.ts`](../src/infrastructure/setup_batch_github_apply_adapter.ts) · [`src/infrastructure/setup_batch_github_read_adapter.ts`](../src/infrastructure/setup_batch_github_read_adapter.ts) · [`src/infrastructure/setup_batch_journal_adapter.ts`](../src/infrastructure/setup_batch_journal_adapter.ts) · [`src/infrastructure/setup_batch_workspace_adapter.ts`](../src/infrastructure/setup_batch_workspace_adapter.ts) · [`src/infrastructure/setup_trusted_credential_health_adapter.ts`](../src/infrastructure/setup_trusted_credential_health_adapter.ts) · [`src/application/policies/setup_remote_facts_policy.ts`](../src/application/policies/setup_remote_facts_policy.ts) · [`src/cli/setup_confirmation_adapter.ts`](../src/cli/setup_confirmation_adapter.ts) · [`src/cli/web_setup_adapters.ts`](../src/cli/web_setup_adapters.ts) · [`scripts/validate-agent-documentation.cjs`](../scripts/validate-agent-documentation.cjs) · [`src/utils/setup_workflow_upgrade.ts`](../src/utils/setup_workflow_upgrade.ts) · [`src/domain/setup_runner.ts`](../src/domain/setup_runner.ts) · [`src/application/policies/setup_runner_policy.ts`](../src/application/policies/setup_runner_policy.ts) · [`src/application/policies/setup_runner_question_policy.ts`](../src/application/policies/setup_runner_question_policy.ts) · [`src/application/policies/setup_runner_guidance_policy.ts`](../src/application/policies/setup_runner_guidance_policy.ts) · [`src/application/ports/setup_runner_ports.ts`](../src/application/ports/setup_runner_ports.ts) · [`src/infrastructure/setup_runner_discovery_adapter.ts`](../src/infrastructure/setup_runner_discovery_adapter.ts) · [`src/infrastructure/composition/setup_runner_composition_root.ts`](../src/infrastructure/composition/setup_runner_composition_root.ts) · [`src/utils/setup_installation_review.ts`](../src/utils/setup_installation_review.ts) · [`src/cli/setup_installation_review_presenter.ts`](../src/cli/setup_installation_review_presenter.ts) · [`src/application/policies/setup_runner_installation_summary_policy.ts`](../src/application/policies/setup_runner_installation_summary_policy.ts) · [`src/utils/setup_files.ts`](../src/utils/setup_files.ts) · [`src/domain/specification_catalog_path_policy.cjs`](../src/domain/specification_catalog_path_policy.cjs) · [`src/domain/sdd_prerequisite_policy.cjs`](../src/domain/sdd_prerequisite_policy.cjs) · [`src/application/contracts/setup_documentation.ts`](../src/application/contracts/setup_documentation.ts) · [`src/application/policies/setup_question_documentation_policy.ts`](../src/application/policies/setup_question_documentation_policy.ts) · [`web/src/components/SetupHelp.svelte`](../web/src/components/SetupHelp.svelte) · [`web/src/components/CompletedSetupHelp.svelte`](../web/src/components/CompletedSetupHelp.svelte) · [`src/application/policies/verification_runtime_policy.ts`](../src/application/policies/verification_runtime_policy.ts) · [`src/infrastructure/verification_runtime_manifest.ts`](../src/infrastructure/verification_runtime_manifest.ts) · [`src/infrastructure/verification_runtime_preflight.ts`](../src/infrastructure/verification_runtime_preflight.ts) · [`src/infrastructure/untrusted_command_environment.ts`](../src/infrastructure/untrusted_command_environment.ts) · [`src/application/ports/git_ports.ts`](../src/application/ports/git_ports.ts) · [`src/application/ports/bugbot_git_ports.ts`](../src/application/ports/bugbot_git_ports.ts) · [`src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts`](../src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts) · [`src/application/usecases/steps/commit/bugbot/verify_command_runner.ts`](../src/application/usecases/steps/commit/bugbot/verify_command_runner.ts) · [`src/cli/setup_config_file.ts`](../src/cli/setup_config_file.ts) · [`src/domain/copilot_comment_workflow.ts`](../src/domain/copilot_comment_workflow.ts) · [`src/infrastructure/copilot_comment_inputs.json`](../src/infrastructure/copilot_comment_inputs.json) +- Tests: [`src/data/repository/__tests__/repository_version_tags_query_repository.test.ts`](../src/data/repository/__tests__/repository_version_tags_query_repository.test.ts) · [`src/cli/__tests__/setup_command_options.test.ts`](../src/cli/__tests__/setup_command_options.test.ts) · [`src/data/repository/__tests__/setup_variable_write_failures.test.ts`](../src/data/repository/__tests__/setup_variable_write_failures.test.ts) · [`src/infrastructure/composition/__tests__/initial_setup_composition_root.test.ts`](../src/infrastructure/composition/__tests__/initial_setup_composition_root.test.ts) · [`src/application/policies/__tests__/setup_questionnaire_policy.test.ts`](../src/application/policies/__tests__/setup_questionnaire_policy.test.ts) · [`src/application/policies/__tests__/setup_configuration_policy.test.ts`](../src/application/policies/__tests__/setup_configuration_policy.test.ts) · [`src/application/policies/__tests__/setup_token_permission_policy.test.ts`](../src/application/policies/__tests__/setup_token_permission_policy.test.ts) · [`src/application/policies/__tests__/setup_remote_facts_policy.test.ts`](../src/application/policies/__tests__/setup_remote_facts_policy.test.ts) · [`src/application/policies/__tests__/setup_doctor_message_catalog.test.ts`](../src/application/policies/__tests__/setup_doctor_message_catalog.test.ts) · [`src/application/policies/__tests__/setup_doctor_report_policy.test.ts`](../src/application/policies/__tests__/setup_doctor_report_policy.test.ts) · [`src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts`](../src/application/usecases/setup/__tests__/setup_questionnaire_controller.test.ts) · [`src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_wizard_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_journey_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts`](../src/application/usecases/setup/__tests__/setup_session_coordinator.test.ts) · [`src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_credentials_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_token_permissions_use_case.test.ts`](../src/application/usecases/setup/__tests__/setup_token_permissions_use_case.test.ts) · [`src/application/usecases/setup/__tests__/doctor_use_case.test.ts`](../src/application/usecases/setup/__tests__/doctor_use_case.test.ts) · [`src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts`](../src/application/usecases/setup/__tests__/merge_queue_readiness_use_case.test.ts) · [`src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts`](../src/application/usecases/actions/__tests__/initial_setup_use_case.test.ts) · [`src/application/usecases/actions/__tests__/setup_resource_provisioning.test.ts`](../src/application/usecases/actions/__tests__/setup_resource_provisioning.test.ts) · [`src/infrastructure/__tests__/setup_workspace_adapter.test.ts`](../src/infrastructure/__tests__/setup_workspace_adapter.test.ts) · [`src/infrastructure/__tests__/setup_remote_credential_health_adapter.test.ts`](../src/infrastructure/__tests__/setup_remote_credential_health_adapter.test.ts) · [`src/infrastructure/__tests__/setup_token_permission_query_adapter.test.ts`](../src/infrastructure/__tests__/setup_token_permission_query_adapter.test.ts) · [`src/infrastructure/__tests__/setup_permission_resource_probes.test.ts`](../src/infrastructure/__tests__/setup_permission_resource_probes.test.ts) · [`src/infrastructure/__tests__/setup_projects_probe_page_policy.test.ts`](../src/infrastructure/__tests__/setup_projects_probe_page_policy.test.ts) · [`src/infrastructure/composition/__tests__/setup_token_permissions_composition_root.test.ts`](../src/infrastructure/composition/__tests__/setup_token_permissions_composition_root.test.ts) · [`src/data/repository/__tests__/repository_variables_repository.test.ts`](../src/data/repository/__tests__/repository_variables_repository.test.ts) · [`src/cli/__tests__/setup_presenters.test.ts`](../src/cli/__tests__/setup_presenters.test.ts) · [`src/cli/__tests__/setup_journey_presenter.test.ts`](../src/cli/__tests__/setup_journey_presenter.test.ts) · [`src/cli/__tests__/setup_prompt_rendering.test.ts`](../src/cli/__tests__/setup_prompt_rendering.test.ts) · [`src/cli/__tests__/setup_token_permission_presenter.test.ts`](../src/cli/__tests__/setup_token_permission_presenter.test.ts) · [`src/__tests__/cli.test.ts`](../src/__tests__/cli.test.ts) · [`src/cli/__tests__/setup_terminal_driver.test.ts`](../src/cli/__tests__/setup_terminal_driver.test.ts) · [`src/architecture/__tests__/setup_doctor_boundaries.test.ts`](../src/architecture/__tests__/setup_doctor_boundaries.test.ts) · [`src/tooling/__tests__/documentation_pat_exception_policy.test.ts`](../src/tooling/__tests__/documentation_pat_exception_policy.test.ts) · [`src/infrastructure/__tests__/setup_pat_audit.test.ts`](../src/infrastructure/__tests__/setup_pat_audit.test.ts) · [`src/infrastructure/__tests__/setup_permission_projects_access.test.ts`](../src/infrastructure/__tests__/setup_permission_projects_access.test.ts) · [`src/infrastructure/__tests__/setup_credential_validation_adapter.test.ts`](../src/infrastructure/__tests__/setup_credential_validation_adapter.test.ts) · [`src/infrastructure/__tests__/setup_github_identity_query_adapter.test.ts`](../src/infrastructure/__tests__/setup_github_identity_query_adapter.test.ts) · [`src/infrastructure/__tests__/git_commit_adapter.test.ts`](../src/infrastructure/__tests__/git_commit_adapter.test.ts) · [`src/actions/__tests__/github_action_input.test.ts`](../src/actions/__tests__/github_action_input.test.ts) · [`src/infrastructure/__tests__/setup_permission_cleanup_contract.test.ts`](../src/infrastructure/__tests__/setup_permission_cleanup_contract.test.ts) · [`src/infrastructure/__tests__/setup_permission_actions_cleanup_timing.test.ts`](../src/infrastructure/__tests__/setup_permission_actions_cleanup_timing.test.ts) · [`src/infrastructure/__tests__/setup_permission_operator_actions.test.ts`](../src/infrastructure/__tests__/setup_permission_operator_actions.test.ts) · [`src/infrastructure/__tests__/setup_permission_journal_contract.test.ts`](../src/infrastructure/__tests__/setup_permission_journal_contract.test.ts) · [`src/infrastructure/__tests__/setup_permission_audit_transactions.test.ts`](../src/infrastructure/__tests__/setup_permission_audit_transactions.test.ts) · [`src/infrastructure/__tests__/setup_permission_write_failures.test.ts`](../src/infrastructure/__tests__/setup_permission_write_failures.test.ts) · [`src/infrastructure/__tests__/setup_permission_resource_failures.test.ts`](../src/infrastructure/__tests__/setup_permission_resource_failures.test.ts) · [`src/infrastructure/__tests__/setup_permission_boundary_failures.test.ts`](../src/infrastructure/__tests__/setup_permission_boundary_failures.test.ts) · [`src/infrastructure/__tests__/github_secret_encryption.test.ts`](../src/infrastructure/__tests__/github_secret_encryption.test.ts) · [`src/infrastructure/__tests__/setup_permission_organization_owner.test.ts`](../src/infrastructure/__tests__/setup_permission_organization_owner.test.ts) · [`src/infrastructure/__tests__/setup_pat_bootstrap_transactions.test.ts`](../src/infrastructure/__tests__/setup_pat_bootstrap_transactions.test.ts) · [`src/data/repository/__tests__/repository_actions_sdk_contract.integration.test.ts`](../src/data/repository/__tests__/repository_actions_sdk_contract.integration.test.ts) · [`src/data/repository/__tests__/repository_actions_resource_edge_cases.test.ts`](../src/data/repository/__tests__/repository_actions_resource_edge_cases.test.ts) · [`src/data/repository/__tests__/repository_selected_resource_grants.test.ts`](../src/data/repository/__tests__/repository_selected_resource_grants.test.ts) · [`src/infrastructure/__tests__/setup_permission_read_contract.test.ts`](../src/infrastructure/__tests__/setup_permission_read_contract.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_conflict.test.ts) · [`src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts`](../src/application/usecases/setup/__tests__/setup_workflow_pat_credential_rotation.test.ts) · [`src/data/repository/__tests__/setup_organization_pat_inventory.test.ts`](../src/data/repository/__tests__/setup_organization_pat_inventory.test.ts) · [`src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts`](../src/cli/__tests__/web_setup_bot_pat_scope_conflict.test.ts) · [`src/actions/__tests__/local_setup_apply_contract.test.ts`](../src/actions/__tests__/local_setup_apply_contract.test.ts) · [`src/cli/commands/__tests__/setup_policy.test.ts`](../src/cli/commands/__tests__/setup_policy.test.ts) · [`src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts`](../src/application/usecases/execution/__tests__/execution_issue_number_policy.test.ts) · [`src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts`](../src/application/usecases/execution/__tests__/setup_execution_workflow.test.ts) · [`src/domain/__tests__/github_runtime_doctor.test.ts`](../src/domain/__tests__/github_runtime_doctor.test.ts) · [`src/domain/__tests__/copilot_command.test.ts`](../src/domain/__tests__/copilot_command.test.ts) · [`src/application/usecases/__tests__/comment_automation_use_case.test.ts`](../src/application/usecases/__tests__/comment_automation_use_case.test.ts) · [`src/application/policies/__tests__/github_runtime_doctor_policy.test.ts`](../src/application/policies/__tests__/github_runtime_doctor_policy.test.ts) · [`src/application/policies/__tests__/doctor_workflow_condition_policy.test.ts`](../src/application/policies/__tests__/doctor_workflow_condition_policy.test.ts) · [`src/application/policies/__tests__/github_runtime_doctor_presentation_policy.test.ts`](../src/application/policies/__tests__/github_runtime_doctor_presentation_policy.test.ts) · [`src/application/usecases/__tests__/read_copilot_doctor_workflow.test.ts`](../src/application/usecases/__tests__/read_copilot_doctor_workflow.test.ts) · [`src/application/usecases/__tests__/runtime_doctor_security_integration.test.ts`](../src/application/usecases/__tests__/runtime_doctor_security_integration.test.ts) · [`src/data/repository/github/__tests__/runtime_doctor_repository.test.ts`](../src/data/repository/github/__tests__/runtime_doctor_repository.test.ts) · [`src/infrastructure/composition/__tests__/github_runtime_doctor_composition_root.test.ts`](../src/infrastructure/composition/__tests__/github_runtime_doctor_composition_root.test.ts) · [`src/application/policies/__tests__/runtime_doctor_agent_activity.test.ts`](../src/application/policies/__tests__/runtime_doctor_agent_activity.test.ts) · [`src/application/policies/__tests__/doctor_workflow_matrix_policy.test.ts`](../src/application/policies/__tests__/doctor_workflow_matrix_policy.test.ts) · [`src/application/policies/__tests__/setup_approval_operator_permissions.test.ts`](../src/application/policies/__tests__/setup_approval_operator_permissions.test.ts) · [`src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts`](../src/application/usecases/setup/__tests__/audit_configured_setup_pat_use_case.test.ts) · [`src/application/policies/__tests__/setup_batch_permission_policy.test.ts`](../src/application/policies/__tests__/setup_batch_permission_policy.test.ts) · [`src/application/policies/__tests__/setup_batch_policy.test.ts`](../src/application/policies/__tests__/setup_batch_policy.test.ts) · [`src/application/policies/__tests__/setup_batch_retry_policy.test.ts`](../src/application/policies/__tests__/setup_batch_retry_policy.test.ts) · [`src/application/policies/__tests__/setup_batch_selection_policy.test.ts`](../src/application/policies/__tests__/setup_batch_selection_policy.test.ts) · [`src/application/policies/__tests__/setup_organization_approval_draft.test.ts`](../src/application/policies/__tests__/setup_organization_approval_draft.test.ts) · [`src/application/policies/__tests__/setup_organization_import_policy.test.ts`](../src/application/policies/__tests__/setup_organization_import_policy.test.ts) · [`src/application/policies/__tests__/setup_organization_import_safety.test.ts`](../src/application/policies/__tests__/setup_organization_import_safety.test.ts) · [`src/application/policies/__tests__/setup_organization_variable_reuse_policy.test.ts`](../src/application/policies/__tests__/setup_organization_variable_reuse_policy.test.ts) · [`src/application/usecases/actions/__tests__/setup_organization_reuse_provisioning.test.ts`](../src/application/usecases/actions/__tests__/setup_organization_reuse_provisioning.test.ts) · [`src/application/usecases/setup/__tests__/apply_setup_batch_use_case.test.ts`](../src/application/usecases/setup/__tests__/apply_setup_batch_use_case.test.ts) · [`src/application/usecases/setup/__tests__/select_setup_batch_targets_use_case.test.ts`](../src/application/usecases/setup/__tests__/select_setup_batch_targets_use_case.test.ts) · [`src/application/usecases/setup/__tests__/setup_batch_flow.test.ts`](../src/application/usecases/setup/__tests__/setup_batch_flow.test.ts) · [`src/application/usecases/setup/__tests__/setup_organization_import_wizard.test.ts`](../src/application/usecases/setup/__tests__/setup_organization_import_wizard.test.ts) · [`src/application/usecases/setup/__tests__/setup_organization_secret_reuse.test.ts`](../src/application/usecases/setup/__tests__/setup_organization_secret_reuse.test.ts) · [`src/cli/__tests__/setup_source_adapter.test.ts`](../src/cli/__tests__/setup_source_adapter.test.ts) · [`src/cli/__tests__/web_setup_batch_components.test.ts`](../src/cli/__tests__/web_setup_batch_components.test.ts) · [`src/cli/__tests__/web_setup_batch_selection.test.ts`](../src/cli/__tests__/web_setup_batch_selection.test.ts) · [`src/infrastructure/__tests__/setup_batch_github_apply_adapter.test.ts`](../src/infrastructure/__tests__/setup_batch_github_apply_adapter.test.ts) · [`src/infrastructure/__tests__/setup_batch_github_read_adapter.test.ts`](../src/infrastructure/__tests__/setup_batch_github_read_adapter.test.ts) · [`src/infrastructure/__tests__/setup_batch_local_adapters.test.ts`](../src/infrastructure/__tests__/setup_batch_local_adapters.test.ts) · [`src/infrastructure/__tests__/setup_reuse_empty_collections.integration.test.ts`](../src/infrastructure/__tests__/setup_reuse_empty_collections.integration.test.ts) · [`src/infrastructure/__tests__/setup_trusted_credential_health_adapter.test.ts`](../src/infrastructure/__tests__/setup_trusted_credential_health_adapter.test.ts) · [`src/infrastructure/__tests__/setup_trusted_health_sdk_contract.integration.test.ts`](../src/infrastructure/__tests__/setup_trusted_health_sdk_contract.integration.test.ts) · [`src/application/policies/__tests__/setup_batch_access_and_view.test.ts`](../src/application/policies/__tests__/setup_batch_access_and_view.test.ts) · [`src/cli/__tests__/setup_batch_adapter.test.ts`](../src/cli/__tests__/setup_batch_adapter.test.ts) · [`src/infrastructure/__tests__/setup_batch_composition.test.ts`](../src/infrastructure/__tests__/setup_batch_composition.test.ts) · [`src/infrastructure/__tests__/setup_batch_guidance_compatibility.test.ts`](../src/infrastructure/__tests__/setup_batch_guidance_compatibility.test.ts) · [`src/utils/__tests__/setup_workflow_upgrade.test.ts`](../src/utils/__tests__/setup_workflow_upgrade.test.ts) · [`src/cli/__tests__/setup_pat_intent_adapter.test.ts`](../src/cli/__tests__/setup_pat_intent_adapter.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/policies/__tests__/setup_runner_policy.test.ts`](../src/application/policies/__tests__/setup_runner_policy.test.ts) · [`src/application/policies/__tests__/setup_runner_question_policy.test.ts`](../src/application/policies/__tests__/setup_runner_question_policy.test.ts) · [`src/infrastructure/__tests__/setup_runner_discovery_adapter.test.ts`](../src/infrastructure/__tests__/setup_runner_discovery_adapter.test.ts) · [`src/utils/__tests__/setup_runner_installation.test.ts`](../src/utils/__tests__/setup_runner_installation.test.ts) · [`src/cli/__tests__/web_setup_runner_components.test.ts`](../src/cli/__tests__/web_setup_runner_components.test.ts) · [`src/application/policies/__tests__/setup_runner_installation_summary_policy.test.ts`](../src/application/policies/__tests__/setup_runner_installation_summary_policy.test.ts) · [`src/application/usecases/setup/__tests__/setup_runner_planning.test.ts`](../src/application/usecases/setup/__tests__/setup_runner_planning.test.ts) · [`src/cli/__tests__/setup_runner_config_file.test.ts`](../src/cli/__tests__/setup_runner_config_file.test.ts) · [`src/infrastructure/__tests__/setup_runner_composition.test.ts`](../src/infrastructure/__tests__/setup_runner_composition.test.ts) · [`src/tooling/__tests__/setup_provisioning_workflow.test.ts`](../src/tooling/__tests__/setup_provisioning_workflow.test.ts) · [`src/infrastructure/__tests__/setup_sdd_prerequisites.test.ts`](../src/infrastructure/__tests__/setup_sdd_prerequisites.test.ts) · [`src/cli/__tests__/setup_documentation_navigation.test.ts`](../src/cli/__tests__/setup_documentation_navigation.test.ts) · [`src/application/policies/__tests__/setup_question_documentation_policy.test.ts`](../src/application/policies/__tests__/setup_question_documentation_policy.test.ts) · [`src/application/policies/__tests__/verification_runtime_policy.test.ts`](../src/application/policies/__tests__/verification_runtime_policy.test.ts) · [`src/infrastructure/__tests__/verification_runtime_preflight.test.ts`](../src/infrastructure/__tests__/verification_runtime_preflight.test.ts) · [`src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts`](../src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts) · [`src/infrastructure/__tests__/untrusted_command_environment.test.ts`](../src/infrastructure/__tests__/untrusted_command_environment.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts) · [`src/tooling/__tests__/verification_runtime_guidance.test.ts`](../src/tooling/__tests__/verification_runtime_guidance.test.ts) · [`src/infrastructure/__tests__/verification_setup_configuration.test.ts`](../src/infrastructure/__tests__/verification_setup_configuration.test.ts) · [`src/domain/__tests__/copilot_comment_workflow.test.ts`](../src/domain/__tests__/copilot_comment_workflow.test.ts) - User documentation: [`README.md`](../README.md) · [`docs/how-to-use.mdx`](../docs/how-to-use.mdx) · [`docs/configuration.mdx`](../docs/configuration.mdx) · [`docs/configuration-checklist.mdx`](../docs/configuration-checklist.mdx) · [`docs/authentication.mdx`](../docs/authentication.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/security-operations/operations/provisioning.mdx`](../docs/security-operations/operations/provisioning.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/security-operations/security/credentials.mdx`](../docs/security-operations/security/credentials.mdx) · [`docs/single-actions/workflow-and-cli.mdx`](../docs/single-actions/workflow-and-cli.mdx) · [`docs/security-operations/operations/verification.mdx`](../docs/security-operations/operations/verification.mdx) · [`docs/development/setup-pat-provider-audit-2026-10-06.md`](../docs/development/setup-pat-provider-audit-2026-10-06.md) · [`docs/issues/comment-commands.mdx`](../docs/issues/comment-commands.mdx) · [`docs/issues/branch-synchronization.mdx`](../docs/issues/branch-synchronization.mdx) · [`docs/setup-web.mdx`](../docs/setup-web.mdx) · [`docs/first-workflow.mdx`](../docs/first-workflow.mdx) · [`docs/using-the-docs.mdx`](../docs/using-the-docs.mdx) · [`docs/guides/index.mdx`](../docs/guides/index.mdx) · [`docs/guides/issues-and-branches.mdx`](../docs/guides/issues-and-branches.mdx) · [`docs/guides/review-pull-requests.mdx`](../docs/guides/review-pull-requests.mdx) · [`docs/guides/work-with-the-bot.mdx`](../docs/guides/work-with-the-bot.mdx) · [`docs/guides/releases-and-hotfixes.mdx`](../docs/guides/releases-and-hotfixes.mdx) · [`docs/agents/repository-collaboration.mdx`](../docs/agents/repository-collaboration.mdx) ### `local-web-setup-assistant` — Local web setup assistant @@ -193,10 +193,10 @@ debt or convert unknown historic intent into a design decision. - Owner: Copilot maintainers - Last verified: 2026-10-21 - Specifications: [`specs/branch-synchronization-and-conflict-recovery.md`](./branch-synchronization-and-conflict-recovery.md) · [`specs/repository-verification-runtime-prerequisites.md`](./repository-verification-runtime-prerequisites.md) · [`specs/repository-verification-setup-hooks.md`](./repository-verification-setup-hooks.md) -- Workflows: [`.github/workflows/copilot_branch_sync.yml`](../.github/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_branch_sync.yml`](../setup/workflows/copilot_branch_sync.yml) · [`.github/workflows/copilot_issue.yml`](../.github/workflows/copilot_issue.yml) · [`setup/workflows/copilot_issue.yml`](../setup/workflows/copilot_issue.yml) · [`setup/workflows/copilot_issue_comment.yml`](../setup/workflows/copilot_issue_comment.yml) · [`setup/workflows/copilot_pull_request_comment.yml`](../setup/workflows/copilot_pull_request_comment.yml) +- Workflows: [`.github/workflows/copilot_branch_sync.yml`](../.github/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_branch_sync.yml`](../setup/workflows/copilot_branch_sync.yml) · [`.github/workflows/copilot_issue.yml`](../.github/workflows/copilot_issue.yml) · [`setup/workflows/copilot_issue.yml`](../setup/workflows/copilot_issue.yml) · [`setup/workflows/copilot_issue_comment.yml`](../setup/workflows/copilot_issue_comment.yml) · [`setup/workflows/copilot_pull_request_comment.yml`](../setup/workflows/copilot_pull_request_comment.yml) · [`.github/workflows/copilot_comment_runtime.yml`](../.github/workflows/copilot_comment_runtime.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) - Entrypoints: [`src/application/usecases/branch_sync/sync_branch_use_case.ts`](../src/application/usecases/branch_sync/sync_branch_use_case.ts) · [`src/application/usecases/actions/observe_branch_sync_use_case.ts`](../src/application/usecases/actions/observe_branch_sync_use_case.ts) -- Core code: [`src/domain/branch_sync_command.ts`](../src/domain/branch_sync_command.ts) · [`src/application/ports/branch_sync_ports.ts`](../src/application/ports/branch_sync_ports.ts) · [`src/application/policies/branch_sync_message_catalog.ts`](../src/application/policies/branch_sync_message_catalog.ts) · [`src/application/policies/branch_sync_notification_policy.ts`](../src/application/policies/branch_sync_notification_policy.ts) · [`src/application/usecases/branch_sync/branch_sync_execution_policy.ts`](../src/application/usecases/branch_sync/branch_sync_execution_policy.ts) · [`src/application/usecases/actions/observe_branch_sync_use_case.ts`](../src/application/usecases/actions/observe_branch_sync_use_case.ts) · [`src/application/usecases/push_single_action_contexts.ts`](../src/application/usecases/push_single_action_contexts.ts) · [`src/application/usecases/steps/common/transition_notification_workflow.ts`](../src/application/usecases/steps/common/transition_notification_workflow.ts) · [`src/data/repository/branch_sync/branch_dependency_policy.ts`](../src/data/repository/branch_sync/branch_dependency_policy.ts) · [`src/data/repository/branch_sync/branch_dependency_repository.ts`](../src/data/repository/branch_sync/branch_dependency_repository.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/infrastructure/composition/push_single_action_capability_port_binding.ts`](../src/infrastructure/composition/push_single_action_capability_port_binding.ts) · [`src/infrastructure/branch_sync_workspace_adapter.ts`](../src/infrastructure/branch_sync_workspace_adapter.ts) · [`src/prompts/branch_sync_conflicts.ts`](../src/prompts/branch_sync_conflicts.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/infrastructure/git_commit_adapter.ts`](../src/infrastructure/git_commit_adapter.ts) · [`src/infrastructure/branch_sync_sdd_catalog.ts`](../src/infrastructure/branch_sync_sdd_catalog.ts) · [`src/domain/branch_sync_validation.ts`](../src/domain/branch_sync_validation.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/infrastructure/branch_sync_communication_budget.ts`](../src/infrastructure/branch_sync_communication_budget.ts) · [`src/application/usecases/actions/retire_branch_sync_use_case.ts`](../src/application/usecases/actions/retire_branch_sync_use_case.ts) · [`src/application/ports/issue_completion_ports.ts`](../src/application/ports/issue_completion_ports.ts) · [`src/application/usecases/pull_request_workflow.ts`](../src/application/usecases/pull_request_workflow.ts) · [`src/application/usecases/pull_request_workflow_context.ts`](../src/application/usecases/pull_request_workflow_context.ts) · [`src/infrastructure/composition/pull_request_use_case_composition_root.ts`](../src/infrastructure/composition/pull_request_use_case_composition_root.ts) · [`src/actions/common_action.ts`](../src/actions/common_action.ts) · [`src/actions/github_action.ts`](../src/actions/github_action.ts) · [`scripts/validate-workflow-contract.cjs`](../scripts/validate-workflow-contract.cjs) · [`src/application/ports/reply_request_read_ports.ts`](../src/application/ports/reply_request_read_ports.ts) · [`src/domain/reply_request_digest.ts`](../src/domain/reply_request_digest.ts) · [`src/infrastructure/composition/reply_request_composition_root.ts`](../src/infrastructure/composition/reply_request_composition_root.ts) · [`src/data/repository/reply_request_repository.ts`](../src/data/repository/reply_request_repository.ts) · [`src/application/policies/verification_runtime_policy.ts`](../src/application/policies/verification_runtime_policy.ts) · [`src/infrastructure/verification_runtime_manifest.ts`](../src/infrastructure/verification_runtime_manifest.ts) · [`src/infrastructure/verification_runtime_preflight.ts`](../src/infrastructure/verification_runtime_preflight.ts) · [`src/infrastructure/untrusted_command_environment.ts`](../src/infrastructure/untrusted_command_environment.ts) · [`src/application/ports/git_ports.ts`](../src/application/ports/git_ports.ts) · [`src/application/ports/bugbot_git_ports.ts`](../src/application/ports/bugbot_git_ports.ts) · [`src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts`](../src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts) · [`src/application/usecases/steps/commit/bugbot/verify_command_runner.ts`](../src/application/usecases/steps/commit/bugbot/verify_command_runner.ts) · [`src/domain/closed_issue_reconciliation.ts`](../src/domain/closed_issue_reconciliation.ts) · [`src/application/errors/closed_issue_reconciliation_error.ts`](../src/application/errors/closed_issue_reconciliation_error.ts) · [`src/application/policies/verification_setup_policy.ts`](../src/application/policies/verification_setup_policy.ts) · [`src/application/ports/verification_setup_ports.ts`](../src/application/ports/verification_setup_ports.ts) · [`src/infrastructure/verification_setup_snapshot.ts`](../src/infrastructure/verification_setup_snapshot.ts) · [`src/infrastructure/verification_setup_result.ts`](../src/infrastructure/verification_setup_result.ts) · [`src/infrastructure/verification_setup_runner.ts`](../src/infrastructure/verification_setup_runner.ts) · [`src/infrastructure/native_verification_protocol.ts`](../src/infrastructure/native_verification_protocol.ts) · [`src/infrastructure/native_verification_candidate.ts`](../src/infrastructure/native_verification_candidate.ts) · [`src/infrastructure/native_verification_staging.ts`](../src/infrastructure/native_verification_staging.ts) · [`src/infrastructure/native_verification_controller.ts`](../src/infrastructure/native_verification_controller.ts) · [`src/infrastructure/native_verification_profiles.ts`](../src/infrastructure/native_verification_profiles.ts) · [`src/infrastructure/native_verification_redaction.ts`](../src/infrastructure/native_verification_redaction.ts) · [`scripts/generate-native-verification-workflows.cjs`](../scripts/generate-native-verification-workflows.cjs) · [`src/infrastructure/verification_executable.ts`](../src/infrastructure/verification_executable.ts) · [`src/infrastructure/native_verification_source_runtime.ts`](../src/infrastructure/native_verification_source_runtime.ts) · [`scripts/prepare-native-source-action.cjs`](../scripts/prepare-native-source-action.cjs) -- Tests: [`src/application/policies/__tests__/branch_sync_notification_policy.test.ts`](../src/application/policies/__tests__/branch_sync_notification_policy.test.ts) · [`src/application/usecases/actions/__tests__/observe_branch_sync_use_case.test.ts`](../src/application/usecases/actions/__tests__/observe_branch_sync_use_case.test.ts) · [`src/application/usecases/branch_sync/__tests__/sync_branch_use_case.test.ts`](../src/application/usecases/branch_sync/__tests__/sync_branch_use_case.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/usecases/steps/common/__tests__/transition_notification_workflow.test.ts`](../src/application/usecases/steps/common/__tests__/transition_notification_workflow.test.ts) · [`src/data/repository/branch_sync/__tests__/branch_dependency_policy.test.ts`](../src/data/repository/branch_sync/__tests__/branch_dependency_policy.test.ts) · [`src/data/repository/branch_sync/__tests__/branch_dependency_repository.test.ts`](../src/data/repository/branch_sync/__tests__/branch_dependency_repository.test.ts) · [`src/infrastructure/__tests__/branch_sync_workspace_adapter.test.ts`](../src/infrastructure/__tests__/branch_sync_workspace_adapter.test.ts) · [`src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts) · [`src/application/usecases/branch_sync/__tests__/branch_sync_execution_policy.test.ts`](../src/application/usecases/branch_sync/__tests__/branch_sync_execution_policy.test.ts) · [`src/application/errors/__tests__/application_error.test.ts`](../src/application/errors/__tests__/application_error.test.ts) · [`src/application/policies/__tests__/application_error_presentation_policy.test.ts`](../src/application/policies/__tests__/application_error_presentation_policy.test.ts) · [`src/infrastructure/__tests__/git_commit_adapter.test.ts`](../src/infrastructure/__tests__/git_commit_adapter.test.ts) · [`src/infrastructure/__tests__/branch_sync_sdd_catalog.test.ts`](../src/infrastructure/__tests__/branch_sync_sdd_catalog.test.ts) · [`src/infrastructure/__tests__/branch_sync_generated_bundle_validation.test.ts`](../src/infrastructure/__tests__/branch_sync_generated_bundle_validation.test.ts) · [`src/application/policies/__tests__/branch_sync_lifecycle_recovery.test.ts`](../src/application/policies/__tests__/branch_sync_lifecycle_recovery.test.ts) · [`src/infrastructure/__tests__/branch_sync_resolved_workspace.test.ts`](../src/infrastructure/__tests__/branch_sync_resolved_workspace.test.ts) · [`src/infrastructure/__tests__/branch_sync_communication_budget.test.ts`](../src/infrastructure/__tests__/branch_sync_communication_budget.test.ts) · [`src/application/usecases/actions/__tests__/retire_branch_sync_use_case.test.ts`](../src/application/usecases/actions/__tests__/retire_branch_sync_use_case.test.ts) · [`src/application/usecases/__tests__/pull_request_use_case.test.ts`](../src/application/usecases/__tests__/pull_request_use_case.test.ts) · [`src/actions/__tests__/common_action.test.ts`](../src/actions/__tests__/common_action.test.ts) · [`src/actions/__tests__/github_action.test.ts`](../src/actions/__tests__/github_action.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) · [`src/data/repository/__tests__/reply_request_repository.test.ts`](../src/data/repository/__tests__/reply_request_repository.test.ts) · [`src/infrastructure/composition/__tests__/reply_request_composition_root.test.ts`](../src/infrastructure/composition/__tests__/reply_request_composition_root.test.ts) · [`src/application/policies/__tests__/verification_runtime_policy.test.ts`](../src/application/policies/__tests__/verification_runtime_policy.test.ts) · [`src/infrastructure/__tests__/verification_runtime_preflight.test.ts`](../src/infrastructure/__tests__/verification_runtime_preflight.test.ts) · [`src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts`](../src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts) · [`src/infrastructure/__tests__/untrusted_command_environment.test.ts`](../src/infrastructure/__tests__/untrusted_command_environment.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts) · [`src/tooling/__tests__/verification_runtime_guidance.test.ts`](../src/tooling/__tests__/verification_runtime_guidance.test.ts) · [`src/application/policies/__tests__/verification_setup_policy.test.ts`](../src/application/policies/__tests__/verification_setup_policy.test.ts) · [`src/infrastructure/__tests__/verification_setup_snapshot.test.ts`](../src/infrastructure/__tests__/verification_setup_snapshot.test.ts) · [`src/infrastructure/__tests__/verification_setup_runner.test.ts`](../src/infrastructure/__tests__/verification_setup_runner.test.ts) · [`src/infrastructure/__tests__/verification_setup_configuration.test.ts`](../src/infrastructure/__tests__/verification_setup_configuration.test.ts) · [`src/infrastructure/__tests__/verification_setup_sync.test.ts`](../src/infrastructure/__tests__/verification_setup_sync.test.ts) · [`src/infrastructure/__tests__/native_verification_runner.test.ts`](../src/infrastructure/__tests__/native_verification_runner.test.ts) · [`src/infrastructure/__tests__/native_verification_protocol.test.ts`](../src/infrastructure/__tests__/native_verification_protocol.test.ts) · [`src/infrastructure/__tests__/native_verification_controller.test.ts`](../src/infrastructure/__tests__/native_verification_controller.test.ts) · [`src/infrastructure/__tests__/native_verification_redaction.test.ts`](../src/infrastructure/__tests__/native_verification_redaction.test.ts) · [`src/infrastructure/__tests__/native_verification_workflow.test.ts`](../src/infrastructure/__tests__/native_verification_workflow.test.ts) · [`src/infrastructure/__tests__/native_verification_profiles.test.ts`](../src/infrastructure/__tests__/native_verification_profiles.test.ts) · [`src/infrastructure/__tests__/verification_executable.test.ts`](../src/infrastructure/__tests__/verification_executable.test.ts) · [`src/infrastructure/__tests__/native_verification_post.test.ts`](../src/infrastructure/__tests__/native_verification_post.test.ts) · [`src/infrastructure/__tests__/native_verification_source_runtime.test.ts`](../src/infrastructure/__tests__/native_verification_source_runtime.test.ts) +- Core code: [`src/domain/branch_sync_command.ts`](../src/domain/branch_sync_command.ts) · [`src/application/ports/branch_sync_ports.ts`](../src/application/ports/branch_sync_ports.ts) · [`src/application/policies/branch_sync_message_catalog.ts`](../src/application/policies/branch_sync_message_catalog.ts) · [`src/application/policies/branch_sync_notification_policy.ts`](../src/application/policies/branch_sync_notification_policy.ts) · [`src/application/usecases/branch_sync/branch_sync_execution_policy.ts`](../src/application/usecases/branch_sync/branch_sync_execution_policy.ts) · [`src/application/usecases/actions/observe_branch_sync_use_case.ts`](../src/application/usecases/actions/observe_branch_sync_use_case.ts) · [`src/application/usecases/push_single_action_contexts.ts`](../src/application/usecases/push_single_action_contexts.ts) · [`src/application/usecases/steps/common/transition_notification_workflow.ts`](../src/application/usecases/steps/common/transition_notification_workflow.ts) · [`src/data/repository/branch_sync/branch_dependency_policy.ts`](../src/data/repository/branch_sync/branch_dependency_policy.ts) · [`src/data/repository/branch_sync/branch_dependency_repository.ts`](../src/data/repository/branch_sync/branch_dependency_repository.ts) · [`src/infrastructure/composition/main_run_route_composition_root.ts`](../src/infrastructure/composition/main_run_route_composition_root.ts) · [`src/infrastructure/composition/push_single_action_capability_port_binding.ts`](../src/infrastructure/composition/push_single_action_capability_port_binding.ts) · [`src/infrastructure/branch_sync_workspace_adapter.ts`](../src/infrastructure/branch_sync_workspace_adapter.ts) · [`src/prompts/branch_sync_conflicts.ts`](../src/prompts/branch_sync_conflicts.ts) · [`src/data/model/application_error.ts`](../src/data/model/application_error.ts) · [`src/application/policies/application_error_message_catalog.ts`](../src/application/policies/application_error_message_catalog.ts) · [`src/infrastructure/git_commit_adapter.ts`](../src/infrastructure/git_commit_adapter.ts) · [`src/infrastructure/branch_sync_sdd_catalog.ts`](../src/infrastructure/branch_sync_sdd_catalog.ts) · [`src/domain/branch_sync_validation.ts`](../src/domain/branch_sync_validation.ts) · [`src/application/policies/lifecycle_state_policy.ts`](../src/application/policies/lifecycle_state_policy.ts) · [`src/infrastructure/branch_sync_communication_budget.ts`](../src/infrastructure/branch_sync_communication_budget.ts) · [`src/application/usecases/actions/retire_branch_sync_use_case.ts`](../src/application/usecases/actions/retire_branch_sync_use_case.ts) · [`src/application/ports/issue_completion_ports.ts`](../src/application/ports/issue_completion_ports.ts) · [`src/application/usecases/pull_request_workflow.ts`](../src/application/usecases/pull_request_workflow.ts) · [`src/application/usecases/pull_request_workflow_context.ts`](../src/application/usecases/pull_request_workflow_context.ts) · [`src/infrastructure/composition/pull_request_use_case_composition_root.ts`](../src/infrastructure/composition/pull_request_use_case_composition_root.ts) · [`src/actions/common_action.ts`](../src/actions/common_action.ts) · [`src/actions/github_action.ts`](../src/actions/github_action.ts) · [`scripts/validate-workflow-contract.cjs`](../scripts/validate-workflow-contract.cjs) · [`src/application/ports/reply_request_read_ports.ts`](../src/application/ports/reply_request_read_ports.ts) · [`src/domain/reply_request_digest.ts`](../src/domain/reply_request_digest.ts) · [`src/infrastructure/composition/reply_request_composition_root.ts`](../src/infrastructure/composition/reply_request_composition_root.ts) · [`src/data/repository/reply_request_repository.ts`](../src/data/repository/reply_request_repository.ts) · [`src/application/policies/verification_runtime_policy.ts`](../src/application/policies/verification_runtime_policy.ts) · [`src/infrastructure/verification_runtime_manifest.ts`](../src/infrastructure/verification_runtime_manifest.ts) · [`src/infrastructure/verification_runtime_preflight.ts`](../src/infrastructure/verification_runtime_preflight.ts) · [`src/infrastructure/untrusted_command_environment.ts`](../src/infrastructure/untrusted_command_environment.ts) · [`src/application/ports/git_ports.ts`](../src/application/ports/git_ports.ts) · [`src/application/ports/bugbot_git_ports.ts`](../src/application/ports/bugbot_git_ports.ts) · [`src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts`](../src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts) · [`src/application/usecases/steps/commit/bugbot/verify_command_runner.ts`](../src/application/usecases/steps/commit/bugbot/verify_command_runner.ts) · [`src/domain/closed_issue_reconciliation.ts`](../src/domain/closed_issue_reconciliation.ts) · [`src/application/errors/closed_issue_reconciliation_error.ts`](../src/application/errors/closed_issue_reconciliation_error.ts) · [`src/application/policies/verification_setup_policy.ts`](../src/application/policies/verification_setup_policy.ts) · [`src/application/ports/verification_setup_ports.ts`](../src/application/ports/verification_setup_ports.ts) · [`src/infrastructure/verification_setup_snapshot.ts`](../src/infrastructure/verification_setup_snapshot.ts) · [`src/infrastructure/verification_setup_result.ts`](../src/infrastructure/verification_setup_result.ts) · [`src/infrastructure/verification_setup_runner.ts`](../src/infrastructure/verification_setup_runner.ts) · [`src/infrastructure/native_verification_protocol.ts`](../src/infrastructure/native_verification_protocol.ts) · [`src/infrastructure/native_verification_candidate.ts`](../src/infrastructure/native_verification_candidate.ts) · [`src/infrastructure/native_verification_staging.ts`](../src/infrastructure/native_verification_staging.ts) · [`src/infrastructure/native_verification_controller.ts`](../src/infrastructure/native_verification_controller.ts) · [`src/infrastructure/native_verification_profiles.ts`](../src/infrastructure/native_verification_profiles.ts) · [`src/infrastructure/native_verification_redaction.ts`](../src/infrastructure/native_verification_redaction.ts) · [`scripts/generate-native-verification-workflows.cjs`](../scripts/generate-native-verification-workflows.cjs) · [`src/infrastructure/verification_executable.ts`](../src/infrastructure/verification_executable.ts) · [`src/infrastructure/native_verification_source_runtime.ts`](../src/infrastructure/native_verification_source_runtime.ts) · [`scripts/prepare-native-source-action.cjs`](../scripts/prepare-native-source-action.cjs) · [`src/domain/copilot_comment_workflow.ts`](../src/domain/copilot_comment_workflow.ts) · [`src/infrastructure/copilot_comment_inputs.json`](../src/infrastructure/copilot_comment_inputs.json) · [`scripts/validate-comment-workflows.cjs`](../scripts/validate-comment-workflows.cjs) +- Tests: [`src/application/policies/__tests__/branch_sync_notification_policy.test.ts`](../src/application/policies/__tests__/branch_sync_notification_policy.test.ts) · [`src/application/usecases/actions/__tests__/observe_branch_sync_use_case.test.ts`](../src/application/usecases/actions/__tests__/observe_branch_sync_use_case.test.ts) · [`src/application/usecases/branch_sync/__tests__/sync_branch_use_case.test.ts`](../src/application/usecases/branch_sync/__tests__/sync_branch_use_case.test.ts) · [`src/application/usecases/__tests__/push_single_action_contexts.test.ts`](../src/application/usecases/__tests__/push_single_action_contexts.test.ts) · [`src/application/usecases/steps/common/__tests__/transition_notification_workflow.test.ts`](../src/application/usecases/steps/common/__tests__/transition_notification_workflow.test.ts) · [`src/data/repository/branch_sync/__tests__/branch_dependency_policy.test.ts`](../src/data/repository/branch_sync/__tests__/branch_dependency_policy.test.ts) · [`src/data/repository/branch_sync/__tests__/branch_dependency_repository.test.ts`](../src/data/repository/branch_sync/__tests__/branch_dependency_repository.test.ts) · [`src/infrastructure/__tests__/branch_sync_workspace_adapter.test.ts`](../src/infrastructure/__tests__/branch_sync_workspace_adapter.test.ts) · [`src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts`](../src/infrastructure/composition/__tests__/push_single_action_capability_port_binding.test.ts) · [`src/application/usecases/branch_sync/__tests__/branch_sync_execution_policy.test.ts`](../src/application/usecases/branch_sync/__tests__/branch_sync_execution_policy.test.ts) · [`src/application/errors/__tests__/application_error.test.ts`](../src/application/errors/__tests__/application_error.test.ts) · [`src/application/policies/__tests__/application_error_presentation_policy.test.ts`](../src/application/policies/__tests__/application_error_presentation_policy.test.ts) · [`src/infrastructure/__tests__/git_commit_adapter.test.ts`](../src/infrastructure/__tests__/git_commit_adapter.test.ts) · [`src/infrastructure/__tests__/branch_sync_sdd_catalog.test.ts`](../src/infrastructure/__tests__/branch_sync_sdd_catalog.test.ts) · [`src/infrastructure/__tests__/branch_sync_generated_bundle_validation.test.ts`](../src/infrastructure/__tests__/branch_sync_generated_bundle_validation.test.ts) · [`src/application/policies/__tests__/branch_sync_lifecycle_recovery.test.ts`](../src/application/policies/__tests__/branch_sync_lifecycle_recovery.test.ts) · [`src/infrastructure/__tests__/branch_sync_resolved_workspace.test.ts`](../src/infrastructure/__tests__/branch_sync_resolved_workspace.test.ts) · [`src/infrastructure/__tests__/branch_sync_communication_budget.test.ts`](../src/infrastructure/__tests__/branch_sync_communication_budget.test.ts) · [`src/application/usecases/actions/__tests__/retire_branch_sync_use_case.test.ts`](../src/application/usecases/actions/__tests__/retire_branch_sync_use_case.test.ts) · [`src/application/usecases/__tests__/pull_request_use_case.test.ts`](../src/application/usecases/__tests__/pull_request_use_case.test.ts) · [`src/actions/__tests__/common_action.test.ts`](../src/actions/__tests__/common_action.test.ts) · [`src/actions/__tests__/github_action.test.ts`](../src/actions/__tests__/github_action.test.ts) · [`src/tooling/__tests__/validate_workflow_contract.test.ts`](../src/tooling/__tests__/validate_workflow_contract.test.ts) · [`src/data/repository/__tests__/reply_request_repository.test.ts`](../src/data/repository/__tests__/reply_request_repository.test.ts) · [`src/infrastructure/composition/__tests__/reply_request_composition_root.test.ts`](../src/infrastructure/composition/__tests__/reply_request_composition_root.test.ts) · [`src/application/policies/__tests__/verification_runtime_policy.test.ts`](../src/application/policies/__tests__/verification_runtime_policy.test.ts) · [`src/infrastructure/__tests__/verification_runtime_preflight.test.ts`](../src/infrastructure/__tests__/verification_runtime_preflight.test.ts) · [`src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts`](../src/infrastructure/__tests__/verification_runtime_branch_sync.test.ts) · [`src/infrastructure/__tests__/untrusted_command_environment.test.ts`](../src/infrastructure/__tests__/untrusted_command_environment.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts) · [`src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts`](../src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts) · [`src/tooling/__tests__/verification_runtime_guidance.test.ts`](../src/tooling/__tests__/verification_runtime_guidance.test.ts) · [`src/application/policies/__tests__/verification_setup_policy.test.ts`](../src/application/policies/__tests__/verification_setup_policy.test.ts) · [`src/infrastructure/__tests__/verification_setup_snapshot.test.ts`](../src/infrastructure/__tests__/verification_setup_snapshot.test.ts) · [`src/infrastructure/__tests__/verification_setup_runner.test.ts`](../src/infrastructure/__tests__/verification_setup_runner.test.ts) · [`src/infrastructure/__tests__/verification_setup_configuration.test.ts`](../src/infrastructure/__tests__/verification_setup_configuration.test.ts) · [`src/infrastructure/__tests__/verification_setup_sync.test.ts`](../src/infrastructure/__tests__/verification_setup_sync.test.ts) · [`src/infrastructure/__tests__/native_verification_runner.test.ts`](../src/infrastructure/__tests__/native_verification_runner.test.ts) · [`src/infrastructure/__tests__/native_verification_protocol.test.ts`](../src/infrastructure/__tests__/native_verification_protocol.test.ts) · [`src/infrastructure/__tests__/native_verification_controller.test.ts`](../src/infrastructure/__tests__/native_verification_controller.test.ts) · [`src/infrastructure/__tests__/native_verification_redaction.test.ts`](../src/infrastructure/__tests__/native_verification_redaction.test.ts) · [`src/infrastructure/__tests__/native_verification_workflow.test.ts`](../src/infrastructure/__tests__/native_verification_workflow.test.ts) · [`src/infrastructure/__tests__/native_verification_profiles.test.ts`](../src/infrastructure/__tests__/native_verification_profiles.test.ts) · [`src/infrastructure/__tests__/verification_executable.test.ts`](../src/infrastructure/__tests__/verification_executable.test.ts) · [`src/infrastructure/__tests__/native_verification_post.test.ts`](../src/infrastructure/__tests__/native_verification_post.test.ts) · [`src/infrastructure/__tests__/native_verification_source_runtime.test.ts`](../src/infrastructure/__tests__/native_verification_source_runtime.test.ts) · [`src/domain/__tests__/copilot_comment_workflow.test.ts`](../src/domain/__tests__/copilot_comment_workflow.test.ts) - User documentation: [`docs/issues/branch-synchronization.mdx`](../docs/issues/branch-synchronization.mdx) · [`docs/issues/comment-commands.mdx`](../docs/issues/comment-commands.mdx) · [`docs/issues/notifications-and-auto-close.mdx`](../docs/issues/notifications-and-auto-close.mdx) · [`docs/development/architecture.mdx`](../docs/development/architecture.mdx) · [`docs/security-operations/operations/verification.mdx`](../docs/security-operations/operations/verification.mdx) · [`docs/security-operations/operations/troubleshooting.mdx`](../docs/security-operations/operations/troubleshooting.mdx) · [`docs/agents/repository-collaboration.mdx`](../docs/agents/repository-collaboration.mdx) ### `pull-request-lifecycle` — Pull request lifecycle and enrichment diff --git a/specs/catalog.json b/specs/catalog.json index ff5fdc794..ccbaae8a8 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -943,7 +943,9 @@ "src/application/ports/bugbot_git_ports.ts", "src/application/usecases/steps/commit/bugbot/commit_and_push_preflight.ts", "src/application/usecases/steps/commit/bugbot/verify_command_runner.ts", - "src/cli/setup_config_file.ts" + "src/cli/setup_config_file.ts", + "src/domain/copilot_comment_workflow.ts", + "src/infrastructure/copilot_comment_inputs.json" ], "tests": [ "src/data/repository/__tests__/repository_version_tags_query_repository.test.ts", @@ -1074,7 +1076,8 @@ "src/application/usecases/steps/commit/bugbot/__tests__/verify_command_runner.test.ts", "src/application/usecases/steps/commit/bugbot/__tests__/commit_verification_workspace.test.ts", "src/tooling/__tests__/verification_runtime_guidance.test.ts", - "src/infrastructure/__tests__/verification_setup_configuration.test.ts" + "src/infrastructure/__tests__/verification_setup_configuration.test.ts", + "src/domain/__tests__/copilot_comment_workflow.test.ts" ], "documentation": [ "README.md", @@ -1978,7 +1981,10 @@ ".github/workflows/copilot_issue.yml", "setup/workflows/copilot_issue.yml", "setup/workflows/copilot_issue_comment.yml", - "setup/workflows/copilot_pull_request_comment.yml" + "setup/workflows/copilot_pull_request_comment.yml", + ".github/workflows/copilot_comment_runtime.yml", + ".github/workflows/copilot_issue_comment.yml", + ".github/workflows/copilot_pull_request_comment.yml" ], "entrypoints": [ "src/application/usecases/branch_sync/sync_branch_use_case.ts", @@ -2042,7 +2048,10 @@ "scripts/generate-native-verification-workflows.cjs", "src/infrastructure/verification_executable.ts", "src/infrastructure/native_verification_source_runtime.ts", - "scripts/prepare-native-source-action.cjs" + "scripts/prepare-native-source-action.cjs", + "src/domain/copilot_comment_workflow.ts", + "src/infrastructure/copilot_comment_inputs.json", + "scripts/validate-comment-workflows.cjs" ], "tests": [ "src/application/policies/__tests__/branch_sync_notification_policy.test.ts", @@ -2090,7 +2099,8 @@ "src/infrastructure/__tests__/native_verification_profiles.test.ts", "src/infrastructure/__tests__/verification_executable.test.ts", "src/infrastructure/__tests__/native_verification_post.test.ts", - "src/infrastructure/__tests__/native_verification_source_runtime.test.ts" + "src/infrastructure/__tests__/native_verification_source_runtime.test.ts", + "src/domain/__tests__/copilot_comment_workflow.test.ts" ], "documentation": [ "docs/issues/branch-synchronization.mdx", diff --git a/specs/repository-verification-setup-hooks.md b/specs/repository-verification-setup-hooks.md index 8bc3851e2..fc2ea8e89 100644 --- a/specs/repository-verification-setup-hooks.md +++ b/specs/repository-verification-setup-hooks.md @@ -1,14 +1,14 @@ # Repository-owned native verification setup - Status: Ready for implementation -- Date: 2026-10-21 +- Date: 2026-10-22 - Catalog capability ID: branch-synchronization -- Last verified: 2026-10-21 +- Last verified: 2026-10-22 - Owners: Copilot maintainers - Scope: Prepare authorized repository verification through a trusted native composite action, without editing generated workflows. - Related issues/PRs: [#647](https://github.com/vypdev/copilot/issues/647), [#652](https://github.com/vypdev/copilot/pull/652) - Required review gates: product UX, architecture, testing, documentation, security/operations -- Open decisions blocking readiness: none; the maintainer selected a same-job composite action on 2026-10-21. +- Open decisions blocking readiness: none; the maintainer selected a same-job composite dependency action on 2026-10-21 and centralized reusable-workflow coordination on 2026-10-22. ## 1. Executive summary @@ -19,7 +19,7 @@ Authorized operation -> prepare candidate -> native composite setup -> credential-free runtime preflight -> verification -> publication guards -> push ``` -This replaces the unreleased Node ESM prototype in PR #652. There is no custom YAML interpreter and no reusable-workflow candidate transport. +This replaces the unreleased Node ESM prototype in PR #652. There is no custom YAML interpreter or cross-job candidate transport. A Copilot-owned reusable workflow encapsulates the complete same-job coordination; the dependency action remains consumer-owned and composite. ## 2. Problem, current behavior, and evidence @@ -153,13 +153,13 @@ The 20-command limit, five-minute native setup timeout, snapshot/result/path bou ### 8.2 Contracts, state, and trust boundaries -The session contains bounded non-secret metadata and private operational logs. Worker stdout/stderr redact configured secrets and dynamic masking commands before bytes reach disk; PAT/model credentials are never serialized as log content. Credentials remain in the admitted worker's memory/environment as in the existing Action; child verifier environments remain allowlisted. Session provenance, request UUIDs and one-use responses prevent accidental replay across jobs/candidates. Root Action post-job cleanup owns cancellation and private directory removal. Source callbacks MUST copy their Action manifest, bundled runtime and setup assets outside the mutable candidate before execution; their continuations and post steps use that snapshot. Remote installed Actions already have an independent runner cache. Post hooks run only for the native callback phases, preserving ordinary direct Action behavior. Dependency-only profiles remain private until nested native post steps finish, then the original Action post step removes them; no later verifier reuses them. No artifacts or remote checkpoints are created. +The session contains bounded non-secret metadata and private operational logs. Worker stdout/stderr redact configured secrets and dynamic masking commands before bytes reach disk; PAT/model credentials are never serialized as log content. Credentials remain in the admitted worker's memory/environment as in the existing Action; child verifier environments remain allowlisted. Session provenance, request UUIDs and one-use responses prevent accidental replay across jobs/candidates. Root Action post-job cleanup owns cancellation and private directory removal. The reusable coordinator MUST use GitHub self-repository `$/` references for its initial Action and every continuation/post registration. GitHub resolves these to the called workflow repository and exact commit in its independent Action cache, including when the caller pins a full SHA; candidate files cannot replace this runtime. No second independently moving Action version is permitted. The standalone native acceptance fixture retains its explicitly owned source snapshot. Post hooks run only for the native callback phases, preserving ordinary direct Action behavior. Dependency-only profiles remain private until nested native post steps finish, then the original Action post step removes them; no later verifier reuses them. No artifacts or remote checkpoints are created. The workflow's fixed native phases support at most 20 setup boundaries per operation. Worker log forwarding preserves complete runner-command lines, with a 1-MiB single-line memory bound; this is distinct from native setup logs. Worker outputs are bounded to 256 KiB. ### 8.3 Executable architecture constraints -Existing architecture/dependency tests remain mandatory. The workflow validator MUST compare all native setup/continue/finish steps with the canonical generator, including conditions, timeout, runtime-only env and consistent Action reference/inputs. Source and distributed callbacks MUST agree. All six existing configuration callbacks retain explicit opt-in forwarding. +Existing architecture/dependency tests remain mandatory. The workflow validator MUST compare the central reusable workflow and compact source/distributed callers with the canonical generator, including events, bot/fork admission, explicit secret bindings, permissions, runner routing, conditions, timeout, runtime-only env and same-commit Action references/inputs. All six existing configuration callbacks retain explicit opt-in forwarding. ## 9. UI/UX and content contract @@ -200,7 +200,7 @@ Native setup steps have `timeout-minutes: 5`; the worker also rejects readiness ## 11. Security, permissions, and privacy -Native setup receives only runtime metadata from the private verifier environment, never Copilot's PAT/model inputs or evidence token. Generated workflows MUST keep provider secrets scoped to the initial Copilot Action step, not the job or consumer action. Checkout credentials remain unpersisted. Native actions can use runner facilities required for normal Actions execution; they are reviewed executable maintainer code. +Native setup receives only runtime metadata from the private verifier environment, never Copilot's PAT/model inputs or evidence token. Callers MUST explicitly forward the existing named Secrets to the reusable workflow; unrestricted `secrets: inherit` is not generated. The coordinator MUST keep provider secrets scoped to the initial Copilot Action step, not the job or consumer action. Checkout credentials remain unpersisted. Native actions can use runner facilities required for normal Actions execution; they are reviewed executable maintainer code. This preserves the trusted-runner boundary and makes no OS-sandbox claim: same-user processes and service-level credentials remain an operator trust concern. PATH/JAVA_HOME are validated after setup; arbitrary `GITHUB_ENV` keys do not enter the verifier. Native external action versions and dependency caches are maintained by the repository owner. Nested local `uses` is excluded because its deferred post scripts could otherwise refer to candidate assets outside the trusted staging tree. @@ -223,7 +223,7 @@ Existing installations remain disabled by default. The unreleased `.copilot/veri ## 14. Testing strategy and numeric budget -Minimum **150 distinct automated cases**, allocated without double counting: +Minimum **190 distinct automated cases**, allocated without double counting: | Area | Minimum | Risk | |---|---:|---| @@ -231,10 +231,10 @@ Minimum **150 distinct automated cases**, allocated without double counting: | Trusted snapshot/assets | 22 | Pinning, hashes, file modes, malformed/native metadata | | Native protocol/controller | 36 | Lifecycle, output framing, replay, timeout, cancellation | | Candidate/runner orchestration | 24 | Ordering, fresh profiles, candidate identity, failure gates | -| Workflows/setup contracts | 18 | Native step structure, env, limits, source/distribution, preservation | +| Workflows/setup contracts | 58 | Native step structure, env, limits, source/distribution, preservation | | Real Git/composition integration | 8 | Exact managed ref, merge manifests, abort/push guards | | Runtime result filesystem security | 12 | Bounds, links, containment, races, owned staging | -| **Total** | **150** | Native rewrite adds at least 70 cases beyond retained applicable baseline | +| **Total** | **190** | Native rewrite adds at least 70 cases beyond retained applicable baseline | Repository-wide thresholds remain in force. New pure policy targets 100% branches; changed setup adapters target aggregate 95% lines/statements and 90% branches/functions. Deterministic unit fakes cover runner responses without interpreting YAML. Separate native CI acceptance MUST execute real composite `uses`/`run` steps with Python/pytest and Node/pnpm on hosted Linux, Windows and macOS, asserting candidate changes, trusted-source selection, fresh profiles candidate preservation, source-runtime immutability even after candidate bundle changes, and final post cleanup. Controlled local Git acceptance covers the exact same managed branch and no release. Native CI evidence is additional to the distinct Jest budget. @@ -289,3 +289,15 @@ Repository-wide thresholds remain in force. New pure policy targets 100% branche ## 20. References and decisions The maintainer selected the composite approach in the task on 2026-10-21. [Issue decision record](https://github.com/vypdev/copilot/issues/647#issuecomment-6318551564). Related contracts: `branch-synchronization`, repository verification prerequisites and the shared automated commit pipeline in the specification catalog. A reusable workflow and a Node ESM helper were rejected for this delivery; no second execution mode is retained. + + +### 20.1 Central comment coordinator — issue #662 + +The [coordinator companion](./copilot-comment-workflow-coordinator.md) owns the +incremental 40-case encapsulation contract. Source and installed callbacks call +one Copilot-owned workflow; the whole operation remains in one job. The consumer +dependency action remains composite. The companion defines compact callers, +same-commit self references, named Secret isolation, unchanged timeout/cleanup +behavior, safe runner migration, effective configuration inspection, platform +prerequisites, docs and rollout. This document retains the verifier and trusted +setup execution contract; no cross-job candidate transport is introduced. diff --git a/specs/setup-runner-profiles-and-installation-parity.md b/specs/setup-runner-profiles-and-installation-parity.md index d309e5f26..8b6f35660 100644 --- a/specs/setup-runner-profiles-and-installation-parity.md +++ b/specs/setup-runner-profiles-and-installation-parity.md @@ -507,3 +507,32 @@ isolated fixed version probes and safe blocked recovery. Runner selection does n install project language tools. Existing consumers without the declaration retain legacy verification. This companion owns its shared incremental numeric test budget; do not count it twice across the setup and synchronization capabilities. + + +## Compact comment coordinator amendment — issue #662 + +Comment callbacks now delegate their complete job to the Copilot-owned reusable +workflow specified in [comment coordinator](./copilot-comment-workflow-coordinator.md). +Their reviewed route is serialized in `with.runs-on` JSON instead of a native +job `runs-on` key. The pure `copilot_comment_workflow` contract recognizes only +the known versioned coordinator and the exact source self-repository reference; +YAML and workspace adapters retain parsing, migration, preview and Apply. + +Setup MUST retain scalar/label/group routes from both old native jobs and new +coordinator calls, apply explicit profile precedence, show the same per-role +routing in review, and write exactly the reviewed YAML. Dynamic or malformed +runner input MUST block rather than fall back. Source self-repository callbacks +remain complete source-owned assets. Custom legacy bootstrap steps MUST require +reviewed migration before switching job shapes; no steps may silently disappear. +Known reusable installation inspection MUST preserve effective Variable/default +and literal override semantics without reading Secret values or claiming an +unverified local Action identity. Runner 2.336.0+ and GitHub platform support are +additional coordinator prerequisites, not evidence of access or capacity. + +Verification maps these requirements to the new pure contract cases, comment +upgrade cases, installation reader cases and preview/Apply parity fixture. Their +shared incremental **40-case** budget is owned by the native-setup amendment and +is not counted twice here. Existing role isolation, coverage gates, receipts, +backup and recovery remain unchanged. Update verification, upgrade and runner +operations docs, regenerate catalog evidence/bundles, and pass all validators +before publication. diff --git a/src/domain/__tests__/copilot_comment_workflow.test.ts b/src/domain/__tests__/copilot_comment_workflow.test.ts new file mode 100644 index 000000000..daa4e24ef --- /dev/null +++ b/src/domain/__tests__/copilot_comment_workflow.test.ts @@ -0,0 +1,35 @@ +import { copilotCommentRunner, isCopilotCommentWorkflow, isCopilotCommentRunner, COPILOT_COMMENT_REMOTE_WORKFLOW, COPILOT_COMMENT_SELF_WORKFLOW } from '../copilot_comment_workflow'; + +describe('known comment coordination and runner contract', () => { + it.each([COPILOT_COMMENT_REMOTE_WORKFLOW, COPILOT_COMMENT_SELF_WORKFLOW, + 'vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3.10.0', + `vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@${'a'.repeat(40)}`])('recognizes the reviewed workflow %s', value => { + expect(isCopilotCommentWorkflow(value)).toBe(true); + }); + it.each([undefined, 42, './', 'vypdev/copilot@v3', 'other/copilot/.github/workflows/copilot_comment_runtime.yml@v3', + 'vypdev/copilot/.github/workflows/other.yml@v3', 'vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@master', + 'vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v4'])('does not interpret arbitrary workflow inputs as a runner: %s', value => { + expect(isCopilotCommentWorkflow(value)).toBe(false); + }); + it('retains ordinary native-job routing', () => { + expect(copilotCommentRunner({ 'runs-on': ['self-hosted', 'Linux'] })).toEqual(['self-hosted', 'Linux']); + expect(copilotCommentRunner(undefined)).toBeUndefined(); + }); + it.each(['ubuntu-latest', ['self-hosted', 'codex', 'Linux'], { group: 'trusted', labels: ['self-hosted', 'Linux'] }])('reads the exact reusable route %j', route => { + expect(copilotCommentRunner({ uses: COPILOT_COMMENT_REMOTE_WORKFLOW, with: { 'runs-on': JSON.stringify(route) } })).toEqual(route); + }); + it.each([undefined, {}, { 'runs-on': 42 }, { 'runs-on': 'invalid json' }, { 'runs-on': 'null' }])('blocks missing or malformed reusable routing %j', inputs => { + expect(() => copilotCommentRunner({ uses: COPILOT_COMMENT_REMOTE_WORKFLOW, with: inputs })).toThrow('review the workflow'); + }); + it.each(['ubuntu-latest', ['self-hosted', 'Linux'], { group: 'trusted' }, { labels: 'ubuntu-latest' }, { labels: ['self-hosted', 'macOS'] }])('accepts literal supported routing %j', route => { + expect(isCopilotCommentRunner(route)).toBe(true); + }); + it.each([undefined, null, true, 42, '', ' leading', 'trailing ', '${{ matrix.os }}', 'x'.repeat(101), 'line\nbreak', + [], [''], ['Linux', 'linux'], Array.from({ length: 11 }, (_, index) => `label-${index}`), ['good', 42], {}, + { group: undefined }, { unknown: 'route' }, { group: '' }, { group: 'trusted', labels: [] }, { labels: true }])('rejects invalid or ambiguous routing %j', route => { + expect(isCopilotCommentRunner(route)).toBe(false); + }); + it('rejects oversized JSON before parsing it', () => { + expect(() => copilotCommentRunner({ uses: COPILOT_COMMENT_REMOTE_WORKFLOW, with: { 'runs-on': ' '.repeat(16_001) } })).toThrow('review'); + }); +}); diff --git a/src/domain/copilot_comment_workflow.ts b/src/domain/copilot_comment_workflow.ts new file mode 100644 index 000000000..66bb3c8d0 --- /dev/null +++ b/src/domain/copilot_comment_workflow.ts @@ -0,0 +1,39 @@ +/** The comment coordinator is a versioned Copilot workflow, not an arbitrary reusable job. */ +export const COPILOT_COMMENT_RUNTIME = 'copilot_comment_runtime.yml'; +export const COPILOT_COMMENT_SELF_WORKFLOW = `$/.github/workflows/${COPILOT_COMMENT_RUNTIME}`; +export const COPILOT_COMMENT_REMOTE_WORKFLOW = `vypdev/copilot/.github/workflows/${COPILOT_COMMENT_RUNTIME}@v3`; + +export function isCopilotCommentWorkflow(value: unknown): value is string { + return typeof value === 'string' && (value === COPILOT_COMMENT_SELF_WORKFLOW + || /^vypdev\/copilot\/\.github\/workflows\/copilot_comment_runtime\.yml@(?:v3(?:\.[0-9]+\.[0-9]+)?|[a-f0-9]{40})$/u.test(value)); +} + +const literal = (value: unknown): value is string => typeof value === 'string' && value.length > 0 && value.length <= 100 + && value === value.trim() && !/[\p{Cc}\p{Cf}${}<>]/u.test(value); +const labels = (value: unknown): boolean => literal(value) || Array.isArray(value) && value.length > 0 && value.length <= 10 + && value.every(literal) && new Set(value.map(label => label.toLowerCase())).size === value.length; + +/** Runner routing is literal data; expressions need their original full workflow reviewed. */ +export function isCopilotCommentRunner(value: unknown): boolean { + if (labels(value)) return true; + if (!value || typeof value !== 'object' || Array.isArray(value)) return false; + const route = value as Record; + const keys = Object.keys(route); + return keys.length > 0 && (route.group !== undefined || route.labels !== undefined) + && keys.every(key => key === 'group' || key === 'labels') + && (route.group === undefined || literal(route.group)) + && (route.labels === undefined || labels(route.labels)); +} + +export function copilotCommentRunner(job: Record | undefined): unknown { + if (!job || !isCopilotCommentWorkflow(job.uses)) return job?.['runs-on']; + const inputs = job.with as Record | undefined; + if (typeof inputs?.['runs-on'] !== 'string') throw new Error('Comment workflow runner JSON is unavailable; review the workflow separately.'); + try { + if (inputs['runs-on'].length > 16_000) throw new Error('Runner JSON exceeds its bound.'); + const route: unknown = JSON.parse(inputs['runs-on']); + if (!isCopilotCommentRunner(route)) throw new Error('Unsupported execution route.'); + return route; + } + catch { throw new Error('Comment workflow runner JSON is invalid; review the workflow separately.'); } +} diff --git a/src/infrastructure/__tests__/native_verification_workflow.test.ts b/src/infrastructure/__tests__/native_verification_workflow.test.ts index a127183ad..9389b4aaf 100644 --- a/src/infrastructure/__tests__/native_verification_workflow.test.ts +++ b/src/infrastructure/__tests__/native_verification_workflow.test.ts @@ -2,32 +2,93 @@ import fs from 'node:fs'; import path from 'node:path'; import { load } from 'js-yaml'; const { assertNativeVerificationWorkflow } = require('../../../scripts/validate-workflow-contract.cjs') as { assertNativeVerificationWorkflow(file: string, workflow: any): void }; -const { MAX_REQUESTS, phaseSteps } = require('../../../scripts/generate-native-verification-workflows.cjs') as {MAX_REQUESTS: number; phaseSteps(action: string): any[]}; +const { MAX_REQUESTS, phaseSteps, RUNTIME, SELF_ACTION, runtimeWorkflow } = require('../../../scripts/generate-native-verification-workflows.cjs') as { + MAX_REQUESTS: number; phaseSteps(action: string): any[]; RUNTIME: string; SELF_ACTION: string; runtimeWorkflow(): any; +}; +const read = (directory: string, name: string): {file: string; workflow: any} => { + const file = path.join(process.cwd(), directory, name); + return { file, workflow: load(fs.readFileSync(file, 'utf8')) }; +}; -describe('native verification workflow contract', () => { - it.each(['.github/workflows', 'setup/workflows'])('parses canonical native YAML and anchors from %s', directory => { - for (const name of ['copilot_issue_comment.yml', 'copilot_pull_request_comment.yml']) { - const file = path.join(process.cwd(), directory, name); const workflow = load(fs.readFileSync(file, 'utf8')); +describe('encapsulated native verification workflow contract', () => { + it.each(['.github/workflows', 'setup/workflows'].flatMap(directory => ['copilot_issue_comment.yml', 'copilot_pull_request_comment.yml'].map(name => [directory, name])))( + 'keeps %s/%s as one compact call without phase or credential environment leakage', (directory, name) => { + const { file, workflow } = read(directory, name); expect(() => assertNativeVerificationWorkflow(file, workflow)).not.toThrow(); - } + expect(fs.readFileSync(file, 'utf8').split('\n').length).toBeLessThanOrEqual(35); + const job = Object.values(workflow.jobs)[0] as any; + expect(job.steps).toBeUndefined(); expect(job.env).toBeUndefined(); + expect(job.secrets.PAT).toBe('${{ secrets.PAT }}'); + }); + it('parses the single central native workflow including shared input anchors', () => { + const { file, workflow } = read('.github/workflows', RUNTIME); + expect(workflow).toEqual(runtimeWorkflow()); + expect(() => assertNativeVerificationWorkflow(file, workflow)).not.toThrow(); + }); + it.each(['.github/workflows', 'setup/workflows'])('accepts a reviewed group route in %s without changing other boundaries', directory => { + const { file, workflow } = read(directory, 'copilot_issue_comment.yml'); + const job = Object.values(workflow.jobs)[0] as any; + job.with['runs-on'] = JSON.stringify({ group: 'trusted', labels: ['self-hosted', 'codex', 'Linux'] }); + expect(() => assertNativeVerificationWorkflow(file, workflow)).not.toThrow(); + }); + it('rejects source routing that loses its agent role', () => { + const { file, workflow } = read('.github/workflows', 'copilot_issue_comment.yml'); + const job = Object.values(workflow.jobs)[0] as any; + job.with['runs-on'] = JSON.stringify(['self-hosted', 'unrelated']); + expect(() => assertNativeVerificationWorkflow(file, workflow)).toThrow('codex role'); }); - it('has exactly twenty native setup slots and one completion, with five-minute native timeouts', () => { - const steps = phaseSteps('./'); expect(MAX_REQUESTS).toBe(20); expect(steps).toHaveLength(41); + it('retains twenty setup slots, five-minute native cancellation and a final cleanup', () => { + const steps = phaseSteps(SELF_ACTION); expect(MAX_REQUESTS).toBe(20); expect(steps).toHaveLength(41); expect(steps.filter(step => step.uses === './.git/copilot-verification-setup').every(step => step['timeout-minutes'] === 5)).toBe(true); + expect(steps.at(-1).env.COPILOT_NATIVE_PHASE).toBe('finish'); + expect(steps.at(-1).if).toContain('always()'); }); - it.each(['timeout', 'env', 'condition', 'reference', 'request', 'outcome', 'finish', 'extra', 'remove', 'prepare'])('rejects a weakened %s contract', kind => { - const file = path.join(process.cwd(), 'setup/workflows/copilot_issue_comment.yml'); const workflow = load(fs.readFileSync(file, 'utf8')) as any; - const job = Object.values(workflow.jobs)[0] as any; const start = job.steps.findIndex((step: any) => step.id === 'copilot'); const steps = job.steps; - if (kind === 'timeout') steps[start + 1]['timeout-minutes'] = 60; - if (kind === 'env') steps[start + 1].env.OPENAI_API_KEY = '${{ secrets.OPENAI_API_KEY }}'; - if (kind === 'condition') steps[start + 1].if = '${{ always() }}'; - if (kind === 'reference') steps[start + 2].uses = 'vypdev/copilot@other'; - if (kind === 'request') steps[start + 2].env.COPILOT_NATIVE_REQUEST = 'stale'; - if (kind === 'outcome') steps[start + 2].env.COPILOT_NATIVE_OUTCOME = 'success'; - if (kind === 'finish') steps[steps.length - 1].if = '${{ success() }}'; - if (kind === 'extra') steps.push({run: 'echo bypass'}); - if (kind === 'remove') steps.splice(start + 1, 2); - if (kind === 'prepare') delete steps[start].env.COPILOT_NATIVE_PHASE; - expect(() => assertNativeVerificationWorkflow(file, workflow)).toThrow(/native/u); + it('binds every phase to the called workflow commit without a second version or mutable checkout', () => { + const workflow = runtimeWorkflow(); const phases = workflow.jobs.copilot.steps.filter((step: any) => step.uses === SELF_ACTION); + expect(phases).toHaveLength(22); + expect(phases.every((step: any) => step.with === phases[0].with)).toBe(true); + expect(JSON.stringify(workflow)).not.toContain('vypdev/copilot@'); + expect(JSON.stringify(workflow)).not.toContain('COPILOT_NATIVE_RUNTIME_CACHE'); + }); + it('scopes provider credentials to the initial phase and keeps setup runtime-only', () => { + const job = runtimeWorkflow().jobs.copilot; + expect(JSON.stringify(job.env)).not.toContain('secrets.'); + const credentialSteps = job.steps.filter((step: any) => Object.values(step.env ?? {}).some(value => String(value).includes('secrets.'))); + expect(credentialSteps.map((step: any) => step.id)).toEqual(['copilot']); + for (const step of job.steps.filter((step: any) => step.uses === './.git/copilot-verification-setup')) { + expect(step.with).toBeUndefined(); + expect(Object.keys(step.env).sort()).toEqual(['HOME', 'USERPROFILE', 'APPDATA', 'LOCALAPPDATA', 'PATH', 'JAVA_HOME', 'TMP', 'TEMP', 'TMPDIR'].sort()); + } }); + it.each(['timeout', 'env', 'condition', 'reference', 'request', 'outcome', 'finish', 'extra', 'remove', 'prepare', 'initial-source', 'credential-scope'])( + 'rejects a weakened central %s contract', kind => { + const { file, workflow } = read('.github/workflows', RUNTIME); + const steps = workflow.jobs.copilot.steps; const start = steps.findIndex((step: any) => step.id === 'copilot'); + if (kind === 'timeout') steps[start + 1]['timeout-minutes'] = 60; + if (kind === 'env') steps[start + 1].env.OPENAI_API_KEY = '${{ secrets.OPENAI_API_KEY }}'; + if (kind === 'condition') steps[start + 1].if = '${{ always() }}'; + if (kind === 'reference') steps[start + 2].uses = 'vypdev/copilot@other'; + if (kind === 'request') steps[start + 2].env.COPILOT_NATIVE_REQUEST = 'stale'; + if (kind === 'outcome') steps[start + 2].env.COPILOT_NATIVE_OUTCOME = 'success'; + if (kind === 'finish') steps.at(-1).if = '${{ success() }}'; + if (kind === 'extra') steps.push({ run: 'echo bypass' }); + if (kind === 'remove') steps.splice(start + 1, 2); + if (kind === 'prepare') delete steps[start].env.COPILOT_NATIVE_PHASE; + if (kind === 'initial-source') steps[start].uses = './'; + if (kind === 'credential-scope') workflow.jobs.copilot.env.OPENAI_API_KEY = '${{ secrets.OPENAI_API_KEY }}'; + expect(() => assertNativeVerificationWorkflow(file, workflow)).toThrow(/native/u); + }); + it.each(['steps', 'env', 'permissions', 'secrets', 'reference', 'events', 'gate', 'runner'])( + 'rejects a caller that changes the %s boundary', kind => { + const { file, workflow } = read('setup/workflows', 'copilot_pull_request_comment.yml'); const job = workflow.jobs['copilot-pull-requests']; + if (kind === 'steps') job.steps = [{ run: 'true' }]; + if (kind === 'env') job.env = { OPENAI_API_KEY: '${{ secrets.OPENAI_API_KEY }}' }; + if (kind === 'permissions') job.permissions.actions = 'write'; + if (kind === 'secrets') job.secrets = 'inherit'; + if (kind === 'reference') job.uses = job.uses.replace('@v3', '@master'); + if (kind === 'events') workflow.on.pull_request_review_comment.types = ['created']; + if (kind === 'gate') job.if = '${{ always() }}'; + if (kind === 'runner') job.with['runs-on'] = 'not-json'; + expect(() => assertNativeVerificationWorkflow(file, workflow)).toThrow(/native/u); + }); }); diff --git a/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts b/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts index 6335523e1..501970d55 100644 --- a/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts +++ b/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts @@ -2,6 +2,7 @@ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, symlinkSync } from 'node import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { SetupManagementWorkspaceAdapter } from '../setup_management_workspace_adapter'; +import { COPILOT_COMMENT_REMOTE_WORKFLOW, COPILOT_COMMENT_SELF_WORKFLOW } from '../../domain/copilot_comment_workflow'; const roots: string[] = []; function fixture(source?: string) { const root = mkdtempSync(join(tmpdir(), 'copilot-management-')); roots.push(root); const directory = join(root, '.github', 'workflows'); mkdirSync(directory, { recursive: true }); if (source !== undefined) writeFileSync(join(directory, 'copilot.yml'), source); return { root, directory, adapter: new SetupManagementWorkspaceAdapter(root, () => 'revision-a') }; } const workflow = (inputs: string, extra = '') => `name: Copilot @@ -77,3 +78,36 @@ test('multiple local workflows retain the same Action evidence and all input bin writeFileSync(join(f.root,'action.yml'), 'name: Copilot - GitHub with super powers\ninputs:\n bugbot-comment-limit: {default: 20}\n'); expect(f.adapter.inspect()).toMatchObject({ unreadable:false, localActionDigest:expect.any(String), workflows:[{file:'copilot.yml',action:'./'},{file:'second.yml',action:'./'}] }); }); + +describe('reusable comment installation inspection', () => { + const reusable = (uses = COPILOT_COMMENT_REMOTE_WORKFLOW, inputs = '') => `jobs:\n comments:\n uses: ${uses}\n with:\n runs-on: '"ubuntu-latest"'\n${inputs}\n secrets:\n PAT: \${{ secrets.PAT }}\n`; + test.each(['v3', 'v3.10.0', 'a'.repeat(40)])('reads effective Variable defaults from the known coordinator at %s without copying Secrets', ref => { + const f = fixture(reusable(COPILOT_COMMENT_REMOTE_WORKFLOW.replace('@v3', '@' + ref))); + const result = f.adapter.inspect(); + expect(result.unreadable).toBe(false); + expect(result.workflows[0]).toMatchObject({ action: `vypdev/copilot@${ref}`, inputs: expect.arrayContaining([ + { name: 'bugbot-comment-limit', variable: 'BUGBOT_COMMENT_LIMIT', fallback: '20' }, + { name: 'verification-setup', variable: 'VERIFICATION_SETUP', fallback: 'false' }, + ]) }); + expect(JSON.stringify(result)).not.toContain('secrets.'); expect(result.workflows[0].inputs.some(input => input.name === 'token')).toBe(false); + }); + test('retains explicit and empty caller overrides with their actual precedence', () => { + const f = fixture(reusable(COPILOT_COMMENT_REMOTE_WORKFLOW, " pre-branch-sdd: 'true'\n ai-ignore-files: ''")); + expect(f.adapter.inspect().workflows[0].inputs).toEqual(expect.arrayContaining([ + { name: 'pre-branch-sdd', literal: 'true' }, { name: 'ai-ignore-files', variable: 'AI_IGNORE_FILES', fallback: 'build/*' }, + ])); + }); + test('unknown caller inputs block guessed effective configuration', () => { + expect(fixture(reusable(COPILOT_COMMENT_REMOTE_WORKFLOW, ' unknown-input: true')).adapter.inspect()).toMatchObject({ unreadable: true, workflows: [] }); + }); + test('a self-repository call without known Copilot metadata fails closed', () => { + expect(fixture(reusable(COPILOT_COMMENT_SELF_WORKFLOW)).adapter.inspect()).toMatchObject({ unreadable: true, workflows: [] }); + }); + test('a verified source coordinator binds the local Action metadata and explicit source policy', () => { + const f = fixture(reusable(COPILOT_COMMENT_SELF_WORKFLOW, " pre-branch-sdd: 'true'")); + writeFileSync(join(f.root, 'action.yml'), 'name: Copilot - GitHub with super powers\ninputs:\n bugbot-comment-limit: {default: 20}\n'); + expect(f.adapter.inspect()).toMatchObject({ unreadable: false, localActionDigest: expect.any(String), workflows: [ + { action: './', inputs: expect.arrayContaining([{ name: 'pre-branch-sdd', literal: 'true' }]) }, + ] }); + }); +}); diff --git a/src/infrastructure/__tests__/verification_setup_configuration.test.ts b/src/infrastructure/__tests__/verification_setup_configuration.test.ts index 1f4350a48..2ba87975b 100644 --- a/src/infrastructure/__tests__/verification_setup_configuration.test.ts +++ b/src/infrastructure/__tests__/verification_setup_configuration.test.ts @@ -40,8 +40,17 @@ describe('verification setup installation contract', () => { it.each(['copilot_issue.yml', 'copilot_issue_comment.yml', 'copilot_pull_request.yml', 'copilot_pull_request_comment.yml', 'copilot_pull_request_review_state.yml', 'copilot_commit.yml'])( 'keeps source and distributed %s opt-in explicit and disabled by default', name => { for (const directory of ['.github/workflows', 'setup/workflows']) { - const workflow = yaml.load(fs.readFileSync(path.resolve(__dirname, '../../..', directory, name), 'utf8')) as {jobs: Record}[]}>}; - const actions = Object.values(workflow.jobs).flatMap(job => job.steps).filter(step => step.uses === './' || step.uses === './../.copilot-native-runtime' || step.uses?.startsWith('vypdev/copilot@')); + type Workflow = {jobs: Record; steps?: {uses?: string; with?: Record}[]}>}; + let workflow = yaml.load(fs.readFileSync(path.resolve(__dirname, '../../..', directory, name), 'utf8')) as Workflow; + if (name === 'copilot_issue_comment.yml' || name === 'copilot_pull_request_comment.yml') { + const caller = Object.values(workflow.jobs)[0]; + expect(caller.uses).toBe(directory.startsWith('setup/') + ? 'vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3' + : '$/.github/workflows/copilot_comment_runtime.yml'); + expect(caller.with?.['verification-setup']).toBeUndefined(); + workflow = yaml.load(fs.readFileSync(path.resolve(__dirname, '../../../.github/workflows/copilot_comment_runtime.yml'), 'utf8')) as Workflow; + } + const actions = Object.values(workflow.jobs).flatMap(job => job.steps ?? []).filter(step => step.uses === '$/' || step.uses === './' || step.uses?.startsWith('vypdev/copilot@')); expect(actions.length).toBeGreaterThan(0); for (const action of actions) expect(action.with?.['verification-setup']).toBe("${{ vars.VERIFICATION_SETUP || 'false' }}"); } diff --git a/src/infrastructure/copilot_comment_inputs.json b/src/infrastructure/copilot_comment_inputs.json new file mode 100644 index 000000000..8cdba0db1 --- /dev/null +++ b/src/infrastructure/copilot_comment_inputs.json @@ -0,0 +1,72 @@ +{ + "repository-locale": "${{ vars.REPOSITORY_LOCALE || 'en-US' }}", + "issues-locale": "${{ vars.ISSUES_LOCALE || '' }}", + "pull-requests-locale": "${{ vars.PULL_REQUESTS_LOCALE || '' }}", + "ai-ignore-files": "${{ vars.AI_IGNORE_FILES || 'build/*' }}", + "debug": "${{ vars.DEBUG }}", + "main-branch": "${{ vars.MAIN_BRANCH || 'master' }}", + "development-branch": "${{ vars.DEVELOPMENT_BRANCH || 'develop' }}", + "feature-tree": "${{ vars.FEATURE_TREE || 'feature' }}", + "bugfix-tree": "${{ vars.BUGFIX_TREE || 'bugfix' }}", + "hotfix-tree": "${{ vars.HOTFIX_TREE || 'hotfix' }}", + "release-tree": "${{ vars.RELEASE_TREE || 'release' }}", + "docs-tree": "${{ vars.DOCS_TREE || 'docs' }}", + "chore-tree": "${{ vars.CHORE_TREE || 'chore' }}", + "issue-managed-branches": "${{ vars.ISSUE_MANAGED_BRANCHES || 'true' }}", + "pre-branch-sdd": "${{ vars.PRE_BRANCH_SDD || 'false' }}", + "verification-setup": "${{ vars.VERIFICATION_SETUP || 'false' }}", + "issue-workflow-profile": "${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }}", + "reopen-issue-on-push": "${{ vars.REOPEN_ISSUE_ON_PUSH || 'true' }}", + "desired-assignees-count": "${{ vars.DESIRED_ASSIGNEES_COUNT || '1' }}", + "desired-reviewers-count": "${{ vars.DESIRED_REVIEWERS_COUNT || '1' }}", + "commit-prefix-transforms": "${{ vars.COMMIT_PREFIX_TRANSFORMS || 'replace-slash' }}", + "ai-pull-request-description-mode": "${{ vars.AI_PULL_REQUEST_DESCRIPTION_MODE || 'replace' }}", + "ai-members-only": "${{ vars.AI_MEMBERS_ONLY || 'false' }}", + "ai-include-reasoning": "${{ vars.AI_INCLUDE_REASONING || 'false' }}", + "bugbot-severity": "${{ vars.BUGBOT_SEVERITY || 'low' }}", + "bugbot-comment-limit": "${{ vars.BUGBOT_COMMENT_LIMIT || '20' }}", + "bugbot-fix-verify-commands": "${{ vars.BUGBOT_AUTOFIX_VERIFY_COMMANDS }}", + "bugbot-dry-run": "${{ vars.BUGBOT_DRY_RUN || 'false' }}", + "bugbot-effort": "${{ vars.BUGBOT_EFFORT || 'smart' }}", + "bugbot-review-drafts": "${{ vars.BUGBOT_REVIEW_DRAFTS || 'false' }}", + "bugbot-trace-rules": "${{ vars.BUGBOT_TRACE_RULES || 'false' }}", + "bugbot-suggested-changes": "${{ vars.BUGBOT_SUGGESTED_CHANGES || 'true' }}", + "bugbot-telemetry": "${{ vars.BUGBOT_TELEMETRY || 'true' }}", + "bugbot-fail-on-unresolved": "${{ vars.BUGBOT_FAIL_ON_UNRESOLVED || 'false' }}", + "bugbot-organization-rules": "${{ vars.BUGBOT_ORGANIZATION_RULES }}", + "project-column-issue-created": "${{ vars.PROJECT_COLUMN_ISSUE_CREATED || 'Todo' }}", + "project-column-pull-request-created": "${{ vars.PROJECT_COLUMN_PULL_REQUEST_CREATED || 'In Progress' }}", + "project-column-issue-in-progress": "${{ vars.PROJECT_COLUMN_ISSUE_IN_PROGRESS || 'In Progress' }}", + "project-column-pull-request-in-progress": "${{ vars.PROJECT_COLUMN_PULL_REQUEST_IN_PROGRESS || 'In Progress' }}", + "agent-provider": "${{ vars.AGENT_PROVIDER || 'codex' }}", + "agent-model-provider": "${{ vars.AGENT_MODEL_PROVIDER || 'openai' }}", + "agent-model": "${{ vars.AGENT_MODEL || 'gpt-6-luna' }}", + "agent-effort": "${{ vars.AGENT_EFFORT }}", + "agent-executable": "${{ vars.AGENT_EXECUTABLE }}", + "findings-provider": "${{ vars.FINDINGS_PROVIDER }}", + "findings-model-provider": "${{ vars.FINDINGS_MODEL_PROVIDER }}", + "findings-model": "${{ vars.FINDINGS_MODEL }}", + "findings-effort": "${{ vars.FINDINGS_EFFORT }}", + "findings-executable": "${{ vars.FINDINGS_EXECUTABLE }}", + "fixer-provider": "${{ vars.FIXER_PROVIDER }}", + "fixer-model-provider": "${{ vars.FIXER_MODEL_PROVIDER }}", + "fixer-model": "${{ vars.FIXER_MODEL }}", + "fixer-effort": "${{ vars.FIXER_EFFORT }}", + "fixer-executable": "${{ vars.FIXER_EXECUTABLE }}", + "planner-provider": "${{ vars.PLANNER_PROVIDER }}", + "planner-model-provider": "${{ vars.PLANNER_MODEL_PROVIDER }}", + "planner-model": "${{ vars.PLANNER_MODEL }}", + "planner-effort": "${{ vars.PLANNER_EFFORT }}", + "planner-executable": "${{ vars.PLANNER_EXECUTABLE }}", + "reviewer-provider": "${{ vars.REVIEWER_PROVIDER }}", + "reviewer-model-provider": "${{ vars.REVIEWER_MODEL_PROVIDER }}", + "reviewer-model": "${{ vars.REVIEWER_MODEL }}", + "reviewer-effort": "${{ vars.REVIEWER_EFFORT }}", + "reviewer-executable": "${{ vars.REVIEWER_EXECUTABLE }}", + "tester-provider": "${{ vars.TESTER_PROVIDER }}", + "tester-model-provider": "${{ vars.TESTER_MODEL_PROVIDER }}", + "tester-model": "${{ vars.TESTER_MODEL }}", + "tester-effort": "${{ vars.TESTER_EFFORT }}", + "tester-executable": "${{ vars.TESTER_EXECUTABLE }}", + "project-ids": "${{ vars.PROJECT_IDS }}" +} diff --git a/src/infrastructure/setup_management_workspace_adapter.ts b/src/infrastructure/setup_management_workspace_adapter.ts index 0bf7f2fc3..e7ca8ace4 100644 --- a/src/infrastructure/setup_management_workspace_adapter.ts +++ b/src/infrastructure/setup_management_workspace_adapter.ts @@ -4,6 +4,8 @@ import { createHash } from 'node:crypto'; import { load, JSON_SCHEMA } from 'js-yaml'; import type { SetupInstallation, SetupInstalledWorkflow, SetupInstalledInput } from '../domain/setup_management'; import { redactSensitiveText } from '../domain/security/sensitive_text'; +import { isCopilotCommentWorkflow, COPILOT_COMMENT_SELF_WORKFLOW } from '../domain/copilot_comment_workflow'; +import commentInputs from './copilot_comment_inputs.json'; type Document = Record; type WorkflowStep = { job: Document; step: Document }; @@ -86,12 +88,25 @@ export class SetupManagementWorkspaceAdapter { private inspectWorkflow(file: string, localAction: () => string | undefined): SetupInstalledWorkflow[] { const { source, document } = readDocument(join(this.root, '.github', 'workflows', file)); const steps = workflowSteps(document); + const calls = Object.values(object(document.jobs)).map(object).filter(job => isCopilotCommentWorkflow(job.uses)); + if (calls.some(job => job.uses === COPILOT_COMMENT_SELF_WORKFLOW) && !localAction()) throw new Error('Unverified source comment workflow.'); + const reusable = calls.map(job => { + const overrides = object(job.with); + if (Object.keys(overrides).some(key => !['runs-on', 'issue-managed-branches', 'pre-branch-sdd', 'ai-ignore-files', 'prepare-source-verification'].includes(key))) throw new Error('Unknown comment workflow input.'); + const bindings: Record = { ...commentInputs }; + for (const name of ['issue-managed-branches', 'pre-branch-sdd', 'ai-ignore-files']) { + if (overrides[name] !== undefined && overrides[name] !== '') bindings[name] = overrides[name]; + } + return { file, action: job.uses === COPILOT_COMMENT_SELF_WORKFLOW ? './' : `vypdev/copilot@${String(job.uses).split('@').at(-1)}`, + digest: digest(source), environmentScoped: environmentScoped(document, job, {}), + inputs: Object.entries(bindings).flatMap(([name, value]) => installedInput(name, value)) }; + }); const knownLocalAction = steps.some(({ step }) => step.uses === './') ? Boolean(localAction()) : false; - return steps.flatMap(({ job, step }) => { + return [...reusable, ...steps.flatMap(({ job, step }) => { if (!this.isCopilotStep(step, knownLocalAction)) return []; const inputs = Object.entries(object(step.with)).flatMap(([name, value]) => installedInput(name, value)); return [{ file, action: step.uses as string, digest: digest(source), environmentScoped: environmentScoped(document, job, step), inputs }]; - }); + })]; } private isCopilotStep(step: Document, knownLocalAction: boolean): boolean { diff --git a/src/tooling/__tests__/validate_workflow_contract.test.ts b/src/tooling/__tests__/validate_workflow_contract.test.ts index e050dcb1f..b58e0a72d 100644 --- a/src/tooling/__tests__/validate_workflow_contract.test.ts +++ b/src/tooling/__tests__/validate_workflow_contract.test.ts @@ -154,21 +154,19 @@ describe('workflow contract validator', () => { }); it.each(['issue-managed-branches', 'pre-branch-sdd', 'verification-setup'])( - 'rejects a PR comment callback that omits or disables the installed %s policy', input => { - const { file, workflow } = loadMutationWorkflow('.github/workflows', 'copilot_pull_request_comment.yml'); - const action = workflow.jobs['copilot-pull-requests'].steps.find((step: { id?: string }) => step.id === 'copilot'); + 'rejects a comment coordinator that omits or disables the installed %s policy', input => { + const { file, workflow } = loadMutationWorkflow('.github/workflows', 'copilot_comment_runtime.yml'); + const action = workflow.jobs.copilot.steps.find((step: { id?: string }) => step.id === 'copilot'); delete action.with[input]; - expect(() => assertIssueBranchConfigurationInputs(file, workflow)).toThrow('must pass consistent'); + expect(() => validateWorkflow(file, workflow)).toThrow('native comment runtime'); action.with[input] = false; - expect(() => assertIssueBranchConfigurationInputs(file, workflow)).toThrow('must pass consistent'); + expect(() => validateWorkflow(file, workflow)).toThrow('native comment runtime'); }, ); it('rejects a distributed callback that enables the SDD gate instead of inheriting its configured default', () => { const { file, workflow } = loadMutationWorkflow('setup/workflows', 'copilot_pull_request_comment.yml'); - const action = workflow.jobs['copilot-pull-requests'].steps.find( - (step: { uses?: string }) => step.uses?.startsWith('vypdev/copilot@'), - ); + const action = workflow.jobs['copilot-pull-requests']; action.with['pre-branch-sdd'] = "${{ vars.PRE_BRANCH_SDD || 'true' }}"; expect(() => assertIssueBranchConfigurationInputs(file, workflow)).toThrow('must pass consistent'); }); @@ -193,7 +191,8 @@ describe('workflow contract validator', () => { 'copilot_issue_comment.yml', 'copilot_pull_request.yml', 'copilot_pull_request_comment.yml', 'copilot_pull_request_review_state.yml', ]) { - const workflow = yaml.load(readFileSync(path.join(process.cwd(), directory, fileName), 'utf8')) as MutationWorkflow; + const coordinator = ['copilot_issue_comment.yml', 'copilot_pull_request_comment.yml'].includes(fileName); + const workflow = yaml.load(readFileSync(path.join(process.cwd(), coordinator ? '.github/workflows' : directory, coordinator ? 'copilot_comment_runtime.yml' : fileName), 'utf8')) as MutationWorkflow; const steps = Object.values(workflow.jobs).flatMap(job => job.steps ?? []); const modelInputs = steps.filter(step => step.with?.['agent-model']); expect(modelInputs).not.toHaveLength(0); @@ -1634,7 +1633,7 @@ describe('workflow contract validator', () => { const file = path.join(process.cwd(), 'setup/workflows/copilot_issue_comment.yml'); const workflow = yaml.load(readFileSync(file, 'utf8')) as MutationWorkflow; - workflow.jobs['copilot-issues'].steps.splice(1, 0, { uses: 'actions/setup-node@v7' }); + workflow.jobs['copilot-issues'].steps = [{ uses: 'actions/setup-node@v7' }]; expect(() => assertAgentInstallationPrerequisites(file, workflow)).toThrow('standalone official agent installation'); }); @@ -1685,11 +1684,13 @@ describe('workflow contract validator', () => { job.permissions = { contents: 'read' }; expect(() => assertAgentWorkflowPermissions(file, workflow)).toThrow('must grant GITHUB_TOKEN exactly'); job.permissions = { checks: 'write', contents: 'read' }; - const action = job.steps.find((step: any) => step.env?.COPILOT_EVIDENCE_TOKEN); + const central = loadMutationWorkflow('.github/workflows', 'copilot_comment_runtime.yml'); + const runtime = central.workflow.jobs.copilot; + const action = runtime.steps.find((step: any) => step.env?.COPILOT_EVIDENCE_TOKEN); delete action.env.COPILOT_EVIDENCE_TOKEN; - expect(() => assertAgentWorkflowPermissions(file, workflow)).toThrow('must scope COPILOT_EVIDENCE_TOKEN'); - job.steps.push({ run: 'true', env: { COPILOT_EVIDENCE_TOKEN: '${{ github.token }}' } }); - expect(() => assertAgentWorkflowPermissions(file, workflow)).toThrow('must scope COPILOT_EVIDENCE_TOKEN'); + expect(() => assertAgentWorkflowPermissions(central.file, central.workflow)).toThrow('must scope COPILOT_EVIDENCE_TOKEN'); + runtime.steps.push({ run: 'true', env: { COPILOT_EVIDENCE_TOKEN: '${{ github.token }}' } }); + expect(() => assertAgentWorkflowPermissions(central.file, central.workflow)).toThrow('must scope COPILOT_EVIDENCE_TOKEN'); } }, ); diff --git a/src/tooling/__tests__/verification_runtime_guidance.test.ts b/src/tooling/__tests__/verification_runtime_guidance.test.ts index d7231b2f0..87e3136b3 100644 --- a/src/tooling/__tests__/verification_runtime_guidance.test.ts +++ b/src/tooling/__tests__/verification_runtime_guidance.test.ts @@ -8,10 +8,12 @@ describe('shipped verification runtime guidance', () => { const content = readFileSync(path.resolve('setup/workflows', `${name}.yml`), 'utf8'); expect(content).toContain('.copilot/verification-prerequisites.json'); expect(content).toContain('#repository-verification-prerequisites'); - const workflow = yaml.load(content) as { jobs: Record }> }; - const actions = Object.values(workflow.jobs).flatMap(job => job.steps.map(step => step.uses)); + const workflow = yaml.load(content) as { jobs: Record }> }; + const actions = Object.values(workflow.jobs).flatMap(job => [job.uses, ...(job.steps ?? []).map(step => step.uses)]); expect(actions).not.toContain('actions/setup-java@v5'); - expect(actions).toContain('vypdev/copilot@v3'); + expect(actions).toContain(name.endsWith('_comment') + ? 'vypdev/copilot/.github/workflows/copilot_comment_runtime.yml@v3' + : 'vypdev/copilot@v3'); } }); }); diff --git a/src/utils/__tests__/setup_runner_installation.test.ts b/src/utils/__tests__/setup_runner_installation.test.ts index b0e1831aa..fd44f6820 100644 --- a/src/utils/__tests__/setup_runner_installation.test.ts +++ b/src/utils/__tests__/setup_runner_installation.test.ts @@ -60,6 +60,16 @@ describe('installation parity and reviewed migration', () => { const write = (path: string, content: string) => { const absolute = join(root, path); mkdirSync(dirname(absolute), { recursive: true }); writeFileSync(absolute, content); }; beforeEach(() => { root = mkdtempSync(join(tmpdir(), 'copilot-runner-parity-')); }); afterEach(() => rmSync(root, { recursive: true, force: true })); + test('reviews and applies the same retained runner for compact reusable comment jobs', () => { + const legacy = single('[self-hosted, reviewed, Linux]').replace('run: echo fixture', 'uses: vypdev/copilot@v3'); + write('.github/workflows/copilot_issue_comment.yml', legacy); + const config = { ...createDefaultSetupConfiguration(), runners: selectSetupRunnerMode('retain') }; + const review = inspectSetupInstallation(root, config); + expect(review.jobs.find(job => job.file === 'copilot_issue_comment.yml')).toMatchObject({ role: 'agent', runsOn: ['self-hosted', 'reviewed', 'Linux'], retained: true }); + const expected = review.changes.find(change => change.path === '.github/workflows/copilot_issue_comment.yml')!.after; + copySetupFiles(root, undefined, config.features, { setupConfiguration: config, updateExistingWorkflows: true, approvedWorkflowFiles: ['copilot_issue_comment.yml'] }); + expect(readFileSync(join(root, '.github/workflows/copilot_issue_comment.yml'), 'utf8')).toBe(expected); + }); test('an incomplete template package still inventories native YAML files without inventing managed assets', () => { const setup = join(root, 'empty-setup'); mkdirSync(setup); write('.github/workflows/native.yaml', workflow(' native:\n runs-on: ubuntu-latest\n')); diff --git a/src/utils/__tests__/setup_workflow_upgrade.test.ts b/src/utils/__tests__/setup_workflow_upgrade.test.ts index cbda42001..53f88cda1 100644 --- a/src/utils/__tests__/setup_workflow_upgrade.test.ts +++ b/src/utils/__tests__/setup_workflow_upgrade.test.ts @@ -1,8 +1,51 @@ import { dump, load } from 'js-yaml'; import { hasRootLocalSetupAction, renderSetupWorkflowUpgrade } from '../setup_workflow_upgrade'; +import { copilotCommentRunner, COPILOT_COMMENT_REMOTE_WORKFLOW, COPILOT_COMMENT_SELF_WORKFLOW } from '../../domain/copilot_comment_workflow'; const workflow = (runner: unknown, extra = '') => `name: Reviewed workflow\non: [pull_request]\njobs:\n copilot:\n${dump({ 'runs-on': runner }).trimEnd().split('\n').map(line => ` ${line}`).join('\n')}\n${extra} steps:\n - run: echo reviewed\n`; const selected = (content: string) => (load(content) as { jobs: { copilot: { 'runs-on': unknown } } }).jobs.copilot['runs-on']; +const comment = (route: unknown = 'ubuntu-latest') => dump({ on: { issue_comment: { types: ['created', 'edited'] } }, jobs: { copilot: { + uses: COPILOT_COMMENT_REMOTE_WORKFLOW, with: { 'runs-on': JSON.stringify(route) }, secrets: { PAT: '${{ secrets.PAT }}' }, +} } }); + +describe('comment workflow coordination upgrade', () => { + it.each(['ubuntu-latest', ['self-hosted', 'codex', 'Linux'], { group: 'trusted', labels: ['self-hosted', 'Linux'] }])('migrates the reviewed native runner %j and stays idempotent', route => { + const previous = workflow(route).replace('run: echo reviewed', 'uses: vypdev/copilot@v3'); + const result = renderSetupWorkflowUpgrade(comment(), previous); + const parsed = load(result) as any; + expect(copilotCommentRunner(parsed.jobs.copilot)).toEqual(route); + expect(parsed.jobs.copilot.steps).toBeUndefined(); + expect(renderSetupWorkflowUpgrade(comment(), result)).toBe(result); + }); + it('retains a previously upgraded group route', () => { + expect(copilotCommentRunner((load(renderSetupWorkflowUpgrade(comment(), comment({ group: 'trusted', labels: ['self-hosted', 'Linux'] }))) as any).jobs.copilot)) + .toEqual({ group: 'trusted', labels: ['self-hosted', 'Linux'] }); + }); + it('uses an explicitly selected runner profile instead of the prior route', () => { + const template = comment().replace(' copilot:', ' copilot-issues:'); + const result = renderSetupWorkflowUpgrade(template, undefined, { file: 'copilot_issue_comment.yml', runners: { + mode: 'manual-self-hosted', profileId: '', group: 'trusted', labels: ['self-hosted', 'Linux'], validation: 'hosted', + } }); + expect(copilotCommentRunner((load(result) as any).jobs['copilot-issues'])).toEqual({ group: 'trusted', labels: ['self-hosted', 'Linux'] }); + }); + it('preserves source-only self-repository coordination exactly', () => { + const source = comment().replace(COPILOT_COMMENT_REMOTE_WORKFLOW, COPILOT_COMMENT_SELF_WORKFLOW); + expect(hasRootLocalSetupAction(source)).toBe(true); + expect(renderSetupWorkflowUpgrade(comment(), source)).toBe(source); + }); + it.each(['actions/setup-node@v7', 'actions/setup-java@v5'])('blocks silently dropping custom bootstrap %s', uses => { + expect(() => renderSetupWorkflowUpgrade(comment(), workflow('ubuntu-latest').replace('run: echo reviewed', `uses: ${uses}`))).toThrow('migration'); + }); + it('blocks custom shell steps during migration', () => { + expect(() => renderSetupWorkflowUpgrade(comment(), workflow('ubuntu-latest'))).toThrow('migration'); + }); + it('blocks malformed reusable runner JSON', () => { + expect(() => renderSetupWorkflowUpgrade(comment(), comment().replace('"ubuntu-latest"', 'invalid'))).toThrow('review'); + }); + it('blocks dynamic native runners instead of transplanting their missing matrix', () => { + expect(() => renderSetupWorkflowUpgrade(comment(), workflow('${{ matrix.os }}').replace('run: echo reviewed', 'uses: vypdev/copilot@v3'))).toThrow('Dynamic'); + }); +}); describe('setup retains reviewed target workflow runners', () => { it('retains source Action jobs, permissions and release customizations instead of consumer templates', () => { diff --git a/src/utils/setup_installation_review.ts b/src/utils/setup_installation_review.ts index 46d5f5064..925004614 100644 --- a/src/utils/setup_installation_review.ts +++ b/src/utils/setup_installation_review.ts @@ -14,6 +14,7 @@ import { REPOSITORY_AGENT_GUIDE_PATH, REPOSITORY_AGENT_PROFILE_PATH, REPOSITORY_ REPOSITORY_AGENT_SKILL_PATH } from '../application/policies/repository_agent_guidance_policy'; import { SETUP_VERIFICATION_ACTION_PATH, type SetupVerificationActionReview } from '../domain/setup_verification_action'; import { inspectSetupVerificationActionPath, readSetupVerificationActionStarter } from '../infrastructure/setup_verification_action'; +import { copilotCommentRunner } from '../domain/copilot_comment_workflow'; export const SETUP_RUNNER_SNAPSHOT = '.copilot/runner-profile.json'; const object = (value: unknown): Record | undefined => value !== null && typeof value === 'object' && !Array.isArray(value) @@ -68,7 +69,7 @@ export function inspectSetupInstallation(root: string, configuration: SetupConfi const parsedJobs = object(object(documents[0])?.jobs); if (!parsedJobs) throw new Error('Workflow jobs are unavailable for review.'); for (const [job, raw] of Object.entries(parsedJobs)) { - const runsOn = object(raw)?.['runs-on']; + const runsOn = copilotCommentRunner(object(raw)); if (runsOn === undefined) continue; // reusable workflow calls have no runner jobs.push({ file, job, role: setupRunnerRole(file, job) ?? 'validation', runsOn: runsOn as SetupInstallationReview['jobs'][number]['runsOn'], status: 'access-unknown', retained }); diff --git a/src/utils/setup_workflow_upgrade.ts b/src/utils/setup_workflow_upgrade.ts index cdf4c869d..44a2e1e5e 100644 --- a/src/utils/setup_workflow_upgrade.ts +++ b/src/utils/setup_workflow_upgrade.ts @@ -3,6 +3,7 @@ import { isDeepStrictEqual } from 'node:util'; import type { SetupRunnerConfiguration } from '../domain/setup_runner'; import { selectedSetupRunsOn, setupRunnerRole, validateSetupRunners } from '../application/policies/setup_runner_policy'; import { ACTIONS } from '../data/model/action_types'; +import { copilotCommentRunner, COPILOT_COMMENT_SELF_WORKFLOW, isCopilotCommentWorkflow } from '../domain/copilot_comment_workflow'; const object = (value: unknown): Record | undefined => value !== null && typeof value === 'object' && !Array.isArray(value) ? value as Record : undefined; @@ -23,6 +24,7 @@ const runner = (value: unknown): boolean => labels(value) || !!object(value) && (object(value)!.labels === undefined || labels(object(value)!.labels)); const copilotCommands = new Set(Object.values(ACTIONS)); const callsRootAction = (jobs: Record | undefined): boolean => !!jobs && Object.values(jobs).some(job => { + if (object(job)?.uses === COPILOT_COMMENT_SELF_WORKFLOW) return true; const steps = object(job)?.steps; return Array.isArray(steps) && steps.some(step => { const invocation = object(step); const inputs = object(invocation?.with); @@ -82,6 +84,28 @@ export function renderSetupWorkflowUpgrade(template: string, existing?: string, } const templateJobs = object(document(template)?.jobs); if (!previousJobs || !templateJobs) throw new Error('Workflow jobs cannot be inspected; review the workflow separately.'); + if (Object.values(templateJobs).some(job => isCopilotCommentWorkflow(object(job)?.uses))) { + const parsed = document(template)!; + const jobs = object(parsed.jobs)!; + let changed = false; + for (const [name, value] of Object.entries(jobs)) { + const job = object(value)!; + if (!isCopilotCommentWorkflow(job.uses)) throw new Error('Mixed comment workflow jobs require separate workflow review before setup.'); + const previousJob = object(previousJobs[name]); + if (Array.isArray(previousJob?.steps) && previousJob.steps.some(raw => { + const uses = object(raw)?.uses; + return typeof uses !== 'string' || !(uses.startsWith('actions/checkout@') + || /^vypdev\/copilot@[^\s]+$/u.test(uses) || uses === './.git/copilot-verification-setup'); + })) throw new Error('Custom comment job steps require migration to the reviewed repository verification setup action before switching to the reusable workflow. Review the workflow separately.'); + const retained = selectedSetupRunsOn(selection?.runners, selection && setupRunnerRole(selection.file, name)) + ?? copilotCommentRunner(previousJob) ?? copilotCommentRunner(job); + if (!runner(retained)) throw new Error('Existing runner selection is invalid; review the workflow separately.'); + if (JSON.stringify(retained).includes('${{') && existing !== template) throw new Error('Dynamic runner selection requires separate workflow review before setup.'); + changed ||= !isDeepStrictEqual(retained, copilotCommentRunner(job)); + job.with = { ...object(job.with), 'runs-on': JSON.stringify(retained) }; + } + return changed ? dump(parsed, { noRefs: true, lineWidth: -1 }) : template; + } const lines = template.split('\n'); let job = ''; let insideJobs = false; From 53567e5031e19abb9a99c927d213fd5a6eab763a Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Thu, 22 Oct 2026 01:31:14 +0200 Subject: [PATCH 43/44] fix(setup): retain unsupported coordinator refs as unreadable (#662) --- build/cli/index.js | 7 ++++++- .../__tests__/setup_management_workspace_adapter.test.ts | 8 ++++++++ src/infrastructure/setup_management_workspace_adapter.ts | 6 +++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/build/cli/index.js b/build/cli/index.js index d559704ad..770378924 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -100584,7 +100584,12 @@ class SetupManagementWorkspaceAdapter { inspectWorkflow(file, localAction) { const { source, document } = readDocument((0, node_path_1.join)(this.root, '.github', 'workflows', file)); const steps = workflowSteps(document); - const calls = Object.values(object(document.jobs)).map(object).filter(job => (0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(job.uses)); + const jobs = Object.values(object(document.jobs)).map(object); + if (jobs.some(job => typeof job.uses === 'string' + && /^(?:vypdev\/copilot\/|[.$]\/)\.github\/workflows\/copilot_comment_runtime\.yml(?:@|$)/iu.test(job.uses) + && !(0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(job.uses))) + throw new Error('Unsupported comment workflow reference.'); + const calls = jobs.filter(job => (0, copilot_comment_workflow_1.isCopilotCommentWorkflow)(job.uses)); if (calls.some(job => job.uses === copilot_comment_workflow_1.COPILOT_COMMENT_SELF_WORKFLOW) && !localAction()) throw new Error('Unverified source comment workflow.'); const reusable = calls.map(job => { diff --git a/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts b/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts index 501970d55..444e20204 100644 --- a/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts +++ b/src/infrastructure/__tests__/setup_management_workspace_adapter.test.ts @@ -100,6 +100,14 @@ describe('reusable comment installation inspection', () => { test('unknown caller inputs block guessed effective configuration', () => { expect(fixture(reusable(COPILOT_COMMENT_REMOTE_WORKFLOW, ' unknown-input: true')).adapter.inspect()).toMatchObject({ unreadable: true, workflows: [] }); }); + test.each(['master', 'v4', ''])('an unsupported coordinator ref %s cannot disappear from installation evidence', ref => { + const f = fixture(reusable(COPILOT_COMMENT_REMOTE_WORKFLOW.replace('@v3', '@' + ref))); + writeFileSync(join(f.directory, 'other.yml'), workflow('bugbot-comment-limit: 20')); + expect(f.adapter.inspect()).toMatchObject({ unreadable: true, workflows: [{ file: 'other.yml', action: 'vypdev/copilot@v3' }] }); + }); + test('an unverified workspace-relative coordinator cannot be treated as absent', () => { + expect(fixture(reusable(COPILOT_COMMENT_SELF_WORKFLOW.replace('$/', './'))).adapter.inspect()).toMatchObject({ unreadable: true, workflows: [] }); + }); test('a self-repository call without known Copilot metadata fails closed', () => { expect(fixture(reusable(COPILOT_COMMENT_SELF_WORKFLOW)).adapter.inspect()).toMatchObject({ unreadable: true, workflows: [] }); }); diff --git a/src/infrastructure/setup_management_workspace_adapter.ts b/src/infrastructure/setup_management_workspace_adapter.ts index e7ca8ace4..d14583db1 100644 --- a/src/infrastructure/setup_management_workspace_adapter.ts +++ b/src/infrastructure/setup_management_workspace_adapter.ts @@ -88,7 +88,11 @@ export class SetupManagementWorkspaceAdapter { private inspectWorkflow(file: string, localAction: () => string | undefined): SetupInstalledWorkflow[] { const { source, document } = readDocument(join(this.root, '.github', 'workflows', file)); const steps = workflowSteps(document); - const calls = Object.values(object(document.jobs)).map(object).filter(job => isCopilotCommentWorkflow(job.uses)); + const jobs = Object.values(object(document.jobs)).map(object); + if (jobs.some(job => typeof job.uses === 'string' + && /^(?:vypdev\/copilot\/|[.$]\/)\.github\/workflows\/copilot_comment_runtime\.yml(?:@|$)/iu.test(job.uses) + && !isCopilotCommentWorkflow(job.uses))) throw new Error('Unsupported comment workflow reference.'); + const calls = jobs.filter(job => isCopilotCommentWorkflow(job.uses)); if (calls.some(job => job.uses === COPILOT_COMMENT_SELF_WORKFLOW) && !localAction()) throw new Error('Unverified source comment workflow.'); const reusable = calls.map(job => { const overrides = object(job.with); From d33064affc66229cae37a27dd8b37dcdd27457f8 Mon Sep 17 00:00:00 2001 From: Efra Espada Date: Thu, 22 Oct 2026 02:13:46 +0200 Subject: [PATCH 44/44] fix(verification): clean up only owned native requests (#665) --- build/cli/index.js | 5 ++++- build/github_action/index.js | 5 ++++- .../operations/verification.mdx | 3 +++ specs/CATALOG.md | 4 ++-- specs/catalog.json | 2 +- specs/repository-verification-setup-hooks.md | 10 ++++++---- .../__tests__/native_verification_runner.test.ts | 14 ++++++++++++++ src/infrastructure/verification_setup_runner.ts | 4 +++- 8 files changed, 37 insertions(+), 10 deletions(-) diff --git a/build/cli/index.js b/build/cli/index.js index 1afb43aca..f3be1315e 100755 --- a/build/cli/index.js +++ b/build/cli/index.js @@ -104057,6 +104057,7 @@ async function prepareRepositoryVerification(setup, environment) { const session = process.env.COPILOT_NATIVE_WORKER_SESSION; if (!session) throw new verification_setup_policy_1.VerificationSetupError('native-workflow-required', setup.sourceSha); + let requestCreated = false; try { (0, native_verification_protocol_1.nativeSession)(session); const requests = (0, native_verification_protocol_1.readNativeRecord)(session, 'request-count.json')?.count ?? 0; @@ -104070,6 +104071,7 @@ async function prepareRepositoryVerification(setup, environment) { (0, native_verification_staging_1.stageNativeVerificationAction)(setup, session); const id = (0, node_crypto_1.randomUUID)(); (0, native_verification_protocol_1.writeNativeRecord)(session, 'request.json', { id, sourceSha: setup.sourceSha, digest: (0, verification_setup_snapshot_1.verificationSetupDigest)(setup), environment }); + requestCreated = true; (0, logging_ports_1.logInfo)(`Preparing repository verification (${verification_setup_policy_1.VERIFICATION_SETUP_PATH}; trusted source SHA: ${setup.sourceSha}).`); const deadline = Date.now() + verification_setup_policy_1.VERIFICATION_SETUP_LIMITS.timeoutMs; let response; @@ -104103,7 +104105,8 @@ async function prepareRepositoryVerification(setup, environment) { throw new verification_setup_policy_1.VerificationSetupError(error instanceof verification_setup_policy_1.VerificationSetupError ? error.reason : 'handoff-invalid', setup.sourceSha); } finally { - (0, node_fs_1.rmSync)((0, node_path_1.join)(session, 'request.json'), { force: true }); + if (requestCreated) + (0, node_fs_1.rmSync)((0, node_path_1.join)(session, 'request.json'), { force: true }); } } diff --git a/build/github_action/index.js b/build/github_action/index.js index dbe5a582a..1d4d40ac2 100644 --- a/build/github_action/index.js +++ b/build/github_action/index.js @@ -90619,6 +90619,7 @@ async function prepareRepositoryVerification(setup, environment) { const session = process.env.COPILOT_NATIVE_WORKER_SESSION; if (!session) throw new verification_setup_policy_1.VerificationSetupError('native-workflow-required', setup.sourceSha); + let requestCreated = false; try { (0, native_verification_protocol_1.nativeSession)(session); const requests = (0, native_verification_protocol_1.readNativeRecord)(session, 'request-count.json')?.count ?? 0; @@ -90632,6 +90633,7 @@ async function prepareRepositoryVerification(setup, environment) { (0, native_verification_staging_1.stageNativeVerificationAction)(setup, session); const id = (0, node_crypto_1.randomUUID)(); (0, native_verification_protocol_1.writeNativeRecord)(session, 'request.json', { id, sourceSha: setup.sourceSha, digest: (0, verification_setup_snapshot_1.verificationSetupDigest)(setup), environment }); + requestCreated = true; (0, logging_ports_1.logInfo)(`Preparing repository verification (${verification_setup_policy_1.VERIFICATION_SETUP_PATH}; trusted source SHA: ${setup.sourceSha}).`); const deadline = Date.now() + verification_setup_policy_1.VERIFICATION_SETUP_LIMITS.timeoutMs; let response; @@ -90665,7 +90667,8 @@ async function prepareRepositoryVerification(setup, environment) { throw new verification_setup_policy_1.VerificationSetupError(error instanceof verification_setup_policy_1.VerificationSetupError ? error.reason : 'handoff-invalid', setup.sourceSha); } finally { - (0, node_fs_1.rmSync)((0, node_path_1.join)(session, 'request.json'), { force: true }); + if (requestCreated) + (0, node_fs_1.rmSync)((0, node_path_1.join)(session, 'request.json'), { force: true }); } } diff --git a/docs/security-operations/operations/verification.mdx b/docs/security-operations/operations/verification.mdx index 43210a048..0537cd75d 100644 --- a/docs/security-operations/operations/verification.mdx +++ b/docs/security-operations/operations/verification.mdx @@ -339,6 +339,9 @@ If a runner crash leaves an unknown reserved staging directory, preparation fail closed rather than overwriting it. Confirm the prior job has stopped, inspect its run, and remove only that stale `.git/copilot-verification-setup` directory before retrying. Normal completion/cancellation uses the Action post cleanup. +Invalid session handoffs fail closed. An invocation removes only the setup request +it created after validating the session; rejection before that point leaves +preexisting request files untouched. Native composite execution is available in the generated **GitHub Actions** callbacks. The local CLI cannot execute `uses` steps: opted-in local verification diff --git a/specs/CATALOG.md b/specs/CATALOG.md index d01a588fc..5526a0369 100644 --- a/specs/CATALOG.md +++ b/specs/CATALOG.md @@ -24,7 +24,7 @@ debt or convert unknown historic intent into a design decision. | `managed-issue-lifecycle` | As-built baseline | Convert typed issues into traceable work branches, project state, and lifecycle state | [Managed issue and branch lifecycle](./managed-issue-and-branch-lifecycle.md) | 71 paths · 2026-10-20 | | `comment-automation` | Implemented | Admit only explicit commands or exact mentions, then route them while protecting repository mutations | [Comment automation and authorization](./comment-automation-and-authorization.md) | 79 paths · 2026-10-11 | | `bugbot-analysis-and-autofix` | Implemented | Select one canonical PR, exhaustively analyze its bounded diff partitions, publish stable findings atomically, and apply authorized verified fixes | [Bugbot analysis, finding publication, and autofix](./bugbot-analysis-publication-and-autofix.md) + 2 companion | 115 paths · 2026-10-21 | -| `branch-synchronization` | Implemented | Observe parent drift with one localized status card and transition-only notifications, then safely merge a parent branch into a linked working branch | [Branch synchronization and conflict recovery](./branch-synchronization-and-conflict-recovery.md) + 2 companion | 126 paths · 2026-10-21 | +| `branch-synchronization` | Implemented | Observe parent drift with one localized status card and transition-only notifications, then safely merge a parent branch into a linked working branch | [Branch synchronization and conflict recovery](./branch-synchronization-and-conflict-recovery.md) + 2 companion | 126 paths · 2026-10-22 | | `pull-request-lifecycle` | Implemented | Enrich linked and unlinked pull requests with safe issue linkage, projects, metadata, reviewers, concise descriptions, and distinct workflow evidence | [Pull request lifecycle and enrichment](./pull-request-lifecycle-and-enrichment.md) | 77 paths · 2026-10-20 | | `agent-runtime` | Implemented | Resolve, provision, authenticate, authorize, and execute only the agent roles reachable by a run | [Agent runtime, provider, model, and role routing](./agent-runtime-provider-and-model-routing.md) + 1 companion | 99 paths · 2026-10-17 | | `cli-and-single-actions` | As-built baseline | Expose bounded local commands and workflow-dispatched operations through the shared application core | [CLI and single-action execution](./cli-and-single-action-execution.md) | 44 paths · 2026-10-19 | @@ -191,7 +191,7 @@ debt or convert unknown historic intent into a design decision. ### `branch-synchronization` — Branch synchronization and conflict recovery - Owner: Copilot maintainers -- Last verified: 2026-10-21 +- Last verified: 2026-10-22 - Specifications: [`specs/branch-synchronization-and-conflict-recovery.md`](./branch-synchronization-and-conflict-recovery.md) · [`specs/repository-verification-runtime-prerequisites.md`](./repository-verification-runtime-prerequisites.md) · [`specs/repository-verification-setup-hooks.md`](./repository-verification-setup-hooks.md) - Workflows: [`.github/workflows/copilot_branch_sync.yml`](../.github/workflows/copilot_branch_sync.yml) · [`setup/workflows/copilot_branch_sync.yml`](../setup/workflows/copilot_branch_sync.yml) · [`.github/workflows/copilot_issue.yml`](../.github/workflows/copilot_issue.yml) · [`setup/workflows/copilot_issue.yml`](../setup/workflows/copilot_issue.yml) · [`setup/workflows/copilot_issue_comment.yml`](../setup/workflows/copilot_issue_comment.yml) · [`setup/workflows/copilot_pull_request_comment.yml`](../setup/workflows/copilot_pull_request_comment.yml) · [`.github/workflows/copilot_comment_runtime.yml`](../.github/workflows/copilot_comment_runtime.yml) · [`.github/workflows/copilot_issue_comment.yml`](../.github/workflows/copilot_issue_comment.yml) · [`.github/workflows/copilot_pull_request_comment.yml`](../.github/workflows/copilot_pull_request_comment.yml) - Entrypoints: [`src/application/usecases/branch_sync/sync_branch_use_case.ts`](../src/application/usecases/branch_sync/sync_branch_use_case.ts) · [`src/application/usecases/actions/observe_branch_sync_use_case.ts`](../src/application/usecases/actions/observe_branch_sync_use_case.ts) diff --git a/specs/catalog.json b/specs/catalog.json index d57e22575..ca41fbc29 100644 --- a/specs/catalog.json +++ b/specs/catalog.json @@ -1970,7 +1970,7 @@ "status": "implemented", "scope": "Observe parent drift with one localized status card and transition-only notifications, then safely merge a parent branch into a linked working branch", "owner": "Copilot maintainers", - "lastVerified": "2026-10-21", + "lastVerified": "2026-10-22", "specs": [ "specs/branch-synchronization-and-conflict-recovery.md", "specs/repository-verification-runtime-prerequisites.md", diff --git a/specs/repository-verification-setup-hooks.md b/specs/repository-verification-setup-hooks.md index 7f6d517b6..791c74b91 100644 --- a/specs/repository-verification-setup-hooks.md +++ b/specs/repository-verification-setup-hooks.md @@ -63,7 +63,7 @@ The **trusted source** is the configured main/production remote branch captured ### 4.2 Non-goals -Reusable workflows, job matrices owned by the consumer hook, YAML emulation, local Actions emulation, arbitrary helper paths and release/deployment changes are out of scope. +Consumer-owned reusable workflows and job matrices inside the dependency hook, YAML emulation, local Actions emulation, arbitrary helper paths and release/deployment changes are out of scope. The Copilot-owned reusable coordinator is in scope and retains the complete operation and native setup in one job. ### 4.3 Fixed product/safety invariants @@ -202,6 +202,8 @@ Existing localized result cards and plain-text error fallback remain in force. N | Invalid runtime output | No verifier/push; install under approved roots | Fresh HOME disposed | | Job canceled/worker exits | No new publication; inspect retained operation result | Post action signals cancellation, waits up to 10 seconds, terminates remaining worker and cleans owned staging after native posts | +Request cleanup MUST run only after the invocation validates its native session and successfully publishes its own request. Invalid session paths or identity, and failures before request creation, MUST leave preexisting request files untouched. Successful and failed continuations MUST remove their owned request. Three distinct rejection regressions cover invalid path, invalid identity and failure before request creation; existing success/failure cases assert owned cleanup. + Native setup steps have `timeout-minutes: 5`; the worker also rejects readiness after 300 seconds. The enclosing existing job timeout remains authoritative. A force-killed worker cannot promise application finally blocks ran: the Action cleans its own staging, and normal runner checkout cleanup/operator recovery owns remaining job-local candidate state. Already-completed remote effects MUST retain their existing truthful result semantics. ## 11. Security, permissions, and privacy @@ -229,7 +231,7 @@ Existing installations remain disabled by default. The unreleased `.copilot/veri ## 14. Testing strategy and numeric budget -Minimum **190 distinct automated cases**, allocated without double counting: +Minimum **193 distinct automated cases**, allocated without double counting: | Area | Minimum | Risk | |---|---:|---| @@ -239,8 +241,8 @@ Minimum **190 distinct automated cases**, allocated without double counting: | Candidate/runner orchestration | 24 | Ordering, fresh profiles, candidate identity, failure gates | | Workflows/setup contracts | 58 | Native step structure, env, limits, source/distribution, preservation | | Real Git/composition integration | 8 | Exact managed ref, merge manifests, abort/push guards | -| Runtime result filesystem security | 12 | Bounds, links, containment, races, owned staging | -| **Total** | **190** | Native rewrite adds at least 70 cases beyond retained applicable baseline | +| Runtime result filesystem security | 15 | Bounds, links, containment, races, owned staging and three early-rejection request ownership cases | +| **Total** | **193** | Native rewrite adds at least 70 cases beyond retained applicable baseline; release review adds three ownership cases | Repository-wide thresholds remain in force. New pure policy targets 100% branches; changed setup adapters target aggregate 95% lines/statements and 90% branches/functions. Deterministic unit fakes cover runner responses without interpreting YAML. Separate native CI acceptance MUST execute real composite `uses`/`run` steps with Python/pytest and Node/pnpm on hosted Linux, Windows and macOS, asserting candidate changes, trusted-source selection, fresh profiles candidate preservation, source-runtime immutability even after candidate bundle changes, and final post cleanup. Controlled local Git acceptance covers the exact same managed branch and no release. Native CI evidence is additional to the distinct Jest budget. diff --git a/src/infrastructure/__tests__/native_verification_runner.test.ts b/src/infrastructure/__tests__/native_verification_runner.test.ts index e0adfaa24..9bbe278b9 100644 --- a/src/infrastructure/__tests__/native_verification_runner.test.ts +++ b/src/infrastructure/__tests__/native_verification_runner.test.ts @@ -29,6 +29,18 @@ describe('native verification boundary', () => { delete process.env.COPILOT_NATIVE_WORKER_SESSION; await expect(prepareRepositoryVerification(f.setup, f.runtime.environment)).rejects.toMatchObject({ reason: 'native-workflow-required' }); }); + it.each(['invalid path', 'invalid identity', 'before request creation'])('preserves an unrelated request on %s rejection', async kind => { + const directory = kind === 'invalid path' ? f.root : f.session; + const request = join(directory, 'request.json'); + fs.writeFileSync(request, 'preexisting request'); + if (kind === 'invalid path') process.env.COPILOT_NATIVE_WORKER_SESSION = directory; + if (kind === 'invalid identity') writeNativeRecord(f.session, 'session.json', { schemaVersion: 1, workspace: 'other' }); + const setup = kind === 'before request creation' ? { ...f.setup, workspace: f.session } as typeof f.setup : f.setup; + await expect(prepareRepositoryVerification(setup, f.runtime.environment)).rejects.toMatchObject({ + reason: kind === 'before request creation' ? 'workspace-changed' : 'handoff-invalid', + }); + expect(fs.readFileSync(request, 'utf8')).toBe('preexisting request'); + }); it('stages only pinned YAML and assets, then restores the candidate byte for byte', async () => { fs.mkdirSync(f.action, { recursive: true }); fs.writeFileSync(join(f.action, 'action.yml'), 'candidate'); const running = prepareRepositoryVerification(f.setup, f.runtime.environment); @@ -38,6 +50,7 @@ describe('native verification boundary', () => { f.respond(); await running; expect(fs.readFileSync(join(f.action, 'action.yml'), 'utf8')).toBe('candidate'); expect(fs.existsSync(join(f.action, 'scripts'))).toBe(false); + expect(fs.existsSync(join(f.session, 'request.json'))).toBe(false); }); it('retains native metadata outside the publishable candidate for deferred post steps', async () => { const running = prepareRepositoryVerification(f.setup, f.runtime.environment); f.respond(); await running; @@ -94,6 +107,7 @@ describe('native verification boundary', () => { const running = prepareRepositoryVerification(f.setup, f.runtime.environment); f.respond(() => response); await expect(running).rejects.toThrow('Verification, commit and push are withheld'); expect(fs.existsSync(f.action)).toBe(false); + expect(fs.existsSync(join(f.session, 'request.json'))).toBe(false); }); it('withholds the command and probes after a setup failure', async () => { const execute = jest.fn(); const preflight = jest.fn(); const adapter = new GitCommitAdapter(execute, preflight, f.setup); diff --git a/src/infrastructure/verification_setup_runner.ts b/src/infrastructure/verification_setup_runner.ts index 7b8f801b6..203ba5b29 100644 --- a/src/infrastructure/verification_setup_runner.ts +++ b/src/infrastructure/verification_setup_runner.ts @@ -18,6 +18,7 @@ export async function prepareRepositoryVerification(setup: PreparedVerificationS if (setup.kind === 'blocked') throw new VerificationSetupError(setup.reason, setup.sourceSha); const session = process.env.COPILOT_NATIVE_WORKER_SESSION; if (!session) throw new VerificationSetupError('native-workflow-required', setup.sourceSha); + let requestCreated = false; try { nativeSession(session); const requests = readNativeRecord<{count: number}>(session, 'request-count.json')?.count ?? 0; @@ -29,6 +30,7 @@ export async function prepareRepositoryVerification(setup: PreparedVerificationS stageNativeVerificationAction(setup, session); const id = randomUUID(); writeNativeRecord(session, 'request.json', { id, sourceSha: setup.sourceSha, digest: verificationSetupDigest(setup), environment }); + requestCreated = true; logInfo(`Preparing repository verification (${VERIFICATION_SETUP_PATH}; trusted source SHA: ${setup.sourceSha}).`); const deadline = Date.now() + VERIFICATION_SETUP_LIMITS.timeoutMs; let response: NativeVerificationResponse | undefined; @@ -55,6 +57,6 @@ export async function prepareRepositoryVerification(setup: PreparedVerificationS } catch (error) { throw new VerificationSetupError(error instanceof VerificationSetupError ? error.reason : 'handoff-invalid', setup.sourceSha); } finally { - rmSync(join(session, 'request.json'), { force: true }); + if (requestCreated) rmSync(join(session, 'request.json'), { force: true }); } }