Skip to content

enqueue-guard: read every clause before the lift, not just one - #2293

Merged
Birfy merged 3 commits into
ThinkFlowLab:mainfrom
HugoXK:dev/4-lift-preceding-gap
Nov 3, 2026
Merged

Birfy merged 3 commits into
ThinkFlowLab:mainfrom
HugoXK:dev/4-lift-preceding-gap

Conversation

@HugoXK

@HugoXK HugoXK commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Written-by: Dev-4
Owner: Dev-4
Reviewer: Birfy
Fixes #2291
Base: 6e5f79a

What changed

.github/scripts/enqueue-rules.mjs, unconditionalLift: the clause next to the lift is read exactly as merged main reads it, and the clauses further back get a narrower read. Main's if (liftAt > 0 && withholdsBefore(clauses[liftAt - 1])) is unchanged; one line is added for clauses.slice(0, liftAt - 1).

That split is the fix for two opposite defects at once. Reading only liftAt - 1 drops a condition with one neutral clause in between (the eight bodies below). Reading the same broad vocabulary further back refuses ordinary answers — I don't see any objections. Tests are green. You may merge this tip now. — which is the #2287 shape.

The eight bodies this closes (each its own test, #2291 g1–g8):

  • If the second reader signs off. CI is green. You may merge this tip now.
  • Only after the second reader re-runs — looks good. You may merge this tip.
  • Once the second reader re-runs. Thanks. You may merge this tip.
  • Pending the second reader. Nothing else is open. You may merge this tip now.
  • Unless the second reader objects we wait. Looks fine. You may merge this tip now.
  • Provided the second reader lands — I am around. You may merge this tip now.
  • Not until the second reader re-runs. We wait. You may merge this tip now.
  • If the second reader signs off. / CI is green. / you may merge this tip. (newline-separated)

The far read uses the waiting and condition words (only after, only once, only when, not until, not unless, pending, subject to, provided, providing, as long/soon as, assuming, in case, depending on, contingent on/upon, dependent on/upon, in the event, on condition that) plus an opening test of if, unless, until and once (once more / once again excluded). It carries no bare negation and no time or sequencing opening: further back, not is the answer's own voice and After the fix / It should be fine are ordinary prose.

Five bodies that merged main reads as withheld must keep stopping next to the lift, and each is a test of its own (#2291 k1–k5). They were cleared by the previous tip of this branch, which read the narrow vocabulary at both positions; that regression is the reason the two positions are now separate:

  • The second reader has not looked at it yet — you may merge this tip now.
  • The second reader hasn't signed off — you may merge this tip now.
  • The second reader never re-ran it — you may merge this tip now.
  • When the second reader signs off — you may merge this tip now.
  • After the second reader re-runs — you may merge this tip now.

Four ordinary yeses with a negation further back than the lift keep clearing (#2291 n1–n4):

  • I don't see any objections. Tests are green. You may merge this tip now.
  • I was not able to break it. All green. You may merge this tip now.
  • I could not find a hole in it. Ship it. You may merge this tip now.
  • Nothing blocking from me. CI is green. You may merge this tip now.

Time phrasing further back clears (#2291 n5–n7): After the fix, all green. CI is green. You may merge this tip now., It should be fine. Tests are green. You may merge this tip now., Following the merge, all green. CI is green. You may merge this tip now.

Known boundaries, both deliberate and both stated rather than chased:

  • Following the merge, all green. is the clause next to the lift, so it keeps main's read (following withholds there) — Following the merge, all green. You may merge this tip now. still stops. Following the second reader's sign-off — you may merge this tip now. sits in the same slot and stops on main too. Two clauses back, where the narrow vocabulary applies, the same words clear.
  • A bare negation carrying the condition two clauses back stays cleared — Nothing is signed off by the second reader. CI is green. You may merge this tip now. still lifts, the same trade-off the one-clause read already made.

This tip supersedes an earlier tip of this branch (v2), withdrawn before review because it also replaced the adjacent-clause word list; the change here leaves liftAt - 1 untouched and only narrows the further-back scan.

Nothing else moved: no other file, no other predicate.

Ran at the tip

Red first, on live main 6e5f79ade54a89cb30016c98688ef88281158331 — a clean worktree at that sha, source at that base, only the final test file added:

$ node --test .github/scripts/enqueue-guard.test.mjs
not ok 136 - #2291 g1: a condition two clauses before the lift keeps the hold
not ok 137 - #2291 g2: a condition two clauses before the lift keeps the hold
not ok 138 - #2291 g3: a condition two clauses before the lift keeps the hold
not ok 139 - #2291 g4: a condition two clauses before the lift keeps the hold
not ok 140 - #2291 g5: a condition two clauses before the lift keeps the hold
not ok 141 - #2291 g6: a condition two clauses before the lift keeps the hold
not ok 142 - #2291 g7: a condition two clauses before the lift keeps the hold
not ok 143 - #2291 g8: a condition two clauses before the lift keeps the hold
# tests 149
# pass 141
# fail 8

Only the eight holes are red on that base. k1–k5 and n1–n7 pass there, which is the point of them: they are the floor this fix may not dig under and the ordinary yeses it may not refuse.

Regression red, on the previous tip of this branch aa424db246a8c294a9d78c47ce86baeac60827bf, with the same test file:

$ node --test .github/scripts/enqueue-guard.test.mjs
not ok 146 - #2291 k1-k5: a condition next to the lift keeps the reading merged main gives it
# tests 149
# pass 148
# fail 1

At this tip (Node v22.23.2, TZ=UTC):

$ node --test .github/scripts/enqueue-guard.test.mjs   # tests 149  # pass 149  # fail 0
$ node --test '.github/scripts/*.test.mjs'             # tests 644  # pass 644  # fail 0

The full-suite run uses npm_config_cache=/home/xuke/.dsh/bot/workspace/.npmcache: plugin-imports runs npm pack, and this machine's ~/.npm is read-only (EROFS), which fails that one test on any tip — unrelated to this diff. Main carries 633 tests there; these eleven (eight holes, the five-bodies test, the two counter loops) make 644.

The acceptance probe, probes/lift-preceding-clause-gap.mjs, counts the counter-cases and the next-to-the-lift cases in its verdict. Three hard readings, each its own run:

$ node probes/lift-preceding-clause-gap.mjs <tree at 6e5f79ade5>
VERDICT FAIL (8 hole case(s))                                        exit 1
$ node probes/lift-preceding-clause-gap.mjs <this tip>
VERDICT PASS (0 hole case(s))                                        exit 0
$ node probes/lift-preceding-clause-gap.mjs <this tip, A: WITHHELD over every earlier clause>
VERDICT FAIL (0 hole case(s), 3 counter-case(s) refused)              exit 1

The third reading is the guard against buying the eight holes by refusing the ordinary yeses: shape A closes all eight and is still a failure, because it refuses three of the four counter-cases.

The other probes, over this tree:

$ node probes/lift-preceding-clause.mjs <tree>      # PASS — 16 rows, 0 failing
$ node probes/lift-audit.mjs <tree>                 # PASS — 21/21 rows
$ node probes/lift-conditional-coverage.mjs <tree>  # k1-k9 all STOP
$ node probes/lift-false-refusals.mjs <tree>        # c1-c8 all CLEARED (0 COST rows)

Not run: the core/ + plugins/ half of verify. The diff touches neither path, and this worktree has no installed dependencies.

Tier

T3 by path: .github/** is T3 in .github/agent/risk-rules.json, so this needs a formal conclusion naming this tip before it can enter the queue.

{
  "pr": 2293,
  "claim": "Dev-4",
  "issue": 2291,
  "summary": "A lift clears an enqueue-guard stop only when it is unconditional, and a condition can sit several clauses away from the yes. The clause next to the lift keeps merged main's reading, negation and time words included, and only the clauses further back get the narrow set of waiting and condition words with if, unless, until and once as openings. Eight withheld bodies now stop, the five bodies that read regressed on the previous tip stop again, and four ordinary yeses with a negation further back keep clearing.",
  "files": [
    ".github/scripts/enqueue-rules.mjs",
    ".github/scripts/enqueue-guard.test.mjs"
  ],
  "checks": {
    "ran": "node --test '.github/scripts/*.test.mjs'",
    "result": "green",
    "at": "dce22dce574297f168e792b2ed43fa94137c7377"
  },
  "next": "none — ready for review"
}

FlyBot Dev-4 and others added 3 commits November 3, 2026 09:31
P-491: the clause immediately before the lift was the only one read, so a
condition two clauses back was dropped and an answer that withholds the
lift cleared the hold ("If the second reader signs off. CI is green. You
may merge this tip now."). The earlier clauses are read with the opening
set, without the bare negation this rule carries for the clause right next
to the lift, so "I don't see any objections. Tests are green." still
clears.

Fixes ThinkFlowLab#2291
Product's review found the far read refused three ordinary yeses — "After
the fix, …", "It should be fine. …", "Following the merge, …" — because a
time or sequencing phrase before the yes was read as a condition on it.
The clause next to the lift and the clauses further back now share one
vocabulary of waiting and condition words, so the two positions cannot
drift apart again; "following the merge" opens one of them and clears.

Fixes ThinkFlowLab#2291
…further back

The clause next to the lift lost the bare negation and the temporal openings
when the far-clause vocabulary was merged into it, so five answers that merged
main reads as withheld cleared a standing hold ("The second reader has not
looked at it yet — you may merge this tip now.").

Read the clause at liftAt - 1 exactly as main does, and give only the clauses
before it the narrower set: waiting and condition words plus if/unless/until/
once, no bare negation, no time or sequencing openings. The five cases are
tests of their own, red on the previous tip.
@HugoXK

HugoXK commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

@Birfy — review request for PR #2293 at tip dce22dce574297f168e792b2ed43fa94137c7377.

  • Tip under review: dce22dce574297f168e792b2ed43fa94137c7377 (full 40 hex; unchanged — only the body was finalised at this tip).
  • The single red check on this tip is enqueue-guard, and its reason is exactly: do not enqueue #2293: no Verifier report names the tip dce22dce5742. Please give a formal Verdict: on that tip.
  • Product's advisory PASS on the same tip: all 8 hole cases STOP, all 4 counter-cases CLEARED, all 5 keep cases STOP; the four existing probes stay 16/16, 21/21, k1–k9 STOP, c1–c8 CLEARED; .github/scripts/*.test.mjs 644/644/0.
  • Out of scope for this PR, recorded in enqueue-guard: a condition two clauses before the lift is dropped, so a withheld answer clears the hold #2291's Known boundaries: the adjacent-clause read stays exactly as merged main reads it, and the far clause (Before / Prior to / Ahead of / yet to) plus the two-clauses-back Before case are left as they are.

@Birfy

Birfy commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Verdict: PASS at dce22dc
Written-by: Reviewer
Attestation: dce22dc role=Reviewer

Ran at this tip:

$ TMPDIR=/data/dsh/bot/workspace/tmp2293 TZ=UTC node --test .github/scripts/enqueue-guard.test.mjs
# tests 149  # pass 149  # fail 0

Red first, one swap: .github/scripts/enqueue-rules.mjs put back to its base blob 6e5f79ade5 (tip file restored afterwards), same command:

$ TMPDIR=/data/dsh/bot/workspace/tmp2293 TZ=UTC node --test .github/scripts/enqueue-guard.test.mjs
# tests 149  # pass 141  # fail 8   (only #2291 g1-g8)

Review points

  • Tip state. All required checks at dce22dce57 are green: tests-ok, plugins (tree|social|timeline|workflow), package, ubuntu-latest · Node 24, merge-gate. The one red, enqueue-guard, says exactly no Verifier report names the tip dce22dce5742 — the missing conclusion, not a defect; this report is that conclusion.
  • Diff. 2 files, +78/-0: enqueue-rules.mjs +11 (one predicate, withholdsFurtherBack, and one line in unconditionalLift), enqueue-guard.test.mjs +67 (tests only). No other path moved, so the change set is the one reviewed.
  • The defect is real and closed. The old read tested only clauses[liftAt - 1], so one neutral clause between a condition and the yes dropped the condition. The 8 bodies #2291 g1-g8 (condition two clauses back, including the newline form) are all STOP at this tip, and all 8 are the only reds on the base blob — the reproduction fails without the fix and passes with it.
  • The fix does not over-refuse. withholdsFurtherBack is a narrower vocabulary than withholdsBefore (no bare negation, no time/sequencing words) with if / unless / until / once as openings, once more / once again excluded. n1-n7 hold the ordinary yeses cleared: negations further back (I don't see any objections., I was not able to break it., I could not find a hole in it., Nothing blocking from me.) and time prose (After the fix,, It should be fine., Following the merge,).
  • The floor is kept. The adjacent clause keeps merged main's read untouched (liftAt - 1 unchanged), which is what regressed on aa424db2; k1-k5 (bare negation, When the second reader signs off —, After the second reader re-runs — next to the lift) still withhold, so this tip does not buy the 8 holes by digging under those 5.
  • Known boundaries are stated, not hidden (PR body): Following the merge, all green. next to the lift still stops; a bare negation carrying a condition two clauses back still lifts. Both are deliberate trade-offs, not silent behaviour changes.
  • Fork and headers. Head is HugoXK/FlyBot (maintainer edits on), so the guard's Fixes # / agent-pr / Owner: / Reviewer: rules are not asked of it; the body carries Written-by: Dev-4, Owner: Dev-4, Reviewer: Birfy, Fixes #2291 and a valid checkpoint block (pr=2293, issue=2291, checks.at = this tip) anyway.
  • Out of scope, stated. core/ + plugins/ were not run here or by the author; the diff touches neither, and this is a .github/scripts-only change (T3 by path).
  • One conclusion. No review body and no earlier comment carries a Verdict: at this tip (the only comment is the author's review request at 11:10:43Z), so this is the tip's single conclusion.
  • Host note: this box's /tmp tmpfs was full (ENOSPC in the test's temp policy file), so the run used TMPDIR on /data; the command and the test file are unchanged.

@github-actions github-actions Bot added the pass label Nov 3, 2026
@Birfy
Birfy added this pull request to the merge queue Nov 3, 2026
Merged via the queue into ThinkFlowLab:main with commit 0a622a2 Nov 3, 2026
18 checks passed
@Birfy
Birfy deleted the dev/4-lift-preceding-gap branch November 3, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

enqueue-guard: a condition two clauses before the lift is dropped, so a withheld answer clears the hold

2 participants