From 5458928a06ca320e8fae6cc0d70e39139a4cad95 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 26 Oct 2026 13:45:07 +0000 Subject: [PATCH 1/6] fix(ci): re-pin the 3.10 candidate to run 40202201744 Point the Feedz/nuget.org pin at the successful prepare-consolidated-release-candidate run from release/3.10.0. The 231-ID and Studio content guards pass on that archive. Refs #9016 Co-authored-by: Sipke Schoorstra (cherry picked from commit 21429f635296db98e374cd06c9ef140078ecb6e3) --- .agents/skills/elsa-release/SKILL.md | 4 +- .../skills/elsa-release/references/runbook.md | 20 +- ...onsolidated-package-recovery-preflight.yml | 32 +- ...table-persisted-workflow-upgrade-proof.yml | 30 +- .../guides/admission-connections-packages.md | 2 +- ...solidated-release-and-publisher-cutover.md | 2 +- .../consolidated-package-recovery.md | 6 +- .../consolidation/package-publisher-gates.md | 6 +- .../consolidated-pin-inventory-baseline.json | 1385 +++++++++-------- .../consolidated_candidate_input.py | 23 +- .../consolidated_package_executor.py | 2 +- .../consolidated_package_recovery.py | 13 +- .../persisted-workflow-upgrade/README.md | 6 +- .../stable-original-envelope.json | 2 +- .../test_consolidated_candidate_clock.py | 4 +- ..._consolidated_executor_approval_summary.py | 16 +- .../test_consolidated_package_executor.py | 60 +- .../test_consolidated_package_recovery.py | 29 +- .../test_consolidated_recovery_inputs.py | 4 +- ...able_persisted_workflow_upgrade_fixture.py | 4 +- scripts/test_validate_packages_id_set.py | 34 +- 21 files changed, 899 insertions(+), 785 deletions(-) diff --git a/.agents/skills/elsa-release/SKILL.md b/.agents/skills/elsa-release/SKILL.md index 80c9037b5c..1bbf50aca6 100644 --- a/.agents/skills/elsa-release/SKILL.md +++ b/.agents/skills/elsa-release/SKILL.md @@ -14,8 +14,8 @@ description: Release Elsa from elsa-core as one tag, one GitHub release and one ## What core publishes today (verify against `origin/main` before relying on it) - `.github/workflows/packages.yml` runs on `release: published`, pushes to `main` and `release/*`, and `workflow_dispatch`. A release or push only tests, builds and uploads the `elsa-nuget-packages` artifact. It never publishes. Publication needs an approved `workflow_dispatch` with `publish_preview_feedz` (Feedz: a branch, or a `3.10.x` prerelease tag) or `publish_nuget` (nuget.org: a release-version tag, including stable `3.10.x`). Stable 3.10.x Feedz is owned only by `publish-consolidated-original-candidate.yml`. -- Stable `3.10.x` nuget.org publishing is blocked until re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)). Both the `packages.yml` promote path and `publish-consolidated-original-candidate.yml` run `scripts/validate_packages_id_set.py` on the current pin (run/artifact `11412848210`, 225 packages) before any push, so that set cannot be published as 3.10.0. After #9016 re-pins a fresh candidate from the `release/3.10.0` tip, nuget.org promotion and the candidate Feedz publish can proceed. Neither workflow is part of the ordinary release-train helper. -- `studio-npm-pair.yml` only proves that the two Studio npm archives can be built and consumed locally. `packages.yml` `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz from a 3.10.x prerelease tag. Stable Feedz publication waits for the 231-ID nuget.org promote guard. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core`. Stable 3.10.x nuget.org publication is blocked until re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)) (part of [#8725](https://github.com/elsa-workflows/elsa-core/issues/8725)). +- Both the `packages.yml` promote path and `publish-consolidated-original-candidate.yml` run `scripts/validate_packages_id_set.py` on the current pin (run `40202201744`, artifact `12603436856`, 231 packages from `release/3.10.0` @ `f60c00766b107cb15038c77873d84779f0680722`) before any push. Neither workflow is part of the ordinary release-train helper. +- `studio-npm-pair.yml` only proves that the two Studio npm archives can be built and consumed locally. `packages.yml` `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz from a 3.10.x prerelease tag. Stable Feedz publication waits for the 231-ID nuget.org promote guard. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core`. Stable 3.10.x nuget.org publication uses the current 231-ID pin (part of [#8725](https://github.com/elsa-workflows/elsa-core/issues/8725)). - The Apps container workflow lived in `elsa-apps` and core has no replacement yet. The container stage is blocked until it is re-homed in core. ## Interpret the request diff --git a/.agents/skills/elsa-release/references/runbook.md b/.agents/skills/elsa-release/references/runbook.md index 14516ec8e6..4a1f71c5a4 100644 --- a/.agents/skills/elsa-release/references/runbook.md +++ b/.agents/skills/elsa-release/references/runbook.md @@ -9,7 +9,7 @@ Studio, Extensions and Apps are folded into `elsa-core`; a release is one `elsa- What `elsa-core` actually does today (check `origin/main` before relying on it): - `.github/workflows/packages.yml` builds and uploads packages on `release: published` and on pushes to `main` and `release/*`. Those events never publish. Publication is an approved `workflow_dispatch`: `publish_preview_feedz` (Feedz, from a branch or a `3.10.x` prerelease tag) or `publish_nuget` (nuget.org, from a release-version tag). Stable `3.10.x` Feedz is owned only by `publish-consolidated-original-candidate.yml`. -- Its `./build.sh Compile+Pack` packs Core only on branch pushes and non-`3.10.0` tags. A `3.10.0` tag `release` event (and a non-promote dispatch from that tag) packs the 231-ID set through `prepare_consolidated_release_candidate.py`. Stable `3.10.x` nuget.org publishing is blocked until re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)). A `publish_nuget` dispatch on a stable `3.10.x` tag does not pack: it downloads the current pin (run/artifact `11412848210`), verifies each `.nupkg` sha256 against that candidate's seal, and runs `scripts/validate_packages_id_set.py` (231 IDs plus the three Studio ClientLib assets per package) before any push. The Oct 6 225-package set fails that guard. That pin's archive size and expiry (`2026-11-05T12:13:30Z`) come from `stable-original-envelope.json`; the replacement candidate's expiry is unknown until it is built. After the freeze, once the [3.10] picks and advisory fixes have landed, #9016 builds a fresh candidate from the `release/3.10.0` tip and re-pins it. `Elsa.SamplePackage` is not packable. The five `Elsa.Secrets.*` IDs and the four `Elsa.Studio.Host.*` IDs stay unpackable and `Elsa.Templates` is not in core. The whole-product 3.10.0 candidate is [prepared without publishing](#consolidated-3100-candidate-preparation-nonpublishing); `publish-consolidated-original-candidate.yml` is the only Feedz publisher for those stable 3.10.x bytes and runs the same 231-ID guard before its Feedz push (also blocked until re-pin (#9016)). +- Its `./build.sh Compile+Pack` packs Core only on branch pushes and non-`3.10.0` tags. A `3.10.0` tag `release` event (and a non-promote dispatch from that tag) packs the 231-ID set through `prepare_consolidated_release_candidate.py`. A `publish_nuget` dispatch on a stable `3.10.x` tag does not pack: it downloads the current pin (run `40202201744`, artifact `12603436856`, source `f60c00766b107cb15038c77873d84779f0680722`), verifies each `.nupkg` sha256 against that candidate's seal, and runs `scripts/validate_packages_id_set.py` (231 IDs plus the three Studio ClientLib assets per package) before any push. That pin's archive size and expiry (`2026-11-24T15:03:46Z`) come from `stable-original-envelope.json`. `Elsa.SamplePackage` is not packable. The five `Elsa.Secrets.*` IDs and the four `Elsa.Studio.Host.*` IDs stay unpackable and `Elsa.Templates` is not in core. The whole-product 3.10.0 candidate is [prepared without publishing](#consolidated-3100-candidate-preparation-nonpublishing); `publish-consolidated-original-candidate.yml` is the only Feedz publisher for those stable 3.10.x bytes and runs the same 231-ID guard before its Feedz push. - `studio-npm-pair.yml` is a local proof of the two Studio npm archives. `packages.yml` `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz from a 3.10.x prerelease tag. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core`. Stable `3.10.x` stays fail-closed until the 231-ID nuget.org promote guard can pass. The pair builder accepts 3.8–3.10 versions only. - Core has no container-image publishing workflow. The Apps workflow it used lived in `elsa-apps`. @@ -30,7 +30,7 @@ Check: - All configured package workflow `base_version` values match the new release line before branch CI. Templates stable workflow policy is checked separately: its `BASE_VERSION` and embedded Core/Studio PackageReferences must match the requested stable version, while a prerelease source must be selected explicitly or from its release branch. Version tags drive named release artifacts, but the branch preview version must also be correct. Make routine preparation changes on the intended release branch when needed. - Before a Templates RC/preview run, inspect its release workflow's tag ancestry guard. It must accept the selected `origin/release/` or explicit prerelease source; if it only accepts `origin/main`, resolve that workflow/source mismatch in the Templates repository before publishing. Never claim a release-line source is runnable while the workflow silently rejects its tag. - The workflow subscribes once to `release: types: [published]`. GitHub `published` covers both stable and prereleases. Use `release.prerelease` or parsed package versions for distinctions, never `event.action == published` as a stable-only test. [GitHub reference](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#release). -- Named stable, RC and preview releases use the approved publication workflows, never the release event itself: nuget.org for release-version tags (stable `3.10.x` is blocked until re-pin (#9016)), Feedz for branches and `3.10.x` prerelease tags through `packages.yml`, and stable `3.10.x` Feedz publication through `publish-consolidated-original-candidate.yml` (also blocked until re-pin (#9016)). Automated branch previews are separate, Feedz-only builds. Studio npm `next`/`latest` publication does not exist in core yet (pending #8725); do not expect it. If the source workflow disagrees with this policy, resolve the mismatch before release; do not weaken verification to match missing output. +- Named stable, RC and preview releases use the approved publication workflows, never the release event itself: nuget.org for release-version tags (stable `3.10.x` uses the pinned 231-ID candidate), Feedz for branches and `3.10.x` prerelease tags through `packages.yml`, and stable `3.10.x` Feedz publication through `publish-consolidated-original-candidate.yml`. Automated branch previews are separate, Feedz-only builds. Studio npm `next`/`latest` publication does not exist in core yet (pending #8725); do not expect it. If the source workflow disagrees with this policy, resolve the mismatch before release; do not weaken verification to match missing output. - Identify advisories and build/test prerequisites early. Assess actual usage and document disposition; a known warning from a prior release is evidence, not permanent acceptance. Keep unrelated upgrades out of the release. New material unresolved risks or failures require an explicit resolution before irreversible publication. Before creating a named release, perform a publishing credential preflight for @@ -429,16 +429,12 @@ publication. The #8629 proof-version persisted matrix cannot certify different stable candidate bytes: applicable persisted compatibility checks must bind to the admitted candidate production bytes before that candidate is published. `publish-consolidated-original-candidate.yml` is the only Feedz publisher for -those stable 3.10.x bytes. Stable 3.10.x nuget.org publishing is blocked until -re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)). A -`packages.yml` nuget.org dispatch on a stable 3.10.x tag downloads the current -pin (run/artifact `11412848210`), verifies each `.nupkg` sha256 against the -candidate seal, and runs the same 231-ID and Studio content guards that the -candidate Feedz publisher runs before its push. The current 225-package set -fails that guard, so neither path can publish 3.10.0 until #9016 re-pins a -fresh candidate from the `release/3.10.0` tip. The promote path does not -restore, build, or pack. `3.10.1` and later stay blocked until a new pin -exists. +those stable 3.10.x bytes. A `packages.yml` nuget.org dispatch on a stable +3.10.x tag downloads the current pin (run `40202201744`, artifact +`12603436856`), verifies each `.nupkg` sha256 against the candidate seal, and +runs the same 231-ID and Studio content guards that the candidate Feedz +publisher runs before its push. The promote path does not restore, build, or +pack. `3.10.1` and later stay blocked until a new pin exists. This task implements no publisher handoff. Ordinary approved Core publication selection remains a `packages.yml` dispatch: branch previews and 3.10.x diff --git a/.github/workflows/consolidated-package-recovery-preflight.yml b/.github/workflows/consolidated-package-recovery-preflight.yml index 786f6cc097..084b5f5892 100644 --- a/.github/workflows/consolidated-package-recovery-preflight.yml +++ b/.github/workflows/consolidated-package-recovery-preflight.yml @@ -28,26 +28,26 @@ jobs: run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/recovery-input" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/11412848210 > "$RUNNER_TEMP/recovery-input/artifact.json" - gh api repos/elsa-workflows/elsa-core/actions/runs/37456860080/attempts/1 > "$RUNNER_TEMP/recovery-input/producer-run.json" - jq -e '.id == 37456860080 and .run_attempt == 1 and - .head_sha == "ba5b348aa2414fdf7c19d9d8806e87b7c91a4205" and .conclusion == "success" and + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856 > "$RUNNER_TEMP/recovery-input/artifact.json" + gh api repos/elsa-workflows/elsa-core/actions/runs/40202201744/attempts/1 > "$RUNNER_TEMP/recovery-input/producer-run.json" + jq -e '.id == 40202201744 and .run_attempt == 1 and + .head_sha == "f60c00766b107cb15038c77873d84779f0680722" and .conclusion == "success" and (.event == "push" or .event == "workflow_dispatch") and .path == ".github/workflows/prepare-consolidated-release-candidate.yml"' "$RUNNER_TEMP/recovery-input/producer-run.json" > /dev/null - jq -e '.id == 11412848210 and - .name == "consolidated-candidate-ba5b348aa2414fdf7c19d9d8806e87b7c91a4205-37456860080-1" and - .expired == false and .expires_at == "2026-11-05T12:13:30Z" and - .digest == "sha256:ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f" and - .size_in_bytes == 92659861 and .workflow_run.id == 37456860080 and - .workflow_run.head_sha == "ba5b348aa2414fdf7c19d9d8806e87b7c91a4205"' "$RUNNER_TEMP/recovery-input/artifact.json" > /dev/null - test "$(date -u -d '2026-11-05T12:13:30Z' +%s)" -gt "$(date -u +%s)" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/11412848210/zip > "$RUNNER_TEMP/recovery-input/candidate.zip" - test "$(stat -c %s "$RUNNER_TEMP/recovery-input/candidate.zip")" -eq 92659861 + jq -e '.id == 12603436856 and + .name == "consolidated-candidate-f60c00766b107cb15038c77873d84779f0680722-40202201744-1" and + .expired == false and .expires_at == "2026-11-24T15:03:46Z" and + .digest == "sha256:13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d" and + .size_in_bytes == 96125850 and .workflow_run.id == 40202201744 and + .workflow_run.head_sha == "f60c00766b107cb15038c77873d84779f0680722"' "$RUNNER_TEMP/recovery-input/artifact.json" > /dev/null + test "$(date -u -d '2026-11-24T15:03:46Z' +%s)" -gt "$(date -u +%s)" + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856/zip > "$RUNNER_TEMP/recovery-input/candidate.zip" + test "$(stat -c %s "$RUNNER_TEMP/recovery-input/candidate.zip")" -eq 96125850 printf '%s %s\n' \ - 'ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f' \ + '13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d' \ "$RUNNER_TEMP/recovery-input/candidate.zip" | sha256sum --check --status jq -nc --arg observed "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - '{schema:1,artifact_id:11412848210,archive_sha256:"ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f",retrieved_at:$observed}' \ + '{schema:1,artifact_id:12603436856,archive_sha256:"13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d",retrieved_at:$observed}' \ > "$RUNNER_TEMP/recovery-input/live-retrieval.json" - name: Transfer only the verified original inputs id: transfer @@ -92,7 +92,7 @@ jobs: run: | python -m unittest test_verify_packages test_release_train python -O -m unittest test_verify_packages test_release_train - - name: Rehearse all 225 original package pairs with a simulated feed + - name: Rehearse all 231 original package pairs with a simulated feed run: >- python scripts/integration-program/run_consolidated_recovery_fixture.py --inputs "$RUNNER_TEMP/recovery-input" diff --git a/.github/workflows/stable-persisted-workflow-upgrade-proof.yml b/.github/workflows/stable-persisted-workflow-upgrade-proof.yml index 33ab214336..0c5e7afbbb 100644 --- a/.github/workflows/stable-persisted-workflow-upgrade-proof.yml +++ b/.github/workflows/stable-persisted-workflow-upgrade-proof.yml @@ -35,26 +35,26 @@ jobs: run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/upgrade-input" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/11412848210 > "$RUNNER_TEMP/upgrade-input/artifact.json" - gh api repos/elsa-workflows/elsa-core/actions/runs/37456860080/attempts/1 > "$RUNNER_TEMP/upgrade-input/producer-run.json" - jq -e '.id == 37456860080 and .run_attempt == 1 and - .head_sha == "ba5b348aa2414fdf7c19d9d8806e87b7c91a4205" and .conclusion == "success" and + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856 > "$RUNNER_TEMP/upgrade-input/artifact.json" + gh api repos/elsa-workflows/elsa-core/actions/runs/40202201744/attempts/1 > "$RUNNER_TEMP/upgrade-input/producer-run.json" + jq -e '.id == 40202201744 and .run_attempt == 1 and + .head_sha == "f60c00766b107cb15038c77873d84779f0680722" and .conclusion == "success" and (.event == "push" or .event == "workflow_dispatch") and .path == ".github/workflows/prepare-consolidated-release-candidate.yml"' "$RUNNER_TEMP/upgrade-input/producer-run.json" > /dev/null - jq -e '.id == 11412848210 and - .name == "consolidated-candidate-ba5b348aa2414fdf7c19d9d8806e87b7c91a4205-37456860080-1" and - .expired == false and .expires_at == "2026-11-05T12:13:30Z" and - .digest == "sha256:ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f" and - .size_in_bytes == 92659861 and .workflow_run.id == 37456860080 and - .workflow_run.head_sha == "ba5b348aa2414fdf7c19d9d8806e87b7c91a4205"' "$RUNNER_TEMP/upgrade-input/artifact.json" > /dev/null - test "$(date -u -d '2026-11-05T12:13:30Z' +%s)" -gt "$(date -u +%s)" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/11412848210/zip > "$RUNNER_TEMP/upgrade-input/candidate.zip" - test "$(stat -c %s "$RUNNER_TEMP/upgrade-input/candidate.zip")" -eq 92659861 + jq -e '.id == 12603436856 and + .name == "consolidated-candidate-f60c00766b107cb15038c77873d84779f0680722-40202201744-1" and + .expired == false and .expires_at == "2026-11-24T15:03:46Z" and + .digest == "sha256:13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d" and + .size_in_bytes == 96125850 and .workflow_run.id == 40202201744 and + .workflow_run.head_sha == "f60c00766b107cb15038c77873d84779f0680722"' "$RUNNER_TEMP/upgrade-input/artifact.json" > /dev/null + test "$(date -u -d '2026-11-24T15:03:46Z' +%s)" -gt "$(date -u +%s)" + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856/zip > "$RUNNER_TEMP/upgrade-input/candidate.zip" + test "$(stat -c %s "$RUNNER_TEMP/upgrade-input/candidate.zip")" -eq 96125850 printf '%s %s\n' \ - 'ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f' \ + '13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d' \ "$RUNNER_TEMP/upgrade-input/candidate.zip" | sha256sum --check --status jq -nc --arg observed "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - '{schema:1,artifact_id:11412848210,archive_sha256:"ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f",retrieved_at:$observed}' \ + '{schema:1,artifact_id:12603436856,archive_sha256:"13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d",retrieved_at:$observed}' \ > "$RUNNER_TEMP/upgrade-input/live-retrieval.json" - name: Transfer only the verified original inputs id: transfer diff --git a/core/docs/guides/admission-connections-packages.md b/core/docs/guides/admission-connections-packages.md index fde010b6ad..02cc097714 100644 --- a/core/docs/guides/admission-connections-packages.md +++ b/core/docs/guides/admission-connections-packages.md @@ -2,7 +2,7 @@ These seven existing module identities are selected for the consolidated Core 3.10 line under [#8661](https://github.com/elsa-workflows/elsa-core/issues/8661). Their projects use the normal Core library packaging convention, inheriting target frameworks `net8.0`, `net9.0` and `net10.0`. This source baseline preserves existing APIs and schemas; it does not claim that the new packages have passed evaluated MSBuild, archive or PostgreSQL consumer verification. Exact-head hosted evidence is required for that acceptance. -Use one tested head and version for the entire internal dependency closure. The accepted [lockstep/Core publisher policy](../../../docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md) applies: no independent version streams, historical candidate modification or publication is authorized by enabling these projects. The original stable candidate `11412848210` excludes these identities and cannot be reused as their package evidence. SQLite Connections persistence and other optional providers remain outside this promotion. +Use one tested head and version for the entire internal dependency closure. The accepted [lockstep/Core publisher policy](../../../docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md) applies: no independent version streams, historical candidate modification or publication is authorized by enabling these projects. The Oct 6 candidate `11412848210` excluded these identities. The current pin (`12603436856`) includes them. SQLite Connections persistence and other optional providers remain outside this promotion. ## Public setup and contract baseline diff --git a/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md b/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md index f4e92fe891..667d6ddb14 100644 --- a/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md +++ b/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md @@ -21,7 +21,7 @@ Two publishers for one package ID and version line would let them race or overwr - disable the original repositories' publishing for 3.10 and later. From then on, each package ID has one publisher per version line. Stable 3.10.x promotion of imported packages from elsa-core is allowed only after that cutover. -3. **Publication stays behind the existing gates, with one Feedz owner for stable 3.10.x.** The root workflow publishes only on an approved `workflow_dispatch` ([package publisher gates](../integration-program/consolidation/package-publisher-gates.md)). Branch previews and 3.10.x prerelease tags may publish to Feedz from `packages.yml`. Stable 3.10.x Feedz publication is owned only by `publish-consolidated-original-candidate.yml`. Stable 3.10.x nuget.org publishing is blocked until re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)): both that Feedz publisher and a `packages.yml` `publish_nuget` dispatch on a stable 3.10.x tag run the same 231-ID guard on the current pin (run/artifact `11412848210`, 225 packages) before any push. Other release-version tags still rebuild and publish from `packages.yml` as before. The imported Extensions and Studio `packages.yml` files stay inert at their `.source` paths. +3. **Publication stays behind the existing gates, with one Feedz owner for stable 3.10.x.** The root workflow publishes only on an approved `workflow_dispatch` ([package publisher gates](../integration-program/consolidation/package-publisher-gates.md)). Branch previews and 3.10.x prerelease tags may publish to Feedz from `packages.yml`. Stable 3.10.x Feedz publication is owned only by `publish-consolidated-original-candidate.yml`. Both that Feedz publisher and a `packages.yml` `publish_nuget` dispatch on a stable 3.10.x tag run the same 231-ID guard on the current pin (run `40202201744`, artifact `12603436856`, 231 packages) before any push. Other release-version tags still rebuild and publish from `packages.yml` as before. The imported Extensions and Studio `packages.yml` files stay inert at their `.source` paths. 4. **Deprecated packages get no consolidated version.** The legacy Extensions Secrets packages (`Elsa.Secrets.Api`, `.Core`, `.Management`, `.Models`, `.Scripting`) also carry their own `IsPackable=false`, so they stay out when the cutover lifts the product-wide setting. A guard test checks it. They are marked deprecated on NuGet at 3.10.0 and keep their 3.8.x versions ([upgrade guide](../../core/docs/migrations/secrets-legacy-extensions-upgrade.md)). 5. **The #8260 proof publishes nothing.** It runs on the import head with a clean local feed and consumer restores. No proof package goes to Feedz or NuGet.org. diff --git a/docs/integration-program/consolidated-package-recovery.md b/docs/integration-program/consolidated-package-recovery.md index 962967f0d1..e601fc86fc 100644 --- a/docs/integration-program/consolidated-package-recovery.md +++ b/docs/integration-program/consolidated-package-recovery.md @@ -2,11 +2,11 @@ [Task #8645](https://github.com/elsa-workflows/elsa-core/issues/8645) prepares read-only reconciliation for the original 3.10.0 candidate accepted by [#8631](https://github.com/elsa-workflows/elsa-core/issues/8631). It does not publish packages, complete the release, or authorize publisher cutover. -The planner always covers the complete retained manifest: 225 NuGet packages and their paired symbol archives, plus 124 exclusion rows representing 123 package IDs. Exclusions retain project identity. There is no package subset, version override or feed override. Maintenance release publishers remain unchanged. +The planner always covers the complete retained manifest: 231 NuGet packages and their paired symbol archives, plus 135 exclusion rows representing 134 package IDs. Exclusions retain project identity. There is no package subset, version override or feed override. Maintenance release publishers remain unchanged. ## Original inputs -Use the original archive from Core run `37456860080`, attempt `1`, artifact `11412848210`, source `ba5b348aa2414fdf7c19d9d8806e87b7c91a4205`. The archive SHA-256 is `ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f` and its size is 92,659,861 bytes. It expires on 2026-11-05 at 12:13:30 UTC. Expiry or deletion blocks this candidate; it never authorizes rebuilding equivalent-looking bytes. +Use the original archive from Core run `40202201744`, attempt `1`, artifact `12603436856`, source `f60c00766b107cb15038c77873d84779f0680722`. The archive SHA-256 is `13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d` and its size is 96,125,850 bytes. It expires on 2026-11-24 at 15:03:46 UTC. Expiry or deletion blocks this candidate; it never authorizes rebuilding equivalent-looking bytes. The input directory contains exactly: @@ -48,7 +48,7 @@ Production reads are fixed to the Elsa Feedz repository. GETs reject redirects a Raw local and remote archive SHA-256 values are distinct from signature-aware payload hashes. Signature normalization reuses the maintenance verifier and does not verify a signing certificate. Symbol archive hashes identify the original local pairs; remote symbol publication and retrieval remain unverified. -Any conflict or unverifiable package blocks reconciliation. `classification_complete` means every package has a classification other than unverifiable, so a complete ledger can still contain blocking conflicts. `content_converged` requires all 225 packages to match. Even a fully matching ledger always has `publication_ready: false` and `publication_performed: false`. +Any conflict or unverifiable package blocks reconciliation. `classification_complete` means every package has a classification other than unverifiable, so a complete ledger can still contain blocking conflicts. `content_converged` requires all 231 packages to match. Even a fully matching ledger always has `publication_ready: false` and `publication_performed: false`. Intended-reader access, remote symbols, publisher authority, publisher quiescence, publication approval and full compatibility remain separate pending gates. The planner never treats a push exit status, `--skip-duplicate`, an anonymous absence or a previous successful invocation as permission to publish. Receipts retain fixed diagnostic categories and hashes, not credentials, response headers, raw server errors or private paths. diff --git a/docs/integration-program/consolidation/package-publisher-gates.md b/docs/integration-program/consolidation/package-publisher-gates.md index 921514a612..980a790a2b 100644 --- a/docs/integration-program/consolidation/package-publisher-gates.md +++ b/docs/integration-program/consolidation/package-publisher-gates.md @@ -3,13 +3,13 @@ The Packages workflow now builds and tests normally on pushes and release events, but those events cannot publish packages or deploy coverage. The four publication jobs are default-off `workflow_dispatch` options: - `publish_preview_feedz` publishes the run's packages to Feedz. Dispatch from a branch for a preview build (`-preview.`), or from a 3.10.x prerelease tag. Stable 3.10.x Feedz is owned only by `publish-consolidated-original-candidate.yml`. -- `publish_nuget` publishes a release-tag package to NuGet.org. Dispatch from a release-version tag. Stable 3.10.x nuget.org publishing is blocked until re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)): the job downloads the current pin (run/artifact `11412848210`), verifies each `.nupkg` sha256 against the candidate seal, and runs the 231-ID list and Studio content guards on that exact set before any push. The current 225-package set fails that guard. Other tags push this run's pack. +- `publish_nuget` publishes a release-tag package to NuGet.org. Dispatch from a release-version tag. A stable 3.10.x nuget.org dispatch downloads the current pin (run `40202201744`, artifact `12603436856`, source `f60c00766b107cb15038c77873d84779f0680722`), verifies each `.nupkg` sha256 against the candidate seal, and runs the 231-ID list and Studio content guards on that exact set before any push. Other tags push this run's pack. - `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz. `build_npm` builds the pair without credentials. Dispatch from a release-version tag. Feedz npm is live for 3.10.x prerelease tags. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core` (#8725). Stable 3.10.x is rejected in the selection check and also fail-closed in the job. The pair builder accepts 3.8–3.10 versions only, so a 3.11+ tag fails that check. - `deploy_coverage` deploys the coverage report to GitHub Pages. Dispatch from `main` or `release/3.6.1`, the refs whose coverage run uploads a Pages artifact. A `3.10.0` tag `release` event (and a non-promote dispatch from that tag) packs through `prepare_consolidated_release_candidate.py` instead of Core-only `Compile+Pack`, then runs the 231-ID guard. The inventory baseline is per branch: `consolidated-candidate-inventory-baseline.json` on `release/3.10.0` is this branch's evaluation (231 packages / 135 exclusions). It is not main's inventory; the two are not the same. A dry-run of the Core-only path on `release/3.10.0` @ `ca7ac4ff` produced 109 IDs. -A tag dispatch accepts only release-version tags matching `^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$`, such as `3.8.4`, `3.8.0-rc2` or `3.10.0`. Tags such as `v3.10.0` or `test-1` are rejected whatever the options, and so is a 3.10 release spelled without the literal `3.10.` prefix (for example `03.10.0`). The tagged commit must also be contained in `main` or a `release/*` branch; the build checks this before packing. A stable 3.10.x nuget.org dispatch still runs this check but skips pack; publication of those bytes is blocked until re-pin ([#9016](https://github.com/elsa-workflows/elsa-core/issues/9016)). `3.10.1` and later cannot reach nuget.org or Feedz until a new pin exists. +A tag dispatch accepts only release-version tags matching `^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$`, such as `3.8.4`, `3.8.0-rc2` or `3.10.0`. Tags such as `v3.10.0` or `test-1` are rejected whatever the options, and so is a 3.10 release spelled without the literal `3.10.` prefix (for example `03.10.0`). The tagged commit must also be contained in `main` or a `release/*` branch; the build checks this before packing. A stable 3.10.x nuget.org dispatch still runs this check but skips pack; it publishes the pinned 231-ID candidate instead. `3.10.1` and later cannot reach nuget.org or Feedz until a new pin exists. Each option defaults to `false`. An authorized operator should set only the option approved for that run; the workflow run records the selected ref and inputs. Package publication and coverage deployment remain separate decisions. Builds and uploaded package artifacts remain available without opting in when their event already uploads them; a manual dispatch uploads package artifacts only when a publisher option is selected. @@ -24,7 +24,7 @@ Each option defaults to `false`. An authorized operator should set only the opti | Dispatch from a release tag | `publish_nuget` | yes, at the tag version | no | tag version | no | | Dispatch from a 3.10.x prerelease tag | `publish_preview_feedz` | yes, at the tag version | tag version | no | no | | Dispatch from a stable 3.10.x tag | `publish_preview_feedz` | rejected | no | no | no | -| Dispatch from a stable 3.10.0 tag | `publish_nuget` | no pack; retrieve + 231-ID guard (blocked until re-pin (#9016)) | no | blocked until re-pin (#9016) | no | +| Dispatch from a stable 3.10.0 tag | `publish_nuget` | no pack; retrieve + 231-ID guard | no | pinned 231-ID candidate | no | | Dispatch from a later stable 3.10.x tag (`3.10.1`, …) | `publish_nuget` | no pack; pin is 3.10.0 only | no | blocked until a new pin | no | | Dispatch from `main` or `release/3.6.1` | `deploy_coverage` | yes | no | no | deployed | | Dispatch from a 3.10.x prerelease tag | `publish_npm` | yes, at the tag version | Feedz npm | no | no | diff --git a/scripts/integration-program/consolidated-pin-inventory-baseline.json b/scripts/integration-program/consolidated-pin-inventory-baseline.json index f7b45f8e2d..768670618c 100644 --- a/scripts/integration-program/consolidated-pin-inventory-baseline.json +++ b/scripts/integration-program/consolidated-pin-inventory-baseline.json @@ -1,1535 +1,1614 @@ { "evidence": { - "archive_sha256": "8317e5766591f9da2d1f83cd6a85274bd41efbfbd0039d6a1bcfaf0c9bf81636", - "artifact_id": 11390805430, - "inventory_sha256": "5981ea53924127299dc165b9cee07de6450be9996c816249e2310cb987a2c6df", - "run_id": 37410240989, + "archive_sha256": "13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d", + "artifact_id": 12603436856, + "inventory_sha256": "56852c6a58d0949dca2aacb8c682f2652e6788634cbc1daf98c110177183f73c", + "run_id": 40202201744, "scope": "Reviewed inventory comparison only; never relabel or reuse as candidate bytes.", - "source_commit": "44083dc4f47d56aa2d5c215b0c7479c0b7290cb0", - "version": "3.10.0-proof.37410240989.1" + "source_commit": "f60c00766b107cb15038c77873d84779f0680722", + "version": "3.10.0" }, "exclusions": [ { - "id": "_build", - "project": "build/_build.csproj", + "id": "Elsa.Server.Shared", + "project": "apps/src/Elsa.Server.Shared/Elsa.Server.Shared.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Server.Web", - "project": "samples/extensions/workbench/Elsa.Server.Web/Elsa.Server.Web.csproj", + "id": "Elsa.Server.Studio.BlazorServer", + "project": "apps/src/Elsa.Server.Studio.BlazorServer/Elsa.Server.Studio.BlazorServer.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.ServerAndStudio.Web", - "project": "samples/extensions/workbench/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj", + "id": "Elsa.Server.Studio.BlazorWasm.Client", + "project": "apps/src/Elsa.Server.Studio.BlazorWasm.Client/Elsa.Server.Studio.BlazorWasm.Client.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "ElsaStudioWebAssembly", - "project": "samples/extensions/workbench/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj", + "id": "Elsa.Server.Studio.BlazorWasm", + "project": "apps/src/Elsa.Server.Studio.BlazorWasm/Elsa.Server.Studio.BlazorWasm.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "BlazorApp1", - "project": "samples/studio/BlazorApp1/BlazorApp1.csproj", + "id": "Elsa.Server", + "project": "apps/src/Elsa.Server/Elsa.Server.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.ModularServer.Web", - "project": "src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj", + "id": "Elsa.Studio.BlazorServer", + "project": "apps/src/Elsa.Studio.BlazorServer/Elsa.Studio.BlazorServer.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Server.LoadBalancer", - "project": "src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj", + "id": "Elsa.Studio.BlazorWasm.Client", + "project": "apps/src/Elsa.Studio.BlazorWasm.Client/Elsa.Studio.BlazorWasm.Client.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Server.Web", - "project": "src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj", + "id": "Elsa.Studio.BlazorWasm", + "project": "apps/src/Elsa.Studio.BlazorWasm/Elsa.Studio.BlazorWasm.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Api", - "project": "src/extensions/secrets/Elsa.Secrets.Api/Elsa.Secrets.Api.csproj", + "id": "Shared", + "project": "apps/src/Shared/Shared.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Core", - "project": "src/extensions/secrets/Elsa.Secrets.Core/Elsa.Secrets.Core.csproj", + "id": "_build", + "project": "build/_build.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Management", - "project": "src/extensions/secrets/Elsa.Secrets.Management/Elsa.Secrets.Management.csproj", + "id": "Elsa.ModularServer.Web", + "project": "core/src/apps/Elsa.ModularServer.Web/Elsa.ModularServer.Web.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Models", - "project": "src/extensions/secrets/Elsa.Secrets.Models/Elsa.Secrets.Models.csproj", + "id": "Elsa.SamplePackage", + "project": "core/src/apps/Elsa.SamplePackage/Elsa.SamplePackage.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Scripting", - "project": "src/extensions/secrets/Elsa.Secrets.Scripting/Elsa.Secrets.Scripting.csproj", + "id": "Elsa.Server.LoadBalancer", + "project": "core/src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Connections.Credentials.Persistence.EFCore.PostgreSql", - "project": "src/modules/Elsa.Connections.Credentials.Persistence.EFCore.PostgreSql/Elsa.Connections.Credentials.Persistence.EFCore.PostgreSql.csproj", + "id": "Elsa.Server.Web", + "project": "core/src/apps/Elsa.Server.Web/Elsa.Server.Web.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { "id": "Elsa.Connections.Credentials.Persistence.EFCore.Sqlite", - "project": "src/modules/Elsa.Connections.Credentials.Persistence.EFCore.Sqlite/Elsa.Connections.Credentials.Persistence.EFCore.Sqlite.csproj", + "project": "core/src/modules/Elsa.Connections.Credentials.Persistence.EFCore.Sqlite/Elsa.Connections.Credentials.Persistence.EFCore.Sqlite.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Connections.Credentials.Persistence.EFCore", - "project": "src/modules/Elsa.Connections.Credentials.Persistence.EFCore/Elsa.Connections.Credentials.Persistence.EFCore.csproj", + "id": "Elsa.Workflows.ComponentTests", + "project": "core/test/component/Elsa.Workflows.ComponentTests/Elsa.Workflows.ComponentTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Connections.Credentials.Workflows", - "project": "src/modules/Elsa.Connections.Credentials.Workflows/Elsa.Connections.Credentials.Workflows.csproj", + "id": "Elsa.AI.IntegrationTests", + "project": "core/test/integration/Elsa.AI.IntegrationTests/Elsa.AI.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Connections", - "project": "src/modules/Elsa.Connections/Elsa.Connections.csproj", + "id": "Elsa.Activities.IntegrationTests", + "project": "core/test/integration/Elsa.Activities.IntegrationTests/Elsa.Activities.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Core.Tests", - "project": "src/studio/framework/Elsa.Studio.Core.Tests/Elsa.Studio.Core.Tests.csproj", + "id": "Elsa.Alterations.IntegrationTests", + "project": "core/test/integration/Elsa.Alterations.IntegrationTests/Elsa.Alterations.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Host.CustomElements", - "project": "src/studio/hosts/Elsa.Studio.Host.CustomElements/Elsa.Studio.Host.CustomElements.csproj", + "id": "Elsa.Alterations.Persistence.ConformanceTests", + "project": "core/test/integration/Elsa.Alterations.Persistence.ConformanceTests/Elsa.Alterations.Persistence.ConformanceTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Host.HostedWasm", - "project": "src/studio/hosts/Elsa.Studio.Host.HostedWasm/Elsa.Studio.Host.HostedWasm.csproj", + "id": "Elsa.Bpmn.IntegrationTests", + "project": "core/test/integration/Elsa.Bpmn.IntegrationTests/Elsa.Bpmn.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Host.Server", - "project": "src/studio/hosts/Elsa.Studio.Host.Server/Elsa.Studio.Host.Server.csproj", + "id": "Elsa.Bpmn.Interchange.IntegrationTests", + "project": "core/test/integration/Elsa.Bpmn.Interchange.IntegrationTests/Elsa.Bpmn.Interchange.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Host.Wasm", - "project": "src/studio/hosts/Elsa.Studio.Host.Wasm/Elsa.Studio.Host.Wasm.csproj", + "id": "Elsa.Common.IntegrationTests", + "project": "core/test/integration/Elsa.Common.IntegrationTests/Elsa.Common.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.AI.Tests", - "project": "src/studio/modules/Elsa.Studio.AI.Tests/Elsa.Studio.AI.Tests.csproj", + "id": "Elsa.Connections.Credentials.Persistence.PostgreSql.IntegrationTests", + "project": "core/test/integration/Elsa.Connections.Credentials.Persistence.PostgreSql.IntegrationTests/Elsa.Connections.Credentials.Persistence.PostgreSql.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Administration.Tests", - "project": "src/studio/modules/Elsa.Studio.Administration.Tests/Elsa.Studio.Administration.Tests.csproj", + "id": "Elsa.Diagnostics.ConsoleLogs.IntegrationTests", + "project": "core/test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/Elsa.Diagnostics.ConsoleLogs.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Authentication.UI.Tests", - "project": "src/studio/modules/Elsa.Studio.Authentication.UI.Tests/Elsa.Studio.Authentication.UI.Tests.csproj", + "id": "Elsa.Diagnostics.OpenTelemetry.IntegrationTests", + "project": "core/test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Dashboard.Tests", - "project": "src/studio/modules/Elsa.Studio.Dashboard.Tests/Elsa.Studio.Dashboard.Tests.csproj", + "id": "Elsa.Diagnostics.StructuredLogs.IntegrationTests", + "project": "core/test/integration/Elsa.Diagnostics.StructuredLogs.IntegrationTests/Elsa.Diagnostics.StructuredLogs.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Diagnostics.ConsoleLogs.Tests", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.ConsoleLogs.Tests/Elsa.Studio.Diagnostics.ConsoleLogs.Tests.csproj", + "id": "Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests", + "project": "core/test/integration/Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests/Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Diagnostics.OpenTelemetry.Tests", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.OpenTelemetry.Tests/Elsa.Studio.Diagnostics.OpenTelemetry.Tests.csproj", + "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.IntegrationTests", + "project": "core/test/integration/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.IntegrationTests/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Diagnostics.StructuredLogs.Tests", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.StructuredLogs.Tests/Elsa.Studio.Diagnostics.StructuredLogs.Tests.csproj", + "id": "Elsa.Dsl.ElsaScript.IntegrationTests", + "project": "core/test/integration/Elsa.Dsl.ElsaScript.IntegrationTests/Elsa.Dsl.ElsaScript.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Environments.Tests", - "project": "src/studio/modules/Elsa.Studio.Environments.Tests/Elsa.Studio.Environments.Tests.csproj", + "id": "Elsa.ExternalAuthentication.IntegrationTests", + "project": "core/test/integration/Elsa.ExternalAuthentication.IntegrationTests/Elsa.ExternalAuthentication.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.ExternalAuthentication.Tests", - "project": "src/studio/modules/Elsa.Studio.ExternalAuthentication.Tests/Elsa.Studio.ExternalAuthentication.Tests.csproj", + "id": "Elsa.Hosts.SmokeTests", + "project": "core/test/integration/Elsa.Hosts.SmokeTests/Elsa.Hosts.SmokeTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Localization.Tests", - "project": "src/studio/modules/Elsa.Studio.Localization.Tests/Elsa.Studio.Localization.Tests.csproj", + "id": "Elsa.Http.IntegrationTests", + "project": "core/test/integration/Elsa.Http.IntegrationTests/Elsa.Http.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.PlatformIntegration.Tests", - "project": "src/studio/modules/Elsa.Studio.PlatformIntegration.Tests/Elsa.Studio.PlatformIntegration.Tests.csproj", + "id": "Elsa.JavaScript.IntegrationTests", + "project": "core/test/integration/Elsa.JavaScript.IntegrationTests/Elsa.JavaScript.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Secrets.Tests", - "project": "src/studio/modules/Elsa.Studio.Secrets.Tests/Elsa.Studio.Secrets.Tests.csproj", + "id": "Elsa.Labels.Persistence.ConformanceTests", + "project": "core/test/integration/Elsa.Labels.Persistence.ConformanceTests/Elsa.Labels.Persistence.ConformanceTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Security.Tests", - "project": "src/studio/modules/Elsa.Studio.Security.Tests/Elsa.Studio.Security.Tests.csproj", + "id": "Elsa.Resilience.IntegrationTests", + "project": "core/test/integration/Elsa.Resilience.IntegrationTests/Elsa.Resilience.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.UserTasks.Tests", - "project": "src/studio/modules/Elsa.Studio.UserTasks.Tests/Elsa.Studio.UserTasks.Tests.csproj", + "id": "Elsa.Secrets.Api.IntegrationTests", + "project": "core/test/integration/Elsa.Secrets.Api.IntegrationTests/Elsa.Secrets.Api.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Workflows.Designer.Tests", - "project": "src/studio/modules/Elsa.Studio.Workflows.Designer.Tests/Elsa.Studio.Workflows.Designer.Tests.csproj", + "id": "Elsa.Secrets.DefaultHost.IntegrationTests", + "project": "core/test/integration/Elsa.Secrets.DefaultHost.IntegrationTests/Elsa.Secrets.DefaultHost.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Workflows.Tests", - "project": "src/studio/modules/Elsa.Studio.Workflows.Tests/Elsa.Studio.Workflows.Tests.csproj", + "id": "Elsa.Workflows.IntegrationTests", + "project": "core/test/integration/Elsa.Workflows.IntegrationTests/Elsa.Workflows.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.ComponentTests", - "project": "test/component/Elsa.Workflows.ComponentTests/Elsa.Workflows.ComponentTests.csproj", + "id": "Elsa.Workflows.Persistence.ConformanceTests", + "project": "core/test/integration/Elsa.Workflows.Persistence.ConformanceTests/Elsa.Workflows.Persistence.ConformanceTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Actors.ProtoActor.UnitTests", - "project": "test/extensions/modules/actors/Elsa.Actors.ProtoActor.UnitTests/Elsa.Actors.ProtoActor.UnitTests.csproj", + "id": "Elsa.Workflows.PerformanceTests", + "project": "core/test/performance/Elsa.Workflows.PerformanceTests/Elsa.Workflows.PerformanceTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Studio.Agents.Tests", - "project": "test/extensions/modules/agents/Elsa.Studio.Agents.Tests/Elsa.Studio.Agents.Tests.csproj", + "id": "Elsa.AI.Abstractions.UnitTests", + "project": "core/test/unit/Elsa.AI.Abstractions.UnitTests/Elsa.AI.Abstractions.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Caching.Distributed.ProtoActor.IntegrationTests", - "project": "test/extensions/modules/caching/Elsa.Caching.Distributed.ProtoActor.IntegrationTests/Elsa.Caching.Distributed.ProtoActor.IntegrationTests.csproj", + "id": "Elsa.AI.Copilot.UnitTests", + "project": "core/test/unit/Elsa.AI.Copilot.UnitTests/Elsa.AI.Copilot.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.DevOps.GitHub.UnitTests", - "project": "test/extensions/modules/devops/Elsa.DevOps.GitHub.UnitTests/Elsa.DevOps.GitHub.UnitTests.csproj", + "id": "Elsa.AI.Host.UnitTests", + "project": "core/test/unit/Elsa.AI.Host.UnitTests/Elsa.AI.Host.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Logging.Core.IntegrationTests", - "project": "test/extensions/modules/diagnostics/Elsa.Logging.Core.IntegrationTests/Elsa.Logging.Core.IntegrationTests.csproj", + "id": "Elsa.AI.Persistence.EFCore.UnitTests", + "project": "core/test/unit/Elsa.AI.Persistence.EFCore.UnitTests/Elsa.AI.Persistence.EFCore.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Logging.Core.UnitTests", - "project": "test/extensions/modules/diagnostics/Elsa.Logging.Core.UnitTests/Elsa.Logging.Core.UnitTests.csproj", + "id": "Elsa.Activities.UnitTests", + "project": "core/test/unit/Elsa.Activities.UnitTests/Elsa.Activities.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Ldap.UnitTests", - "project": "test/extensions/modules/ldap/Elsa.Ldap.UnitTests/Elsa.Ldap.UnitTests.csproj", + "id": "Elsa.Alterations.Core.UnitTests", + "project": "core/test/unit/Elsa.Alterations.Core.UnitTests/Elsa.Alterations.Core.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Mqtt.UnitTests", - "project": "test/extensions/modules/mqtt/Elsa.Mqtt.UnitTests/Elsa.Mqtt.UnitTests.csproj", + "id": "Elsa.Api.Common.UnitTests", + "project": "core/test/unit/Elsa.Api.Common.UnitTests/Elsa.Api.Common.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Dapper.UnitTests", - "project": "test/extensions/modules/persistence/Elsa.Dapper.UnitTests/Elsa.Dapper.UnitTests.csproj", + "id": "Elsa.Bpmn.Interchange.UnitTests", + "project": "core/test/unit/Elsa.Bpmn.Interchange.UnitTests/Elsa.Bpmn.Interchange.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.MongoDb.UnitTests", - "project": "test/extensions/modules/persistence/Elsa.MongoDb.UnitTests/Elsa.MongoDb.UnitTests.csproj", + "id": "Elsa.Bpmn.UnitTests", + "project": "core/test/unit/Elsa.Bpmn.UnitTests/Elsa.Bpmn.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Persistence.Dapper.UnitTests", - "project": "test/extensions/modules/persistence/Elsa.Persistence.Dapper.UnitTests/Elsa.Persistence.Dapper.UnitTests.csproj", + "id": "Elsa.Common.UnitTests", + "project": "core/test/unit/Elsa.Common.UnitTests/Elsa.Common.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.Runtime.ProtoActor.UnitTests", - "project": "test/extensions/modules/runtimes/Elsa.Workflows.Runtime.ProtoActor.UnitTests/Elsa.Workflows.Runtime.ProtoActor.UnitTests.csproj", + "id": "Elsa.Connections.UnitTests", + "project": "core/test/unit/Elsa.Connections.UnitTests/Elsa.Connections.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Scheduling.Hangfire.UnitTests", - "project": "test/extensions/modules/scheduling/Elsa.Scheduling.Hangfire.UnitTests/Elsa.Scheduling.Hangfire.UnitTests.csproj", + "id": "Elsa.Dashboard.Api.UnitTests", + "project": "core/test/unit/Elsa.Dashboard.Api.UnitTests/Elsa.Dashboard.Api.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Scheduling.Quartz.ComponentTests", - "project": "test/extensions/modules/scheduling/Elsa.Scheduling.Quartz.ComponentTests/Elsa.Scheduling.Quartz.ComponentTests.csproj", + "id": "Elsa.Diagnostics.ConsoleLogs.UnitTests", + "project": "core/test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Elsa.Diagnostics.ConsoleLogs.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Scheduling.Quartz.UnitTests", - "project": "test/extensions/modules/scheduling/Elsa.Scheduling.Quartz.UnitTests/Elsa.Scheduling.Quartz.UnitTests.csproj", + "id": "Elsa.Diagnostics.OpenTelemetry.UnitTests", + "project": "core/test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Management.UnitTests", - "project": "test/extensions/modules/secrets/Elsa.Secrets.Management.UnitTests/Elsa.Secrets.Management.UnitTests.csproj", + "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Relational.UnitTests", + "project": "core/test/unit/Elsa.Diagnostics.StructuredLogs.Persistence.Relational.UnitTests/Elsa.Diagnostics.StructuredLogs.Persistence.Relational.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.ServiceBus.AzureServiceBus.ComponentTests", - "project": "test/extensions/modules/servicebus/Elsa.ServiceBus.AzureServiceBus.ComponentTests/Elsa.ServiceBus.AzureServiceBus.ComponentTests.csproj", + "id": "Elsa.Diagnostics.StructuredLogs.UnitTests", + "project": "core/test/unit/Elsa.Diagnostics.StructuredLogs.UnitTests/Elsa.Diagnostics.StructuredLogs.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.ServiceBus.MassTransit.UnitTests", - "project": "test/extensions/modules/servicebus/Elsa.ServiceBus.MassTransit.UnitTests/Elsa.ServiceBus.MassTransit.UnitTests.csproj", + "id": "Elsa.Expressions.UnitTests", + "project": "core/test/unit/Elsa.Expressions.UnitTests/Elsa.Expressions.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Slack.Tests", - "project": "test/extensions/modules/slack/Elsa.Slack.Tests/Elsa.Slack.Tests.csproj", + "id": "Elsa.ExternalAuthentication.UnitTests", + "project": "core/test/unit/Elsa.ExternalAuthentication.UnitTests/Elsa.ExternalAuthentication.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.TestServer.Web", - "project": "test/extensions/workbench/Elsa.TestServer.Web/Elsa.TestServer.Web.csproj", + "id": "Elsa.Features.UnitTests", + "project": "core/test/unit/Elsa.Features.UnitTests/Elsa.Features.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.AI.IntegrationTests", - "project": "test/integration/Elsa.AI.IntegrationTests/Elsa.AI.IntegrationTests.csproj", + "id": "Elsa.Hosting.Management.UnitTests", + "project": "core/test/unit/Elsa.Hosting.Management.UnitTests/Elsa.Hosting.Management.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Activities.IntegrationTests", - "project": "test/integration/Elsa.Activities.IntegrationTests/Elsa.Activities.IntegrationTests.csproj", + "id": "Elsa.Http.UnitTests", + "project": "core/test/unit/Elsa.Http.UnitTests/Elsa.Http.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Alterations.IntegrationTests", - "project": "test/integration/Elsa.Alterations.IntegrationTests/Elsa.Alterations.IntegrationTests.csproj", + "id": "Elsa.Identity.UnitTests", + "project": "core/test/unit/Elsa.Identity.UnitTests/Elsa.Identity.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Alterations.Persistence.ConformanceTests", - "project": "test/integration/Elsa.Alterations.Persistence.ConformanceTests/Elsa.Alterations.Persistence.ConformanceTests.csproj", + "id": "Elsa.Labels.UnitTests", + "project": "core/test/unit/Elsa.Labels.UnitTests/Elsa.Labels.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Bpmn.IntegrationTests", - "project": "test/integration/Elsa.Bpmn.IntegrationTests/Elsa.Bpmn.IntegrationTests.csproj", + "id": "Elsa.Mediator.UnitTests", + "project": "core/test/unit/Elsa.Mediator.UnitTests/Elsa.Mediator.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Bpmn.Interchange.IntegrationTests", - "project": "test/integration/Elsa.Bpmn.Interchange.IntegrationTests/Elsa.Bpmn.Interchange.IntegrationTests.csproj", + "id": "Elsa.Persistence.EFCore.MySql.UnitTests", + "project": "core/test/unit/Elsa.Persistence.EFCore.MySql.UnitTests/Elsa.Persistence.EFCore.MySql.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Common.IntegrationTests", - "project": "test/integration/Elsa.Common.IntegrationTests/Elsa.Common.IntegrationTests.csproj", + "id": "Elsa.Persistence.EFCore.UnitTests", + "project": "core/test/unit/Elsa.Persistence.EFCore.UnitTests/Elsa.Persistence.EFCore.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Connections.Credentials.Persistence.PostgreSql.IntegrationTests", - "project": "test/integration/Elsa.Connections.Credentials.Persistence.PostgreSql.IntegrationTests/Elsa.Connections.Credentials.Persistence.PostgreSql.IntegrationTests.csproj", + "id": "Elsa.Persistence.VNext.UnitTests", + "project": "core/test/unit/Elsa.Persistence.VNext.UnitTests/Elsa.Persistence.VNext.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.ConsoleLogs.IntegrationTests", - "project": "test/integration/Elsa.Diagnostics.ConsoleLogs.IntegrationTests/Elsa.Diagnostics.ConsoleLogs.IntegrationTests.csproj", + "id": "Elsa.Platform.Integration.UnitTests", + "project": "core/test/unit/Elsa.Platform.Integration.UnitTests/Elsa.Platform.Integration.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.OpenTelemetry.IntegrationTests", - "project": "test/integration/Elsa.Diagnostics.OpenTelemetry.IntegrationTests/Elsa.Diagnostics.OpenTelemetry.IntegrationTests.csproj", + "id": "Elsa.Resilience.Core.UnitTests", + "project": "core/test/unit/Elsa.Resilience.Core.UnitTests/Elsa.Resilience.Core.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.StructuredLogs.IntegrationTests", - "project": "test/integration/Elsa.Diagnostics.StructuredLogs.IntegrationTests/Elsa.Diagnostics.StructuredLogs.IntegrationTests.csproj", + "id": "Elsa.SasTokens.UnitTests", + "project": "core/test/unit/Elsa.SasTokens.UnitTests/Elsa.SasTokens.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests", - "project": "test/integration/Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests/Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests.csproj", + "id": "Elsa.Scheduling.UnitTests", + "project": "core/test/unit/Elsa.Scheduling.UnitTests/Elsa.Scheduling.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.IntegrationTests", - "project": "test/integration/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.IntegrationTests/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.IntegrationTests.csproj", + "id": "Elsa.Secrets.UnitTests", + "project": "core/test/unit/Elsa.Secrets.UnitTests/Elsa.Secrets.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Dsl.ElsaScript.IntegrationTests", - "project": "test/integration/Elsa.Dsl.ElsaScript.IntegrationTests/Elsa.Dsl.ElsaScript.IntegrationTests.csproj", + "id": "Elsa.Shells.Api.Tests", + "project": "core/test/unit/Elsa.Shells.Api.Tests/Elsa.Shells.Api.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.ExternalAuthentication.IntegrationTests", - "project": "test/integration/Elsa.ExternalAuthentication.IntegrationTests/Elsa.ExternalAuthentication.IntegrationTests.csproj", + "id": "Elsa.Tenants.UnitTests", + "project": "core/test/unit/Elsa.Tenants.UnitTests/Elsa.Tenants.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Hosts.SmokeTests", - "project": "test/integration/Elsa.Hosts.SmokeTests/Elsa.Hosts.SmokeTests.csproj", + "id": "Elsa.UserTasks.Persistence.ConformanceTests", + "project": "core/test/unit/Elsa.UserTasks.Persistence.ConformanceTests/Elsa.UserTasks.Persistence.ConformanceTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Http.IntegrationTests", - "project": "test/integration/Elsa.Http.IntegrationTests/Elsa.Http.IntegrationTests.csproj", + "id": "Elsa.UserTasks.Persistence.EFCore.UnitTests", + "project": "core/test/unit/Elsa.UserTasks.Persistence.EFCore.UnitTests/Elsa.UserTasks.Persistence.EFCore.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.JavaScript.IntegrationTests", - "project": "test/integration/Elsa.JavaScript.IntegrationTests/Elsa.JavaScript.IntegrationTests.csproj", + "id": "Elsa.UserTasks.UnitTests", + "project": "core/test/unit/Elsa.UserTasks.UnitTests/Elsa.UserTasks.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Labels.Persistence.ConformanceTests", - "project": "test/integration/Elsa.Labels.Persistence.ConformanceTests/Elsa.Labels.Persistence.ConformanceTests.csproj", + "id": "Elsa.Workflows.Api.UnitTests", + "project": "core/test/unit/Elsa.Workflows.Api.UnitTests/Elsa.Workflows.Api.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Resilience.IntegrationTests", - "project": "test/integration/Elsa.Resilience.IntegrationTests/Elsa.Resilience.IntegrationTests.csproj", + "id": "Elsa.Workflows.Core.UnitTests", + "project": "core/test/unit/Elsa.Workflows.Core.UnitTests/Elsa.Workflows.Core.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.Api.IntegrationTests", - "project": "test/integration/Elsa.Secrets.Api.IntegrationTests/Elsa.Secrets.Api.IntegrationTests.csproj", + "id": "Elsa.Workflows.Management.UnitTests", + "project": "core/test/unit/Elsa.Workflows.Management.UnitTests/Elsa.Workflows.Management.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.DefaultHost.IntegrationTests", - "project": "test/integration/Elsa.Secrets.DefaultHost.IntegrationTests/Elsa.Secrets.DefaultHost.IntegrationTests.csproj", + "id": "Elsa.Workflows.Runtime.UnitTests", + "project": "core/test/unit/Elsa.Workflows.Runtime.UnitTests/Elsa.Workflows.Runtime.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.IntegrationTests", - "project": "test/integration/Elsa.Workflows.IntegrationTests/Elsa.Workflows.IntegrationTests.csproj", + "id": "Elsa.Connections.Credentials.WorkerProcess", + "project": "core/test/workers/Elsa.Connections.Credentials.WorkerProcess/Elsa.Connections.Credentials.WorkerProcess.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.Persistence.ConformanceTests", - "project": "test/integration/Elsa.Workflows.Persistence.ConformanceTests/Elsa.Workflows.Persistence.ConformanceTests.csproj", + "id": "Elsa.Workflows.Admission.WorkerProcess", + "project": "core/test/workers/Elsa.Workflows.Admission.WorkerProcess/Elsa.Workflows.Admission.WorkerProcess.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.PerformanceTests", - "project": "test/performance/Elsa.Workflows.PerformanceTests/Elsa.Workflows.PerformanceTests.csproj", + "id": "Elsa.Server.Web", + "project": "extensions/samples/workbench/Elsa.Server.Web/Elsa.Server.Web.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.AI.Abstractions.UnitTests", - "project": "test/unit/Elsa.AI.Abstractions.UnitTests/Elsa.AI.Abstractions.UnitTests.csproj", + "id": "Elsa.ServerAndStudio.Web", + "project": "extensions/samples/workbench/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.AI.Copilot.UnitTests", - "project": "test/unit/Elsa.AI.Copilot.UnitTests/Elsa.AI.Copilot.UnitTests.csproj", + "id": "ElsaStudioWebAssembly", + "project": "extensions/samples/workbench/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.AI.Host.UnitTests", - "project": "test/unit/Elsa.AI.Host.UnitTests/Elsa.AI.Host.UnitTests.csproj", + "id": "Elsa.Secrets.Api", + "project": "extensions/src/secrets/Elsa.Secrets.Api/Elsa.Secrets.Api.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.AI.Persistence.EFCore.UnitTests", - "project": "test/unit/Elsa.AI.Persistence.EFCore.UnitTests/Elsa.AI.Persistence.EFCore.UnitTests.csproj", + "id": "Elsa.Secrets.Core", + "project": "extensions/src/secrets/Elsa.Secrets.Core/Elsa.Secrets.Core.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Activities.UnitTests", - "project": "test/unit/Elsa.Activities.UnitTests/Elsa.Activities.UnitTests.csproj", + "id": "Elsa.Secrets.Management", + "project": "extensions/src/secrets/Elsa.Secrets.Management/Elsa.Secrets.Management.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Alterations.Core.UnitTests", - "project": "test/unit/Elsa.Alterations.Core.UnitTests/Elsa.Alterations.Core.UnitTests.csproj", + "id": "Elsa.Secrets.Models", + "project": "extensions/src/secrets/Elsa.Secrets.Models/Elsa.Secrets.Models.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Api.Common.UnitTests", - "project": "test/unit/Elsa.Api.Common.UnitTests/Elsa.Api.Common.UnitTests.csproj", + "id": "Elsa.Secrets.Scripting", + "project": "extensions/src/secrets/Elsa.Secrets.Scripting/Elsa.Secrets.Scripting.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Bpmn.Interchange.UnitTests", - "project": "test/unit/Elsa.Bpmn.Interchange.UnitTests/Elsa.Bpmn.Interchange.UnitTests.csproj", + "id": "Elsa.Actors.ProtoActor.UnitTests", + "project": "extensions/test/modules/actors/Elsa.Actors.ProtoActor.UnitTests/Elsa.Actors.ProtoActor.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Bpmn.UnitTests", - "project": "test/unit/Elsa.Bpmn.UnitTests/Elsa.Bpmn.UnitTests.csproj", + "id": "Elsa.Agents.Core.UnitTests", + "project": "extensions/test/modules/agents/Elsa.Agents.Core.UnitTests/Elsa.Agents.Core.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Common.UnitTests", - "project": "test/unit/Elsa.Common.UnitTests/Elsa.Common.UnitTests.csproj", + "id": "Elsa.Studio.Agents.Tests", + "project": "extensions/test/modules/agents/Elsa.Studio.Agents.Tests/Elsa.Studio.Agents.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Connections.UnitTests", - "project": "test/unit/Elsa.Connections.UnitTests/Elsa.Connections.UnitTests.csproj", + "id": "Elsa.Caching.Distributed.ProtoActor.IntegrationTests", + "project": "extensions/test/modules/caching/Elsa.Caching.Distributed.ProtoActor.IntegrationTests/Elsa.Caching.Distributed.ProtoActor.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Dashboard.Api.UnitTests", - "project": "test/unit/Elsa.Dashboard.Api.UnitTests/Elsa.Dashboard.Api.UnitTests.csproj", + "id": "Elsa.DevOps.GitHub.UnitTests", + "project": "extensions/test/modules/devops/Elsa.DevOps.GitHub.UnitTests/Elsa.DevOps.GitHub.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.ConsoleLogs.UnitTests", - "project": "test/unit/Elsa.Diagnostics.ConsoleLogs.UnitTests/Elsa.Diagnostics.ConsoleLogs.UnitTests.csproj", + "id": "Elsa.Logging.Core.IntegrationTests", + "project": "extensions/test/modules/diagnostics/Elsa.Logging.Core.IntegrationTests/Elsa.Logging.Core.IntegrationTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.OpenTelemetry.UnitTests", - "project": "test/unit/Elsa.Diagnostics.OpenTelemetry.UnitTests/Elsa.Diagnostics.OpenTelemetry.UnitTests.csproj", + "id": "Elsa.Logging.Core.UnitTests", + "project": "extensions/test/modules/diagnostics/Elsa.Logging.Core.UnitTests/Elsa.Logging.Core.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Relational.UnitTests", - "project": "test/unit/Elsa.Diagnostics.StructuredLogs.Persistence.Relational.UnitTests/Elsa.Diagnostics.StructuredLogs.Persistence.Relational.UnitTests.csproj", + "id": "Elsa.Ldap.UnitTests", + "project": "extensions/test/modules/ldap/Elsa.Ldap.UnitTests/Elsa.Ldap.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Diagnostics.StructuredLogs.UnitTests", - "project": "test/unit/Elsa.Diagnostics.StructuredLogs.UnitTests/Elsa.Diagnostics.StructuredLogs.UnitTests.csproj", + "id": "Elsa.Mqtt.UnitTests", + "project": "extensions/test/modules/mqtt/Elsa.Mqtt.UnitTests/Elsa.Mqtt.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Expressions.UnitTests", - "project": "test/unit/Elsa.Expressions.UnitTests/Elsa.Expressions.UnitTests.csproj", + "id": "Elsa.Dapper.UnitTests", + "project": "extensions/test/modules/persistence/Elsa.Dapper.UnitTests/Elsa.Dapper.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.ExternalAuthentication.UnitTests", - "project": "test/unit/Elsa.ExternalAuthentication.UnitTests/Elsa.ExternalAuthentication.UnitTests.csproj", + "id": "Elsa.MongoDb.UnitTests", + "project": "extensions/test/modules/persistence/Elsa.MongoDb.UnitTests/Elsa.MongoDb.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Features.UnitTests", - "project": "test/unit/Elsa.Features.UnitTests/Elsa.Features.UnitTests.csproj", + "id": "Elsa.Persistence.Dapper.UnitTests", + "project": "extensions/test/modules/persistence/Elsa.Persistence.Dapper.UnitTests/Elsa.Persistence.Dapper.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Hosting.Management.UnitTests", - "project": "test/unit/Elsa.Hosting.Management.UnitTests/Elsa.Hosting.Management.UnitTests.csproj", + "id": "Elsa.Workflows.Runtime.ProtoActor.UnitTests", + "project": "extensions/test/modules/runtimes/Elsa.Workflows.Runtime.ProtoActor.UnitTests/Elsa.Workflows.Runtime.ProtoActor.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Http.UnitTests", - "project": "test/unit/Elsa.Http.UnitTests/Elsa.Http.UnitTests.csproj", + "id": "Elsa.Scheduling.Hangfire.UnitTests", + "project": "extensions/test/modules/scheduling/Elsa.Scheduling.Hangfire.UnitTests/Elsa.Scheduling.Hangfire.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Identity.UnitTests", - "project": "test/unit/Elsa.Identity.UnitTests/Elsa.Identity.UnitTests.csproj", + "id": "Elsa.Scheduling.Quartz.ComponentTests", + "project": "extensions/test/modules/scheduling/Elsa.Scheduling.Quartz.ComponentTests/Elsa.Scheduling.Quartz.ComponentTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Labels.UnitTests", - "project": "test/unit/Elsa.Labels.UnitTests/Elsa.Labels.UnitTests.csproj", + "id": "Elsa.Scheduling.Quartz.UnitTests", + "project": "extensions/test/modules/scheduling/Elsa.Scheduling.Quartz.UnitTests/Elsa.Scheduling.Quartz.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Persistence.EFCore.UnitTests", - "project": "test/unit/Elsa.Persistence.EFCore.UnitTests/Elsa.Persistence.EFCore.UnitTests.csproj", + "id": "Elsa.Secrets.Management.UnitTests", + "project": "extensions/test/modules/secrets/Elsa.Secrets.Management.UnitTests/Elsa.Secrets.Management.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Persistence.VNext.UnitTests", - "project": "test/unit/Elsa.Persistence.VNext.UnitTests/Elsa.Persistence.VNext.UnitTests.csproj", + "id": "Elsa.ServiceBus.AzureServiceBus.ComponentTests", + "project": "extensions/test/modules/servicebus/Elsa.ServiceBus.AzureServiceBus.ComponentTests/Elsa.ServiceBus.AzureServiceBus.ComponentTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Platform.Integration.UnitTests", - "project": "test/unit/Elsa.Platform.Integration.UnitTests/Elsa.Platform.Integration.UnitTests.csproj", + "id": "Elsa.ServiceBus.MassTransit.UnitTests", + "project": "extensions/test/modules/servicebus/Elsa.ServiceBus.MassTransit.UnitTests/Elsa.ServiceBus.MassTransit.UnitTests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Resilience.Core.UnitTests", - "project": "test/unit/Elsa.Resilience.Core.UnitTests/Elsa.Resilience.Core.UnitTests.csproj", + "id": "Elsa.Slack.Tests", + "project": "extensions/test/modules/slack/Elsa.Slack.Tests/Elsa.Slack.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.SasTokens.UnitTests", - "project": "test/unit/Elsa.SasTokens.UnitTests/Elsa.SasTokens.UnitTests.csproj", + "id": "Elsa.TestServer.Web", + "project": "extensions/test/workbench/Elsa.TestServer.Web/Elsa.TestServer.Web.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Scheduling.UnitTests", - "project": "test/unit/Elsa.Scheduling.UnitTests/Elsa.Scheduling.UnitTests.csproj", + "id": "BlazorApp1", + "project": "studio/samples/BlazorApp1/BlazorApp1.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Secrets.UnitTests", - "project": "test/unit/Elsa.Secrets.UnitTests/Elsa.Secrets.UnitTests.csproj", + "id": "Elsa.Studio.Core.Tests", + "project": "studio/src/framework/Elsa.Studio.Core.Tests/Elsa.Studio.Core.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Shells.Api.Tests", - "project": "test/unit/Elsa.Shells.Api.Tests/Elsa.Shells.Api.Tests.csproj", + "id": "Elsa.Studio.Host.CustomElements", + "project": "studio/src/hosts/Elsa.Studio.Host.CustomElements/Elsa.Studio.Host.CustomElements.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Tenants.UnitTests", - "project": "test/unit/Elsa.Tenants.UnitTests/Elsa.Tenants.UnitTests.csproj", + "id": "Elsa.Studio.Host.HostedWasm", + "project": "studio/src/hosts/Elsa.Studio.Host.HostedWasm/Elsa.Studio.Host.HostedWasm.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.UserTasks.Persistence.ConformanceTests", - "project": "test/unit/Elsa.UserTasks.Persistence.ConformanceTests/Elsa.UserTasks.Persistence.ConformanceTests.csproj", + "id": "Elsa.Studio.Host.Server", + "project": "studio/src/hosts/Elsa.Studio.Host.Server/Elsa.Studio.Host.Server.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.UserTasks.Persistence.EFCore.UnitTests", - "project": "test/unit/Elsa.UserTasks.Persistence.EFCore.UnitTests/Elsa.UserTasks.Persistence.EFCore.UnitTests.csproj", + "id": "Elsa.Studio.Host.Wasm", + "project": "studio/src/hosts/Elsa.Studio.Host.Wasm/Elsa.Studio.Host.Wasm.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.UserTasks.UnitTests", - "project": "test/unit/Elsa.UserTasks.UnitTests/Elsa.UserTasks.UnitTests.csproj", + "id": "Elsa.Studio.AI.Tests", + "project": "studio/src/modules/Elsa.Studio.AI.Tests/Elsa.Studio.AI.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.Api.UnitTests", - "project": "test/unit/Elsa.Workflows.Api.UnitTests/Elsa.Workflows.Api.UnitTests.csproj", + "id": "Elsa.Studio.Administration.Tests", + "project": "studio/src/modules/Elsa.Studio.Administration.Tests/Elsa.Studio.Administration.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.Core.UnitTests", - "project": "test/unit/Elsa.Workflows.Core.UnitTests/Elsa.Workflows.Core.UnitTests.csproj", + "id": "Elsa.Studio.Authentication.UI.Tests", + "project": "studio/src/modules/Elsa.Studio.Authentication.UI.Tests/Elsa.Studio.Authentication.UI.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.Management.UnitTests", - "project": "test/unit/Elsa.Workflows.Management.UnitTests/Elsa.Workflows.Management.UnitTests.csproj", + "id": "Elsa.Studio.Dashboard.Tests", + "project": "studio/src/modules/Elsa.Studio.Dashboard.Tests/Elsa.Studio.Dashboard.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Workflows.Runtime.UnitTests", - "project": "test/unit/Elsa.Workflows.Runtime.UnitTests/Elsa.Workflows.Runtime.UnitTests.csproj", + "id": "Elsa.Studio.Diagnostics.ConsoleLogs.Tests", + "project": "studio/src/modules/Elsa.Studio.Diagnostics.ConsoleLogs.Tests/Elsa.Studio.Diagnostics.ConsoleLogs.Tests.csproj", "reason": "Project or inherited nonpackable setting remains active" - } - ], - "packages": [ + }, { - "id": "Elsa.SamplePackage", - "project": "src/apps/Elsa.SamplePackage/Elsa.SamplePackage.csproj" + "id": "Elsa.Studio.Diagnostics.OpenTelemetry.Tests", + "project": "studio/src/modules/Elsa.Studio.Diagnostics.OpenTelemetry.Tests/Elsa.Studio.Diagnostics.OpenTelemetry.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Api.Client", - "project": "src/clients/Elsa.Api.Client/Elsa.Api.Client.csproj" + "id": "Elsa.Studio.Diagnostics.StructuredLogs.Tests", + "project": "studio/src/modules/Elsa.Studio.Diagnostics.StructuredLogs.Tests/Elsa.Studio.Diagnostics.StructuredLogs.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Api.Common", - "project": "src/common/Elsa.Api.Common/Elsa.Api.Common.csproj" + "id": "Elsa.Studio.Environments.Tests", + "project": "studio/src/modules/Elsa.Studio.Environments.Tests/Elsa.Studio.Environments.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Features", - "project": "src/common/Elsa.Features/Elsa.Features.csproj" + "id": "Elsa.Studio.ExternalAuthentication.Tests", + "project": "studio/src/modules/Elsa.Studio.ExternalAuthentication.Tests/Elsa.Studio.ExternalAuthentication.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Mediator", - "project": "src/common/Elsa.Mediator/Elsa.Mediator.csproj" + "id": "Elsa.Studio.Localization.Tests", + "project": "studio/src/modules/Elsa.Studio.Localization.Tests/Elsa.Studio.Localization.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" }, { - "id": "Elsa.Testing.Shared.Component", - "project": "src/common/Elsa.Testing.Shared.Component/Elsa.Testing.Shared.Component.csproj" + "id": "Elsa.Studio.PlatformIntegration.Tests", + "project": "studio/src/modules/Elsa.Studio.PlatformIntegration.Tests/Elsa.Studio.PlatformIntegration.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" + }, + { + "id": "Elsa.Studio.Secrets.Tests", + "project": "studio/src/modules/Elsa.Studio.Secrets.Tests/Elsa.Studio.Secrets.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" + }, + { + "id": "Elsa.Studio.Security.Tests", + "project": "studio/src/modules/Elsa.Studio.Security.Tests/Elsa.Studio.Security.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" + }, + { + "id": "Elsa.Studio.UserTasks.Tests", + "project": "studio/src/modules/Elsa.Studio.UserTasks.Tests/Elsa.Studio.UserTasks.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" + }, + { + "id": "Elsa.Studio.Workflows.Designer.Tests", + "project": "studio/src/modules/Elsa.Studio.Workflows.Designer.Tests/Elsa.Studio.Workflows.Designer.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" + }, + { + "id": "Elsa.Studio.Workflows.Tests", + "project": "studio/src/modules/Elsa.Studio.Workflows.Tests/Elsa.Studio.Workflows.Tests.csproj", + "reason": "Project or inherited nonpackable setting remains active" + } + ], + "packages": [ + { + "id": "Elsa.Api.Client", + "project": "core/src/clients/Elsa.Api.Client/Elsa.Api.Client.csproj" + }, + { + "id": "Elsa.Api.Common", + "project": "core/src/common/Elsa.Api.Common/Elsa.Api.Common.csproj" + }, + { + "id": "Elsa.Features", + "project": "core/src/common/Elsa.Features/Elsa.Features.csproj" + }, + { + "id": "Elsa.Mediator", + "project": "core/src/common/Elsa.Mediator/Elsa.Mediator.csproj" + }, + { + "id": "Elsa.Testing.Shared.Component", + "project": "core/src/common/Elsa.Testing.Shared.Component/Elsa.Testing.Shared.Component.csproj" }, { "id": "Elsa.Testing.Shared.Integration", - "project": "src/common/Elsa.Testing.Shared.Integration/Elsa.Testing.Shared.Integration.csproj" + "project": "core/src/common/Elsa.Testing.Shared.Integration/Elsa.Testing.Shared.Integration.csproj" }, { "id": "Elsa.Testing.Shared", - "project": "src/common/Elsa.Testing.Shared/Elsa.Testing.Shared.csproj" + "project": "core/src/common/Elsa.Testing.Shared/Elsa.Testing.Shared.csproj" }, { - "id": "Elsa.Actors.ProtoActor.PubSub.Redis", - "project": "src/extensions/actors/Elsa.Actors.ProtoActor.PubSub.Redis/Elsa.Actors.ProtoActor.PubSub.Redis.csproj" + "id": "Elsa.AI.Abstractions", + "project": "core/src/modules/Elsa.AI.Abstractions/Elsa.AI.Abstractions.csproj" }, { - "id": "Elsa.Actors.ProtoActor", - "project": "src/extensions/actors/Elsa.Actors.ProtoActor/Elsa.Actors.ProtoActor.csproj" + "id": "Elsa.AI.Copilot", + "project": "core/src/modules/Elsa.AI.Copilot/Elsa.AI.Copilot.csproj" }, { - "id": "Elsa.Agents.Activities", - "project": "src/extensions/agents/Elsa.Agents.Activities/Elsa.Agents.Activities.csproj" + "id": "Elsa.AI.Host", + "project": "core/src/modules/Elsa.AI.Host/Elsa.AI.Host.csproj" }, { - "id": "Elsa.Agents.Api", - "project": "src/extensions/agents/Elsa.Agents.Api/Elsa.Agents.Api.csproj" + "id": "Elsa.AI.Persistence.EFCore.MySql", + "project": "core/src/modules/Elsa.AI.Persistence.EFCore.MySql/Elsa.AI.Persistence.EFCore.MySql.csproj" }, { - "id": "Elsa.Agents.AzureOpenAI", - "project": "src/extensions/agents/Elsa.Agents.AzureOpenAI/Elsa.Agents.AzureOpenAI.csproj" + "id": "Elsa.AI.Persistence.EFCore.Oracle", + "project": "core/src/modules/Elsa.AI.Persistence.EFCore.Oracle/Elsa.AI.Persistence.EFCore.Oracle.csproj" }, { - "id": "Elsa.Agents.Core", - "project": "src/extensions/agents/Elsa.Agents.Core/Elsa.Agents.Core.csproj" + "id": "Elsa.AI.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.AI.Persistence.EFCore.PostgreSql/Elsa.AI.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.Agents.Models", - "project": "src/extensions/agents/Elsa.Agents.Models/Elsa.Agents.Models.csproj" + "id": "Elsa.AI.Persistence.EFCore.SqlServer", + "project": "core/src/modules/Elsa.AI.Persistence.EFCore.SqlServer/Elsa.AI.Persistence.EFCore.SqlServer.csproj" }, { - "id": "Elsa.Agents.OpenAI", - "project": "src/extensions/agents/Elsa.Agents.OpenAI/Elsa.Agents.OpenAI.csproj" + "id": "Elsa.AI.Persistence.EFCore.Sqlite", + "project": "core/src/modules/Elsa.AI.Persistence.EFCore.Sqlite/Elsa.AI.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.Agents.Persistence.EFCore.MySql", - "project": "src/extensions/agents/Elsa.Agents.Persistence.EFCore.MySql/Elsa.Agents.Persistence.EFCore.MySql.csproj" + "id": "Elsa.AI.Persistence.EFCore", + "project": "core/src/modules/Elsa.AI.Persistence.EFCore/Elsa.AI.Persistence.EFCore.csproj" }, { - "id": "Elsa.Agents.Persistence.EFCore.PostgreSql", - "project": "src/extensions/agents/Elsa.Agents.Persistence.EFCore.PostgreSql/Elsa.Agents.Persistence.EFCore.PostgreSql.csproj" + "id": "Elsa.Alterations.Core", + "project": "core/src/modules/Elsa.Alterations.Core/Elsa.Alterations.Core.csproj" }, { - "id": "Elsa.Agents.Persistence.EFCore.SqlServer", - "project": "src/extensions/agents/Elsa.Agents.Persistence.EFCore.SqlServer/Elsa.Agents.Persistence.EFCore.SqlServer.csproj" + "id": "Elsa.Alterations", + "project": "core/src/modules/Elsa.Alterations/Elsa.Alterations.csproj" }, { - "id": "Elsa.Agents.Persistence.EFCore.Sqlite", - "project": "src/extensions/agents/Elsa.Agents.Persistence.EFCore.Sqlite/Elsa.Agents.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.Bpmn.Interchange", + "project": "core/src/modules/Elsa.Bpmn.Interchange/Elsa.Bpmn.Interchange.csproj" }, { - "id": "Elsa.Agents.Persistence.EFCore", - "project": "src/extensions/agents/Elsa.Agents.Persistence.EFCore/Elsa.Agents.Persistence.EFCore.csproj" + "id": "Elsa.Bpmn", + "project": "core/src/modules/Elsa.Bpmn/Elsa.Bpmn.csproj" }, { - "id": "Elsa.Agents.Persistence", - "project": "src/extensions/agents/Elsa.Agents.Persistence/Elsa.Agents.Persistence.csproj" + "id": "Elsa.Caching", + "project": "core/src/modules/Elsa.Caching/Elsa.Caching.csproj" }, { - "id": "Elsa.Agents", - "project": "src/extensions/agents/Elsa.Agents/Elsa.Agents.csproj" + "id": "Elsa.Common", + "project": "core/src/modules/Elsa.Common/Elsa.Common.csproj" }, { - "id": "Elsa.Studio.Agents", - "project": "src/extensions/agents/Elsa.Studio.Agents/Elsa.Studio.Agents.csproj" + "id": "Elsa.Connections.Credentials.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.Connections.Credentials.Persistence.EFCore.PostgreSql/Elsa.Connections.Credentials.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.Alterations.MassTransit", - "project": "src/extensions/alterations/Elsa.Alterations.MassTransit/Elsa.Alterations.MassTransit.csproj" + "id": "Elsa.Connections.Credentials.Persistence.EFCore", + "project": "core/src/modules/Elsa.Connections.Credentials.Persistence.EFCore/Elsa.Connections.Credentials.Persistence.EFCore.csproj" }, { - "id": "Elsa.Caching.Distributed.MassTransit", - "project": "src/extensions/caching/Elsa.Caching.Distributed.MassTransit/Elsa.Caching.Distributed.MassTransit.csproj" + "id": "Elsa.Connections.Credentials.Workflows", + "project": "core/src/modules/Elsa.Connections.Credentials.Workflows/Elsa.Connections.Credentials.Workflows.csproj" }, { - "id": "Elsa.Caching.Distributed.ProtoActor", - "project": "src/extensions/caching/Elsa.Caching.Distributed.ProtoActor/Elsa.Caching.Distributed.ProtoActor.csproj" + "id": "Elsa.Connections", + "project": "core/src/modules/Elsa.Connections/Elsa.Connections.csproj" }, { - "id": "Elsa.Caching.Distributed", - "project": "src/extensions/caching/Elsa.Caching.Distributed/Elsa.Caching.Distributed.csproj" + "id": "Elsa.Dashboard.Abstractions", + "project": "core/src/modules/Elsa.Dashboard.Abstractions/Elsa.Dashboard.Abstractions.csproj" }, { - "id": "Elsa.OrchardCore", - "project": "src/extensions/cms/Elsa.OrchardCore/Elsa.OrchardCore.csproj" + "id": "Elsa.Dashboard.Api", + "project": "core/src/modules/Elsa.Dashboard.Api/Elsa.Dashboard.Api.csproj" }, { - "id": "Elsa.Slack", - "project": "src/extensions/communication/Elsa.Slack/Elsa.Slack.csproj" + "id": "Elsa.Diagnostics.ConsoleLogs.Dashboard", + "project": "core/src/modules/Elsa.Diagnostics.ConsoleLogs.Dashboard/Elsa.Diagnostics.ConsoleLogs.Dashboard.csproj" }, { - "id": "Elsa.Connections.Api", - "project": "src/extensions/connections/Elsa.Connections.Api/Elsa.Connections.Api.csproj" + "id": "Elsa.Diagnostics.ConsoleLogs", + "project": "core/src/modules/Elsa.Diagnostics.ConsoleLogs/Elsa.Diagnostics.ConsoleLogs.csproj" }, { - "id": "Elsa.Connections.Core", - "project": "src/extensions/connections/Elsa.Connections.Core/Elsa.Connections.Core.csproj" + "id": "Elsa.Diagnostics.OpenTelemetry", + "project": "core/src/modules/Elsa.Diagnostics.OpenTelemetry/Elsa.Diagnostics.OpenTelemetry.csproj" }, { - "id": "Elsa.Connections.Models", - "project": "src/extensions/connections/Elsa.Connections.Models/Elsa.Connections.Models.csproj" + "id": "Elsa.Diagnostics.StructuredLogs.Dashboard", + "project": "core/src/modules/Elsa.Diagnostics.StructuredLogs.Dashboard/Elsa.Diagnostics.StructuredLogs.Dashboard.csproj" }, { - "id": "Elsa.Connections.Persistence.EFCore.Sqlite", - "project": "src/extensions/connections/Elsa.Connections.Persistence.EFCore.Sqlite/Elsa.Connections.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Relational", + "project": "core/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Elsa.Diagnostics.StructuredLogs.Persistence.Relational.csproj" }, { - "id": "Elsa.Connections.Persistence.EFCore", - "project": "src/extensions/connections/Elsa.Connections.Persistence.EFCore/Elsa.Connections.Persistence.EFCore.csproj" + "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite", + "project": "core/src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.csproj" }, { - "id": "Elsa.Connections.Persistence", - "project": "src/extensions/connections/Elsa.Connections.Persistence/Elsa.Connections.Persistence.csproj" + "id": "Elsa.Diagnostics.StructuredLogs", + "project": "core/src/modules/Elsa.Diagnostics.StructuredLogs/Elsa.Diagnostics.StructuredLogs.csproj" }, { - "id": "Elsa.Data.Csv", - "project": "src/extensions/data/Elsa.Data.Csv/Elsa.Data.Csv.csproj" + "id": "Elsa.Dsl.ElsaScript", + "project": "core/src/modules/Elsa.Dsl.ElsaScript/Elsa.Dsl.ElsaScript.csproj" }, { - "id": "Elsa.DevOps.GitHub", - "project": "src/extensions/devops/Elsa.DevOps.GitHub/Elsa.DevOps.GitHub.csproj" + "id": "Elsa.Expressions.CSharp", + "project": "core/src/modules/Elsa.Expressions.CSharp/Elsa.Expressions.CSharp.csproj" }, { - "id": "Elsa.Logging.Console", - "project": "src/extensions/diagnostics/Elsa.Logging.Console/Elsa.Logging.Console.csproj" + "id": "Elsa.Expressions.JavaScript.Libraries", + "project": "core/src/modules/Elsa.Expressions.JavaScript.Libraries/Elsa.Expressions.JavaScript.Libraries.csproj" }, { - "id": "Elsa.Logging.Core", - "project": "src/extensions/diagnostics/Elsa.Logging.Core/Elsa.Logging.Core.csproj" + "id": "Elsa.Expressions.JavaScript", + "project": "core/src/modules/Elsa.Expressions.JavaScript/Elsa.Expressions.JavaScript.csproj" }, { - "id": "Elsa.Logging.Serilog", - "project": "src/extensions/diagnostics/Elsa.Logging.Serilog/Elsa.Logging.Serilog.csproj" + "id": "Elsa.Expressions.Liquid", + "project": "core/src/modules/Elsa.Expressions.Liquid/Elsa.Expressions.Liquid.csproj" }, { - "id": "Elsa.Logging", - "project": "src/extensions/diagnostics/Elsa.Logging/Elsa.Logging.csproj" + "id": "Elsa.Expressions.Python", + "project": "core/src/modules/Elsa.Expressions.Python/Elsa.Expressions.Python.csproj" }, { - "id": "Elsa.OpenTelemetry", - "project": "src/extensions/diagnostics/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj" + "id": "Elsa.Expressions", + "project": "core/src/modules/Elsa.Expressions/Elsa.Expressions.csproj" }, { - "id": "Elsa.DropIns.Core", - "project": "src/extensions/dropins/Elsa.DropIns.Core/Elsa.DropIns.Core.csproj" + "id": "Elsa.ExternalAuthentication.OpenIdConnect", + "project": "core/src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Elsa.ExternalAuthentication.OpenIdConnect.csproj" }, { - "id": "Elsa.DropIns", - "project": "src/extensions/dropins/Elsa.DropIns/Elsa.DropIns.csproj" + "id": "Elsa.ExternalAuthentication.Persistence.EFCore.MySql", + "project": "core/src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.MySql/Elsa.ExternalAuthentication.Persistence.EFCore.MySql.csproj" }, { - "id": "Elsa.Email", - "project": "src/extensions/email/Elsa.Email/Elsa.Email.csproj" + "id": "Elsa.ExternalAuthentication.Persistence.EFCore.Oracle", + "project": "core/src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.Oracle/Elsa.ExternalAuthentication.Persistence.EFCore.Oracle.csproj" }, { - "id": "Elsa.Http.OpenApi", - "project": "src/extensions/http/Elsa.Http.OpenApi/Elsa.Http.OpenApi.csproj" + "id": "Elsa.ExternalAuthentication.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.PostgreSql/Elsa.ExternalAuthentication.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.IO.Compression", - "project": "src/extensions/io/Elsa.IO.Compression/Elsa.IO.Compression.csproj" + "id": "Elsa.ExternalAuthentication.Persistence.EFCore.SqlServer", + "project": "core/src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.SqlServer/Elsa.ExternalAuthentication.Persistence.EFCore.SqlServer.csproj" }, { - "id": "Elsa.IO.Http", - "project": "src/extensions/io/Elsa.IO.Http/Elsa.IO.Http.csproj" + "id": "Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite", + "project": "core/src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite/Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.IO", - "project": "src/extensions/io/Elsa.IO/Elsa.IO.csproj" + "id": "Elsa.ExternalAuthentication.Persistence.EFCore", + "project": "core/src/modules/Elsa.ExternalAuthentication.Persistence.EFCore/Elsa.ExternalAuthentication.Persistence.EFCore.csproj" }, { - "id": "Elsa.Ldap", - "project": "src/extensions/ldap/Elsa.Ldap/Elsa.Ldap.csproj" + "id": "Elsa.ExternalAuthentication.Secrets", + "project": "core/src/modules/Elsa.ExternalAuthentication.Secrets/Elsa.ExternalAuthentication.Secrets.csproj" }, { - "id": "Elsa.Mqtt", - "project": "src/extensions/mqtt/Elsa.Mqtt/Elsa.Mqtt.csproj" + "id": "Elsa.ExternalAuthentication", + "project": "core/src/modules/Elsa.ExternalAuthentication/Elsa.ExternalAuthentication.csproj" }, { - "id": "Elsa.Persistence.Dapper.Migrations", - "project": "src/extensions/persistence/Elsa.Persistence.Dapper.Migrations/Elsa.Persistence.Dapper.Migrations.csproj" + "id": "Elsa.Hosting.Management", + "project": "core/src/modules/Elsa.Hosting.Management/Elsa.Hosting.Management.csproj" }, { - "id": "Elsa.Persistence.Dapper", - "project": "src/extensions/persistence/Elsa.Persistence.Dapper/Elsa.Persistence.Dapper.csproj" + "id": "Elsa.Http.Webhooks", + "project": "core/src/modules/Elsa.Http.Webhooks/Elsa.Http.Webhooks.csproj" }, { - "id": "Elsa.Persistence.Elasticsearch", - "project": "src/extensions/persistence/Elsa.Persistence.Elasticsearch/Elsa.Persistence.Elasticsearch.csproj" + "id": "Elsa.Http", + "project": "core/src/modules/Elsa.Http/Elsa.Http.csproj" }, { - "id": "Elsa.Persistence.MongoDb", - "project": "src/extensions/persistence/Elsa.Persistence.MongoDb/Elsa.Persistence.MongoDb.csproj" + "id": "Elsa.Identity", + "project": "core/src/modules/Elsa.Identity/Elsa.Identity.csproj" }, { - "id": "Elsa.Retention", - "project": "src/extensions/retention/Elsa.Retention/Elsa.Retention.csproj" + "id": "Elsa.KeyValues", + "project": "core/src/modules/Elsa.KeyValues/Elsa.KeyValues.csproj" }, { - "id": "Elsa.Workflows.Runtime.ProtoActor", - "project": "src/extensions/runtimes/Elsa.Workflows.Runtime.ProtoActor/Elsa.Workflows.Runtime.ProtoActor.csproj" + "id": "Elsa.Labels", + "project": "core/src/modules/Elsa.Labels/Elsa.Labels.csproj" }, { - "id": "Elsa.Scheduling.Hangfire", - "project": "src/extensions/scheduling/Elsa.Scheduling.Hangfire/Elsa.Scheduling.Hangfire.csproj" + "id": "Elsa.Persistence.EFCore.Common", + "project": "core/src/modules/Elsa.Persistence.EFCore.Common/Elsa.Persistence.EFCore.Common.csproj" }, { - "id": "Elsa.Scheduling.Quartz.EFCore.MySql", - "project": "src/extensions/scheduling/Elsa.Scheduling.Quartz.EFCore.MySql/Elsa.Scheduling.Quartz.EFCore.MySql.csproj" + "id": "Elsa.Persistence.EFCore.MySql", + "project": "core/src/modules/Elsa.Persistence.EFCore.MySql/Elsa.Persistence.EFCore.MySql.csproj" }, { - "id": "Elsa.Scheduling.Quartz.EFCore.PostgreSql", - "project": "src/extensions/scheduling/Elsa.Scheduling.Quartz.EFCore.PostgreSql/Elsa.Scheduling.Quartz.EFCore.PostgreSql.csproj" + "id": "Elsa.Persistence.EFCore.Oracle", + "project": "core/src/modules/Elsa.Persistence.EFCore.Oracle/Elsa.Persistence.EFCore.Oracle.csproj" }, { - "id": "Elsa.Scheduling.Quartz.EFCore.SqlServer", - "project": "src/extensions/scheduling/Elsa.Scheduling.Quartz.EFCore.SqlServer/Elsa.Scheduling.Quartz.EFCore.SqlServer.csproj" + "id": "Elsa.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.Persistence.EFCore.PostgreSql/Elsa.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.Scheduling.Quartz.EFCore.Sqlite", - "project": "src/extensions/scheduling/Elsa.Scheduling.Quartz.EFCore.Sqlite/Elsa.Scheduling.Quartz.EFCore.Sqlite.csproj" + "id": "Elsa.Persistence.EFCore.SqlServer", + "project": "core/src/modules/Elsa.Persistence.EFCore.SqlServer/Elsa.Persistence.EFCore.SqlServer.csproj" }, { - "id": "Elsa.Scheduling.Quartz", - "project": "src/extensions/scheduling/Elsa.Scheduling.Quartz/Elsa.Scheduling.Quartz.csproj" + "id": "Elsa.Persistence.EFCore.Sqlite", + "project": "core/src/modules/Elsa.Persistence.EFCore.Sqlite/Elsa.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.ServiceBus.AzureServiceBus", - "project": "src/extensions/servicebus/Elsa.ServiceBus.AzureServiceBus/Elsa.ServiceBus.AzureServiceBus.csproj" + "id": "Elsa.Persistence.EFCore", + "project": "core/src/modules/Elsa.Persistence.EFCore/Elsa.Persistence.EFCore.csproj" }, { - "id": "Elsa.ServiceBus.Kafka", - "project": "src/extensions/servicebus/Elsa.ServiceBus.Kafka/Elsa.ServiceBus.Kafka.csproj" + "id": "Elsa.Persistence.VNext.Extensions", + "project": "core/src/modules/Elsa.Persistence.VNext.Extensions/Elsa.Persistence.VNext.Extensions.csproj" }, { - "id": "Elsa.ServiceBus.MassTransit.AzureServiceBus", - "project": "src/extensions/servicebus/Elsa.ServiceBus.MassTransit.AzureServiceBus/Elsa.ServiceBus.MassTransit.AzureServiceBus.csproj" + "id": "Elsa.Persistence.VNext.MongoDb", + "project": "core/src/modules/Elsa.Persistence.VNext.MongoDb/Elsa.Persistence.VNext.MongoDb.csproj" }, { - "id": "Elsa.ServiceBus.MassTransit.RabbitMq", - "project": "src/extensions/servicebus/Elsa.ServiceBus.MassTransit.RabbitMq/Elsa.ServiceBus.MassTransit.RabbitMq.csproj" + "id": "Elsa.Persistence.VNext.PostgreSql", + "project": "core/src/modules/Elsa.Persistence.VNext.PostgreSql/Elsa.Persistence.VNext.PostgreSql.csproj" }, { - "id": "Elsa.ServiceBus.MassTransit", - "project": "src/extensions/servicebus/Elsa.ServiceBus.MassTransit/Elsa.ServiceBus.MassTransit.csproj" + "id": "Elsa.Persistence.VNext.Relational", + "project": "core/src/modules/Elsa.Persistence.VNext.Relational/Elsa.Persistence.VNext.Relational.csproj" }, { - "id": "Elsa.Sql.MySql", - "project": "src/extensions/sql/Elsa.Sql.MySql/Elsa.Sql.MySql.csproj" + "id": "Elsa.Persistence.VNext.Runtime", + "project": "core/src/modules/Elsa.Persistence.VNext.Runtime/Elsa.Persistence.VNext.Runtime.csproj" }, { - "id": "Elsa.Sql.PostgreSql", - "project": "src/extensions/sql/Elsa.Sql.PostgreSql/Elsa.Sql.PostgreSql.csproj" + "id": "Elsa.Persistence.VNext.SqlServer", + "project": "core/src/modules/Elsa.Persistence.VNext.SqlServer/Elsa.Persistence.VNext.SqlServer.csproj" }, { - "id": "Elsa.Sql.SqlServer", - "project": "src/extensions/sql/Elsa.Sql.SqlServer/Elsa.Sql.SqlServer.csproj" + "id": "Elsa.Persistence.VNext.Sqlite", + "project": "core/src/modules/Elsa.Persistence.VNext.Sqlite/Elsa.Persistence.VNext.Sqlite.csproj" }, { - "id": "Elsa.Sql.Sqlite", - "project": "src/extensions/sql/Elsa.Sql.Sqlite/Elsa.Sql.Sqlite.csproj" + "id": "Elsa.Persistence.VNext", + "project": "core/src/modules/Elsa.Persistence.VNext/Elsa.Persistence.VNext.csproj" }, { - "id": "Elsa.Sql", - "project": "src/extensions/sql/Elsa.Sql/Elsa.Sql.csproj" + "id": "Elsa.Platform.Integration", + "project": "core/src/modules/Elsa.Platform.Integration/Elsa.Platform.Integration.csproj" }, { - "id": "Elsa.Storage.AzureStorage", - "project": "src/extensions/storage/Elsa.Storage.AzureStorage/Elsa.Storage.AzureStorage.csproj" + "id": "Elsa.Resilience.Core", + "project": "core/src/modules/Elsa.Resilience.Core/Elsa.Resilience.Core.csproj" }, { - "id": "Elsa.Storage.Files", - "project": "src/extensions/storage/Elsa.Storage.Files/Elsa.Storage.Files.csproj" + "id": "Elsa.Resilience", + "project": "core/src/modules/Elsa.Resilience/Elsa.Resilience.csproj" }, { - "id": "Elsa.Telnyx", - "project": "src/extensions/telecom/Elsa.Telnyx/Elsa.Telnyx.csproj" + "id": "Elsa.SasTokens", + "project": "core/src/modules/Elsa.SasTokens/Elsa.SasTokens.csproj" }, { - "id": "Elsa.Studio.WorkflowContexts", - "project": "src/extensions/workflows/Elsa.Studio.WorkflowContexts/Elsa.Studio.WorkflowContexts.csproj" + "id": "Elsa.Scheduling", + "project": "core/src/modules/Elsa.Scheduling/Elsa.Scheduling.csproj" }, { - "id": "Elsa.WorkflowContexts", - "project": "src/extensions/workflows/Elsa.WorkflowContexts/Elsa.WorkflowContexts.csproj" + "id": "Elsa.Secrets.JavaScript", + "project": "core/src/modules/Elsa.Secrets.JavaScript/Elsa.Secrets.JavaScript.csproj" }, { - "id": "Elsa.AI.Abstractions", - "project": "src/modules/Elsa.AI.Abstractions/Elsa.AI.Abstractions.csproj" + "id": "Elsa.Secrets.Persistence.EFCore.MySql", + "project": "core/src/modules/Elsa.Secrets.Persistence.EFCore.MySql/Elsa.Secrets.Persistence.EFCore.MySql.csproj" }, { - "id": "Elsa.AI.Copilot", - "project": "src/modules/Elsa.AI.Copilot/Elsa.AI.Copilot.csproj" + "id": "Elsa.Secrets.Persistence.EFCore.Oracle", + "project": "core/src/modules/Elsa.Secrets.Persistence.EFCore.Oracle/Elsa.Secrets.Persistence.EFCore.Oracle.csproj" }, { - "id": "Elsa.AI.Host", - "project": "src/modules/Elsa.AI.Host/Elsa.AI.Host.csproj" + "id": "Elsa.Secrets.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.Secrets.Persistence.EFCore.PostgreSql/Elsa.Secrets.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.AI.Persistence.EFCore.MySql", - "project": "src/modules/Elsa.AI.Persistence.EFCore.MySql/Elsa.AI.Persistence.EFCore.MySql.csproj" + "id": "Elsa.Secrets.Persistence.EFCore.SqlServer", + "project": "core/src/modules/Elsa.Secrets.Persistence.EFCore.SqlServer/Elsa.Secrets.Persistence.EFCore.SqlServer.csproj" }, { - "id": "Elsa.AI.Persistence.EFCore.Oracle", - "project": "src/modules/Elsa.AI.Persistence.EFCore.Oracle/Elsa.AI.Persistence.EFCore.Oracle.csproj" + "id": "Elsa.Secrets.Persistence.EFCore.Sqlite", + "project": "core/src/modules/Elsa.Secrets.Persistence.EFCore.Sqlite/Elsa.Secrets.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.AI.Persistence.EFCore.PostgreSql", - "project": "src/modules/Elsa.AI.Persistence.EFCore.PostgreSql/Elsa.AI.Persistence.EFCore.PostgreSql.csproj" + "id": "Elsa.Secrets.Persistence.EFCore", + "project": "core/src/modules/Elsa.Secrets.Persistence.EFCore/Elsa.Secrets.Persistence.EFCore.csproj" }, { - "id": "Elsa.AI.Persistence.EFCore.SqlServer", - "project": "src/modules/Elsa.AI.Persistence.EFCore.SqlServer/Elsa.AI.Persistence.EFCore.SqlServer.csproj" + "id": "Elsa.Secrets.Persistence.VNext", + "project": "core/src/modules/Elsa.Secrets.Persistence.VNext/Elsa.Secrets.Persistence.VNext.csproj" }, { - "id": "Elsa.AI.Persistence.EFCore.Sqlite", - "project": "src/modules/Elsa.AI.Persistence.EFCore.Sqlite/Elsa.AI.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.Secrets", + "project": "core/src/modules/Elsa.Secrets/Elsa.Secrets.csproj" }, { - "id": "Elsa.AI.Persistence.EFCore", - "project": "src/modules/Elsa.AI.Persistence.EFCore/Elsa.AI.Persistence.EFCore.csproj" + "id": "Elsa.Shells.Api", + "project": "core/src/modules/Elsa.Shells.Api/Elsa.Shells.Api.csproj" }, { - "id": "Elsa.Alterations.Core", - "project": "src/modules/Elsa.Alterations.Core/Elsa.Alterations.Core.csproj" + "id": "Elsa.Tenants.AspNetCore", + "project": "core/src/modules/Elsa.Tenants.AspNetCore/Elsa.Tenants.AspNetCore.csproj" }, { - "id": "Elsa.Alterations", - "project": "src/modules/Elsa.Alterations/Elsa.Alterations.csproj" + "id": "Elsa.Tenants", + "project": "core/src/modules/Elsa.Tenants/Elsa.Tenants.csproj" }, { - "id": "Elsa.Bpmn.Interchange", - "project": "src/modules/Elsa.Bpmn.Interchange/Elsa.Bpmn.Interchange.csproj" + "id": "Elsa.UserTasks.Persistence.EFCore.MySql", + "project": "core/src/modules/Elsa.UserTasks.Persistence.EFCore.MySql/Elsa.UserTasks.Persistence.EFCore.MySql.csproj" }, { - "id": "Elsa.Bpmn", - "project": "src/modules/Elsa.Bpmn/Elsa.Bpmn.csproj" + "id": "Elsa.UserTasks.Persistence.EFCore.Oracle", + "project": "core/src/modules/Elsa.UserTasks.Persistence.EFCore.Oracle/Elsa.UserTasks.Persistence.EFCore.Oracle.csproj" }, { - "id": "Elsa.Caching", - "project": "src/modules/Elsa.Caching/Elsa.Caching.csproj" + "id": "Elsa.UserTasks.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.UserTasks.Persistence.EFCore.PostgreSql/Elsa.UserTasks.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.Common", - "project": "src/modules/Elsa.Common/Elsa.Common.csproj" + "id": "Elsa.UserTasks.Persistence.EFCore.SqlServer", + "project": "core/src/modules/Elsa.UserTasks.Persistence.EFCore.SqlServer/Elsa.UserTasks.Persistence.EFCore.SqlServer.csproj" }, { - "id": "Elsa.Dashboard.Abstractions", - "project": "src/modules/Elsa.Dashboard.Abstractions/Elsa.Dashboard.Abstractions.csproj" + "id": "Elsa.UserTasks.Persistence.EFCore.Sqlite", + "project": "core/src/modules/Elsa.UserTasks.Persistence.EFCore.Sqlite/Elsa.UserTasks.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.Dashboard.Api", - "project": "src/modules/Elsa.Dashboard.Api/Elsa.Dashboard.Api.csproj" + "id": "Elsa.UserTasks.Persistence.EFCore", + "project": "core/src/modules/Elsa.UserTasks.Persistence.EFCore/Elsa.UserTasks.Persistence.EFCore.csproj" }, { - "id": "Elsa.Diagnostics.ConsoleLogs.Dashboard", - "project": "src/modules/Elsa.Diagnostics.ConsoleLogs.Dashboard/Elsa.Diagnostics.ConsoleLogs.Dashboard.csproj" + "id": "Elsa.UserTasks.Persistence.VNext", + "project": "core/src/modules/Elsa.UserTasks.Persistence.VNext/Elsa.UserTasks.Persistence.VNext.csproj" }, { - "id": "Elsa.Diagnostics.ConsoleLogs", - "project": "src/modules/Elsa.Diagnostics.ConsoleLogs/Elsa.Diagnostics.ConsoleLogs.csproj" + "id": "Elsa.UserTasks", + "project": "core/src/modules/Elsa.UserTasks/Elsa.UserTasks.csproj" }, { - "id": "Elsa.Diagnostics.OpenTelemetry", - "project": "src/modules/Elsa.Diagnostics.OpenTelemetry/Elsa.Diagnostics.OpenTelemetry.csproj" + "id": "Elsa.WorkflowProviders.BlobStorage.ElsaScript", + "project": "core/src/modules/Elsa.WorkflowProviders.BlobStorage.ElsaScript/Elsa.WorkflowProviders.BlobStorage.ElsaScript.csproj" }, { - "id": "Elsa.Diagnostics.StructuredLogs.Dashboard", - "project": "src/modules/Elsa.Diagnostics.StructuredLogs.Dashboard/Elsa.Diagnostics.StructuredLogs.Dashboard.csproj" + "id": "Elsa.WorkflowProviders.BlobStorage", + "project": "core/src/modules/Elsa.WorkflowProviders.BlobStorage/Elsa.WorkflowProviders.BlobStorage.csproj" }, { - "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Relational", - "project": "src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Relational/Elsa.Diagnostics.StructuredLogs.Persistence.Relational.csproj" + "id": "Elsa.Workflows.Admission.Persistence.EFCore.PostgreSql", + "project": "core/src/modules/Elsa.Workflows.Admission.Persistence.EFCore.PostgreSql/Elsa.Workflows.Admission.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite", - "project": "src/modules/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite/Elsa.Diagnostics.StructuredLogs.Persistence.Sqlite.csproj" + "id": "Elsa.Workflows.Admission.Persistence.EFCore", + "project": "core/src/modules/Elsa.Workflows.Admission.Persistence.EFCore/Elsa.Workflows.Admission.Persistence.EFCore.csproj" }, { - "id": "Elsa.Diagnostics.StructuredLogs", - "project": "src/modules/Elsa.Diagnostics.StructuredLogs/Elsa.Diagnostics.StructuredLogs.csproj" + "id": "Elsa.Workflows.Admission", + "project": "core/src/modules/Elsa.Workflows.Admission/Elsa.Workflows.Admission.csproj" }, { - "id": "Elsa.Dsl.ElsaScript", - "project": "src/modules/Elsa.Dsl.ElsaScript/Elsa.Dsl.ElsaScript.csproj" + "id": "Elsa.Workflows.Api", + "project": "core/src/modules/Elsa.Workflows.Api/Elsa.Workflows.Api.csproj" }, { - "id": "Elsa.Expressions.CSharp", - "project": "src/modules/Elsa.Expressions.CSharp/Elsa.Expressions.CSharp.csproj" + "id": "Elsa.Workflows.Core", + "project": "core/src/modules/Elsa.Workflows.Core/Elsa.Workflows.Core.csproj" }, { - "id": "Elsa.Expressions.JavaScript.Libraries", - "project": "src/modules/Elsa.Expressions.JavaScript.Libraries/Elsa.Expressions.JavaScript.Libraries.csproj" + "id": "Elsa.Workflows.Management", + "project": "core/src/modules/Elsa.Workflows.Management/Elsa.Workflows.Management.csproj" }, { - "id": "Elsa.Expressions.JavaScript", - "project": "src/modules/Elsa.Expressions.JavaScript/Elsa.Expressions.JavaScript.csproj" + "id": "Elsa.Workflows.Runtime.Dashboard", + "project": "core/src/modules/Elsa.Workflows.Runtime.Dashboard/Elsa.Workflows.Runtime.Dashboard.csproj" }, { - "id": "Elsa.Expressions.Liquid", - "project": "src/modules/Elsa.Expressions.Liquid/Elsa.Expressions.Liquid.csproj" + "id": "Elsa.Workflows.Runtime.Distributed", + "project": "core/src/modules/Elsa.Workflows.Runtime.Distributed/Elsa.Workflows.Runtime.Distributed.csproj" }, { - "id": "Elsa.Expressions.Python", - "project": "src/modules/Elsa.Expressions.Python/Elsa.Expressions.Python.csproj" + "id": "Elsa.Workflows.Runtime", + "project": "core/src/modules/Elsa.Workflows.Runtime/Elsa.Workflows.Runtime.csproj" }, { - "id": "Elsa.Expressions", - "project": "src/modules/Elsa.Expressions/Elsa.Expressions.csproj" + "id": "Elsa", + "project": "core/src/modules/Elsa/Elsa.csproj" }, { - "id": "Elsa.ExternalAuthentication.OpenIdConnect", - "project": "src/modules/Elsa.ExternalAuthentication.OpenIdConnect/Elsa.ExternalAuthentication.OpenIdConnect.csproj" + "id": "Elsa.Actors.ProtoActor.PubSub.Redis", + "project": "extensions/src/actors/Elsa.Actors.ProtoActor.PubSub.Redis/Elsa.Actors.ProtoActor.PubSub.Redis.csproj" }, { - "id": "Elsa.ExternalAuthentication.Persistence.EFCore.MySql", - "project": "src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.MySql/Elsa.ExternalAuthentication.Persistence.EFCore.MySql.csproj" + "id": "Elsa.Actors.ProtoActor", + "project": "extensions/src/actors/Elsa.Actors.ProtoActor/Elsa.Actors.ProtoActor.csproj" }, { - "id": "Elsa.ExternalAuthentication.Persistence.EFCore.Oracle", - "project": "src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.Oracle/Elsa.ExternalAuthentication.Persistence.EFCore.Oracle.csproj" + "id": "Elsa.Agents.Activities", + "project": "extensions/src/agents/Elsa.Agents.Activities/Elsa.Agents.Activities.csproj" }, { - "id": "Elsa.ExternalAuthentication.Persistence.EFCore.PostgreSql", - "project": "src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.PostgreSql/Elsa.ExternalAuthentication.Persistence.EFCore.PostgreSql.csproj" + "id": "Elsa.Agents.Api", + "project": "extensions/src/agents/Elsa.Agents.Api/Elsa.Agents.Api.csproj" }, { - "id": "Elsa.ExternalAuthentication.Persistence.EFCore.SqlServer", - "project": "src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.SqlServer/Elsa.ExternalAuthentication.Persistence.EFCore.SqlServer.csproj" + "id": "Elsa.Agents.AzureOpenAI", + "project": "extensions/src/agents/Elsa.Agents.AzureOpenAI/Elsa.Agents.AzureOpenAI.csproj" }, { - "id": "Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite", - "project": "src/modules/Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite/Elsa.ExternalAuthentication.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.Agents.Core", + "project": "extensions/src/agents/Elsa.Agents.Core/Elsa.Agents.Core.csproj" }, { - "id": "Elsa.ExternalAuthentication.Persistence.EFCore", - "project": "src/modules/Elsa.ExternalAuthentication.Persistence.EFCore/Elsa.ExternalAuthentication.Persistence.EFCore.csproj" + "id": "Elsa.Agents.Models", + "project": "extensions/src/agents/Elsa.Agents.Models/Elsa.Agents.Models.csproj" }, { - "id": "Elsa.ExternalAuthentication.Secrets", - "project": "src/modules/Elsa.ExternalAuthentication.Secrets/Elsa.ExternalAuthentication.Secrets.csproj" + "id": "Elsa.Agents.OpenAI", + "project": "extensions/src/agents/Elsa.Agents.OpenAI/Elsa.Agents.OpenAI.csproj" }, { - "id": "Elsa.ExternalAuthentication", - "project": "src/modules/Elsa.ExternalAuthentication/Elsa.ExternalAuthentication.csproj" + "id": "Elsa.Agents.Persistence.EFCore.MySql", + "project": "extensions/src/agents/Elsa.Agents.Persistence.EFCore.MySql/Elsa.Agents.Persistence.EFCore.MySql.csproj" }, { - "id": "Elsa.Hosting.Management", - "project": "src/modules/Elsa.Hosting.Management/Elsa.Hosting.Management.csproj" + "id": "Elsa.Agents.Persistence.EFCore.PostgreSql", + "project": "extensions/src/agents/Elsa.Agents.Persistence.EFCore.PostgreSql/Elsa.Agents.Persistence.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.Http.Webhooks", - "project": "src/modules/Elsa.Http.Webhooks/Elsa.Http.Webhooks.csproj" + "id": "Elsa.Agents.Persistence.EFCore.SqlServer", + "project": "extensions/src/agents/Elsa.Agents.Persistence.EFCore.SqlServer/Elsa.Agents.Persistence.EFCore.SqlServer.csproj" }, { - "id": "Elsa.Http", - "project": "src/modules/Elsa.Http/Elsa.Http.csproj" + "id": "Elsa.Agents.Persistence.EFCore.Sqlite", + "project": "extensions/src/agents/Elsa.Agents.Persistence.EFCore.Sqlite/Elsa.Agents.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.Identity", - "project": "src/modules/Elsa.Identity/Elsa.Identity.csproj" + "id": "Elsa.Agents.Persistence.EFCore", + "project": "extensions/src/agents/Elsa.Agents.Persistence.EFCore/Elsa.Agents.Persistence.EFCore.csproj" }, { - "id": "Elsa.KeyValues", - "project": "src/modules/Elsa.KeyValues/Elsa.KeyValues.csproj" + "id": "Elsa.Agents.Persistence", + "project": "extensions/src/agents/Elsa.Agents.Persistence/Elsa.Agents.Persistence.csproj" }, { - "id": "Elsa.Labels", - "project": "src/modules/Elsa.Labels/Elsa.Labels.csproj" + "id": "Elsa.Agents", + "project": "extensions/src/agents/Elsa.Agents/Elsa.Agents.csproj" }, { - "id": "Elsa.Persistence.EFCore.Common", - "project": "src/modules/Elsa.Persistence.EFCore.Common/Elsa.Persistence.EFCore.Common.csproj" + "id": "Elsa.Studio.Agents", + "project": "extensions/src/agents/Elsa.Studio.Agents/Elsa.Studio.Agents.csproj" }, { - "id": "Elsa.Persistence.EFCore.MySql", - "project": "src/modules/Elsa.Persistence.EFCore.MySql/Elsa.Persistence.EFCore.MySql.csproj" + "id": "Elsa.Alterations.MassTransit", + "project": "extensions/src/alterations/Elsa.Alterations.MassTransit/Elsa.Alterations.MassTransit.csproj" }, { - "id": "Elsa.Persistence.EFCore.Oracle", - "project": "src/modules/Elsa.Persistence.EFCore.Oracle/Elsa.Persistence.EFCore.Oracle.csproj" + "id": "Elsa.Caching.Distributed.MassTransit", + "project": "extensions/src/caching/Elsa.Caching.Distributed.MassTransit/Elsa.Caching.Distributed.MassTransit.csproj" }, { - "id": "Elsa.Persistence.EFCore.PostgreSql", - "project": "src/modules/Elsa.Persistence.EFCore.PostgreSql/Elsa.Persistence.EFCore.PostgreSql.csproj" + "id": "Elsa.Caching.Distributed.ProtoActor", + "project": "extensions/src/caching/Elsa.Caching.Distributed.ProtoActor/Elsa.Caching.Distributed.ProtoActor.csproj" }, { - "id": "Elsa.Persistence.EFCore.SqlServer", - "project": "src/modules/Elsa.Persistence.EFCore.SqlServer/Elsa.Persistence.EFCore.SqlServer.csproj" + "id": "Elsa.Caching.Distributed", + "project": "extensions/src/caching/Elsa.Caching.Distributed/Elsa.Caching.Distributed.csproj" }, { - "id": "Elsa.Persistence.EFCore.Sqlite", - "project": "src/modules/Elsa.Persistence.EFCore.Sqlite/Elsa.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.OrchardCore", + "project": "extensions/src/cms/Elsa.OrchardCore/Elsa.OrchardCore.csproj" }, { - "id": "Elsa.Persistence.EFCore", - "project": "src/modules/Elsa.Persistence.EFCore/Elsa.Persistence.EFCore.csproj" + "id": "Elsa.Slack", + "project": "extensions/src/communication/Elsa.Slack/Elsa.Slack.csproj" }, { - "id": "Elsa.Persistence.VNext.Extensions", - "project": "src/modules/Elsa.Persistence.VNext.Extensions/Elsa.Persistence.VNext.Extensions.csproj" + "id": "Elsa.Connections.Api", + "project": "extensions/src/connections/Elsa.Connections.Api/Elsa.Connections.Api.csproj" }, { - "id": "Elsa.Persistence.VNext.MongoDb", - "project": "src/modules/Elsa.Persistence.VNext.MongoDb/Elsa.Persistence.VNext.MongoDb.csproj" + "id": "Elsa.Connections.Core", + "project": "extensions/src/connections/Elsa.Connections.Core/Elsa.Connections.Core.csproj" }, { - "id": "Elsa.Persistence.VNext.PostgreSql", - "project": "src/modules/Elsa.Persistence.VNext.PostgreSql/Elsa.Persistence.VNext.PostgreSql.csproj" + "id": "Elsa.Connections.Models", + "project": "extensions/src/connections/Elsa.Connections.Models/Elsa.Connections.Models.csproj" }, { - "id": "Elsa.Persistence.VNext.Relational", - "project": "src/modules/Elsa.Persistence.VNext.Relational/Elsa.Persistence.VNext.Relational.csproj" + "id": "Elsa.Connections.Persistence.EFCore.Sqlite", + "project": "extensions/src/connections/Elsa.Connections.Persistence.EFCore.Sqlite/Elsa.Connections.Persistence.EFCore.Sqlite.csproj" }, { - "id": "Elsa.Persistence.VNext.Runtime", - "project": "src/modules/Elsa.Persistence.VNext.Runtime/Elsa.Persistence.VNext.Runtime.csproj" + "id": "Elsa.Connections.Persistence.EFCore", + "project": "extensions/src/connections/Elsa.Connections.Persistence.EFCore/Elsa.Connections.Persistence.EFCore.csproj" }, { - "id": "Elsa.Persistence.VNext.SqlServer", - "project": "src/modules/Elsa.Persistence.VNext.SqlServer/Elsa.Persistence.VNext.SqlServer.csproj" + "id": "Elsa.Connections.Persistence", + "project": "extensions/src/connections/Elsa.Connections.Persistence/Elsa.Connections.Persistence.csproj" }, { - "id": "Elsa.Persistence.VNext.Sqlite", - "project": "src/modules/Elsa.Persistence.VNext.Sqlite/Elsa.Persistence.VNext.Sqlite.csproj" + "id": "Elsa.Data.Csv", + "project": "extensions/src/data/Elsa.Data.Csv/Elsa.Data.Csv.csproj" }, { - "id": "Elsa.Persistence.VNext", - "project": "src/modules/Elsa.Persistence.VNext/Elsa.Persistence.VNext.csproj" + "id": "Elsa.DevOps.GitHub", + "project": "extensions/src/devops/Elsa.DevOps.GitHub/Elsa.DevOps.GitHub.csproj" }, { - "id": "Elsa.Platform.Integration", - "project": "src/modules/Elsa.Platform.Integration/Elsa.Platform.Integration.csproj" + "id": "Elsa.Logging.Console", + "project": "extensions/src/diagnostics/Elsa.Logging.Console/Elsa.Logging.Console.csproj" }, { - "id": "Elsa.Resilience.Core", - "project": "src/modules/Elsa.Resilience.Core/Elsa.Resilience.Core.csproj" + "id": "Elsa.Logging.Core", + "project": "extensions/src/diagnostics/Elsa.Logging.Core/Elsa.Logging.Core.csproj" }, { - "id": "Elsa.Resilience", - "project": "src/modules/Elsa.Resilience/Elsa.Resilience.csproj" + "id": "Elsa.Logging.Serilog", + "project": "extensions/src/diagnostics/Elsa.Logging.Serilog/Elsa.Logging.Serilog.csproj" }, { - "id": "Elsa.SasTokens", - "project": "src/modules/Elsa.SasTokens/Elsa.SasTokens.csproj" + "id": "Elsa.Logging", + "project": "extensions/src/diagnostics/Elsa.Logging/Elsa.Logging.csproj" }, { - "id": "Elsa.Scheduling", - "project": "src/modules/Elsa.Scheduling/Elsa.Scheduling.csproj" + "id": "Elsa.OpenTelemetry", + "project": "extensions/src/diagnostics/Elsa.OpenTelemetry/Elsa.OpenTelemetry.csproj" }, { - "id": "Elsa.Secrets.JavaScript", - "project": "src/modules/Elsa.Secrets.JavaScript/Elsa.Secrets.JavaScript.csproj" + "id": "Elsa.DropIns.Core", + "project": "extensions/src/dropins/Elsa.DropIns.Core/Elsa.DropIns.Core.csproj" }, { - "id": "Elsa.Secrets.Persistence.EFCore.MySql", - "project": "src/modules/Elsa.Secrets.Persistence.EFCore.MySql/Elsa.Secrets.Persistence.EFCore.MySql.csproj" + "id": "Elsa.DropIns", + "project": "extensions/src/dropins/Elsa.DropIns/Elsa.DropIns.csproj" }, { - "id": "Elsa.Secrets.Persistence.EFCore.Oracle", - "project": "src/modules/Elsa.Secrets.Persistence.EFCore.Oracle/Elsa.Secrets.Persistence.EFCore.Oracle.csproj" + "id": "Elsa.Email", + "project": "extensions/src/email/Elsa.Email/Elsa.Email.csproj" }, { - "id": "Elsa.Secrets.Persistence.EFCore.PostgreSql", - "project": "src/modules/Elsa.Secrets.Persistence.EFCore.PostgreSql/Elsa.Secrets.Persistence.EFCore.PostgreSql.csproj" + "id": "Elsa.Http.OpenApi", + "project": "extensions/src/http/Elsa.Http.OpenApi/Elsa.Http.OpenApi.csproj" }, { - "id": "Elsa.Secrets.Persistence.EFCore.SqlServer", - "project": "src/modules/Elsa.Secrets.Persistence.EFCore.SqlServer/Elsa.Secrets.Persistence.EFCore.SqlServer.csproj" + "id": "Elsa.IO.Compression", + "project": "extensions/src/io/Elsa.IO.Compression/Elsa.IO.Compression.csproj" }, { - "id": "Elsa.Secrets.Persistence.EFCore.Sqlite", - "project": "src/modules/Elsa.Secrets.Persistence.EFCore.Sqlite/Elsa.Secrets.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.IO.Http", + "project": "extensions/src/io/Elsa.IO.Http/Elsa.IO.Http.csproj" }, { - "id": "Elsa.Secrets.Persistence.EFCore", - "project": "src/modules/Elsa.Secrets.Persistence.EFCore/Elsa.Secrets.Persistence.EFCore.csproj" + "id": "Elsa.IO", + "project": "extensions/src/io/Elsa.IO/Elsa.IO.csproj" }, { - "id": "Elsa.Secrets.Persistence.VNext", - "project": "src/modules/Elsa.Secrets.Persistence.VNext/Elsa.Secrets.Persistence.VNext.csproj" + "id": "Elsa.Ldap", + "project": "extensions/src/ldap/Elsa.Ldap/Elsa.Ldap.csproj" }, { - "id": "Elsa.Secrets", - "project": "src/modules/Elsa.Secrets/Elsa.Secrets.csproj" + "id": "Elsa.Mqtt", + "project": "extensions/src/mqtt/Elsa.Mqtt/Elsa.Mqtt.csproj" }, { - "id": "Elsa.Shells.Api", - "project": "src/modules/Elsa.Shells.Api/Elsa.Shells.Api.csproj" + "id": "Elsa.Persistence.Dapper.Migrations", + "project": "extensions/src/persistence/Elsa.Persistence.Dapper.Migrations/Elsa.Persistence.Dapper.Migrations.csproj" }, { - "id": "Elsa.Tenants.AspNetCore", - "project": "src/modules/Elsa.Tenants.AspNetCore/Elsa.Tenants.AspNetCore.csproj" + "id": "Elsa.Persistence.Dapper", + "project": "extensions/src/persistence/Elsa.Persistence.Dapper/Elsa.Persistence.Dapper.csproj" }, { - "id": "Elsa.Tenants", - "project": "src/modules/Elsa.Tenants/Elsa.Tenants.csproj" + "id": "Elsa.Persistence.Elasticsearch", + "project": "extensions/src/persistence/Elsa.Persistence.Elasticsearch/Elsa.Persistence.Elasticsearch.csproj" }, { - "id": "Elsa.UserTasks.Persistence.EFCore.MySql", - "project": "src/modules/Elsa.UserTasks.Persistence.EFCore.MySql/Elsa.UserTasks.Persistence.EFCore.MySql.csproj" + "id": "Elsa.Persistence.MongoDb", + "project": "extensions/src/persistence/Elsa.Persistence.MongoDb/Elsa.Persistence.MongoDb.csproj" }, { - "id": "Elsa.UserTasks.Persistence.EFCore.Oracle", - "project": "src/modules/Elsa.UserTasks.Persistence.EFCore.Oracle/Elsa.UserTasks.Persistence.EFCore.Oracle.csproj" + "id": "Elsa.Retention", + "project": "extensions/src/retention/Elsa.Retention/Elsa.Retention.csproj" }, { - "id": "Elsa.UserTasks.Persistence.EFCore.PostgreSql", - "project": "src/modules/Elsa.UserTasks.Persistence.EFCore.PostgreSql/Elsa.UserTasks.Persistence.EFCore.PostgreSql.csproj" + "id": "Elsa.Workflows.Runtime.ProtoActor", + "project": "extensions/src/runtimes/Elsa.Workflows.Runtime.ProtoActor/Elsa.Workflows.Runtime.ProtoActor.csproj" }, { - "id": "Elsa.UserTasks.Persistence.EFCore.SqlServer", - "project": "src/modules/Elsa.UserTasks.Persistence.EFCore.SqlServer/Elsa.UserTasks.Persistence.EFCore.SqlServer.csproj" + "id": "Elsa.Scheduling.Hangfire", + "project": "extensions/src/scheduling/Elsa.Scheduling.Hangfire/Elsa.Scheduling.Hangfire.csproj" }, { - "id": "Elsa.UserTasks.Persistence.EFCore.Sqlite", - "project": "src/modules/Elsa.UserTasks.Persistence.EFCore.Sqlite/Elsa.UserTasks.Persistence.EFCore.Sqlite.csproj" + "id": "Elsa.Scheduling.Quartz.EFCore.MySql", + "project": "extensions/src/scheduling/Elsa.Scheduling.Quartz.EFCore.MySql/Elsa.Scheduling.Quartz.EFCore.MySql.csproj" }, { - "id": "Elsa.UserTasks.Persistence.EFCore", - "project": "src/modules/Elsa.UserTasks.Persistence.EFCore/Elsa.UserTasks.Persistence.EFCore.csproj" + "id": "Elsa.Scheduling.Quartz.EFCore.PostgreSql", + "project": "extensions/src/scheduling/Elsa.Scheduling.Quartz.EFCore.PostgreSql/Elsa.Scheduling.Quartz.EFCore.PostgreSql.csproj" }, { - "id": "Elsa.UserTasks.Persistence.VNext", - "project": "src/modules/Elsa.UserTasks.Persistence.VNext/Elsa.UserTasks.Persistence.VNext.csproj" + "id": "Elsa.Scheduling.Quartz.EFCore.SqlServer", + "project": "extensions/src/scheduling/Elsa.Scheduling.Quartz.EFCore.SqlServer/Elsa.Scheduling.Quartz.EFCore.SqlServer.csproj" }, { - "id": "Elsa.UserTasks", - "project": "src/modules/Elsa.UserTasks/Elsa.UserTasks.csproj" + "id": "Elsa.Scheduling.Quartz.EFCore.Sqlite", + "project": "extensions/src/scheduling/Elsa.Scheduling.Quartz.EFCore.Sqlite/Elsa.Scheduling.Quartz.EFCore.Sqlite.csproj" }, { - "id": "Elsa.WorkflowProviders.BlobStorage.ElsaScript", - "project": "src/modules/Elsa.WorkflowProviders.BlobStorage.ElsaScript/Elsa.WorkflowProviders.BlobStorage.ElsaScript.csproj" + "id": "Elsa.Scheduling.Quartz", + "project": "extensions/src/scheduling/Elsa.Scheduling.Quartz/Elsa.Scheduling.Quartz.csproj" }, { - "id": "Elsa.WorkflowProviders.BlobStorage", - "project": "src/modules/Elsa.WorkflowProviders.BlobStorage/Elsa.WorkflowProviders.BlobStorage.csproj" + "id": "Elsa.ServiceBus.AzureServiceBus", + "project": "extensions/src/servicebus/Elsa.ServiceBus.AzureServiceBus/Elsa.ServiceBus.AzureServiceBus.csproj" }, { - "id": "Elsa.Workflows.Api", - "project": "src/modules/Elsa.Workflows.Api/Elsa.Workflows.Api.csproj" + "id": "Elsa.ServiceBus.Kafka", + "project": "extensions/src/servicebus/Elsa.ServiceBus.Kafka/Elsa.ServiceBus.Kafka.csproj" }, { - "id": "Elsa.Workflows.Core", - "project": "src/modules/Elsa.Workflows.Core/Elsa.Workflows.Core.csproj" + "id": "Elsa.ServiceBus.MassTransit.AzureServiceBus", + "project": "extensions/src/servicebus/Elsa.ServiceBus.MassTransit.AzureServiceBus/Elsa.ServiceBus.MassTransit.AzureServiceBus.csproj" }, { - "id": "Elsa.Workflows.Management", - "project": "src/modules/Elsa.Workflows.Management/Elsa.Workflows.Management.csproj" + "id": "Elsa.ServiceBus.MassTransit.RabbitMq", + "project": "extensions/src/servicebus/Elsa.ServiceBus.MassTransit.RabbitMq/Elsa.ServiceBus.MassTransit.RabbitMq.csproj" }, { - "id": "Elsa.Workflows.Runtime.Dashboard", - "project": "src/modules/Elsa.Workflows.Runtime.Dashboard/Elsa.Workflows.Runtime.Dashboard.csproj" + "id": "Elsa.ServiceBus.MassTransit", + "project": "extensions/src/servicebus/Elsa.ServiceBus.MassTransit/Elsa.ServiceBus.MassTransit.csproj" }, { - "id": "Elsa.Workflows.Runtime.Distributed", - "project": "src/modules/Elsa.Workflows.Runtime.Distributed/Elsa.Workflows.Runtime.Distributed.csproj" + "id": "Elsa.Sql.MySql", + "project": "extensions/src/sql/Elsa.Sql.MySql/Elsa.Sql.MySql.csproj" }, { - "id": "Elsa.Workflows.Runtime", - "project": "src/modules/Elsa.Workflows.Runtime/Elsa.Workflows.Runtime.csproj" + "id": "Elsa.Sql.PostgreSql", + "project": "extensions/src/sql/Elsa.Sql.PostgreSql/Elsa.Sql.PostgreSql.csproj" }, { - "id": "Elsa", - "project": "src/modules/Elsa/Elsa.csproj" + "id": "Elsa.Sql.SqlServer", + "project": "extensions/src/sql/Elsa.Sql.SqlServer/Elsa.Sql.SqlServer.csproj" + }, + { + "id": "Elsa.Sql.Sqlite", + "project": "extensions/src/sql/Elsa.Sql.Sqlite/Elsa.Sql.Sqlite.csproj" + }, + { + "id": "Elsa.Sql", + "project": "extensions/src/sql/Elsa.Sql/Elsa.Sql.csproj" + }, + { + "id": "Elsa.Storage.AzureStorage", + "project": "extensions/src/storage/Elsa.Storage.AzureStorage/Elsa.Storage.AzureStorage.csproj" + }, + { + "id": "Elsa.Storage.Files", + "project": "extensions/src/storage/Elsa.Storage.Files/Elsa.Storage.Files.csproj" + }, + { + "id": "Elsa.Telnyx", + "project": "extensions/src/telecom/Elsa.Telnyx/Elsa.Telnyx.csproj" + }, + { + "id": "Elsa.Studio.WorkflowContexts", + "project": "extensions/src/workflows/Elsa.Studio.WorkflowContexts/Elsa.Studio.WorkflowContexts.csproj" + }, + { + "id": "Elsa.WorkflowContexts", + "project": "extensions/src/workflows/Elsa.WorkflowContexts/Elsa.WorkflowContexts.csproj" }, { "id": "Elsa.Studio", - "project": "src/studio/bundles/Elsa.Studio/Elsa.Studio.csproj" + "project": "studio/src/bundles/Elsa.Studio/Elsa.Studio.csproj" }, { "id": "Elsa.Studio.Core.BlazorServer", - "project": "src/studio/framework/Elsa.Studio.Core.BlazorServer/Elsa.Studio.Core.BlazorServer.csproj" + "project": "studio/src/framework/Elsa.Studio.Core.BlazorServer/Elsa.Studio.Core.BlazorServer.csproj" }, { "id": "Elsa.Studio.Core.BlazorWasm", - "project": "src/studio/framework/Elsa.Studio.Core.BlazorWasm/Elsa.Studio.Core.BlazorWasm.csproj" + "project": "studio/src/framework/Elsa.Studio.Core.BlazorWasm/Elsa.Studio.Core.BlazorWasm.csproj" }, { "id": "Elsa.Studio.Core", - "project": "src/studio/framework/Elsa.Studio.Core/Elsa.Studio.Core.csproj" + "project": "studio/src/framework/Elsa.Studio.Core/Elsa.Studio.Core.csproj" }, { "id": "Elsa.Studio.DomInterop", - "project": "src/studio/framework/Elsa.Studio.DomInterop/Elsa.Studio.DomInterop.csproj" + "project": "studio/src/framework/Elsa.Studio.DomInterop/Elsa.Studio.DomInterop.csproj" }, { "id": "Elsa.Studio.Shared", - "project": "src/studio/framework/Elsa.Studio.Shared/Elsa.Studio.Shared.csproj" + "project": "studio/src/framework/Elsa.Studio.Shared/Elsa.Studio.Shared.csproj" }, { "id": "Elsa.Studio.Shell", - "project": "src/studio/framework/Elsa.Studio.Shell/Elsa.Studio.Shell.csproj" + "project": "studio/src/framework/Elsa.Studio.Shell/Elsa.Studio.Shell.csproj" }, { "id": "Elsa.Studio.Translations", - "project": "src/studio/framework/Elsa.Studio.Translations/Elsa.Studio.Translations.csproj" + "project": "studio/src/framework/Elsa.Studio.Translations/Elsa.Studio.Translations.csproj" }, { "id": "Elsa.Studio.AI", - "project": "src/studio/modules/Elsa.Studio.AI/Elsa.Studio.AI.csproj" + "project": "studio/src/modules/Elsa.Studio.AI/Elsa.Studio.AI.csproj" }, { "id": "Elsa.Studio.ActivityPortProviders", - "project": "src/studio/modules/Elsa.Studio.ActivityPortProviders/Elsa.Studio.ActivityPortProviders.csproj" + "project": "studio/src/modules/Elsa.Studio.ActivityPortProviders/Elsa.Studio.ActivityPortProviders.csproj" }, { "id": "Elsa.Studio.Alterations", - "project": "src/studio/modules/Elsa.Studio.Alterations/Elsa.Studio.Alterations.csproj" + "project": "studio/src/modules/Elsa.Studio.Alterations/Elsa.Studio.Alterations.csproj" }, { "id": "Elsa.Studio.Authentication.Abstractions", - "project": "src/studio/modules/Elsa.Studio.Authentication.Abstractions/Elsa.Studio.Authentication.Abstractions.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.Abstractions/Elsa.Studio.Authentication.Abstractions.csproj" }, { "id": "Elsa.Studio.Authentication.ElsaIdentity.BlazorServer", - "project": "src/studio/modules/Elsa.Studio.Authentication.ElsaIdentity.BlazorServer/Elsa.Studio.Authentication.ElsaIdentity.BlazorServer.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.ElsaIdentity.BlazorServer/Elsa.Studio.Authentication.ElsaIdentity.BlazorServer.csproj" }, { "id": "Elsa.Studio.Authentication.ElsaIdentity.BlazorWasm", - "project": "src/studio/modules/Elsa.Studio.Authentication.ElsaIdentity.BlazorWasm/Elsa.Studio.Authentication.ElsaIdentity.BlazorWasm.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.ElsaIdentity.BlazorWasm/Elsa.Studio.Authentication.ElsaIdentity.BlazorWasm.csproj" }, { "id": "Elsa.Studio.Authentication.ElsaIdentity.UI", - "project": "src/studio/modules/Elsa.Studio.Authentication.ElsaIdentity.UI/Elsa.Studio.Authentication.ElsaIdentity.UI.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.ElsaIdentity.UI/Elsa.Studio.Authentication.ElsaIdentity.UI.csproj" }, { "id": "Elsa.Studio.Authentication.ElsaIdentity", - "project": "src/studio/modules/Elsa.Studio.Authentication.ElsaIdentity/Elsa.Studio.Authentication.ElsaIdentity.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.ElsaIdentity/Elsa.Studio.Authentication.ElsaIdentity.csproj" }, { "id": "Elsa.Studio.Authentication.OpenIdConnect.BlazorServer", - "project": "src/studio/modules/Elsa.Studio.Authentication.OpenIdConnect.BlazorServer/Elsa.Studio.Authentication.OpenIdConnect.BlazorServer.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.OpenIdConnect.BlazorServer/Elsa.Studio.Authentication.OpenIdConnect.BlazorServer.csproj" }, { "id": "Elsa.Studio.Authentication.OpenIdConnect.BlazorWasm", - "project": "src/studio/modules/Elsa.Studio.Authentication.OpenIdConnect.BlazorWasm/Elsa.Studio.Authentication.OpenIdConnect.BlazorWasm.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.OpenIdConnect.BlazorWasm/Elsa.Studio.Authentication.OpenIdConnect.BlazorWasm.csproj" }, { "id": "Elsa.Studio.Authentication.OpenIdConnect", - "project": "src/studio/modules/Elsa.Studio.Authentication.OpenIdConnect/Elsa.Studio.Authentication.OpenIdConnect.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.OpenIdConnect/Elsa.Studio.Authentication.OpenIdConnect.csproj" }, { "id": "Elsa.Studio.Authentication.Themes", - "project": "src/studio/modules/Elsa.Studio.Authentication.Themes/Elsa.Studio.Authentication.Themes.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.Themes/Elsa.Studio.Authentication.Themes.csproj" }, { "id": "Elsa.Studio.Authentication.UI", - "project": "src/studio/modules/Elsa.Studio.Authentication.UI/Elsa.Studio.Authentication.UI.csproj" + "project": "studio/src/modules/Elsa.Studio.Authentication.UI/Elsa.Studio.Authentication.UI.csproj" }, { "id": "Elsa.Studio.Counter", - "project": "src/studio/modules/Elsa.Studio.Counter/Elsa.Studio.Counter.csproj" + "project": "studio/src/modules/Elsa.Studio.Counter/Elsa.Studio.Counter.csproj" }, { "id": "Elsa.Studio.Dashboard", - "project": "src/studio/modules/Elsa.Studio.Dashboard/Elsa.Studio.Dashboard.csproj" + "project": "studio/src/modules/Elsa.Studio.Dashboard/Elsa.Studio.Dashboard.csproj" }, { "id": "Elsa.Studio.Diagnostics.ConsoleLogs.Dashboard", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.ConsoleLogs.Dashboard/Elsa.Studio.Diagnostics.ConsoleLogs.Dashboard.csproj" + "project": "studio/src/modules/Elsa.Studio.Diagnostics.ConsoleLogs.Dashboard/Elsa.Studio.Diagnostics.ConsoleLogs.Dashboard.csproj" }, { "id": "Elsa.Studio.Diagnostics.ConsoleLogs", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.ConsoleLogs/Elsa.Studio.Diagnostics.ConsoleLogs.csproj" + "project": "studio/src/modules/Elsa.Studio.Diagnostics.ConsoleLogs/Elsa.Studio.Diagnostics.ConsoleLogs.csproj" }, { "id": "Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard/Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard.csproj" + "project": "studio/src/modules/Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard/Elsa.Studio.Diagnostics.OpenTelemetry.Dashboard.csproj" }, { "id": "Elsa.Studio.Diagnostics.OpenTelemetry", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.OpenTelemetry/Elsa.Studio.Diagnostics.OpenTelemetry.csproj" + "project": "studio/src/modules/Elsa.Studio.Diagnostics.OpenTelemetry/Elsa.Studio.Diagnostics.OpenTelemetry.csproj" }, { "id": "Elsa.Studio.Diagnostics.StructuredLogs.Dashboard", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.StructuredLogs.Dashboard/Elsa.Studio.Diagnostics.StructuredLogs.Dashboard.csproj" + "project": "studio/src/modules/Elsa.Studio.Diagnostics.StructuredLogs.Dashboard/Elsa.Studio.Diagnostics.StructuredLogs.Dashboard.csproj" }, { "id": "Elsa.Studio.Diagnostics.StructuredLogs", - "project": "src/studio/modules/Elsa.Studio.Diagnostics.StructuredLogs/Elsa.Studio.Diagnostics.StructuredLogs.csproj" + "project": "studio/src/modules/Elsa.Studio.Diagnostics.StructuredLogs/Elsa.Studio.Diagnostics.StructuredLogs.csproj" }, { "id": "Elsa.Studio.Environments", - "project": "src/studio/modules/Elsa.Studio.Environments/Elsa.Studio.Environments.csproj" + "project": "studio/src/modules/Elsa.Studio.Environments/Elsa.Studio.Environments.csproj" }, { "id": "Elsa.Studio.ExternalAuthentication.BlazorServer", - "project": "src/studio/modules/Elsa.Studio.ExternalAuthentication.BlazorServer/Elsa.Studio.ExternalAuthentication.BlazorServer.csproj" + "project": "studio/src/modules/Elsa.Studio.ExternalAuthentication.BlazorServer/Elsa.Studio.ExternalAuthentication.BlazorServer.csproj" }, { "id": "Elsa.Studio.ExternalAuthentication.BlazorWasm", - "project": "src/studio/modules/Elsa.Studio.ExternalAuthentication.BlazorWasm/Elsa.Studio.ExternalAuthentication.BlazorWasm.csproj" + "project": "studio/src/modules/Elsa.Studio.ExternalAuthentication.BlazorWasm/Elsa.Studio.ExternalAuthentication.BlazorWasm.csproj" }, { "id": "Elsa.Studio.ExternalAuthentication", - "project": "src/studio/modules/Elsa.Studio.ExternalAuthentication/Elsa.Studio.ExternalAuthentication.csproj" + "project": "studio/src/modules/Elsa.Studio.ExternalAuthentication/Elsa.Studio.ExternalAuthentication.csproj" }, { "id": "Elsa.Studio.Http.Webhooks", - "project": "src/studio/modules/Elsa.Studio.Http.Webhooks/Elsa.Studio.Http.Webhooks.csproj" + "project": "studio/src/modules/Elsa.Studio.Http.Webhooks/Elsa.Studio.Http.Webhooks.csproj" }, { "id": "Elsa.Studio.Labels", - "project": "src/studio/modules/Elsa.Studio.Labels/Elsa.Studio.Labels.csproj" + "project": "studio/src/modules/Elsa.Studio.Labels/Elsa.Studio.Labels.csproj" }, { "id": "Elsa.Studio.Localization.BlazorServer", - "project": "src/studio/modules/Elsa.Studio.Localization.BlazorServer/Elsa.Studio.Localization.BlazorServer.csproj" + "project": "studio/src/modules/Elsa.Studio.Localization.BlazorServer/Elsa.Studio.Localization.BlazorServer.csproj" }, { "id": "Elsa.Studio.Localization.BlazorWasm", - "project": "src/studio/modules/Elsa.Studio.Localization.BlazorWasm/Elsa.Studio.Localization.BlazorWasm.csproj" + "project": "studio/src/modules/Elsa.Studio.Localization.BlazorWasm/Elsa.Studio.Localization.BlazorWasm.csproj" }, { "id": "Elsa.Studio.Localization", - "project": "src/studio/modules/Elsa.Studio.Localization/Elsa.Studio.Localization.csproj" + "project": "studio/src/modules/Elsa.Studio.Localization/Elsa.Studio.Localization.csproj" }, { "id": "Elsa.Studio.Login.BlazorServer", - "project": "src/studio/modules/Elsa.Studio.Login.BlazorServer/Elsa.Studio.Login.BlazorServer.csproj" + "project": "studio/src/modules/Elsa.Studio.Login.BlazorServer/Elsa.Studio.Login.BlazorServer.csproj" }, { "id": "Elsa.Studio.Login.BlazorWasm", - "project": "src/studio/modules/Elsa.Studio.Login.BlazorWasm/Elsa.Studio.Login.BlazorWasm.csproj" + "project": "studio/src/modules/Elsa.Studio.Login.BlazorWasm/Elsa.Studio.Login.BlazorWasm.csproj" }, { "id": "Elsa.Studio.Login", - "project": "src/studio/modules/Elsa.Studio.Login/Elsa.Studio.Login.csproj" + "project": "studio/src/modules/Elsa.Studio.Login/Elsa.Studio.Login.csproj" }, { "id": "Elsa.Studio.PlatformIntegration", - "project": "src/studio/modules/Elsa.Studio.PlatformIntegration/Elsa.Studio.PlatformIntegration.csproj" + "project": "studio/src/modules/Elsa.Studio.PlatformIntegration/Elsa.Studio.PlatformIntegration.csproj" }, { "id": "Elsa.Studio.Secrets", - "project": "src/studio/modules/Elsa.Studio.Secrets/Elsa.Studio.Secrets.csproj" + "project": "studio/src/modules/Elsa.Studio.Secrets/Elsa.Studio.Secrets.csproj" }, { "id": "Elsa.Studio.Security", - "project": "src/studio/modules/Elsa.Studio.Security/Elsa.Studio.Security.csproj" + "project": "studio/src/modules/Elsa.Studio.Security/Elsa.Studio.Security.csproj" }, { "id": "Elsa.Studio.Settings", - "project": "src/studio/modules/Elsa.Studio.Settings/Elsa.Studio.Settings.csproj" + "project": "studio/src/modules/Elsa.Studio.Settings/Elsa.Studio.Settings.csproj" }, { "id": "Elsa.Studio.UIHints", - "project": "src/studio/modules/Elsa.Studio.UIHints/Elsa.Studio.UIHints.csproj" + "project": "studio/src/modules/Elsa.Studio.UIHints/Elsa.Studio.UIHints.csproj" }, { "id": "Elsa.Studio.UserTasks", - "project": "src/studio/modules/Elsa.Studio.UserTasks/Elsa.Studio.UserTasks.csproj" + "project": "studio/src/modules/Elsa.Studio.UserTasks/Elsa.Studio.UserTasks.csproj" }, { "id": "Elsa.Studio.Workflows.Core", - "project": "src/studio/modules/Elsa.Studio.Workflows.Core/Elsa.Studio.Workflows.Core.csproj" + "project": "studio/src/modules/Elsa.Studio.Workflows.Core/Elsa.Studio.Workflows.Core.csproj" }, { "id": "Elsa.Studio.Workflows.Dashboard", - "project": "src/studio/modules/Elsa.Studio.Workflows.Dashboard/Elsa.Studio.Workflows.Dashboard.csproj" + "project": "studio/src/modules/Elsa.Studio.Workflows.Dashboard/Elsa.Studio.Workflows.Dashboard.csproj" }, { "id": "Elsa.Studio.Workflows.Designer", - "project": "src/studio/modules/Elsa.Studio.Workflows.Designer/Elsa.Studio.Workflows.Designer.csproj" + "project": "studio/src/modules/Elsa.Studio.Workflows.Designer/Elsa.Studio.Workflows.Designer.csproj" }, { "id": "Elsa.Studio.Workflows", - "project": "src/studio/modules/Elsa.Studio.Workflows/Elsa.Studio.Workflows.csproj" + "project": "studio/src/modules/Elsa.Studio.Workflows/Elsa.Studio.Workflows.csproj" } ] } diff --git a/scripts/integration-program/consolidated_candidate_input.py b/scripts/integration-program/consolidated_candidate_input.py index 3c5b6ca581..00518750be 100644 --- a/scripts/integration-program/consolidated_candidate_input.py +++ b/scripts/integration-program/consolidated_candidate_input.py @@ -8,23 +8,30 @@ import prepare_consolidated_release_candidate as candidate -SOURCE = "ba5b348aa2414fdf7c19d9d8806e87b7c91a4205" -RUN = 37456860080 +SOURCE = "f60c00766b107cb15038c77873d84779f0680722" +RUN = 40202201744 ATTEMPT = 1 -ARTIFACT = 11412848210 -ARCHIVE_SHA256 = "ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f" -MANIFEST_SHA256 = "df25b11556bbf21210cfc33ef02f3d0841af6316a20ece69422c7b8143a11820" -ENVELOPE_SHA256 = "ef5e772020b151089b64b90b819d36ff371ed5e65212f7fdc7b2934d9860ddda" +ARTIFACT = 12603436856 +ARCHIVE_SHA256 = "13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d" +MANIFEST_SHA256 = "ac881065f8c59465955032a37ad733dd95e3c32c91acdbbb10b267ed993524e6" +ENVELOPE_SHA256 = "417f73adf02866c6ec4aaa261609c50320508bed683fd78b217e2dcbb8c35af8" ORIGINAL_ENVELOPE = Path(__file__).resolve().parent / "persisted-workflow-upgrade/stable-original-envelope.json" -# Frozen Oct 6 pin inventory (225 packages, including Elsa.SamplePackage). -# The forward-looking candidate baseline may differ; recovery and the executor +# Frozen candidate pin inventory (231 packages). Recovery and the executor # use this snapshot so they still accept the real pinned artifact. PIN_INVENTORY = Path(__file__).resolve().parent / "consolidated-pin-inventory-baseline.json" PRODUCER = {"version": "3.10.0", "source_commit": SOURCE, "run_id": RUN, "run_attempt": ATTEMPT, "artifact_id": ARTIFACT} _PIN = json.loads(PIN_INVENTORY.read_text(encoding="utf-8")) +_ENVELOPE = json.loads(ORIGINAL_ENVELOPE.read_text(encoding="utf-8")) PIN_PACKAGE_COUNT = len(_PIN["packages"]) PIN_EXCLUSION_COUNT = len(_PIN["exclusions"]) PIN_EXCLUSION_ID_COUNT = len({row["id"] for row in _PIN["exclusions"]}) +ARCHIVE_SIZE = _ENVELOPE["archive_size"] +EXPIRES_AT = _ENVELOPE["expires_at"] +if any(_ENVELOPE.get(key) != value for key, value in ( + ("source_commit", SOURCE), ("run_id", RUN), ("run_attempt", ATTEMPT), + ("artifact_id", ARTIFACT), ("archive_sha256", ARCHIVE_SHA256), + ("preupload_manifest_sha256", MANIFEST_SHA256))): + raise RuntimeError("Pinned envelope identity does not match candidate input constants") def require(condition: bool, message: str) -> None: diff --git a/scripts/integration-program/consolidated_package_executor.py b/scripts/integration-program/consolidated_package_executor.py index 7710b0cb3a..dcdbc93388 100644 --- a/scripts/integration-program/consolidated_package_executor.py +++ b/scripts/integration-program/consolidated_package_executor.py @@ -39,7 +39,7 @@ PACKAGE_BASE = "https://f.feedz.io/elsa-workflows/elsa-3/nuget/v3/packages" PACKAGE_PUBLISH = "https://f.feedz.io/elsa-workflows/elsa-3/nuget" SYMBOL_PUBLISH = "https://f.feedz.io/elsa-workflows/elsa-3/symbols" -EXPIRY = "2026-11-05T12:13:30Z" +EXPIRY = candidate_input.EXPIRES_AT # A later separately approved source change must pin real existing IDs, exact # refs and the operational packet. No CLI/environment/artifact override exists. REVIEWED_OPERATIONAL_POLICY = None diff --git a/scripts/integration-program/consolidated_package_recovery.py b/scripts/integration-program/consolidated_package_recovery.py index 5f116cc5fc..338e27ae43 100644 --- a/scripts/integration-program/consolidated_package_recovery.py +++ b/scripts/integration-program/consolidated_package_recovery.py @@ -28,7 +28,7 @@ FEED_INDEX = "https://f.feedz.io/elsa-workflows/elsa-3/nuget/index.json" FEED_ORIGIN = "https://f.feedz.io" VERSION = "3.10.0" -SOURCE = "ba5b348aa2414fdf7c19d9d8806e87b7c91a4205" +SOURCE = candidate_input.SOURCE PACKAGE_COUNT = candidate_input.PIN_PACKAGE_COUNT MAX_PACKAGE_BYTES = 32 * 1024 * 1024 MAX_PAYLOAD_BYTES = 256 * 1024 * 1024 @@ -209,12 +209,13 @@ def _provenance(value: dict) -> dict: producer = value["candidate_producer"] if not isinstance(producer, dict) or any(type(producer.get(key)) is not int for key in ("run_id", "run_attempt", "artifact_id")): raise ValueError() - if producer != {"version": VERSION, "source_commit": SOURCE, "run_id": 37456860080, - "run_attempt": 1, "artifact_id": 11412848210}: + if producer != {"version": VERSION, "source_commit": SOURCE, "run_id": candidate_input.RUN, + "run_attempt": candidate_input.ATTEMPT, "artifact_id": candidate_input.ARTIFACT}: raise ValueError() - if value["artifact_name"] != f"consolidated-candidate-{SOURCE}-37456860080-1": + if value["artifact_name"] != ( + f"consolidated-candidate-{SOURCE}-{candidate_input.RUN}-{candidate_input.ATTEMPT}"): raise ValueError() - if type(value["archive_size"]) is not int or value["archive_size"] != 92659861: + if type(value["archive_size"]) is not int or value["archive_size"] != candidate_input.ARCHIVE_SIZE: raise ValueError() for key in keys - {"candidate_producer", "artifact_name", "archive_size", "observed_at", "planner"}: if not _valid_sha(value[key]): @@ -363,7 +364,7 @@ def _local_inventory(root, provenance, verifier): local.append(item) expected = {f"{row['id']}.{VERSION}.{ext}" for row in local for ext in ("nupkg", "snupkg")} actual = {path.name for path in (root / "artifacts").iterdir() if path.suffix in (".nupkg", ".snupkg")} - if expected != actual or "elsa.samplepackage" not in seen: + if expected != actual: raise RecoveryError("local_input_invalid") return manifest, local, invalid diff --git a/scripts/integration-program/persisted-workflow-upgrade/README.md b/scripts/integration-program/persisted-workflow-upgrade/README.md index 577c066c32..83134fc141 100644 --- a/scripts/integration-program/persisted-workflow-upgrade/README.md +++ b/scripts/integration-program/persisted-workflow-upgrade/README.md @@ -38,9 +38,9 @@ Hosted execution logs contain command kinds/phases, exit codes/timeouts, recogni ## Accepted stable 3.10.0 adapter -`run_stable_persisted_workflow_upgrade_fixture.py` applies the same six-cell lifecycle to the distinct stable bytes accepted through #8635. The original proof entrypoint, workflow, archive pins and earlier evidence remain separate. The stable producer is source `ba5b348aa2414fdf7c19d9d8806e87b7c91a4205`, run `37456860080`, attempt `1`, artifact `11412848210`. Its original archive is exactly 92,659,861 bytes with SHA-256 `ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f`, expiring at `2026-11-05T12:13:30Z`. Deleted or expired originals fail; no replacement/rebuild/repack is accepted. +`run_stable_persisted_workflow_upgrade_fixture.py` applies the same six-cell lifecycle to the distinct stable bytes accepted through #8635. The original proof entrypoint, workflow, archive pins and earlier evidence remain separate. The stable producer is source `f60c00766b107cb15038c77873d84779f0680722`, run `40202201744`, attempt `1`, artifact `12603436856`. Its original archive is exactly 96,125,850 bytes with SHA-256 `13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d`, expiring at `2026-11-24T15:03:46Z`. Deleted or expired originals fail; no replacement/rebuild/repack is accepted. -The checked-in `stable-original-envelope.json` preserves the accepted historical envelope verbatim (SHA-256 `ef5e772020b151089b64b90b819d36ff371ed5e65212f7fdc7b2934d9860ddda`, retrieved at `2026-10-06T12:13:47Z`). Its pre-upload manifest SHA-256 is `df25b11556bbf21210cfc33ef02f3d0841af6316a20ece69422c7b8143a11820`. Each execution separately records fresh live artifact metadata, the exact successful producer run/attempt and a new retrieval observation. The existing candidate verifier checks the accepted envelope, archive and complete file inventory before extraction. The package manifest validator still checks the complete inventory and reviewed external exceptions; this fixture requires only Elsa and Elsa.Persistence.EFCore.Sqlite. Other representative consumers retain their five-package default. +The checked-in `stable-original-envelope.json` preserves the accepted historical envelope verbatim (SHA-256 `417f73adf02866c6ec4aaa261609c50320508bed683fd78b217e2dcbb8c35af8`, retrieved at `2026-10-25T15:04:07Z`). Its pre-upload manifest SHA-256 is `ac881065f8c59465955032a37ad733dd95e3c32c91acdbbb10b267ed993524e6`. Each execution separately records fresh live artifact metadata, the exact successful producer run/attempt and a new retrieval observation. The existing candidate verifier checks the accepted envelope, archive and complete file inventory before extraction. The package manifest validator still checks the complete inventory and reviewed external exceptions; this fixture requires only Elsa and Elsa.Persistence.EFCore.Sqlite. Other representative consumers retain their five-package default. ```sh python3 -m unittest discover -s scripts/integration-program -p 'test_*persisted_workflow_upgrade_fixture.py' @@ -51,7 +51,7 @@ python3 scripts/integration-program/run_stable_persisted_workflow_upgrade_fixtur --fixture-source "$(git rev-parse HEAD)" ``` -The fresh retrieval JSON has exactly `schema: 1`, `artifact_id: 11412848210`, the accepted `archive_sha256`, and the new timezone-qualified `retrieved_at`. The input directory contains exactly candidate.zip, artifact.json, producer-run.json and live-retrieval.json as regular files, with no nested, extra or symlinked entries. Artifact JSON is the current GitHub API response; producer-run.json comes from the fixed actions/runs/37456860080/attempts/1 endpoint so a later rerun cannot replace the accepted producer attempt. Local executions record null matrix run/attempt; hosted runs pass their actual run/attempt. Receipts distinguish the candidate producer from the exact fixture checkout commit and matrix run/attempt, record the selected execution SDK in the sdk field, without relabeling it as the producer's SDK, and retain both envelope and observation bytes with hashes. A development `--cell` remains incomplete and cannot pass the matrix gate. +The fresh retrieval JSON has exactly `schema: 1`, `artifact_id: 12603436856`, the accepted `archive_sha256`, and the new timezone-qualified `retrieved_at`. The input directory contains exactly candidate.zip, artifact.json, producer-run.json and live-retrieval.json as regular files, with no nested, extra or symlinked entries. Artifact JSON is the current GitHub API response; producer-run.json comes from the fixed actions/runs/40202201744/attempts/1 endpoint so a later rerun cannot replace the accepted producer attempt. Local executions record null matrix run/attempt; hosted runs pass their actual run/attempt. Receipts distinguish the candidate producer from the exact fixture checkout commit and matrix run/attempt, record the selected execution SDK in the sdk field, without relabeling it as the producer's SDK, and retain both envelope and observation bytes with hashes. A development `--cell` remains incomplete and cannot pass the matrix gate. The dedicated `Stable persisted workflow upgrade proof` workflow uses the same trusted push/manual retrieval boundary: fixed API requests without checkout or repository execution in the only token-bearing job; four fixed inputs cross through ID-only same-run transport. Execution checks out the exact fixture head with credentials disabled and `actions: none`, verifies bytes, then runs all six cells. Initial push can activate this costly workflow, so review the coherent head before pushing. It does not rebuild Elsa packages or publish/deploy anything. A green tooling job is not lifecycle acceptance; all six cells and all 18 lifecycle processes, retained database hashes and a fresh original-artifact availability check require independent exact-head audit. Inspect retained SQLite originals only through disposable copies. diff --git a/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json b/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json index 04149efea5..4847087b0b 100644 --- a/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json +++ b/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json @@ -1 +1 @@ -{"schema":1,"published":false,"version":"3.10.0","source_commit":"ba5b348aa2414fdf7c19d9d8806e87b7c91a4205","run_id":37456860080,"run_attempt":1,"artifact_id":11412848210,"artifact_name":"consolidated-candidate-ba5b348aa2414fdf7c19d9d8806e87b7c91a4205-37456860080-1","archive_sha256":"ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f","archive_size":92659861,"expires_at":"2026-11-05T12:13:30Z","retention_days":30,"retrieved_at":"2026-10-06T12:13:47Z","preupload_manifest_sha256":"df25b11556bbf21210cfc33ef02f3d0841af6316a20ece69422c7b8143a11820"} +{"schema":1,"published":false,"version":"3.10.0","source_commit":"f60c00766b107cb15038c77873d84779f0680722","run_id":40202201744,"run_attempt":1,"artifact_id":12603436856,"artifact_name":"consolidated-candidate-f60c00766b107cb15038c77873d84779f0680722-40202201744-1","archive_sha256":"13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d","archive_size":96125850,"expires_at":"2026-11-24T15:03:46Z","retention_days":30,"retrieved_at":"2026-10-25T15:04:07Z","preupload_manifest_sha256":"ac881065f8c59465955032a37ad733dd95e3c32c91acdbbb10b267ed993524e6"} diff --git a/scripts/integration-program/test_consolidated_candidate_clock.py b/scripts/integration-program/test_consolidated_candidate_clock.py index 5c3977621a..256cef25f9 100644 --- a/scripts/integration-program/test_consolidated_candidate_clock.py +++ b/scripts/integration-program/test_consolidated_candidate_clock.py @@ -6,7 +6,7 @@ from unittest.mock import patch -SYNTHETIC_NOW = datetime(2026, 10, 7, 12, tzinfo=timezone.utc) +SYNTHETIC_NOW = datetime(2026, 10, 26, 14, tzinfo=timezone.utc) AFTER_EXPIRY = datetime(2030, 1, 1, tzinfo=timezone.utc) @@ -45,7 +45,7 @@ def test_success_fixtures_survive_future_wall_clock_and_restore_it(self): execution.FullInventoryTests("test_verify_missing_is_complete_observation_not_release_acceptance"), execution.AdmissionTests("test_native_approval_and_exact_preexisting_policy"), execution.AdmissionTests("test_preschedule_requires_policy_but_not_future_approval"), - approvals.SummaryTests("test_complete_missing_observation_reports_actual_668_and_immutable_bindings"), + approvals.SummaryTests("test_complete_missing_observation_reports_actual_associations_and_immutable_bindings"), stable.StableAdapterContracts("test_two_package_scope_and_distinct_execution_identity"), ]) output = io.StringIO() diff --git a/scripts/integration-program/test_consolidated_executor_approval_summary.py b/scripts/integration-program/test_consolidated_executor_approval_summary.py index a1579b54ad..448926e60d 100644 --- a/scripts/integration-program/test_consolidated_executor_approval_summary.py +++ b/scripts/integration-program/test_consolidated_executor_approval_summary.py @@ -70,18 +70,24 @@ def setUp(self): "credential_provenance_verified": False, "credential_isolation": "pending_authenticated_execution_check", "candidate": {**executor.candidate_input.PRODUCER, "archive_sha256": executor.candidate_input.ARCHIVE_SHA256, "preupload_manifest_sha256": executor.candidate_input.MANIFEST_SHA256, "expires_at": executor.EXPIRY, - "package_count": 225, "exclusion_count": 124, "excluded_id_count": 123}}} + "package_count": executor.candidate_input.PIN_PACKAGE_COUNT, + "exclusion_count": executor.candidate_input.PIN_EXCLUSION_COUNT, + "excluded_id_count": executor.candidate_input.PIN_EXCLUSION_ID_COUNT}}} def render(self): return summary.render_summary(self.admission, self.verification, artifact_id=1234, artifact_digest="sha256:"+"c"*64, admission_hash="d"*64, verification_hash="e"*64) - def test_complete_missing_observation_reports_actual_668_and_immutable_bindings(self): + def test_complete_missing_observation_reports_actual_associations_and_immutable_bindings(self): + packages = executor.candidate_input.PIN_PACKAGE_COUNT + associations = packages + 7 + (packages - 7) * 2 text = self.render() for value in (self.context["GITHUB_SHA"], executor.candidate_input.SOURCE, executor.candidate_input.ARCHIVE_SHA256, executor.candidate_input.MANIFEST_SHA256, executor.candidate_input.ENVELOPE_SHA256, - self.verification["original_provenance"]["inventory_sha256"], "668 DLL/PDB associations", "668 distinct PDB keys", - "225 package pairs / 450 original archives", "0 matching, 225 missing", "Native approval is **pending**", + self.verification["original_provenance"]["inventory_sha256"], + f"{associations} DLL/PDB associations", f"{associations} distinct PDB keys", + f"{packages} package pairs / {packages * 2} original archives", + f"0 matching, {packages} missing", "Native approval is **pending**", "Publication readiness remains **false**", "not release acceptance", "does not independently reconstruct", "/actions/runs/99/artifacts/1234"): self.assertIn(value, text) @@ -96,7 +102,7 @@ def test_all_matching_still_does_not_imply_release_acceptance(self): row.update(classification="matching", status=200, pdb_sha256=pdbs[row["key"]]) proof.update(counts=summary.counts(proof["packages"]), content_converged=True) self.verification["before"]["content_verified"] = self.verification["content_verified"] = True - self.assertIn("225 matching, 0 missing", self.render()) + self.assertIn(f"{executor.candidate_input.PIN_PACKAGE_COUNT} matching, 0 missing", self.render()) self.assertIn("Publication readiness remains **false**", self.render()) def test_runtime_and_receipt_identity_mismatch_block(self): diff --git a/scripts/integration-program/test_consolidated_package_executor.py b/scripts/integration-program/test_consolidated_package_executor.py index b0f7a008a5..21298e6755 100644 --- a/scripts/integration-program/test_consolidated_package_executor.py +++ b/scripts/integration-program/test_consolidated_package_executor.py @@ -21,6 +21,10 @@ from test_consolidated_candidate_clock import AFTER_EXPIRY, candidate_clock, install_candidate_clock from test_consolidated_package_recovery import package_bytes, provenance +PIN_COUNT = executor.candidate_input.PIN_PACKAGE_COUNT +PIN_EXCLUSIONS = executor.candidate_input.PIN_EXCLUSION_COUNT +PIN_ARCHIVES = PIN_COUNT * 2 + def loopback_server(test, handler): server = ThreadingHTTPServer(("127.0.0.1", 0), handler) @@ -123,15 +127,15 @@ def fill_feed(self): self.feed.accepted[row["nupkg"].lower()] = (self.root / "artifacts" / row["nupkg"]).read_bytes() self.feed.symbols.update({key: value["pdb"] for key, value in self.expected.items()}) - def test_all_225_pairs_and_124_exclusions_converge(self): + def test_all_pin_pairs_and_exclusions_converge(self): result = self.run_executor() self.assertEqual(result["result"], "content_verified") - self.assertEqual(len(result["operations"]), 450) - self.assertEqual(len(result["associations"]), 225) - self.assertEqual(result["after"]["packages"]["counts"]["matching"], 225) - self.assertEqual(result["after"]["packages"]["exclusion_count"], 124) - self.assertEqual(len(result["after"]["symbols"]), 225) - self.assertEqual(len(self.feed.calls), 450) + self.assertEqual(len(result["operations"]), PIN_ARCHIVES) + self.assertEqual(len(result["associations"]), PIN_COUNT) + self.assertEqual(result["after"]["packages"]["counts"]["matching"], PIN_COUNT) + self.assertEqual(result["after"]["packages"]["exclusion_count"], PIN_EXCLUSIONS) + self.assertEqual(len(result["after"]["symbols"]), PIN_COUNT) + self.assertEqual(len(self.feed.calls), PIN_ARCHIVES) self.assertFalse(result["publication_ready"]) self.assertFalse(result["remote_snupkg_archive_verified"]) self.assertEqual(result["scope"], "injected_simulation") @@ -139,7 +143,7 @@ def test_all_225_pairs_and_124_exclusions_converge(self): self.assertEqual(result[phase]["packages"]["observation_mode"], "injected_simulation") self.assertNotIn("private-synthetic-key", json.dumps(result)) self.assertTrue(self.run_executor()["content_verified"]) - self.assertEqual(len(self.feed.calls), 450) + self.assertEqual(len(self.feed.calls), PIN_ARCHIVES) def test_verify_missing_is_complete_observation_not_release_acceptance(self): result = self.run_executor(mode="verify", authorize=lambda: self.fail("verification requested authority")) @@ -155,7 +159,7 @@ def test_default_reader_preserves_production_observation_provenance(self): self.assertEqual(result["result"], "verified") self.assertEqual(result["scope"], "production") self.assertEqual(result["before"]["packages"]["observation_mode"], "production") - self.assertEqual(reader.call_count, 452) # Two index reads, all packages, all PDBs. + self.assertEqual(reader.call_count, PIN_ARCHIVES + 2) # Two index reads, all packages, all PDBs. self.assertFalse(result["publication_performed"]) self.assertFalse(result["upload_attempted"]) self.assertEqual(self.feed.calls, []) @@ -169,17 +173,17 @@ def test_package_present_symbol_missing_and_arbitrary_partial(self): self.feed.calls.clear() result = self.run_executor() self.assertTrue(result["content_verified"]) - self.assertEqual(len(self.feed.calls), 375 if partial else 225) - self.assertEqual(sum(row["kind"] == "snupkg" for row in self.feed.calls), 225) + self.assertEqual(len(self.feed.calls), (2 * PIN_COUNT - PIN_COUNT // 3) if partial else PIN_COUNT) + self.assertEqual(sum(row["kind"] == "snupkg" for row in self.feed.calls), PIN_COUNT) def test_accepted_then_interrupted_resume_without_duplicate(self): self.feed.interrupt_next = True result = self.run_executor() self.assertEqual(result["failure_category"], "upload_acceptance_unknown") - self.assertEqual(len(result["operations"]), 450) + self.assertEqual(len(result["operations"]), PIN_ARCHIVES) self.assertEqual(len(self.feed.calls), 1) self.assertTrue(self.run_executor()["content_verified"]) - self.assertEqual(len(self.feed.calls), 450) + self.assertEqual(len(self.feed.calls), PIN_ARCHIVES) def test_409_and_uncertain_results_stop_without_retry(self): for response in (recovery.ReadResult(409, b"raw-private-body", True), recovery.ReadResult(401, b"secret", True), @@ -201,7 +205,7 @@ def invisible(kind, data, key): result = self.run_executor() self.assertFalse(result["content_verified"]) self.assertEqual(result["failure_category"], "readback_incomplete") - self.assertEqual(len(self.feed.calls), 450) + self.assertEqual(len(self.feed.calls), PIN_ARCHIVES) def test_package_and_pdb_conflicts_or_unreadable_block_every_upload(self): first = self.manifest["packages"][0] @@ -256,7 +260,7 @@ def get(url, **kwargs): observed = result["before"] if change_after == 1 else result["after"] self.assertFalse(observed["feed_index_consistent"]) self.assertTrue(observed["blocked"]) - self.assertEqual(len(self.feed.calls), 0 if change_after == 1 else 450) + self.assertEqual(len(self.feed.calls), 0 if change_after == 1 else PIN_ARCHIVES) def test_authority_failure_never_uses_key(self): def blocked(): @@ -293,7 +297,7 @@ def put(kind, data, key): result = executor.run_verified(self.root, self.provenance, self.inspector, mode="publish", transport=self.feed, authorize=lambda: {"scope": "simulation_only"}, credential=lambda: "synthetic", checkpoint=checkpoint) self.assertEqual(result["failure_category"], "upload_acceptance_unknown") - self.assertEqual(len(snapshots[-1]["operations"]), 450) + self.assertEqual(len(snapshots[-1]["operations"]), PIN_ARCHIVES) self.assertEqual(snapshots[-1]["operations"][0]["state"], "acceptance_unknown") def test_expiry_blocks_before_network(self): @@ -348,7 +352,7 @@ def inspect(*args): nonlocal calls calls += 1 result = original(*args) - if calls > 225: + if calls > PIN_COUNT: result["symbol"][field] = value return result with patch.object(self.inspector, "inspect", side_effect=inspect): @@ -369,9 +373,9 @@ def test_consistent_duplicate_keys_retain_each_association(self): try: path.write_bytes(output.getvalue()) associations, expected = executor.associations(self.root, self.manifest, self.inspector) - self.assertEqual(len(associations), 225) - self.assertEqual(sum(len(row["associations"]) for row in associations), 225) - self.assertEqual(len(expected), 224) + self.assertEqual(len(associations), PIN_COUNT) + self.assertEqual(sum(len(row["associations"]) for row in associations), PIN_COUNT) + self.assertEqual(len(expected), PIN_COUNT - 1) finally: path.write_bytes(original) @@ -429,16 +433,16 @@ def test_shared_missing_keys_skip_second_archive_only_after_actual_pdb_readback( root, original_provenance, manifest, feed = self.overlapping_inventory() result = self.publish_overlap(root, original_provenance, feed) self.assertTrue(result["content_verified"]) - self.assertEqual(len(result["operations"]), 450) - self.assertEqual(len(result["associations"]), 225) - self.assertEqual(sum(len(row["associations"]) for row in result["associations"]), 225) - self.assertEqual(len(feed.attempts), 449) + self.assertEqual(len(result["operations"]), PIN_ARCHIVES) + self.assertEqual(len(result["associations"]), PIN_COUNT) + self.assertEqual(sum(len(row["associations"]) for row in result["associations"]), PIN_COUNT) + self.assertEqual(len(feed.attempts), PIN_ARCHIVES - 1) operation = result["operations"][3] self.assertEqual(operation["archive_sha256"], manifest["packages"][1]["snupkg_sha256"]) self.assertEqual(operation["state"], "pdbs_already_matching_archive_unverified") self.assertIsNone(operation["status"]) self.assertEqual([row["classification"] for row in operation["overlap_readback"]], ["matching"]) - self.assertEqual(len(result["after"]["symbols"]), 224) + self.assertEqual(len(result["after"]["symbols"]), PIN_COUNT - 1) self.assertFalse(result["remote_snupkg_archive_verified"]) self.assertFalse(result["publication_ready"]) @@ -498,16 +502,16 @@ def test_assembly_free_accounting_does_not_drop_pair(self): try: path.write_text(json.dumps(source)) associations, expected = executor.associations(self.root, manifest, self.inspector) - self.assertEqual(len(associations), 225) + self.assertEqual(len(associations), PIN_COUNT) self.assertTrue(associations[0]["assembly_free"]) - self.assertEqual(len(expected), 224) + self.assertEqual(len(expected), PIN_COUNT - 1) finally: path.write_bytes(original) def test_full_original_rehearsal(self): result = executor.rehearse(self.root, self.provenance, self.inspector) self.assertEqual(result["result"], "passed") - self.assertEqual(result["simulated_upload_count"], 450) + self.assertEqual(result["simulated_upload_count"], PIN_ARCHIVES) self.assertFalse(result["publication_performed"]) self.assertTrue(result["resumed"]["content_verified"]) diff --git a/scripts/integration-program/test_consolidated_package_recovery.py b/scripts/integration-program/test_consolidated_package_recovery.py index 785b43922b..076bf5acca 100644 --- a/scripts/integration-program/test_consolidated_package_recovery.py +++ b/scripts/integration-program/test_consolidated_package_recovery.py @@ -12,9 +12,12 @@ import zipfile import warnings +import consolidated_candidate_input as candidate_input import consolidated_package_recovery as recovery from run_consolidated_recovery_fixture import SimulatedFeed +COUNT = recovery.PACKAGE_COUNT + def package_bytes(package_id, *, version=recovery.VERSION, source=recovery.SOURCE, dependency="1.0.0", payload=b"original", signature=False): stream = io.BytesIO() @@ -28,8 +31,8 @@ def package_bytes(package_id, *, version=recovery.VERSION, source=recovery.SOURC def provenance(root): - return {"candidate_producer": {"version": recovery.VERSION, "source_commit": recovery.SOURCE, "run_id": 37456860080, "run_attempt": 1, "artifact_id": 11412848210}, - "artifact_name": f"consolidated-candidate-{recovery.SOURCE}-37456860080-1", "archive_sha256": "a" * 64, "archive_size": 92659861, + return {"candidate_producer": {"version": recovery.VERSION, "source_commit": recovery.SOURCE, "run_id": candidate_input.RUN, "run_attempt": candidate_input.ATTEMPT, "artifact_id": candidate_input.ARTIFACT}, + "artifact_name": f"consolidated-candidate-{recovery.SOURCE}-{candidate_input.RUN}-{candidate_input.ATTEMPT}", "archive_sha256": "a" * 64, "archive_size": candidate_input.ARCHIVE_SIZE, "original_envelope_sha256": "b" * 64, "preupload_manifest_sha256": recovery._sha((root / "preupload-manifest.json").read_bytes()), "verified_artifacts_sha256": recovery._sha((root / "verified-artifacts.json").read_bytes()), "inventory_sha256": recovery._sha(json.dumps(__import__("prepare_consolidated_release_candidate").inventory_identity(json.loads((root / "verified-artifacts.json").read_text())), sort_keys=True, separators=(",", ":")).encode()), "live_retrieval_sha256": "c" * 64, "observed_at": datetime.now(timezone.utc).isoformat(), @@ -76,15 +79,15 @@ def changed_file(self, path, data): def test_all_missing_full_set_is_visibility_only(self): result = self.plan() - self.assertEqual(result["counts"], {"missing": 225, "matching": 0, "conflicting": 0, "unverifiable": 0}) + self.assertEqual(result["counts"], {"missing": COUNT, "matching": 0, "conflicting": 0, "unverifiable": 0}) self.assertTrue(result["classification_complete"]) self.assertFalse(result["reconciliation_blocked"]) for key in ("publication_ready", "publication_performed", "remote_symbols_verified", "content_converged"): self.assertFalse(result[key]) self.assertEqual(result["access_mode"], "anonymous") self.assertEqual(result["absence_scope"], "declared_access_visibility_only") - self.assertEqual(len(self.feed.calls), 226) - self.assertEqual(len({row["id"] for row in result["packages"]}), 225) + self.assertEqual(len(self.feed.calls), COUNT + 1) + self.assertEqual(len({row["id"] for row in result["packages"]}), COUNT) self.assertIn("intended_reader_access", result["pending_gates"]) def test_all_matching_signature_aware_payload_and_distinct_raw_digest(self): @@ -92,7 +95,7 @@ def test_all_matching_signature_aware_payload_and_distinct_raw_digest(self): self.feed.overrides["elsa.samplepackage"] = recovery.ReadResult(200, package_bytes("Elsa.SamplePackage", signature=True), True) result = self.plan() self.assertTrue(result["content_converged"]) - self.assertEqual(result["counts"]["matching"], 225) + self.assertEqual(result["counts"]["matching"], COUNT) first = result["packages"][0] self.assertNotEqual(first["remote"]["archive_sha256"], first["local_nupkg_sha256"]) self.assertEqual(first["remote"]["payload_sha256"], first["local_payload_sha256"]) @@ -102,10 +105,10 @@ def test_partial_and_later_visibility_requery_remote_truth(self): self.feed.overrides["elsa.samplepackage"] = recovery.ReadResult(200, package_bytes("Elsa.SamplePackage"), True) first = self.plan() self.assertEqual(first["counts"]["matching"], 1) - self.assertEqual(first["counts"]["missing"], 224) + self.assertEqual(first["counts"]["missing"], COUNT - 1) self.feed.outcome = 200 self.assertTrue(self.plan()["content_converged"]) - self.assertEqual(len(self.feed.calls), 452) + self.assertEqual(len(self.feed.calls), 2 * (COUNT + 1)) def test_each_content_mismatch_blocks_reconciliation(self): for category, arguments in [("identity", {"version": "3.10.1"}), ("source", {"source": "f" * 40}), ("dependencies", {"dependency": "2.0.0"}), ("payload", {"payload": b"changed"})]: @@ -134,19 +137,19 @@ def test_ambiguous_and_foreign_index_fail_whole_set(self): with self.subTest(bases=bases): self.feed.calls.clear() self.feed.index = recovery.ReadResult(200, json.dumps({"version": "3.0.0", "resources": [{"@type": "PackageBaseAddress/3.0.0", "@id": base} for base in bases]}).encode(), True) - self.assertEqual(self.plan()["counts"]["unverifiable"], 225) + self.assertEqual(self.plan()["counts"]["unverifiable"], COUNT) self.assertEqual(len(self.feed.calls), 1) def test_duplicate_index_json_keys_fail_closed(self): self.feed.index = recovery.ReadResult(200, b'{"version":"3.0.0","resources":[],"resources":[]}', True) - self.assertEqual(self.plan()["counts"]["unverifiable"], 225) + self.assertEqual(self.plan()["counts"]["unverifiable"], COUNT) def test_last_local_symbol_pin_checked_before_first_get(self): path = self.root / "artifacts" / self.manifest["packages"][-1]["snupkg"] with self.changed_file(path, b"changed last symbols"): result = self.plan() self.assertEqual(self.feed.calls, []) - self.assertEqual(result["counts"]["unverifiable"], 225) + self.assertEqual(result["counts"]["unverifiable"], COUNT) self.assertEqual({row["failure_category"] for row in result["packages"]}, {"local_input_invalid"}) def test_feedz_package_base_without_trailing_slash_preserves_the_full_path(self): @@ -158,7 +161,7 @@ def test_feedz_package_base_without_trailing_slash_preserves_the_full_path(self) def test_changed_manifest_duplicate_and_subset_rejected_before_get(self): path = self.root / "verified-artifacts.json" - for rows in (self.manifest["packages"][:-1], [self.manifest["packages"][0]] * 225): + for rows in (self.manifest["packages"][:-1], [self.manifest["packages"][0]] * COUNT): with self.changed_file(path, json.dumps(dict(self.manifest, packages=rows)).encode()): with self.assertRaisesRegex(recovery.RecoveryError, "local_input_invalid"): self.plan() @@ -172,7 +175,7 @@ def test_interruption_retains_completed_rows_and_stops_new_gets(self): self.feed.overrides["elsa.synthetic002"] = KeyboardInterrupt() result = self.plan() self.assertEqual(result["counts"]["missing"], 2) - self.assertEqual(result["counts"]["unverifiable"], 223) + self.assertEqual(result["counts"]["unverifiable"], COUNT - 2) self.assertEqual(len(self.feed.calls), 4) self.assertEqual(result["packages"][-1]["failure_category"], "interrupted") diff --git a/scripts/integration-program/test_consolidated_recovery_inputs.py b/scripts/integration-program/test_consolidated_recovery_inputs.py index fc1e85f118..068d6dbda1 100644 --- a/scripts/integration-program/test_consolidated_recovery_inputs.py +++ b/scripts/integration-program/test_consolidated_recovery_inputs.py @@ -257,10 +257,10 @@ def rebuild_with_current_manifest(self): self.rewrite_outer_archive() self.patch_constants() - def test_valid_inputs_recheck_all_225_pairs_and_emit_bound_provenance(self): + def test_valid_inputs_recheck_all_pin_pairs_and_emit_bound_provenance(self): root, provenance = self.run_prepare(planner_run=99, planner_attempt=2) self.assertEqual(self.destination, root) - self.assertEqual(225, len(json.loads((root / "verified-artifacts.json").read_text())["packages"])) + self.assertEqual(candidate_input.PIN_PACKAGE_COUNT, len(json.loads((root / "verified-artifacts.json").read_text())["packages"])) self.assertEqual(candidate_input.PRODUCER, provenance["candidate_producer"]) self.assertEqual(self.archive_sha256, provenance["archive_sha256"]) self.assertEqual(self.archive_size, provenance["archive_size"]) diff --git a/scripts/integration-program/test_stable_persisted_workflow_upgrade_fixture.py b/scripts/integration-program/test_stable_persisted_workflow_upgrade_fixture.py index 9d8712690a..28038cbbd6 100644 --- a/scripts/integration-program/test_stable_persisted_workflow_upgrade_fixture.py +++ b/scripts/integration-program/test_stable_persisted_workflow_upgrade_fixture.py @@ -248,7 +248,7 @@ def test_fixed_token_boundary_same_run_layout_and_full_matrix(self): self.assertNotIn(forbidden, retrieve.split(" retrieve:\n", 1)[1]) for value in (str(stable.ARTIFACT), str(stable.RUN), stable.SOURCE, stable.ARCHIVE_SHA256): self.assertIn(value, retrieve) - self.assertIn("actions/runs/37456860080/attempts/1", retrieve) + self.assertIn(f"actions/runs/{stable.RUN}/attempts/1", retrieve) self.assertIn(".run_attempt == 1", retrieve) self.assertIn("actions: none", execution) self.assertIn("ref: ${{ github.sha }}", execution) @@ -289,7 +289,7 @@ def test_transport_rejects_extra_nested_missing_and_symlinked_entries(self): def test_accepted_envelope_and_lifecycle_fixture_are_verbatim(self): # Pins here are independent of any test fixture patches. - self.assertEqual("ef5e772020b151089b64b90b819d36ff371ed5e65212f7fdc7b2934d9860ddda", fixture.sha256(stable.ORIGINAL_ENVELOPE)) + self.assertEqual(stable.ENVELOPE_SHA256, fixture.sha256(stable.ORIGINAL_ENVELOPE)) self.assertEqual(stable.FIXTURE_SHA256, fixture.sha256(fixture.FIXTURE)) diff --git a/scripts/test_validate_packages_id_set.py b/scripts/test_validate_packages_id_set.py index b2cc47146f..1dc829627a 100644 --- a/scripts/test_validate_packages_id_set.py +++ b/scripts/test_validate_packages_id_set.py @@ -264,14 +264,9 @@ def test_pin_inventory_ids_are_tied_to_the_guard_list(self): pin = json.loads(candidate_input.PIN_INVENTORY.read_text(encoding="utf-8")) pin_ids = {row["id"] for row in pin["packages"]} guard_ids = set(load_expected_ids(DEFAULT_EXPECTED)) - unexpected = pin_ids - guard_ids - missing = guard_ids - pin_ids - stale_delta = unexpected == {"Elsa.SamplePackage"} and missing == set(STALE_OCT6_MISSING) - matched = not unexpected and not missing - self.assertTrue( - stale_delta or matched, - f"pin/guard delta must be the known fail-closed set or empty; unexpected={sorted(unexpected)} missing={sorted(missing)}", - ) + self.assertEqual(pin_ids, guard_ids) + self.assertEqual(231, len(pin_ids)) + self.assertEqual(candidate_input.PIN_PACKAGE_COUNT, len(pin_ids)) def test_stale_225_set_can_never_be_published_as_310(self): expected = load_expected_ids(DEFAULT_EXPECTED) @@ -289,6 +284,29 @@ def test_stale_225_set_can_never_be_published_as_310(self): self.assertIn("Unexpected (1):", text) self.assertIn("Elsa.SamplePackage", text) + def test_preflight_and_upgrade_workflows_pin_the_same_artifact(self): + root = Path(__file__).resolve().parents[1] + sys.path.insert(0, str(root / "scripts/integration-program")) + import consolidated_candidate_input as candidate_input + + for relative in ( + ".github/workflows/consolidated-package-recovery-preflight.yml", + ".github/workflows/stable-persisted-workflow-upgrade-proof.yml", + ): + source = (root / relative).read_text(encoding="utf-8") + for value in ( + str(candidate_input.ARTIFACT), + str(candidate_input.RUN), + candidate_input.SOURCE, + candidate_input.ARCHIVE_SHA256, + str(candidate_input.ARCHIVE_SIZE), + candidate_input.EXPIRES_AT, + ): + self.assertIn(value, source) + self.assertNotIn("11412848210", source) + self.assertNotIn("37456860080", source) + self.assertNotIn("ba5b348aa2414fdf7c19d9d8806e87b7c91a4205", source) + def test_both_publishers_run_the_same_id_set_guard_before_push(self): root = Path(__file__).resolve().parents[1] packages = (root / ".github/workflows/packages.yml").read_text(encoding="utf-8") From 7f93869df3fc3aeb42817734f6d186f0b00ace49 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 26 Oct 2026 13:53:04 +0000 Subject: [PATCH 2/6] docs: align recovery rehearsal counts with the 231-package pin CodeRabbit noted the executor rehearsal and full-acceptance instructions still said 225 after the re-pin. Refs #9016 Co-authored-by: Sipke Schoorstra (cherry picked from commit eef85f909366e75912eca30c7dc89fcdf60742fd) --- docs/integration-program/consolidated-package-recovery.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/integration-program/consolidated-package-recovery.md b/docs/integration-program/consolidated-package-recovery.md index e601fc86fc..c248913fd0 100644 --- a/docs/integration-program/consolidated-package-recovery.md +++ b/docs/integration-program/consolidated-package-recovery.md @@ -88,9 +88,9 @@ python3 scripts/integration-program/consolidated_package_executor.py verify \ Use `rehearse` instead of `verify`, with separate new destinations, to exercise simulated uploads and recovery with the original complete candidate. Hosted commands additionally bind `--executor-run` and `--executor-attempt`. The workflow retains separate verification, rehearsal, admission and publication artifacts identified by the GitHub run and attempt. Before scheduling native approval, its job summary binds the exact executor revision, original producer/artifact/archive/manifest, observed feed index, complete same-run verification and GitHub-reported verification artifact ID/digest. The summary links the retained evidence and distinguishes verification with missing content from release acceptance. -A successful `verify` exit means original inputs and every required local DLL/PDB association passed, and remote classifications are complete and nonconflicting. Missing packages or PDBs are allowed in this nonpublishing result. It is not release acceptance. A successful `rehearse` must demonstrate complete simulated convergence and interruption/resume across all 225 pairs, without writing to Feedz. Neither command grants upload authority. +A successful `verify` exit means original inputs and every required local DLL/PDB association passed, and remote classifications are complete and nonconflicting. Missing packages or PDBs are allowed in this nonpublishing result. It is not release acceptance. A successful `rehearse` must demonstrate complete simulated convergence and interruption/resume across all 231 pairs, without writing to Feedz. Neither command grants upload authority. -The symbol inspector preserves the existing SourceLink/document checks and emits the Portable PDB key, GUID, stamp, DLL-declared checksum and unchanged PDB hash. Readback compares actual remote PDB bytes with the corresponding original `.snupkg` member. The normalized DLL checksum and raw PDB hash are distinct. Deduplicated symbol requests must retain every package/framework association; assembly-free entries and inconsistent duplicate keys cannot be silently omitted. Full acceptance needs 225 matching packages and every expected symbol association. Original `.snupkg` archive readback remains a separate, unproven contract. +The symbol inspector preserves the existing SourceLink/document checks and emits the Portable PDB key, GUID, stamp, DLL-declared checksum and unchanged PDB hash. Readback compares actual remote PDB bytes with the corresponding original `.snupkg` member. The normalized DLL checksum and raw PDB hash are distinct. Deduplicated symbol requests must retain every package/framework association; assembly-free entries and inconsistent duplicate keys cannot be silently omitted. Full acceptance needs 231 matching packages and every expected symbol association. Original `.snupkg` archive readback remains a separate, unproven contract. ## Publication admission and execution From 5119f038af8a76207e2d4e07d72065654161e739 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 06:40:43 +0000 Subject: [PATCH 3/6] Re-pin the 3.10 candidate to run 40347931480 Co-authored-by: Sipke Schoorstra --- .agents/skills/elsa-release/SKILL.md | 2 +- .../skills/elsa-release/references/runbook.md | 8 ++--- ...onsolidated-package-recovery-preflight.yml | 30 +++++++++---------- .github/workflows/packages.yml | 8 ++--- ...table-persisted-workflow-upgrade-proof.yml | 30 +++++++++---------- .../guides/admission-connections-packages.md | 2 +- ...solidated-release-and-publisher-cutover.md | 2 +- .../consolidated-package-recovery.md | 2 +- .../consolidated-publisher-handoff.md | 2 +- .../consolidation/package-publisher-gates.md | 2 +- extensions/docs/README.md | 2 +- .../consolidated-pin-inventory-baseline.json | 8 ++--- .../consolidated_candidate_input.py | 12 ++++---- .../persisted-workflow-upgrade/README.md | 6 ++-- .../stable-original-envelope.json | 2 +- .../test_consolidated_candidate_clock.py | 2 +- ..._consolidated_executor_approval_summary.py | 6 ++-- .../test_consolidated_package_executor.py | 5 ++-- scripts/test_validate_packages_id_set.py | 3 +- 19 files changed, 68 insertions(+), 66 deletions(-) diff --git a/.agents/skills/elsa-release/SKILL.md b/.agents/skills/elsa-release/SKILL.md index 1bbf50aca6..62ad07434d 100644 --- a/.agents/skills/elsa-release/SKILL.md +++ b/.agents/skills/elsa-release/SKILL.md @@ -14,7 +14,7 @@ description: Release Elsa from elsa-core as one tag, one GitHub release and one ## What core publishes today (verify against `origin/main` before relying on it) - `.github/workflows/packages.yml` runs on `release: published`, pushes to `main` and `release/*`, and `workflow_dispatch`. A release or push only tests, builds and uploads the `elsa-nuget-packages` artifact. It never publishes. Publication needs an approved `workflow_dispatch` with `publish_preview_feedz` (Feedz: a branch, or a `3.10.x` prerelease tag) or `publish_nuget` (nuget.org: a release-version tag, including stable `3.10.x`). Stable 3.10.x Feedz is owned only by `publish-consolidated-original-candidate.yml`. -- Both the `packages.yml` promote path and `publish-consolidated-original-candidate.yml` run `scripts/validate_packages_id_set.py` on the current pin (run `40202201744`, artifact `12603436856`, 231 packages from `release/3.10.0` @ `f60c00766b107cb15038c77873d84779f0680722`) before any push. Neither workflow is part of the ordinary release-train helper. +- Both the `packages.yml` promote path and `publish-consolidated-original-candidate.yml` run `scripts/validate_packages_id_set.py` on the current pin (run `40347931480`, artifact `12664519771`, 231 packages from `release/3.10.0` @ `5cff67228e550b353b3483eb3b37dfdb73a41c74`) before any push. Neither workflow is part of the ordinary release-train helper. - `studio-npm-pair.yml` only proves that the two Studio npm archives can be built and consumed locally. `packages.yml` `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz from a 3.10.x prerelease tag. Stable Feedz publication waits for the 231-ID nuget.org promote guard. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core`. Stable 3.10.x nuget.org publication uses the current 231-ID pin (part of [#8725](https://github.com/elsa-workflows/elsa-core/issues/8725)). - The Apps container workflow lived in `elsa-apps` and core has no replacement yet. The container stage is blocked until it is re-homed in core. diff --git a/.agents/skills/elsa-release/references/runbook.md b/.agents/skills/elsa-release/references/runbook.md index 4a1f71c5a4..60550c0820 100644 --- a/.agents/skills/elsa-release/references/runbook.md +++ b/.agents/skills/elsa-release/references/runbook.md @@ -9,7 +9,7 @@ Studio, Extensions and Apps are folded into `elsa-core`; a release is one `elsa- What `elsa-core` actually does today (check `origin/main` before relying on it): - `.github/workflows/packages.yml` builds and uploads packages on `release: published` and on pushes to `main` and `release/*`. Those events never publish. Publication is an approved `workflow_dispatch`: `publish_preview_feedz` (Feedz, from a branch or a `3.10.x` prerelease tag) or `publish_nuget` (nuget.org, from a release-version tag). Stable `3.10.x` Feedz is owned only by `publish-consolidated-original-candidate.yml`. -- Its `./build.sh Compile+Pack` packs Core only on branch pushes and non-`3.10.0` tags. A `3.10.0` tag `release` event (and a non-promote dispatch from that tag) packs the 231-ID set through `prepare_consolidated_release_candidate.py`. A `publish_nuget` dispatch on a stable `3.10.x` tag does not pack: it downloads the current pin (run `40202201744`, artifact `12603436856`, source `f60c00766b107cb15038c77873d84779f0680722`), verifies each `.nupkg` sha256 against that candidate's seal, and runs `scripts/validate_packages_id_set.py` (231 IDs plus the three Studio ClientLib assets per package) before any push. That pin's archive size and expiry (`2026-11-24T15:03:46Z`) come from `stable-original-envelope.json`. `Elsa.SamplePackage` is not packable. The five `Elsa.Secrets.*` IDs and the four `Elsa.Studio.Host.*` IDs stay unpackable and `Elsa.Templates` is not in core. The whole-product 3.10.0 candidate is [prepared without publishing](#consolidated-3100-candidate-preparation-nonpublishing); `publish-consolidated-original-candidate.yml` is the only Feedz publisher for those stable 3.10.x bytes and runs the same 231-ID guard before its Feedz push. +- Its `./build.sh Compile+Pack` packs Core only on branch pushes and non-`3.10.0` tags. A `3.10.0` tag `release` event (and a non-promote dispatch from that tag) packs the 231-ID set through `prepare_consolidated_release_candidate.py`. A `publish_nuget` dispatch on a stable `3.10.x` tag does not pack: it downloads the current pin (run `40347931480`, artifact `12664519771`, source `5cff67228e550b353b3483eb3b37dfdb73a41c74`), verifies each `.nupkg` sha256 against that candidate's seal, and runs `scripts/validate_packages_id_set.py` (231 IDs plus the three Studio ClientLib assets per package) before any push. That pin's archive size and expiry (`2026-11-25T16:05:50Z`) come from `stable-original-envelope.json`. `Elsa.SamplePackage` is not packable. The five `Elsa.Secrets.*` IDs and the four `Elsa.Studio.Host.*` IDs stay unpackable and `Elsa.Templates` is not in core. The whole-product 3.10.0 candidate is [prepared without publishing](#consolidated-3100-candidate-preparation-nonpublishing); `publish-consolidated-original-candidate.yml` is the only Feedz publisher for those stable 3.10.x bytes and runs the same 231-ID guard before its Feedz push. - `studio-npm-pair.yml` is a local proof of the two Studio npm archives. `packages.yml` `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz from a 3.10.x prerelease tag. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core`. Stable `3.10.x` stays fail-closed until the 231-ID nuget.org promote guard can pass. The pair builder accepts 3.8–3.10 versions only. - Core has no container-image publishing workflow. The Apps workflow it used lived in `elsa-apps`. @@ -380,7 +380,7 @@ python3 scripts/integration-program/prepare_consolidated_release_candidate.py \ The canonical proof evaluator derives every package/exclusion from current Elsa.sln properties. It compares IDs, project paths and exclusion reasons with `consolidated-candidate-inventory-baseline.json`, derived from the accepted proof -inventory. The 225 package/symbol pairs and 124 excluded projects (123 IDs) are +inventory. The 231 package/symbol pairs and 135 excluded projects (134 IDs) are baseline sanity evidence, never an allowlist. A difference emits `inventory-diff.json` and stops before building. Review and commit any justified baseline update; do not silently shrink it. The five retired Extensions Secrets @@ -430,8 +430,8 @@ stable candidate bytes: applicable persisted compatibility checks must bind to the admitted candidate production bytes before that candidate is published. `publish-consolidated-original-candidate.yml` is the only Feedz publisher for those stable 3.10.x bytes. A `packages.yml` nuget.org dispatch on a stable -3.10.x tag downloads the current pin (run `40202201744`, artifact -`12603436856`), verifies each `.nupkg` sha256 against the candidate seal, and +3.10.x tag downloads the current pin (run `40347931480`, artifact +`12664519771`), verifies each `.nupkg` sha256 against the candidate seal, and runs the same 231-ID and Studio content guards that the candidate Feedz publisher runs before its push. The promote path does not restore, build, or pack. `3.10.1` and later stay blocked until a new pin exists. diff --git a/.github/workflows/consolidated-package-recovery-preflight.yml b/.github/workflows/consolidated-package-recovery-preflight.yml index 084b5f5892..ac4bbf6daa 100644 --- a/.github/workflows/consolidated-package-recovery-preflight.yml +++ b/.github/workflows/consolidated-package-recovery-preflight.yml @@ -28,26 +28,26 @@ jobs: run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/recovery-input" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856 > "$RUNNER_TEMP/recovery-input/artifact.json" - gh api repos/elsa-workflows/elsa-core/actions/runs/40202201744/attempts/1 > "$RUNNER_TEMP/recovery-input/producer-run.json" - jq -e '.id == 40202201744 and .run_attempt == 1 and - .head_sha == "f60c00766b107cb15038c77873d84779f0680722" and .conclusion == "success" and + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12664519771 > "$RUNNER_TEMP/recovery-input/artifact.json" + gh api repos/elsa-workflows/elsa-core/actions/runs/40347931480/attempts/1 > "$RUNNER_TEMP/recovery-input/producer-run.json" + jq -e '.id == 40347931480 and .run_attempt == 1 and + .head_sha == "5cff67228e550b353b3483eb3b37dfdb73a41c74" and .conclusion == "success" and (.event == "push" or .event == "workflow_dispatch") and .path == ".github/workflows/prepare-consolidated-release-candidate.yml"' "$RUNNER_TEMP/recovery-input/producer-run.json" > /dev/null - jq -e '.id == 12603436856 and - .name == "consolidated-candidate-f60c00766b107cb15038c77873d84779f0680722-40202201744-1" and - .expired == false and .expires_at == "2026-11-24T15:03:46Z" and - .digest == "sha256:13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d" and - .size_in_bytes == 96125850 and .workflow_run.id == 40202201744 and - .workflow_run.head_sha == "f60c00766b107cb15038c77873d84779f0680722"' "$RUNNER_TEMP/recovery-input/artifact.json" > /dev/null - test "$(date -u -d '2026-11-24T15:03:46Z' +%s)" -gt "$(date -u +%s)" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856/zip > "$RUNNER_TEMP/recovery-input/candidate.zip" - test "$(stat -c %s "$RUNNER_TEMP/recovery-input/candidate.zip")" -eq 96125850 + jq -e '.id == 12664519771 and + .name == "consolidated-candidate-5cff67228e550b353b3483eb3b37dfdb73a41c74-40347931480-1" and + .expired == false and .expires_at == "2026-11-25T16:05:50Z" and + .digest == "sha256:2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6" and + .size_in_bytes == 96096205 and .workflow_run.id == 40347931480 and + .workflow_run.head_sha == "5cff67228e550b353b3483eb3b37dfdb73a41c74"' "$RUNNER_TEMP/recovery-input/artifact.json" > /dev/null + test "$(date -u -d '2026-11-25T16:05:50Z' +%s)" -gt "$(date -u +%s)" + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12664519771/zip > "$RUNNER_TEMP/recovery-input/candidate.zip" + test "$(stat -c %s "$RUNNER_TEMP/recovery-input/candidate.zip")" -eq 96096205 printf '%s %s\n' \ - '13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d' \ + '2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6' \ "$RUNNER_TEMP/recovery-input/candidate.zip" | sha256sum --check --status jq -nc --arg observed "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - '{schema:1,artifact_id:12603436856,archive_sha256:"13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d",retrieved_at:$observed}' \ + '{schema:1,artifact_id:12664519771,archive_sha256:"2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6",retrieved_at:$observed}' \ > "$RUNNER_TEMP/recovery-input/live-retrieval.json" - name: Transfer only the verified original inputs id: transfer diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 1487c329ae..84d7880889 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -9,7 +9,7 @@ on: type: boolean default: false publish_nuget: - description: Publish a release-tag package to NuGet.org for this run (requires publisher approval). Stable 3.10.x nuget.org publishing is blocked until re-pin (#9016). + description: Publish a release-tag package to NuGet.org for this run (requires publisher approval). Stable 3.10.x nuget.org publishes the pinned 231-ID candidate. required: true type: boolean default: false @@ -374,7 +374,7 @@ jobs: fi echo "VERSION=${VERSION}" >> $GITHUB_ENV - # Stable 3.10.x nuget.org is blocked until re-pin (#9016); this job must not pack. + # Stable 3.10.x nuget.org stages the pinned candidate; this job must not pack. - uses: actions/setup-dotnet@v4 if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.publish_nuget && startsWith(github.ref, 'refs/tags/3.10.') && !contains(github.ref_name, '-')) }} with: @@ -456,7 +456,7 @@ jobs: # cancel a publish half-done. Move the two together. timeout-minutes: 30 # NuGet publication requires an explicit dispatch on a release tag. Stable - # 3.10.x is blocked until re-pin (#9016); other tags push this run's pack. + # 3.10.x stages the pinned candidate; other tags push this run's pack. if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_nuget && startsWith(github.ref, 'refs/tags/') }} permissions: contents: read @@ -478,7 +478,7 @@ jobs: - name: Download Packages # Pinned for the reason given on the checkout above. Skipped for stable - # 3.10.x, which stages the current pin and fails the 231-ID guard until #9016. + # 3.10.x, which stages the pinned 231-ID candidate. if: ${{ !(startsWith(github.ref, 'refs/tags/3.10.') && !contains(github.ref_name, '-')) }} uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: diff --git a/.github/workflows/stable-persisted-workflow-upgrade-proof.yml b/.github/workflows/stable-persisted-workflow-upgrade-proof.yml index 0c5e7afbbb..90ecac9cd0 100644 --- a/.github/workflows/stable-persisted-workflow-upgrade-proof.yml +++ b/.github/workflows/stable-persisted-workflow-upgrade-proof.yml @@ -35,26 +35,26 @@ jobs: run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/upgrade-input" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856 > "$RUNNER_TEMP/upgrade-input/artifact.json" - gh api repos/elsa-workflows/elsa-core/actions/runs/40202201744/attempts/1 > "$RUNNER_TEMP/upgrade-input/producer-run.json" - jq -e '.id == 40202201744 and .run_attempt == 1 and - .head_sha == "f60c00766b107cb15038c77873d84779f0680722" and .conclusion == "success" and + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12664519771 > "$RUNNER_TEMP/upgrade-input/artifact.json" + gh api repos/elsa-workflows/elsa-core/actions/runs/40347931480/attempts/1 > "$RUNNER_TEMP/upgrade-input/producer-run.json" + jq -e '.id == 40347931480 and .run_attempt == 1 and + .head_sha == "5cff67228e550b353b3483eb3b37dfdb73a41c74" and .conclusion == "success" and (.event == "push" or .event == "workflow_dispatch") and .path == ".github/workflows/prepare-consolidated-release-candidate.yml"' "$RUNNER_TEMP/upgrade-input/producer-run.json" > /dev/null - jq -e '.id == 12603436856 and - .name == "consolidated-candidate-f60c00766b107cb15038c77873d84779f0680722-40202201744-1" and - .expired == false and .expires_at == "2026-11-24T15:03:46Z" and - .digest == "sha256:13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d" and - .size_in_bytes == 96125850 and .workflow_run.id == 40202201744 and - .workflow_run.head_sha == "f60c00766b107cb15038c77873d84779f0680722"' "$RUNNER_TEMP/upgrade-input/artifact.json" > /dev/null - test "$(date -u -d '2026-11-24T15:03:46Z' +%s)" -gt "$(date -u +%s)" - gh api repos/elsa-workflows/elsa-core/actions/artifacts/12603436856/zip > "$RUNNER_TEMP/upgrade-input/candidate.zip" - test "$(stat -c %s "$RUNNER_TEMP/upgrade-input/candidate.zip")" -eq 96125850 + jq -e '.id == 12664519771 and + .name == "consolidated-candidate-5cff67228e550b353b3483eb3b37dfdb73a41c74-40347931480-1" and + .expired == false and .expires_at == "2026-11-25T16:05:50Z" and + .digest == "sha256:2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6" and + .size_in_bytes == 96096205 and .workflow_run.id == 40347931480 and + .workflow_run.head_sha == "5cff67228e550b353b3483eb3b37dfdb73a41c74"' "$RUNNER_TEMP/upgrade-input/artifact.json" > /dev/null + test "$(date -u -d '2026-11-25T16:05:50Z' +%s)" -gt "$(date -u +%s)" + gh api repos/elsa-workflows/elsa-core/actions/artifacts/12664519771/zip > "$RUNNER_TEMP/upgrade-input/candidate.zip" + test "$(stat -c %s "$RUNNER_TEMP/upgrade-input/candidate.zip")" -eq 96096205 printf '%s %s\n' \ - '13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d' \ + '2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6' \ "$RUNNER_TEMP/upgrade-input/candidate.zip" | sha256sum --check --status jq -nc --arg observed "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - '{schema:1,artifact_id:12603436856,archive_sha256:"13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d",retrieved_at:$observed}' \ + '{schema:1,artifact_id:12664519771,archive_sha256:"2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6",retrieved_at:$observed}' \ > "$RUNNER_TEMP/upgrade-input/live-retrieval.json" - name: Transfer only the verified original inputs id: transfer diff --git a/core/docs/guides/admission-connections-packages.md b/core/docs/guides/admission-connections-packages.md index 02cc097714..1fc3fad960 100644 --- a/core/docs/guides/admission-connections-packages.md +++ b/core/docs/guides/admission-connections-packages.md @@ -2,7 +2,7 @@ These seven existing module identities are selected for the consolidated Core 3.10 line under [#8661](https://github.com/elsa-workflows/elsa-core/issues/8661). Their projects use the normal Core library packaging convention, inheriting target frameworks `net8.0`, `net9.0` and `net10.0`. This source baseline preserves existing APIs and schemas; it does not claim that the new packages have passed evaluated MSBuild, archive or PostgreSQL consumer verification. Exact-head hosted evidence is required for that acceptance. -Use one tested head and version for the entire internal dependency closure. The accepted [lockstep/Core publisher policy](../../../docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md) applies: no independent version streams, historical candidate modification or publication is authorized by enabling these projects. The Oct 6 candidate `11412848210` excluded these identities. The current pin (`12603436856`) includes them. SQLite Connections persistence and other optional providers remain outside this promotion. +Use one tested head and version for the entire internal dependency closure. The accepted [lockstep/Core publisher policy](../../../docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md) applies: no independent version streams, historical candidate modification or publication is authorized by enabling these projects. The Oct 6 candidate `11412848210` excluded these identities. The current pin (`12664519771`) includes them. SQLite Connections persistence and other optional providers remain outside this promotion. ## Public setup and contract baseline diff --git a/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md b/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md index 667d6ddb14..aee9f8df2a 100644 --- a/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md +++ b/docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md @@ -21,7 +21,7 @@ Two publishers for one package ID and version line would let them race or overwr - disable the original repositories' publishing for 3.10 and later. From then on, each package ID has one publisher per version line. Stable 3.10.x promotion of imported packages from elsa-core is allowed only after that cutover. -3. **Publication stays behind the existing gates, with one Feedz owner for stable 3.10.x.** The root workflow publishes only on an approved `workflow_dispatch` ([package publisher gates](../integration-program/consolidation/package-publisher-gates.md)). Branch previews and 3.10.x prerelease tags may publish to Feedz from `packages.yml`. Stable 3.10.x Feedz publication is owned only by `publish-consolidated-original-candidate.yml`. Both that Feedz publisher and a `packages.yml` `publish_nuget` dispatch on a stable 3.10.x tag run the same 231-ID guard on the current pin (run `40202201744`, artifact `12603436856`, 231 packages) before any push. Other release-version tags still rebuild and publish from `packages.yml` as before. The imported Extensions and Studio `packages.yml` files stay inert at their `.source` paths. +3. **Publication stays behind the existing gates, with one Feedz owner for stable 3.10.x.** The root workflow publishes only on an approved `workflow_dispatch` ([package publisher gates](../integration-program/consolidation/package-publisher-gates.md)). Branch previews and 3.10.x prerelease tags may publish to Feedz from `packages.yml`. Stable 3.10.x Feedz publication is owned only by `publish-consolidated-original-candidate.yml`. Both that Feedz publisher and a `packages.yml` `publish_nuget` dispatch on a stable 3.10.x tag run the same 231-ID guard on the current pin (run `40347931480`, artifact `12664519771`, 231 packages) before any push. Other release-version tags still rebuild and publish from `packages.yml` as before. The imported Extensions and Studio `packages.yml` files stay inert at their `.source` paths. 4. **Deprecated packages get no consolidated version.** The legacy Extensions Secrets packages (`Elsa.Secrets.Api`, `.Core`, `.Management`, `.Models`, `.Scripting`) also carry their own `IsPackable=false`, so they stay out when the cutover lifts the product-wide setting. A guard test checks it. They are marked deprecated on NuGet at 3.10.0 and keep their 3.8.x versions ([upgrade guide](../../core/docs/migrations/secrets-legacy-extensions-upgrade.md)). 5. **The #8260 proof publishes nothing.** It runs on the import head with a clean local feed and consumer restores. No proof package goes to Feedz or NuGet.org. diff --git a/docs/integration-program/consolidated-package-recovery.md b/docs/integration-program/consolidated-package-recovery.md index c248913fd0..d08b117316 100644 --- a/docs/integration-program/consolidated-package-recovery.md +++ b/docs/integration-program/consolidated-package-recovery.md @@ -6,7 +6,7 @@ The planner always covers the complete retained manifest: 231 NuGet packages and ## Original inputs -Use the original archive from Core run `40202201744`, attempt `1`, artifact `12603436856`, source `f60c00766b107cb15038c77873d84779f0680722`. The archive SHA-256 is `13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d` and its size is 96,125,850 bytes. It expires on 2026-11-24 at 15:03:46 UTC. Expiry or deletion blocks this candidate; it never authorizes rebuilding equivalent-looking bytes. +Use the original archive from Core run `40347931480`, attempt `1`, artifact `12664519771`, source `5cff67228e550b353b3483eb3b37dfdb73a41c74`. The archive SHA-256 is `2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6` and its size is 96,096,205 bytes. It expires on 2026-11-25 at 16:05:50 UTC. Expiry or deletion blocks this candidate; it never authorizes rebuilding equivalent-looking bytes. The input directory contains exactly: diff --git a/docs/integration-program/consolidated-publisher-handoff.md b/docs/integration-program/consolidated-publisher-handoff.md index 4156c68b3e..de38ed5f26 100644 --- a/docs/integration-program/consolidated-publisher-handoff.md +++ b/docs/integration-program/consolidated-publisher-handoff.md @@ -60,7 +60,7 @@ The proposed environment names in this packet are `elsa-3-10-feedz` in Core and ## Ordered cutover packet -1. **Finish the evidence before requesting execution.** Retain the original candidate from #8631 (artifact 11412848210, archive SHA-256 `ace85260c3389916fe3dcd7ee9cd5b766e4030dd6cee13c7f89285ada79c944f`, expiry 2026-11-05T12:13:30Z), its complete 225 package/symbol pairs and exclusions. Complete #8643's browser/profile acceptance and the remaining compatibility checks. Reconfirm intended-reader access, symbol upload/readback, all original bytes and candidate availability. Never substitute a rebuild under the same version. +1. **Finish the evidence before requesting execution.** Retain the current pin (artifact 12664519771, archive SHA-256 `2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6`, expiry 2026-11-25T16:05:50Z), its complete 231 package/symbol pairs and 135 exclusions. Complete #8643's browser/profile acceptance and the remaining compatibility checks. Reconfirm intended-reader access, symbol upload/readback, all original bytes and candidate availability. Never substitute a rebuild under the same version. 2. **Prepare the exact code and settings changes.** Review a Core artifact-only executor that consumes the verified original bytes, never packs, and refuses conflicts/uncertainty before further uploads. Prepare source publisher guards that validate actual package identity/version, accepting only the approved 3.8/3.9 maintenance route and refusing 3.10+ on every executable source path. Include dispatch overrides and release/tag/rerun behavior, not just main push conditions. Bind all changes to reviewed commits, workflow digests and configured environment IDs/ref policies. 3. **Prepare replacement authority before retirement.** Specify dedicated environment credentials and a reviewed source maintenance route. Prove the separate npm replacement path required before retiring its old credential access; #8216's ownership decision is not implied by this NuGet handoff. Audit every repository and encoded/plain credential alias that can reach the shared Feedz repository. Preserve a verified maintenance procedure without retaining an unrestricted historical workflow bypass. 4. **Request one concrete operational approval.** Present the exact reviewer/bypass/ref configuration, credential creation/retirement plan, affected repositories and maintenance/npm paths, reviewed executor and source guard commits, candidate hashes, compatibility/symbol evidence, expected feed/version, and stop/recovery instructions. This document and a green PR do not authorize those live actions. diff --git a/docs/integration-program/consolidation/package-publisher-gates.md b/docs/integration-program/consolidation/package-publisher-gates.md index 980a790a2b..7f5bc42e14 100644 --- a/docs/integration-program/consolidation/package-publisher-gates.md +++ b/docs/integration-program/consolidation/package-publisher-gates.md @@ -3,7 +3,7 @@ The Packages workflow now builds and tests normally on pushes and release events, but those events cannot publish packages or deploy coverage. The four publication jobs are default-off `workflow_dispatch` options: - `publish_preview_feedz` publishes the run's packages to Feedz. Dispatch from a branch for a preview build (`-preview.`), or from a 3.10.x prerelease tag. Stable 3.10.x Feedz is owned only by `publish-consolidated-original-candidate.yml`. -- `publish_nuget` publishes a release-tag package to NuGet.org. Dispatch from a release-version tag. A stable 3.10.x nuget.org dispatch downloads the current pin (run `40202201744`, artifact `12603436856`, source `f60c00766b107cb15038c77873d84779f0680722`), verifies each `.nupkg` sha256 against the candidate seal, and runs the 231-ID list and Studio content guards on that exact set before any push. Other tags push this run's pack. +- `publish_nuget` publishes a release-tag package to NuGet.org. Dispatch from a release-version tag. A stable 3.10.x nuget.org dispatch downloads the current pin (run `40347931480`, artifact `12664519771`, source `5cff67228e550b353b3483eb3b37dfdb73a41c74`), verifies each `.nupkg` sha256 against the candidate seal, and runs the 231-ID list and Studio content guards on that exact set before any push. Other tags push this run's pack. - `publish_npm` publishes `@elsa-workflows/elsa-studio-wasm` and `@elsa-workflows/elsa-studio-wasm-react` to Feedz. `build_npm` builds the pair without credentials. Dispatch from a release-version tag. Feedz npm is live for 3.10.x prerelease tags. The npmjs.com upload is not in this job until trusted publishing is confirmed for `elsa-workflows/elsa-core` (#8725). Stable 3.10.x is rejected in the selection check and also fail-closed in the job. The pair builder accepts 3.8–3.10 versions only, so a 3.11+ tag fails that check. - `deploy_coverage` deploys the coverage report to GitHub Pages. Dispatch from `main` or `release/3.6.1`, the refs whose coverage run uploads a Pages artifact. diff --git a/extensions/docs/README.md b/extensions/docs/README.md index d7f0dad403..17e9ca49fe 100644 --- a/extensions/docs/README.md +++ b/extensions/docs/README.md @@ -28,7 +28,7 @@ Normal source builds retain the imported product's packing guard. The reviewed [consolidated package proof](../../docs/integration-program/consolidated-package-proof.md) evaluates eligible packages explicitly and verifies original archive/consumer provenance. The [first 3.10 release policy](../../docs/adr/2026-09-28-lockstep-consolidated-release-and-publisher-cutover.md) -is lockstep with Core as sole 3.10+ publisher (NuGet.org for release tags (stable 3.10.x by candidate promotion, blocked until re-pin (#9016)); Feedz for previews, 3.10.x prereleases, and the stable 3.10.x candidate publish, blocked until re-pin (#9016)); +is lockstep with Core as sole 3.10+ publisher (NuGet.org for release tags (stable 3.10.x by candidate promotion); Feedz for previews, 3.10.x prereleases, and the stable 3.10.x candidate publish); source publisher cutover remains separately governed. The earlier [Slack release-unit handoff](../../docs/integration-program/publisher-handoff.md) is bounded historical preparation, not evidence that live publisher ownership diff --git a/scripts/integration-program/consolidated-pin-inventory-baseline.json b/scripts/integration-program/consolidated-pin-inventory-baseline.json index 768670618c..a8a9ba5e10 100644 --- a/scripts/integration-program/consolidated-pin-inventory-baseline.json +++ b/scripts/integration-program/consolidated-pin-inventory-baseline.json @@ -1,11 +1,11 @@ { "evidence": { - "archive_sha256": "13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d", - "artifact_id": 12603436856, + "archive_sha256": "2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6", + "artifact_id": 12664519771, "inventory_sha256": "56852c6a58d0949dca2aacb8c682f2652e6788634cbc1daf98c110177183f73c", - "run_id": 40202201744, + "run_id": 40347931480, "scope": "Reviewed inventory comparison only; never relabel or reuse as candidate bytes.", - "source_commit": "f60c00766b107cb15038c77873d84779f0680722", + "source_commit": "5cff67228e550b353b3483eb3b37dfdb73a41c74", "version": "3.10.0" }, "exclusions": [ diff --git a/scripts/integration-program/consolidated_candidate_input.py b/scripts/integration-program/consolidated_candidate_input.py index 00518750be..4c088bd5e6 100644 --- a/scripts/integration-program/consolidated_candidate_input.py +++ b/scripts/integration-program/consolidated_candidate_input.py @@ -8,13 +8,13 @@ import prepare_consolidated_release_candidate as candidate -SOURCE = "f60c00766b107cb15038c77873d84779f0680722" -RUN = 40202201744 +SOURCE = "5cff67228e550b353b3483eb3b37dfdb73a41c74" +RUN = 40347931480 ATTEMPT = 1 -ARTIFACT = 12603436856 -ARCHIVE_SHA256 = "13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d" -MANIFEST_SHA256 = "ac881065f8c59465955032a37ad733dd95e3c32c91acdbbb10b267ed993524e6" -ENVELOPE_SHA256 = "417f73adf02866c6ec4aaa261609c50320508bed683fd78b217e2dcbb8c35af8" +ARTIFACT = 12664519771 +ARCHIVE_SHA256 = "2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6" +MANIFEST_SHA256 = "b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994" +ENVELOPE_SHA256 = "9c1840b8f6c68c70338390453995b9382f21feadf7d577b257dd7a95e8b1417b" ORIGINAL_ENVELOPE = Path(__file__).resolve().parent / "persisted-workflow-upgrade/stable-original-envelope.json" # Frozen candidate pin inventory (231 packages). Recovery and the executor # use this snapshot so they still accept the real pinned artifact. diff --git a/scripts/integration-program/persisted-workflow-upgrade/README.md b/scripts/integration-program/persisted-workflow-upgrade/README.md index 83134fc141..e7b0d8bc61 100644 --- a/scripts/integration-program/persisted-workflow-upgrade/README.md +++ b/scripts/integration-program/persisted-workflow-upgrade/README.md @@ -38,9 +38,9 @@ Hosted execution logs contain command kinds/phases, exit codes/timeouts, recogni ## Accepted stable 3.10.0 adapter -`run_stable_persisted_workflow_upgrade_fixture.py` applies the same six-cell lifecycle to the distinct stable bytes accepted through #8635. The original proof entrypoint, workflow, archive pins and earlier evidence remain separate. The stable producer is source `f60c00766b107cb15038c77873d84779f0680722`, run `40202201744`, attempt `1`, artifact `12603436856`. Its original archive is exactly 96,125,850 bytes with SHA-256 `13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d`, expiring at `2026-11-24T15:03:46Z`. Deleted or expired originals fail; no replacement/rebuild/repack is accepted. +`run_stable_persisted_workflow_upgrade_fixture.py` applies the same six-cell lifecycle to the distinct stable bytes accepted through #8635. The original proof entrypoint, workflow, archive pins and earlier evidence remain separate. The stable producer is source `5cff67228e550b353b3483eb3b37dfdb73a41c74`, run `40347931480`, attempt `1`, artifact `12664519771`. Its original archive is exactly 96,096,205 bytes with SHA-256 `2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6`, expiring at `2026-11-25T16:05:50Z`. Deleted or expired originals fail; no replacement/rebuild/repack is accepted. -The checked-in `stable-original-envelope.json` preserves the accepted historical envelope verbatim (SHA-256 `417f73adf02866c6ec4aaa261609c50320508bed683fd78b217e2dcbb8c35af8`, retrieved at `2026-10-25T15:04:07Z`). Its pre-upload manifest SHA-256 is `ac881065f8c59465955032a37ad733dd95e3c32c91acdbbb10b267ed993524e6`. Each execution separately records fresh live artifact metadata, the exact successful producer run/attempt and a new retrieval observation. The existing candidate verifier checks the accepted envelope, archive and complete file inventory before extraction. The package manifest validator still checks the complete inventory and reviewed external exceptions; this fixture requires only Elsa and Elsa.Persistence.EFCore.Sqlite. Other representative consumers retain their five-package default. +The checked-in `stable-original-envelope.json` preserves the accepted historical envelope verbatim (SHA-256 `9c1840b8f6c68c70338390453995b9382f21feadf7d577b257dd7a95e8b1417b`, retrieved at `2026-10-27T06:37:49Z`). Its pre-upload manifest SHA-256 is `b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994`. Each execution separately records fresh live artifact metadata, the exact successful producer run/attempt and a new retrieval observation. The existing candidate verifier checks the accepted envelope, archive and complete file inventory before extraction. The package manifest validator still checks the complete inventory and reviewed external exceptions; this fixture requires only Elsa and Elsa.Persistence.EFCore.Sqlite. Other representative consumers retain their five-package default. ```sh python3 -m unittest discover -s scripts/integration-program -p 'test_*persisted_workflow_upgrade_fixture.py' @@ -51,7 +51,7 @@ python3 scripts/integration-program/run_stable_persisted_workflow_upgrade_fixtur --fixture-source "$(git rev-parse HEAD)" ``` -The fresh retrieval JSON has exactly `schema: 1`, `artifact_id: 12603436856`, the accepted `archive_sha256`, and the new timezone-qualified `retrieved_at`. The input directory contains exactly candidate.zip, artifact.json, producer-run.json and live-retrieval.json as regular files, with no nested, extra or symlinked entries. Artifact JSON is the current GitHub API response; producer-run.json comes from the fixed actions/runs/40202201744/attempts/1 endpoint so a later rerun cannot replace the accepted producer attempt. Local executions record null matrix run/attempt; hosted runs pass their actual run/attempt. Receipts distinguish the candidate producer from the exact fixture checkout commit and matrix run/attempt, record the selected execution SDK in the sdk field, without relabeling it as the producer's SDK, and retain both envelope and observation bytes with hashes. A development `--cell` remains incomplete and cannot pass the matrix gate. +The fresh retrieval JSON has exactly `schema: 1`, `artifact_id: 12664519771`, the accepted `archive_sha256`, and the new timezone-qualified `retrieved_at`. The input directory contains exactly candidate.zip, artifact.json, producer-run.json and live-retrieval.json as regular files, with no nested, extra or symlinked entries. Artifact JSON is the current GitHub API response; producer-run.json comes from the fixed actions/runs/40347931480/attempts/1 endpoint so a later rerun cannot replace the accepted producer attempt. Local executions record null matrix run/attempt; hosted runs pass their actual run/attempt. Receipts distinguish the candidate producer from the exact fixture checkout commit and matrix run/attempt, record the selected execution SDK in the sdk field, without relabeling it as the producer's SDK, and retain both envelope and observation bytes with hashes. A development `--cell` remains incomplete and cannot pass the matrix gate. The dedicated `Stable persisted workflow upgrade proof` workflow uses the same trusted push/manual retrieval boundary: fixed API requests without checkout or repository execution in the only token-bearing job; four fixed inputs cross through ID-only same-run transport. Execution checks out the exact fixture head with credentials disabled and `actions: none`, verifies bytes, then runs all six cells. Initial push can activate this costly workflow, so review the coherent head before pushing. It does not rebuild Elsa packages or publish/deploy anything. A green tooling job is not lifecycle acceptance; all six cells and all 18 lifecycle processes, retained database hashes and a fresh original-artifact availability check require independent exact-head audit. Inspect retained SQLite originals only through disposable copies. diff --git a/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json b/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json index 4847087b0b..ad961e0112 100644 --- a/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json +++ b/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json @@ -1 +1 @@ -{"schema":1,"published":false,"version":"3.10.0","source_commit":"f60c00766b107cb15038c77873d84779f0680722","run_id":40202201744,"run_attempt":1,"artifact_id":12603436856,"artifact_name":"consolidated-candidate-f60c00766b107cb15038c77873d84779f0680722-40202201744-1","archive_sha256":"13241bc1889f03165d4925e6294e829eee3094cd9694b00ef37d904e69d01a0d","archive_size":96125850,"expires_at":"2026-11-24T15:03:46Z","retention_days":30,"retrieved_at":"2026-10-25T15:04:07Z","preupload_manifest_sha256":"ac881065f8c59465955032a37ad733dd95e3c32c91acdbbb10b267ed993524e6"} +{"schema":1,"published":false,"version":"3.10.0","source_commit":"5cff67228e550b353b3483eb3b37dfdb73a41c74","run_id":40347931480,"run_attempt":1,"artifact_id":12664519771,"artifact_name":"consolidated-candidate-5cff67228e550b353b3483eb3b37dfdb73a41c74-40347931480-1","archive_sha256":"2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6","archive_size":96096205,"expires_at":"2026-11-25T16:05:50Z","retention_days":30,"retrieved_at":"2026-10-27T06:37:49Z","preupload_manifest_sha256":"b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994"} \ No newline at end of file diff --git a/scripts/integration-program/test_consolidated_candidate_clock.py b/scripts/integration-program/test_consolidated_candidate_clock.py index 256cef25f9..00cbaf3645 100644 --- a/scripts/integration-program/test_consolidated_candidate_clock.py +++ b/scripts/integration-program/test_consolidated_candidate_clock.py @@ -6,7 +6,7 @@ from unittest.mock import patch -SYNTHETIC_NOW = datetime(2026, 10, 26, 14, tzinfo=timezone.utc) +SYNTHETIC_NOW = datetime(2026, 10, 27, 14, tzinfo=timezone.utc) AFTER_EXPIRY = datetime(2030, 1, 1, tzinfo=timezone.utc) diff --git a/scripts/integration-program/test_consolidated_executor_approval_summary.py b/scripts/integration-program/test_consolidated_executor_approval_summary.py index 448926e60d..94c9548e72 100644 --- a/scripts/integration-program/test_consolidated_executor_approval_summary.py +++ b/scripts/integration-program/test_consolidated_executor_approval_summary.py @@ -15,6 +15,8 @@ from test_consolidated_candidate_clock import AFTER_EXPIRY, candidate_clock, install_candidate_clock executor = summary.executor +# First seven fixture rows add one extra framework; the rest add two. +SINGLE_EXTRA_FRAMEWORK_COUNT = 7 class SummaryTests(unittest.TestCase): @@ -52,7 +54,7 @@ def setUp(self): # Give the receipt the actual candidate's association count without # creating additional archives or pretending this fixture is that proof. for index, row in enumerate(self.verification["associations"]): - for framework in ("net9.0",) if index < 7 else ("net9.0", "net10.0"): + for framework in ("net9.0",) if index < SINGLE_EXTRA_FRAMEWORK_COUNT else ("net9.0", "net10.0"): item = copy.deepcopy(row["associations"][0]) item["framework"] = framework digest = executor.sha((row["id"]+framework).encode()) @@ -80,7 +82,7 @@ def render(self): def test_complete_missing_observation_reports_actual_associations_and_immutable_bindings(self): packages = executor.candidate_input.PIN_PACKAGE_COUNT - associations = packages + 7 + (packages - 7) * 2 + associations = packages + SINGLE_EXTRA_FRAMEWORK_COUNT + (packages - SINGLE_EXTRA_FRAMEWORK_COUNT) * 2 text = self.render() for value in (self.context["GITHUB_SHA"], executor.candidate_input.SOURCE, executor.candidate_input.ARCHIVE_SHA256, executor.candidate_input.MANIFEST_SHA256, executor.candidate_input.ENVELOPE_SHA256, diff --git a/scripts/integration-program/test_consolidated_package_executor.py b/scripts/integration-program/test_consolidated_package_executor.py index 21298e6755..4d8a4831e9 100644 --- a/scripts/integration-program/test_consolidated_package_executor.py +++ b/scripts/integration-program/test_consolidated_package_executor.py @@ -24,6 +24,7 @@ PIN_COUNT = executor.candidate_input.PIN_PACKAGE_COUNT PIN_EXCLUSIONS = executor.candidate_input.PIN_EXCLUSION_COUNT PIN_ARCHIVES = PIN_COUNT * 2 +PARTIAL_KEEP_STRIDE = 3 # keep every third accepted nupkg def loopback_server(test, handler): @@ -168,12 +169,12 @@ def test_package_present_symbol_missing_and_arbitrary_partial(self): for partial in (False, True): self.fill_feed() if partial: - self.feed.accepted = {key: value for index, (key, value) in enumerate(self.feed.accepted.items()) if index % 3 == 1} + self.feed.accepted = {key: value for index, (key, value) in enumerate(self.feed.accepted.items()) if index % PARTIAL_KEEP_STRIDE == 1} self.feed.symbols.clear() self.feed.calls.clear() result = self.run_executor() self.assertTrue(result["content_verified"]) - self.assertEqual(len(self.feed.calls), (2 * PIN_COUNT - PIN_COUNT // 3) if partial else PIN_COUNT) + self.assertEqual(len(self.feed.calls), (2 * PIN_COUNT - PIN_COUNT // PARTIAL_KEEP_STRIDE) if partial else PIN_COUNT) self.assertEqual(sum(row["kind"] == "snupkg" for row in self.feed.calls), PIN_COUNT) def test_accepted_then_interrupted_resume_without_duplicate(self): diff --git a/scripts/test_validate_packages_id_set.py b/scripts/test_validate_packages_id_set.py index 1dc829627a..a38528f8ba 100644 --- a/scripts/test_validate_packages_id_set.py +++ b/scripts/test_validate_packages_id_set.py @@ -1,3 +1,4 @@ +import json import os import subprocess import sys @@ -256,8 +257,6 @@ def test_script_rejects_a_studio_nupkg_with_the_bundle_removed(self): class SharedPublisherGuardTests(unittest.TestCase): def test_pin_inventory_ids_are_tied_to_the_guard_list(self): - import json - sys.path.insert(0, str(Path(__file__).resolve().parent / "integration-program")) import consolidated_candidate_input as candidate_input From cf9202ce917428f65172b7fbb70b8ee9820ce1a2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 06:42:11 +0000 Subject: [PATCH 4/6] Stop listing elsa-studio-v3 as a 3.10 published image Co-authored-by: Sipke Schoorstra --- .github/workflows/docker-publish.yml | 5 +---- core/docs/wiki/build-run-operate.md | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 1e171b46bf..39f91b6c69 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -3,8 +3,8 @@ # Images (Docker Hub only; these are the names the old Community publishers used, # and the names still referenced by the root README, wiki, samples, and docs): # elsaworkflows/elsa-server-v3 <- docker/ElsaServer.Dockerfile -# elsaworkflows/elsa-studio-v3 <- docker/ElsaStudio.Dockerfile # elsaworkflows/elsa-server-and-studio-v3 <- docker/ElsaServerAndStudio.Dockerfile +# 3.10 does not publish elsaworkflows/elsa-studio-v3. # # Tags: # every accepted version publishes its exact X.Y.Z or X.Y.Z-preview.N tag @@ -159,9 +159,6 @@ jobs: - name: elsa-server-and-studio dockerfile: docker/ElsaServerAndStudio.Dockerfile image: elsaworkflows/elsa-server-and-studio-v3 - - name: elsa-studio - dockerfile: docker/ElsaStudio.Dockerfile - image: elsaworkflows/elsa-studio-v3 steps: - name: Checkout ${{ needs.prepare.outputs.source_ref }} uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/core/docs/wiki/build-run-operate.md b/core/docs/wiki/build-run-operate.md index d91ec02cfd..b7038bd22b 100644 --- a/core/docs/wiki/build-run-operate.md +++ b/core/docs/wiki/build-run-operate.md @@ -87,7 +87,7 @@ docker pull elsaworkflows/elsa-server-and-studio-v3:latest docker run -t -i -e ASPNETCORE_ENVIRONMENT='Development' -e HTTP_PORTS=8080 -e HTTP__BASEURL=http://localhost:13000 -p 13000:8080 elsaworkflows/elsa-server-and-studio-v3:latest ``` -The same source-built Community images are also published as `elsaworkflows/elsa-server-v3` and `elsaworkflows/elsa-studio-v3`. Every accepted tag publishes that exact version. Stable `3.X.Y` also moves `X.Y` when it is the highest stable tag on that line, and `latest` when it is the highest stable 3.x tag. Preview tags never move `X.Y` or `latest`. The publisher is [`.github/workflows/docker-publish.yml`](../../../.github/workflows/docker-publish.yml); `docker-ca.yml` builds the same Dockerfiles for TLS smoke tests without pushing. +The same source-built Community images are also published as `elsaworkflows/elsa-server-v3`. Every accepted tag publishes that exact version. Stable `3.X.Y` also moves `X.Y` when it is the highest stable tag on that line, and `latest` when it is the highest stable 3.x tag. Preview tags never move `X.Y` or `latest`. The publisher is [`.github/workflows/docker-publish.yml`](../../../.github/workflows/docker-publish.yml); `docker-ca.yml` builds the same Dockerfiles for TLS smoke tests without pushing. Production containers must inject a secure JWT signing key through environment variables or a secrets manager. The appsettings placeholder and known public sample keys are rejected during startup outside `Development` or `Demo`. From a5a252d4de3bf60cf718e88fc652759240767e9a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 06:53:05 +0000 Subject: [PATCH 5/6] Restore the producer envelope for the 3.10 candidate pin Co-authored-by: Sipke Schoorstra (cherry picked from commit 9f1d704fb7a4fad278dd31b4975f75aa86b63581) --- scripts/integration-program/consolidated_candidate_input.py | 2 +- .../integration-program/persisted-workflow-upgrade/README.md | 2 +- .../persisted-workflow-upgrade/stable-original-envelope.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/integration-program/consolidated_candidate_input.py b/scripts/integration-program/consolidated_candidate_input.py index 4c088bd5e6..95b91cf119 100644 --- a/scripts/integration-program/consolidated_candidate_input.py +++ b/scripts/integration-program/consolidated_candidate_input.py @@ -14,7 +14,7 @@ ARTIFACT = 12664519771 ARCHIVE_SHA256 = "2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6" MANIFEST_SHA256 = "b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994" -ENVELOPE_SHA256 = "9c1840b8f6c68c70338390453995b9382f21feadf7d577b257dd7a95e8b1417b" +ENVELOPE_SHA256 = "2369a297877ec51b5fc5da4f4f90df65f33dbf03036485109d994b7cae678328" ORIGINAL_ENVELOPE = Path(__file__).resolve().parent / "persisted-workflow-upgrade/stable-original-envelope.json" # Frozen candidate pin inventory (231 packages). Recovery and the executor # use this snapshot so they still accept the real pinned artifact. diff --git a/scripts/integration-program/persisted-workflow-upgrade/README.md b/scripts/integration-program/persisted-workflow-upgrade/README.md index e7b0d8bc61..3a9c2d9114 100644 --- a/scripts/integration-program/persisted-workflow-upgrade/README.md +++ b/scripts/integration-program/persisted-workflow-upgrade/README.md @@ -40,7 +40,7 @@ Hosted execution logs contain command kinds/phases, exit codes/timeouts, recogni `run_stable_persisted_workflow_upgrade_fixture.py` applies the same six-cell lifecycle to the distinct stable bytes accepted through #8635. The original proof entrypoint, workflow, archive pins and earlier evidence remain separate. The stable producer is source `5cff67228e550b353b3483eb3b37dfdb73a41c74`, run `40347931480`, attempt `1`, artifact `12664519771`. Its original archive is exactly 96,096,205 bytes with SHA-256 `2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6`, expiring at `2026-11-25T16:05:50Z`. Deleted or expired originals fail; no replacement/rebuild/repack is accepted. -The checked-in `stable-original-envelope.json` preserves the accepted historical envelope verbatim (SHA-256 `9c1840b8f6c68c70338390453995b9382f21feadf7d577b257dd7a95e8b1417b`, retrieved at `2026-10-27T06:37:49Z`). Its pre-upload manifest SHA-256 is `b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994`. Each execution separately records fresh live artifact metadata, the exact successful producer run/attempt and a new retrieval observation. The existing candidate verifier checks the accepted envelope, archive and complete file inventory before extraction. The package manifest validator still checks the complete inventory and reviewed external exceptions; this fixture requires only Elsa and Elsa.Persistence.EFCore.Sqlite. Other representative consumers retain their five-package default. +The checked-in `stable-original-envelope.json` preserves the accepted historical envelope verbatim (SHA-256 `2369a297877ec51b5fc5da4f4f90df65f33dbf03036485109d994b7cae678328`, retrieved at `2026-10-26T16:06:11Z`). Its pre-upload manifest SHA-256 is `b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994`. Each execution separately records fresh live artifact metadata, the exact successful producer run/attempt and a new retrieval observation. The existing candidate verifier checks the accepted envelope, archive and complete file inventory before extraction. The package manifest validator still checks the complete inventory and reviewed external exceptions; this fixture requires only Elsa and Elsa.Persistence.EFCore.Sqlite. Other representative consumers retain their five-package default. ```sh python3 -m unittest discover -s scripts/integration-program -p 'test_*persisted_workflow_upgrade_fixture.py' diff --git a/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json b/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json index ad961e0112..caf9d9a43c 100644 --- a/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json +++ b/scripts/integration-program/persisted-workflow-upgrade/stable-original-envelope.json @@ -1 +1 @@ -{"schema":1,"published":false,"version":"3.10.0","source_commit":"5cff67228e550b353b3483eb3b37dfdb73a41c74","run_id":40347931480,"run_attempt":1,"artifact_id":12664519771,"artifact_name":"consolidated-candidate-5cff67228e550b353b3483eb3b37dfdb73a41c74-40347931480-1","archive_sha256":"2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6","archive_size":96096205,"expires_at":"2026-11-25T16:05:50Z","retention_days":30,"retrieved_at":"2026-10-27T06:37:49Z","preupload_manifest_sha256":"b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994"} \ No newline at end of file +{"schema":1,"published":false,"version":"3.10.0","source_commit":"5cff67228e550b353b3483eb3b37dfdb73a41c74","run_id":40347931480,"run_attempt":1,"artifact_id":12664519771,"artifact_name":"consolidated-candidate-5cff67228e550b353b3483eb3b37dfdb73a41c74-40347931480-1","archive_sha256":"2dd253e1f2946ddcb2b8e75ef397596001757ddbcb0a91f717e9505bbf28b4f6","archive_size":96096205,"expires_at":"2026-11-25T16:05:50Z","retention_days":30,"retrieved_at":"2026-10-26T16:06:11Z","preupload_manifest_sha256":"b6a1750f1f796f68a441bef93f67386b4a862dbca94d498ecf64536b102c2994"} \ No newline at end of file From 067f952980511a9e7a26aad6dbcab9319200fcd9 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 06:56:27 +0000 Subject: [PATCH 6/6] Keep the producer envelope including its trailing LF The previous pin hashed the committed 565-byte envelope (trailing LF). Match that convention, bind ENVELOPE_SHA256 to those bytes, and fold the 3.10.0 wording, leftover import, and stale #9016 comment nits. Co-authored-by: Sipke Schoorstra --- .github/workflows/packages.yml | 8 ++++---- build/ConsolidatedPackageProof.targets | 2 +- .../integration-program/consolidated_candidate_input.py | 2 +- .../persisted-workflow-upgrade/README.md | 2 +- .../stable-original-envelope.json | 2 +- scripts/test_validate_packages_id_set.py | 8 ++------ 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 84d7880889..56789eee89 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -9,7 +9,7 @@ on: type: boolean default: false publish_nuget: - description: Publish a release-tag package to NuGet.org for this run (requires publisher approval). Stable 3.10.x nuget.org publishes the pinned 231-ID candidate. + description: Publish a release-tag package to NuGet.org for this run (requires publisher approval). Stable 3.10.0 nuget.org publishes the pinned 231-ID candidate. required: true type: boolean default: false @@ -374,7 +374,7 @@ jobs: fi echo "VERSION=${VERSION}" >> $GITHUB_ENV - # Stable 3.10.x nuget.org stages the pinned candidate; this job must not pack. + # Stable 3.10.0 nuget.org stages the pinned candidate; this job must not pack. - uses: actions/setup-dotnet@v4 if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.publish_nuget && startsWith(github.ref, 'refs/tags/3.10.') && !contains(github.ref_name, '-')) }} with: @@ -456,7 +456,7 @@ jobs: # cancel a publish half-done. Move the two together. timeout-minutes: 30 # NuGet publication requires an explicit dispatch on a release tag. Stable - # 3.10.x stages the pinned candidate; other tags push this run's pack. + # 3.10.0 stages the pinned candidate; other tags push this run's pack. if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_nuget && startsWith(github.ref, 'refs/tags/') }} permissions: contents: read @@ -478,7 +478,7 @@ jobs: - name: Download Packages # Pinned for the reason given on the checkout above. Skipped for stable - # 3.10.x, which stages the pinned 231-ID candidate. + # 3.10.0, which stages the pinned 231-ID candidate. if: ${{ !(startsWith(github.ref, 'refs/tags/3.10.') && !contains(github.ref_name, '-')) }} uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: diff --git a/build/ConsolidatedPackageProof.targets b/build/ConsolidatedPackageProof.targets index de05c1aaf0..5e3e6a04af 100644 --- a/build/ConsolidatedPackageProof.targets +++ b/build/ConsolidatedPackageProof.targets @@ -6,7 +6,7 @@ Code="ELSA0003" Text="ConsolidatedPackageProof requires PackageVersion 3.10.0-proof.<positive run>.<positive attempt>. Publication and publisher cutover remain separate approvals." /> - +