Skip to content

Mixed-version teams: tests_update (2026.10.12+) writes per-test updated_by/updated_at that pre-10.12 hosts drop from hashes — valid history fails verify and CI goes red #1458

Closed

Description

@unbraind

Problem

tests_update, added in 2026.10.12 ("Edit linked-test metadata in place with preserved provenance"), writes new per-test fields: metadata.tests[i].updated_by and metadata.tests[i].updated_at. Hosts older than 2026.10.12 don't know these fields. When they canonicalize the item for hashing they drop them, so they compute a different item hash and report history corruption on a perfectly valid history.

In a fleet where agents use a newer global pm while the repository pins an older @unbrained/pm-cli, which is the normal state between Dependabot bumps, a single linked-test edit turns the repo's CI red.

Real occurrence (public repo unbraind/pm-review, PR #1, pins 2026.10.10)

An agent ran pm test <id> --update … --timeout 600 with a global 2026.10.13 host. History entry 23 of pm-review-round:

{"op":"tests_update","patch":[
 {"op":"add","path":"/metadata/tests/0/timeout_seconds","value":600},
 {"op":"add","path":"/metadata/tests/0/updated_by","value":"codex-agent"},
 {"op":"add","path":"/metadata/tests/0/updated_at","value":"2026-10-13T12:56:35.894Z"},
 {"op":"replace","path":"/metadata/updated_at","value":"2026-10-13T12:56:35.894Z"}]}

Same files, two hosts:

pm 2026.10.13 history pm-review-round --verify  → ok:true, current_matches_latest:true
pm 2026.10.10 history pm-review-round --verify  → ok:false
  errors: verify_failed:after_hash_mismatch:entry_23, verify_failed:current_item_hash_mismatch

CI (pinned 2026.10.10) then fails pm health with history_drift_chain_mismatch:pm-review-round and history_drift_hash_mismatch:pm-review-round.

A second agent in another repo (pm-context) hit the same thing. The pinned host also rewrote the tests block and dropped updated_by/updated_at when it next touched the item, so the "fix" an agent reaches for is data loss: re-anchoring history with the older host.

Why this matters

The CLI's core promise is that many agents on many branches can work on one tracker and merge losslessly. Mixed host versions are unavoidable in that world: global installs, pinned devDependencies and CI images all drift. This is the same class as #976, #1040 and #1162, now triggered by a new feature's fields rather than by hashing changes.

Proposal

  1. Forward-compatible hashing: older hosts hash unknown nested fields verbatim instead of dropping them, or the canonical form is declared field-agnostic for metadata.tests[] entries.
  2. Or gate new fields behind a declared format/feature version: a newer host writing to a tracker whose settings.json / format_version predates the feature either refuses or writes the legacy shape, unless the tracker opts in (for example pm workspace upgrade).
  3. Diagnostics: when verification fails on an op the verifying host doesn't recognize, or on fields it doesn't know, report history_written_by_newer_host (naming the op and fields) rather than generic chain/hash drift, and recommend upgrading the verifying host. Never suggest a re-anchor that drops the newer data.
  4. A cross-version test matrix: history written by N verifies under N-1 and N-2 for every new op and field.

Activity

  1. unbraind commented on Oct 13, 2026

    @unbraind
    OwnerAuthor

    Second independent occurrence, in a different repo (unbraind/pm-github PR #115). The repository pins @unbrained/pm-cli 2026.10.9; an agent wrote with a global 2026.10.13. Both report item_hash_version: 3 for the same TOON document, yet 2026.10.9 cannot reproduce the before_hash/after_hash values 2026.10.13 stored. CI then reports history_drift_chain_mismatch and history_drift_hash_mismatch at every write boundary, although every patch replays cleanly with no content loss.

    Two consequences worth designing for:

    1. Nothing warns at write time. The newer host writes, and the failure only appears later, in CI, run by the older host. A write-time warning when the running host differs from the host that wrote the item's last history record (or from the repo-pinned version in package.json) would catch it before commit.
    2. The natural agent remedy destroys history. Two separate agents "fixed" CI by re-anchoring the chain with the pinned older host. That replaces existing JSONL records (not append-only) and drops the newer per-test fields. A code reviewer bot flagged it as a non-append-only history rewrite. The diagnostic should say "written by a newer host; upgrade the verifying host" and explicitly advise against re-anchoring.
  2. unbraind commented on Oct 13, 2026

    @unbraind
    OwnerAuthor

    Tracked by pm-gh1458. The linked-test editor and published-artifact matrix are linked predecessors. This owner captures both reported occurrences, nested-field/hash preservation and safe verifier-upgrade diagnostics; independent reproduction remains pending.

  3. unbraind commented on Oct 14, 2026

    @unbraind
    OwnerAuthor

    Independent synthetic published-artifact reproduction now confirms this existing report for 2026.10.10 → 2026.10.13 → 2026.10.10.

    Provenance/scope: both were existing installed official npm artifacts, with file bytes checked against their retained tarballs (10.10: 6,375 files; 10.13: 6,411 files). No fetch or upgrade was used. The test used disposable unpinned Git worktrees, an isolated HOME/global PM root, disabled telemetry and a deny-network preload. This does not claim that the existing project-pin guard is absent, or that a 10.14 package was tested.

    Minimal sequence (PM path and JSON output applied consistently):

    1. With 10.10: initialize a tracker, create a synthetic Task, then pm test <id> --add 'command=node --version'.
    2. Both 10.10 and 10.13 history <id> --verify return ok:true (two records).
    3. With 10.13: pm test <id> --update 'node --version' --set-json '{"timeout_seconds":600}' --author newer-editor. This adds the nested updated_by/updated_at stamps.
    4. Preserve all authoritative bytes before any old-host access. On those identical bytes, 10.13 verifies three records; 10.10 reports verify_failed:after_hash_mismatch:entry_3 and verify_failed:current_item_hash_mismatch. The old read omits the two stamps, but these read-only commands do not change the files.
    5. On a separate copy, a normal 10.10 comments <id> --add 'Synthetic older-host ordinary mutation' succeeds and removes both nested stamps from the item. It appends a fourth event with an incompatible before-hash; both versions then reject verification. Original history records remain a byte-identical prefix, so a rewrite/re-anchor is not needed to trigger the incompatible chain.

    Negative controls:

    • The same 10.10 comment mutation on the preserved pre-editor shape verifies under both hosts.
    • On actual 10.13 alone, three waves of six concurrent writers (18 mutations) retain all 12 distinct comments and disjoint field edits, retain nested editor stamps, preserve the starting history prefix and verify after every wave (21 records at end).
    • The newer-written original fixture and original JSONL were preserved. No re-anchor, real repository mutation or network attempt occurred.

    The 10.14 item-format.ts Git blob is identical to 10.13, but that is only source evidence; this reproduction does not establish 10.14 installed behavior. Suggested next acceptance remains the existing pm-gh1458 scope: per-operation/nested-field matrix coverage and a preserve-or-refuse boundary before unsupported writes, with diagnostics pointing to a compatible verifier rather than destructive history repair.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions