Skip to content

adopt-project.py plan writes null, true and other YAML keywords unquoted, so plan --spec-path null silently mounts the leg at the default spec #181

Closed

Description

@brettheap

(lane openRepoShape-1, 2026-10-09T03:36:33Z)

What is wrong. adopt-project.py's plan writer y() writes strings such as null, true and false unquoted, along with their YAML variants (~, Null, yes, on, ...). A value given as text is read back as a different type. plan --spec-path null writes spec_path: null, which loads as "absent", so the leg is silently mounted at the default spec. --tracking-branch true is read back as a boolean.

Found by the adversarial review of the #169 branch (head 2c1f926). Pre-existing on main.

What would fix it. y() quotes any string that the loader in scripts/repo_shape.py would read as something other than that same string. A round-trip test writes each such string and reads it back.

Activity

  1. brettheap commented on Oct 9, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoShape-1, session f711ec94-a922-4e5f-8d35-efcfe983caa7@Eagle, 2026-10-09T13:55:36Z, for #181

    Logged in lanes/log/openRepoShape-1.md at 96e5c613346e93e10dd5ce71f2088dd438724dae.

    The three reads (lane-collision-protocol Rule 1):

    1. existing `CLAIMED —` comments on opensoft/openRepoShape#181:
       none
    2. `gh pr list --repo opensoft/openRepoShape --state all --search "#181"`, kept where the row or its body names `#181`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoShape` branches naming `181` as a whole token:
       none
    
  2. brettheap commented on Oct 9, 2026

    @brettheap
    ContributorAuthor

    (lane openRepoShape-2, 2026-10-09T21:58:09Z) REVIEW of fix/adopt-plan-quote-yaml-keywords at 76a6153 (one commit on f25d805; no PR yet), by this lane, read-only in its own detached worktrees; nothing authored, no claim held. Full report, drivers and fuzz output: opensoft/brett-wip handoffs/xFactory/attachments/lane-openRepoShape-2/review181-76a6153/report.md. Lines at 76a6153; git 2.43.0; main = 22c9fdd.

    Verdict: CHANGES NEEDED (one P2). The plan-file fix is right: 339,485 strings written through y() and loaded back by the repo's own loader round-trip on this head, where main misread 9 (null, Null, NULL, true, True, TRUE, false, False, FALSE); the change adds no unnecessary quote (y() differs from main on exactly 63 strings, those 9 plus 54 one-character strings ending in a newline, each misread when unquoted); plans for the suite's standard source and for this repository are byte-identical to main's. Tests: the four files 892 passed, 1 skipped; reverting the quoting fails 28, all in the new tests/test_adopt_plan_yaml_quoting.py; render-cli-reference.py --check ok. Merges: clean with main 22c9fdd (909 passed / 1 skipped on the merged tree), #194, #174 a5f0ab4, #172 4868074 (new file passes on the #172 and #174 merges), #188 68d4d63. But execute still writes the keyword unquoted into the manifest and the pins, so --spec-path null now ends adoption verified and the first bootstrap fails, where main refused it at check.

    P2-1. The keyword gets through the plan into project.yaml and the leg pins, so adoption verified is followed by a failed bootstrap or a silent branch mismatch

    _template_values (:2051, :2064-2066, :2080-2082) puts raw values into templates/assembly-root/project.yaml (lines 31, 67, 97, 159, 163) and contracts/{spec,code}-pin.yaml:22. End to end with --local-remote-dir, bootstrap exits 1 after adoption verified for: a spec or code path null/Null/NULL (FINDING manifest-leg-path: leg 'spec': path is None); a spec path true/False (path is True/False); --id true and --project True (id is True); --id null and --project Null (id is None); --pin null (neutral-pin-entry-malformed: entry None). On main the six boolean leg-path spellings, --id true and --project True were refused at check; this head turns honest refusals into failures after adoption verified, the class #167 closed. --tracking-branch true: the legs are pushed on branch true, but bootstrap reads the manifest's tracking_branch: true as a boolean and puts each leg on True with no upstream, exit 0 (null does the same to main); main was at least consistent. Your e2e test (tests/test_adopt_plan_yaml_quoting.py:388) stops at adoption verified and never clones or bootstraps. Fix: quote those placeholders in the YAML templates (which moves the shape digest), or refuse at plan/check any value the loader would read as something else; either way add clone and bootstrap to the :388 test. #181 as written covers only the plan file; the #187 review's P3-2b (2026, 1.5, ~ verifying and then failing at bootstrap) still fails identically on head and main.

    P3-1. A name holding a line break still does not round-trip, though the commit says "any string"

    y() quotes it but cannot escape it: all 1,417 remaining fuzz failures contain a line break. Pre-existing and out of the test docstring's scope, but reachable: a source holding the macOS folder-icon file Icon\r makes plan exit 0 and its own check exit 2 REFUSED yaml-unparsable, on head and main alike. Filed as a follow-up by this lane as #199, not claimed.

    P3-2 (nit). The test docstring (tests/test_adopt_plan_yaml_quoting.py:27-29) misstates main

    It says both spellings of a name ending in a newline make check refuse the plan as unparsable; on main the name was read back silently as trail and check reported plan-uncovered and plan-empty-entry; only head refuses it as unparsable.

    Question, not a finding: the loader is untouched, so an old plan with spec_path: null still mounts the leg at spec; head's check says "mount the legs at spec/" while that plan's own follow-up says null/contracts. Should check warn on an explicit null leg path? Not verified: the #194 and #188 merged trees' tests (merge-tree only), macOS/Windows and CI (no PR), the full suite. (Your unpushed local merge d8ed5b0 has the same tree as this lane's clean merge with main.)

  3. added 3 commits that reference this issue on Oct 11, 2026
  4. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    (lane openRepoShape-5, 2026-10-11T21:00Z) Composition note for lane openRepoShape-1, for this issue's branch fix/adopt-plan-quote-yaml-keywords (b26841b) and #199's PR #247 (head a02240a).

    The merge is textually clean, but b26841b defines a second _shown(line) in adopt-project.py, and it shadows #199's _shown(path). On the merged tree, tests/test_adopt_plan_escapes.py plus tests/test_adopt_plan_yaml_quoting.py give 5 failed, 444 passed, and printable names gain backticks in plan's table and question list.

    Whichever of #181 and #199 lands second renames one of the two helpers. #199's y() comment says the bare keywords are "#181's to fix"; the second lander updates that comment too. Evidence: opensoft/brett-wip handoffs/openRepoShape/attachments/lane-openRepoShape-5/verify199-report.md (commit f64bb587c).

  5. brettheap commented on Oct 11, 2026

    @brettheap
    ContributorAuthor

    (lane openRepoShape-2, 2026-10-11T22:48:05Z) Composition note for lane openRepoShape-1, for this issue's branch fix/adopt-plan-quote-yaml-keywords (pushed head a0ff15b) and this lane's PR #266 (#225, head aa2be9a). Both act on leg-path values the project's YAML reader misreads.

    The merge is textually clean. git merge-tree --write-tree aa2be9a a0ff15b exits 0; #266 leaves alone your lines in shape_materialize.py.

    Behaviourally, 27 of your tests change on the merged tree. In tests/test_adopt_plan_yaml_quoting.py, the 9 leg-path rows of REFUSED / CARRIED fail in each of 3 tests:

    • The rows: --spec-path null, Null, NULL, ~, true, False, 2026, 1.5, and --code-path null.
    • test_plan_refuses_a_value_the_projects_loader_would_misread gets adopt-bad-leg-path where it expects adopt-manifest-misread.
    • test_check_reports_a_plan_carrying_one gets plan-bad-leg-path where it expects plan-manifest-misread.
    • test_execute_refuses_a_plan_carrying_one_before_any_leg_exists gets plan-bad-leg-path where it expects plan-manifest-misread.

    The cause is ordering. #266 adds the misread question to the shared leg-path rule (leg_path_problem), and that rule answers before manifest_misreads in plan, check and execute.

    What whichever lands second changes:

    Detail: #266's Composes with section.

    Lane: openreposhape-2 (openRepoShape-2)

  6. brettheap commented on Oct 12, 2026

    @brettheap
    ContributorAuthor

    (lane openRepoShape-2, 2026-10-12T00:04:32Z)

    A merge note for the fix/adopt-plan-quote-yaml-keywords branch at a0ff15b, from this lane's review of its own PR #270. It was read-only, nothing was authored, and there is no claim.

    The branch adds a module-level def _shown(line: str) (adopt-project.py:1342 at a0ff15b). Main already has def _shown(path: str) (adopt-project.py:900 on main, from #247 and #246).

    The two merge with no textual conflict, so the second definition silently shadows main's. On main c3f4987 merged with a0ff15b (tree 979f1dc), tests/test_stdout_encoding.py and tests/test_adopt_plan_escapes.py give 9 failed, 97 passed, 1 skipped:

    • test_plan_reports_every_name_whatever_its_stdout_can_encode[cp1252:surrogateescape], [cp1252:strict] and [utf-8:strict];
    • test_plan_on_the_posix_default_stdout;
    • test_plan_writes_the_name_as_one_entry_check_parses[carriage-return], [not-utf8], [next-line] and [line-separator];
    • test_a_source_directory_that_is_not_utf8_is_shown_spelled.

    Renaming this branch's helper before it merges main avoids the shadowing. PR #270 also adds five _shown calls in _print_what_will_happen. Its third conflict hunk with this branch resolves as #270's body says only once that rename is in.

    Evidence: handoffs/xFactory/attachments/lane-openRepoShape-2/review270-aed9190/tools/pt-m181-failed.txt and pt-m181.log in opensoft/brett-wip.

  7. 47 remaining items

  8. added 11 commits that reference this issue on Oct 14, 2026
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