Skip to content

Triad migration: follow-ups deferred at the landing of #190 and #192 #193

Open

Description

@brettheap

Follow-ups deferred at the landing of #190 and #192, which lane 3 landed on Brett Heap's word in its window, "land 190 and 192" (2026-10-09): #192 as 1abee1d, then #190 as f87fd5a at b50f197. Part of #186. Each item names where it was found; none of them is in either PR as landed, except item 1, which #190 carries.

From #190 (explicit test roots)

  1. RESOLVED by Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190's landing. Lane 1 folded b50f197 into Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190 before the squash (its delta review 5471080687; CI, tests-macos included, green on that head), and Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190 landed at b50f197. The record as filed: The lane suite aborts in a code leg with no spec root. tests/test_lane_helpers.sh:6601-6602 read $ln_doc outside its $LANE_MANUAL guard, so under set -u a standalone code-leg run stops on ln_doc: unbound variable instead of skipping. The fix exists on feat/test-roots-manual-guard @ b50f197, a fast-forward onto Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190's head. Lane 1 may fold it into Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190 before the squash (its handoff plans that; the window is in lane 3's landing notice on Triad migration (feature 004-migrate-to-triad): execution tracking under Brett Heap's word of 2026-10-07 #186, and Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190's gate then re-runs); if Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190 lands at dbc6837 instead, b50f197 needs its own PR onto main and this item stays open. Found by lane 3's review (5464931249) and confirmed by lane 1 on Triad migration (feature 004-migrate-to-triad): execution tracking under Brett Heap's word of 2026-10-07 #186.
  2. Mixed tests and the four roots in AGENTS.md. feat/test-roots-followups @ 7144eef (6e63083, 2064390, with b50f197 merged in): each mixed test asserts its code-only half before its first document read, and AGENTS.md documents the four roots (cap 316 → 323; 340 → 347 at an assembly root). Note from lane 3's candidate review on Triad migration (feature 004-migrate-to-triad): execution tracking under Brett Heap's word of 2026-10-07 #186: 7144eef does not compose with T006's assembly-0001, which rewrites the assembly's AGENTS.md.
  3. A behaviour test for the missing-manual branch (only its text is checked today).
  4. Composed validation never reads contracts/{role}-pin.yaml's commit: (Copilot round 2, High; thread on tests/conftest.py:270). With the pin moved off the gitlink, ROOTS.refusal() returns None while scripts/validate-pins.py exits 1 (pin-gitlink-mismatch). The exact-pin CI job runs the validator first, so only a hand-made composed run is exposed. Refuse a pin whose commit: differs from the gitlink. Also (Medium): root markers must be regular files, not any existing path.
  5. The paired layout is not discovered. discover_assembly (tests/conftest.py:159-172) returns nothing for <assembly>/worktrees/<feature>/code, so after Gate C every document test would skip in a feature worktree.
  6. The root variables redirect the suite silently. OPENREPOTOOLS_CODE_ROOT re-points REPO and UPSTREAM; OPENREPOTOOLS_ASSEMBLY_ROOT accepts any directory with two empty marker files and loosens the caps to 340/510. The only trace is the report header, which -q hides. Show the roots a run used where -q cannot hide them.
  7. Nits. Roots.owner_of gives LICENSE and .gitignore to code; abs_root turns a quoted ~/x into $PWD/~/x; a stale GIT_ENV comment.

From #192 (run C evidence and T006 patches; lane 3's review 5464893559)

  1. Two records now contradict each other on main. adopter-rehearsal-2026-10-08.md:62-64 and the 2026-10-07 file at :178-180 both say "On this branch, the mapping is…" about the same adoption-plan.yaml, so the run B sentence is false since this squash; :13-17 still calls the 2026-10-07 file a branch file. One dated paragraph fixes it.
  2. T006 undercounts the front-door failures. root-guidance-2026-10-08.md:397-398 says 17; the measured count is 18 (test_openrepotools_command.py::test_the_help_and_the_readme_say_the_mode_the_receipt_is_born_at is uncounted). :180's "23 mentions in 9 files" adds up to 26 in 11 by its own list.
  3. Say that adopt-project.py check reads the clone's local main, not HEAD, so it reports plan-stale (exit 1) against any main newer than 837928a; the plan's header and planning_status imply it but do not say it.
  4. T006's evidence cites no receipt; its setup-openspeckit, store-precedence, doctor and shape_advisory rows exist only in the document.
  5. "The rebuilt bench has no ensurepip" is contradicted (the venv packages were installed on 2026-09-23); the refusal is real, its cause is unestablished.
  6. The review's remaining recommended edits: findings 5, 6, 8, 9, 16 and 17 of review 5464893559.

From lane 3's review of the composed candidate (#186)

  1. test_repo_hygiene.py::test_agents_md_names_the_pin_rules fails in the composed candidate. T006's assembly-0001 rewrites the two AGENTS.md lines it checks (code/upstream/openRepoShape, git -C code submodule update …), so 2 of its 4 assertions miss. Decide which side gives before the composed run is the record.

From lane 2's refusal-case runs on an r2-equivalent build (#186, 6087267593)

  1. The exit-4 refusal misnames a root that was NAMED. When OPENREPOTOOLS_SPEC_ROOT or OPENREPOTOOLS_ASSEMBLY_ROOT is set to a directory that is not a root, the composed refusal still says the variable "is unset", or that there is "no OPENREPOTOOLS_ASSEMBLY_ROOT". It should name the value it rejected and why. The refusal itself holds; only its words are wrong. Found by lane 2, which ran the five refusal cases on its own r2-equivalent build, one flock per case; lane 1's r2 logs do not show it.

From lane 3's review of #195 at fb77bed (5481360555), not blocking it

  1. A root refused for a bad marker names both markers. When one marker is a directory, or only one is missing, the composed refusal still says the root "carries no" both (tests/conftest.py:433-434 and :444-445 at fb77bed). Lane 2 noticed the directory case first (Triad migration (feature 004-migrate-to-triad): execution tracking under Brett Heap's word of 2026-10-07 #186, 6103529172). It should name the marker that failed, and how.
  2. The restated installer-source hygiene rule still accepts some fetch shapes: a payload variable set by read -r or printf -v; a one-line pin_scalar() { …; } reader; a source_repository) line that reads another pin (the docstring says only the code pin's line counts); and git clone or an unquoted gh api, which main's rule never read either. None of them occurs in the installer today: the rule finds 0 offences on main's 7 fetching lines and on Install from the code an adopted assembly pins, resolved to one commit, and keep a single repository's install on today's reads, words and network needs. #191's 16 at 8246983. Copilot's two rounds on Follow up #190's test roots: name a refused root's value, check the pin's commit, find paired feature worktrees, show redirected roots under -q, run the lane manual sections, and restate the installer-source test #195 are spent, so these come here.

Lane 1 (openRepoTools-1) owns the migration order (#186); these are its to schedule.

Activity

  1. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-11: #195 status, and the new follow-ups from lane 3's LAND review (5481360555).

    #195 (feat/test-roots-followups @ e378871) answers:

    These are still open, none of them blocking #195:

    1. A rejected root is reported twice in the composed refusal: once as the problem and once as the absent root (review finding 2).

    2. A marker refusal should name the marker that failed, and say whether it is missing or not a regular file. Today it names both markers (finding 3).

    3. ~user/… diverges. tests/run.sh makes it $PWD/~user/…, while conftest's expanduser expands it (finding 7).

    4. The restated installer-source rule still accepts six shapes (finding 8):

      • A, B: read -r and printf -v assignments to a payload variable;
      • C: a one-line pin_scalar() { …; };
      • D: a source_repository) arm of a pin other than contracts/code-pin.yaml;
      • E: a git clone https://github.com/$OTHER.git;
      • F: an unquoted gh api repos/$OTHER/….

      None of these shapes is in main's installer or in Install from the code an adopted assembly pins, resolved to one commit, and keep a single repository's install on today's reads, words and network needs. #191's 8246983.

    5. Carried from lane 3's 01ccc86 review (finding 14):

      • the exit-3 and suite-wrapper reorders have no planted proof;
      • test_openrepotools_command.py's receipt test asserts nothing from --help before its README read can skip;
      • AGENTS.md's paragraph names the spec leg as docs/, while SPEC_TREES holds four trees.
  2. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-11T16:4xZ: two more deferred items, from lane 3's review of the T010 patches (#186 6089801221). The T010 record on 004-migrate-to-triad-ci @ 22bdb2e (section 10) gives every finding of that review a disposition, and these two have no other home:

    1. The AGENTS.md test-roots paragraph describes rather than instructs (finding 7 (i)). Rewrite it as a rule a contributor follows, when it lands in the assembly's AGENTS.md (see the Gate C decision on Give the test suite explicit code, assembly, spec and dependency roots, so it runs on today's single repository and in the adopted triad, and refuses composed acceptance without all of them #190's follow-ups).
    2. The nested-run proof checks only the outcome (finding 8). Make it also assert the command half was reached, not only the final status.

    Both are for T014/T015. Lane 1 schedules them.

  3. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-11T16:4xZ: 18. #195's code_mount() test always uses a pin with submodule_path: code (tests/test_test_roots.py:77), so a hard-coded code would also pass. Add a case whose pin mounts the leg at another path, such as impl, so CI holds the derivation. From lane 1's delta review of #195 (5484079561, point 4). Not a landing condition.

  4. brettheap commented on Oct 13, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-13T18:35Z: three more deferred items, from lane 3's review of the installer record (#196 review 5481368376) and lane 2's #186 6090038382. The installer record on 004-migrate-to-triad-installer @ 7428e78 (specs/004-migrate-to-triad/installer-2026-10-08.md, section "Lane 2's open items on #191") gives each of these a disposition and proposes it here:

    1. A capability check in the assembly's root entry point.
    2. A 200-garbage answer to the code-pin probe: a refusal where main installs, and words that name nothing.
      • Source: lane 2's item 4 (8 of 8 rows exit 2, with nothing placed and 0 payload requests).
      • The case: on today's single-repository layout, garbage or an empty body at 200 for contracts/code-pin.yaml is taken as a pin: probe_path takes any gh success or curl 200 as present (openRepoTools:656-658, :668 at a74c7fc). The listing at the resolved commit then shows no pin, and the run refuses at :761-764 with "the ref moved between the two reads". Main never asks for that file, so it installs. Like a 502 on the same file (lane 2's item 3), this is a refusal where main installs. Unlike that case, Install from the code an adopted assembly pins, resolved to one commit, and keep a single repository's install on today's reads, words and network needs. #191's body does not disclose it: it says "anything but a 404 (offline, 5xx, 401/403, a portal)" refuses "naming what answered", but a 200 that is not GitHub's, a portal's page among them, names nothing and blames a moved ref.
      • Proposal: the refusal names both readings, the ref moved or the first answer was not GitHub's, and says what answered the probe. The words keep "the ref moved", which test_r07_a_branch_that_moves_right_after_the_layout_question_is_read_at_one_commit[single] asserts.
      • Deferred because: like lane 2's item 3, it is the cost of asking the layout question at all. An answer that is not GitHub's 404 is never read as the older layout (the design's "no silent legacy fallback"), and nothing is placed. The record discloses it. Install from the code an adopted assembly pins, resolved to one commit, and keep a single repository's install on today's reads, words and network needs. #191 has landed (a74c7fc), so the words need their own small change to openRepoTools.
    3. An identity match for the enclosing-assembly walk.
      • Source: lane 2's item 1, rows 24a–c.
      • The case: since fdc5f18 the walk accepts only <root>/<submodule_path> and <root>/worktrees/<NNN>/<submodule_path>, where the pin names this directory. A foreign pin that names exactly this directory as its leg still matches: outer/product refuses; an installed copy in $HOME/bin under a $HOME pin with submodule_path: bin refuses to reinstall, where main installs.
      • Proposal: also require the checkout's own identity to match the pin: its origin is the pin's source_repository, or its HEAD is the pinned commit.
      • Deferred because: it cannot be reached today. No ancestor of a checkout or of ~/.local/bin carries contracts/ (lane 3, Install from the code an adopted assembly pins, resolved to one commit, and keep a single repository's install on today's reads, words and network needs. #191 review 5471121210, delta 4). It needs a decision on what identity an installed copy, which has no git checkout, can show.

    All three are for T014/T015 or a follow-up to #191. Lane 1 schedules them.

    Edited 2026-10-13: item 20 corrected after lane 2's check (lane 2's register note of 2026-10-13T18:22:15Z). It is a refusal where main installs, not wording only. The record reference moved from 7668c51 to 7428e78.

    🤖 Generated with Claude Code

  5. brettheap commented on Oct 13, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-13T18:5xZ: one more deferred item, found during #196's refold.

    1. Host-absolute /workspace/ paths are on main, and the hygiene rule does not catch them.
  6. brettheap commented on Oct 17, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-17T21:0xZ: item numbering map, and item 23 (from lane 3's #196 review 5560058266).

    Lane 3's finding 9 on #196: #193's item numbers repeat across its body and its comments, and #196's records cite the repeated ones in two senses. This comment maps every number to the comment that defines it and says what each of #196's citations means. Nothing is renumbered or edited.

    Map. Item number → where it is defined:

    Source Items
    the issue body 1–17
    6103860685 16–20
    6111225631 16–17
    6111250692 18
    6152519565 19–21
    6152761778 22
    this comment 23

    Repeated numbers: 16 and 17 (body, 6103860685, 6111225631), 18 (6103860685, 6111250692), 19 and 20 (6103860685, 6152519565). Numbers 1–15, 21, 22 and 23 occur once. From now on cite an item as "#193 item ", and the body's as "#193 body item ". Numbers 1–23 are used, so new items start at 24.

    What the repeated numbers are:

    • 16: body, a root refused for a bad marker names both markers; 6103860685, a rejected root is reported twice in the composed refusal; 6111225631, the AGENTS.md test-roots paragraph describes rather than instructs.
    • 17: body, the restated installer-source hygiene rule still accepts some fetch shapes; 6103860685, a marker refusal should name the marker that failed; 6111225631, the nested-run proof checks only the outcome.
    • 18: 6103860685, ~user/… diverges between tests/run.sh and conftest; 6111250692, Follow up #190's test roots: name a refused root's value, check the pin's commit, find paired feature worktrees, show redirected roots under -q, run the lane manual sections, and restate the installer-source test #195's code_mount() test always uses submodule_path: code.
    • 19: 6103860685, the restated installer-source rule still accepts six shapes; 6152519565, a capability check in the assembly's root entry point.
    • 20: 6103860685, the carry-overs from lane 3's 01ccc86 review (reorders without a planted proof, the receipt test's --help half, the AGENTS.md paragraph naming only docs/); 6152519565, a 200-garbage answer to the code-pin probe.

    What each of #196's citations means (line numbers at b50c83c):

    Lane 3's finding 11. test-roots-and-ci-2026-10-08.md:447 ("7 (i) … not yet filed") and :450 ("that the proof checks only the outcome is not yet filed") were filed 40 seconds after 22bdb2e: they are 6111225631 items 16 and 17.

    1. The T010 code-leg workflow patch no longer applies to main, and three passages describe jobs that are gone.
      • Source: lane 3's note 16 (review 5560058266).
      • The case: ci: run the test suite on Linux only #227 (aaa7bc8, 2026-10-15) made CI Linux-only. .github/workflows/tests.yml on main now has guard-launch-mode, tests and tests-no-submodule; tests-windows, parse-macos and tests-macos are gone, and its own header says no job parses the repository's bash under Apple's bash 3.2 any more.
        • patches/t010-code-leg-tests-workflow.patch has base e27bc64, main's tests.yml up to a74c7fc. Against main's tests.yml (blob 3c7caa4), git apply --check fails at line 21. Re-measured today; against a74c7fc's file it still applies.
        • test-roots-and-ci-2026-10-08.md:354 (the landing tooling reads tests-macos by name), gate-b-status-2026-10-09.md:172 (line 33, platform policies and bash 3.2) and installer-2026-10-08.md:236 ("parse-macos covers the implementation only") describe jobs that no longer exist.
      • Proposal: at T014/T015, regenerate the patch against main's tests.yml at the cutover, and restate the bash 3.2 point: say whether the code leg or the assembly's composed.yml needs a 3.2 parse of the root entry point (which installer-2026-10-08.md:236 already says parse-macos did not cover), or that the check is gone by decision.
      • Deferred because: the three passages are evidence of their dates (2026-10-09 to 2026-10-13), and Triad migration evidence of 2026-10-08 and 2026-10-09: test roots and CI patches, installer entry point, restore and rollback, #192's corrections, T018, Gate B status #196 folds records already reviewed. The patch is rehearsal input that T014 regenerates anyway.

    Lane 3's note 15, no new item. openRepoShape v1.0.0 is tagged (2026-10-14T23:17Z; v1.0.1 at 2026-10-15T14:20Z). By the order the hold gives after the tag (#186 6152410188: the pin-bump PR, a fresh rehearsal and plan at v1.0.0, then the cutover), the next composed run is on a candidate rebuilt after the pin bump, not on the 7f84ca4 candidate. The candidate record's "still owed: the full composed suite on this candidate" is read that way, and the next record says so.

    🤖 Generated with Claude Code

  7. added a commit that references this issue on Oct 17, 2026
  8. brettheap commented on Oct 17, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-17T22:2xZ: item 24, from the independent review of #229 (5560316525). Numbering follows the map in 6241015109: new items start at 24.

    1. The /workspace/ host-path rule (Hygiene rule refuses bench-root host paths, with an allowance for quoted grep patterns; replace them in the consumer reads and the durable-intent sample #229) has gaps and edge cases, deferred. Findings 1 and 2 of that review are being folded into Hygiene rule refuses bench-root host paths, with an allowance for quoted grep patterns; replace them in the consumer reads and the durable-intent sample #229 itself. These four remain:

    Why deferred: none blocks. The review's verdict is LAND, and the rule already catches every host path main carries (87 lines).

  9. brettheap commented on Oct 17, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-17T22:5xZ: item 25. Numbering continues from 6241015109 and 6241963987.

    1. The suite reads the real lane register when the session exports LANES_REPO and LANES_WORKSPACE_ROOT.
    • Cause: the lane launcher exports both into every lane session, along with the other LANES_* variables and TMUX. The wip-init tests' wip_env does not clear them.
    • Effect: on the pin-bump branch, test_wip_init_and_the_lane_helpers_read_one_pointer_file_the_same_way failed 5 ways, and its lanes-edit.sh fetched the real per-lane register clone. Nothing was written.
    • With the variables unset, it passes 6 of 6.
    • Fix: clear every LANES_* variable, and TMUX, in the suite's env helpers or with an autouse conftest fixture. Add a test that sets each to a sentinel path and proves no read reaches it.
    • Until then, run tests in a lane session with those variables unset.
  10. brettheap commented on Oct 17, 2026

    @brettheap
    ContributorAuthor

    Lane openRepoTools-1, 2026-10-17T23:23Z: item 26, from the independent review of #233 (5560570028). Numbering continues from 6241015109 and 6242560775.

    The review's findings 1 and 2 are filed as #235 and #236. The items below are its notes 3, 5 and 6, which do not block. None is caused by #233.

    1. Coverage the suite cannot see, three parts.

      1. Four assertions that cannot see what they guard (tests/test_park_resume_commands.py, line numbers at main 2732d59). At openRepoShape 190133d each passes for the right reason, but none would go red if upstream moved the thing it couples to. I re-measured each with the suite's own builders, with every LANES_* and TMUX* variable unset.

        • :1247-1248. "(b) the layout" and "holder TestFam" each appear 2 times in the fresh-machine resume output. Once is make siblings' own tee'd output, and once is resume's step (5) reprint. A heading change upstream would send step (5) (resume:1420, grep -q '^(b) the layout$') to its fallback, (no layout table …) (resume:1435), and these asserts would stay green. Fix: assert .count(...) == 2, or assert "(no layout table" not in result.stdout.
        • :1981. BOOTSTRAP-{name} ran appears 2 times per sibling: the holder's own bootstrap also runs each pinned member's make bootstrap. So it does not prove that the sibling's own bootstrap ran. Fix: assert count == 2.
        • :1826-1840 (test_the_real_bootstrap_would_have_moved_that_leg). It never checks the bootstrap's exit code. At 190133d that code is 0, bootstrap ok, and step (a) printed on main at … (branch tip == pin). Fix: assert proc.returncode == 0.
        • :1843-1851 (test_a_leg_detached_at_the_pin_is_not_a_refusal). It asserts neither resume's exit code nor the absence of "make bootstrap did not exit 0". Fix: assert both.
      2. family Makefile: siblings, park and resume refuse by name when scripts/siblings.py is absent, and update-shape.py says the Makefile it copies calls it, so a holder updated without --add no longer fails on can't open file (#489) openRepoShape#503's $(error) path is unobserved. A family holder without scripts/siblings.py now stops on make's $(error), exit 2, naming update-shape.py check and apply --add. Under park --all it is still counted as refused (exit 2), as the old can't open file was, so park's classification does not change. No test here builds such a holder: seed_holder always copies siblings.py. Low priority; a test would pin the classification.

      3. The --install docstring citation is right, but nothing checks it. tests/test_install_payload_source.py:917-922 cites openRepoShape:547 at 190133d. That line equals 7f84ca4's line 280 by cmp. But:

        • the test runs only in composed acceptance, so it skips standalone and on CI;
        • its pipeline is a string literal, so "BYTE FOR BYTE" is a claim in the docstring only.

        Fix: a standalone hygiene assertion that reads that line out of upstream/openRepoShape and compares it with the test's literal, so the next pin bump that moves it goes red. No other openRepoShape line citation exists in tests/.

    Lane: openRepoTools-1

    🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions