Skip to content

Propagate tags from entity-started orchestrations - #812

Open
wangbill (YunchuWang) wants to merge 2 commits into
mainfrom
yunchuwang-entity-tags-sdk-e2e
Open

wangbill (YunchuWang) wants to merge 2 commits into
mainfrom
yunchuwang-entity-tags-sdk-e2e

Conversation

@YunchuWang

@YunchuWang wangbill (YunchuWang) commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

Summary

What changed?

  • Snapshot StartOrchestrationOptions.Tags in the actual entity shim and carry tags through both Core/protobuf operation-action conversions.
  • Import the canonical optional StartNewOrchestrationAction.tags = 8 schema and record its upstream commit in versions.txt.
  • Reject runtime null tag keys/values during scheduling, so normal entity-operation failure and rollback happen before batch serialization or extended-session cache publication. Valid Unicode and empty strings remain supported.
  • Add 29 regression cases covering both scheduling overloads, null/empty tags, existing name/ID/version/input/timing/trace fields, dictionary reuse/mutation, transactional rollback, cached execution, and serialized public GrpcEntityRunner request/response and protocol round trips. Document snapshot behavior without changing public signatures.
  • Address the dependency review in 5c304330dde4a2044f1ef35da288966aa31e9a89: restore Directory.Packages.props byte-for-byte to PR baseline fb044a3c84ec093a30c3a4f5c7bb295357eec1c0, retaining released Core 3.9.0. This manifest now has no aggregate PR diff; no preview/speculative package reference or validation override is committed.

Why is this change needed?

  • Entity-scheduled orchestration tags are currently dropped before reaching the scheduler, preventing metadata display and tag searches. Prerequisites must be released and the native receiver rolled out before enabling this sender end to end.

Issues / work items

  • Resolves #807 -- SDK portion; native backend consumption/persistence and dependency releases remain separate gates.
  • Related #399, #559.

Companion PRs and release order

Companion Responsibility
microsoft/durabletask-protobuf#80 Canonical optional entity-start tags field8. Current companion head 3455f719b18ed156bbbc008d757821e72f58d63b; schema blob remains 2429fff4696ea9e8615e7f39f8960fcaf7b73a93, identical to the SDK's recorded import from 8188ba772b1c9e2b47e2ce51ae528149867f0f09.
Azure/durabletask#1412 Core action property and wrapped-Core tag merging; source 76a6f9e0c4fddc04e4f1c9178ef3d9739184349e.
#812 (this PR) SDK snapshotting and both protocol conversions.
Azure/azure-functions-durable-extension#3566 Functions consumer, host bridge, and separate wrapped-Core provider path.
DTS native backend companion (private/internal PR; link omitted from public GitHub) Native entity-start receiver consumption/persistence; approved rollout is required. No private URL, ID, repository, code, or logs are disclosed here.
  1. Merge the canonical protocol contract first; this is a contract change, not a NuGet release.
  2. After the protocol, merge/release the Core prerequisite and complete the approved receiver-first DTS backend rollout; these can proceed in parallel. The native backend has no dependency on the new Core NuGet package.
  3. Only after the actual Core package is published, update the SDK Core dependency to that real released version, obtain green CI, and release the tag-aware SDK. Do not guess or commit a future release version.
  4. Only after Core and the tag-aware SDK are actually published, update Functions dependencies to their real released versions, obtain green CI, and release the extension.

The native receiver must be deployed before SDK senders are enabled, otherwise correct field8 tags can still be dropped. Package version changes happen only after the prerequisite is actually released. Local validation overrides stay outside source control and do not bypass public CI or release gates.


Project checklist

  • Release notes are not required for the next release
    • Otherwise: Notes added to release_notes.md
  • Backport is not required
    • Otherwise: Backport tracked by issue/PR #issue_or_pr
  • All required tests have been added/updated (unit tests, E2E tests)
  • Breaking change?
    • If yes:
      • Impact:
      • Migration guidance:

AI-assisted code disclosure (required)

Was an AI tool used? (select one)

  • No
  • Yes, AI helped write parts of this PR (e.g., GitHub Copilot)
  • Yes, an AI agent generated most of this PR

If AI was used:

  • Tool(s): GitHub Copilot App.
  • AI-assisted areas/files: Entity shim, shared protocol conversions, focused tests, XML documentation, canonical schema refresh, isolated Azure validation harness, and reviewed manifest restoration.
  • What you changed after AI output: Agent refined snapshot-time null validation/rollback coverage, preserved existing mixed line endings and legacy comment bytes, adjusted the historical harness for numeric versions/ID-length constraints, and restored the released Core manifest following review. No human post-generation edits are claimed.

AI verification (required if AI was used):

  • I understand the code and can explain it
  • I verified referenced APIs/types exist and are correct
  • I reviewed edge cases/failure paths (timeouts, retries, cancellation, exceptions)
  • I reviewed concurrency/async behavior
  • I checked for unintended breaking or behavior changes

Testing

Automated tests

Fresh review validation -- October 7, source 5c304330dde4a2044f1ef35da288966aa31e9a89

Passed with an explicit build-only local Core override; not a default/public-CI pass. The committed/default manifest retains Core 3.9.0, which lacks the new action Tags API. This draft stays blocked until the Core prerequisite is actually published and the SDK dependency is then updated to its real released version.

The uncommitted session artifact review-812.Directory.Packages.props imports the repository's unchanged Directory.Packages.props and updates only the local build's Core reference to 3.10.1-entitytags807.local from Core source 76a6f9e0c4fddc04e4f1c9178ef3d9739184349e. Its package SHA256 is A3812665B2AF7DB313AD8122884E62156270667038EC62DC8F8868FF0F861DAF. Restore uses the explicit session-local feed and isolated NUGET_PACKAGES cache, never an official package shadow or version-warning suppression. SubOutRoot=review-812 keeps these outputs separate from the original Azure-bound build.

With $OVERRIDE pointing to that session-only props file, $LOCAL_CONFIG to the existing explicit local-feed NuGet config, and $RESULTS to the session's review-812-results:

dotnet restore test\Worker\Core.Tests\Worker.Tests.csproj --configfile "$LOCAL_CONFIG" --verbosity quiet -p:DirectoryPackagesPropsPath="$OVERRIDE" -p:SubOutRoot=review-812
dotnet restore test\Worker\Grpc.Tests\Worker.Grpc.Tests.csproj --configfile "$LOCAL_CONFIG" --verbosity quiet -p:DirectoryPackagesPropsPath="$OVERRIDE" -p:SubOutRoot=review-812

Both restores passed.

dotnet test test\Worker\Core.Tests\Worker.Tests.csproj --configuration Release --no-restore --verbosity quiet --filter "FullyQualifiedName~TaskEntityShimTests" --logger "trx;LogFileName=shim.trx" --results-directory "$RESULTS" -p:DirectoryPackagesPropsPath="$OVERRIDE" -p:SubOutRoot=review-812
dotnet test test\Worker\Grpc.Tests\Worker.Grpc.Tests.csproj --configuration Release --no-restore --verbosity quiet --filter "FullyQualifiedName~GrpcEntityRunnerTagTests|FullyQualifiedName~ProtoUtilsEntityActionTests" --logger "trx;LogFileName=grpc.trx" --results-directory "$RESULTS" -p:DirectoryPackagesPropsPath="$OVERRIDE" -p:SubOutRoot=review-812
dotnet build src\Worker\Grpc\Worker.Grpc.csproj --configuration Release --no-restore --verbosity quiet -p:DirectoryPackagesPropsPath="$OVERRIDE" -p:SubOutRoot=review-812
  • Actual shim tests: passed, 12/12.
  • Encoded public GrpcEntityRunner and protocol conversion tests: passed, 17/17.
  • Worker gRPC type build: passed for netstandard2.0/net6.0/net8.0/net10.0, 0 errors. Existing unrelated analyzer warnings remain.
  • git diff --cached --check -- passed. Manifest Git blob 7b634b8fc999cb4b54e3fc8327cbc956360832c2 exactly matches the PR baseline; git diff fb044a3c84ec093a30c3a4f5c7bb295357eec1c0..HEAD -- Directory.Packages.props is empty.

Historical October 6 validation -- source c6ef936bc02ea52a720f6014cab90ec70c2c8cf4 only

The original 416-test run and original packages are not validation/artifacts of the new review head:

  • dotnet test test\Worker\Core.Tests\Worker.Tests.csproj --configuration Release --no-restore --verbosity quiet -p:VersionSuffix=entitytags807.local -- historical pass, 149 tests.
  • dotnet test test\Worker\Grpc.Tests\Worker.Grpc.Tests.csproj --configuration Release --no-restore --verbosity quiet -p:VersionSuffix=entitytags807.local -- historical pass, 203 tests.
  • dotnet test test\Client\Grpc.Tests\Client.Grpc.Tests.csproj --configuration Release --no-restore --verbosity quiet -p:VersionSuffix=entitytags807.local -- historical pass, 64 tests.
  • Test-first evidence at the original source: shim tag tests initially failed 8/11; protocol/public-runner tests initially failed 8/16; null-value tests reproduced batch-serialization poisoning before the guard.
  • src\Grpc\refresh-protos.ps1 -branch 8188ba772b1c9e2b47e2ce51ae528149867f0f09 -- historical pass; exact schema blob verified and unchanged.
  • For the original eight Abstractions/Grpc/Client/Client.Grpc/Client.AzureManaged/Worker/Worker.Grpc/Worker.AzureManaged projects, dotnet pack $project --configuration Release --no-restore --verbosity quiet -p:VersionSuffix=entitytags807.local --output $LOCAL_FEED -- historical pass. All original 1.26.0-entitytags807.local package nuspec commits, 21 SourceLink documents, DLL hashes, and runtime identities remain bound to c6ef936bc02ea52a720f6014cab90ec70c2c8cf4. Their bytes were checked unchanged; nothing was repacked or relabeled as 5c304330....

Manual validation (only if runtime/behavior changed)

  • Environment (OS, .NET version, components): Historical October 6 run at SDK source c6ef936bc02ea52a720f6014cab90ec70c2c8cf4, Windows/.NET SDK 10.0.401, real Azure DTS Consumption scheduler in centraluseuap, newly-created isolated authorized hub, Azure CLI identity, standard https://durabletask.io audience. No emulator, copied secrets, private service deployment, or primary-checkout builds. No new Azure run/deployment was performed for this manifest-only review change.
  • Steps + observed results:
    1. Historical authenticated baseline GetInstanceAsync probe -- passed, zero instances created. The original combined Core/protocol/SDK artifacts were verified by loaded DLL hashes, informational commits/MVIDs, and field8 before the Azure run.
    2. Historical pwsh -NoProfile -File $HARNESS\run-e2e.ps1 -- FAIL: 84 checks passed, exactly 3 tag-persistence assertions failed. Six real native entity-triggered child orchestrations completed. Name, numeric version 807.0.0, input, future StartAt, emitted dictionary snapshots, no-tags/null/empty starts, transactional rollback, null-value rejection, and repeated no-orphan checks passed. Correct outgoing /TaskHubSidecarService/CompleteEntityTask field8 maps for the tagged start and both snapshots yielded persisted tags: {}. Client-start control tags persisted. Native inheritance was not surfaced; no native inheritance/override success is claimed.
    3. Historical authenticated dashboard searches by key, unique value, and exact key/value at 2026-10-06T22:25:18Z each returned totalCount 1, the completed client control only, not the entity child. Strict assertions requiring both IDs failed. Final unfiltered query at 22:27:04Z returned both completed instances with control tags present/entity tags empty; a synthetic negative filter returned 0. This proves missing persisted tags, not query/authentication failure or missing orchestration execution.
  • Evidence (optional): Original JSONL and dashboard JSONs preserve redacted outgoing payloads versus persisted metadata, loaded identities, assertions, and cleanup. All original Azure/provenance evidence remains explicitly historical at c6ef936...; it is not a new-review-head or deployed-backend success claim. Endpoint/hub/tenant/subscription/instance suffixes are redacted here.
  • Historical cleanup: Worker stopped; five nonretained children, parent, and exact uniquely-created entity purged/absence verified. Control/entity fixtures remained only for coordinator queries, followed by coordinator-owned isolated-hub deletion. No shared scheduler or other hub was changed.

Notes for reviewers

  • Ready for review / not merge-ready. Committed dependencies remain their released baselines. The normal/default Core 3.9.0 cannot compile the new action Tags API; no default/public-CI success is claimed. Only after Core is actually published should this SDK manifest be updated to the real released version, CI made green, and the SDK released. Local overrides are not committed and are not a CI bypass.
  • The native receiver must complete its approved rollout before senders are enabled. Historical correct field8 payloads did not produce persisted/searchable native tags; this PR does not deploy the receiver and does not claim that the backend is fixed/deployed.
  • The Functions provider's wrapped-Core-generated ExecutionStarted path is separate from native EntityBatchResult. Core action/merging tests and local provider/bridge tests cover that wrapped path within their stated scope, not deployment or persistence of the Azure native receiver. The native failure does not by itself prove the wrapped Functions path fails or passes.
  • Size risk remains: tag dictionaries add bytes to actions and batches. Existing transport/message limits still apply; large tags/batches and load behavior are not proven by these small synthetic cases. No new global tag limits or silently dropped values were added.
  • No breaking change: public TaskEntityContext and StartOrchestrationOptions signatures remain unchanged; the optional map only adds field8 and preserves existing field numbers/empty-map bytes. No orchestrator replay logic or JSON converter defaults changed. Null tag values fail consistently with existing client constraints inside the transactional operation.
  • No reflective/conditional compatibility workaround was added. Tags were not moved into input. No packages were published, no source release version was invented, no private backend identifiers/code/logs were disclosed, and no PR was merged.

Snapshot and validate entity scheduling tags, carry them through both gRPC action conversions, and import the pinned canonical field8 schema. Cover both overloads, mutation, rollback, cached execution, and wire round trips with the explicit unpublished Core PR dependency.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d59e0dc-efdb-4b0a-b588-6dbd83416193
Comment thread Directory.Packages.props
Restore Directory.Packages.props to the exact PR baseline. Validate tag propagation only with an explicit session-local build override; update the SDK dependency to a real published Core version after the prerequisite release.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3d59e0dc-efdb-4b0a-b588-6dbd83416193
@YunchuWang
wangbill (YunchuWang) marked this pull request as ready for review October 7, 2026 19:42
Copilot AI balanced review requested due to automatic review settings October 7, 2026 19:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The committed Core 3.9.0 dependency lacks the new Tags API, causing default builds and CI to fail.

1 open finding
What changed in this PR

Propagates tags from entity-scheduled orchestrations through the Core and protobuf layers.

Changes:

  • Snapshots and validates tags during entity scheduling.
  • Adds protobuf field 8 and bidirectional conversion.
  • Adds comprehensive regression coverage.
File Description
src/​Abstractions/​Entities/​TaskEntityContext.cs Documents tag snapshot and validation behavior.
src/​Grpc/​orchestrator_service.proto Adds the optional tags map.
src/​Grpc/​versions.txt Records updated protobuf provenance.
src/​Shared/​Grpc/​ProtoUtils.cs Converts tags between Core and protobuf.
src/​Worker/​Core/​Shims/​TaskEntityShim.cs Snapshots and validates scheduled tags.
test/​Worker/​Core.Tests/​Shims/​TaskEntityShimTests.cs Tests shim behavior and rollback.
test/​Worker/​Grpc.Tests/​GrpcEntityRunnerTagTests.cs Tests serialized entity execution.
test/​Worker/​Grpc.Tests/​ProtoUtilsEntityActionTests.cs Tests protocol conversions and schema.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Version = options?.Version ?? string.Empty,
InstanceId = instanceId,
Input = this.dataConverter.Serialize(input),
Tags = options?.Tags?.ToDictionary(tag => tag.Key, tag => Check.NotNull(tag.Value)),
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.

Support for Tags in TaskEntityContext.ScheduleNewOrchestration

2 participants