gabriel / muse public
Closed #107 Bug design
filed by aaronrene human · 29 days ago

Integrity: 1,080 historical commit signatures invalid after ID migrations

0 Anchors
— Blast radius
— Churn 30d
0 Proposals

Summary

Whole-history verification of the current canonical gabriel/muse ancestry reports 1,080 invalid Ed25519 signatures. Current objects, snapshots, commit IDs, and recent signatures verify; the failures are historical and align with the May 20–21 commit-ID/unified-store migrations.

This is not currently tracked by an issue. Related issues #10/#11 intentionally changed all object IDs but did not specify signature preservation. Issue #83 later established the correct invariant—every changed-ID commit must be re-signed—but it addressed a different snapshot-repair case and is closed.

Exact observation

  • Staging repo ID: sha256:200e8689fe34a831289bc1eca17633b2069d595379b7c2f57a158e35d8291bec
  • Production repo ID: sha256:f97e3518b7887284682a8a7b357b514c3383f5565d4039422598936d354fc83c
  • Both main and dev: sha256:c606568badb1bd51b0da285b5c395370f5e6148b205cd3948de4113c5714ba70
  • Snapshot: sha256:20f25c55ab64ce347280522b2eefbb937bf90dc3241967d6918bd3fac10ce0cd
  • muse verify --branch dev --json: 1,550 commits, 1,518 snapshots, 1,204 rehashed objects, 1,464 signatures checked, 1,080 signature failures, zero other failure kinds
  • Oldest failure: sha256:1c4b3e3a9a1f300774c3ee662b572a698d5fd405bf765a71e6011a2e9c3eaaaa
  • Newest failure: sha256:2f17e90958a3a39216322972274314b4c495ed995ea0edf4d24a777d171226f7
  • Valid signing resumes at sha256:1900655993c83c4107067375548a7be823e471d2515830842f1a12cba4bd3cdf

muse/core/migrate.py recomputes commit/snapshot/parent IDs and copies the old signature. Since the provenance payload includes commit_id, the copied signature becomes invalid. Current records reproduce their current IDs, but the original pre-migration signed objects and a complete immutable original-ID→current-ID map have not been recovered; migration-only transformation therefore cannot be cryptographically proved for every affected record.

Impact

  • Adding Timeline, Knowtation/Notation, or any other built-in domain to this source repository inherits a failing whole-history gate even when the new code is correct.
  • New user repositories do not inherit these failures.
  • Runtime use is not known to be broken, but maintainers, contributors, release verification, and anyone auditing gabriel/muse encounter an unresolved provenance result.
  • A staging-only exception is insufficient because production publishes the same head under a different repository ID.

Preserve all old records unchanged and add a versioned, maintainer-signed history-boundary/v1 attestation. This is a new trust root, not a claim that the 1,080 old signatures were recovered or verified.

The attestation and verifier must bind and validate:

  1. Repository identity (or an explicit signed staging↔production mirror relationship), exact boundary commit and snapshot.
  2. Content digest of the exhaustive affected-current-ID manifest and exact failure count.
  3. Classification of that bounded set as legacy_unverified caused by an ID-changing migration whose original mapping/proof is unavailable.
  4. Migration code/version and observation time.
  5. Gabriel's maintainer key and revocation state.
  6. Normal object, snapshot, commit-ID, and signature verification for every descendant after the boundary.

The verifier must report the bounded exception explicitly and fail closed for a wrong repo/head/snapshot, altered or extra affected ID, new pre/post-boundary failure, invalid/revoked attestation, or untrusted signer. A blanket --ignore-signatures mode is out of scope.

Other defensible options

  1. Recover authoritative original objects/backups plus an immutable old→current map, verify every original signature, and perform a reviewed canonical repair.
  2. Archive the current repository and establish a clean official successor from reviewed current bytes, with a signed link to the archive.

Acceptance criteria

  • Maintainer chooses and documents the trust policy before implementation.
  • Machine-readable exhaustive manifest and deterministic digest are generated.
  • Tests cover every binding, tamper, omission, extra-failure, signer, revocation, offline/cache, and mirror case.
  • Staging and production identities are both covered.
  • Current legacy failures remain visible and are never labeled valid.
  • All post-boundary commits verify normally.
  • Independent review reproduces the result before this is used as a release/domain-development gate.

Aaron can prepare the implementation, tests, documentation, evidence manifest, and proposal on an isolated feature branch after Gabriel confirms the policy. Gabriel would review/merge and issue the final maintainer signature.

◎ Activity1
●
aaronrene opened this issue 29 days ago
○
gabriel 2 days ago

Resolved — repaired, not left as a formally-unverified trust boundary.

The ticket's "original pre-migration signed objects... have not been recovered" premise turned out to be incorrect. Canonical local gabriel/muse history has (and apparently always had) 0 signature failures — every commit's current, valid signature was never actually lost. What was actually broken was the same bug we just found and fixed in gabriel/musehub this week: staging's stored copy of historical commit rows got corrupted by the rc10 object-store migration (spurious signer_public_key/signature stamped on rows without recomputing commit_id), but the correct data was sitting right there in canonical local history the whole time.

Repaired directly via wire_repair_commit (recomputes commit_id from the canonical record, fails closed on any mismatch — no "trust me" step, every repair is independently re-verified). Final result:

  • Staging: 1,079 of 1,080 repaired, confirmed via fresh clone + muse verify across multiple follow-up passes (0 failures except the one noted below).
  • Production: already clean — 0 failures, the corruption never reached production's database.
  • One known exception: sha256:2f17e90958a3a39216322972274314b4c495ed995ea0edf4d24a777d171226f7 has a 15.6 MB structured_delta, which exceeds the /repair-commit endpoint's request body size limit (HTTP 413). Needs a scoped follow-up to raise or chunk that limit — filing separately, not blocking this closure.

The elaborate history-boundary/v1 attestation system this ticket proposed is not needed — there's no "legacy_unverified" class of commit here, just a repair that was never run against the full affected set. Full detail and cross-reference posted on muse#108 (Gate-1 L1), since this is the same 1,080 rows that surfaced there during the real-history migration spike.

Closing.

✓
closed this issue 2 days ago