Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions build/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5255,6 +5255,12 @@ exports.APPLICATION_ERROR_METADATA = {
action: 'Correct the input and retry.',
retainedState: UNCHANGED_STATE,
},
'validation.evidence-unavailable': {
kind: 'validation', retryable: false,
impact: 'Progress was not assessed because GitHub omitted a required file patch.',
action: 'Inspect the exact base/head comparison manually or split the work into smaller reviewed changes with complete patches before a new assessment. Retrying the same commits cannot restore omitted evidence.',
retainedState: 'Existing progress labels and published assessments were preserved; no model assessment was made.',
},
'validation.evidence-too-large': {
kind: 'validation', retryable: false,
impact: 'Progress could not be assessed within the fixed evidence limits.',
Expand Down
2 changes: 1 addition & 1 deletion build/api/src/data/model/application_error.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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' | 'workflow.invalid-event' | 'workflow.stale' | 'workflow.cancelled' | 'workflow.failed' | 'workflow.presentation-pending' | 'timeout' | 'unexpected';
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"];
export type ApplicationErrorRecoveryId = typeof APPLICATION_ERROR_RECOVERY_IDS[number];
interface ApplicationErrorRecoveryVariables {
Expand Down
17 changes: 15 additions & 2 deletions build/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39201,6 +39201,11 @@ const SPANISH_CONTENT = Object.freeze({
action: 'Corrige la entrada y reinténtalo.',
retainedState: UNCHANGED_STATE_ES,
}),
'validation.evidence-unavailable': Object.freeze({
impact: 'No se evaluó el progreso porque GitHub omitió un patch necesario.',
action: 'Inspecciona manualmente la comparación entre los commits base y head exactos o divide el trabajo en cambios revisados más pequeños con patches completos antes de otra evaluación. Reintentar los mismos commits no recuperará la evidencia omitida.',
retainedState: 'Se conservaron las etiquetas de progreso y las evaluaciones publicadas; no se realizó ninguna evaluación del modelo.',
}),
'validation.evidence-too-large': Object.freeze({
impact: 'No se pudo evaluar el progreso dentro de los límites fijos de evidencia.',
action: 'Reduce el tamaño de la comparación o divide el trabajo en cambios revisados más pequeños antes de iniciar otra evaluación.',
Expand Down Expand Up @@ -78106,6 +78111,12 @@ exports.APPLICATION_ERROR_METADATA = {
action: 'Correct the input and retry.',
retainedState: UNCHANGED_STATE,
},
'validation.evidence-unavailable': {
kind: 'validation', retryable: false,
impact: 'Progress was not assessed because GitHub omitted a required file patch.',
action: 'Inspect the exact base/head comparison manually or split the work into smaller reviewed changes with complete patches before a new assessment. Retrying the same commits cannot restore omitted evidence.',
retainedState: 'Existing progress labels and published assessments were preserved; no model assessment was made.',
},
'validation.evidence-too-large': {
kind: 'validation', retryable: false,
impact: 'Progress could not be assessed within the fixed evidence limits.',
Expand Down Expand Up @@ -85414,8 +85425,10 @@ class ProgressDiffRepository {
throw unavailable();
paths.add(path);
const generated = path.startsWith('build/') || path === 'specs/CATALOG.md';
if (!generated && (file.additions > 0 || file.deletions > 0) && (typeof file.patch !== 'string' || !file.patch))
throw unavailable();
const unchanged = file.status === 'unchanged' && file.additions === 0 && file.deletions === 0;
if (!generated && !unchanged && (typeof file.patch !== 'string' || !file.patch)) {
throw new application_error_1.ApplicationError('validation.evidence-unavailable', 'GitHub omitted a required file patch from the pinned comparison. Progress was not assessed and existing state was retained.');
}
return { path, status: file.status, additions: file.additions, deletions: file.deletions,
...(generated ? { evidence: 'generated-metadata-only' } : { patch: file.patch ?? '' }) };
});
Expand Down
17 changes: 15 additions & 2 deletions build/github_action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40545,6 +40545,11 @@ const SPANISH_CONTENT = Object.freeze({
action: 'Corrige la entrada y reinténtalo.',
retainedState: UNCHANGED_STATE_ES,
}),
'validation.evidence-unavailable': Object.freeze({
impact: 'No se evaluó el progreso porque GitHub omitió un patch necesario.',
action: 'Inspecciona manualmente la comparación entre los commits base y head exactos o divide el trabajo en cambios revisados más pequeños con patches completos antes de otra evaluación. Reintentar los mismos commits no recuperará la evidencia omitida.',
retainedState: 'Se conservaron las etiquetas de progreso y las evaluaciones publicadas; no se realizó ninguna evaluación del modelo.',
}),
'validation.evidence-too-large': Object.freeze({
impact: 'No se pudo evaluar el progreso dentro de los límites fijos de evidencia.',
action: 'Reduce el tamaño de la comparación o divide el trabajo en cambios revisados más pequeños antes de iniciar otra evaluación.',
Expand Down Expand Up @@ -68461,6 +68466,12 @@ exports.APPLICATION_ERROR_METADATA = {
action: 'Correct the input and retry.',
retainedState: UNCHANGED_STATE,
},
'validation.evidence-unavailable': {
kind: 'validation', retryable: false,
impact: 'Progress was not assessed because GitHub omitted a required file patch.',
action: 'Inspect the exact base/head comparison manually or split the work into smaller reviewed changes with complete patches before a new assessment. Retrying the same commits cannot restore omitted evidence.',
retainedState: 'Existing progress labels and published assessments were preserved; no model assessment was made.',
},
'validation.evidence-too-large': {
kind: 'validation', retryable: false,
impact: 'Progress could not be assessed within the fixed evidence limits.',
Expand Down Expand Up @@ -75906,8 +75917,10 @@ class ProgressDiffRepository {
throw unavailable();
paths.add(path);
const generated = path.startsWith('build/') || path === 'specs/CATALOG.md';
if (!generated && (file.additions > 0 || file.deletions > 0) && (typeof file.patch !== 'string' || !file.patch))
throw unavailable();
const unchanged = file.status === 'unchanged' && file.additions === 0 && file.deletions === 0;
if (!generated && !unchanged && (typeof file.patch !== 'string' || !file.patch)) {
throw new application_error_1.ApplicationError('validation.evidence-unavailable', 'GitHub omitted a required file patch from the pinned comparison. Progress was not assessed and existing state was retained.');
}
return { path, status: file.status, additions: file.additions, deletions: file.deletions,
...(generated ? { evidence: 'generated-metadata-only' } : { patch: file.patch ?? '' }) };
});
Expand Down
20 changes: 17 additions & 3 deletions docs/agents/execution-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,20 @@ Progress assessments receive a complete comparison pinned to the repository's
base and source commits. Generated `build/` outputs and the exact generated
`specs/CATALOG.md` index contribute file facts only; the editable catalog JSON
still contributes its full source patch. These generated facts never certify a
build or test. Comparisons exceeding the existing 256,000-byte evidence budget
remain unavailable and preserve progress state. That condition does not imply
that the branch changed during the invocation.
build or test. Complete comparisons are assessed in whole-file partitions of at
most 256,000 UTF-8 bytes each, with at most 16 partitions and one final assessment.
An individual oversized file or an exhausted partition budget is nonretryable
`validation.evidence-too-large`; existing progress remains unchanged.

If GitHub omits any required source patch, progress is **not assessed** and the
result is nonretryable `validation.evidence-unavailable`. This includes pnpm
lockfiles and binary or zero-line changed files whose contents cannot be proven.
Lockfiles are not generated-metadata exceptions. Only explicitly unchanged paths
with zero changed lines may carry empty source evidence. No workspace fallback,
partial review, or automatic completion is claimed. Inspect the exact base/head
comparison manually, or split the work into smaller reviewed changes that expose
complete patches before requesting a fresh assessment. Manual inspection does
not update Copilot's progress; rerunning the same commits cannot recover an
omitted patch. A genuine provider outage remains retryable. These conditions do
not imply that the branch changed during the invocation. See the
[error reference](/security-operations/operations/error-reference).
1 change: 1 addition & 0 deletions docs/security-operations/operations/error-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ English. Error codes and references never translate.
| `agent.failed` | An admitted agent did not produce a usable result. | Inspect sanitized agent status and retry if appropriate. |
| `locale.output-invalid` | Generated product content violated its target-locale contract. | Retry with a provider compatible with the configured repository locale. |
| `locale.translation-failed` | An addressed request could not be safely adapted to the target locale. | Rephrase the request or retry when the language provider is available. |
| `validation.evidence-unavailable` | GitHub omitted a required patch from an exact-SHA progress comparison, including a lockfile or binary change. Progress was not assessed; existing labels and assessments remain unchanged. This is nonretryable. | Inspect the exact base/head comparison manually or split into smaller reviewed changes with complete patches. Retrying the same commits does not recover omitted evidence; manual inspection does not certify Copilot completion. |
| `validation.evidence-too-large` | Progress evidence exceeds a fixed per-file, aggregate or partition-count limit. Existing labels and assessments remain unchanged; this is nonretryable. | Reduce the comparison or split work into smaller reviewed changes before a new assessment. |
| `validation.invalid-input` | Entrypoint input is malformed. | Correct the input and retry. |
| `workflow.invalid-event` | The event cannot start the requested workflow. | Start from a supported event or surface. |
Expand Down
10 changes: 5 additions & 5 deletions specs/CATALOG.md

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions specs/catalog.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"status": "implemented",
"scope": "English-default, localized, semantic, bounded, and idempotent product messages across GitHub and repository-aware operator surfaces",
"owner": "Copilot maintainers",
"lastVerified": "2026-10-17",
"lastVerified": "2026-10-20",
"specs": [
"specs/semantic-github-publication-and-notification.md",
"specs/repository-locale-and-localization.md",
Expand Down Expand Up @@ -151,7 +151,8 @@
"src/application/policies/progress_diff_partition_policy.ts",
"src/application/policies/progress_partition_response_policy.ts",
"src/application/usecases/actions/summarize_progress_diff_workflow.ts",
"src/data/repository/agent_json_schema_validator.ts"
"src/data/repository/agent_json_schema_validator.ts",
"src/data/model/application_error.ts"
],
"tests": [
"src/domain/__tests__/implementation_plan.test.ts",
Expand Down Expand Up @@ -247,7 +248,8 @@
"src/application/policies/__tests__/progress_diff_partition_policy.test.ts",
"src/application/policies/__tests__/progress_partition_response_policy.test.ts",
"src/application/usecases/actions/__tests__/progress_multipart.integration.test.ts",
"src/data/repository/__tests__/agent_json_schema_validator.test.ts"
"src/data/repository/__tests__/agent_json_schema_validator.test.ts",
"src/application/errors/__tests__/application_error.test.ts"
],
"documentation": [
"docs/configuration.mdx",
Expand Down Expand Up @@ -284,7 +286,9 @@
"docs/security-operations/operations/verification.mdx",
"docs/development/architecture.mdx",
"docs/development/testing.mdx",
"docs/issues/branch-management.mdx"
"docs/issues/branch-management.mdx",
"docs/agents/execution-contract.mdx",
"docs/security-operations/operations/error-reference.mdx"
]
},
{
Expand Down
78 changes: 78 additions & 0 deletions specs/semantic-github-publication-and-notification.md
Original file line number Diff line number Diff line change
Expand Up @@ -1916,3 +1916,81 @@ one extra code point at both stages. They supplement, rather than recount, the
three parser-only cases. Existing response size/prompt byte ceilings and typed,
sanitized length failures remain unchanged; catalog evidence and operator docs
must identify the shared local validator.


### Omitted progress patches are terminal evidence loss (2026-10-20, #611)

Observed defect: GitHub returned 14 file records for an immutable dependency
remediation comparison, but omitted the changed `frontend/pnpm-lock.yaml` patch.
The adapter mislabeled this as a retryable provider outage. The intentional
contract now reports **`validation.evidence-unavailable`, nonretryable**, before
any model call or progress mutation. Transport failures remain distinct and
retryable. The code is part of the shared error model and English/Spanish catalog;
other locales retain complete-catalog resolution/fallback. It introduces no
additional publication, permission, configuration, stored state or migration.

```text
exact-SHA authenticated comparison -> all required source patches present -> existing assessment
-> omitted required patch -> unassessed; retain progress
-> transport failure -> existing retryable provider failure
```

Text equivalent: validate the entire inventory before assessment; complete
evidence permits analysis, omitted evidence stops without assessing progress,
and actual transport failures retain their temporary-provider semantics.

Every changed source path, including pnpm lockfiles, binary changes, empty-file
changes and content-unproven renames, MUST provide a nonempty patch. Only paths
explicitly marked unchanged with zero additions/deletions may carry empty source
evidence. Existing `build/` and exact `specs/CATALOG.md` exceptions retain their
explicit generated metadata label; metadata never proves reviewed contents,
builds, tests, or completion. Lockfiles MUST NOT become a metadata exception.
The patch release deliberately uses the issue's supported terminal-diagnostic
route rather than adding a content retrieval fallback. Requests remain bound to
the configured credential and exact base/head SHAs; no mutable ref, workspace
read, ignored file, truncation, or increased limit is introduced.

Representative Job Summary/CLI content:

```text
Impact: Progress was not assessed because GitHub omitted a required file patch.
Error code: validation.evidence-unavailable
Action: Inspect the exact base/head comparison manually or split the work into
smaller reviewed changes with complete patches before a new assessment.
Retrying the same commits cannot restore omitted evidence.
Retained state: Existing progress labels and published assessments were preserved;
no model assessment was made.
Retryable: No
```

Pending/complete/stale/canceled states keep the existing content. If other steps
succeed, their completed facts remain visible alongside this failed assessment;
there is no partial percentage. Existing linked-run navigation, plain-language
labels, sanitization and accessibility rules apply. The maintainer inspects the
exact immutable comparison in GitHub and may split subsequent reviewed work to
obtain complete patches. Manual review alone MUST NOT alter progress or mark
Copilot completion. Repeating the same input is not an automated recovery path.

The **12-case regression budget** is distributed as eight adapter cases (14-file
pnpm incident, four zero-line/binary/empty/rename ambiguity cases, two explicit
generated exceptions, one complete lockfile), one adapter-to-use-case case with
no model/label calls, two localized terminal-diagnostic cases, and the updated
closed error-model contract. Existing exact-SHA, token, 299/300-file, per-file,
partition, invalid-input, and real transport-failure tests remain mandatory.
Deterministic fakes use no network or sleeps. Global coverage, dependency and
semantic publication guards remain unchanged; full tests/build/type/lint,
specification/catalog and documentation checks are required.

Traceability: the patch-presence rule belongs to `ProgressDiffRepository` and its
repository tests; no-assessment/state retention belongs to the existing progress
use case plus its adapter integration fixture; the terminal content belongs to
the shared error model/catalog and presentation tests. Documentation changes
land in `docs/agents/execution-contract.mdx` and the operational error reference.
Acceptance MUST reproduce the omitted 14th patch, preserve existing progress,
make zero model calls, report No for retry, and keep genuine outage semantics.
A complete lockfile patch still assesses normally. Rollout is a patch upgrade
with no state migration; rollback restores misleading retry guidance. Live
consumer verification remains separate from deterministic local evidence.

Primary source: [GitHub compare-two-commits](https://docs.github.com/en/rest/commits/commits#compare-two-commits)
documents missing binary patches and the fixed first-page file inventory bound.
2 changes: 1 addition & 1 deletion src/application/errors/__tests__/application_error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('ApplicationError', () => {
it('exposes the closed semantic contract for every error code', () => {
const codes = Object.keys(APPLICATION_ERROR_METADATA) as ApplicationErrorCode[];

expect(codes).toHaveLength(22);
expect(codes).toHaveLength(23);
for (const code of codes) {
const error = new ApplicationError(code, 'Safe public message.', { correlationId: CORRELATION_ID });
expect(error).toMatchObject({
Expand Down
Loading
Loading