Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Version
- **`Agent Handoff 1.17` stops an untrusted checkout from executing a command during session start.** The `session-start` launcher ran its Git reads with the full inherited process environment and no configuration isolation, so a repository-local or ancestor `core.fsmonitor` setting named a hook that Git ran — unconditionally, before the operator had seen anything — as soon as that checkout was opened as a session-start target ([#235](https://github.com/L3DigitalNet/project-standards/issues/235)). Every read now runs with an explicit minimal environment (`PATH` and `HOME` only, so no `GIT_DIR`, `GIT_WORK_TREE`, or `GIT_CONFIG_*` value from the harness can redirect it) and passes `-c core.fsmonitor=`, which outranks every configuration file, plus `--no-optional-locks` so the read cannot race a concurrent write. The injected session context is byte-identical to 1.16; reconcile replaces the installed hook because its digest moved. Catalog 5 promotes `agent-handoff@1.17` and retains 1.16.
- **`Agent Handoff 1.17`'s launcher reports the payload version that ships it.** 1.15 and 1.16 carried forward the 1.14 binary byte for byte, so `session-start --version` answered `1.14` on both — the one question the stale-launcher diagnostic exists to answer, answered with a version the consumer never selected ([#229](https://github.com/L3DigitalNet/project-standards/issues/229)). 1.17 is re-linked from its own payload path with its own stamp and prints `agent-handoff session-start 1.17`; a contract test now pins that equality against the catalog's default version, so a future cut cannot reintroduce the drift. The 1.14–1.16 bytes are published and immutable and keep answering `1.14`.

- **`scripts/verify.sh --full` runs its ordinary lane in parallel, and the compatibility matrix drops 21 rows and 57 duplicate wheel arms** ([#236](https://github.com/L3DigitalNet/project-standards/issues/236), [#227](https://github.com/L3DigitalNet/project-standards/issues/227)). The `--full` ordinary lane ran single-process for roughly 50 minutes of every release train to claim test isolation, a claim the written record of past trains never once shows catching a red ([`docs/research/2026-09-01-release-train-wall-clock.md`](docs/research/2026-09-01-release-train-wall-clock.md) §2, lever F); it now runs the identical selection at `-n 16 --dist load`, still under the default trace core, so the coverage-core cross-check against the `sysmon` fast gate that the lane also carried is unaffected. `--full` therefore gains a `coverage-combine` lane, which its single data file previously made unnecessary. In the compatibility matrix the 36 pairwise rows now run against the source distribution only — pairwise interaction between two packages' managed blocks is distribution-independent, and source/wheel parity is still proven per package by the single-package, full-set, and partial-migration rows — and the 21 legacy pairwise rows are removed as redundant with the 14 partial-migration rows and the `all-namespace-legacy` full-set row. Collected compatibility rows fall from 150 to 129. Repository tooling only: no package, payload, or consumer-visible byte changes.

## [5.28.0] — 2026-09-01

### Added
Expand Down
2 changes: 2 additions & 0 deletions docs/research/2026-09-01-release-train-wall-clock.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,5 @@ paths-ignore:
- **Cheapest safe adoption today:** lever A. Run the pre-tag battery as `rexec -- env VERIFY_FULL_COMPAT_WORKERS=16 scripts/verify.sh --full`. No file changes, no claim weakened, ~30 minutes off every train. If it proves out over a train or two, the owner can decide whether the default at `scripts/verify.sh:70` should move (a code change this report does not make).
- **Right long-term, even though it costs more up front:** lever D plus the §4 verdict record, then lever C for the hosted path. The record is the piece with lasting value: it converts "the gate ran" into "these five verdicts cover this exact tree", which is what makes any future reuse or lane-scoped re-run safe. Lever E should not be built until that record exists and has been exercised.
- **Do not adopt yet:** lever F. The serial ordinary lane has never been shown to earn its 45 minutes, but it carries the coverage-core cross-check as well, and A+C recover more time without giving up anything.

**Adopted 2026-09-01 (owner decision, issue #236 C4) — in the narrowed form this section asks for.** The lane is replaced rather than retired: `--full` now runs the identical selection at `-n 16 --dist load` under the default trace core, so the coverage-core cross-check against the `sysmon` fast gate survives intact and only the isolation claim of §2 — the one this report could find no evidence for — is given up. `--full` gains a `coverage-combine` lane, which the previous single-process data file made unnecessary.
47 changes: 26 additions & 21 deletions scripts/verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@
# (its assertions are timing-sensitive and must not share the machine),
# then `coverage combine` + `coverage report`.
#
# --full runs the legacy serial sequence instead (statics, serial ordinary
# coverage run, compatibility, performance, report). That is the release-prep
# cross-check: it is the configuration the coverage baseline was established
# under, so a disagreement between it and the fast gate is a real signal
# rather than a parallelism artifact.
# --full runs the same lane selections one at a time (statics, ordinary
# coverage run, compatibility, performance, coverage combine, report). That is
# the release-prep cross-check: it varies the coverage core and the machine
# contention, not the test selection, so a disagreement between it and the fast
# gate is a real signal rather than a parallelism artifact.
#
# Its ordinary lane runs at -n "$ORDINARY_WORKERS" like the fast gate's, not
# single-process (issue #236 C4, lever F of
# docs/research/2026-09-01-release-train-wall-clock.md, adopted 2026-09-01).
# The single-process form cost ~50 minutes of every train and its isolation
# claim was never once the thing that caught a red; the coverage-core claim it
# also carried is the half worth keeping, and that one only needs the lane to
# run under the trace core, not to run serially.
#
# Every command runs from `.venv/bin` rather than through `uv run`. Concurrent
# `uv run` invocations contend on the uv cache (the 2026-07-29 failure class);
Expand All @@ -34,10 +42,10 @@
# next to the data file; in-root they race the read-only digest
# proofs and the wheel-source copytree.
# COVERAGE_CORE sysmon in the fast gate only (proved report-identical to the
# serial trace core). --full keeps the default trace core so the
# cross-check varies the core as well as the parallelism —
# otherwise a sysmon-specific divergence would be undetectable
# by the very lane documented to catch it.
# trace core). --full keeps the default trace core, and that is
# now the whole of what the two modes vary in their ordinary
# lane — otherwise a sysmon-specific divergence would be
# undetectable by the very lane documented to catch it.
#
# Usage:
# scripts/verify.sh fast gate (default)
Expand Down Expand Up @@ -372,17 +380,6 @@ lane_ordinary() {
reap_basetemp "$BASETEMP_ROOT/ordinary"
}

lane_ordinary_serial() {
local args=(
--source=project_standards -m pytest
-m "not performance and not compatibility"
--basetemp="$BASETEMP_ROOT/ordinary"
)
[[ "$SMOKE" == "1" ]] && args+=(-k test_repository_workflow)
"$VENV_BIN/coverage" run "${args[@]}" || return $?
reap_basetemp "$BASETEMP_ROOT/ordinary"
}

lane_compatibility() {
local workers="$1"
local args=(
Expand Down Expand Up @@ -457,9 +454,17 @@ if [[ "$MODE" == "fast" ]]; then
serial_lane_unless_red coverage-combine lane_coverage_combine
else
serial_lane_unless_red statics lane_statics
serial_lane_unless_red ordinary lane_ordinary_serial
# The same lane the fast gate runs, deliberately: what --full varies is the
# coverage core (trace here, sysmon there) and the fact that nothing else is
# on the machine, not the selection or the worker count.
serial_lane_unless_red ordinary lane_ordinary
serial_lane_unless_red compatibility lane_compatibility "$FULL_COMPAT_WORKERS"
serial_lane_unless_red performance lane_performance
# Required since the ordinary lane became parallel here too: xdist workers
# write their own `.coverage.*` files (tests/conftest.py), so without a
# combine the report would see only the controller process and the fail-under
# would trip on a lane that actually passed.
serial_lane_unless_red coverage-combine lane_coverage_combine
fi

serial_lane_unless_red coverage-report lane_coverage_report
Expand Down
33 changes: 17 additions & 16 deletions tests/package_compatibility/test_catalog_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,10 @@
# satisfy the byte-identical re-enable assertion. The fresh rows carry the
# catalog-5-only packages' full pair and full-set coverage.
_LEGACY_DEFAULTS = legacy_migratable_ids()
_LEGACY_PAIRS = tuple(combinations(_LEGACY_DEFAULTS, 2))
_PARTIAL_MIGRATION_ROWS = tuple((standard_id,) for standard_id in _LEGACY_DEFAULTS) + tuple(
tuple(candidate for candidate in _LEGACY_DEFAULTS if candidate != omitted)
for omitted in _LEGACY_DEFAULTS
)
_PAIR_ROWS = tuple((pair, False) for pair in _PAIRS) + tuple((pair, True) for pair in _LEGACY_PAIRS)
_MANDATORY_GROUPS = (
("python-tooling", "agent-handoff", "markdown-tooling"),
("adr", "markdown-frontmatter"),
Expand Down Expand Up @@ -343,27 +341,30 @@ def test_each_package_converges_alone_from_source_and_wheel(


def _pair_row_id(value: object) -> str:
if isinstance(value, tuple):
return "+".join(cast("tuple[str, ...]", value))
return "migrated" if value else "fresh"
return "+".join(cast("tuple[str, ...]", value))


@pytest.mark.parametrize(("standard_ids", "migrated"), _PAIR_ROWS, ids=_pair_row_id)
@pytest.mark.parametrize("standard_ids", _PAIRS, ids=_pair_row_id)
def test_every_unordered_pair_preserves_ownership_and_converges(
tmp_path: Path,
source_payload_distribution: InstalledDistribution,
wheel_payload_distribution: InstalledDistribution,
standard_ids: tuple[str, str],
*,
migrated: bool,
) -> None:
_exercise_both(
tmp_path,
source_payload_distribution,
wheel_payload_distribution,
standard_ids,
migrated=migrated,
)
"""Prove the pairwise ownership and convergence claim, source distribution only.

What each pair row is for is the interaction between two packages' managed
blocks, which is distribution-independent: both distributions serve the same
payload bytes. Dual-distribution parity is a separate claim, and it is still
proven for every package by the single-package rows, the two full-set rows
and the partial-migration rows (owner decision 2026-09-01, #227 E2#1; the
battery record carries no red that only the wheel arm ever produced).

The 21 migrated pair rows are gone with it (#227 E2#2): a legacy pair adds
nothing over the partial-migration rows, which exercise the same migration
against every one-package and every one-omitted subset, plus the
all-namespace-legacy full-set row.
"""
exercise_fresh_lifecycle(tmp_path / "source", source_payload_distribution, standard_ids)


@pytest.mark.parametrize("migrated", [False, True], ids=["fresh", "all-namespace-legacy"])
Expand Down
17 changes: 14 additions & 3 deletions tests/test_repository_test_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,15 @@ def test_verify_gate__fast_mode__starts_parallel_lanes_before_serial_tail(tmp_pa


def test_verify_gate__full_mode__preserves_serial_lane_order(tmp_path: Path) -> None:
"""--full sequences the lanes one at a time, with the fast gate's selections.

The ordinary lane is parallel here too since #236 C4 (lever F of
docs/research/2026-09-01-release-train-wall-clock.md): what --full still
varies is the coverage core and the exclusive machine, not the selection.
The combine is load-bearing rather than cosmetic — xdist workers write their
own ``.coverage.*`` files, so a report without it would see only the
controller process.
"""
repo, log, environment = _gate_fixture(tmp_path, wheel_count=1)

completed = _run_gate(repo, environment, "--full")
Expand All @@ -413,11 +422,13 @@ def test_verify_gate__full_mode__preserves_serial_lane_order(tmp_path: Path) ->
assert invocations[1] == "ruff format --check ."
assert invocations[2] == "ruff check ."
assert invocations[3].startswith(
"coverage run --source=project_standards -m pytest -m not performance and not compatibility"
"coverage run --source=project_standards -m pytest "
"-m not performance and not compatibility -n 16 --dist load"
)
assert invocations[4].startswith("pytest -m compatibility -n 16")
assert invocations[5].startswith("pytest -m performance")
assert invocations[6] == "coverage report --fail-under=0"
assert invocations[6] == "coverage combine"
assert invocations[7] == "coverage report --fail-under=0"


def test_verify_gate__full_mode__red_ordinary_lane__skips_the_later_lanes(
Expand All @@ -440,7 +451,7 @@ def test_verify_gate__full_mode__red_ordinary_lane__skips_the_later_lanes(
summary = completed.stdout[completed.stdout.index("════ summary ════") :]
assert "ordinary" in summary
assert "FAILED (exit 13)" in summary
for lane in ("compatibility", "performance", "coverage-report"):
for lane in ("compatibility", "performance", "coverage-combine", "coverage-report"):
assert lane in summary
line = next(row for row in summary.splitlines() if row.strip().startswith(lane))
assert "skipped (--fail-fast)" in line
Expand Down
Loading