Pass shared run timestamp into CodeGen to prevent dual-target merge conflicts - #92
Merged
Merged
Conversation
…onflicts
The codegen workflow runs as a matrix on main and develop. Each leg
embedded `DateTime.UtcNow:o` directly into `CodeGen/CodeGen.cs`, so
even within a single workflow invocation the two legs produced
different file contents (timestamps ~2 seconds apart). Every
develop->main release after a codegen sync then conflicted textually
on that one line, and the conflict blocked the merge ref from
computing, which in turn prevented `pull_request` workflows from
firing on the develop->main PR.
Fix: add a `--runtime` CLI flag to the CodeGen project that overrides
the embedded timestamp; the workflow passes
`${{ github.run_started_at }}` to both matrix legs so they emit
byte-identical output. When `--runtime` is omitted (local
`dotnet run`), behavior is unchanged (DateTime.UtcNow).
Also resolves the existing CodeGen.cs divergence on develop by
pinning to main's already-released timestamp, so the next
develop->main release won't conflict on this file.
Note on scope: per-run-unique demo output is *expected* for codegen
in general — the `--runtime` plumbing is template-internal hygiene
to keep the dual-target template from generating release-blocking
conflicts on every cycle. Derived projects' real generators should
not copy this pattern; design generators to be deterministic given
the same inputs, run them on a single release branch, or absorb the
per-release merge cost.Contributor
There was a problem hiding this comment.
Pull request overview
This PR removes recurring develop → main merge conflicts caused by the codegen demo embedding a per-run timestamp by allowing a shared, externally-provided runtime timestamp to be used across both codegen workflow matrix legs.
Changes:
- Add an optional
--runtime/-rCLI flag and plumb it through to code generation so the embedded timestamp can be injected deterministically. - Update the codegen builder to use the injected timestamp when provided, otherwise preserve the prior
DateTime.UtcNowbehavior. - Update the codegen workflow to pass
${{ github.run_started_at }}so bothmainanddevelopruns emit byte-identicalCodeGen.csoutput.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| CodeGen/Program.cs | Passes parsed runtime option into code generation. |
| CodeGen/CommandLine.cs | Adds --runtime/-r option and exposes it via parsed options. |
| CodeGen/CodeGenBuilder.cs | Uses injected runtime timestamp (or falls back to UtcNow) and emits it safely as a C# string literal. |
| CodeGen/CodeGen.cs | Updates the generated timestamp constant to align branches and unblock current merge conflicts. |
| AGENTS.md | Documents the dual-target codegen + per-run state pitfall and the template-only mitigation. |
| .github/workflows/run-codegen-pull-request-task.yml | Passes github.run_started_at into codegen for deterministic output across the matrix. |
Uh oh!
There was an error while loading. Please reload this page.
ptr727 added a commit
that referenced
this pull request
Jun 3, 2026
## Problem The dual-target codegen "byte-identical output" mechanism (#92) was silently broken. `run-codegen-pull-request-task.yml` passed `--runtime "${{ github.run_started_at }}"` to both matrix legs, but **`github.run_started_at` resolves to an empty string in this reusable-workflow context**. `CodeGenBuilder` falls back to `DateTime.UtcNow` when `--runtime` is empty, so each leg stamped its own wall-clock time — the `main` and `develop` legs diverged (observed ~5s apart), and `CodeGen.cs` differed between branches, reintroducing the exact `develop → main` release conflict the mechanism was meant to prevent. ## Fix Capture **one** UTC timestamp in a new `get-runtime` job and feed it to both matrix legs via `needs.get-runtime.outputs.runtime`. Both legs now receive an identical, non-empty value, so `CodeGen.cs` is byte-identical across branches again. Discovered while resolving the `CodeGen.cs` conflict on the develop→main release PR (#99). AGENTS.md updated to match. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Eliminates the recurring
develop → mainmerge conflict onCodeGen/CodeGen.cs. PR #91 surfaced the issue: the codegen matrix's two legs (main, develop) each embed their ownDateTime.UtcNow:o, so the generated file diverges every codegen cycle and every release merge conflicts on the same line. The conflict also blocks GitHub from computing the PR merge ref, which is why nopull_requestworkflow could fire on PR #91.Changes
--runtime/-rCLI flag. When set, the value is embedded verbatim as the file'sdateTimeconstant; when omitted, behavior is unchanged (DateTime.UtcNow.ToString("o")).CommandLine.cs,CodeGenBuilder.cs,Program.cs.--runtime "${{ github.run_started_at }}"so both matrix legs in a single invocation receive the same string and emit byte-identicalCodeGen.cs..github/workflows/run-codegen-pull-request-task.yml.CodeGen/CodeGen.cs: pin develop's timestamp to main's already-released value, so the currently-open PR Migrate App-token to client-id and drop inert codegen PR base filter (#90) #91 unblocks and the next codegen run starts both branches from the same string.AGENTS.md: documents the dual-target-codegen + per-run-state pitfall and labels the--runtimeplumbing as template-internal hygiene, not a generator pattern derived projects should reproduce.Scope note (per the user)
Per-run-unique output from a codegen demo is expected. The
--runtimeflag exists only because this template runs the same demo generator on two release branches in parallel; passing a shared timestamp keeps releases from blocking on the resulting textual conflicts. Derived projects' real generators should be deterministic given the same inputs, or be scoped to a single release branch, or accept the per-release merge cost — not copy this--runtimeplumbing.Inline comments at CodeGenBuilder.cs:7-13, CommandLine.cs:67-73, and run-codegen-pull-request-task.yml:67-74 repeat this so each touchpoint is self-explanatory.
Test plan
dotnet run --project CodeGen/CodeGen.csproj -- --codepath /tmp/x --runtime "2026-05-24T20:00:00Z"producesdateTime = "2026-05-24T20:00:00Z"; omitting--runtimeproduces aDateTime.UtcNow:o-style value as before.pull_requestworkflows fire on it, and it can merge cleanly.run-periodic-codegen-pull-request.yml: both matrix legs produce identicalCodeGen/CodeGen.cscontent.