Skip to content

fix: harden Agent recovery, corpus proof, and release signing - #74

Open
div0-space wants to merge 18 commits into
developfrom
fix/engine-routing
Open

fix: harden Agent recovery, corpus proof, and release signing#74
div0-space wants to merge 18 commits into
developfrom
fix/engine-routing

Conversation

@div0-space

@div0-space div0-space commented Aug 15, 2026

Copy link
Copy Markdown
Member

Summary

Foundation cut stacked on fix/the-tail-patches. It hardens four existing product surfaces before the single-owner runtime cuts that follow:

  • Agent recovery: terminal fallback events, a surgical Reset Agent flow, and preservation of non-Agent settings and secrets.
  • Transcript UI: selectable live/final text with bounded overlay geometry.
  • Corpus proof: redacted corpus census plus isolated production-session replay and private quality reports.
  • Release safety: concurrency-safe ephemeral signing keychains, a read-only doctor/canary, and hermetic keychain lifecycle tests.
  • Model packaging: MiniLM is a signed app resource in the normal build; Whisper remains runtime-loaded unless the embedded SKU is explicitly requested.

User impact

  • Failed Agent fallback requests terminate visibly instead of leaving the UI hanging.
  • Reset Agent removes only Agent-owned conversations, connectors, credentials, and defaults.
  • Long transcripts remain selectable without painting through the overlay controls.
  • Release builds no longer leave a temporary signing keychain in the user search/default domain.
  • Corpus comparisons can exercise the production replay path without loading operator settings or Keychain state.

Scope boundary

This is a broad foundation cut, not the owner of every runtime axis. Microphone ownership, committed transcript truth, Agent-thread capture ownership, and delivery routing are intentionally handled by later stacked cuts. Do not reintroduce those decisions here.

Verification

Remote checks currently green:

  • Format Check
  • Security Scan
  • Clippy + Tests
  • Snyk

Operator evidence represented by this cut:

  • hermetic keychain-session regression suite
  • fail-closed corpus/runtime-input checks
  • signed-resource and DMG payload contracts updated
  • production DMG signing/notarization is a release step, not implied by this PR

Review status

Copilot found one real corpus-report issue: Layer 1 observation was inferred from tail-patch count rather than the provider-armed signal. A tested local correction exists, but it is not on the remote branch yet; keep the PR review-required until the operator pushes that checkpoint and the checks rerun.

Release notes

Internal reliability and tooling foundation. User-visible reset and transcript-selection changes should be folded into the eventual product release notes, not shipped independently from the later runtime-owner cuts.

Copilot AI lite review requested due to automatic review settings August 15, 2026 07:46

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization has reached its monthly code review spending cap.

An organization admin can view or raise the cap at claude.ai/admin-settings/claude-code. The cap resets at the start of the next billing period.

Once the cap resets or is raised, reopen this pull request to trigger a review.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens release-signing keychain handling, introduces corpus census/replay tooling for parity analysis, and updates build/docs/UI to reflect the new “MiniLM as signed runtime resource” asset strategy (with Whisper still runtime by default, embedded only in the full SKU).

Changes:

  • Replaces inlined ephemeral keychain manipulation in the release workflow with a concurrency-safe keychain-session.sh + adds hermetic regression tests and a read-only “doctor” canary.
  • Adds codescribe-corpus for private corpus census and isolated production-session replay/parity reporting (with Keychain disabled and operator config untouched).
  • Refactors model asset embedding/bundling policy and updates app/overlay UX (native selectable live transcript) + adds a narrowly-scoped “Reset Agent” destructive action.

Reviewed changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.github/workflows/release.yml Uses keychain-session.sh for robust keychain lifecycle; adds post-cleanup diagnostic warning.
Cargo.toml Registers codescribe-corpus binary; promotes sha2 to non-dev dependency.
Makefile Adds corpus targets and test-keychain-session; updates release/model policy messaging and gate ledger notes.
README.md Updates public docs for MiniLM runtime resource + Whisper runtime/full-SKU embedding.
app/controller/helpers.rs Ensures legacy formatter fallback always emits a terminal Agent UI event sequence.
bin/codescribe-corpus.rs New corpus census + replay/parity tool with redacted machine reports + private Qube HTML output.
bridge/src/config.rs Adds Agent-only reset preview/reset APIs and scoped secret/env/settings cleanup.
core/build.rs Changes embedder policy to runtime bundle/cache by default; adds explicit CODESCRIBE_EMBED_EMBEDDER=1 embed path.
core/config/loader.rs Adds surgical .env key removal helper for scoped reset flows.
core/config/settings.rs Adds surgical Agent-owned settings removal (preserving unknown/non-Agent fields; fail-closed on malformed JSON).
core/embedder/engine.rs Adds app-bundle resource resolution for MiniLM under Contents/Resources/models/embedder before HF cache.
core/embedder/mod.rs Updates module docs to match bundled/cached/embedded runtime model resolution.
core/mcp/config_store.rs Makes list_servers_at public for path-explicit callers (reset tooling).
core/mcp/mod.rs Re-exports list_servers_at.
core/quality/qube_report.rs Exposes render_html publicly for reuse in replay tooling.
core/stt/apple_stt/mod.rs Adds ensure_noninteractive_ready for fail-closed unattended probes (no dialogs/downloads).
docs/ARCHITECTURE.md Updates architecture docs for runtime model policy and MiniLM resolution order.
docs/ENV_REGISTRY.toml Updates embedder defaults and adds CODESCRIBE_EMBED_EMBEDDER.
docs/INSTALLATION.md Updates installation docs for slim vs full DMG model packaging policy.
docs/TEAM_SETUP.md Updates team setup docs for runtime model policy and explicit fat/debug embed toggles.
macos/Codescribe/Bridge/codescribe_ffi.swift Adds UniFFI surface for Agent reset preview/reset + CsAgentResetPreview.
macos/Codescribe/Bridge/codescribe_ffiFFI.h Adds generated UniFFI symbols for Agent reset methods.
macos/Codescribe/Screens/AgentChat/AgentChatStore.swift Exposes attachment defaults key for Agent reset cleanup.
macos/Codescribe/Screens/Overlay/DictationOverlayView.swift Switches live transcript to native AppKit-backed selectable view; clips to prevent platform view paint bleed.
macos/Codescribe/Screens/Overlay/LiveTranscriptTextView.swift New NSTextView representable preserving selection across live updates + tail-follow behavior.
macos/Codescribe/Screens/Settings/SettingsEngine.swift Extends Settings engine protocol/implementations for Agent reset preview/reset.
macos/Codescribe/Screens/Settings/SettingsViewModel.swift Adds Agent reset state/flows and narrow defaults cleanup + relaunch behavior.
macos/Codescribe/Screens/Settings/UserPanel.swift Adds “Reset Agent” danger-zone section with separate confirmation phrase.
macos/CodescribeTests/LiveTranscriptTextViewTests.swift Adds tests for live transcript text view behavior and selection policy.
macos/CodescribeTests/OverlayStateTests.swift Adds snapshot guard for formatted overlay minimum height rendering regression.
macos/CodescribeTests/SettingsTruthTests.swift Adds tests covering Agent reset confirmation, scope, and relaunch/error markers.
scripts/build-app.sh Bundles MiniLM into app resources for normal builds; resolves model source from HF cache or explicit path.
scripts/build-dmg.sh Updates help/messaging and env unsets for new embedder bundling policy.
scripts/canaries.sh Adds host canary for keychain-domain cleanliness using read-only doctor.
scripts/entitlements.appstore-basic.plist Updates commentary to match Candle ML dylib signing context.
scripts/entitlements.plist Updates commentary to match Candle ML execution requirements.
scripts/keychain-doctor.sh New read-only keychain domain diagnostic + derived recovery command.
scripts/lib/keychain-session.sh New concurrency-safe keychain session manager with robust unlist-before-delete and trap chaining.
scripts/tests/keychain-session-test.sh New hermetic regression suite with fake security + redirected HOME (no real keychain touches).
scripts/verify-dmg-payload.sh Updates DMG payload gate to validate MiniLM as resource and adjust dylib/DMG thresholds accordingly.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread bin/codescribe-corpus.rs
@div0-space div0-space changed the title Refactor Agent handling and improve keychain management fix: harden Agent recovery, corpus proof, and release signing Aug 15, 2026
Copilot AI review requested due to automatic review settings August 15, 2026 11:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 46 out of 47 changed files in this pull request and generated no new comments.

Suppressed comments (1)

scripts/canaries.sh:237

  • The FAIL evidence extraction truncates keychain paths that contain spaces (e.g. "Team Signing.keychain-db") because the awk script prints only $2. This can misreport the stale/foreign/hijacked path and make recovery harder.

Base automatically changed from fix/the-tail-patches to develop August 19, 2026 10:01
div0-space and others added 17 commits August 19, 2026 12:01
- Publish TextDone and Done after a persisted legacy fallback
- Publish an actionable Error when both provider paths fail
- Guard the terminal mapping against blank fallback output

Authored-By: Codex <agents@vetcoders.io>
- Census private recordings without loading operator state or Keychain
- Replay explicit production profiles in isolated worker processes
- Emit redacted JSON/Markdown plus private keyboard-driven Qube HTML
- Preserve host configuration hashes and fail closed on TCC readiness

Authored-By: Codex <agents@vetcoders.io>
- Keep MiniLM bytes out of normal Cargo targets
- Resolve signed app resources before falling back to the HF cache
- Bundle and sign the model during app assembly
- Verify the resource directly instead of inferring it from dylib size
- Mark corpus source identity dirty when the Living Tree is not clean

Authored-By: Codex <agents@vetcoders.io>
- move only Agent conversations and MCP/tool files to Trash\n- clear Agent provider state and credentials without touching dictation data\n- add separate Settings confirmation, previews, bindings, and preservation tests\n\nAuthored-By: Codex <agents@vetcoders.io>
- stop animating the AppKit-backed TextEditor across overlay modes
- clip the transcript body at its sibling boundary
- render the observed minimum-height geometry and assert the action row stays clean

Authored-By: Codex <agents@vetcoders.io>
- preserve every non-Agent settings value and fail closed on malformed JSON
- delete only MCP connector tokens referenced by the active Agent config
- keep Agent relaunch handling out of the hotkey reset path

Authored-By: Codex <agents@vetcoders.io>
- Normalize the operator preferences plist through plutil before hashing.
- Keep settings.json and dotenv byte-exact while avoiding plist encoding false positives.
- Cover equivalent XML and binary plist storage with a regression test.

Authored-By: Codex <agents@vetcoders.io>
- Replace reset helper lint debt with explicit control flow.
- Bundle replay execution inputs so report rows cannot receive mismatched arguments.
- Bound corpus reads and private audio publication through capability-safe helpers.
- Pass the full static gate with zero Semgrep findings.

Authored-By: Codex <agents@vetcoders.io>
…eychain

A Codescribe run on 2026-08-15 popped "Codescribe wants to use the
'Vibecrafted-signing' keychain", with a password no human has. Measured
at the time: the user search list AND the default keychain both pointed
at a release's ephemeral keychain, while that release was still running.

- add scripts/lib/keychain-session.sh — an ephemeral signing keychain
  that always gives the user domain back. It never takes the login
  session's default keychain (opt-in via KEYCHAIN_SESSION_SET_DEFAULT),
  snapshots the search list as structured argv instead of one joined
  string, traps EXIT INT TERM HUP, and unlists BEFORE deleting so
  cleanup still works when the keychain file was already destroyed
- make restoration remove-self rather than replay-snapshot: two
  overlapping releases can no longer drop each other's keychain or
  resurrect a dead one
- add scripts/keychain-doctor.sh — read-only diagnosis grading each
  entry resident/FOREIGN/STALE and the default ok/HIJACKED, printing a
  recovery line derived from the surviving entries, never canned
  login-only, and never mutating
- add scripts/tests/keychain-session-test.sh (43 assertions) against a
  fake `security` and a temp HOME: spaces in paths, multiple keychains,
  failed build, SIGINT/SIGTERM, vanished keychain file, concurrent
  sessions, stale-entry reclaim, empty-list refusal, no secret leakage
- wire release.yml onto the library; its cleanup step only deleted the
  keychain and never restored the search list
- add the keychain-domain-clean canary and its GATE LEDGER row

Authored-By: claude <agents@vetcoders.io>
…aining

The trap-chaining path had no test. Adding one found a real defect: the
caller's own handler was preserved on EXIT and silently dropped on
INT, TERM and HUP — the three signals a bare EXIT trap cannot cover,
which is the whole reason the chaining exists.

- `trap -p` answers with the normalized signal name: `trap -p INT`
  prints `... SIGINT`, while the pseudo-signal EXIT stays bare. Stripping
  a literal " $sig" matched only EXIT and left the other three bodies
  malformed. Strip the last whitespace-delimited word instead
- cover both orderings: the caller's EXIT handler still runs and ours
  runs first, and the caller's INT handler survives alongside ours
- write child scripts verbatim instead of through an unquoted heredoc.
  The heredoc expanded the snippet's own `$$` and `$(...)` in the test
  harness, so `kill -INT $$` signalled the harness rather than the child
  under test

48 assertions, all green.

Authored-By: claude <agents@vetcoders.io>
…ning

shellcheck flags the trap bodies as expanding now rather than at signal
time. Here that is the intent: $body holds the handler that was already
registered, read back from `trap -p`, and it must be baked in at arm
time — deferring would splice an empty variable when the signal fires.
Documented rather than silenced.

Authored-By: claude <agents@vetcoders.io>
… shell bar

The sibling repo that also needs this library gates commits on
scripts/check_shell.py, which fails on ANY shellcheck finding —
info and style included. The suite carried ten.

- replace `A && ok ... || bad ...` with explicit if/else (SC2015): the
  short-circuit form is not if-then-else and would have run the failure
  branch had `ok` ever returned non-zero
- read the doctor's exit code from the command itself rather than `$?`
  (SC2181), and capture it without losing it to the assignment
- drop an unused local (SC2034)
- annotate the three single-quoted child snippets whose `$(...)` is meant
  for the child shell, not this one (SC2016)

48 assertions still green; shellcheck clean in both repos.

Authored-By: claude <agents@vetcoders.io>
…hable

Smoke-testing the new row against a substituted `security` reporting a
poisoned domain printed nothing at all: canaries.sh runs under `set -e`,
and `out="$(cmd)"; rc=$?` never reaches the second statement — the
assignment carries the substitution's exit status and aborts the whole
run before any row is recorded.

So the canary could only ever report PASS. That is the exact class of
silent hole the catalog exists to catch, in the catalog itself.

- take the status with `|| rc=$?`, which suspends `set -e` for the call
- state what PASS actually proves: the search list holds only the
  operator's own keychains and the default is one of them. "Every path
  resolves to an existing file" was the weaker claim the doctor stopped
  making when it learned to grade FOREIGN and HIJACKED
- widen the FAIL evidence to name STALE, FOREIGN or HIJACKED

Verified both branches: FAIL row recorded and the run exits 1 against a
fake poisoned domain; PASS on the live host.

Authored-By: claude <agents@vetcoders.io>
codescribe-corpus now owns the HTML reports. Those pages were still
a WER table an agent could narrate any way it liked.

Rust constants in core/quality/engine_contract.rs are the source of
truth (the-engine/v1). Qube HTML, Teacher HTML, and corpus schema
v3 carry them. HQ/Cloud columns are proposals. The rejected line
"whole text is mutable until session seal" is a forbidden token.

docs/THE_ENGINE_CONTRACT.md is the one prose lock. Do not re-derive
the three bars from chat.
The Claude artifact is the instrument: one take, one PCM clock,
production Silero, SealedSpan.words from the live dump, Whisper
mapped backward, word-grain vs utterance-grain, clock-lie as a
finding, letters marked as interpolation.

Take 01 („no to dobra") is the gold HTML. Contract tests pin
span 2 (41 chars / 100 ms) as the canonical clock-lie.
voice-lab already owns the Seal Atlas tab. It classifies private
HTML under the Codescribe artifacts tree: 'seal atlas' wins,
Qube WER titles fall through to quality_report.

Mirror that classifier in engine_contract so corpus HTML that
fails the handshake cannot pretend it is the atlas.
Copilot AI review requested due to automatic review settings August 19, 2026 10:01

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 46 out of 47 changed files in this pull request and generated 2 comments.

Comment thread scripts/lib/keychain-session.sh
Comment thread scripts/canaries.sh
Co-authored-by: div0-space <155201063+div0-space@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 19, 2026 10:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 46 out of 47 changed files in this pull request and generated 1 comment.

Comment thread scripts/lib/keychain-session.sh
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.

4 participants