Skip to content

Promotion sets + grace agent + lots of redesign#62

Merged
ScottArbeit merged 30 commits intomainfrom
feature/promotion-sets
Mar 2, 2026
Merged

Promotion sets + grace agent + lots of redesign#62
ScottArbeit merged 30 commits intomainfrom
feature/promotion-sets

Conversation

@ScottArbeit
Copy link
Owner

This PR is a massive redesign of the promotion-set construct, getting rid of unused CLI command structures, and starting to add features that directly help reviewers, including the beginning of grace agent implementation.

Scott Arbeit added 26 commits February 18, 2026 01:49
…; beginning of the `grace agent` command; documentation updates; first-run scripts; much more tinkering.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d7d2b79cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +433 to +437
SessionId =
(if String.IsNullOrWhiteSpace parameters.OperationId then
Guid.NewGuid().ToString("N")
else
parameters.OperationId.Trim())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Decouple agent session IDs from operation idempotency keys

The new session identifier is built from parameters.OperationId, but that field is also used as the idempotency token (replayKey) and can be reused by callers across independent starts. Because activeAgentSessionsBySessionId is keyed only by this SessionId, a later start using the same operation id can overwrite the earlier mapping, which breaks /agent/session/status and /agent/session/stop lookups by session id for the original active session. Session identity should be generated independently from the idempotency token.

Useful? React with 👍 / 👎.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex is your recommendation to use Guid.NewGuid() every time?

else
let mutable stepId = Guid.Empty

if not <| Guid.TryParse(parameters.StepId, &stepId) then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject empty step IDs when resolving promotion-set conflicts

ResolveConflicts validates StepId with Guid.TryParse, which accepts 00000000-0000-0000-0000-000000000000; that value then flows to the actor. In PromotionSetActor.RecomputeSteps, manual decisions are only applied when the supplied step id equals a real step id, so an empty guid is silently ignored and the request can appear to succeed without applying any of the provided resolutions. Treat Guid.Empty as InvalidPromotionSetStepId at the API boundary.

Useful? React with 👍 / 👎.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex Please fix

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

  • Fixed ResolveConflicts step ID validation so the API now rejects both unparseable IDs and Guid.Empty, returning InvalidPromotionSetStepId before calling the actor. This closes the gap where 00000000-0000-0000-0000-000000000000 could be accepted and silently ignored downstream. src/Grace.Server/PromotionSet.Server.fsL343-L350
  • Committed the change on the current branch (9dcd143) and created a follow-up PR entry via the make_pr tool.

Testing

  • curl -s https://learn.microsoft.com/en-us/dotnet/api/system.guid.tryparse?view=net-9.0 | head -n 20
  • ⚠️ dotnet build src/Grace.Server/Grace.Server.fsproj -c Release (environment limitation: dotnet CLI is not installed, command not found)

View task →

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c9a01b11ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +434 to +437
(if String.IsNullOrWhiteSpace parameters.OperationId then
Guid.NewGuid().ToString("N")
else
parameters.OperationId.Trim())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Generate session IDs independently from operation IDs

OperationId is defined as a caller-supplied idempotency token, but this code reuses it as SessionId, which lets different sessions collide on the global activeAgentSessionsBySessionId index; once that happens, tryResolveActiveSession prefers the collided SessionId path and can return the wrong session (or fail to find the real one) for stop/status calls. This is especially likely when callers reuse operation IDs across retries or agents, so each new session should get its own unique ID (for example Guid.NewGuid()), while OperationId remains only for replay caching.

Useful? React with 👍 / 👎.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codex Please fix

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

  • Updated agent session creation to always generate a new SessionId via Guid.NewGuid().ToString("N"), instead of reusing caller-supplied OperationId. This decouples session identity from idempotency replay keys and prevents session-id collisions in the active session index. src/Grace.Server/Startup.Server.fsL431-L445
  • Committed the fix on the current branch (b3b002c) and created a follow-up PR entry with make_pr.

Testing

  • curl -s https://learn.microsoft.com/en-us/dotnet/api/system.guid.newguid?view=net-9.0 | head -n 20
  • ⚠️ dotnet build src/Grace.Server/Grace.Server.fsproj -c Release (environment limitation: dotnet CLI is not installed, command not found)

View task →

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why keep an index if it's always new?

@ScottArbeit ScottArbeit merged commit d2482e8 into main Mar 2, 2026
3 checks passed
@ScottArbeit ScottArbeit deleted the feature/promotion-sets branch March 2, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants