Skip to content

feat(trust): replay-integrity panel — script logic on the operator surface#352

Open
ctol3r wants to merge 1 commit into
wave/recent-npis-lineagefrom
wave/replay-integrity-surface
Open

feat(trust): replay-integrity panel — script logic on the operator surface#352
ctol3r wants to merge 1 commit into
wave/recent-npis-lineagefrom
wave/replay-integrity-surface

Conversation

@ctol3r
Copy link
Copy Markdown
Owner

@ctol3r ctol3r commented May 12, 2026

Summary

Stacked on #350 (recent-NPI memory). Promotes the CLI tooling shipped in #351 into a visible operator surface on /passport/[id]. A reviewer now sees replay continuity health without terminal access — three rows in the institutional register.

Panel rows

Row States
coherence computing / coherent (emerald) / no-declaration (dashed border) / run-drift (amber, role="status") / lineage-drift (rose, role="alert")
gaps computing / no-history / continuous (emerald) / discontinuous (amber, reports gap count + largest gap with from/to timestamps)
identity always renders lineage · lin_v1_… + <RunIdentity> — visible mono text, never aria-only

coherence answers: "does the runId the backend declared match the runId I can recompute from the same evidence?" That detects either upstream tampering / cache contamination OR algorithm drift between the web mirror and the backend canonical.

gaps uses the same DEFAULT_MAX_GAP_HOURS=720 threshold as scripts/replay/find-replay-gaps.ts. The history input is the recent-NPIs list from #350, filtered to the current subject — so the gap rendering is per-subject continuity over what this client has actually inspected.

Files

File Status
apps/web/lib/replay/clientReplayIdentity.ts new — browser-compatible mirror of the v1 algorithm (uses crypto.subtle.digest)
apps/web/lib/replay/integrityEvaluation.ts newevaluateReplayCoherence + summarizeReplayGaps pure helpers
apps/web/components/trust/ReplayIntegrityPanel.tsx new — composes Lane B <CheckedAtStamp> + <RunIdentity>; no new visual vocabulary
apps/web/components/trust/index.ts barrel export
apps/web/app/passport/[id]/PassportEntityClient.tsx renders the panel below RecentNpis
apps/web/__tests__/replay-identity-parity.test.ts new — 13 cases pinning the v1 algorithm shape contract
apps/web/__tests__/replay-integrity-panel.test.tsx new — 12 cases for helpers + panel + doctrine

Aesthetic compliance

Per the institutional brief: monochrome with coloured borders ONLY on coherence states; no charts; no animations; no decorative iconography; mono identifiers; left-aligned. The panel reads as an institutional log row, not a card.

Truth rules

  • Banned-strings scan: CLEAN across all four coherence states
  • No bare Verified label
  • No new product claims; the panel reports observable algorithm state only

Validation

  • Targeted vitest: 25/25 passing
  • Full build: pnpm turbo run build --filter @vitalcv/web13/13 tasks
  • No new dependencies

Cross-implementation parity

The web mirror at clientReplayIdentity.ts produces v1-prefixed ids using crypto.subtle.digest. The backend canonical (#343, parallel stack) uses node:crypto over the SAME algorithm. Until both stacks merge, the parity test pins the shape + invariants of the web mirror; a follow-up integration test will lock direct web↔backend cross-import once the stacks converge.

Out of scope (explicit follow-ups)

  • /ops/replay / /ops/lineage / /ops/survivability diagnostic pages (operator-only routes)
  • /api/replay/integrity/[id] external endpoint
  • Direct web↔backend parity import-test (post-merge follow-up)

…rface

Stacked on #350 (recent-NPI replay-memory). Promotes the CLI tooling
shipped in #351 (scripts/replay/*) into a visible operator surface
on the passport page. A reviewer now sees replay continuity health
without terminal access.

Three rows render in the institutional register (monochrome,
mono identifiers, left-aligned, no shadows, no decorative iconography):

  1. coherence: does the runId the backend declared on the passport
     match the runId locally recomputed from the same evidence?
     States: computing / coherent (emerald) / no-declaration /
     run-drift (amber) / lineage-drift (rose, role=alert).

  2. gaps: chronology gap summary over the recent-NPIs history,
     using the same DEFAULT_MAX_GAP_HOURS=720 the find-replay-gaps.ts
     script uses. Reports "continuous (N snapshots)" or "N gap(s);
     largest XXh" with explicit from/to timestamps.

  3. identity: the resolved lineageKey + runId rendered as visible
     mono text, always — never aria-only, never tooltip-only.

New files:

  apps/web/lib/replay/clientReplayIdentity.ts
    Browser-compatible mirror of the v1 replay-identity algorithm.
    Uses crypto.subtle.digest (async) instead of node:crypto. Same
    inputs, same normalization, same scheme prefix as the backend
    canonical (#343). Pinned by the parity test below.

  apps/web/lib/replay/integrityEvaluation.ts
    Pure server-side helpers:
      - evaluateReplayCoherence(input) → CoherenceFinding
      - summarizeReplayGaps(history, thresholdHours) → GapSummary
    Same gap-detection semantics as scripts/replay/find-replay-gaps.ts.

  apps/web/components/trust/ReplayIntegrityPanel.tsx
    Client component composing the three rows. Reuses Lane B
    <CheckedAtStamp> + <RunIdentity> — no new visual vocabulary.

  apps/web/__tests__/replay-identity-parity.test.ts (13 cases)
    Pins the web mirror against the v1 algorithm shape contract:
    prefixes, lengths, normalization invariance, sensitivity to
    every input field, deterministic 25-iteration loop, degraded
    distinguishability, error on empty entity id.

    Direct cross-implementation parity (web ↔ backend module) is
    deferred to a post-merge integration test once the parallel
    stacks converge — the backend module ships in #343, which this
    branch doesn't have in its history.

  apps/web/__tests__/replay-integrity-panel.test.tsx (12 cases)
    evaluateReplayCoherence transitions through all four states;
    summarizeReplayGaps respects threshold + sorting + largest-gap
    selection; panel renders the expected data-* anchors for each
    initial state; doctrine banned-strings scan CLEAN.

Adoption:
  apps/web/app/passport/[id]/PassportEntityClient.tsx
    <ReplayIntegrityPanel> renders below the RecentNpis section,
    consumes passport.replay (Wave 10 / #343) when present, falls
    back gracefully to "no-declaration" state otherwise.

Validation: 25/25 vitest passing; pnpm turbo run build --filter
@vitalcv/web → 13/13 tasks; truth-strings CLEAN.

Out of scope (explicit follow-ups):
  - /ops/replay diagnostics page — would consume the same helpers
    but expose them at an operator-only route
  - Direct web↔backend parity test — needs both stacks merged
  - /api/replay/integrity/[id] external endpoint — wraps the helpers
    for third-party verifier polling
@vercel
Copy link
Copy Markdown

vercel Bot commented May 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vcv-web Ready Ready Preview, Comment May 12, 2026 11:59pm
vitalcv Ready Ready Preview, Comment May 12, 2026 11:59pm

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 954ffc33cb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

replay integrity
</span>
<span className="font-mono text-[10px] uppercase tracking-wider opacity-60">
scheme · {declared?.schemeVersion ?? coherence?.state === 'coherent' ? 'v1' : 'pending'}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve declared replay scheme in header

The scheme badge expression currently parses as (declared?.schemeVersion ?? coherence?.state === 'coherent') ? 'v1' : 'pending', so any non-null declared version is treated as truthy and rendered as v1. This means a future backend value like "v2" would be mislabeled as v1, which breaks the intended survivability/version marker for operators. Parenthesize the fallback so the actual declared string is displayed when present.

Useful? React with 👍 / 👎.

// via passport.replay when present; otherwise the panel
// computes from entityId + lastCheckedAt alone, which
// still gives a coherent lineage check.
artifactChecksums: undefined,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass artifact checksums into coherence evaluation

This panel recomputes runId to compare with the backend declaration, but artifactChecksums is always forced to undefined here. In any environment where the backend runId includes artifact-derived inputs, the client recomputation will systematically omit part of the evidence and produce false run-drift states for otherwise matching snapshots. Wire the replay/artifact inputs through instead of hardcoding undefined.

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants