Skip to content

A lane sidecar passes validation on its schema: line alone, so a truncated schema: 1 record is read AND replaced #115

Closed

Description

@brettheap

lane_sidecar_schema_ok is the gate every writer of a lifecycle snapshot or a tree sidecar takes before it replaces one (design decision 17, Copilot round 5 on #97), and it asks one question:

lane_sidecar_schema_ok() {   # <file>
  [ -e "${1-}" ] || return 0
  lss_v="$(lane_sidecar_field "$1" schema 2>/dev/null || :)"
  [ "$lss_v" = "$LANE_STATE_SCHEMA" ]
}

A file whose first line is schema: 1 and which holds NOTHING ELSE passes it. So does a tree sidecar with no tree: and no path:. That is a record of the current version which is not valid at that version, and both sides treat it as one:

  • the READERS emit empty fields for it. lane_state_read prints state empty, which lane_reconcile then classifies through its *) arm as unknown-state — it happens to fail safe, but by accident rather than by a check; lane_trees_list prints a row with an empty path, which the reconciliation reads as a tree whose path is the empty string.
  • the WRITERS replace it. set-lane-state and set-lane-tree take this gate as nothing here needs protecting and rename their own file over the top — which is the exact act decision 17 exists to refuse for an unknown schema, made instead against a record whose schema is known and whose content is not.

A truncated file is not exotic here: these records are written by lane_sidecar_put, whose cat > "$f.tmp.$$" can be cut short by a full disk or a killed process, and the rename is what makes a COMPLETE file atomic — not what makes an incomplete one impossible.

Why this is filed rather than fixed on #97

Copilot review rounds are capped at two per pull request (Brett Heap's ruling of 2026-09-16); #97 is at round six and took only the two safety holes it could not land with. This one is a hardening of a gate that already exists and already fails closed for the case it was written for.

What's open

Validate the record and not only its version line: the required keys for the kind of sidecar it is (lane, state, generation, operation for a snapshot; tree, path for a tree), their shapes, and the identity the file claims — and route a malformed record of a KNOWN schema through the same refusal path an unknown schema takes, so that nothing replaces what it could not make sense of.

Filed from Copilot round 6 on #97 — #97 (comment) — and named in openspec/changes/add-crash-consistent-lane-worktree-recovery/tasks.md section 7.

Activity

  1. brettheap commented on Sep 16, 2026

    @brettheap
    ContributorAuthor

    CLAIMED — lane openRepoTools-3, session 4135b2c9-34a6-47e3-a156-5adebb632fae@Eagle, 2026-09-16T13:05:47Z, for #115

    Logged in lanes/log/openRepoTools-3.md at 8650a32b7c1fcd93d6a3f8918b49bffb4877cf60.

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

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

    @brettheap
    ContributorAuthor

    TAKEOVERopenRepoTools-3 — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-18T13:36:04Z, for #115

    Logged in lanes/log/openRepoTools-4.md at ad3c7b1142eb2ddd85bab4cb96330998b020cad2 (takeover of the stale claim held by lane openRepoTools-3).

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

    1. existing `CLAIMED —` comments on opensoft/openRepoTools#115:
    6:CLAIMED — lane openRepoTools-3, session 4135b2c9-34a6-47e3-a156-5adebb632fae@Eagle, 2026-09-16T13:05:47Z, for opensoft/openRepoTools#115
    13:1. existing `CLAIMED —` comments on opensoft/openRepoTools#115:
    2. `gh pr list --repo opensoft/openRepoTools --state all --search "#115"`, kept where the row or its body names `#115`:
       none
    3. `git ls-remote --heads git@github.com:opensoft/openRepoTools` branches naming `115` as a whole token:
       none
    
  3. brettheap commented on Oct 19, 2026

    @brettheap
    ContributorAuthor

    Fixed by #252, landed on main as 00d52ae on Brett Heap's word of 2026-10-18 ("merge #252 when green"), by commits 6924ecf (a lane sidecar of the current schema is read and replaced only when it is whole), e95d072 (review r1: a snapshot under a directory named trees stays a snapshot; set-lane-tree refuses a blank field with 64) and e6a41b4 (#219's two path-less sidecar cases assert this rule).

    #252's body said "Closes #113, #114, #115", but GitHub reads the keyword only before the first number, so the merge closed #113 alone. This closes #115 by hand, as #252 intended.

    Lane: openRepoTools-4

  4. added a commit that references this issue on Oct 19, 2026
  5. brettheap commented on Oct 19, 2026

    @brettheap
    ContributorAuthor

    RELEASED — lane openRepoTools-4, session e545e636-93fd-4b80-81b1-48177346b887@Eagle, 2026-10-19T21:09:05Z, for #115 — fixed by #252, landed as 00d52ae on Brett Heap's word of 2026-10-18; #115 is closed; #252's mC test follow-up goes under #173

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