Skip to content

chore(loop): let workflow_dispatch fall back to the write switch - #47

Merged
Alex1990 merged 1 commit into
mainfrom
fix/loop-execute-writes-fallback
Sep 15, 2026
Merged

Alex1990 merged 1 commit into
mainfrom
fix/loop-execute-writes-fallback

Conversation

@Alex1990

Copy link
Copy Markdown
Owner

A one-line bug with exactly the wrong blast radius: the entry point a human uses to test the write switch could never exercise it.

The bug

LOOP_EXECUTE_WRITES: ${{ github.event.inputs.execute_writes || vars.LOOP_EXECUTE_WRITES || 'false' }}

The input declared default: 'false', so GitHub filled github.event.inputs.execute_writes with the non-empty string 'false' on every manual run and the || short-circuited there. vars.LOOP_EXECUTE_WRITES was unreachable.

Verified on run 35002295453 with the repository variable already set to true: the payload showed "execute_writes": "false" and the engine logged writeLevel=report.

Schedule / issues / pull_request runs were unaffected — github.event.inputs is null there, so the fallback worked. That made it worse rather than better: the loop would have started writing on real events while the switch appeared broken in the one place you would look to confirm it.

The fix

Drop the default:, making the input tri-state and the expression mean what it reads:

dispatch result
input empty follows vars.LOOP_EXECUTE_WRITES
-f execute_writes=true writes, for that run
-f execute_writes=false reports, for that run

Both directions verified on Actions, dispatched against this branch (--ref):

$ gh workflow run loop.yml --ref fix/loop-execute-writes-fallback -f smoke=true
 [loop] ... · writeLevel=auto        ← falls back to the variable

$ gh workflow run loop.yml --ref fix/loop-execute-writes-fallback -f smoke=true -f execute_writes=false
 [loop] ... · writeLevel=report      ← explicit override still wins

smoke=true was used for both probes: it skips the agent and never reaches applyActions, so neither run wrote anything anywhere.

scripts/loop/README.md records the tri-state semantics and why the input must stay default-less — the failure mode is invisible from the workflow file alone, so the next person to add a "sensible default" needs to know it is not one.

Not in this PR

Nothing else about the switch changed. First real auto execution is still pending (see #46): it needs a claimable task, and the state layer currently has none — all 14 tasks are terminal or waiting-human.

@Alex1990
Alex1990 force-pushed the fix/loop-execute-writes-fallback branch from ce75321 to 0cb7063 Compare September 15, 2026 17:43
@github-actions

Copy link
Copy Markdown
Contributor

Coverage

Metric % Covered / Total
Lines 90.19% 1003/1112
Statements 89.06% 1083/1216
Functions 91.03% 193/212
Branches 76.43% 519/679

@github-actions github-actions Bot added the needs-triage Maintainer needs to evaluate (loop can't decide; too risky; external PR) label Sep 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Loop triage — needs-triage (human review + merge).

PR #47 edits the loop host's own machinery (.github/workflows/loop.yml and scripts/loop/README.md) on a same-repo branch fix/loop-execute-writes-fallback with no loop-task: marker. loopTaskOf() returns null, so the router sends owner repo PRs to triage: it is not a loop PR, and the loop must not be maker or checker for the change it runs on. It also touches .github/workflows/**, which the job token can never push — so there is no agent-actionable work here even in principle. What remains is a maintainer review/merge decision.

The bug and the fix both check out against live Actions logs:

  • Bug on main — run 35002295453, workflow_dispatch with no input: payload "execute_writes": "false", engine log LOOP_EXECUTE_WRITES: false … writeLevel=report. The default: 'false' injected a non-empty string, so vars.LOOP_EXECUTE_WRITES was never reached.
  • Fix, automatic direction — run 35002456149 on the fix branch, input left empty: LOOP_EXECUTE_WRITES: true … writeLevel=auto.
  • Fix, explicit override — run 35002567015 with -f execute_writes=false: LOOP_EXECUTE_WRITES: false … writeLevel=report.

Both fix-side probes logged smoke mode: skipping the agent, so nothing was written. entry.mjs resolves the level fail-closed (=== 'true' ? 'auto' : 'report'), and the parallel smoke input keeps its default because it has no vars fallback — that one is harmless. CI on head 0cb7063 is green (Lint ✅, Test ✅); the pending loop check is this triage run. mergeable: MERGEABLE, mergeStateStatus: BLOCKED (review required by the Main branch ruleset).

One point for the reviewer: the commit/title type is fix(loop):, but AGENTS.md reserves fix for changes a package consumer can observe and requires chore(loop): for loop maintenance — fix is rendered into the user-facing CHANGELOG.md. Retitle/squash as chore(loop): when landing.

Proposed action: label needs-triage; a human reviews and merges. The loop must not merge it.

`LOOP_EXECUTE_WRITES: ${{ github.event.inputs.execute_writes || vars.LOOP_EXECUTE_WRITES || 'false' }}`
never reached the variable: the input declared `default: 'false'`, so GitHub filled
`github.event.inputs.execute_writes` with the non-empty string `'false'` on every
manual run and the `||` short-circuited there. Verified on run 35002295453 with the
repository variable already set to true — the engine still logged `writeLevel=report`
and the payload showed `"execute_writes": "false"`.

The effect was narrow but exactly wrong: schedule/issues/pull_request runs (where
`github.event.inputs` is null) followed the variable correctly, while the one entry
point a human uses to *test* the switch could never exercise it.

Dropping the default makes the input tri-state and the expression mean what it
reads: unset → fall back to the repository variable; `true`/`false` → override for
that run. The description says so now, since "empty follows the variable" is
otherwise invisible from the dispatch form.

Spotted by the loop's own triage of this PR (run 35003006260, its first `auto`
execution): the commit type was `fix(loop)`, which AGENTS.md reserves for changes a
package consumer can observe, and changelogen renders into the user-facing
CHANGELOG.
@Alex1990
Alex1990 force-pushed the fix/loop-execute-writes-fallback branch from 0cb7063 to be8f0b7 Compare September 15, 2026 17:47
@Alex1990 Alex1990 changed the title fix(loop): let workflow_dispatch fall back to the write switch chore(loop): let workflow_dispatch fall back to the write switch Sep 15, 2026
@Alex1990
Alex1990 merged commit 1e452a2 into main Sep 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-triage Maintainer needs to evaluate (loop can't decide; too risky; external PR)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant