diff --git a/.github/workflows/release-successor-candidate.yml b/.github/workflows/release-successor-candidate.yml
index ed5d6b3b4..4e21cb929 100644
--- a/.github/workflows/release-successor-candidate.yml
+++ b/.github/workflows/release-successor-candidate.yml
@@ -1,6 +1,6 @@
name: release-successor-candidate
-# Source/byte qualification for coherent set 0.102.0 only. This route has no tag, release,
+# Source/byte qualification for coherent set 0.103.0 only. This route has no tag, release,
# journal, package-feed, OIDC or promotion write. Its retained Actions artifact
# is an unpromoted candidate, not a published release or an admission receipt.
on:
@@ -43,7 +43,7 @@ jobs:
test "$(git rev-parse HEAD)" = "$SOURCE_SHA"
test "$(git ls-remote origin refs/heads/main | cut -f1)" = "$SOURCE_SHA"
version="$(dotnet msbuild src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj -getProperty:Version | tr -d '[:space:]')"
- test "$version" = 0.102.0
+ test "$version" = 0.103.0
echo "version=$version" >> "$GITHUB_OUTPUT"
- name: Verify the stable predecessor and unused package version
env:
@@ -53,24 +53,24 @@ jobs:
run: |
set -euo pipefail
mkdir -p artifacts/predecessor artifacts/packages
- gh release download coherent-set/v0.101.0 --repo "$GITHUB_REPOSITORY" \
+ gh release download coherent-set/v0.102.0 --repo "$GITHUB_REPOSITORY" \
--pattern stable-channel.json --dir artifacts/predecessor
python3 scripts/release-saga.py predecessor \
--channel artifacts/predecessor/stable-channel.json \
- --release-tag coherent-set/v0.101.0 \
- --tag-source 79051e56b025dadfc6fcaabd58b79e33f2854928 \
+ --release-tag coherent-set/v0.102.0 \
+ --tag-source 6e9be17bacd288ece103b67ecd5842d37a9c8e50 \
> artifacts/predecessor/identity.json
- test "$(jq -r .version artifacts/predecessor/identity.json)" = 0.101.0
+ test "$(jq -r .version artifacts/predecessor/identity.json)" = 0.102.0
python3 scripts/check-release-candidate-uniqueness.py \
- --version "$VERSION" --predecessor 0.101.0
+ --version "$VERSION" --predecessor 0.102.0
release_status="$(curl --silent --show-error --location -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer $GH_TOKEN" \
-H 'Accept: application/vnd.github+json' \
- "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/tags/coherent-set/v0.102.0")"
+ "https://api.github.com/repos/$GITHUB_REPOSITORY/releases/tags/coherent-set/v0.103.0")"
test "$release_status" = 404
test -z "$(git ls-remote --tags origin \
- 'refs/tags/coherent-set/v0.102.0' 'refs/tags/kit/v0.102.0' \
- 'refs/tags/drivers/v0.102.0' 'refs/tags/coord-engine/v0.102.0')"
+ 'refs/tags/coherent-set/v0.103.0' 'refs/tags/kit/v0.103.0' \
+ 'refs/tags/drivers/v0.103.0' 'refs/tags/coord-engine/v0.103.0')"
- name: Test the telemetry producer and prepare the browser fixture
run: |
set -euo pipefail
@@ -167,7 +167,7 @@ jobs:
set -euo pipefail
test "$(git ls-remote origin refs/heads/main | cut -f1)" = "$SOURCE_SHA"
python3 scripts/check-release-candidate-uniqueness.py \
- --version "$VERSION" --predecessor 0.101.0
+ --version "$VERSION" --predecessor 0.102.0
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: release-successor-candidate-${{ github.sha }}-${{ github.run_id }}
diff --git a/.github/workflows/release-successor-publish.yml b/.github/workflows/release-successor-publish.yml
index 5f073d1a0..47d8384eb 100644
--- a/.github/workflows/release-successor-publish.yml
+++ b/.github/workflows/release-successor-publish.yml
@@ -1,6 +1,6 @@
name: release-successor-publish
-# Single-operator, exact-candidate publication for 0.102.0; fixed journal19 recovery
+# Single-operator, exact-candidate publication for 0.103.0; fixed journal19 recovery
# remains bound to the original 0.101.0 candidate. This is distinct
# from the five GS2-08.9 sealed workflows and cannot select a historical ref.
on:
diff --git a/Directory.Build.props b/Directory.Build.props
index bd9f92df2..c554a16db 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -609,7 +609,7 @@
telemetry CI legacy-default selection repair. Publication and installed
consumer adoption remain separate from this source version. -->
- 0.102.0
+ 0.103.0
diff --git a/docs/roadmaps/utel-release-successor.md b/docs/roadmaps/utel-release-successor.md
index 46bf68ed2..cd75ab02f 100644
--- a/docs/roadmaps/utel-release-successor.md
+++ b/docs/roadmaps/utel-release-successor.md
@@ -977,3 +977,27 @@ continuation contract must bind the exact admitted candidate and base, retained
resource progress, complete inventory and final stability checks within explicit
request and time bounds. No larger cap, new cursor or provider replay follows
from this diagnosis.
+
+
+### C3 receiver-first coherent successor source — 2026-10-12
+
+Source selects coherent **0.103.0** and fresh logical `utel-rel-21`, with published
+0.102.0 as predecessor. The source includes PR #4446's authenticated CI suite graph,
+durable pending recovery and aggregate bounded provider continuation. Candidate and
+publisher identities are selected only after exact source qualification and fresh
+both-feed, tag, release and journal collision checks; this source selection creates
+no release effect. The existing candidate/preflight/publisher rail remains in force.
+
+The explicit original-successor recovery profile remains pinned to the unchanged
+0.102.0 candidate and consumed `utel-rel-20`; advancing ordinary source cannot redirect
+that recovery into `utel-rel-21`. Original 0.101.0 profiles, consumed journals, archived
+package bytes and the five sealed historical workflows remain unchanged.
+
+Publish and verify the coherent CLI/Kit/Drivers bytes before receiver adoption.
+Install the capable local CLI receiver before enabling the new producer route; an
+independent Host successor is unnecessary for that selected destination. Verify the
+installed suite contract and exact payload, schema-14 migration journal and historical
+rows, then qualify packaged receiver composition and the genuinely admitted native
+more-than-40-request provider journey. These publication, installation and native
+acceptance outcomes remain pending; version-only output and source tests do not
+qualify them. Whole UTEL remains open.
diff --git a/scripts/release-successor-publish.py b/scripts/release-successor-publish.py
index 74a639625..e07b83bf4 100644
--- a/scripts/release-successor-publish.py
+++ b/scripts/release-successor-publish.py
@@ -24,13 +24,18 @@
from release_successor_provider import GitHubAPI, LiveProvider, NotFound
REPOSITORY = "FS-GG/.github"
-SUCCESSOR_VERSION = "0.102.0"
-SUCCESSOR_PREDECESSOR = "0.101.0"
-SUCCESSOR_REF = "refs/heads/fsgg/v2/journal/release/utel-rel-20"
+SUCCESSOR_VERSION = "0.103.0"
+SUCCESSOR_PREDECESSOR = "0.102.0"
+SUCCESSOR_REF = "refs/heads/fsgg/v2/journal/release/utel-rel-21"
+ORIGINAL_SUCCESSOR_VERSION = "0.102.0"
+ORIGINAL_SUCCESSOR_PREDECESSOR = "0.101.0"
+ORIGINAL_SUCCESSOR_REF = "refs/heads/fsgg/v2/journal/release/utel-rel-20"
def selected_release_binding(args):
"""New ordinary source cut; explicit historical profiles keep original bindings."""
+ if getattr(args, "recover_original_successor_checkpoint", False):
+ return (ORIGINAL_SUCCESSOR_VERSION, ORIGINAL_SUCCESSOR_PREDECESSOR, ORIGINAL_SUCCESSOR_REF)
historical = any(getattr(args, flag, False) for flag in
("recovery_checkpoint", "repeat_original_nuget_kit_intent", "recover_original_runtime_intent"))
return ("0.101.0", "0.100.0", REF) if historical else (SUCCESSOR_VERSION, SUCCESSOR_PREDECESSOR, SUCCESSOR_REF)
@@ -439,8 +444,8 @@ def run_recovery_checkpoint(manifest, journal, admission, provider, report, dead
def validate_successor_checkpoint(manifest, journal, expected):
- require(journal.ref == SUCCESSOR_REF and journal.main_directory
- and manifest["descriptor"]["version"] == SUCCESSOR_VERSION
+ require(journal.ref == ORIGINAL_SUCCESSOR_REF and journal.main_directory
+ and manifest["descriptor"]["version"] == ORIGINAL_SUCCESSOR_VERSION
and manifest["descriptor"]["sourceSha"] == SUCCESSOR_CHECKPOINT_CANDIDATE["sourceSha"]
and manifest["contentId"] == SUCCESSOR_CHECKPOINT_CANDIDATE["contentId"],
"original successor checkpoint binding differs")
diff --git a/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj b/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj
index 0368bba07..7bc96adfc 100644
--- a/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj
+++ b/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj
@@ -130,16 +130,15 @@ bytes under 0.52.0 would make the same version identify different artifacts. Ado
coherent set cut from corrected source. All three partial sets are recorded in
`registry/dependencies.yml`.
- 0.102.0 — SDK-installed telemetry engine identity pairing.
-
-The telemetry adapter recognizes the configured engine when it resolves to the running
-SDK-installed executable and independently binds its actual entry assembly. Other
-executables retain the adjacent-assembly route. Exact executable and assembly hashes,
-movement checks and typed rejection proofs remain required; a byte-identical foreign
-executable does not inherit the running engine's identity.
-No Store schema, protocol or pending-input rewrite is introduced. Published0.101
-archives remain immutable. Source qualification alone establishes no successor package
-publication, installed adoption or original operational recovery.
+ 0.103.0 — Authenticated bounded CI continuation and receiver suite graphs.
+
+The telemetry receiver proves exact executable and entry-assembly identity before
+accepting bounded provider continuation. Authenticated suite graphs retain exact
+applied-fact references and reject foreign, moved or mismatched receiver identities.
+This coherent source candidate advances the ordinary release rail while keeping
+original0.102 operational recovery pinned to its immutable candidate and journal.
+No Store schema, protocol or pending-input rewrite is introduced. Source qualification
+alone establishes no package publication, installed adoption or operational recovery.
$(FsggStandingAdvisories)
diff --git a/tests/release-successor-candidate/run.py b/tests/release-successor-candidate/run.py
index 9056ca22a..1ea41f610 100644
--- a/tests/release-successor-candidate/run.py
+++ b/tests/release-successor-candidate/run.py
@@ -142,13 +142,13 @@ def test_missing_token_and_nonforward_version_refuse_before_feed_reads(self) ->
class SuccessorRailBindingTests(unittest.TestCase):
def test_candidate_binds_the_next_version_and_exact_predecessor(self) -> None:
workflow = (ROOT / ".github/workflows/release-successor-candidate.yml").read_text()
- self.assertIn('test "$version" = 0.102.0', workflow)
- self.assertIn("gh release download coherent-set/v0.101.0", workflow)
- self.assertIn("--tag-source 79051e56b025dadfc6fcaabd58b79e33f2854928", workflow)
- self.assertEqual(workflow.count("--predecessor 0.101.0"), 2)
- self.assertIn("--release-tag coherent-set/v0.101.0", workflow)
+ self.assertIn('test "$version" = 0.103.0', workflow)
+ self.assertIn("gh release download coherent-set/v0.102.0", workflow)
+ self.assertIn("--tag-source 6e9be17bacd288ece103b67ecd5842d37a9c8e50", workflow)
+ self.assertEqual(workflow.count("--predecessor 0.102.0"), 2)
+ self.assertIn("--release-tag coherent-set/v0.102.0", workflow)
for namespace in ("coherent-set", "kit", "drivers", "coord-engine"):
- self.assertIn(f"refs/tags/{namespace}/v0.102.0", workflow)
+ self.assertIn(f"refs/tags/{namespace}/v0.103.0", workflow)
for project in ("FS.GG.Coord.Cli", "FS.GG.Kit", "FS.GG.Drivers"):
self.assertEqual(workflow.count(f"dotnet pack src/{project}/"), 1)
self.assertIn("--policy-version release-successor/1", workflow)
@@ -177,9 +177,9 @@ def test_packed_causal_qualifier_preserves_candidate_retention_and_requires_reop
def test_publisher_and_journal_bind_one_unused_successor(self) -> None:
publisher = (ROOT / "scripts/release-successor-publish.py").read_text()
journal = (ROOT / "scripts/release_successor_journal.py").read_text()
- self.assertIn('SUCCESSOR_VERSION = "0.102.0"', publisher)
- self.assertIn('SUCCESSOR_PREDECESSOR = "0.101.0"', publisher)
- self.assertIn('SUCCESSOR_REF = "refs/heads/fsgg/v2/journal/release/utel-rel-20"', publisher)
+ self.assertIn('SUCCESSOR_VERSION = "0.103.0"', publisher)
+ self.assertIn('SUCCESSOR_PREDECESSOR = "0.102.0"', publisher)
+ self.assertIn('SUCCESSOR_REF = "refs/heads/fsgg/v2/journal/release/utel-rel-21"', publisher)
self.assertIn('manifest["descriptor"]["version"] == version', publisher)
self.assertIn('"--version", version, "--predecessor", predecessor', publisher)
self.assertIn('coherent-set/v{manifest', publisher)
diff --git a/tests/release-successor-live/run.py b/tests/release-successor-live/run.py
index d8cc166dc..833ad18cd 100644
--- a/tests/release-successor-live/run.py
+++ b/tests/release-successor-live/run.py
@@ -281,9 +281,9 @@ def test_fresh_successor_uses_canonical_version_tag_and_selected_journal(self):
self.admission = publisher.ProtectedPublisherAdmission(base, self.ledger, publisher.SUCCESSOR_REF)
self.assertFalse(self.prepare())
self.assertEqual(self.journal.initializations, 1)
- self.assertEqual(self.journal.intent["version"], "0.102.0")
- self.assertIn("repos/FS-GG/.github/git/ref/tags/coherent-set/v0.102.0", self.source.reads)
- self.assertNotIn("repos/FS-GG/.github/git/ref/tags/coherent-set/v0.101.0", self.source.reads)
+ self.assertEqual(self.journal.intent["version"], "0.103.0")
+ self.assertIn("repos/FS-GG/.github/git/ref/tags/coherent-set/v0.103.0", self.source.reads)
+ self.assertNotIn("repos/FS-GG/.github/git/ref/tags/coherent-set/v0.102.0", self.source.reads)
self.assertIn(f"repos/{AUTHORITY}/git/ref/{publisher.SUCCESSOR_REF.removeprefix('refs/')}", self.ledger.reads)
self.assertEqual(self.journal.state.content_id, self.manifest["contentId"])
self.assertEqual(self.provider.calls, [])
diff --git a/tests/release-successor-recovery/run.py b/tests/release-successor-recovery/run.py
index c25c67530..601b80ec4 100644
--- a/tests/release-successor-recovery/run.py
+++ b/tests/release-successor-recovery/run.py
@@ -1603,11 +1603,18 @@ def test_primary_upload_uncertainty_survives_report_failure(self):
class SelectedReleaseBindingTests(unittest.TestCase):
- def test_new_ordinary_cut_has_102_101_and_distinct20(self):
+ def test_new_ordinary_cut_has_103_102_and_distinct21(self):
args = types.SimpleNamespace(recovery_checkpoint=False, repeat_original_nuget_kit_intent=False,
recover_original_runtime_intent=False)
+ self.assertEqual(publisher.selected_release_binding(args),
+ ("0.103.0", "0.102.0", "refs/heads/fsgg/v2/journal/release/utel-rel-21"))
+
+ def test_original_102_checkpoint_retains_consumed20_after_ordinary_cut_moves(self):
+ args = types.SimpleNamespace(recover_original_successor_checkpoint=True)
self.assertEqual(publisher.selected_release_binding(args),
("0.102.0", "0.101.0", "refs/heads/fsgg/v2/journal/release/utel-rel-20"))
+ self.assertNotEqual(publisher.ORIGINAL_SUCCESSOR_REF, publisher.SUCCESSOR_REF)
+ self.assertNotEqual(publisher.ORIGINAL_SUCCESSOR_VERSION, publisher.SUCCESSOR_VERSION)
def test_every_explicit_original_profile_retains_101_100_and19(self):
for selected in ("recovery_checkpoint", "repeat_original_nuget_kit_intent", "recover_original_runtime_intent"):
@@ -1623,17 +1630,17 @@ class PublicationReliabilityControls(unittest.TestCase):
def context(self, generation=21, ordinary=False):
candidate = json.loads((pathlib.Path(__file__).parent / "original-0102-manifest.json").read_bytes())
candidate, authority, intent, _ = fixture(generation, candidate,
- publisher.SUCCESSOR_CHECKPOINT_CANDIDATE["archiveSha256"], publisher.SUCCESSOR_REF)
+ publisher.SUCCESSOR_CHECKPOINT_CANDIDATE["archiveSha256"], publisher.ORIGINAL_SUCCESSOR_REF)
counter = publisher.CountedAuthorityAPI(authority,
ceiling=publisher.ORDINARY_AUTHORITY_CALL_CEILING,
quota_floor=publisher.ORDINARY_AUTHORITY_QUOTA_FLOOR)
counter.admit_quota(now=1900000000)
rows = report()
- journal = publisher.ReportingJournal(ProtectedReleaseJournal(counter, ref=publisher.SUCCESSOR_REF, main_directory=True), rows, detailed=True)
+ journal = publisher.ReportingJournal(ProtectedReleaseJournal(counter, ref=publisher.ORIGINAL_SUCCESSOR_REF, main_directory=True), rows, detailed=True)
api = MemoryPublisher();api.head = candidate["descriptor"]["sourceSha"]
provider = MemoryProvider(ordered_effects(candidate), {})
admission = publisher.ProtectedPublisherAdmission(
- SingleOperatorAdmission(api, candidate, api.head, 1, "EHotwagner", "refs/heads/main"), counter, publisher.SUCCESSOR_REF)
+ SingleOperatorAdmission(api, candidate, api.head, 1, "EHotwagner", "refs/heads/main"), counter, publisher.ORIGINAL_SUCCESSOR_REF)
publisher.prepare_release_journal(journal, counter, admission, provider, api, candidate, intent,
api.head, api.head, False, lambda: None, recovery_checkpoint=not ordinary)
journal.capture()
@@ -1673,10 +1680,12 @@ def test_exact_expected_checkpoint_changes_refuse_before_provider_write(self):
self.assertEqual(n.attempted["patch"],0)
def test_original_candidate_and_journal_mismatch_refuse(self):
- for target in ("content", "ref"):
+ for target in ("content", "ref", "ordinary-ref", "ordinary-version"):
c,a,n,r,j,ad,p,e=self.context()
if target=="content":c=copy.deepcopy(c);c["contentId"]="sha256:"+"0"*64
- else:j.journal.ref=REF
+ elif target=="ref":j.journal.ref=REF
+ elif target=="ordinary-ref":j.journal.ref=publisher.SUCCESSOR_REF
+ else:c=copy.deepcopy(c);c["descriptor"]["version"]=publisher.SUCCESSOR_VERSION
with self.assertRaises(publisher.Refused):publisher.validate_successor_checkpoint(c,j,e)
self.assertEqual(p.dispatched,[])
@@ -1736,13 +1745,13 @@ def test_budget_wait_propagates_through_real_protected_admission(self):
def test_fresh_journal_preparation_uses_original_mutation_deadline(self):
candidate=json.loads((pathlib.Path(__file__).parent/'original-0102-manifest.json').read_bytes())
- a=MemoryAuthority(ref=publisher.SUCCESSOR_REF)
+ a=MemoryAuthority(ref=publisher.ORIGINAL_SUCCESSOR_REF)
n=publisher.CountedAuthorityAPI(a,ceiling=1500,quota_floor=1800);n.admit_quota(now=1900000000)
now=[0];n.api=publisher.RuntimeDeadlineAuthority(n.api,10,lambda:now[0])
- r=report();j=publisher.ReportingJournal(ProtectedReleaseJournal(n,ref=publisher.SUCCESSOR_REF,main_directory=True),r)
+ r=report();j=publisher.ReportingJournal(ProtectedReleaseJournal(n,ref=publisher.ORIGINAL_SUCCESSOR_REF,main_directory=True),r)
api=MemoryPublisher();api.head=candidate['descriptor']['sourceSha']
p=MemoryProvider(ordered_effects(candidate),{});p._release=lambda:None
- composite=publisher.ProtectedPublisherAdmission(SingleOperatorAdmission(api,candidate,api.head,1,'EHotwagner','refs/heads/main'),n,publisher.SUCCESSOR_REF)
+ composite=publisher.ProtectedPublisherAdmission(SingleOperatorAdmission(api,candidate,api.head,1,'EHotwagner','refs/heads/main'),n,publisher.ORIGINAL_SUCCESSOR_REF)
ad=publisher.RuntimeDeadlineAdmission(composite,10,lambda:now[0])
intent={'contentId':candidate['contentId'],'sourceSha':api.head,'version':'0.102.0','candidateArchiveSha256':publisher.SUCCESSOR_CHECKPOINT_CANDIDATE['archiveSha256'],'operator':'EHotwagner'}
def uniqueness():now[0]=10