Skip to content

Recover a missing stable GitHub publication without replaying release side effects #602

Open
1 of 1 issue completed

Description

@devantler

🤖 Generated by the Agentic Engineer

Problem

Two recorded tag-only releases remain unpublished. The inspector diagnoses them safely, but operators still have no maintained path to publish the existing tag without rerunning arbitrary release plugins or creating another version.

Design

Add a separate repository-local publisher and a default-off reusable recovery workflow. The workflow must run in the affected public repository on its default branch, sharing the normal release concurrency group. Build immutable catalogue code before credentials; first admit the incident with a one-repository read token, then obtain only Contents(write) and Actions(read) for that repository. Reuse the inspector’s original run/tag/source/config checks.

Under the writer credential, prove push capability, enumerate a complete bounded release inventory twice, refuse drafts/conflicting records and capture an existing stable latest release. Re-admit identity immediately before a single create-release request. Publish only the existing stable tag with its captured source, deterministic honest recovery receipt, no generated notes/assets and the JSON string make_latest=false. Independently re-read publication, source and latest anchor. A matching existing publication is a no-op. Ambiguous or failed writes fail without POST retries; a later explicit invocation reconciles through fresh reads.

The receipt names the original run/tag/source/producer and says original generated notes were not reconstructed. No channel-note mutation is included: native semantic-release stable/default-branch controls must establish that missing notes do not require repair in this bounded scope.

Implementation contract

Keep the publisher in the inspector's existing Go module, using a narrow typed GET-only admission/result interface. The inspection command remains read-only. Do not copy its identity checks or parse its printed diagnosis to reconstruct an admitted snapshot.

Keep permanent explicit operator confirmation separate from the temporary rollout flag. Production publication is manual-dispatch only; removing the rollout flag later must not remove publication consent. A matching publication found during read-only admission returns a verified no-op without acquiring a writer token; the same applies if it appears during writer re-admission.

Encode the latest-preservation field as the JSON string "make_latest":"false", not a JSON boolean; the endpoint uses a string enum and otherwise defaults to making a published release latest. A successful read-token release list does not establish draft absence: draft visibility requires push access, so that check belongs under the proven writer capability. Historical workflow-file differences can require additional workflow authorization; propagate a refusal without a broader-token fallback. Preserve exactly one POST and fail ambiguous transport results rather than retrying them.

Primary provider contracts: release creation and draft visibility, conditional request limits. These are design constraints, not evidence that the protected consumer or App has accepted publication.

Provider limits

GitHub has no documented conditional create-release or idempotency key. The queue serializes cooperating workflows only; concurrent external tag mutations are unsupported, and readback detects rather than prevents that race. Missing App push metadata or draft visibility fails closed. Historical workflow authorization may require more than Contents(write); a refusal must propagate without obtaining broader credentials or substituting another source. Protected consumer recovery must resolve these provider uncertainties before claiming either recorded incident recovered.

Acceptance criteria

  • Default-off workflow and explicit enabled/offline CI calls execute without production credentials; every reusable caller is included in required aggregate coverage.
  • Native HTTP controls exercise one successful POST and independent readback, matching publication no-op, wrong identity, draft/conflict on later pages, missing/false push proof, incomplete/changed inventory, changed latest/tag/source, failed reads/writes, malformed success, connection loss after accepted POST and explicit rerun reconciliation with zero additional POSTs.
  • The original inspection command remains read-only. No assets, tag/notes/ref mutation, success/fail plugins, unrelated publication or broader-token fallback exists.
  • The maintained workflow is documented, reviewed, merged and released. Real protected consumer publication remains Recover GitHub releases after a tag-only partial publication #587 acceptance; offline tests must not claim it.
  • Track rollout and short-lived flag removal as separate open work before shipping the flag.

Refinement

Priority: High. Effort: High including native controls, hosted CI, review and consumer proof. Service class: Risk reduction. Directly reduces repeat operator risk for two observed incidents; no artificial deadline. Prerequisites: #600 admission extraction (delivered and verified) and #604 maintained channel-preservation coverage. Publisher implementation begins after both merge. User explicitly waived WIP limits for this run.

Part of #587

Activity

  1. devantler commented on Oct 15, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Primary-source design review confirms that release listings expose drafts only to principals with push access, and release creation has no documented conditional-write or idempotency parameter. The writer must establish its own inventory/capability proof; the read-only diagnosis cannot authorize publication. Existing-tag target behavior also does not promise an exception from historical workflow authorization. A refused write propagates without permission expansion.

    Sources: release API, conditional requests, reusable workflow context, concurrency scope. Independent read-only design assessment completed; no provider publication has been attempted.

  2. moved this to 🫴 Ready in 🌊 Project Boardon Oct 15, 2026
  3. devantler commented on Oct 15, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Refinement complete; Ready with native dependency #600. Rollout/opt-in disposition is separately tracked in #603. Implementation will retain default-off behavior and will not equate loopback fixtures with completed provider recovery. Native planning-field writes remain QUERY-UNKNOWN under the required GraphQL binding classifier; no fallback Priority/Effort copies were created.

  4. updated Priority High and Effort High on Oct 15, 2026
  5. devantler commented on Oct 15, 2026

    @devantler
    ContributorAuthor

    🤖 Generated by the Agentic Engineer

    Repeated the native stable-channel characterization with Node 22.23.3 and the production semantic-release 25.0.3 decision stack, omitting only the authenticated GitHub publisher. Both absent-note and matching {"channels":[null]} cases select no new version at the stranded tag and 1.2.5 after one subsequent fix. All four runs preserve local refs, remote refs and the working tree. This supports leaving notes unchanged within the stable/default-branch scope; it does not prove prerelease/multibranch behavior or real GitHub publication. The maintained offline suite must retain this coverage.

    Native HTTP test design is prepared for one POST plus independent readback, explicit confirmation, matching-publication no-op, missing/false writer capability, later-page drafts, pagination refusal, changed inventories/latest/tag/source, malformed success and lost connections after server-side publication. An explicit rerun must reconcile without another POST. Product implementation still waits for #600 to merge.

  6. added a commit that references this issue on Oct 15, 2026
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

    Fields

    Priority

    High

    Start date

    None yet

    Target date

    None yet

    Effort

    High

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions