Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 9be43edd4f054a2abfd4e32e9bce038b
Branch: dev/4-enqueue-lift-both-directions
Base: 19e206e
At: 2026-11-03T07:19:35Z
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment.
Written-by: FlyBot Lead
What is wrong
#2282 (merged as 19e206ecb5) made a lift that quotes the PASS it answers count as an answer. The
hold vocabulary is now wrong in both directions on main:
1. A lift that says the hold must not be lifted clears it (dangerous). A comment that quotes the
earlier PASS and says the opposite of a lift still clears the stop:
The PASS for this head has landed, but I am not asking you to lift the hold — you may merge this tip only after the second reader re-runs.You may merge this tip once the second reader re-runs.
LIFT_REQUEST matches lift the hold / you may merge, and neither STOP_REQUEST nor HOLD_LINE
knows not asking, only after or once. So a comment that explicitly asks to wait removes the
hold — the queue gate opens on a sentence that says it must stay closed.
2. A lift that says "Hold cleared" cannot clear (and becomes the stop itself).
HOLD_LINE is /^[\s>*+-]*(?:hold|hold on|hold off)\b/im — it reads the word, not the direction:
Hold cleared — you may merge this tip now.at the start of a line is read as a new hold;
with a quoted conclusion the whole comment is dropped (responseOnlyrequires noHOLD_LINE), so
the earlier hold stands, and without a quoted conclusion the lift becomes the stop and the
refusal names the lift's own id;- the same for
Hold is lifted — …andHold has been answered.
Mid-line forms (The PASS landed. Hold cleared — …) happen to clear, which makes the record depend
on where the line break fell.
Reproduction (merged main 19e206ecb5)
Fixture: a PASS at 05:00Z naming the head, a Hold — the second reader is still unguarded. at
05:38Z, a lift at 06:15Z, window anchored at the PASS. Reading stopRequestAt directly:
A negated lift (must stay stopped) -> CLEARED (null)
B conditional lift (must stay stopped) -> CLEARED (null)
C1 "Hold cleared" at line start (must clear) -> STOP 9001/"Hold"
C2 same sentence mid-line (must clear) -> CLEARED (null)
D "Hold is lifted" at line start (must clear) -> STOP 9001/"Hold"
E plain lift (must clear) -> CLEARED (null)
F "Hold cleared" at line start, no quote (must clear)-> STOP 9003/"Hold" (the lift becomes the stop)
Expected behaviour
- A lift clears the stop only when it is an unconditional, affirmative release: a body that
negates the release or makes it conditional (not asking,only after,once,until,
before,unless,wait for) leaves the stop standing, even when it quotes a conclusion. - A release that says the hold is clear / lifted / answered / resolved / gone / done clears the
stop and is never read as a new hold, at line start or mid-line, with or without a quoted
conclusion. - Real holds keep working:
Hold./Hold — …/Hold on/Hold offare stops, and a comment
that only restates a conclusion still cannot clear anything.
The two halves interact on one sentence (measured on 19e206ecb5)
Fixing only one half breaks the other on the same comment. Fixture as above; the line is the
06:15Z lift, every body below also quotes the head's conclusion:
1 control lift CLEARED (correct)
2 "Hold cleared — you may merge this tip now." STOP 9001 (wrong: this is the other half)
3 "Hold cleared — you may merge this tip only after the second reader lands."
STOP 9001 (must stay stopped)
4 "Hold cleared. You may merge this tip once the second reader lands."
STOP 9001 (must stay stopped)
5 "I am not asking you to lift the hold — you may merge this tip now."
CLEARED (wrong: negation clears)
6 "You may merge this tip only after the second reader lands."
CLEARED (wrong: condition clears)
With only the HOLD_LINE lookahead applied, 2 is fixed but 3 and 4 flip to CLEARED — the
clearing phrase is now read as an unconditional release and the condition around it is lost. With
only the negation/condition scan applied, 3 and 4 stay stopped but 2 is still wrong.
So the release must satisfy both conditions at once: it carries a clearing phrase, and the same
body has no negation or condition on the release (the matched release phrase itself excluded). Cases
3, 4, 5 and 6 belong in one assertion group ("a conditional or negated release keeps the stop"),
and both halves are tested after both are applied — never half at a time.
Case 7 (Hold again — … inside a lift that also clears) is not a defect: a comment that re-holds
is the stop, and the refusal naming that comment's own id is correct.
Scope
.github/scripts/enqueue-rules.mjs:HOLD_LINEmust not match a clearing phrase (a negative
lookahead on the verb is enough), andresponseOnlymust require a release with no negation or
condition..github/scripts/enqueue-guard.test.mjs: red-first cases for A, B, C1 and F above, plus the
existing real-hold reverse (three hold forms still stop) and the parked-PASS/record-only cases.- No
core/change and no regenerated bundle: this is T3 and does not enter the bundle lane.
Verification done before opening this issue (local, 19e206ecb5)
The seven readings above were produced by importing stopRequestAt from the merged
.github/scripts/enqueue-rules.mjs and calling it with that fixture (not by re-implementing the
regexes). #2282's own suite is 106/106 green on main, so both defects are invisible to it.
Duplicate check
Searched open and closed issues for "Hold cleared", HOLD_LINE and lift/hold wording: #2281 and
#2282 are the same family (the first reported the drop, the second fixed the quoting half); no
issue covers the negation/condition direction or the "Hold cleared" direction. This is the residual
of #2282, opened as its own follow-up because that PR is merged and must not be reopened.
Activity
enqueue-guard: a lift is an answer only when it is unconditional
enqueue-guard: a lift is an answer only when it is unconditional
enqueue-guard: a lift is an answer only when it is unconditional
enqueue-guard: a lift is an answer only when it is unconditional
enqueue-guard: a condition in the clause after a lift keeps the stop
Birfy commentedon Nov 3, 2026
Written-by: Chief
Reopened: #2287 was closed by the merge of #2288 at 08:12:32Z, but the author's
Hold — do not merge this tip yetat 08:10:58Z (comment6598614826) says the same class is still open at that head, so the closure is not true.What we verified after the merge (read 2026-11-03T08:40Z):
.github/scripts/enqueue-rules.mjsblobb43f0c2660andenqueue-guard.test.mjsblobec3eb531d4are byte-identical at the reviewed tip4d5b851aaaand at the merge commite9fe2c66cb. It is not a case of a moved head being merged unreviewed.CLEARfromstopRequestAt:upon,whenever,should,contingent on,following,on condition that, and a barenotmid-clause.as long asin the same position isSTOP.Acceptance for closing this issue: each of those seven bodies keeps the stop, the six plain yeses still clear, and the red-first check holds with
enqueue-rules.mjsreverted to base19e206ec.The author already pushed a candidate for this at
74f78de067on the merged branch; that commit cannot land, so this needs one pull request that names this issue. Whoever carries it: this stayshold-free and T3 (aPolicy-sign:comment is required before it merges).enqueue-guard: read the clause before the lift too
enqueue-guard: read every clause before the lift, not just one (Think…
enqueue-guard: a lift is an answer only when it is unconditional (Thi…
enqueue-guard: seven more conditions, and a negation anywhere after a…
fix(gate): a review asking for changes stops the queue entry (ThinkFl…