Skip to content

seal --verify never checks dependency hashes; 21 claw seals record stale ones #10727

Open

Description

@gHashTag

What

t27c seal <spec> --verify does not compare the dependency hashes that a seal records. It checks the spec's own spec_hash and the four gen_hash_* values, and nothing else.

As a result, 21 claw seals on master record 25 dependency hashes that no longer match their dependency, and every one of them still verifies.

Negative control (Railway lab, /root/t27c-master, 2026-10-19)

On .trinity/seals/claw_ClawMergeLane.json:

Edit seal specs/claw/merge_lane.t27 --verify
none rc 0, "all hashes MATCH"
the specs/claw/text.t27 dependency spec_hash set to sha256:000000... rc 0, "all hashes MATCH"
the seal's own spec_hash set to sha256:000000... rc 1

The verifier prints a line for spec_hash and for each gen_hash_*. It prints no line for the dependencies.

What is stale on master now

The recorded dependency hash differs from sha256(git show origin/master:<dep>) in these seals:

  • text.t27: CheckLatest, CheckState, Evidence, Gates, LedgerUnion, MergeLane, Preview, PushGate, QueueCost, RequiredRed, SarifPins, Service, ShapeRace, Suggest, SuggestFeed, TokenShape
  • sarif.t27: Refresh, SarifFeed, SarifPins
  • github_surface.t27: ControlPins
  • evidence.t27 and t27f/spec_graph.t27: EvidencePins
  • gates.t27: GatesPins
  • refresh.t27: PushGate
  • suggest.t27: SuggestFeed

Most of the text.t27 entries date from #10714, which changed text.t27 without resealing its importers. That PR passed CI because nothing reads these hashes.

Why it matters

A seal says "this spec, built against these dependencies, generated this code". If only the first half is checked, a dependency can change underneath a sealed spec, and the seal goes on saying the spec was checked against it.

Possible fixes

  1. Verifier. seal --verify hashes each recorded dependency and fails on a mismatch, printing one line per dependency. This is a t27c change (Rust), so it needs the owner's owner-approved-foreign label; the claw lane does not make it.
  2. Data, until then. Reseal the stale seals (19 once test(claw): kill the real check_state.t27 and merge_lane.t27 mutation survivors #10726 merges) with seal --save, with zig on PATH and without --force. This is tool-written data, so it is allowed under the t27-only rule. The two seals in test(claw): kill the real check_state.t27 and merge_lane.t27 mutation survivors #10726 are already resealed this way.

Found while resealing for #10724 / PR #10726: the seal diff changed the recorded text.t27 hash, although that PR does not touch text.t27.

User Scenarios

  • Given a claw seal that records dependency hashes, when running t27c seal <spec> --verify with a dependency whose current hash no longer matches the recorded hash, then the command fails with a non-zero exit code and prints a mismatch line for that dependency.
  • Given a claw seal where all recorded dependency hashes match their current dependencies, when running t27c seal <spec> --verify, then the command exits 0 and prints one line per dependency hash checked showing MATCH.

Requirements

  • FR-001: The verifier MUST compute the current hash of each recorded dependency and compare it against the hash stored in the seal.
  • FR-002: The verifier MUST print one line per dependency hash checked, similar to the existing lines for spec_hash and gen_hash_*.
  • FR-003: The verifier MUST exit with a non-zero code if any dependency hash mismatches.

Success Criteria

  • t27c seal specs/claw/merge_lane.t27 --verify exits 0 and prints dependency hash lines for all recorded dependencies when all hashes match
  • t27c seal specs/claw/merge_lane.t27 --verify exits non-zero and prints a MISMATCH line for text.t27 when its recorded hash in .trinity/seals/claw_ClawMergeLane.json is altered to an incorrect value
  • The verifier output includes exactly one line per dependency (e.g., "dependency specs/claw/text.t27: MATCH")

Boundary

  • cli/tri/src/seals.rs
  • .trinity/seals/claw_ClawMergeLane.json
  • specs/claw/merge_lane.t27
  • specs/claw/text.t27

Boundary

Fix 2 (data, done in #10729):

  • .trinity/seals/claw_ClawCheckLatest.json
  • .trinity/seals/claw_ClawControlPins.json
  • .trinity/seals/claw_ClawEvidence.json
  • .trinity/seals/claw_ClawEvidencePins.json
  • .trinity/seals/claw_ClawGates.json
  • .trinity/seals/claw_ClawGatesPins.json
  • .trinity/seals/claw_ClawLedgerUnion.json
  • .trinity/seals/claw_ClawPreview.json
  • .trinity/seals/claw_ClawPushGate.json
  • .trinity/seals/claw_ClawQueueCost.json
  • .trinity/seals/claw_ClawRefresh.json
  • .trinity/seals/claw_ClawRequiredRed.json
  • .trinity/seals/claw_ClawSarifFeed.json
  • .trinity/seals/claw_ClawSarifPins.json
  • .trinity/seals/claw_ClawService.json
  • .trinity/seals/claw_ClawShapeRace.json
  • .trinity/seals/claw_ClawSuggest.json
  • .trinity/seals/claw_ClawSuggestFeed.json
  • .trinity/seals/claw_ClawTokenShape.json

Fix 1 (verifier) is in t27c's seal command, which is Rust. It needs the owner's owner-approved-foreign label, and the claw lane does not make it.

User Scenarios

  • Given a seal whose recorded dependency spec_hash differs from the dependency file on disk, when t27c seal <spec> --verify runs, then it exits non-zero and names the dependency.
  • Given a seal whose dependencies all match, when --verify runs, then it prints one MATCH line per dependency and exits 0.

Requirements

  • FR-001: seal --verify MUST hash every recorded dependency and fail on a mismatch.
  • FR-002: Until FR-001 lands, stale dependency hashes on master MUST be resealed with seal --save, without --force.

Success Criteria

Status

Fix 2 is done (#10729, merged). Fix 1 stays open and waits for the owner's label.

Update 2026-10-19: the whole repository, not only claw

A scan of every seal on master 2520ee1 compared each recorded dependency hash with sha256(git show HEAD:<dep>). It found 154 stale dependency entries:

Stale entries Dependency
74 specs/base/types.t27
8 specs/verified/corpus_receipt.t27
7 specs/math/constants.t27
5 specs/tri/t27b/type_text.t27
5 specs/base/ops.t27
4 specs/trinet/tri-bridge.t27
4 specs/compiler/parser.t27

The claw lane leaves those 131 seals to the lanes that own them. Each one verifies today only because seal --verify skips dependencies (fix 1 above). So a verifier fix would turn all 131 red on its first run: it has to land together with one reseal sweep.

Activity

  1. added
    shape-refusedClosed by the issue-shape gate (specs/policy/issue_shape.t27); a passing edit reopens it
    on Oct 19, 2026
  2. github-actions commented on Oct 19, 2026

    @github-actions
    Contributor

    Closed by the issue-shape gate (specs/policy/issue_shape.t27, #7498): an issue must have the template's sections. Edit the body; an edit that passes reopens it.

    • missing: ## Boundary -- list every file this task may touch, one per line (- specs/x.t27); without it the Queen reserves nothing and no bee can take the issue
    • missing: ## User Scenarios -- at least one Given/When/Then scenario
    • missing: ## Requirements -- numbered obligations, FR-001: ... MUST ...
    • missing: ## Success Criteria -- an outcome a machine can settle: a number with a unit, a backticked file, exit 0, or a backticked command
  3. removed
    shape-refusedClosed by the issue-shape gate (specs/policy/issue_shape.t27); a passing edit reopens it
    on Oct 19, 2026
  4. github-actions commented on Oct 19, 2026

    @github-actions
    Contributor

    The shape check passes now (specs/policy/issue_shape.t27); reopened.

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions