Skip to content

BCH-1155: Populate ExecutionStreamUUID in WorkflowExecution.GetByID#401

Open
saltpy-cs wants to merge 1 commit into
mainfrom
fix/BCH-1155
Open

BCH-1155: Populate ExecutionStreamUUID in WorkflowExecution.GetByID#401
saltpy-cs wants to merge 1 commit into
mainfrom
fix/BCH-1155

Conversation

@saltpy-cs
Copy link
Copy Markdown
Contributor

@saltpy-cs saltpy-cs commented May 22, 2026

Add a computed ExecutionStreamUUID field to WorkflowExecution and derive it deterministically in GetByID using a pure SHA256-based helper that mirrors the algorithm already used by EvidenceIntegration.

Summary by CodeRabbit

  • New Features

    • Added execution_stream_uuid field to workflow executions, enabling unique identification and tracking of each execution.
  • Documentation

    • Updated API documentation and schemas to include the new execution_stream_uuid field.
  • Tests

    • Added tests validating execution stream UUID generation and retrieval consistency.

Review Change Stack

Add a computed ExecutionStreamUUID field to WorkflowExecution and
derive it deterministically in GetByID using a pure SHA256-based
helper that mirrors the algorithm already used by EvidenceIntegration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

📝 Walkthrough

Walkthrough

This PR introduces a computed execution_stream_uuid field to workflow executions. The field is derived deterministically from definition, instance, and execution IDs using SHA-256 hashing, integrated into the WorkflowExecution model and service layer, populated in the GetByID method, validated by tests, and documented in the API schema.

Changes

Execution Stream UUID Feature

Layer / File(s) Summary
Deterministic UUID computation algorithm
internal/service/relational/workflows/stream_uuid.go
ComputeExecutionStreamUUID derives a UUID deterministically from definition, instance, and execution IDs by constructing a versioned seed string, hashing with SHA-256, converting to hex, formatting into a UUID string, and parsing the result.
Model definition and service integration
internal/service/relational/workflows/workflow_execution.go, internal/service/relational/workflows/workflow_execution_service.go
WorkflowExecution struct adds ExecutionStreamUUID field (non-persisted, JSON-exposed); GetByID conditionally populates it by calling ComputeExecutionStreamUUID when all required IDs and related entities are present.
Service test validation
internal/service/relational/workflows/workflow_execution_service_test.go
TestWorkflowExecutionService_GetByID_PopulatesExecutionStreamUUID verifies the field is populated with a non-nil, non-zero UUID and that repeated calls return the same deterministic value for the same execution.
API schema documentation updates
docs/swagger.json, docs/swagger.yaml, docs/docs.go
Swagger, YAML, and generated docs schemas document the new execution_stream_uuid field as a computed (non-persisted) string property.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • gusfcarvalho

Poem

A UUID springs from seeds that blend,
Definition, instance, execution bound,
SHA-256 hashes bring it home,
No database, just computed grace,
Schema documented, tests now sound! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding ExecutionStreamUUID population to WorkflowExecution.GetByID method, which is the core objective across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/swagger.json`:
- Around line 40223-40226: The schema for the computed field
execution_stream_uuid currently only declares "type": "string" but should
declare a UUID format to enforce the intended shape; update the JSON schema for
the execution_stream_uuid property to add "format": "uuid" alongside "type":
"string" so generated clients and validators will treat it as a UUID.

In `@docs/swagger.yaml`:
- Around line 8922-8924: The OpenAPI schema entry for execution_stream_uuid is
too permissive; update the execution_stream_uuid property (in docs/swagger.yaml)
to include format: uuid and readOnly: true while keeping type: string and the
existing description ("Computed field (not persisted)") so generated clients and
validators treat it as a server-computed UUID-only, read-only field.

In `@internal/service/relational/workflows/stream_uuid.go`:
- Around line 23-24: The code currently ignores the error from uuid.Parse when
building streamUUID (streamUUID, _ := uuid.Parse(...)); change it to capture and
handle the error (streamUUID, err := uuid.Parse(...)) and propagate it by
updating the function signature to return (uuid.UUID, error) or otherwise return
uuid.Nil with a wrapped error; update callers to handle the error so a malformed
UUID assembly cannot silently produce a uuid.Nil used for execution_stream_uuid.

In `@internal/service/relational/workflows/workflow_execution_service_test.go`:
- Around line 119-127: The test currently only asserts stability of
ExecutionStreamUUID across fetches; update it to also assert the canonical
expected UUID and guard against nil on the second retrieval. After calling
retrieved2, require.NoError(t, err) (already present) and add require.NotNil(t,
retrieved2.ExecutionStreamUUID) before dereferencing it, then compute the
expected UUID using the same deterministic generator the service uses (e.g., the
function that produces the execution stream UUID in your implementation — call
it directly, e.g., computeExecutionStreamUUID(execution) or
ExecutionStreamUUIDFor(execution)) and assert assert.Equal(t, expectedUUID,
*retrieved2.ExecutionStreamUUID) instead of only comparing retrieved to
retrieved2.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d1e82e79-2c59-4f5d-a466-1f6014476acc

📥 Commits

Reviewing files that changed from the base of the PR and between 7597d41 and 9dd6b9a.

📒 Files selected for processing (7)
  • docs/docs.go
  • docs/swagger.json
  • docs/swagger.yaml
  • internal/service/relational/workflows/stream_uuid.go
  • internal/service/relational/workflows/workflow_execution.go
  • internal/service/relational/workflows/workflow_execution_service.go
  • internal/service/relational/workflows/workflow_execution_service_test.go

Comment thread docs/swagger.json
Comment on lines +40223 to +40226
"execution_stream_uuid": {
"description": "Computed field (not persisted)",
"type": "string"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Add UUID format to strengthen the API contract.

execution_stream_uuid is documented as a UUID but only typed as string. Add "format": "uuid" so generated clients and validators enforce the intended shape consistently.

Suggested diff
                 "execution_stream_uuid": {
                     "description": "Computed field (not persisted)",
-                    "type": "string"
+                    "type": "string",
+                    "format": "uuid"
                 },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/swagger.json` around lines 40223 - 40226, The schema for the computed
field execution_stream_uuid currently only declares "type": "string" but should
declare a UUID format to enforce the intended shape; update the JSON schema for
the execution_stream_uuid property to add "format": "uuid" alongside "type":
"string" so generated clients and validators will treat it as a UUID.

Comment thread docs/swagger.yaml
Comment on lines +8922 to +8924
execution_stream_uuid:
description: Computed field (not persisted)
type: string
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tighten API contract for computed UUID field

On Line 8924, execution_stream_uuid is documented as a plain string, but this field is semantically a UUID and computed server-side. Please add format: uuid and readOnly: true so generated clients and validators enforce the intended contract.

Suggested patch
       execution_stream_uuid:
         description: Computed field (not persisted)
         type: string
+        format: uuid
+        readOnly: true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
execution_stream_uuid:
description: Computed field (not persisted)
type: string
execution_stream_uuid:
description: Computed field (not persisted)
type: string
format: uuid
readOnly: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/swagger.yaml` around lines 8922 - 8924, The OpenAPI schema entry for
execution_stream_uuid is too permissive; update the execution_stream_uuid
property (in docs/swagger.yaml) to include format: uuid and readOnly: true while
keeping type: string and the existing description ("Computed field (not
persisted)") so generated clients and validators treat it as a server-computed
UUID-only, read-only field.

Comment on lines +23 to +24
streamUUID, _ := uuid.Parse(h[:8] + "-" + h[8:12] + "-" + h[12:16] + "-" + h[16:20] + "-" + h[20:32])
return streamUUID
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify no ignored uuid.Parse errors remain in workflows package.
rg -nP 'uuid\.Parse\([^)]*\)' internal/service/relational/workflows -C2

Repository: compliance-framework/api

Length of output: 545


Handle uuid.Parse errors explicitly in stream_uuid construction.

In internal/service/relational/workflows/stream_uuid.go (lines 23-24), uuid.Parse is called with a dropped error (streamUUID, _ := uuid.Parse(...)). While h is currently built as a fixed 32-hex-char string (sha256hash[:16]hex.EncodeToString), ignoring the parse error makes this fragile: any future change to the UUID string assembly can silently produce uuid.Nil and generate broken execution_stream_uuid values.

Proposed fix
-	streamUUID, _ := uuid.Parse(h[:8] + "-" + h[8:12] + "-" + h[12:16] + "-" + h[16:20] + "-" + h[20:32])
-	return streamUUID
+	uuidStr := h[:8] + "-" + h[8:12] + "-" + h[12:16] + "-" + h[16:20] + "-" + h[20:32]
+	streamUUID, err := uuid.Parse(uuidStr)
+	if err != nil {
+		return uuid.Nil
+	}
+	return streamUUID
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
streamUUID, _ := uuid.Parse(h[:8] + "-" + h[8:12] + "-" + h[12:16] + "-" + h[16:20] + "-" + h[20:32])
return streamUUID
uuidStr := h[:8] + "-" + h[8:12] + "-" + h[12:16] + "-" + h[16:20] + "-" + h[20:32]
streamUUID, err := uuid.Parse(uuidStr)
if err != nil {
return uuid.Nil
}
return streamUUID
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/relational/workflows/stream_uuid.go` around lines 23 - 24,
The code currently ignores the error from uuid.Parse when building streamUUID
(streamUUID, _ := uuid.Parse(...)); change it to capture and handle the error
(streamUUID, err := uuid.Parse(...)) and propagate it by updating the function
signature to return (uuid.UUID, error) or otherwise return uuid.Nil with a
wrapped error; update callers to handle the error so a malformed UUID assembly
cannot silently produce a uuid.Nil used for execution_stream_uuid.

Comment on lines +119 to +127
// ExecutionStreamUUID must be populated and deterministic
require.NotNil(t, retrieved.ExecutionStreamUUID)
assert.NotEqual(t, uuid.Nil, *retrieved.ExecutionStreamUUID)

// Calling again should produce the same UUID
retrieved2, err := service.GetByID(execution.ID)
require.NoError(t, err)
assert.Equal(t, *retrieved.ExecutionStreamUUID, *retrieved2.ExecutionStreamUUID)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Assert against the canonical computed UUID, not only repeatability.

Lines 124-126 only prove the value is stable across calls. A wrong-but-deterministic seed composition would still pass. Add an explicit expected-value assertion and a nil guard for the second retrieval pointer before dereference.

Proposed test hardening
 	// ExecutionStreamUUID must be populated and deterministic
 	require.NotNil(t, retrieved.ExecutionStreamUUID)
 	assert.NotEqual(t, uuid.Nil, *retrieved.ExecutionStreamUUID)
+	expected := ComputeExecutionStreamUUID(*workflowDef.ID, *instance.ID, *execution.ID)
+	assert.Equal(t, expected, *retrieved.ExecutionStreamUUID)

 	// Calling again should produce the same UUID
 	retrieved2, err := service.GetByID(execution.ID)
 	require.NoError(t, err)
+	require.NotNil(t, retrieved2.ExecutionStreamUUID)
 	assert.Equal(t, *retrieved.ExecutionStreamUUID, *retrieved2.ExecutionStreamUUID)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/relational/workflows/workflow_execution_service_test.go`
around lines 119 - 127, The test currently only asserts stability of
ExecutionStreamUUID across fetches; update it to also assert the canonical
expected UUID and guard against nil on the second retrieval. After calling
retrieved2, require.NoError(t, err) (already present) and add require.NotNil(t,
retrieved2.ExecutionStreamUUID) before dereferencing it, then compute the
expected UUID using the same deterministic generator the service uses (e.g., the
function that produces the execution stream UUID in your implementation — call
it directly, e.g., computeExecutionStreamUUID(execution) or
ExecutionStreamUUIDFor(execution)) and assert assert.Equal(t, expectedUUID,
*retrieved2.ExecutionStreamUUID) instead of only comparing retrieved to
retrieved2.

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.

1 participant