Conversation
…re-push hook runs its suite timed out on every master push (#1631) `_PUSH_TIMEOUT = 300` was reachable only from the per-call `:budget=SECONDS` flag, and its own comment argued against itself: what decides the right number "is not visible from here". It is visible from the project's config — whether a pre-push hook runs a suite is a property of the repo. Measured: 12868 passed in 309.86s against the 300s default, so two pushes failed at 302.70s and 302.90s with nothing sent before a third at :budget=1500 landed. Adds `ops.git-push.budget`, merged over the preset entry key-by-key like every other per-op key. Precedence is flag > config > 300, and 300 is still the answer when neither is set. Refused, never clamped: validated against ops.git-push.timeout from the SAME merged entry — both keys from one read, because core exports `budget` to the subprocess but reserves `timeout`, and checking one against the other would be two answers to one question. A value that is not a whole positive number of seconds, is above 1800, is at or above the op timeout, or whose timeout could not be read at all, refuses the push before anything is sent and names both numbers (#399, #1615). Ten seconds of margin is also the argument against a bigger constant: it would move this repo from always-fails to sometimes-fails, and a repo with no hook wants a shorter budget for the same reason. Co-Authored-By: Max <noreply>
…as the clock, and two doc sites still described the flag as the only lever (#1631) Found by the independent review of the first commit. `_budget_advice` is printed by three receipts and opened with "That budget is _PUSH_TIMEOUT in presets/git/push.py". With `ops.git-push.budget` in force that sends the caller to raise a number that did not cut — #1530's own defect one indirection further in. `_BUDGET` gains a `source`, reset in `main()`'s prologue like the rest of it, and the advice names the lever that was actually pulled; every arm still hands back a runnable `git-push:budget=SECONDS`. `tests/test_git_push_budget_1530.py`'s reset fixture cleared `seconds` and not `source`, so a driven push decided which remedy a later receipt offered. docs/presets/git.md: the new section called `:budget=SECONDS` "per-call" two paragraphs above the #1615 section stating it is NOT a per-call timeout; and the hook-relay paragraph still named `_PUSH_TIMEOUT` as the clock a push outlasts. Co-Authored-By: Max <noreply>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
git-push's 300s budget was a module constant, and this repo's own pre-push hook takes 309.86s — so every master push here timed out on a healthy machine with a green suite, and paid 300s to learn it again. Measured tonight: two failures at 302.70s and 302.90s, thenbudget=1500landed with12868 passed, 51 skipped in 309.86s.Ten seconds of margin is why "raise the constant" is the wrong fix: a bumped default moves this repo from always fails to sometimes works, and a repo with no pre-push hook wants a budget shorter than 300, because there a long one only delays an honest failure. The number is per-repo in both directions, which is what makes it config.
Precedence and validation
Flag > config > 300 default, and 300 is still the answer when neither is set.
_config_budget()has three states and refuses rather than clamps: non-int (bool is an int), ≤ 0, > 1800, ≥ops.git-push.timeoutread from the same merged entry, or an unreadabletimeout— naming both numbers each time. Clamping would convert "you asked for one number and got another" into a discovery made at the moment a push cannot be verified, which is what #399's strict-under constraint exists to prevent._read_json/_UNREADABLEkeep "did not answer" separate from "answered with nothing": the core stops walking on[]but continues past a parse failure, so collapsing the two would resolve a budget out of a config the core never read.The judgment call
Both keys are read off disk rather than taking
budgetfromSUPERTOOL_BUDGET, which the core exports for free.timeoutis in the core's_RESERVED_KEYSand never reaches the subprocess (pinned bytests/test_custom_ops.py:463), so validating an env-supplied budget against a disk-read timeout would be two answers to one question checked against each other — and it would lose any project that overridestimeouttoo.Reviewer
Independent Sonnet pass against the committed diff. Correctness, vacuous tests and cross-platform: none. Three accepted on the fourth category, all about the receipt pointing at the wrong lever —
_budget_advice()opened "That budget is_PUSH_TIMEOUTin presets/git/push.py" while a configured budget was the clock, and two doc lines said the same. Each is now pinned; the pins were proved red against the pre-review commit.Adjacent, fixed
.supertool.jsongainsops.git-push.budget = 1500. Without it this PR ships the capability and the maintainer still pays 300s per master push.tests/test_op_registry_1356.py's register of live partial overrides updated with the reason, as its own docstring instructs; the assertion was never relaxed. That test was the single full-suite failure and is the reason the suite was worth running.tests/test_git_push_budget_1530.py's reset fixture cleared_BUDGET["seconds"]but notsource, so a driven push in that file decided which remedy a later receipt test saw.Withdrawn during review, worth stating
The first version of
test_the_budget_source_is_cleared_by_the_main_prologuedrovepush.main()with cwd at the checkout — i.e. it attempted a real push of this repository, and errored eleven neighbouring tests. Replaced with an assertion onmain()'s prologue source, which is whatconftest.PRESET_SELF_CLEARING_GLOBALScredits anyway. Stated here because it generalises: a test in this repo that callspush.main()outside a sandbox pushes the repo.Suite
39 passedon the new file;227 passedacross the git-push family and registry under random order; full suite in a disposable clone withoriginre-pointed:12921 passed, 97 skipped, 15 warnings, 2 subtests passed in 314.08s. Windows unverified locally.RED before implementation was
31 failed, 4 passed— the four passing are unchanged-behaviour pins (flag still wins, no config means noPush budget:line,_PUSH_TIMEOUT_MAX < op timeout).Closes #1631