Repository navigation
M10+M11 (engine): organization compatibility campaigns and continuous upstream watchers - #68
Merged
Merged
Conversation
… compatibility graph Adds the campaign vocabulary (repo/campaign states, freshness, org classes), the two pure state-derivation functions, the derived (never stored) org graph and the bounded explicit-identity internal contract model. Includes the Phase 0 audit/implementation map.
… gate Uncertainty is never rounded to safe: stale, unknown, access-lost and version-level-only repositories are UNKNOWN and keep the organization unsafe. The pure publication gate (watch mode / verification requirement / publication mode) lives here so its semantics are inspectable in the public engine.
…R support Composes the existing M6->M9 functions per repository with structural isolation (a failure is that repository's FAILED record, never another's), independent per-repo publication under workspace policy, idempotent re-runs, and reconciliation to RESOLVED only through fresh re-evaluation. Adds Alembic 0038, the CampaignStore, the machine-readable dossier, and a backward-compatible draft flag through the PR publisher/client/fake. Acme + internal-contract fixtures and the end-to-end suite (real sandbox verification, fake GitHub).
…egistry, URL safety Public-engine half of continuous watching: normalized snapshots, an opaque JSON cursor, deterministic version/contract comparison with first-observation baselines and duplicate suppression, adapters for PyPI, npm, GitHub Releases, OpenAPI URLs and structured changelog feeds (no scraping), a manual-snapshot path, a SSRF-safe fetcher, typed errors with pure backoff, and the watch registry that de-duplicates fetches across workspaces. Hosted scheduling is deliberately not here.
…he end-to-end demo process_change_for_workspace applies the launch gate (structural proof by default), loads the previous campaign, runs the per-repo M6->M9 flow, and writes the campaign, the M6 event and the M7/M8 audit trail in one transaction. Adds label-validated watcher/campaign/PR metrics, the 'patchfrog campaigns analyze|demo' commands, and the deterministic four-repo demo (baseline -> change -> one campaign -> one PR -> no duplicates -> RESOLVED). Fixes a latent crash: an SDK surface restored from a stored snapshot now rebuilds its SdkSurface so it can be the old side of a diff.
The disposable GitHub App private key lived in the job-level env block, which GitHub prints (resolved) in every step header. The key and the webhook secret are now generated at run time, written to a file / $GITHUB_ENV, masked, and the container check mounts the key file instead of passing its content. The new workflow-hygiene test fails on the previous configuration and passes on this one. This stops intentional plain-text display going forward; it does not erase anything already present in historical logs.
…try-consulted evidence Hosted pipelines detect a change in one process and evaluate it per workspace in others: add a lossless ExternalChangeEvent JSON round trip. Add a repository-scoped registry read (the existing one is intentionally global and unsafe for multi-tenant callers; an empty scope never means 'all'). Let a repository input say 'the registry was consulted' so a fresh discovery that found nothing matching is NOT_AFFECTED without a checkout, while no evidence at all stays UNKNOWN.
…resh evaluation approved_repositories is threaded through run_campaign/process_change_for_workspace. Approval never lowers the bar: the evaluation is recomputed from scratch, a partially verified migration is still a draft, and an approval for a repository whose migration is not eligible changes nothing.
…er classified from weaker evidence Found while building the hosted runner: a failed checkout fell back to registry evidence, which for an SDK without a built-in discovery adapter (package declaration only, no call sites) reads as 'not affected'. RepositoryInput now carries evidence_error; the evaluation marks such a repository FAILED, with credentials scrubbed by the engine itself.
…e for beta), boundary, CI hygiene
… unique identity)
…ry, so it needs the sandbox (found by CI, where bwrap is unavailable)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M10 + M11 (engine side): organization compatibility campaigns and continuous upstream watchers
Public-engine half of the final milestone block. The hosted half (scheduling, credentials, dashboard) is a separate PR in the private
patchfrog-cloudrepository, which pins this branch's head.Not merged automatically. Please review before merge.
What this adds
patchfrog/campaigns/): one upstream change across a workspace's repositories as one idempotentCompatibilityCampaign; derived (never stored) organization graph; org blast radius that never rounds uncertainty to "safe"; deterministic repository/campaign states; freshness (FRESH/STALE/UNKNOWN/ACCESS_LOST); per-repository isolation; bounded explicit-identity internal contracts; dossier (JSON + markdown); Alembic0038;patchfrog campaigns analyze|demo.patchfrog/watchers/): source adapters (PyPI, npm, GitHub Releases, OpenAPI URL, structured changelog feeds, manual), snapshot comparison with an opaque cursor, baseline-on-first-observation, duplicate suppression, watch-registry aggregation, the campaign launch gate (structural proof by default), an SSRF-safe fetcher with typed errors and pure backoff.process_change_for_workspace(gate -> campaign -> M6->M9 per repo -> audit trail -> persist, one transaction), human-approval support, label-validated metrics, lossless event serialization, tenant-scoped registry read, draft-PR support,GitHubClient.get_default_branch.env:block that GitHub prints; a regression test fails on the old workflow.Boundary
Everything that determines how compatibility is understood, analyzed, planned, verified or decided is here. Nothing hosted (schedules, cursors storage, credentials, accounts, dashboard) is.
docs/product-boundary.mdhas the table.Honest findings made while building (all fixed, all tested)
FAILED(evidence_error).SdkSurfaceand crashed the diff.IntegrityErrorat flush, not only commit (Cloud side).PARTIALLY_VERIFIED/UNVERIFIEDprecedence and M9no_op_unchanged(human-closed PR) are now treated as a human decision, not "in flight".Verification
mypy . --strictclean; Alembic single head0038; fresh upgrade + downgrade/upgrade round trip on real PostgreSQL 16.PATCHFROG_REQUIRE_POSTGRES=1: see the validation summary (validation/m10_m11/latest-summary.md) for the final numbers.VerificationOutcomeprecedence, M9 PR identity, stale-base protection unchanged.Limits (unchanged by this PR)
Verification needs a working
bwrapsandbox (the stock Docker profile reports it unavailable -> nothing can beVERIFIEDthere); JS/TS usage is lexical; remote OpenAPI$refnot resolved; a bare version bump opens no campaign by default. Seedocs/campaigns.md,docs/watchers.md.Security wording
Tracked files and the PR diff contain no detected secret material. This does not prove that secret material was never exposed locally or historically in logs. The new CI configuration no longer intentionally exposes key material; earlier logs are not retroactively cleaned.
🤖 Generated with Claude Code