Skip to content

docs: scratch placement and its refusals in one place (1.7.0 and later) - #518

Merged
luisleo526 merged 2 commits into
mainfrom
tnx/scratch-placement-doc
Oct 26, 2026
Merged

luisleo526 merged 2 commits into
mainfrom
tnx/scratch-placement-doc

Conversation

@luisleo526

Copy link
Copy Markdown
Collaborator

Docs only (docs/pages/run-failure-codes.md): one place that states where a run without an attached arena puts its command-scratch file, and when that placement is refused (1.7.0 and later):

  • With no explicit scratch directory, the engine uses $TMPDIR (or /tmp); if that is memory-backed (tmpfs/ramfs) it falls back to /var/tmp only when /var/tmp is disk-backed. If both are memory-backed, the run is refused before the strategy runs (run_request_invalid).
  • An explicit PINEFORGE_COMMAND_SCRATCH_DIR on a memory-backed filesystem never falls back (scratch_io_failed).
  • Example: on Cloudflare Containers /run is a tmpfs mount while /tmp and /var/tmp are disk-backed.

Source for the example: layout reported by the MCP release-test fleet owner (relayed 2026-10-26); no measurement file attached. The behaviour statement follows the engine source as read for the 1.7.0 tag. The 1.8.0 CHANGELOG line lands with the 1.8.0 section.

🤖 Generated with Claude Code

luisleo526 and others added 2 commits October 26, 2026 07:20
…d later)

Add one paragraph to the run-failure-codes page, after the file-backed scratch
block: where an unjailed or native run puts its command-scratch file (TMPDIR,
else /tmp; /var/tmp only when the first candidate is proven tmpfs/ramfs and
/var/tmp is disk-backed), what refuses a run at begin when both candidates are
memory-backed (scratch_io_failed from the engine, run_request_invalid from the
default unjailed run_json profile, container exit code 4 through the hub
entrypoint), that an explicit PINEFORGE_COMMAND_SCRATCH_DIR on tmpfs/ramfs never
falls back, and an example with /run on tmpfs and /tmp and /var/tmp on ext4.

Prose only: no table, no file:line anchor and no code changes; the 1.7.0 text
it restates is unchanged. Scratch placement behaviour is identical between the
1.7.0 pin and this tree (scratch_directory.hpp and command_scratch_production.cpp
are byte-identical, read by REV-CX 2026-10-26).

Source of the example layout: reported by the MCP release-test fleet owner
(relayed by SUPER TOP 2026-10-26 07:0x); no measurement file attached.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…nch was made)

Merge commit, no rebase: first parent is the branch head, second parent is
main. The page docs/pages/run-failure-codes.md is unchanged on main since the
branch base, so the merge result is main's tree plus this branch's one-page
insertion; no conflict.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@luisleo526
luisleo526 merged commit 2561cfb into main Oct 26, 2026
12 checks passed
luisleo526 added a commit that referenced this pull request Oct 26, 2026
…it (#526)

## What this changes

The release gate (`scripts/ci_release_gate.py`) now also requires a successful, non-skipped `ci-post` run for the commit being released. Until now it read only the `pineforge/verify` and `pineforge/parity` statuses: the engine dry run 40260918204 printed `release gate green: PR #518 head 9325b64...; verify=success; parity=success` for a release of main 2561cfb whose own ci-post legs were never read. This closes that gap.

## Rule

Proof commit: the release sha, or, when the release sha is docs-only, the nearest first-parent ancestor that is not docs-only (docs-only by the merge gate's own classifier `ci_docs_only.is_documentation`; at most 20 docs-only commits, then `walk-too-long`; unreadable history -> `walk-blocked`).

Every skipped docs-only commit (the release tip included) must have a newest ci-post run that exists and is completed with conclusion `success` (run-level conclusion only, no jobs read): else `docs-commit-no-run` / `docs-commit-red`.

For the proof commit, runs of that exact sha on `main` (any event) are examined newest first (`created_at`, then id), at most 10, one jobs read per examined completed run. Newer-run table:

| Newer completed run on the proof sha | Result |
| --- | --- |
| a build job failed / cancelled / timed_out (any row) | `ci-post: newer-run-failed` (first, over any run conclusion) |
| run-level `skipped`, all four build legs skipped | passes over (counted as a newer skipped-only run) |
| run-level `skipped`, any other leg shape | `not-success` (contradictory data), naming the legs |
| any other non-success run conclusion (neutral, action_required, stale, startup_failure, null, ...) | `not-success`, whatever the legs show |
| run-level `success`, all four legs present, each success or skipped | passes over |
| run-level `success`, a leg neutral / null / unknown / missing | `not-success` naming the leg (while an older run exists to protect) |
| not completed | `run-in-progress` |

The proof run itself needs run-level `success` AND all four build legs `success` (`build (ubuntu-24.04|macos-26, Debug|Release)`, pinned to the `ci-post.yml` matrices by a workflow-pin test); a skipped leg there is `no-full-run`. Judgement call: a run-level `success` run with a bad/missing leg that is the LAST examined run (nothing older to protect, or the tenth examined run) ends in `no-full-run` instead of `not-success`: both are refusals, only the typed reason differs (pinned from both sides by `test_single_run_with_a_missing_leg_gives_no_full_run` and `test_missing_leg_run_with_an_older_proof_refuses_not_success`).

## Read count

1 paginated runs read per skipped docs-only commit (at most 20, typically 0 or 1, no jobs reads), then 1 paginated runs read for the proof sha plus 1 jobs read per examined completed proof run (at most 10). A plain pass with a non-docs release sha: 1 + 1.

## Scope notes

- Runs on other branches are excluded (`head_branch == main`): they are not main evidence. Runs are matched by `head_sha` of the examined commit (filter at `_ci_post_runs`); a red or running run of another commit never counts, whatever its run time (rows: `test_later_parent_failure_only_blocks_after_release_sha_flip` and the three siblings flip only `head_sha`).
- Phase 2 (receipt) is not live; the requirement applies to it from the day it goes live (same code path).
- The `release.yml` gate step has no `dry_run` guard, so a `dry_run=true` dispatch executes it. The Actions API read scope of the release App token is unproven until that step runs: the engine dry run at the freeze commit is its first live proof.

## Existing test lines changed (against main)

The diff against main removes lines in `scripts/test_ci_release_gate.py` in exactly six existing methods; everything else in the file is added, no method is deleted:

- `GateTests.assert_no_pr_fallback` (takes the new `ci_post` keyword).
- `GateTests.run_gate` (opt-in green ci-post fixture and the `history=` seam).
- `GateTests.test_green_reads_both_newest_statuses_and_names_the_reviewed_tree`, `GateTests.test_main_proof_with_full_contexts_green_passes_without_pr_reads`, `ReleaseBumpTests.assert_bump_green`: the expected stdout gains `; ci-post run <id> for <sha>`.
- `ReleaseRulesetTests.test_removing_each_new_condition_admits_its_unsafe_input`: the full-module mutant gets `history=` and the suffix.

In `scripts/ci_release_gate.py` the removed lines are 13: the old module docstring sentence, the `gate()` signature (new `history` parameter), its return statements (the evidence now ends with the ci-post evidence), the phase-one / release-bump wrapper lines folded into the new flow, and the `main(...)` signature and call line (gains `history`). The public CLI (`gate --repo --sha --ref`) is unchanged; `gate()` and `main()` gain an optional injected `history` seam that defaults to `git_history`.

## Evidence

Every test run below was on the project's cloud runner; none ran on a developer machine.

- The release-gate test file and the rest of the preflight pass on the final tree.
- The new tests fail against the first fail-closed reading of the table, on the rows that reading got wrong (over-blocking skipped runs, under-blocking a run-level success with a bad leg).
- A mutant that treats a missing leg as skipped fails only the missing-leg rows.
- One-line mutants of the decision block, each caught by the tests: in the success branch, never refusing for a bad leg fails 28 rows (all four cases of `test_missing_leg_run_with_an_older_proof_refuses_not_success`) and always refusing (dropping the older-run condition) fails 25 rows (all four cases of `test_single_run_with_a_missing_leg_gives_no_full_run`); never refusing in the run-level `skipped` branch fails 25 rows; never refusing in the branch for failed / cancelled / timed-out / other conclusions fails 47 rows. The success branch (both directions), the skipped branch and the other-conclusions branch are each mutation-checked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
luisleo526 added a commit that referenced this pull request Oct 26, 2026
## What

Adds the `## 1.8.0 — 2026-10-27` section (with migration notes) to `CHANGELOG.md`, above `## 1.7.0`. `CHANGELOG.md` is the only file changed (+131/-0). Documentation only: no `src/`, `include/`, `docker/`, `scripts/`, `tests/` or workflow file is touched.

## Why

The engine release body is generated from git-log subjects only and carries no migration notes; the release notes users read are this file (and the GitHub release body edited from it after publish). The notes must be on main before the release dispatch.

## Content

- Compatibility and migration: exact pairing with codegen 1.8.0, regenerate C++ and relink every strategy library, no public header change, the new codegen `color` input type, the changed harness file `docker/run_json.py`.
- Faster `run_json` report handling (#517) with the measured table against 1.6.3 and 1.7.0 and the statement that the gap to 1.6.3 is not closed.
- Scratch placement restated (#518); the unused storage building block (#515; its allocation-gate sites are unreviewed, no bound claimed); a known limit (memory with never-filled pending orders, "a fix is planned for a later release").
- CI and release process: every merged change since 1.7.0 not listed above (#505-#510, #513, #514, #516, #519, #520, #522, #469, #481, #504). Every line is taken from the merged commit body; none claims a behaviour change for a tests-only or CI-only change.

Not in this commit (not on main at base `641349a`): the release gate, tmpwatch and the TvJO fix. Each gets one line from its merged PR body as a follow-up commit on this branch before this PR merges; this PR is meant to merge after those three.

## Checks

- Route: docs-only, `lab verify --via ci-only` (no sweep).
- Read as a committed diff by an independent reviewer: GO. All 18 engine commits `v1.7.0..641349a` have a bullet, none extra.
- Numbers: the #517 timings and RSS are the measurements in the #517 body; the ratios in the text were recomputed (1.77/0.36 = 4.9, 8.26/1.35 = 6.1, 8.94/5.39 = 1.66; 4.61/0.36 = 12.8, 22.31/1.35 = 16.5, 22.99/5.39 = 4.27).
- The heading date `2026-10-27` is the planned tag date and is corrected before the tag if the date moves.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant