{"id":51885702,"url":"https://github.com/stablekernel/cascade-example-retries","last_synced_at":"2026-07-25T20:30:46.829Z","repository":{"id":372296914,"uuid":"1306232113","full_name":"stablekernel/cascade-example-retries","owner":"stablekernel","description":"Cascade example: a deploy that fails once and is rescued by its retry, with a dependent deploy that still runs on the effective result.","archived":false,"fork":false,"pushed_at":"2026-07-20T08:05:32.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-20T09:14:42.414Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stablekernel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-20T05:01:44.000Z","updated_at":"2026-07-20T08:06:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/stablekernel/cascade-example-retries","commit_stats":null,"previous_names":["stablekernel/cascade-example-retries"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/stablekernel/cascade-example-retries","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade-example-retries","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade-example-retries/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade-example-retries/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade-example-retries/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stablekernel","download_url":"https://codeload.github.com/stablekernel/cascade-example-retries/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stablekernel%2Fcascade-example-retries/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35892725,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-25T02:00:06.922Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-25T20:30:46.296Z","updated_at":"2026-07-25T20:30:46.823Z","avatar_url":"https://github.com/stablekernel.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# cascade-example-retries\n\nA cascade fleet example that exercises deploy retry semantics: a deploy whose\nfirst attempt fails and whose retry succeeds must leave the environment deployed\nand the run green, and a dependent deploy gated on that retried deploy must\nstill run. These are runtime behaviors that only real GitHub Actions can show,\nbecause they depend on how live job results flow through the generated workflow.\n\n## What this repo proves\n\nWhen a deploy declares `retries`, cascade emits a retry shim job\n(`Deploy (app) - Retry 1`) that re-invokes the deploy callee when the base\nattempt fails. Downstream jobs must key on the deploy's effective result (the\nbase attempt or any retry succeeded), not on the immutable result of the base\nattempt. This repo proves both halves of that contract:\n\n1. A deploy that fails once and then succeeds on the retry leaves the\n   environment deployed and the orchestrate run green: the base attempt\n   concludes failure, the retry concludes success, the environment's deployed\n   sha advances, and the overall run is green.\n2. A dependent deploy (`notify`) that `depends_on` the retried deploy runs\n   rather than being skipped, because its gate reads the effective result of the\n   base deploy, not the failed result of the first attempt.\n\n## Manifest shape\n\nTwo environments (`staging`, `prod`) and two deploys:\n\n| Deploy | Role | Callee |\n| --- | --- | --- |\n| `app` | environment deploy with `retries: 1`; fails once, then succeeds | `deploy-app.yaml` |\n| `notify` | dependent deploy with `depends_on: [app]`; must still run | `deploy-notify.yaml` |\n\nA stub `build` callback gives the repo a valid build and promote chain.\n\n## The fail-once marker\n\n`deploy-app.yaml` fails on its first attempt and succeeds on its retry using an\nActions cache entry as a one-shot marker. The cache key is\n`deploy-app-attempted-\u003crun id\u003e-\u003cenvironment\u003e`:\n\n- On the first attempt the cache misses (no marker), so the callee writes the\n  marker, then fails. The retry shim re-invokes the same callee, the cache now\n  hits, and the callee succeeds.\n- The key is scoped to `github.run_id`, so the marker is unique to a single run\n  and resets on its own: a fresh run always starts with a cache miss, so the\n  first attempt fails again. No state carries between runs, so the marker can\n  never wedge a later run into a stuck state.\n\nThis marker needs no secret and no committed state; it lives entirely in the\nActions cache for the duration of one run.\n\n## Scenario suite\n\n`scenario-suite.yaml` merges a source change to drive an orchestrate run, then\nreads that run's jobs and the committed deploy state and asserts:\n\n- the base `Deploy (app)` attempt concluded failure and `Deploy (app) - Retry 1`\n  concluded success (the retry rescued the deploy);\n- the dependent `Deploy (notify)` job ran rather than being skipped;\n- the orchestrate run concluded success; and\n- the `staging` deploy sha for `app` advanced to the merge sha.\n\nEvery run the suite causes is recorded in the fleet ledger, and the final\nreconcile job fails closed on any unregistered run.\n\n## Layout\n\n```\n.github/manifest.yaml              cascade manifest (config plus live state)\n.github/workflows/build.yaml       build callee stub\n.github/workflows/deploy-app.yaml  fail-once deploy callee\n.github/workflows/deploy-notify.yaml dependent deploy callee\n.github/workflows/orchestrate.yaml generated CI on trunk merges\n.github/workflows/promote.yaml     generated environment promotion\n.github/workflows/scenario-suite.yaml driver and assertions\n```\n\nThe orchestrate, promote, hotfix, and rollback workflows and the\n`manage-release` action are generated by cascade from the manifest. Run\n`cascade generate-workflow` after editing the manifest.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablekernel%2Fcascade-example-retries","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstablekernel%2Fcascade-example-retries","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstablekernel%2Fcascade-example-retries/lists"}