Skip to content

Increase post-result watchdog default to 120s and add frontmatter timeout override - #51292

Merged
pelikhan merged 6 commits into
mainfrom
copilot/increase-watchdog-default-time
Aug 8, 2026
Merged

Increase post-result watchdog default to 120s and add frontmatter timeout override#51292
pelikhan merged 6 commits into
mainfrom
copilot/increase-watchdog-default-time

Conversation

Copilot AI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

The post-result harness watchdog default (20s of stdio inactivity after terminal safe output) was too short for legitimate quiet shell phases in large repos, causing premature SIGTERM and incomplete runs. This updates the shared default to 120s and adds a first-class frontmatter control so timeout behavior can be tuned per workflow while preserving env-var overrides.

  • Shared watchdog default

    • Raised DEFAULT_POST_RESULT_WATCHDOG_IDLE_TIMEOUT_MS from 20000 to 120000 in the shared process runner used by Copilot and Codex harnesses.
  • Frontmatter-configurable watchdog timeout

    • Added engine.harness.watchdog-timeout-ms.
    • Compiles to GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS so harness behavior is configurable from workflow frontmatter.
    • Existing override semantics remain: explicit engine.env.GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS still takes precedence.
  • Schema and docs updates

    • Extended the main workflow schema to validate engine.harness.watchdog-timeout-ms.
    • Updated engine/frontmatter reference docs to describe watchdog semantics, default, and override surfaces.
    • Added a changeset note documenting the behavior change.
  • Behavioral coverage additions

    • Added targeted assertions for:
      • new 120000ms default,
      • frontmatter parsing into engine config,
      • env injection to GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS,
      • validation bounds and precedence behavior.
engine:
  id: copilot
  harness:
    watchdog-timeout-ms: 120000

Run: https://github.com/github/gh-aw/actions/runs/31239156270> Generated by 👨‍🍳 PR Sous Chef · gpt54 · 13.2 AIC · ⌖ 5.14 AIC · ⊞ 8.5K ·

Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Increase post-result harness watchdog default to 2 minutes Increase post-result watchdog default to 120s and add frontmatter timeout override Aug 8, 2026
Copilot AI requested a review from pelikhan August 8, 2026 03:29
@pelikhan

pelikhan commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

@copilot use seconds.

watchdog-timeout: 120

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot use seconds.

...

Implemented in e70abf1. Frontmatter now uses seconds via engine.harness.watchdog-timeout (e.g. watchdog-timeout: 120), and it is converted to GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS during env injection.

@pelikhan
pelikhan marked this pull request as ready for review August 8, 2026 03:51
Copilot AI balanced review requested due to automatic review settings August 8, 2026 03:51
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ failed during design decision gate check.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • api.individual.githubcopilot.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "api.individual.githubcopilot.com"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

🧪 Test quality analysis by Test Quality Sentinel

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Raises the shared post-result watchdog default and adds workflow-level configuration.

Changes:

  • Raises the default timeout from 20 seconds to 120 seconds.
  • Adds frontmatter parsing and environment-variable injection.
  • Updates schema, tests, documentation, and release notes.
Show a summary per file
File Description
pkg/workflow/engine.go Adds watchdog engine configuration.
pkg/workflow/engine_helpers.go Injects the watchdog environment variable.
pkg/workflow/engine_helpers_test.go Tests injection and precedence.
pkg/workflow/engine_config_test.go Tests frontmatter extraction.
pkg/workflow/engine_config_parser.go Converts timeout values to milliseconds.
pkg/parser/schemas/main_workflow_schema.json Adds schema validation.
pkg/parser/schema_test.go Tests schema bounds.
docs/src/content/docs/reference/frontmatter-full.md Documents frontmatter syntax.
docs/src/content/docs/reference/engines.md Documents watchdog behavior.
actions/setup/js/process_runner.cjs Raises the shared default.
actions/setup/js/codex_harness.test.cjs Verifies the new default.
.changeset/patch-harness-watchdog-timeout-default-and-frontmatter.md Adds the release note.

Review details

Tip

Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 12/12 changed files
  • Comments generated: 3
  • Review effort level: Balanced

Comment thread pkg/workflow/engine_config_parser.go Outdated
return ""
}
if inner, ok := extractWrappedGitHubExpression(seconds); ok {
return "${{ (" + inner + ") * 1000 }}"
Comment thread pkg/workflow/engine.go
Comment on lines +531 to +532
if v, ok := h["watchdog-timeout"]; ok {
config.HarnessWatchdogTimeoutMs = parseHarnessWatchdogTimeoutValue(v)
| `initial-delay-ms` | `5000` | Delay in ms before the first retry |
| `backoff-multiplier` | `2` | Multiplier applied to the delay after each retry |
| `max-delay-ms` | `60000` | Maximum delay cap in ms |
| `watchdog-timeout` | `120` | Post-result idle watchdog timeout in seconds before terminating a quiet process |

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The implementation is clean and complete across all layers — schema, Go parser, env injection, JS harness constant, docs, and tests. No blocking issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 17.4 AIC · ⌖ 7.16 AIC · ⊞ 5.5K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /codebase-design and /tdd — requesting changes on three targeted issues.

📋 Key Themes & Issues

Issues Found

  1. Unit inconsistency (engines.md line 368): watchdog-timeout uses seconds while all sibling harness fields use milliseconds — a footgun that is easy to misread.
  2. Unreachable overflow guard (engine_config_parser.go line 83): maxInt64Div1000 can never be reached because ParseIntValue returns int. Replace with a meaningful 600 s upper bound matching the JS-side MAX_POST_RESULT_WATCHDOG_TIMEOUT_MS.
  3. Schema missing maximum (main_workflow_schema.json line 12808): Values > 600 s are silently clamped by the harness. Adding "maximum": 600 + a schema test gives users early feedback.
  4. Weak precedence test (engine_helpers_test.go line 91): Only checks the final value; an intermediate assert would make the override order verifiable.

Positive Highlights

  • ✅ Clean seconds→ms conversion in the parser with expression passthrough
  • ✅ Good coverage: default value, integer input, expression input, and env injection all tested
  • ✅ Changeset correctly tagged as patch

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 41.5 AIC · ⌖ 7.97 AIC · ⊞ 7.1K
Comment /matt to run again

engineLog.Printf("Ignoring invalid harness.watchdog-timeout value: %q", seconds)
return ""
}
const maxInt64Div1000 = int64((1<<63)-1) / 1000

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/codebase-design] The maxInt64Div1000 overflow guard is unreachable — ParseIntValue returns int, which overflows long before reaching int64 max ÷ 1000 on any supported platform.

💡 Details

parseIntOrExpressionValue calls typeutil.ParseIntValue which returns (int, bool). On 64-bit targets int tops out at ~9.2 × 1018, so parsedSeconds will never exceed maxInt64Div1000 (~9.2 × 1015). The guard was copied defensively but adds noise without protection.

The real upper bound enforced by the JS runtime is MAX_POST_RESULT_WATCHDOG_TIMEOUT_MS = 10 * 60 * 1000 (600 s). Consider validating against that instead:

const maxWatchdogSeconds = 600
if parsedSeconds > maxWatchdogSeconds {
    engineLog.Printf("Ignoring out-of-range harness.watchdog-timeout value (max 600 s): %q", seconds)
    return ""
}

This gives users a meaningful error when they exceed the JS-side clamp, keeping Go and JS bounds in sync.

@copilot please address this.

@@ -365,8 +366,9 @@ All four fields accept a literal integer or a GitHub Actions expression (e.g. `$
| `initial-delay-ms` | `5000` | Delay in ms before the first retry |
| `backoff-multiplier` | `2` | Multiplier applied to the delay after each retry |
| `max-delay-ms` | `60000` | Maximum delay cap in ms |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/codebase-design] watchdog-timeout uses seconds while every other engine.harness field uses milliseconds (initial-delay-ms, max-delay-ms, backoff-multiplier). This unit inconsistency is a user-facing footgun.

💡 Discussion

All sibling fields in the same engine.harness block use milliseconds. A user copying the retry-policy pattern might write watchdog-timeout: 120000 expecting 120 s, but would get 33 hours.

Consider:

  1. Rename to watchdog-timeout-ms (aligns with the injected env var GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS) — no s→ms conversion needed, no unit mismatch.
  2. Or keep seconds but rename to watchdog-timeout-seconds or watchdog-timeout-s to make the unit explicit.

If the seconds choice is intentional (human-friendly), the docs and schema description should explicitly warn about the unit difference from the other fields.

@copilot please address this.

"minimum": 1
},
{
"type": "string"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Schema enforces minimum: 1 but has no maximum, so values above the JS-side MAX_POST_RESULT_WATCHDOG_TIMEOUT_MS (600 s / 10 min) are silently clamped by the harness with no feedback to the user.

💡 Suggestion

Add "maximum": 600 to the schema integer branch to match MAX_POST_RESULT_WATCHDOG_TIMEOUT_MS:

"watchdog-timeout": {
  "oneOf": [
    {
      "type": "integer",
      "minimum": 1,
      "maximum": 600
    },
    { "type": "string" }
  ]
}

And add a negative test in schema_test.go for a value of 601 to document and protect this bound.

@copilot please address this.

},
}

applyEngineHarnessRetryEnv(env, workflowData)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The precedence test (engine.env override wins) calls applyEngineHarnessRetryEnv and applyEngineAndAgentEnv sequentially, but does not assert that the harness-injected value "120000" was first written and then overwritten — it only checks the final value. A race or bug that skips the harness injection entirely would still pass.

💡 Suggestion

Capture an intermediate snapshot to make the test a real precedence proof:

applyEngineHarnessRetryEnv(env, workflowData)
assert.Equal(t, "120000", env["GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS"], "harness injection should write 120000 first")

applyEngineAndAgentEnv(env, workflowData, nil)
assert.Equal(t, "90000", env["GH_AW_HARNESS_WATCHDOG_TIMEOUT_MS"], "engine.env override should win")

@copilot please address this.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Score: 78/100⚠️ Acceptable

Summary

This PR adds 85 lines of test code across 4 test files to verify the new engine.harness.watchdog-timeout frontmatter field and its propagation through configuration and environment injection. Quality: Good — 83% of tests are design-focused with proper edge-case coverage.

Key Metrics

  • Total test entities: 6 (new/modified tests)
  • Design tests: 5/6 (83%) ✅ Design-focused, behavioral contracts
  • Implementation tests: 1/6 (17%) ⚠️ Direct constant verification
  • Edge cases: 50% of tests include edge cases (invalid values, expression transformation, override precedence)
  • Test inflation: 1.29:1 (85 test lines / 66 prod lines) — ✅ Acceptable (<2:1 threshold)

Per-Test Breakdown

Test Classifications & Analysis
Test Type Lines Assertions Classification Value
TestValidateMainWorkflowFrontmatterWithSchemaAndLocation_EngineHarnessWatchdogTimeout NEW 33 2 behavioral_contract HIGH ✅
TestApplyEngineHarnessRetryEnv (subtest 1) NEW 18 5 behavioral_contract HIGH ✅
TestApplyEngineHarnessRetryEnv (subtest 2) NEW 16 1 behavioral_contract HIGH ✅
TestExtractEngineConfig (2 new rows + 1 assertion) MODIFIED 7 3 behavioral_contract HIGH ✅
"uses a 2-minute shared default" (JS) NEW 4 1 implementation_detail LOW ⚠️

Flagged Test:

  • codex_harness.test.cjs: "uses a 2-minute shared default" — Pure constant verification. If DEFAULT_POST_RESULT_WATCHDOG_IDLE_TIMEOUT_MS changes, the test fails, but no behavioral logic is verified. Acceptable as a sanity check but low signal for regressions.

Design Invariants Verified ✅

  1. Schema validation: Engine harness watchdog-timeout field accepts positive values (120), rejects invalid (0)
  2. Config extraction: Converts seconds → milliseconds; supports GitHub Actions expressions with transformation
  3. Environment injection: Harness policy env vars propagate correctly; engine.env overrides still take precedence
  4. Default constant: Shared 120-second default is enforced across JS harness module

Compliance Check ✅

  • No Go mock library usage ✅ (no gomock, testify/mock, .EXPECT(), .On())
  • No missing build tags
  • No assertions without context ✅ (all have descriptive failure messages)
  • No duplication

Verdict

PASS — Implementation test ratio is 17% (well below 30% threshold). Strong design coverage with proper edge cases and no violations. Score reflects "Acceptable" quality: solid behavioral contracts with one lightweight constant-check test.

🧪 Test quality analysis by Test Quality Sentinel · haiku45 · 27.8 AIC · ⌖ 4.2 AIC · ⊞ 7.7K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 78/100. 17% implementation tests (threshold: 30%). Strong design coverage with proper edge cases and no violations.

…timeout control

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot Quick triage nudge for this PR.

Please refresh the branch if GitHub can update it cleanly, address the remaining items below, and run the pr-finisher skill before handing back to maintainers.

Open items (newest first):

Branch refresh was requested.

Run: https://github.com/github/gh-aw/actions/runs/31239156270

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 13.2 AIC · ⌖ 5.14 AIC · ⊞ 8.5K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot use seconds.

...

Done — watchdog-timeout uses seconds for literal integers. Fixed in the latest commit: expressions (${{ ... }}) are now passed through unchanged (they must already be in ms, since GitHub Actions doesn't support arithmetic operators in expressions), and the docs note this constraint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Increase the post-result harness watchdog default from 20 seconds to 2 minutes

4 participants