LearnNewsExamplesServices
Frontmatter
id15746
titleRegenerate Actions Data Sync output when dev advances
stateClosed
labels
bugairegressionarchitecturebuild
assigneesneo-gpt-emmy
createdAtJul 23, 2026, 10:48 AM
updatedAtJul 23, 2026, 2:08 PM
githubUrlhttps://github.com/neomjs/neo/issues/15746
authorneo-gpt-emmy
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 23, 2026, 2:08 PM

Regenerate Actions Data Sync output when dev advances

Closed Backlog/active-chunk-8 bugairegressionarchitecturebuild
neo-gpt-emmy
neo-gpt-emmy commented on Jul 23, 2026, 10:48 AM

Context

A census of the latest 100 scheduled Data Sync Pipeline runs through 2026-07-23 07:37 UTC found 67 failures and 33 successes. Two failures terminated when dev advanced during the long-running job and the final generated-content rebase conflicted.

Representative runs: conflict run 1, conflict run 2.

Problem

Data Sync checks out one dev snapshot, performs the expensive update pipeline, creates a local generated-data commit, and only then runs git pull origin dev --rebase before pushing.

Normal development merges can advance dev while Data Sync is running. When both the pipeline and the intervening commit touch a generated artifact such as an ID map or sitemap, Git is asked to reconcile two cache emissions. A conflict terminates the run and discards the publication opportunity even though the correct operation is deterministic regeneration from the new authority.

Workflow concurrency serializes Data Sync runs with each other; it does not serialize them against ordinary dev merges.

Architectural Reality

  • The Actions workflow commits generated paths and then rebases immediately before a direct push: data-sync-pipeline.yml.
  • ADR-0004 treats synchronized GitHub content as a regeneratable local cache whose provenance remains GitHub: 0004-github-content-architecture.md.
  • The separate GitHub Workflow SyncService already implements bounded fresh-checkout recovery and re-emission for generated-content push conflicts: SyncService.mjs, introduced by #13798.
  • #15130 concerns content-sync/archive index integrity. It is adjacent, not this Actions checkout/publication race.

Fix

Apply the established discard-and-regenerate contract to the Actions Data Sync publisher.

  • Capture the checked-out dev SHA at the start of an emission attempt.
  • Before publication, fetch origin/dev and compare it with that base instead of blindly rebasing the generated commit.
  • If dev moved, discard only the ephemeral runner's generated attempt, restore a clean checkout at the new head, and rerun the complete generated-output emission pipeline.
  • Verify head freshness again before publishing the replacement commit.
  • Bound the operation to two emission attempts. If dev advances again, restore a clean runner state and fail with an explicit stale-head diagnostic.
  • Preserve one atomic generated-data commit on a verified current head.
  • Never force-push and never resolve conflicts inside derived JSON/Markdown output.
  • Keep the workflow's generated-path allowlist explicit so unrelated files cannot enter the publication commit.

Prefer extracting or reusing the existing recovery contract where that reduces semantic duplication; do not mechanically couple the Actions workflow to SyncService internals if their execution substrates require different adapters.

Contract Ledger

Surface Current contract Required contract Verification
Actions generated-data publish Commit, rebase, direct push Verify head; discard and re-emit once on authority advance Temporary-repository integration harness
Fresh-head guard Implicit final rebase Explicit base/current SHA comparison before publish Deterministic injected branch advance
Existing SyncService precedent Bounded recovery on a different publisher Shared semantic contract, substrate-appropriate adapter Contract-focused comparison/tests

Decision Record Impact

aligned-with ADR-0004. This operationalizes the existing regeneratable-cache principle on the Actions publisher. No generated-content shape or provenance decision changes.

Acceptance Criteria

  • When origin/dev is unchanged, Data Sync emits and publishes in one attempt.
  • A deterministic test advances dev and touches the same generated artifact; the workflow discards the stale attempt, checks out the new head, re-emits, and publishes a clean commit.
  • A second injected advance terminates after the bounded retry with a clear stale-head diagnostic and a clean ephemeral runner state.
  • Publication no longer rebases or conflict-resolves derived output.
  • No force push is possible in the recovery path.
  • Only the explicit generated-path allowlist can be staged in either attempt.
  • The final commit is based on the verified current dev head and contains one atomic generated-data emission.
  • Logs identify attempt number and base/current SHAs without dumping generated payloads or credentials.
  • Focused coverage uses temporary repositories or an equivalent deterministic Git harness rather than relying on a naturally timed production race.

Out of Scope

  • GitHub App identity, cross-repository authorization, or ruleset bypass
  • GraphQL quota budgeting and batch sizing
  • Content/archive integrity work owned by #15130
  • Changing generated data or release-archive formats
  • Serializing all human and agent merges behind Data Sync

Avoided Traps

  • No line-by-line conflict resolution in generated files
  • No force push
  • No unbounded retry loop
  • No assumption that workflow-level concurrency blocks normal dev advancement
  • No reopening or mutating closed historical tickets

Related

  • Authorization and publication identity sibling: #15744
  • GraphQL-cost budget sibling: #15745
  • Conflict-recovery precedent on the separate SyncService publisher: #13798
  • Unified pipeline origin: #9869
  • Derived-content coupling precedent: #13260
  • Adjacent content/archive repair: #15130

Live duplicate sweep: the latest 30 open issues and recent all-state A2A claims were checked immediately before creation on 2026-07-23; no equivalent open lane was found.

Origin Session ID: 72bb1088-8ed5-48b7-a835-c288cf30e814

Retrieval Hint: Actions Data Sync dev advanced stale checkout regenerate derived output rebase conflict