Skip to content

feat(resummarize): re-run the AI pass on edited meeting/memo transcripts - #526

Merged
silverstein merged 4 commits into
silverstein:mainfrom
rymalia:feat/resummarize
Jul 25, 2026
Merged

feat(resummarize): re-run the AI pass on edited meeting/memo transcripts#526
silverstein merged 4 commits into
silverstein:mainfrom
rymalia:feat/resummarize

Conversation

@rymalia

@rymalia rymalia commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Implements #523 — re-run the AI pass on an edited meeting/memo transcript,
per the maintainer-approved plan (docs/plans/rerun-ai-pass-resummarize-2026-07-21.md,
maintainer notes M1–M5 folded in).

What this adds

  • minutes-core::resummarize::resummarize_meeting — re-runs the
    summarize stage + local derivations (action items, decisions, intents,
    entity links) against the current transcript text and splices the
    regenerated AI-owned sections back in under a strict safety contract:
    • Never destroy on failure. Engine none, provider errors, empty
      output, scaffolding-only output, and unstructured-regression output are
      hard no-write failures.
    • Concurrent-edit guard. Full-content snapshot before inference,
      re-compared before the backup copy and again immediately before the
      atomic rename.
    • Splice, don't rewrite. Only AI-owned body sections
      (## Summary## Commitments) and derived frontmatter change;
      ## Notes, ## Transcript, speaker_map, capture/consent metadata are
      preserved byte-for-byte / field-for-field. Fence-aware, fail-closed
      section parser (duplicate headings reject the write).
    • Status-preserving merge (M2). Exact normalized identity only — never
      fuzzy. User-curated state (status: done, due dates, decision
      authority/supersession) carries forward; everything ambiguous, unmatched,
      or dropped is surfaced in the preview, never silently resolved.
    • Timestamped backups. Each apply writes
      .<name>.pre-resummarize.<unix-secs>.bak (mode-preserving); the newest
      3 per artifact are kept.
  • CLI: minutes resummarize <meeting|memo|search-term> — preview by
    default (the preview does invoke the model, stated in the output per
    M3); --apply, --engine, --template, --json (errors also emit a JSON
    envelope). Serves minutes import text archives (feat(import): generic importer for existing text transcript archives #516) as their first AI
    pass.
  • Run record (M4): summarization: health block shaped like the existing
    speaker_mapping block (model, template, duration_ms, last_run).
  • Engine choke point (M1): engine resolution happens only inside
    summarize_with_template — resummarize passes config through and can never
    bypass per-meeting egress policy. Note for the in-flight privacy work:
    this adds a second caller of that choke point.
  • Scope per M5: text-only, CLI + core. Desktop button and MCP tool are
    follow-ups (plan Phases 3–4).

Review findings intentionally declined (with rationale)

Two findings from the Codex review rounds were declined rather than fixed:

  1. Assignee-only action items count as "pristine" (droppable).
    Assignee and due are extractor-derived on every fresh pass (@name:
    prefixes), so treating assignee as user-curated state would make items
    effectively undroppable. Only status != open and an explicit due date
    count as user state — and every drop is surfaced in the preview
    regardless.
  2. Unknown YAML keys are lost on frontmatter reserialize. Identical to
    the in-tree update_frontmatter precedent that
    redo-speaker-mapping already ships with; fixing it is an orthogonal
    schema-preservation project, not part of this feature.

Clarification: sensitivity: restricted artifacts

Restricted artifacts are not blanket-rejected on purpose: generated
sensitive artifacts carry capture: none, and that gate already rejects them
(their "transcript" may be a placeholder plus human-authored debrief).
A restricted artifact with a real transcript is a legitimate resummarize
target; on cloud engines the preview/apply output states that the model was
invoked, and the M1 choke point is where per-meeting egress policy will be
enforced.

Notes

  • The core fence parser tracks fence char + opener run length
    (CommonMark closing semantics) — a strict improvement over the historical
    CLI transcript extractor, which tracked the char only.
  • The tmp file's mode is enforced with set_permissions on the open handle
    (fchmod), not OpenOptions::mode alone, which is umask-masked — preserves
    0640 Team-visibility artifacts under restrictive umasks. A
    umask-manipulation test was deliberately skipped (process-global, not
    parallel-safe); a 0640 mode-preservation test is included.
  • Backup retention count (3) is cheap to change if you'd prefer another
    number.
  • Redaction caveat documented in README: transcript edits never touch the
    retained WAV — true audio redaction is minutes cleanup/retention
    territory.

Tests

1158 core unit + 8 integration + 80 CLI tests pass (--no-default-features);
workspace clippy -D warnings and cargo fmt --check clean. New coverage
includes: the fence-aware section parser (incl. fence-length and
closing-syntax cases), splice, the status-preserving merge (densest coverage,
per M2), concurrent-edit guard + backup isolation on conflict, 0640
mode preservation, scaffolding and unstructured-output rejection, timestamped
backup naming + prune-to-3 retention.

@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

@rymalia is attempting to deploy a commit to the evil genius laboratory Team on Vercel.

A member of the Team first needs to authorize it.

@rymalia

rymalia commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Note on CI: the four MCP jobs (Lockfile ×3, MCP Server) fail because crates/mcp/package.json pins minutes-sdk@0.23.0 (from fc9e4ee), which isn't published to npm yet — the same failure is currently on main itself, so it's inherited from the mid-release state rather than caused by this diff. They should turn green once minutes-sdk@0.23.0 is published (or on a re-run after that).

The two agent-docs sync failures were real (the new resummarize error variants weren't in the generated error catalog) and are fixed by the latest push, which regenerates site/public/docs/errors.md + site/app/docs/errors/data.json.

Rust build/test jobs pass locally on the merged tree: 1168 core + 8 integration + 80 CLI tests, clippy -D warnings clean.

@silverstein

Copy link
Copy Markdown
Owner

Heads up on the red checks before you spend any time on them: the MCP Lockfile / MCP Server / CI Gate failures are not yours. Main is mid-release for v0.23.0 - the release pin commit references minutes-sdk@0.23.0, which only appears on npm when the release tag publishes it, so every PR's merge ref fails npm ci in that window. Those checks will heal on a re-run once v0.23.0 is out (shortly).

On the PR itself: impressive turnaround, and the safety contract reads exactly like the plan we agreed - the declined-findings section with rationale is exactly how I like disagreements documented. As noted on #523 this lands in the release after 0.23.0, so I will do the full review right after the release ships. Two early notes meanwhile: (1) the CLAUDE.md command-count and commands.rs test-struct updates are fine to keep in scope; (2) please rebase on main once 0.23.0 is tagged so the generated site constants regenerate against the released tree - that has bitten two PRs this week.

rymalia added 2 commits July 23, 2026 15:41
…pts (silverstein#523)

Adds minutes-core::resummarize + `minutes resummarize <meeting>`: re-runs
the summarize stage and local derivations against the current transcript
and splices only the AI-owned sections back in.

- Hard no-write on engine "none", provider error, empty, scaffolding-only,
  or unstructured-regression output; concurrent-edit guard compared before
  the backup copy and again immediately before the atomic rename;
  fence-aware fail-closed section parser (CommonMark fence-length +
  closing syntax); file modes enforced via set_permissions on the open
  handle (umask-proof — preserves 0640 Team files).
- Status-preserving merge by exact normalized identity, never fuzzy; every
  conflict/keep/drop/ambiguity surfaced in the preview (M2).
- Timestamped backups (.<name>.pre-resummarize.<unix-secs>.bak), newest 3
  kept per artifact; the report carries the actual backup path.
- Engine resolution stays inside summarize_with_template (M1); the
  summarization: health block follows the speaker_mapping shape (M4);
  preview states the model was invoked (M3); v1 is text-only CLI+core (M5).
- CLI: preview by default, --apply/--engine/--template/--json (JSON error
  envelope on failures); serves `minutes import text` archives as their
  first AI pass.

1158 core + 8 integration + 80 CLI tests; clippy -D warnings clean.

@silverstein silverstein left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Full review done: approved. This is the most disciplined feature contribution this repo has received, and the safety contract is not just described - it is implemented and tested.

Verified independently (fresh worktree, own test runs, plus reading every safety-critical path):

Merge semantics (the part I flagged as hardest): correct. Exact normalized identity with uniqueness required on BOTH sides before anything matches - duplicates go to Ambiguous rather than being guessed at, user-stated items survive unmatched, conflicts keep the user's value and emit an explicit note, and every drop is surfaced. That is the wrong-is-worse-than-none doctrine implemented, not just cited.

Splice: fail-closed as specified. All AI-owned ranges resolved strictly before any mutation; duplicate headings abort; covered by tests.

Engine choke point (M1): honored. No engine resolution anywhere in resummarize - everything flows through summarize_with_template, with an injectable seam that makes the failure/concurrency/splice contract testable without a live engine. This composes correctly with the in-flight per-meeting egress policy work.

Write safety: better than the plan asked for. Unique tmp names, mode-correct from the first byte, post-write frontmatter validation, the concurrent-edit guard compared twice (before backup and again before rename), failed runs cleaning up their own backups, newest-3 retention. The residual compare-to-rename window is inherent without file locking and acceptable for a user-edited file.

Both declined findings: agreed with your rationale. Assignee/due are extractor-derived each pass, so treating them as user state would make items undroppable; and the unknown-YAML-keys limitation matches the existing update_frontmatter precedent - an orthogonal project, correctly kept out of scope.

My runs: 34/34 resummarize + 81/81 CLI green, scoped clippy -D warnings clean, fmt clean. Your branch CI already covered the full three-platform matrix; the only reds were our release-window npm ci failures, now healed since v0.23.0 published.

One mechanical step before merge: rebase onto current main (v0.23.0 shipped, so the site constants need regenerating against the released tree - node scripts/generate_llms_txt.mjs && node scripts/sync_site_release_version.mjs, commit site/) and push. Green CI after that and this merges as the headline of the next release.

silverstein and others added 2 commits July 25, 2026 00:00
Merged main (v0.23.0 release) into the resummarize branch and regenerated
llms.txt, error catalog, and MCP tool docs so counts reflect the released
tree (58 commands, 1660 tests). No resummarize logic touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@silverstein

Copy link
Copy Markdown
Owner

I pushed a mechanical update to your branch (maintainer edit) to unblock the two red checks — no resummarize logic touched:

  1. Merged current main into the branch. Your PR predated the v0.23.0 release, and the release moved the generated version constants (site/lib/release.ts, llms.txt, error + MCP catalogs). Merge was clean — no conflicts with your code. I regenerated those docs so counts reflect the released tree (58 commands, 1660 tests including your 34 new resummarize tests). Regen is idempotent.
  2. That also re-rolls the one macOS failure, which was not your code: it was the pre-existing flaky copilot::relay reconnect test (broken pipe), tracked in Flaky test: copilot::relay repeated_reconnects_replay_each_cursor_advance fails with broken pipe on macOS CI #529. 1,167 other tests passed.

Once CI is green on the new head I'll squash-merge. This lands as the headline of the next release. Thanks again for an exceptionally clean feature.

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