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
3 changes: 3 additions & 0 deletions docs/src/content/docs/specs/forecast-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,8 @@ and adding new fixtures.
- **T-FC-021**: Sampling respects `--days` historical window cutoff.
- **T-FC-022**: Run with missing `aw_info.json` artifact contributes zero ET and is still counted in `sampled_runs`.
- **T-FC-023**: Workflow with zero sampled runs produces nil projection with zero fields.
- **T-FC-024**: An in-progress run with a non-zero token usage snapshot is represented as a partial observation.
- **T-ET-006**: A run with total effective tokens of at least 1,000,000 is handled without overflow.

#### 12.1.4 Monte Carlo Engine Tests

Expand Down Expand Up @@ -972,6 +974,7 @@ and adding new fixtures.
| Data sampling with limit and window | T-FC-020–021 | 1 | Required |
| Missing artifact graceful handling | T-FC-022 | 1 | Required |
| Nil projection for empty sample | T-FC-023 | 1 | Required |
| Partial observation for in-progress run | T-FC-024 | 1 | Required |
| Knuth Poisson algorithm (λ ≤ 15) | T-FC-031 | 1 | Required |
| Normal approximation (λ > 15) | T-FC-032 | 1 | Required |
| Zero-λ projection | T-FC-033 | 1 | Required |
Expand Down
67 changes: 43 additions & 24 deletions pkg/cli/forecast_compliance_fixtures_formal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ package cli
// - FC-P6: run_summary_failed.json has conclusion == "failure" (T-FC-035)
// - FC-P7: run_summary_cancelled.json has conclusion == "cancelled" (T-FC-036)
// - FC-P8: RunSummary JSON round-trip serialization is lossless
// - FC-P9: run_started_at <= updated_at in every fixture
// - FC-P9: StartedAt <= UpdatedAt in every fixture
// - FC-P10: all five fixtures have required Monte Carlo input fields

import (
Expand Down Expand Up @@ -69,10 +69,10 @@ func TestFormal_P1_FixtureFieldMapping(t *testing.T) {
// Top-level identity field.
assert.Contains(t, fixture, "run_id", "P1: run_id must be present")

// run sub-object must expose conclusion, updated_at, run_started_at.
// run sub-object must expose conclusion, updatedAt, startedAt.
run, ok := fixture["run"].(map[string]any)
require.True(t, ok, "P1: 'run' must be a JSON object")
for _, field := range []string{"conclusion", "updated_at", "run_started_at"} {
for _, field := range []string{"conclusion", "updatedAt", "startedAt"} {
assert.Contains(t, run, field, "P1: run.%s must be present for forecast inputs", field)
}

Expand Down Expand Up @@ -411,7 +411,7 @@ func TestFormal_P13_FixtureJSONConformance(t *testing.T) {
// run sub-object required fields.
run, ok := fixture["run"].(map[string]any)
require.True(t, ok, "P13: 'run' must be a JSON object")
runRequired := []string{"conclusion", "updated_at", "run_started_at"}
runRequired := []string{"conclusion", "updatedAt", "startedAt"}
for _, field := range runRequired {
assert.Contains(t, run, field,
"P13: run.%q must be present for duration and Bernoulli derivation", field)
Expand Down Expand Up @@ -504,6 +504,26 @@ func TestFormal_FC_P7_CancelledRunFixture(t *testing.T) {
"so it is included in the sample but not counted as a Bernoulli success")
}

// TestFormal_FC_P11_PartialETFixture verifies that run_summary_partial_et.json
// represents an in-progress run with a non-zero token usage snapshot.
//
// Specification reference: T-FC-024; specs/forecast-compliance-fixtures/README.md
func TestFormal_FC_P11_PartialETFixture(t *testing.T) {
fixture := loadFixture(t, "run_summary_partial_et.json")

run, ok := fixture["run"].(map[string]any)
require.True(t, ok, "FC-P11: 'run' must be a JSON object")
assert.Equal(t, "in_progress", run["status"],
"FC-P11 (T-FC-024): partial fixture must represent an in-progress run")

usage, ok := fixture["token_usage_summary"].(map[string]any)
require.True(t, ok, "FC-P11: token_usage_summary must be a JSON object")
et, ok := usage["total_effective_tokens"].(float64)
require.True(t, ok, "FC-P11: total_effective_tokens must be a number")
assert.Greater(t, et, 0.0,
"FC-P11 (T-FC-024): partial fixture must contain a non-zero token usage snapshot")
}

// TestFormal_FC_P8_RunSummaryRoundTrip verifies that marshalling a RunSummary to
// JSON and unmarshalling it back produces an equal value (cache-hit determinism).
//
Expand Down Expand Up @@ -549,10 +569,10 @@ func TestFormal_FC_P8_RunSummaryRoundTrip(t *testing.T) {
"FC-P8: Run.UpdatedAt must survive round-trip")
}

// TestFormal_FC_P9_TimestampOrdering verifies that run_started_at <= updated_at
// TestFormal_FC_P9_TimestampOrdering verifies that StartedAt <= UpdatedAt
// in every fixture (TLA+ ordering invariant).
//
// Formal predicate (FC-P9): ∀f ∈ Fixtures: f["run"]["run_started_at"] ≤ f["run"]["updated_at"]
// Formal predicate (FC-P9): ∀f ∈ Fixtures: f.Run.StartedAt ≤ f.Run.UpdatedAt
// Specification reference: §6.2.2 Duration Derivation
func TestFormal_FC_P9_TimestampOrdering(t *testing.T) {
fixtures := []string{
Expand All @@ -561,28 +581,25 @@ func TestFormal_FC_P9_TimestampOrdering(t *testing.T) {
"run_summary_failed.json",
"run_summary_high_et.json",
"run_summary_cancelled.json",
"run_summary_partial_et.json",
}

for _, name := range fixtures {
t.Run(name, func(t *testing.T) {
fixture := loadFixture(t, name)

run, ok := fixture["run"].(map[string]any)
require.True(t, ok, "FC-P9: 'run' must be a JSON object in %s", name)

startedStr, ok := run["run_started_at"].(string)
require.True(t, ok, "FC-P9: run.run_started_at must be a string in %s", name)
updatedStr, ok := run["updated_at"].(string)
require.True(t, ok, "FC-P9: run.updated_at must be a string in %s", name)

started, err := time.Parse(time.RFC3339, startedStr)
require.NoError(t, err, "FC-P9: run_started_at must parse as RFC3339 in %s", name)
updated, err := time.Parse(time.RFC3339, updatedStr)
require.NoError(t, err, "FC-P9: updated_at must parse as RFC3339 in %s", name)

assert.False(t, started.After(updated),
"FC-P9: run_started_at (%s) must be <= updated_at (%s) in %s",
startedStr, updatedStr, name)
data, err := os.ReadFile(filepath.Join(fixtureDir(t), name))
require.NoError(t, err, "FC-P9: fixture file %q must be readable", name)

var summary RunSummary
require.NoError(t, json.Unmarshal(data, &summary),
"FC-P9: fixture file %q must unmarshal as RunSummary", name)
require.False(t, summary.Run.StartedAt.IsZero(),
"FC-P9: run.startedAt must populate RunSummary.Run.StartedAt in %s", name)
require.False(t, summary.Run.UpdatedAt.IsZero(),
"FC-P9: run.updatedAt must populate RunSummary.Run.UpdatedAt in %s", name)

assert.False(t, summary.Run.StartedAt.After(summary.Run.UpdatedAt),
"FC-P9: StartedAt (%s) must be <= UpdatedAt (%s) in %s",
summary.Run.StartedAt, summary.Run.UpdatedAt, name)
})
}
}
Expand All @@ -607,6 +624,7 @@ func TestFormal_FC_P10_MonteCarloInputCompleteness(t *testing.T) {
{name: "run_summary_failed.json", wantConclusion: "failure", aicMustBeGT0: false},
{name: "run_summary_high_et.json", wantConclusion: "success", aicMustBeGT0: true},
{name: "run_summary_cancelled.json", wantConclusion: "cancelled", aicMustBeGT0: false},
{name: "run_summary_partial_et.json", wantConclusion: "", aicMustBeGT0: true},
}

for _, tc := range cases {
Expand Down Expand Up @@ -663,6 +681,7 @@ var documentedForecastFixtures = []string{
"run_summary_failed.json",
"run_summary_high_et.json",
"run_summary_cancelled.json",
"run_summary_partial_et.json",
}

// TestFormal_FixtureCountConsistency verifies that the fixture files documented in
Expand Down
1 change: 1 addition & 0 deletions pkg/workflow/github_mcp_access_control_formal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ var documentedComplianceFixtures = []string{
"empty-repos-block.yaml",
"role-deny.yaml",
"tool-name-filter.yaml",
"empty-tool-name-deny.yaml",
"blocked-user-deny.yaml",
"private-repo-block.yaml",
"integrity-level-block.yaml",
Expand Down
3 changes: 2 additions & 1 deletion specs/awf-config-sources-compliance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The following test IDs cover the `DriftRecord` schema and its usage requirements
## Spec Reference

- **Specification**: `specs/awf-config-sources-spec.md`
- **Repository structure**: [Structure](../awf-config-sources-spec.md#structure)
- **Defining section**: §6.5 — DriftRecord Entity Schema
- **Related sections**: §6.2 (Drift Detection Procedure), §5 (Conformance Requirements CR-05, CR-06)

Expand All @@ -40,7 +41,7 @@ The following test IDs cover the `DriftRecord` schema and its usage requirements
Conformance tests that validate `DriftRecord` schema compliance are implemented in:

```
pkg/workflow/awf_config_drift_test.go — DriftRecord schema validation and usage (T-DR-001 through T-DR-010)
pkg/workflow/awf_config_drift_test.go — DriftRecord schema validation and usage (T-DR-001 through T-DR-010; T-DR-005: TestDriftRecord_TDR005_NoAdditionalProperties)
```

To run related tests:
Expand Down
13 changes: 12 additions & 1 deletion specs/awf-config-sources-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,20 @@ The following documents are authoritative and MUST be consulted together:
- `docs/authentication-architecture.md` — credential isolation architecture
- `schemas/README.md` — schema directory overview

## Structure

This specification, the [conformance fixture index](awf-config-sources-compliance/README.md), and
[`pkg/workflow/awf_config_drift_test.go`](../pkg/workflow/awf_config_drift_test.go) form one
conformance unit. The specification defines `DriftRecord` requirements, the fixture index maps
them to `T-DR-*` IDs, and the Go test file implements those IDs. Changes to any member of this
unit **MUST** keep the other two members synchronized.

## 3. Data Model

This section defines the canonical data entities used in the drift detection procedure. The `DriftRecord` entity is the primary structured output of drift detection.
This section defines the canonical data entities used in the drift detection procedure. The
repository relationships that maintain its conformance coverage are defined in
[Structure](#structure). The `DriftRecord` entity is the primary structured output of drift
detection.

### 3.1 DriftRecord

Expand Down
18 changes: 6 additions & 12 deletions specs/compiler-threat-detection-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,11 @@ This section anchors the specification version to the minimum gh-aw binary versi
| Spec version | Minimum gh-aw binary version | Lock-file compatibility notes |
|--------------|------------------------------|-------------------------------|
| `1.0.20` | `v0.83.6` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), conditional import rejection (`imports.if` rejection for CTR-020), `workflow_run` trigger branch scope enforcement (CTR-021), git subprocess argument-injection guards for remote import/download ref and path arguments (CTR-022), and bash command allowlist illusion rejection for engines lacking allowlist enforcement (CTR-023). No `.lock.yml` schema changes are introduced by CTR-022 or CTR-023; both are compile-time-only validations. |
| `1.0.19` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), conditional import rejection (`imports.if` rejection for CTR-020), and `workflow_run` trigger branch scope enforcement (CTR-021). The `docker-sbx` runtime enforcement (CTR-004 scope) requires `sudo: true`, compatible runner topology, and a minimum AWF version; the credential refresh step emitted before agent execution is a security improvement with no new constraint on `.lock.yml` semantics. Playwright CLI mode (`tools.playwright.mode: cli`) is compiler-generated infrastructure with no new constraint on `.lock.yml` semantics. |
| `1.0.18` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), conditional import rejection (`imports.if` rejection for CTR-020), and `workflow_run` trigger branch scope enforcement (CTR-021). The `docker-sbx` runtime enforcement (CTR-004 scope) requires `sudo: true`, compatible runner topology, and a minimum AWF version; the credential refresh step emitted before agent execution is a security improvement with no new constraint on `.lock.yml` semantics. Playwright CLI mode (`tools.playwright.mode: cli`) is compiler-generated infrastructure with no new constraint on `.lock.yml` semantics. |
| `1.0.17` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), conditional import rejection (`imports.if` rejection for CTR-020), and `workflow_run` trigger branch scope enforcement (CTR-021). The `docker-sbx` runtime enforcement (CTR-004 scope) requires `sudo: true`, compatible runner topology, and a minimum AWF version; the credential refresh step emitted before agent execution is a security improvement with no new constraint on `.lock.yml` semantics. |
| `1.0.16` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), conditional import rejection (`imports.if` rejection for CTR-020), and `workflow_run` trigger branch scope enforcement (CTR-021). The `docker-sbx` runtime enforcement (CTR-004 scope) requires `sudo: true`, compatible runner topology, and a minimum AWF version; the credential refresh step emitted before agent execution is a security improvement with no new constraint on `.lock.yml` semantics. |
| `1.0.15` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), conditional import rejection (`imports.if` rejection for CTR-020), and `workflow_run` trigger branch scope enforcement (CTR-021). |
| `1.0.14` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019), and conditional import rejection (`imports.if` rejection for CTR-020). |
| `1.0.13` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), and cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019). |
| `1.0.12` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), and cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019). |
| `1.0.11` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), and cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019). |
| `1.0.10` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016), update-check validation (`check-for-updates` handling for CTR-018), and cache-memory integrity enforcement (`update_cache_memory` gating for CTR-019). |
| `1.0.9` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016) and update-check validation (`check-for-updates` handling for CTR-018). Top-level `sandbox: false` is no longer a valid workflow input; `sandbox.agent: false` is the supported field for CTR-004 detection. |
| `1.0.8` | `v0.72.1` (or newer) | Threat-detection behavior must remain compatible with current `.lock.yml` compilation semantics, including manifest drift enforcement (`gh-aw-manifest` checks for CTR-016) and update-check validation (`check-for-updates` handling for CTR-018). |
| `1.0.15`–`1.0.19` | `v0.72.1` (or newer) | Adds `workflow_run` trigger branch-scope enforcement (CTR-021); runtime-only `docker-sbx`, credential-refresh, and Playwright changes introduce no `.lock.yml` schema constraint. |
| `1.0.8`–`1.0.14` baseline | `v0.72.1` (or newer) | Establishes manifest drift (CTR-016), update-check (CTR-018), cache-memory integrity (CTR-019), and conditional-import (CTR-020) validation. |
Compact changelog: `1.0.8` introduced CTR-016 and CTR-018; `1.0.10`–`1.0.13` added
CTR-019; `1.0.14` added CTR-020; `1.0.15` added CTR-021; and `1.0.20` added CTR-022
and CTR-023. Versions with no distinct lock-file impact are grouped above.

When this specification version changes, maintainers MUST update this table in the same pull request as any lock-file compatibility changes.

Expand Down Expand Up @@ -247,6 +240,7 @@ When the GitHub API or any external service required by the optimizer (for examp
1. The optimizer **MUST** not emit false noop reports. When authoritative data cannot be retrieved, the optimizer **MUST** emit an `OPTIMIZER_DEGRADED` diagnostic entry in its daily output that records the failing endpoint(s), the HTTP status or error class, and the UTC timestamp of the failure.
2. The optimizer **MUST NOT** open a pull request or update spec artifacts based on incomplete threat-coverage data obtained during a degraded API run.
3. The optimizer **SHOULD** retry failed API calls with an exponential back-off policy (initial delay: 10 seconds; maximum delay: 5 minutes; maximum attempts: 3) before declaring the run degraded.
4. After exhausting that policy, the optimizer **MUST NOT** retry the same request against a different degraded endpoint; it **MUST** declare the run degraded unless a configured, independently authoritative endpoint is available.

**Failure Mode 2 — Runner Timeout**

Expand Down
Loading
Loading