Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .github/workflows/release-successor-candidate.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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 }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-successor-publish.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@
telemetry CI legacy-default selection repair. Publication and installed
consumer adoption remain separate from this source version. -->
<PropertyGroup>
<FsggCoherentSetVersion>0.102.0</FsggCoherentSetVersion>
<FsggCoherentSetVersion>0.103.0</FsggCoherentSetVersion>
</PropertyGroup>

</Project>
24 changes: 24 additions & 0 deletions docs/roadmaps/utel-release-successor.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
15 changes: 10 additions & 5 deletions scripts/release-successor-publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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")
Expand Down
19 changes: 9 additions & 10 deletions src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -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`.</FsggStandingAdvisories>

<PackageReleaseNotes>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.
<PackageReleaseNotes>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)

Expand Down
18 changes: 9 additions & 9 deletions tests/release-successor-candidate/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions tests/release-successor-live/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, [])
Expand Down
27 changes: 18 additions & 9 deletions tests/release-successor-recovery/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"):
Expand All @@ -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()
Expand Down Expand Up @@ -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,[])

Expand Down Expand Up @@ -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
Expand Down
Loading