Skip to content

feat(harness)!: steer by default, opt out with steer.enabled: false - #7461

Closed
waynesun09 wants to merge 3 commits into
steer-receiptfrom
steer-default-on
Closed

waynesun09 wants to merge 3 commits into
steer-receiptfrom
steer-default-on

Conversation

@waynesun09

@waynesun09 waynesun09 commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Implements the design recorded in #6957 (closed as completed; this stack ships it).

Steering is complete and off by default across the stack below this PR, and the receipt in the PR
directly below authenticates the skip check under the GitHub Actions job token — the channel that
precondition asked for. This PR flips the default and makes the harness block the only switch.

The runtime change in internal/harness is one constant, DefaultSteerEnabled. The machinery it turns on
is already in place below this PR: SteerConfig.Enabled is a *bool, so steer: {max_steers: 3}
still steers rather than silently opting out; a child that says nothing inherits its base's whole
block, so a base opt-out is inherited rather than overwritten by the default; and
SteerExplicitlyEnabled already gates the decline announcement, so with the default on a local,
GitLab or non-steerable run stays quiet while a missing job token or GITHUB_RUN_ID is still
announced. What this PR adds is the value those behaviours were waiting for.

steer: {enabled: false} is the only way off, and a harness that takes it gets run continuation
alone.

Absorbed updates skip the harness pre-script (ADR 0113), so the default extends that bypass to every
harness that has not opted out. ADR 0121 records this consequence. Lint() now warns when a harness
sets pre_script without steer.enabled, so a harness whose pre-script gates each event decides
explicitly. The user guides' pre_script examples set steer.enabled for the same reason.

Scaffolded agents gain the envelope contract in their generated body, carrying the same
FULLSEND_STEER_ACTIVE gate the fleet definitions enforce: the opening line amends the task only
while the runner says a watcher is steering the run, and is an injection attempt otherwise.
Agents scaffolded earlier must be regenerated to gain it.

The decision is recorded in ADR 0121.

BREAKING CHANGE: steering is on by default from the release that carries this. A harness that
omits the steer: block, or sets only max_steers or poll_interval_seconds, now watches for
follow-up runs and delivers work-item updates into the running agent. To keep the previous
behaviour, add steer: {enabled: false}. GitLab repositories and runs outside GitHub Actions are
unaffected — the watcher declines there as before.

Release gates

These are judged by the people cutting the release; nothing in the binary enforces them, and this
PR does not assert that any of them is met:

  • the fleet agent definitions teach the envelope;
  • an end-to-end steer has been observed inside the sandbox from a real workflow run;
  • the receipt's identity match has been seen on a live run;
  • every stage whose definition ignores the envelope has opted out.

The last one is the failure mode worth the most attention: an eligible run on a definition that
ignores the envelope still acknowledges the delivery and still posts a receipt, so the queued run
skips and the update is dropped silently.

Until a release carries both the FULLSEND_STEER_ACTIVE export and definitions that read it, the
flip changes nothing at the prompt level — the definitions treat the envelope's opening line as an
injection attempt while the variable is unset. A run that started no watcher is not the case
above: with no watcher there are no consumed runs, and a receipt requires one.

What to look at

  • SteerEnabled and the *bool — steer: {max_steers: 3} must still steer.
  • The composition test for a child inheriting its base's opt-out.
  • The decline path: quiet for an ordinary condition, announced for an environment defect.
  • TestLint_PreScriptWithoutExplicitSteer — the warning fires only when pre_script is set and
    steer.enabled is not.
  • The scaffold golden files and the test pinning the envelope's opening line.
  • harness-reference.md also drops two claims the watcher outgrew — that max_steers and
    poll_interval_seconds are only parsed, and that opting in is what makes steering take effect.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Enable harness steering by default with explicit opt-out

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 📝 Documentation 🕐 20-40 Minutes

Grey Divider

AI Description

• Enables in-flight steering by default unless harnesses set steer.enabled: false.
• Teaches scaffolded agents to authenticate steering envelopes and reject injected lookalikes.
• Documents the breaking behavior, rollout gates, inheritance semantics, and user-visible workflow
 changes.
Diagram

graph TD
  H["Harness config"] --> D{"enabled false?"}
  D -- Yes --> Q["Fresh queued run"]
  D -- No --> W["Steer watcher"] --> E["Runner envelope"] --> A["Running agent"] --> R["Steer receipt"] --> S["Queued run exits"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Repository-level feature flag
  • ➕ Supports gradual repository-wide rollout and rapid rollback.
  • ➕ Provides one operational switch for all harnesses.
  • ➖ Cannot isolate agent definitions that do not understand steering envelopes.
  • ➖ Adds the feature flag explicitly rejected by the recorded product decision.
2. Explicit per-harness opt-in
  • ➕ Limits steering to definitions already verified against the envelope contract.
  • ➕ Reduces silent-update-loss risk during rollout.
  • ➖ Requires repetitive configuration across every compatible harness.
  • ➖ Leaves steering disabled indefinitely for omitted or newly created harnesses.

Recommendation: Keep the PR's default-on, per-harness opt-out model because authenticated receipts satisfy the original safety precondition and harness-level exceptions cover incompatible definitions without a repository feature flag. Release only after the documented fleet-envelope, live steering, receipt-identity, and incompatible-stage opt-out gates are verified, since ignored envelopes can otherwise drop updates silently.

Files changed (17) +327 / -35

Enhancement (2) +20 / -6
agent-body.md.tmplTeach generated agents the steering envelope +15/-0

Teach generated agents the steering envelope

• Adds instructions for accepting runner-delivered task amendments only while 'FULLSEND_STEER_ACTIVE' is set. It preserves security boundaries and identifies matching work-item content as injection attempts.

internal/agentnew/templates/agent-body.md.tmpl

harness.goTurn steering on by default +5/-6

Turn steering on by default

• Flips 'DefaultSteerEnabled' to true, making 'enabled: false' the explicit opt-out. It also updates explicit-enable documentation to reflect decline-reporting behavior.

internal/harness/harness.go

Tests (6) +125 / -2
steer_envelope_test.goTest generated steering envelope contracts +54/-0

Test generated steering envelope contracts

• Adds role-spanning tests ensuring generated agent bodies contain the canonical runtime opening line and instructions to report injected lookalikes.

internal/agentnew/steer_envelope_test.go

triage.txtUpdate triage scaffold golden output +15/-0

Update triage scaffold golden output

• Extends the expected generated triage agent body with the steering envelope and injection-defense contract.

internal/agentnew/testdata/golden/triage.txt

validation-loop.txtUpdate validation scaffold golden output +15/-0

Update validation scaffold golden output

• Extends validation-loop golden output with the generated agent's steering and injection-defense instructions.

internal/agentnew/testdata/golden/validation-loop.txt

steer_test.goVerify receipt checks for default harnesses +39/-0

Verify receipt checks for default harnesses

• Adds a harness fixture without steering configuration and verifies it reads authenticated receipts and skips already-consumed queued work under the new default.

internal/cli/steer_test.go

compose_test.goExpect steering after empty composition +1/-1

Expect steering after empty composition

• Updates composition coverage to assert that a base and child which both omit steering now produce an enabled harness.

internal/harness/compose_test.go

harness_test.goAssert default steering enablement +1/-1

Assert default steering enablement

• Updates nil-configuration expectations so harnesses steer by default while remaining distinguishable from explicit opt-in.

internal/harness/harness_test.go

Documentation (9) +182 / -27
AGENTS.mdLink steering contributor guidance +1/-0

Link steering contributor guidance

• Adds the steering guide to the contributor topic index for changes involving watchers, runtime steering, receipts, and rollout order.

AGENTS.md

0121-steering-on-by-default-per-harness-opt-out.mdRecord the default-on steering decision +100/-0

Record the default-on steering decision

• Introduces ADR 0121, documenting considered switch models, the per-harness opt-out decision, rollout prerequisites, inheritance semantics, and operational consequences.

docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md

fix.mdExplain in-flight fix update absorption +5/-0

Explain in-flight fix update absorption

• Documents that active fix runs absorb new comments by default while opted-out harnesses leave work to the queued run.

docs/agents/fix.md

review.mdDocument review command amendments +7/-2

Document review command amendments

• Clarifies that arguments on review comments amend an active review run, with explicit steering opt-out restoring fresh queued runs.

docs/agents/review.md

triage.mdDocument triage command amendments +5/-2

Document triage command amendments

• Explains how comments posted during active triage amend the running agent and how harness opt-out changes that behavior.

docs/agents/triage.md

architecture.mdUpdate steering architecture defaults +4/-2

Update steering architecture defaults

• Revises the architecture overview from explicit steering opt-in to default-on behavior with per-harness opt-out and links ADR 0121.

docs/architecture.md

steering.mdDefine default-on steering and rollout gates +47/-16

Define default-on steering and rollout gates

• Updates configuration, eligibility, decline reporting, and composition semantics for default-on steering. Adds release sequencing and warns that envelope-incompatible definitions can silently lose absorbed updates.

docs/contributing/steering.md

bugfix-workflow.mdDescribe mid-run command delivery +8/-0

Describe mid-run command delivery

• Explains that authorized stage comments normally reach an in-flight agent and suppress duplicate queued work, unless the harness opts out.

docs/guides/user/bugfix-workflow.md

harness-reference.mdRevise harness steering reference +5/-5

Revise harness steering reference

• Changes 'steer.enabled' to an opt-out, documents eligibility and logging behavior, and clarifies cap, polling, sandbox, and inheritance semantics.

docs/reference/harness-reference.md

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 3:32 PM UTC · Completed 4:15 PM UTC

Commit: 80f699d · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5 · Effort: high · Cost: $9.60

@qodo-code-review

qodo-code-review Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Fleet agents drop steered updates ✗ Dismissed
Description
DefaultSteerEnabled now enables steering for every fullsend-ai/agents harness that omits an
opt-out, but their referenced agent definitions contain neither the runner-envelope instruction nor
the FULLSEND_STEER_ACTIVE gate. On eligible GitHub runs for code, fix, prioritize, retro, review,
scribe, or triage, the watcher can acknowledge and receipt an update that the active agent never
applies, so the queued run skips it.
Code

internal/harness/harness.go[R275-277]

+// about it. On since the release that carries it; a harness opts out with
+// enabled: false.
+const DefaultSteerEnabled = true
Relevance

●●● Strong

The PR explicitly acknowledges silent drops when fleet definitions ignore the envelope, making this
a concrete rollout correctness gap.

PR-#7061

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The PR changes an omitted steering setting from disabled to enabled. The agents repository's
GitHub-capable harnesses reference definitions that only describe their ordinary inputs and role
behavior, while containing no steering opt-out or envelope gate, so the new default activates a
contract those definitions do not implement.

internal/harness/harness.go[274-292]
External repo: fullsend-ai/agents, harness/review.yaml [1-17]
External repo: fullsend-ai/agents, harness/review.yaml [93-111]
External repo: fullsend-ai/agents, agents/review.md [1-55]
External repo: fullsend-ai/agents, harness/triage.yaml [1-70]
External repo: fullsend-ai/agents, agents/triage.md [1-100]
External repo: fullsend-ai/agents, harness/code.yaml [7-8]
External repo: fullsend-ai/agents, harness/fix.yaml [7-8]
External repo: fullsend-ai/agents, harness/prioritize.yaml [48-66]
External repo: fullsend-ai/agents, harness/retro.yaml [64-81]
External repo: fullsend-ai/agents, harness/scribe.yaml [72-85]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Default-on steering reaches the pinned fullsend-ai/agents fleet before its definitions understand the steering envelope, allowing acknowledged updates to be lost.

## Fix Focus Areas
- internal/harness/harness.go[274-277]
- /cross_repos/agents/harness/review.yaml[1-17]
- /cross_repos/agents/agents/review.md[1-55]
- /cross_repos/agents/harness/triage.yaml[1-70]
- /cross_repos/agents/agents/triage.md[1-100]

## Recommended Fix
Before enabling the default, coordinate an agents-repository change that adds the exact runner-envelope opening line and `FULLSEND_STEER_ACTIVE` validation contract to every fleet definition, plus a contract test covering every harness-referenced definition. Otherwise retain the disabled default or add `steer: {enabled: false}` to all affected fleet harnesses until synchronized releases contain that support.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. One decision record bundles policies ✗ Dismissed
Description
The Decision section sets the steering default and then separately defines decline-announcement
behavior, rollout-gate enforcement, and scaffolded-agent envelope handling. Future changes to any
one of these independent policies would require revising or superseding the same record, obscuring
which architectural choice is being changed.
Code

docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md[R70-73]

+With most runs now steering by default, most declined watches are ordinary conditions rather than
+misconfiguration: a local run is not in GitHub Actions, a GitLab run queues instead, a runtime
+that cannot take a message never could. The runner therefore announces a decline only when the
+harness asked for steering by name. A missing job token or run id is a defect in the environment
Relevance

●● Moderate

ADR structure feedback is often accepted, but no close precedent establishes that these policies
require separate records.

PR-#2743
PR-#6956

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance rule 1062089 requires each ADR to record exactly one decision. The new ADR first chooses
default-on steering and its opt-out at lines 60-62, but lines 70-84 additionally prescribe output
policy, release-gate enforcement, and generated-agent behavior.

docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md[60-84]
Skill: writing-adrs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
ADR 0121 records several independently changeable policies beyond the default-on steering decision, including decline reporting, rollout enforcement, and scaffolded-agent handling.

## Fix Focus Areas
- docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md[58-84]

## Recommended Fix
Keep ADR 0121 focused on steering being enabled by default with per-harness opt-out. Move independently changeable decisions into separate ADRs, or reframe non-decision material as links to existing records and implementation documentation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Harness jargon is left undefined ⊘ Outdated
Description
bugfix-workflow.md introduces harness in the new opt-out explanation without defining it or
linking its first use to the glossary. Developers encountering steering here must leave the workflow
guide to infer which agent configuration controls the behavior.
Code

docs/guides/user/bugfix-workflow.md[R73-74]

+An agent whose harness opts out with `steer: {enabled: false}` queues a fresh
+run instead, as it always has.
Relevance

●●● Strong

Recent guide reviews accepted defining or linking domain jargon on first use.

PR-#6455
PR-#5778

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance rule 1062083 requires jargon to be defined or linked on first use in a guide. The new
text uses harness without either treatment, even though the repository glossary provides the
applicable definition.

docs/guides/user/bugfix-workflow.md[73-74]
docs/glossary.md[197-202]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The user guide introduces the domain-specific term `harness` without defining it or linking to the existing glossary entry.

## Fix Focus Areas
- docs/guides/user/bugfix-workflow.md[73-74]

## Recommended Fix
Link the first occurrence of `harness` to `../../glossary.md#harness`, or add a concise inline definition before using the term.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. The steering contract lacks a spec ✗ Dismissed
Description
The Decision section embeds field-level semantics for absent versus false enabled values and
whole-block inheritance instead of linking to a versioned normative contract. Changes to
configuration compatibility now lack a canonical major-version boundary outside this point-in-time
record.
Code

docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md[R64-67]

+`enabled` is a pointer internally, because absent and `false` have to mean different things: a
+block that sets only `max_steers` or `poll_interval_seconds` is tuning steering, not silently
+opting out of it. Composition is unchanged and covers both directions — a child that says nothing
+inherits its base's whole block, so a base opt-out is inherited rather than overwritten by the
Relevance

●● Moderate

Evidence is mixed: normative cross-references are accepted, but removing inline ADR semantics was
recently rejected.

PR-#6956
PR-#6769

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance rule 1525847 requires field-level contracts to live under a versioned
docs/normative/<topic>/v<major>/ path and be linked from the ADR. Lines 64-68 define exact
configuration presence and inheritance semantics inline, while the repository contains no steering
specification under docs/normative/.

docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md[64-68]
Skill: writing-adrs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
ADR 0121 inlines detailed compatibility rules for the steering configuration rather than referencing a versioned normative specification.

## Fix Focus Areas
- docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md[64-68]

## Recommended Fix
Create a versioned steering contract under `docs/normative/`, document the `enabled` presence semantics and composition behavior there, and replace the detailed contract in the ADR with a concise link to that specification.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 72 rules
✅ Cross-repo context — repo relationships
  Explored: repo: fullsend-ai/agents (sha: 8eb4b4ba)
Review mode: ⚖️ Balanced: This changes a runtime default affecting steering, concurrency, authorization-sensitive workflow behavior, and generated agent contracts, so it warrants a complete careful review.

Grey Divider

Tip of the day
💡 Did you know, you can route each severity your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread docs/guides/user/bugfix-workflow.md Resolved
Comment thread internal/harness/harness.go Resolved
@codecov

codecov Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment at moderate risk (score 2): change size remains in the 11-25 files (22) and 300-799 lines (567) bands with exactly one protected path (AGENTS.md), no dependency changes, an established author, and rollback safety via the steer.enabled opt-out toggle. Score stable across 6+ prior review rounds on this PR; only file content (docs clarification, one new test) changed this round, not the overall shape.

Previous run

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment at moderate risk (score 2): change size remains in the 11-25 files (22) and 300-799 lines (567) bands with exactly one protected path (AGENTS.md), no dependency changes, an established author, and rollback safety via the steer.enabled opt-out toggle. Score stable across 6+ prior review rounds on this PR; only file content (a docs clarification) changed this round, not the overall shape.

Previous run (2)

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment at moderate risk (score 2): change size remains in the 11-25 files (22) and 300-799 lines (567) bands with exactly one protected path (AGENTS.md), no dependency changes, an established author, and rollback safety via the steer.enabled opt-out toggle. Score stable across 5+ prior review rounds on this PR.

Previous run (3)

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment at moderate risk (score 2): change size remains in the 11-25 files (22) and 300-799 lines (567) bands with exactly one protected path (AGENTS.md), no dependency changes, an established author, and rollback safety via the steer.enabled opt-out toggle. Only file content (docs clarifications, test additions) changed this round, not the overall shape.

Previous run (4)

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment at moderate risk (score 2): change size remains in the 11-25 files (22) and 300-799 lines (567) bands with exactly one protected path (AGENTS.md), no dependency changes, an established author, and rollback safety via the steer.enabled opt-out toggle. This PR's own diff content is byte-identical to the immediately prior reviewed round.

Previous run (5)

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment at moderate risk (score 2): file count grew from 18 to 22 files (567 lines) with the addition of harness linting, but change size remains in the same 11-25 files / 300-799 lines bands; protected paths remain limited to AGENTS.md with no dependency changes; the default-on steering change includes an opt-out config toggle providing rollback safety.

Previous run (6)

Risk Assessment: moderate (2/5)

Details

Anchored to prior assessment; Tier 1 signals unchanged (18 files, 515 lines, one protected path, no dependency changes, established author, opt-out toggle providing rollback safety).

Previous run (7)

Risk Assessment: moderate (2/5)

Details

Moderate risk from a 511-line default-on feature flip touching one protected path (AGENTS.md) and active harness code, anchored to the prior assessment as diff signals remain unchanged with an opt-out toggle and no dependency modifications.

Previous run (8)

Risk Assessment: moderate (2/5)

Details

Moderate risk from a 511-line default-on feature flip touching one protected path (AGENTS.md) and active harness code, anchored to the prior assessment as diff signals remain unchanged with an opt-out toggle and no dependency modifications.

Previous run (9)

Risk Assessment: moderate (2/5)

Details

Moderate risk from a 511-line default-on feature flip touching one protected path (AGENTS.md) and active harness code, anchored to the prior assessment as diff signals remain unchanged with an opt-out toggle and no dependency modifications.

Previous run (10)

Risk Assessment: moderate (2/5)

Details

Moderate risk from a 511-line default-on feature flip touching one protected path (AGENTS.md) and active harness code, mitigated by an opt-out configuration toggle, no dependency changes, and settled issue consensus.

Previous run (11)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata (18 files, 519 lines, one protected-path touch, no CI or dependency changes, established author) combined with Tier 2 git history on actively maintained files yields a 62/38-weighted composite that rounds to 2; the process-integrity and fail-open concerns are qualitative flags captured in review findings, not folded into the numeric score.

Previous run (12)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata (18 files, 519 lines, one protected-path touch, no CI or dependency changes, established author) combined with Tier 2 git history on actively maintained files yields a 62/38-weighted composite that rounds to 2; the process-integrity and missing-authorization concerns are qualitative flags captured in review findings, not folded into the numeric score.

Previous run (13)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata (18 files, 501 lines, one protected-path touch, no CI/dependency changes, established author) combined with Tier 2 git history on actively maintained harness files yields a 62/38-weighted composite that rounds to 2; the self-edited #6957 issue and process-integrity concern are qualitative flags captured in review findings, not folded into the numeric score.

Previous run (14)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata (18 files, 501 lines, one protected-path touch, no CI/dependency changes, established author) combined with Tier 2 git history on actively maintained harness files yields a 62/38-weighted composite that rounds to 2; the self-edited #6957 issue and process-integrity concern are qualitative flags captured in review findings, not folded into the numeric score.

Previous run (15)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata (18 files, 501 lines, one protected-path touch, no CI/dependency changes, established author) combined with Tier 2 git history on actively maintained harness files yields a 62/38-weighted composite that rounds to 2; the self-edited #6957 issue and process-integrity concern are qualitative flags captured in review findings, not folded into the numeric score.

Previous run (16)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata signals remain effectively unchanged (18 files, 501 lines, one protected path touch on AGENTS.md, no workflow or dependency changes, established author) and measured Tier 2 git history across active harness and documentation files yields a 62/38 composite that rounds to 2.

Previous run (17)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata signals remain effectively unchanged (18 files, 501 lines, one protected path touch on AGENTS.md, no workflow or dependency changes, established author) and measured Tier 2 git history across active harness and documentation files yields a 62/38 composite that rounds to 2.

Previous run (18)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the moderate (2) risk rating: Tier 1 metadata signals remain unchanged (18 files, 503 lines, one protected path touch on AGENTS.md, no workflow or dependency changes, established author) and measured Tier 2 git history across active harness and documentation files yields a 62/38 composite that rounds to 2.

Previous run (19)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the prior moderate (2) assessment: metadata signals are unchanged (18 files, 500 lines, single protected-path touch on AGENTS.md, no CI or dependency changes, established non-bot author) and measured Tier 2 git churn across the touched harness/compose hotspot files maintains a composite that, at the 62/38 (no linked issue) weighting, rounds to 2 (moderate). The unresolved contradiction with issue #6957's off-by-default validation criteria and the lack of a formal issue link remain qualitative flags reflected in review findings, not folded into the numeric score.

Previous run (20)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring preserves the prior moderate (2) assessment: metadata signals remain essentially unchanged (18 files/500 lines, single protected-path touch on AGENTS.md, no CI or dependency changes, established non-bot author) and measured Tier 2 git history maintains a composite around 3.0 across the core harness/compose hotspot files, giving a 62/38-weighted (no linked issue) composite that rounds to 2 (moderate).

Previous run (21)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring: Tier 1 metadata is byte-for-byte unchanged from the prior round (18 files/499 lines, medium blast radius, one protected-path touch on AGENTS.md, no CI/dependency changes, established non-bot author, test ratio 0.22) giving Tier 1 composite ~1.875, and Tier 2 git-history signals reproduce the prior pattern on the shared harness/compose hotspot files (high 30-day churn, broad author contention, heavy fix/revert-grep matches) yielding a Tier 2 composite in the same ~3.0 range; with no linked issue, 62/38 weighting gives 0.62x1.875 + 0.38x3.0 = 2.30, rounding to 2 (moderate), matching the prior assessment with no new risk drivers identified.

Previous run (22)

Risk Assessment: moderate (2/5)

Details

Re-review anchoring: Tier 1 metadata is unchanged from the prior round (1.875 -- 18 files/499 lines, one protected-path touch on AGENTS.md, no CI/dependency changes, established non-bot author) and Tier 2 churn/author/fix-revert signals on the same hotspot files reproduce the prior composite of 3.0; with no linked issue, 62/38 weighting gives 0.62x1.875 + 0.38x3.0 = 2.30, rounding to 2 (moderate), matching the prior assessment. The unreconciled #6957 discrepancy remains a qualitative flag captured in the review findings, not folded into the numeric score.

Previous run (23)

Risk Assessment: moderate (2/5)

Details

Repo checkout was not shallow this round, so Tier 2 was computable (previously degraded/unavailable): harness.go/AGENTS.md/architecture.md show very high 30-day churn, 8+ distinct authors in 90 days, and heavy fix/revert history (Tier2=3.0), but Tier1 remains modest (1.875) with no CI/workflow, dependency, or security-sensitive-path changes beyond the single AGENTS.md protected-path touch and an established non-bot author; weighted 62/38 (no linked issue) composite is 2.30, rounding to 2 (moderate) versus the prior round's anchored 3 (elevated), which had assumed Tier 2 was degraded rather than measuring it directly.

Previous run (24)

Risk Assessment: elevated (3/5)

Details

Tier 1 signals are unchanged from the prior assessment (18 files/497 lines, 1 protected path touched, no CI/dependency changes, non-bot non-first-time author), and Tier 2 remains degraded in this stale checkout, so anchoring preserves the prior elevated score of 3, driven by the explicit BREAKING CHANGE flipping steering to on-by-default, the AGENTS.md protected-path touch, and the PR's own risk/elevated + needs-human labels.

Previous run (25)

Risk Assessment: elevated (3/5)

Details

Explicitly declared BREAKING CHANGE flipping a default runtime behavior for every harness that does not opt out, touching a protected path (AGENTS.md) and high-churn/high-coupling files (internal/harness/harness.go, docs/architecture.md); raw weighted composite rounds to 2 but is adjusted up to 3 (elevated) given the breaking-change declaration, protected-path touch, and risk/elevated + needs-human labels the PR itself already carries.

Previous run (26)

Risk Assessment: elevated (3/5)

Details

Re-review anchoring applied: Tier 1 signals are unchanged from the prior assessment (same file/line/blast-radius bands, one protected-path hit, no CI/security/dependency touches, non-bot non-first-time author), and Tier 2 git-history checks reconfirm the same elevated pattern previously identified in internal/harness/harness.go and its co-located, high-churn, multi-author, fix-heavy test files. No new protected paths, dependency changes, or materially different file set were found, so the prior elevated score of 3 is preserved.

Previous run (27)

Risk Assessment: elevated (3/5)

Details

Tier 1 signals are unchanged from the prior review (moderate size/blast radius, no CI/security/dependency touches, one protected-path hit, non-bot non-first-time author), and Tier 2 confirms the same elevated-risk pattern previously identified: the breaking-change logic lands in internal/harness/harness.go and its directly co-located tests, all showing very high 30-day commit frequency, wide multi-author contention, and a dense fix-commit history. Per re-review anchoring, the prior elevated score of 3 is preserved; the unresolved contradiction between this PR default-on flip and issue #6957 validation criteria remains a qualitative flag rather than a numeric adjustment.

Previous run (28)

Risk Assessment: elevated (3/5)

Details

Tier 1/2 signals essentially unchanged from the prior review (core logic still lands in internal/harness/harness.go and its high-churn, multi-author test files); prior elevated score of 3 preserved. The unresolved contradiction with issue #6957 validation criteria and the lack of a formal issue link remain qualitative flags not folded into the numeric score.

Previous run (29)

Risk Assessment: elevated (3/5)

Details

Tier 1 metadata risk is low-moderate (no security/CI/dependency touches, non-first-time non-bot author, moderate size/blast radius) but Tier 2 is elevated because the core logic change lands in internal/harness/harness.go and its tests, files with very high recent churn and a dense fix/revert history, and no issue is formally linked (62/38 Tier1/Tier2 weighting yields ~3); the informal reference to issue #6957, whose acceptance criteria contradict this PR default-on flip and remain unreconciled, is a qualitative flag not folded into the numeric score.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Review

Findings

High

  • [protected-path] AGENTS.md:43 — This PR modifies AGENTS.md, which is on the repository's protected-paths list. The change further expands the "Steering" row's description in the topic-guidance table (now also naming internal/steerwatch/, the runtime.Steerer contract, the mailbox transport, provenance checks, the amendment/context split, settle, ceilings, the receipt/skip check, and rollout order) — a topic-index expansion, not a policy rewrite — but closingIssuesReferences for this PR is empty (re-verified via GraphQL this round), so no issue formally closes or links to this PR, and this falls under the insufficient-context criterion regardless of how mechanical the edit is. ADR 0121, added by this same PR, documents the design decision but does not substitute for a linked issue under this check's own, independent criterion. AGENTS.md is byte-identical to the prior reviewed SHA.
    Remediation: A maintainer must explicitly approve the AGENTS.md change; linking an authorizing issue would move this to the lower sufficient-context tier on a future re-review, but human approval is required either way.

  • [fail-open] internal/harness/harness.go:282 — DefaultSteerEnabled is true, so SteerEnabled() returns that default whenever h.Steer is nil or Enabled is unset — including harness YAML that omits steer: and any agent definition that has never been taught the steer envelope contract. startSteerWatcher and checkSteerAlreadyHandled gate solely on SteerEnabled(); neither inspects the loaded agent body for the envelope opening line or FULLSEND_STEER_ACTIVE teaching. This PR's own tests (TestStartSteerWatcher_StartsForADefaultHarness, TestCheckSteerAlreadyHandled_RunsForADefaultHarness) pin that both gates fire on SteerEnabled() alone. An untaught definition still yields a receipt and the queued run still exits on the skip check with the work-item update dropped silently — ADR 0121 and docs/contributing/steering.md's "Rollout order" section both name this as the residual failure mode. Newly scaffolded agents are taught the envelope, but only from this change forward — the existing fleet is untouched. internal/harness/harness.go is byte-identical to the prior reviewed SHA; the only content change this round (docs/contributing/steering.md, an unrelated clarification about head-move-budget truncation reporting) does not touch this gate. This round's adversarial challenger pass proposed removing this finding on the theory that ADR 0121's acceptance of the residual risk makes flagging it here a request to reverse the ADR. That argument has already been raised and explicitly rejected in this PR's own review history (round 831f3eec): "a documented, unenforced fail-open is still fail-open." No new evidence was presented this round to overturn that precedent, so the finding is restored at its anchored severity.
    Remediation: Do not enable DefaultSteerEnabled=true on main until a runner-side guard makes an untaught agent definition unable to silently drop the queued run (refuse to start the watcher, or withhold the receipt, unless the loaded agent body contains the steer envelope opening line / FULLSEND_STEER_ACTIVE teaching), or keep the constant false and flip it once fleet definitions teach the envelope and every non-participating role/harness has an explicit steer: {enabled: false}.

Medium

  • [process-integrity] docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md:31 — This PR is a breaking default-on flip (feat(harness)!) with empty closingIssuesReferences — no tracking issue formally authorizes it. ADR 0121 (line 31) cites issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 while conceding the meeting it records "speaks to event coalescing rather than to steering's own switch." Issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 closed 2026-09-21; its validation criteria were edited by the PR's own author (waynesun09) on 2026-09-24 to endorse default-on steering, followed roughly six hours later by a self-authored disclosure comment. Re-verified this round via the issue's full comment thread and the PR's full review history through 2026-09-30T21:09 UTC: no comment, edit, review, or approval from any GitHub user other than waynesun09 appears anywhere in that history — every PR review state and every issue comment since closure is either from waynesun09 or from bots. The needs-human label documents that independent sign-off is required, not that it has occurred.
    Remediation: Obtain sign-off from a maintainer who did not author this PR — either approval of a fresh, explicitly-scoped tracking issue for the default-on change, or an explicit maintainer statement in the PR itself — and formally link that issue to this PR. The retroactive edit to Steer the in-flight agent run on work-item updates instead of cancelling it #6957 is disclosed and explained, but disclosure by the same author is not independent authorization.

  • [cross-repo-contracts] internal/harness/harness.go:282 — DefaultSteerEnabled flipping false to true reinterprets every existing harness YAML with no steer: block (or one that sets only max_steers/poll_interval_seconds) for every downstream installation consuming reusable-dispatch.yml. A consumer pinned to reusable-dispatch.yml@main adopts the new default on its next dispatched run — fullsend_version falls back to job.workflow_sha, so there is no version such a consumer can hold back on — and nothing in the binary enforces the pre-release rollout audit. internal/harness/lint.go's Lint() warning narrows this only for the pre_script-without-steer.enabled sub-case; a harness with no pre_script that otherwise depends on steer being off gets no signal at all. Distinct from the fail-open finding above: that one is about silent data loss on an untaught agent definition; this one is about downstream automation having no way to detect or defer the behavioral change before it takes effect. internal/harness/harness.go and internal/harness/lint.go are byte-identical to the prior reviewed SHA. This round's challenger proposed removing this finding as a duplicate of the PR's disclosed breaking-change status, arguing the lint warning is the intended mitigation. This finding has survived independent re-derivation across 6+ prior rounds specifically because it targets a distinct gap — machine-readable detection for @main-pinned consumers — that a commit-message ! and a narrow lint warning do not close; the challenger's argument presents no new evidence changing that, so severity is preserved.
    Remediation: Either treat the ADR 0121 pre-merge audit (fleet definitions updated, opt-outs applied) as a hard, enforced merge gate rather than release-team guidance, or expose a machine-readable harness-schema/CLI version (or a transitional explicit-opt-in window) so @main-pinned automation can detect and defer the new default instead of inheriting it silently on the next dispatch.

  • [stale-documentation] docs/agents/prioritize.md:31 — The doc unconditionally states "The /fs-prioritize command does not accept arguments." With steering enabled by default (this PR), an in-flight /fs-prioritize run on GitHub Actions absorbs a subsequent comment and delivers the trailing text to the running agent as a task amendment, contradicting the doc. In this same PR, docs/agents/review.md and docs/agents/triage.md were updated to qualify the equivalent claim with "when it starts a run" and to explain the in-flight steering behavior, but docs/agents/prioritize.md was not touched and remains outside this PR's diff entirely.
    Remediation: Update docs/agents/prioritize.md to state that /fs-prioritize does not accept arguments when it starts a run, and add the same in-flight-absorption explanation used in review.md/triage.md (queues instead when steer: {enabled: false}, or on GitLab).

  • [missing-documentation] docs/contributing/harness-fields.md:66 — This doc is the canonical reference for Harness/ForgeConfig field classification and merge rules (per AGENTS.md). The Steer field — a genuine top-level Harness field (h.Steer *SteerConfig) whose default this PR flips from off to on for every harness that doesn't configure it — appears in neither the "Fields that stay at top level only" table nor the "Merge and inheritance rules" table. This PR does update the parallel, user-facing docs/reference/harness-reference.md, but leaves the contributor-facing classification/merge-semantics reference silent on steer. This round's challenger proposed removing this finding on the grounds that the steer field pre-dates this PR (ADR 0113) and so the gap is pre-existing rather than introduced here. That was equally true in every prior round, none of which removed the finding: this PR is precisely the one that makes steer's default-on behavior significant enough that it updated the parallel harness-reference.md, so the omission in the contributor-facing reference remains a live gap this PR's own scope should close.
    Remediation: Add steer to the "Fields that stay at top level only" table and the "Merge and inheritance rules" table in docs/contributing/harness-fields.md, documenting its top-level-only classification and whole-block replacement/inheritance merge semantics.

Low

  • [stale-reference] internal/cli/steer_test.go:54 — The steerHarness comment (lines 52-54) still says an absent steer block is a third state these tests never rely on and that "what that default is belongs to a later change" — but steerHarnessDefault() plus TestStartSteerWatcher_StartsForADefaultHarness / TestCheckSteerAlreadyHandled_RunsForADefaultHarness now explicitly rely on and assert default-on behavior. Separately, three unsteered-path comments still claim that path covers all of production: TestSteerAwareTimeout_UnsteeredPathUnchanged (line 640, "Steerable is false everywhere today"), TestHeartbeatBudget_UnsteeredIsTheHarnessTimeout (lines 713-715, "every run in production today"), and TestIterationEnvBudget_UnsteeredIsUnchanged (lines 726-727, "pins every run in production today"). The tests themselves remain valid, correctly-scoped unsteered-path (steered=false) regressions; only the comments are stale. This file is byte-identical to the prior reviewed SHA.
    Remediation: Update the steerHarness comment to reflect that steering is now enabled by default and that steerHarnessDefault() plus its tests now cover that default case. Rewrite the three unsteered-path comments to describe the steered=false timeout/heartbeat/budget paths without claiming they cover every production run.

Findings from the prior review not observed in the current diff: none. All seven prior findings persist. Of this PR's 22 files, only one differs in content from the prior reviewed SHA (621e2212078b9599339fce63091cdba7e201439e): docs/contributing/steering.md, which gained a clarification that a file listing longer than the head-move budget is reported as an unreadable move, and that a move the steer budget cuts off is not taken as told (the last-seen head does not advance, so the next steer reports the move again). This was established by direct blob-SHA comparison against the GitHub Contents API for all 22 files. The other 21 files, including internal/harness/harness.go, internal/harness/lint.go, AGENTS.md, and docs/ADRs/0121-...md, are byte-identical to the prior round. This round's internal/steerwatch/ package (which would implement the new claim) is outside this PR's diff and was not independently verifiable from the files fetched for this review. No maintainer other than the PR's own author has commented on, reviewed, or edited this PR or its linked issue since the prior round (re-verified via the GitHub API through 2026-09-30T21:09 UTC).

This round's challenger pass proposed removing three of the seven findings (the fail-open and cross-repo-contracts findings on internal/harness/harness.go, and the missing-documentation finding on docs/contributing/harness-fields.md) on code that is unchanged from the prior reviewed SHA. In each case the challenger's argument either reprises reasoning already explicitly rejected earlier in this PR's own review history, or fails to identify anything that changed since the last round in which an independent challenger pass kept the same finding. Per this review's severity-anchoring rule for unchanged code, all three findings are restored unmodified; this is noted for transparency rather than silently overridden.

This is based on reading the current diff and source, not on any external verification of runtime behavior.

Risk assessment: moderate (2/5) — anchored to the prior assessment; Tier 1 signals are unchanged (22 files / 567 lines, one protected path, no dependency changes, established author, opt-out toggle available).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run

Review

Findings

High

  • [protected-path] AGENTS.md:43 — This PR modifies AGENTS.md, which is on the repository's protected-paths list. The change expands the "Steering" row's description in the topic-guidance table (not a policy rewrite), but closingIssuesReferences for this PR is empty (re-verified via GraphQL this round), so no issue formally closes or links to this PR, and this falls under the insufficient-context criterion regardless of how mechanical the edit is. ADR 0121, added by this same PR, documents the design decision but does not substitute for a linked issue under this check's own, independent criterion. AGENTS.md is byte-identical to the prior reviewed SHA.
    Remediation: A maintainer must explicitly approve the AGENTS.md change; linking an authorizing issue would move this to the lower sufficient-context tier on a future re-review, but human approval is required either way.

  • [fail-open] internal/harness/harness.go:282 — DefaultSteerEnabled is true, so SteerEnabled() returns that default whenever h.Steer is nil or Enabled is unset — including harness YAML that omits steer: and any agent definition that has never been taught the steer envelope contract. startSteerWatcher and checkSteerAlreadyHandled gate solely on SteerEnabled(); neither inspects the loaded agent body for the envelope opening line or FULLSEND_STEER_ACTIVE teaching. This PR's own tests (TestStartSteerWatcher_StartsForADefaultHarness, TestCheckSteerAlreadyHandled_RunsForADefaultHarness) pin that both gates fire on SteerEnabled() alone. An untaught definition still yields a receipt and the queued run still exits on the skip check with the work-item update dropped silently — ADR 0121 and docs/contributing/steering.md's "Rollout order" section both name this as the residual failure mode. Newly scaffolded agents are taught the envelope, but only from this change forward — the existing fleet is untouched. internal/harness/harness.go is byte-identical to the prior reviewed SHA. This round's new content — a docs/contributing/steering.md subsection describing anti-replay checks 4 and 5 reading the Route/stage job by exact job name — hardens who is allowed to deliver a follow-up run; it does not address whether the receiving agent was ever taught the envelope, so this finding stands unchanged. An independent adversarial challenger pass this round re-verified the cited code and kept the finding without modification.
    Remediation: Do not enable DefaultSteerEnabled=true on main until a runner-side guard makes an untaught agent definition unable to silently drop the queued run (refuse to start the watcher, or withhold the receipt, unless the loaded agent body contains the steer envelope opening line / FULLSEND_STEER_ACTIVE teaching), or keep the constant false and flip it once fleet definitions teach the envelope and every non-participating role/harness has an explicit steer: {enabled: false}.

Medium

  • [process-integrity] docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md:31 — This PR is a breaking default-on flip (feat(harness)!) with empty closingIssuesReferences — no tracking issue formally authorizes it. ADR 0121 (line 31) cites issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 while conceding the meeting it records "speaks to event coalescing rather than to steering's own switch." Issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 closed 2026-09-21; its validation criteria were edited by the PR's own author (waynesun09) on 2026-09-24 to endorse default-on steering, followed roughly six hours later by a self-authored disclosure comment. Re-verified this round via the issue's full comment thread and the PR's full review history through 2026-09-30T20:49 UTC: no comment, edit, review, or approval from any GitHub user other than waynesun09 appears anywhere in that history — every PR review state and every issue comment since closure is either from waynesun09 or from bots. The needs-human label documents that independent sign-off is required, not that it has occurred.
    Remediation: Obtain sign-off from a maintainer who did not author this PR — either approval of a fresh, explicitly-scoped tracking issue for the default-on change, or an explicit maintainer statement in the PR itself — and formally link that issue to this PR. The retroactive edit to Steer the in-flight agent run on work-item updates instead of cancelling it #6957 is disclosed and explained, but disclosure by the same author is not independent authorization.

  • [cross-repo-contracts] internal/harness/harness.go:282 — DefaultSteerEnabled flipping false to true reinterprets every existing harness YAML with no steer: block (or one that sets only max_steers/poll_interval_seconds) for every downstream installation consuming reusable-dispatch.yml. This file is byte-identical to the prior reviewed SHA. This round's updated docs/contributing/steering.md ("Rollout order") confirms in its own words that a consumer pinned to reusable-dispatch.yml@main adopts the new default on its next dispatched run — fullsend_version falls back to job.workflow_sha, so there is no version such a consumer can hold back on — and that nothing in the binary enforces the pre-release rollout audit. internal/harness/lint.go's Lint() warning narrows this only for the pre_script-without-steer.enabled sub-case; a harness with no pre_script that otherwise depends on steer being off gets no signal at all. Distinct from the fail-open finding above: that one is about silent data loss on an untaught agent definition; this one is about downstream automation having no way to detect or defer the behavioral change before it takes effect.
    Remediation: Either treat the ADR 0121 pre-merge audit (fleet definitions updated, opt-outs applied) as a hard, enforced merge gate rather than release-team guidance, or expose a machine-readable harness-schema/CLI version (or a transitional explicit-opt-in window) so @main-pinned automation can detect and defer the new default instead of inheriting it silently on the next dispatch.

  • [stale-documentation] docs/agents/prioritize.md:31 — The doc unconditionally states "The /fs-prioritize command does not accept arguments." With steering enabled by default (this PR), an in-flight /fs-prioritize run on GitHub Actions absorbs a subsequent comment and delivers the trailing text to the running agent as a task amendment, contradicting the doc. In this same PR, docs/agents/review.md and docs/agents/triage.md were updated to qualify the equivalent claim with "when it starts a run" and to explain the in-flight steering behavior, but docs/agents/prioritize.md was not touched and remains outside this PR's diff entirely.
    Remediation: Update docs/agents/prioritize.md to state that /fs-prioritize does not accept arguments when it starts a run, and add the same in-flight-absorption explanation used in review.md/triage.md (queues instead when steer: {enabled: false}, or on GitLab).

  • [missing-documentation] docs/contributing/harness-fields.md:66 — This doc is the canonical reference for Harness/ForgeConfig field classification and merge rules (per AGENTS.md). The Steer field — a genuine top-level Harness field (h.Steer *SteerConfig) whose default this PR flips from off to on for every harness that doesn't configure it — appears in neither the "Fields that stay at top level only" table nor the "Merge and inheritance rules" table. This PR does update the parallel, user-facing docs/reference/harness-reference.md, but leaves the contributor-facing classification/merge-semantics reference silent on steer.
    Remediation: Add steer to the "Fields that stay at top level only" table and the "Merge and inheritance rules" table in docs/contributing/harness-fields.md, documenting its top-level-only classification and whole-block replacement/inheritance merge semantics.

Low

  • [stale-reference] internal/cli/steer_test.go:52 — The steerHarness comment (lines 52-54) still says an absent steer block is a third state these tests never rely on and that "what that default is belongs to a later change" — but steerHarnessDefault() plus TestStartSteerWatcher_StartsForADefaultHarness / TestCheckSteerAlreadyHandled_RunsForADefaultHarness now explicitly rely on and assert default-on behavior. Separately, three unsteered-path comments still claim that path covers all of production: TestSteerAwareTimeout_UnsteeredPathUnchanged (line 640, "Steerable is false everywhere today"), TestHeartbeatBudget_UnsteeredIsTheHarnessTimeout (lines 713-715, "every run in production today"), and TestIterationEnvBudget_UnsteeredIsUnchanged (lines 726-727, "pins every run in production today"). The tests themselves remain valid, correctly-scoped unsteered-path (steered=false) regressions; only the comments are stale. This file gained a new test since the prior review (TestSteerSession_TurnEndKeepsTheNewest, pinning that the one-slot turnEnd channel keeps the newest turn end — itself unremarkable), which shifted the line numbers of the stale comments down from their prior positions; the comments' substance is unchanged.
    Remediation: Update the steerHarness comment to reflect that steering is now enabled by default and that steerHarnessDefault() plus its tests now cover that default case. Rewrite the three unsteered-path comments to describe the steered=false timeout/heartbeat/budget paths without claiming they cover every production run.

Findings from the prior review not observed in the current diff: none. All seven prior findings persist. Of this PR's 22 files, two differ in content from the prior reviewed SHA (bbfb0dab3dfdfc7295928f931372ce5c03ead9b8): docs/contributing/steering.md (a new subsection explaining that anti-replay checks 4 and 5 read the Route/stage job by exact job name, since a run's job listing mixes the shim's own jobs with the reusable workflow's) and internal/cli/steer_test.go (a new test, TestSteerSession_TurnEndKeepsTheNewest, pinning one-slot-channel behavior — this insertion shifted the line numbers of the pre-existing stale test comments, addressed above). Neither change touches the code or documents underlying any of the seven persisting findings. This was established by direct blob-SHA comparison against the GitHub Contents API for all 22 files. The other 20 files, including internal/harness/harness.go, internal/harness/lint.go, AGENTS.md, and docs/ADRs/0121-...md, are byte-identical to the prior round. No maintainer other than the PR's own author has commented on, reviewed, or edited this PR or its linked issue since the prior round (re-verified via the GitHub API through 2026-09-30T20:49 UTC). All findings above were independently re-derived this round by fresh sub-agent dispatches per dimension, then adjudicated by an adversarial challenger pass, which kept all six sub-agent findings without modification; the protected-path finding is an orchestrator-only check, re-applied this round against unchanged facts (AGENTS.md byte-identical, closingIssuesReferences still empty).

This is based on reading the current diff and source, not on any external verification of runtime behavior.

Risk assessment: moderate (2/5) — anchored to the prior assessment; Tier 1 signals are unchanged (22 files / 567 lines, one protected path, no dependency changes, established author, opt-out toggle available).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (2)

Review

Findings

High

  • [protected-path] AGENTS.md:49 — This PR modifies AGENTS.md, which is on the repository's protected-paths list. The change expands the "Steering" row's description in the topic-guidance table (not a policy rewrite), but closingIssuesReferences for this PR is empty, so no issue formally closes or links to this PR, and this falls under the insufficient-context criterion regardless of how mechanical the edit is. ADR 0121, added by this same PR, documents the design decision but does not substitute for a linked issue under this check's own, independent criterion. AGENTS.md is byte-identical to the prior reviewed SHA.
    Remediation: A maintainer must explicitly approve the AGENTS.md change; linking an authorizing issue would move this to the lower sufficient-context tier on a future re-review, but human approval is required either way.

  • [fail-open] internal/harness/harness.go:282 — DefaultSteerEnabled is true, so SteerEnabled() returns that default whenever h.Steer is nil or Enabled is unset — including harness YAML that omits steer: and any agent definition that has never been taught the steer envelope contract. startSteerWatcher and checkSteerAlreadyHandled gate solely on SteerEnabled(); neither inspects the loaded agent body for the envelope opening line or FULLSEND_STEER_ACTIVE teaching. This PR's own tests (TestStartSteerWatcher_StartsForADefaultHarness, TestCheckSteerAlreadyHandled_RunsForADefaultHarness) pin that both gates fire on SteerEnabled() alone. An untaught definition still yields a receipt and the queued run still exits on the skip check with the work-item update dropped silently — ADR 0121 and docs/contributing/steering.md's "Rollout order" section both name this as the residual failure mode and concede that nothing in the binary enforces the pre-release rollout gates. Newly scaffolded agents are taught the envelope, but only from this change forward — the existing fleet is untouched. internal/harness/harness.go and internal/harness/lint.go are byte-identical to the prior reviewed SHA. The only content change since the prior round — a docs/contributing/steering.md clarification that a matched pi ack attests rpc-message-id acceptance, not that the runner's text survived — restates an existing limitation and does not add a runner-side envelope guard, so this finding stands unchanged. An independent adversarial challenger pass this round re-verified the cited code and kept the finding without modification.
    Remediation: Do not enable DefaultSteerEnabled=true on main until a runner-side guard makes an untaught agent definition unable to silently drop the queued run (refuse to start the watcher, or withhold the receipt, unless the loaded agent body contains the steer envelope opening line / FULLSEND_STEER_ACTIVE teaching), or keep the constant false and flip it once fleet definitions teach the envelope and every non-participating role/harness has an explicit steer: {enabled: false}.

Medium

  • [process-integrity] docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md:31 — This PR is a breaking default-on flip (feat(harness)!) with empty closingIssuesReferences — no tracking issue formally authorizes it. ADR 0121 (line 31) cites issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 while conceding the meeting it records "speaks to event coalescing rather than to steering's own switch." Issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 closed 2026-09-21; its validation criteria were edited by the PR's own author (waynesun09) on 2026-09-24 to endorse default-on steering, followed roughly six hours later by a self-authored disclosure comment acknowledging "the PRs still need maintainer approval to merge." Re-verified this round via the issue's full comment thread and the PR's full review history through 2026-09-30T19:36 UTC (fetched directly via the GitHub API): no comment, edit, review, or approval from any GitHub user other than waynesun09 appears anywhere in that history — every PR review state and every issue comment since closure is either from waynesun09 or from bots (fullsend-ai-review[bot], qodo-code-review[bot], codecov[bot], github-actions[bot]). The needs-human label documents that independent sign-off is required, not that it has occurred.
    Remediation: Obtain sign-off from a maintainer who did not author this PR — either approval of a fresh, explicitly-scoped tracking issue for the default-on change, or an explicit maintainer statement in the PR itself — and formally link that issue to this PR. The retroactive edit to Steer the in-flight agent run on work-item updates instead of cancelling it #6957 is disclosed and explained, but disclosure by the same author is not independent authorization.

  • [cross-repo-contracts] internal/harness/harness.go:282 — DefaultSteerEnabled flipping false to true reinterprets every existing harness YAML with no steer: block (or one that sets only max_steers/poll_interval_seconds) for every downstream installation consuming reusable-dispatch.yml. Consumers pinned to reusable-dispatch.yml@main adopt the new default on their next dispatched run — fullsend_version falls back to job.workflow_sha, so there is no version such a consumer can hold back on — with no schema/config version field, CLI flag, or other machine-readable signal to detect or defer the change. internal/harness/lint.go's Lint() warning narrows this only for the pre_script-without-steer.enabled sub-case; it is non-blocking, and a harness with no pre_script that otherwise depends on steer being off gets no signal at all. Distinct from the fail-open finding above: that one is about silent data loss on an untaught agent definition; this one is about downstream automation having no way to detect or defer the behavioral change before it takes effect. internal/harness/harness.go and internal/harness/lint.go are byte-identical to the prior reviewed SHA.
    Remediation: Either treat the ADR 0121 pre-merge audit (fleet definitions updated, opt-outs applied) as a hard, enforced merge gate rather than release-team guidance, or expose a machine-readable harness-schema/CLI version (or a transitional explicit-opt-in window) so @main-pinned automation can detect and defer the new default instead of inheriting it silently on the next dispatch.

  • [stale-documentation] docs/agents/prioritize.md:31 — The doc unconditionally states "The /fs-prioritize command does not accept arguments." With steering enabled by default (this PR), an in-flight /fs-prioritize run on GitHub Actions absorbs a subsequent comment and delivers the trailing text to the running agent as a task amendment, contradicting the doc. In this same PR, docs/agents/review.md and docs/agents/triage.md were updated to qualify the equivalent claim with "when it starts a run" and to explain the in-flight steering behavior, but docs/agents/prioritize.md was not touched and remains outside this PR's diff entirely.
    Remediation: Update docs/agents/prioritize.md to state that /fs-prioritize does not accept arguments when it starts a run, and add the same in-flight-absorption explanation used in review.md/triage.md (queues instead when steer: {enabled: false}, or on GitLab).

  • [missing-documentation] docs/contributing/harness-fields.md:66 — This doc is the canonical reference for Harness/ForgeConfig field classification and merge rules (per AGENTS.md). The Steer field — a genuine top-level Harness field (h.Steer *SteerConfig) whose default this PR flips from off to on for every harness that doesn't configure it — appears in neither the "Fields that stay at top level only" table nor the "Merge and inheritance rules" table. This PR does update the parallel, user-facing docs/reference/harness-reference.md, but leaves the contributor-facing classification/merge-semantics reference silent on steer.
    Remediation: Add steer to the "Fields that stay at top level only" table and the "Merge and inheritance rules" table in docs/contributing/harness-fields.md, documenting its top-level-only classification and whole-block replacement/inheritance merge semantics.

Low

  • [stale-reference] internal/cli/steer_test.go:52 — The steerHarness comment (lines 52-54) still says an absent steer block is a third state these tests never rely on and that "what that default is belongs to a later change" — but steerHarnessDefault() plus TestStartSteerWatcher_StartsForADefaultHarness / TestCheckSteerAlreadyHandled_RunsForADefaultHarness now explicitly rely on and assert default-on behavior. Separately, three unsteered-path comments still claim that path covers all of production: TestSteerAwareTimeout_UnsteeredPathUnchanged (line 623, "Steerable is false everywhere today"), TestHeartbeatBudget_UnsteeredIsTheHarnessTimeout (lines 696-698, "every run in production today"), and TestIterationEnvBudget_UnsteeredIsUnchanged (lines 709-710, "pins every run in production today"). The tests themselves remain valid, correctly-scoped unsteered-path (steered=false) regressions; only the comments are stale.
    Remediation: Update the steerHarness comment (lines 52-54) to reflect that steering is now enabled by default and that steerHarnessDefault() plus its tests now cover that default case. Rewrite the three unsteered-path comments (lines 623, 696-698, 709-710) to describe the steered=false timeout/heartbeat/budget paths without claiming they cover every production run.

Findings from the prior review not observed in the current diff: none. All seven prior findings persist. Of this PR's 22 files, only one differs in content from the prior reviewed SHA (cbd5ec9c9f97e95b69a1cd9ff843cde569d40f39): docs/contributing/steering.md, which gained a 3-line clarification about pi ack semantics (that a matched ack attests rpc-message-id acceptance, not that the runner's text survived) — a restatement of a caveat the document already made elsewhere, not a behavior or code change, and not a fix to any of the seven findings above. This was established by direct blob-SHA comparison against the GitHub Contents API for all 22 files (the GitHub compare API reports diverged for this SHA pair, as in prior rounds, because this PR sits in a stacked series whose shared base branch keeps advancing). The other 21 files, including internal/harness/harness.go, internal/harness/lint.go, AGENTS.md, and docs/ADRs/0121-...md, are byte-identical to the prior round. No maintainer other than the PR's own author has commented on, reviewed, or edited this PR or its linked issue since the prior round (re-verified via the GitHub API through 2026-09-30T19:36 UTC). All findings above were independently re-derived this round by fresh sub-agent dispatches per dimension, then adjudicated by an adversarial challenger pass, which kept all seven findings without modification.

This is based on reading the current diff and source, not on any external verification of runtime behavior.

Risk assessment: moderate (2/5) — anchored to the prior assessment; Tier 1 signals are unchanged (22 files / 567 lines, one protected path, no dependency changes, established author, opt-out toggle available).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (3)

Review

Findings

High

  • [protected-path] AGENTS.md — This PR modifies AGENTS.md, which is on the repository's protected-paths list. The change further expands the "Steering" row's description in the topic-guidance table (not a policy rewrite), but closingIssuesReferences for this PR is empty (re-verified via GraphQL this round), so no issue formally closes or links to this PR, and this falls under the insufficient-context criterion regardless of how mechanical the edit is. ADR 0121, added by this same PR, documents the design decision but does not substitute for a linked issue under this check's own, independent criterion. AGENTS.md is byte-identical to the prior reviewed SHA.
    Remediation: A maintainer must explicitly approve the AGENTS.md change; linking an authorizing issue would move this to the lower sufficient-context tier on a future re-review, but human approval is required either way.

  • [fail-open] internal/harness/harness.go:282 — DefaultSteerEnabled is true, so SteerEnabled() returns that default whenever h.Steer is nil or Enabled is unset — including harness YAML that omits steer: and any agent definition that has never been taught the steer envelope contract. startSteerWatcher and checkSteerAlreadyHandled gate solely on SteerEnabled(); neither inspects the loaded agent body for the envelope opening line or FULLSEND_STEER_ACTIVE teaching. This PR's own tests (TestStartSteerWatcher_StartsForADefaultHarness, TestCheckSteerAlreadyHandled_RunsForADefaultHarness) pin that both gates fire on SteerEnabled() alone. An untaught definition still yields a receipt and the queued run still exits on the skip check with the work-item update dropped silently — ADR 0121 and docs/contributing/steering.md's "Rollout order" section both name this as the residual failure mode and concede that nothing in the binary enforces the pre-release rollout gates. Newly scaffolded agents are taught the envelope, but only from this change forward — the existing fleet is untouched. internal/harness/harness.go is byte-identical to the prior reviewed SHA; a fresh security-dimension dispatch and an adversarial challenger pass both independently re-derived this finding at high severity this round with no new mitigating evidence.
    Remediation: Do not enable DefaultSteerEnabled=true on main until a runner-side guard makes an untaught agent definition unable to silently drop the queued run (refuse to start the watcher, or withhold the receipt, unless the loaded agent body contains the steer envelope opening line / FULLSEND_STEER_ACTIVE teaching), or keep the constant false and flip it once fleet definitions teach the envelope and every non-participating role/harness has an explicit steer: {enabled: false}.

Medium

  • [process-integrity] docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md:31 — This PR is a breaking default-on flip (feat(harness)!) with empty closingIssuesReferences — no tracking issue formally authorizes it. ADR 0121 (line 31) cites issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 while conceding the meeting it records "speaks to event coalescing rather than to steering's own switch." Issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 closed 2026-09-21; its validation criteria were edited by the PR's own author (waynesun09) on 2026-09-24 to endorse default-on steering, followed roughly six hours later by a self-authored disclosure comment. Re-verified this round via the issue's comment thread and the PR's full review history through 2026-09-30T01:30 (fetched directly via the GitHub API): no comment, edit, or review from any maintainer other than the PR's own author is on record endorsing either the edit or the default-on decision — every PR review state and every issue comment since closure is either from waynesun09 or from bots. The needs-human label documents that independent sign-off is required, not that it has occurred.
    Remediation: Obtain sign-off from a maintainer who did not author this PR — either approval of a fresh, explicitly-scoped tracking issue for the default-on change, or an explicit maintainer statement in the PR itself — and formally link that issue to this PR. The retroactive edit to Steer the in-flight agent run on work-item updates instead of cancelling it #6957 is disclosed and explained, but disclosure by the same author is not independent authorization.

  • [cross-repo-contracts] internal/harness/harness.go:282 — DefaultSteerEnabled flipping false to true reinterprets every existing harness YAML with no steer: block (or one that sets only max_steers/poll_interval_seconds) for every downstream installation consuming reusable-dispatch.yml. Consumers pinned to reusable-dispatch.yml@main adopt the new default on their next dispatched run — fullsend_version falls back to job.workflow_sha, so there is no version such a consumer can hold back on — with no schema/config version field, CLI flag, or other machine-readable signal to detect or defer the change. internal/harness/lint.go's Lint() warning narrows this only for the pre_script-without-steer.enabled sub-case; it is non-blocking, and a harness with no pre_script that otherwise depends on steer being off gets no signal at all. Distinct from the fail-open finding above: that one is about silent data loss on an untaught agent definition; this one is about downstream automation having no way to detect or defer the behavioral change before it takes effect. internal/harness/harness.go and internal/harness/lint.go are byte-identical to the prior reviewed SHA.
    Remediation: Either treat the ADR 0121 pre-merge audit (fleet definitions updated, opt-outs applied) as a hard, enforced merge gate rather than release-team guidance, or expose a machine-readable harness-schema/CLI version (or a transitional explicit-opt-in window) so @main-pinned automation can detect and defer the new default instead of inheriting it silently on the next dispatch.

  • [stale-documentation] docs/agents/prioritize.md:31 — The doc unconditionally states "The /fs-prioritize command does not accept arguments." With steering enabled by default (this PR), an in-flight /fs-prioritize run on GitHub Actions absorbs a subsequent comment and delivers the trailing text to the running agent as a task amendment, contradicting the doc. In this same PR, docs/agents/review.md and docs/agents/triage.md were updated to qualify the equivalent claim with "when it starts a run" and to explain the in-flight steering behavior, but docs/agents/prioritize.md was not touched and remains outside this PR's diff entirely.
    Remediation: Update docs/agents/prioritize.md to state that /fs-prioritize does not accept arguments when it starts a run, and add the same in-flight-absorption explanation used in review.md/triage.md (queues instead when steer: {enabled: false}, or on GitLab).

  • [missing-documentation] docs/contributing/harness-fields.md:66 — This doc is the canonical reference for Harness/ForgeConfig field classification and merge rules (per AGENTS.md). The Steer field — a genuine top-level Harness field (h.Steer *SteerConfig, internal/harness/harness.go) whose default this PR flips from off to on for every harness that doesn't configure it — appears in neither the "Fields that stay at top level only" table nor the "Merge and inheritance rules" table. Re-verified this round by grepping the doc (case-insensitive, "steer") — zero matches. This PR does update the parallel, user-facing docs/reference/harness-reference.md, but leaves the contributor-facing classification/merge-semantics reference silent on steer. docs/contributing/harness-fields.md is not part of this PR's diff.
    Remediation: Add steer to the "Fields that stay at top level only" table and the "Merge and inheritance rules" table in docs/contributing/harness-fields.md, documenting its top-level-only classification and whole-block replacement/inheritance merge semantics.

Low

  • [stale-reference] internal/cli/steer_test.go:52 — The steerHarness comment (lines 52-54) still says an absent steer block is a third state these tests never rely on and that "what that default is belongs to a later change" — but steerHarnessDefault() plus TestStartSteerWatcher_StartsForADefaultHarness / TestCheckSteerAlreadyHandled_RunsForADefaultHarness now explicitly rely on and assert default-on behavior. Separately, three unsteered-path comments still claim that path covers all of production: TestSteerAwareTimeout_UnsteeredPathUnchanged (line 623, "Steerable is false everywhere today"), TestHeartbeatBudget_UnsteeredIsTheHarnessTimeout (lines 696-698, "every run in production today"), and TestIterationEnvBudget_UnsteeredIsUnchanged (lines 709-710, "pins every run in production today"). The tests themselves remain valid, correctly-scoped unsteered-path (steered=false) regressions; only the comments are stale.
    Remediation: Update the steerHarness comment (lines 52-54) to reflect that steering is now enabled by default and that steerHarnessDefault() plus its tests now cover that default case. Rewrite the three unsteered-path comments (lines 623, 696-698, 709-710) to describe the steered=false timeout/heartbeat/budget paths without claiming they cover every production run.

Findings from the prior review not observed in the current diff: none. All seven prior findings persist. Of this PR's 22 files, only 3 differ in content from the prior reviewed SHA (371245c5): docs/architecture.md, docs/reference/harness-reference.md, and internal/cli/steer_test.go — all wording/test-comment updates to the already-documented default-on mechanism, not a change to the underlying fail-open gap, authorization gap, or the two stale-documentation issues. This was established by direct blob-sha comparison against the GitHub Contents API for all 22 files (the compare API reports diverged here, as in prior rounds, because this PR sits in a stacked series whose shared base branch keeps advancing). The other 19 files, including internal/harness/harness.go, internal/harness/lint.go, AGENTS.md, and docs/ADRs/0121-...md, are byte-identical to the prior round. No maintainer other than the PR's own author has commented on, reviewed, or edited this PR or its linked issue since the prior round. All findings above were independently re-derived this round by fresh sub-agent dispatches per dimension, then adjudicated by an adversarial challenger pass, which kept all seven findings without modification.

This is based on reading the current diff and source, not on any external verification of runtime behavior.

Risk assessment: moderate (2/5) — anchored to the prior assessment; Tier 1 signals are unchanged (22 files / 567 lines, one protected path, no dependency changes, established author, opt-out toggle available).


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR
Previous run (4)

Review

Findings

High

  • [protected-path] AGENTS.md — This PR modifies AGENTS.md, which is on the repository's protected-paths list. The change further expands the "Steering" row's description in the topic-guidance table (not a policy rewrite), but closingIssuesReferences for this PR is empty (re-verified via GraphQL this round), so no issue formally closes or links to this PR, and this falls under the insufficient-context criterion regardless of how mechanical the edit is. ADR 0121, added by this same PR, documents the design decision but does not substitute for a linked issue under this check's own, independent criterion. AGENTS.md gained new content this round (the Steering row now also names internal/steerwatch/, provenance checks, the amendment/context split, settle, ceilings, the receipt/skip check, and rollout order), which does not change this finding's basis.
    Remediation: A maintainer must explicitly approve the AGENTS.md change; linking an authorizing issue would move this to the lower sufficient-context tier on a future re-review, but human approval is required either way.

  • [fail-open] internal/harness/harness.go:282 — DefaultSteerEnabled is true, so SteerEnabled() returns that default whenever h.Steer is nil or Enabled is unset — including harness YAML that omits steer: and any agent definition that has never been taught the steer envelope contract. startSteerWatcher and checkSteerAlreadyHandled gate solely on SteerEnabled(); neither inspects the loaded agent body for the envelope opening line or FULLSEND_STEER_ACTIVE teaching. This PR's tests (TestStartSteerWatcher_StartsForADefaultHarness, TestCheckSteerAlreadyHandled_RunsForADefaultHarness) pin that both gates fire on SteerEnabled() alone, and fail if gated on SteerExplicitlyEnabled() instead. Newly scaffolded agents (internal/agentnew/templates/agent-body.md.tmpl) are taught the envelope, but that only covers agents generated from this change forward — the existing fleet is untouched. An untaught definition still yields a receipt and the queued run still exits on the skip check with the work-item update dropped silently; ADR 0121 and docs/contributing/steering.md's new "Rollout order" section both name this as the residual failure mode and concede that nothing in the binary enforces the pre-release rollout gates. internal/harness/harness.go and internal/harness/lint.go are byte-identical to the prior reviewed SHA (831f3ee) — confirmed this round via GitHub Contents API blob-sha comparison. A fresh security-dimension dispatch and an adversarial challenger pass both independently re-derived this finding at high severity this round with no new mitigating evidence, consistent with every prior review round on this unchanged code.
    Remediation: Do not enable DefaultSteerEnabled=true on main until a runner-side guard makes an untaught agent definition unable to silently drop the queued run (refuse to start the watcher, or withhold the receipt, unless the loaded agent body contains the steer envelope opening line / FULLSEND_STEER_ACTIVE teaching), or keep the constant false and flip it once fleet definitions teach the envelope and every non-participating role/harness has an explicit steer: {enabled: false}.

Medium

  • [process-integrity] docs/ADRs/0121-steering-on-by-default-per-harness-opt-out.md:31 — This PR is a breaking default-on flip (feat(harness)!) with empty closingIssuesReferences — no tracking issue formally authorizes it. ADR 0121 (line 31, byte-identical to the prior reviewed SHA) cites issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 while conceding the meeting it records "speaks to event coalescing rather than to steering's own switch." Issue Steer the in-flight agent run on work-item updates instead of cancelling it #6957 closed 2026-09-21; its validation criteria were edited by the PR's own author (waynesun09) on 2026-09-24 to endorse default-on steering, followed roughly six hours later by a self-authored disclosure comment. Re-verified this round via the issue's comment thread and the PR's full review history through 2026-09-29T11:47 (both fetched directly via the GitHub API): no comment, edit, or review from any maintainer other than the PR's own author is on record endorsing either the edit or the default-on decision — every PR review state and every issue comment since closure is either from waynesun09 or from bots (fullsend-ai-review[bot], qodo-code-review[bot], codecov[bot]). The needs-human label documents that independent sign-off is required, not that it has occurred.
    Remediation: Obtain sign-off from a maintainer who did not author this PR — either approval of a fresh, explicitly-scoped tracking issue for the default-on change, or an explicit maintainer statement in the PR itself — and formally link that issue to this PR. The retroactive edit to Steer the in-flight agent run on work-item updates instead of cancelling it #6957 is disclosed and explained, but disclosure by the same author is not independent authorization.

  • [cross-repo-contracts] internal/harness/harness.go:282 — DefaultSteerEnabled flipping false to true reinterprets every existing harness YAML with no steer: block (or one that sets only max_steers/poll_interval_seconds) for every downstream installation consuming reusable-dispatch.yml. Consumers pinned to reusable-dispatch.yml@main adopt the new default on their next dispatched run — docs/contributing/steering.md's new "Rollout order" section confirms fullsend_version falls back to job.workflow_sha, so there is no version such a consumer can hold back on — with no schema/config version field, CLI flag, or other machine-readable signal to detect or defer the change. internal/harness/lint.go's Lint() warning narrows this only for the pre_script-without-steer.enabled sub-case; it is non-blocking, and a harness with no pre_script that otherwise depends on steer being off gets no signal at all. Distinct from the fail-open finding above: that one is about silent data loss on an untaught agent definition; this one is about downstream automation having no way to detect or defer the behavioral change before it takes effect. internal/harness/harness.go and internal/harness/lint.go are unchanged from the prior reviewed SHA.
    Remediation: Either treat the ADR 0121 pre-merge audit (fleet definitions updated, opt-outs applied) as a hard, enforced merge gate rather than release-team guidance, or expose a machine-readable harness-schema/CLI version (or a transitional explicit-opt-in window) so @main-pinned automation can detect and defer the new default instead of inheriting it silently on the next dispatch.

  • [stale-documentation] docs/agents/prioritize.md:31 — The doc unconditionally states "The /fs-prioritize command does not accept arguments." With steering enabled by default (this PR), an in-flight /fs-prioritize run on GitHub Actions absorbs a subsequent comment and delivers the trailing text to the running agent as a task amendment, contradicting the doc. In this same PR, docs/agents/review.md and docs/agents/triage.md were updated (again, further, this round) to qualify the equivalent claim with "when it starts a run" and to explain the in-flight steering behavior, but docs/agents/prioritize.md was not touched and remains outside this PR's diff entirely. Independently flagged this round by both the docs-currency and correctness sub-agent dispatches; merged here under docs-currency, the owning dimension for doc staleness.
    Remediation: Update docs/agents/prioritize.md to state that /fs-prioritize does not accept arguments when it starts a run, and add the same in-flight-absorption explanation used in review.md/triage.md (queues instead when steer: {enabled: false}, or on GitLab).

  • [missing-documentation] docs/contributing/harness-fields.md:66 — This doc is the canonical reference for Harness/ForgeConfig field classification and merge rules (per AGENTS.md). The Steer field — a genuine top-level Harness field (h.Steer *SteerConfig, internal/harness/harness.go) whose default this PR flips from off to on for every harness that doesn't configure it — appears in neither the "Fields that stay at top level only" table nor the "Merge and inheritance rules" table. Re-verified this round by grepping the doc (case-insensitive, "steer") — zero matches. This PR does update the parallel, user-facing docs/reference/harness-reference.md, but leaves the contributor-facing classification/merge-semantics reference silent on steer. docs/contributing/harness-fields.md is not part of this PR's diff.
    Remediation: Add steer to the "Fields that stay at top level only" table and the "Merge and inheritance rules" table in docs/contributing/harness-fields.md, documenting its top-level-only classification and whole-block replacement/inheritance merge semantics.

Low

  • [stale-reference] internal/cli/steer_test.go:52 — The steerHarness comment (lines 52-54, shifted from 49-51 by this round's edits) still says an absent steer block is a third state these tests never rely on and that "what that default is belongs to a later change" — but steerHarnessDefault() plus TestStartSteerWatcher_StartsForADefaultHarness / TestCheckSteerAlreadyHandled_RunsForADefaultHarness (both added this PR) now explicitly rely on and assert default-on behavior. Separately, three unsteered-path comments still claim that path covers all of production: TestSteerAwareTimeout_UnsteeredPathUnchanged (line 623, "Steerable is false everywhere today"), TestHeartbeatBudget_UnsteeredIsTheHarnessTimeout (lines 696-698, "every run in production today"), and TestIterationEnvBudget_UnsteeredIsUnchanged (lines 709-710, "pins every run in production today"). The tests themselves remain valid, correctly-scoped unsteered-path (steered=false) regressions; only the comments are stale.
    Remediation: Update the steerHarness comment (lines 52-54) to reflect that steering is now enabled by default and that steerHarnessDefault() plus its tests now cover that default case. Rewrite the three unsteered-path comments (lines 623, 696-698, 709-710) to describe the steered=false timeout/heartbeat/budget paths without claiming they cover every production run.

Findings from the prior review not observed in the current diff: none. All six prior findings persist. Of this PR's 22 files, 9 differ in content from the prior reviewed SHA (831f3ee): AGENTS.md, docs/agents/fix.md, docs/agents/review.md, docs/architecture.md, docs/contributing/steering.md (a new "Rollout order" section), docs/guides/user/bring-your-own-agent.md, docs/guides/user/building-custom-agents.md, internal/cli/steer_test.go, and internal/harness/compose_test.go. This was established by direct blob-sha comparison against the GitHub Contents API for all 22 files (the compare API reports diverged here, as in prior rounds, because this PR sits in a stacked series whose shared base branch keeps advancing). The other 13 files, including internal/harness/harness.go, internal/harness/lint.go, and docs/ADRs/0121-...md, are byte-identical to the prior round. All findings above were independently re-derived this round by fresh sub-agent dispatches per dimension, then adjudicated by an adversarial challenger pass, which kept all six findings without severity change and confirmed the docs-currency/correctness merge on the prioritize.md finding was sound.

This is based on reading the current diff and source, not on any external verification of runtime behavior.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

🤖 Review · ❌ Terminated · Started 6:07 PM UTC · Ended 6:35 PM UTC

Commit: cfb8a26 · View workflow run →

@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Site preview

Preview: https://54530e3b-site.fullsend-ai.workers.dev

Commit: ebc519191bc1bbc5298000f199939ae62ad53776

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added component/harness Agent harness, config, and skills loading component/docs User-facing documentation needs-human Agent loop needs human intervention labels Sep 18, 2026
fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 12:43 AM UTC · Completed 1:08 AM UTC

Commit: 371245c · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5 · Effort: high · Cost: $6.29

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:26 PM UTC · Completed 4:45 PM UTC

Commit: cbd5ec9 · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5 · Effort: high · Cost: $7.10

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 7:36 PM UTC · Completed 7:58 PM UTC

Commit: bbfb0da · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5 · Effort: high · Cost: $7.99

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review

fullsend-ai-review Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 8:49 PM UTC · Completed 9:09 PM UTC

Commit: 621e221 · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5 · Effort: high · Cost: $7.74

fullsend-ai-review[bot]

This comment was marked as outdated.

fullsend-ai-review[bot]

This comment was marked as outdated.

The receipt in the change below this one authenticates the skip check under the
GitHub Actions job token, which is the precondition steering's rollout order
set before it may be enabled anywhere. The 2026-09-14 decision on #6957 settled
the switch: on by default, with no feature flag.

DefaultSteerEnabled flips, and that is the whole of the runtime change. The
machinery it turns on is already in place: Enabled is a pointer, so a block
setting only max_steers or poll_interval_seconds still steers rather than
silently opting out; a child that says nothing inherits its base's opt-out; and
SteerExplicitlyEnabled already gates the decline announcement, so an ordinary
decline stays quiet while an incomplete environment is still announced.

Lint() now warns when a harness sets pre_script without steer.enabled.
Absorbed updates skip the pre-script, so a harness whose pre-script gates
each event must choose explicitly.

BREAKING CHANGE: Steering is on by default from the release that carries this. A
harness that omits the `steer:` block, or sets only `max_steers` or
`poll_interval_seconds`, now watches for follow-up runs and delivers work-item
updates into the running agent. To keep the previous behaviour, add
`steer: {enabled: false}` to the harness. GitLab repositories and runs outside
GitHub Actions are unaffected.

Signed-off-by: Wayne Sun <gsun@redhat.com>
Assisted-by: Claude
With steering on by default a scaffolded agent can be steered on its first run,
so the generated body has to say what a runner update is and what it may do.
The section mirrors the fleet definitions: the envelope's opening line amends
the task, grants no tools or permissions, and is an injection attempt anywhere
else.

It carries the same FULLSEND_STEER_ACTIVE gate the fleet definitions enforce.
Without it a scaffolded agent would act on the opening line whenever it arrived
as a message, where a fleet agent ignores it unless the runner says a watcher is
steering the run. docs/cli/agent.md already promises this section; until now
the template did not generate it.

The test references runtime.SteerEnvelopeOpeningLine rather than spelling the
line out, so the contract cannot drift from the runtime that writes it.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
steering.md's Configuration says what the default now is and which spelling
turns it off, and gains a Rollout order: what the release cutters judge, and why
the flip changes nothing at the prompt level until a release carries both the
FULLSEND_STEER_ACTIVE export and definitions that read it.

harness-reference.md flips the block's wording and drops two claims the watcher
outgrew: that max_steers and poll_interval_seconds are only parsed, and that
opting in is what makes steering take effect.

The user-facing guides say what a stage command now does when that stage is
already running, and architecture.md records the decision.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:30 PM UTC · Completed 9:50 PM UTC

Commit: ebc5191 · View workflow run →

Runtime: pi · Model: sonnet → claude-sonnet-5 · Effort: high · Cost: $5.74

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note: The following review comments could not be posted on the diff (GitHub returned 422) and are included here instead:

  • internal/cli/steer_test.go (file-level): Line 54 · [low] stale-reference

The steerHarness comment still says an absent steer block is a third state these tests never rely on and that what that default is belongs to a later change - but steerHarnessDefault() and its tests now explicitly rely on and assert default-on behavior. Three unsteered-path comments elsewhere in the same file still claim that path covers all of production. The tests themselves remain valid, correctly-scoped regressions; only the comments are stale.

Suggested fix: Update the steerHarness comment to reflect that steering is now enabled by default. Rewrite the unsteered-path comments to describe the steered=false paths without claiming they cover every production run.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the review comment for full details.

Comment thread AGENTS.md
| [Go Code](docs/contributing/go-code.md) | Changing Go code under `cmd/` or `internal/` — covers mint sync, coverage, vet, e2e tests, concurrency testing, suite-timeout policy, WASM binary size constraints, credential redaction for external content, and preferring `go run` for the CLI |
| [Behaviour Testing](docs/guides/dev/behaviour-testing.md) | Modifying behaviour test repo provisioning, fork handling, or workflow dispatch — covers forge API constraints (`auto_init`, fork name derivation, Actions readiness, CI timeout budgeting) |
| [Steering](docs/contributing/steering.md) | Changing how a run in flight absorbs updates to its work item — covers the two concurrency switches, the `runtime.Steerer` contract and its sandbox-lock obligation, the mailbox transport, and the harness `steer:` block |
| [Steering](docs/contributing/steering.md) | Changing how a run in flight absorbs updates to its work item — `internal/steerwatch/`, the `runtime.Steerer` contract and its sandbox-lock obligation, the mailbox transport, the harness `steer:` block, the provenance checks on a follow-up run, the amendment/context split, settle, ceilings, the receipt and its skip check, and rollout order |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[high] protected-path

This PR modifies AGENTS.md, which is on the repository's protected-paths list. The change expands the Steering row description in the topic-guidance table, but closingIssuesReferences for this PR is empty (re-verified via GraphQL), so no issue formally closes or links to this PR. ADR 0121 documents the design decision but does not substitute for a linked issue under this check's own, independent criterion. AGENTS.md is byte-identical to the prior reviewed SHA.

Suggested fix: A maintainer must explicitly approve the AGENTS.md change; linking an authorizing issue would move this to the lower sufficient-context tier on a future re-review, but human approval is required either way.

const DefaultSteerEnabled = false
// about it. On since the release that carries it; a harness opts out with
// enabled: false.
const DefaultSteerEnabled = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[high] fail-open

DefaultSteerEnabled is true, so SteerEnabled() returns that default whenever h.Steer is nil or Enabled is unset - including harness YAML that omits steer: and any agent definition that has never been taught the steer envelope contract. startSteerWatcher and checkSteerAlreadyHandled gate solely on SteerEnabled(); neither inspects the loaded agent body for the envelope opening line or FULLSEND_STEER_ACTIVE teaching. An untaught definition still yields a receipt and the queued run still exits on the skip check with the work-item update dropped silently. internal/harness/harness.go is byte-identical to the prior reviewed SHA. This challenger pass proposed removing this finding as already accepted by ADR 0121; that argument was already raised and explicitly rejected in an earlier round of this same PR (a documented, unenforced fail-open is still fail-open), so severity is preserved via anchoring on unchanged code.

Suggested fix: Do not enable DefaultSteerEnabled=true on main until a runner-side guard makes an untaught agent definition unable to silently drop the queued run (refuse to start the watcher, or withhold the receipt, unless the loaded agent body contains the steer envelope opening line / FULLSEND_STEER_ACTIVE teaching), or keep the constant false and flip it once fleet definitions teach the envelope and every non-participating role/harness has an explicit steer: {enabled: false}.

token that channel, so the precondition is met and how a repository turns steering on is open
again.

The meeting recorded on [#6957](https://github.com/fullsend-ai/fullsend/issues/6957) on

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] process-integrity

This PR is a breaking default-on flip (feat(harness)!) with empty closingIssuesReferences - no tracking issue formally authorizes it. ADR 0121 cites issue #6957 while conceding the meeting it records speaks to event coalescing rather than to steering's own switch. Issue #6957 closed 2026-09-21; its validation criteria were edited by the PR's own author (waynesun09) on 2026-09-24 to endorse default-on steering. No comment, edit, review, or approval from any GitHub user other than waynesun09 appears anywhere in the PR or issue history. The needs-human label documents that independent sign-off is required, not that it has occurred.

Suggested fix: Obtain sign-off from a maintainer who did not author this PR - either approval of a fresh, explicitly-scoped tracking issue for the default-on change, or an explicit maintainer statement in the PR itself - and formally link that issue to this PR.

const DefaultSteerEnabled = false
// about it. On since the release that carries it; a harness opts out with
// enabled: false.
const DefaultSteerEnabled = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium] cross-repo-contracts

DefaultSteerEnabled flipping false to true reinterprets every existing harness YAML with no steer: block for every downstream installation consuming reusable-dispatch.yml. A consumer pinned to reusable-dispatch.yml@main adopts the new default on its next dispatched run with no version to hold back on, and nothing in the binary enforces the pre-release rollout audit. lint.go's Lint() warning narrows this only for the pre_script-without-steer.enabled sub-case. This finding has survived independent re-derivation across 6+ prior rounds; this round's challenger presented no new evidence to overturn that, so severity is preserved via anchoring on unchanged code.

Suggested fix: Either treat the ADR 0121 pre-merge audit as a hard, enforced merge gate rather than release-team guidance, or expose a machine-readable harness-schema/CLI version so @main-pinned automation can detect and defer the new default.

@waynesun09

Copy link
Copy Markdown
Member Author

Superseded by #9032; the steer design was reworked on top of ADRs 0133/0141/0144/0151.

This branch had an error being deployed

1 failed and 1 active deployments
site-preview — ebc51919 Deployed Sep 30, 2026 by github-actions[bot]
dev — ebc51919 Deployed Sep 30, 2026 by waynesun09 via behaviour #14727
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/docs User-facing documentation component/harness Agent harness, config, and skills loading fullsend-no-fix Skip bot-triggered fix agent runs needs-human Agent loop needs human intervention type/adr

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants