Skip to content

feat(release): per-constituent semantic diff between agent releases - #77

Merged
gibbsie merged 2 commits into
mainfrom
feat/agent-release-diff
Aug 19, 2026
Merged

feat(release): per-constituent semantic diff between agent releases#77
gibbsie merged 2 commits into
mainfrom
feat/agent-release-diff

Conversation

@gibbsie

@gibbsie gibbsie commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Agent releases are immutable, content-addressed bundles - but when an approver signs off on a promotion today, they see the candidate's identity, not what actually changed against the release currently serving the target environment. Answering "what exactly am I approving?" means manually comparing constituents across stores. This adds a first-class semantic diff and puts it in front of the approver.

What changed

  • Pure diff module (utils/release-diff.ts): per-constituent semantic diff - agent config, prompt text (Line-level LCS diff, implemented locally, no new dependency), model id/params, tool list additions/removals, policy config field deltas, and eval-evidence delta including per-dimension score-vector movement. Enumerates every changed constituent with before/after; unchanged constituents are omitted; per-constituent output is truncated at 256KB with an explicit flag; the function never throws.
  • Exhaustiveness guard: a satisfies Record<keyof ...› coverage map makes any future bundle constituent a compile error if the diff doesn't handle it, backed by a runtime missing-key check - a newly added constituent cannot silently escape the diff while still being covered by the release's content hash.
    -*releaseDiff(releaseIdA, releaseIdB) GraphQL query: read-only, org-scoped (cross-org requests rejected), served by a dedicated Least-privilege Lambda (GetItem on two tables, nothing else).
  • Approval embedding: when a promotion approval is written, the candidate-vs-current-stable diff is embedded additively in the approval record - capped at 256KB for the whole payload with a truncated stub, and strictly best-effort: an approval can never fail because of its diff.
  • UI: no release-detail surface exists yet, so this is API-only for now (documented in the release runbook, consistent with the epic's interim pattern).

Testing

  • Property-based (fast-check): 'diff(a, a) is empty for arbitrary bundles; diffs are symmetric-inverse - diff(a, b) and diff(b, a) enumerate the same constituents with before/after swapped (this property caught a real structural asymmetry in the tools diff during development).
  • Per-constituent coverage tests including score-vector movement; oversized approval test (2,000 changed prompts pushing past the whole-payload cap - approval still succeeds and embeds the truncated stub); exhaustiveness-guard tests (missing-key rejection, superset-input tolerance); cross-org rejection.
  • tsc --noEmit clean; full backend suite green (6,548 tests); synth clean for both affected stacks.

Deployment notes

Adds one read-only Lambda with a two-table GetItem role, plus GraphQL schema additions. Light infrastructure delta; the usual pre-merge branch deploy to dev applies.

@gibbsie
gibbsie merged commit 3b0cb45 into main Aug 19, 2026
14 checks passed
@gibbsie
gibbsie deleted the feat/agent-release-diff branch August 19, 2026 09:57
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.

1 participant