Skip to content

Catch up with upstream Polly (v8.8.0, 34 commits ahead of our fork point) #28

Description

@iancooper

Summary

Fences forked from App-vNext/Polly at commit 47e3b41 (~Polly 8.7.x). Upstream is still
BSD-3-Clause and fork-migration-plan.md §5 (risk R2) already commits us to tracking it —
"Keep a read-only upstream remote and a polly-upstream tracking branch. Cherry-picks will
need path/namespace fixups — that is the accepted cost of D1." That remote/branch was never
actually created, and upstream has moved on: Polly 8.8.0 shipped 2026-09-14, and
App-vNext/Polly's main is now 34 commits ahead of our fork point, 0 behind.

While Polly's licence keeps letting us pull these changes (we only have to re-brand them), we
should be doing this on a cadence, with a repeatable process, rather than discovering the drift
ad hoc and re-deriving the triage from scratch each time, as this issue just had to.

What's behind

Checked via gh api repos/App-vNext/Polly/compare/47e3b41...main (2026-09-20):

Category Count Notes
Dependency bumps (Dependabot) ~30 dotnet, xunit, github-codeql-action, SonarAnalyzer.CSharp, MinVer, Cake.Sdk, zizmor-action, codecov-action, meziantou.framework.nugetpackagevalidation.tool, Refit.HttpClientFactory, azure/login, anchore/sbom-action — we track most of these independently via our own Dependabot config, so likely skip, not port
Behavioural fix 1 482bdf82 — "Return null from FaultGenerator when no fault is generated" (#3220) — worth porting
Test infra 1 1a80392b — "Update to xunit v3" (#3131) — evaluate; Fences already diverges from Polly's test conventions (NSubstitute vs FakeItEasy, test/ vs tests/), so this may not transplant cleanly
Platform prep 1 f35bc00d — ".NET 11 preparation" (#3225) — evaluate against our own global.json/TFM support
Housekeeping 1 e381630d — "Update CHANGELOG" (the 8.8.0 entry) — useful as a summary of what upstream considers user-visible in this range

8 of the 34 commits landed after the 8.8.0 tag itself (9ad5ae9b) and are unreleased
dependency bumps on upstream main.

This isn't a simple git pull

Phase 2 of the migration renamed the namespace, assembly names, package IDs, the strong-name key
(Fences.snk vs Polly.snk), and the one Polly-named public type
(PollyServiceCollectionExtensions → FencesServiceCollectionExtensions). A straight cherry-pick
will conflict on nearly every file it touches. That's the accepted cost recorded in R2 — this
issue is about doing that porting work, not avoiding it.

Proposed approach for this catch-up

  1. License gate, before anything else — see Reusable process below. Confirm upstream's
    LICENSE is still what we based the fork on before doing any diff/triage/port work.
  2. Add the read-only upstream remote (https://github.com/App-vNext/Polly.git) and a
    polly-upstream tracking branch pinned at 47e3b41, per the R2 mitigation that was planned
    but never executed.
  3. Triage the 34 commits into: skip (routine dependency bumps we already track ourselves),
    port (behavioural fixes — at minimum #3220), and decide-case-by-case (xunit v3, .NET 11 prep).
  4. Port what's kept, with the namespace/path fixups the rename requires. Reference the upstream
    SHA in each commit message for traceability.
  5. Add a CHANGELOG.md entry in Fences' own voice for anything ported — the file itself is never
    rewritten (per CLAUDE.md), only appended to.
  6. Move polly-upstream to the SHA just triaged, so the next catch-up's diff starts there
    instead of back at 47e3b41.

Reusable process

The point of formalising this is to make the next catch-up cheap — most of the cost above was
spent re-deriving "what changed and does it matter", which a repeatable process should do for us.

Step 0 — Licence gate (blocking, runs first, every time). Fetch upstream's current LICENSE
at the tip of main and diff it against our recorded baseline (today: BSD-3-Clause, matching our
own LICENSE, copied at the fork). If it has changed at all, stop — do not run the diff or
triage steps.
A licence change is a "should we still be pulling from this repo" decision, not
something to fold into routine triage; it needs explicit maintainer/legal review before any more
upstream code enters Fences. Note this is distinct from the OSMF: OSMF governs App vNext's own
binary distribution and doesn't touch the source licence (see README.md, the "OSMF" section)
— it's the LICENSE file text itself we're gating on, not App vNext's pricing policy for their
own packages.

Step 1 — Cheap diff. Compare polly-upstream (pinned at the last-synced SHA, not the original
fork point) against upstream main/latest tag, so each run only surfaces what's new since last
time.

Step 2 — Auto-triage. Bucket commits automatically where possible: commit messages matching
Dependabot's Bump <dep> from <x> to <y> pattern → default to the skip bucket, since we already
track our own dependencies independently; everything else → needs-human-triage.

Step 3 — Report into one recurring issue, not a fresh write-up. Update a single ongoing
tracking issue with: the licence-gate result, the new commits since last sync, and the
auto-triage buckets, rather than reconstructing the analysis each time.

Step 4 — Port (human). Apply the kept commits with the rename fixups, upstream SHA references,
and a CHANGELOG entry, per steps 3–4 above.

Step 5 — Advance the pointer. Move polly-upstream forward to what was just triaged.

Where it lives. .agent_instructions/upstream_sync.md should capture steps 0–5 as the durable
runbook — per CLAUDE.md's "Context Management" guidance, this belongs in a project-owned file,
not memory. Whether steps 0–2 are worth automating as a scheduled workflow (vs. a manual runbook
someone runs monthly) is an implementation choice for whoever picks this up; either way the
licence gate must run before the other steps, automated or not. Given the licence gate is a
standing legal-risk control rather than a workflow preference, it's also worth a short ADR (R2
says "record this in ADR 0002", but the merged docs/adr/0002-fork-polly-as-fences.md only covers
the decision to fork, not sync mechanics — this would be a new one).

Acceptance

  • upstream remote + polly-upstream tracking branch exist and are documented.
  • The 34 outstanding commits are triaged, each recorded as ported or deliberately skipped.
  • The licence gate (step 0) is documented and demonstrably runs before any diff/triage/port work,
    for this catch-up and the next one.
  • The reusable process (steps 0–5) is recorded in .agent_instructions/upstream_sync.md and/or an
    ADR, so the next catch-up doesn't re-derive it from scratch.

Activity

  1. iancooper commented on Sep 20, 2026

    @iancooper
    MemberAuthor

    Reusable process is now drafted:

    Not yet committed — working-tree changes only, pending review.

  2. iancooper commented on Sep 20, 2026

    @iancooper
    MemberAuthor

    Correction: the "34 commits behind" figure above was computed against 47e3b41, the ADR 0002 fork commit. A hand-sync already ran on 2026-08-24, before ADR 0003/the runbook existed, carrying the repo to upstream 173d6d1d (five Dependabot-only commits, already on main via the rename branch). PR #32 corrects the runbook's bootstrap SHA to 173d6d1d accordingly.

    Not a correctness bug — those five would have landed in the auto-skip bucket regardless (ADR 0003, D5) — but the real backlog is five commits smaller than stated above. Rerun Step 1 from the corrected bootstrap once #32 is merged rather than trusting the number in this issue as written.

  3. iancooper commented on Sep 25, 2026

    @iancooper
    MemberAuthor

    Sync #1 — 2026-09-25 (runbook Steps 0–3)

    Step 0 — licence gate: PASS (checked 2026-09-25)

    Upstream main's LICENSE is byte-identical to the one at the fork commit 47e3b412 (BSD-3-Clause, 1501 bytes, empty diff).

    Step 1 — diff

    polly-upstream at 173d6d1d (the corrected bootstrap, #32) → upstream/main at 9a81fdc7: 29 ahead, 0 behind. That replaces the "34" in the issue body: 34 counted from 47e3b41, minus the five commits already hand-synced.

    Step 2 — triage

    Port (4)

    Upstream What Notes
    482bdf82 Return null from FaultGenerator when no fault is generated (#3220) Behavioural fix, 1 line in src plus a test
    9ad5ae9b Fix flaky test (#3231) PooledCancellationTokenSourcePool changes from private to internal nested class. No public API change
    f35bc00d .NET 11 preparation (#3225) Adds DeterministicTimestamp and CheckSdkVulnerabilities, plus smoke specs
    1a80392b Update to xunit v3 (#3131) Tracked separately as #34. Too large for a one-commit port (33 files, replaces coverlet, changes dependencies and src), but must be done to stay aligned with upstream. Affects #14, and I've commented there

    Skip, with reason (2)

    Upstream What Reason
    2247db24 Update .NET SDK to 10.0.401 (#3222) Dependabot SDK bump in global.json. Fences tracks its own
    e381630d Update CHANGELOG for v8.8.0 (#3232) Upstream's CHANGELOG entry, plus sample references to Polly.* 8.8.0. Fences never rewrites Polly's CHANGELOG history, and its entries for ported changes are written in its own voice (runbook Step 4.5)

    Skip: Dependabot (23)

    17 match the runbook's ^Bump .+ from .+ to .+:
    16514e3d e1b7365e df539592 0340c804 654715db f19381ee a057350b 82f31237 e6582c39 0c29408d 5f9fa589 9d289ab1 3c7e2758 a1e026e9 0442ab6f 681d9ad5 9a81fdc7

    6 are Dependabot group bumps ("Bump the … group with N updates"). ADR 0003 D5's pattern doesn't match that wording, so they were reviewed by a person and are skip-with-reason: each is dependency versions only, and Fences tracks its own:
    cc882a82 f78e6c60 791fbaf0 a761a8f5 a0df1704 3a466d61

    Runbook defects found on this first run

    1. Step 0's curl can't run under the project's own .claude/settings.json (Bash(curl:*) is denied). Use gh api 'repos/App-vNext/Polly/contents/LICENSE?ref=main' --jq .content | base64 -d.
    2. Step 1's gh api …/compare/<sha>...upstream/main returns 404, because upstream/main is a local ref. GitHub needs main.
    3. Step 2's Dependabot pattern misses group bumps. The runbook now says so; widening the automatic pattern itself would amend ADR 0003 D5, so it's left for a separate decision.
    4. Adding a remote named upstream makes gh default to App-vNext/Polly for gh issue, gh pr and the rest. Without gh repo set-default BrighterCommand/Fences, later steps (including this Step 3 report) would target Polly's repo.

    Fixed in #35.

    Next

  4. iancooper commented on Sep 27, 2026

    @iancooper
    MemberAuthor

    Step 4 progress, sync #1:

    Decision for this sync: ports don't hand-edit CHANGELOG.md. It's generated from PR titles at release time, so each port PR's title is its changelog entry.

  5. iancooper commented on Sep 28, 2026

    @iancooper
    MemberAuthor

    Sync #1 is complete (Step 5).

    Looking ahead: upstream already has 7 commits past 9a81fdc7, and all of them are Dependabot bumps.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions