Skip to content

feat(releases): show the stable release's blocks in the authoring UI - #635

Open
dc2tom wants to merge 1 commit into
aws-samples:mainfrom
dc2tom:feat/release-catalog-authoring
Open

dc2tom wants to merge 1 commit into
aws-samples:mainfrom
dc2tom:feat/release-catalog-authoring

Conversation

@dc2tom

@dc2tom dc2tom commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Fixes #607.

Problem

With release pinning on, a release's own blocks are invisible to the authoring UI. The block library, the workflows page and the stage editor's lead, support and reviewer pickers list only the mutable library (SYSTEM plus default) from GET /blocks/{type}. A release's closure lives in S3, and nothing in the UI can browse it.

So when an admin promotes a release to stable, typically a custom fork that adds its own agents, nobody can find those agents or choose them in a custom stage. The only workaround is copying each agent into default. But those copies then override the release's versions in every pinned intent, which defeats the point of an immutable release.

Solution

Backend (workflows Lambda): its role can already read aidlc-releases/*, so there's no IAM change.

  • GET /aidlc-releases/{releaseId}/blocks[?type=agent,stage] lists a registered release's blocks by type, plus its workflow.

    • Blocks come back in the GET /blocks/{type} shape, with source: "release" and the releaseId.
    • It reads the digest-verified closure (loadReleaseClosure) and never the SYSTEM rows.
  • GET /aidlc-releases/{releaseId}/blocks/{type}/{blockId} returns one block with its body and script.

    • Each object must be one the manifest lists with that digest, and its bytes must match.
    • Otherwise it answers 409 (release_closure_mismatch / release_object_missing). A missing object that S3 reports as AccessDenied is handled the same way.
  • Access follows the same rule as ?release=: an admin may read any registered release, anyone else only a selectable one. Unknown and hidden releases get the same 404, so the routes can't be used to enumerate the registry.

  • ?libraryRelease=<id> on compiled, execution-preview and validate-grid checks the live workflow the way an intent created now, pinned to that release, would resolve it:

    • the closure replaces the SYSTEM rows, and the default library overrides it where ids match;
    • SYSTEM placements resolve from the closure.

    A custom stage that names a release-only agent therefore checks clean, as it will run. This is separate from ?release=, which reads a pinned intent's immutable snapshot and refuses unversioned user stages. The two can't be combined.

Frontend:

  • Admin → AI-DLC releases: a Contents view per release, listing its workflow and its blocks by type, with search.
  • Block library: the stable release's blocks of the current type appear below the library, read-only, with the release id. ?release=<id> shows another registered release instead. A library block with the same id is flagged, because it replaces the release's block in pinned intents.
  • Block editor: a block opened with ?release= is read from the release and is read-only.
  • Workflows page: the stable release's workflow is listed, read-only.
  • Stage editor pickers (block editor and composer modal): agents, artifacts, sensors and stages include the stable release's blocks.
    • Each id appears once, resolved as a pinned intent resolves it: library, then release, then SYSTEM.
    • Each option is labelled by source.
    • Typed ids not in a picker are still accepted, as before.
  • Composer: for a user workflow, the plan check and compiled view use ?libraryRelease=<stable>. The page says "Checked against … (stable)" only when both reads actually used the release. If the release can't be read, it says the check used the library only.

Terraform: three API Gateway resources, their CORS modules, and their entries in the redeployment trigger.

Docs: a "Release contents in the authoring UI" section in docs/concepts/aidlc-release-compatibility.md, and a note in docs/using-the-platform/workflows.md.

Testing

  • Backend: lambda/workflows/test/aidlc-release-contents.test.js, 23 tests, covering:

    • the listing by type;
    • that SYSTEM rows are never read;
    • the non-admin 404 gate;
    • tampered closures, rewritten bodies and missing bodies, including AccessDenied;
    • libraryRelease resolving a release-only agent, library-over-release precedence, SYSTEM placements read from the closure, and refusal when combined with release.

    The workflows and release resolver/registry suites pass, 372 tests.

  • Frontend: new tests for the releases service (paths, caching, invalidation on a closure upgrade, the stable catalog), picker merging, the contents dialog, the library and editor in release mode (including a stale-type race), picker source labels, the admin Contents button, and the composer's label and fallback. The related suites pass, 228 tests.

  • Checks: npm run lint and npm run format:check pass at the root and in frontend/, with no findings in changed files. tsc passes. terraform fmt -check, terraform validate -no-tests and terraform test (27 passed) pass.

  • Live: we have run this as an overlay on our deployment, with a custom fork release on stable.

Impact

  • Pinning off, or no stable release: nothing changes in the UI or the API.
  • New routes: read-only. They reuse the existing selectability gate and expose nothing a non-admin can't already select.
  • Existing behaviour: ?release= and the unpinned preview are unchanged.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Fixes aws-samples#607. With release pinning on, the block library, the workflows
page and the stage editor's pickers read only the mutable library, so a
release's own agents can't be found or chosen in a custom stage.

- workflows Lambda: GET /aidlc-releases/{releaseId}/blocks[?type=] and
  .../blocks/{type}/{blockId} read a registered release's digest-verified
  closure, read-only. Admins may read any registered release, anyone else
  only a selectable one, with the same 404 for hidden and unknown.
- ?libraryRelease= on compiled, execution-preview and validate-grid
  previews the live workflow as a new pinned intent resolves it.
- UI: a Contents view per release in the admin releases tab, the stable
  release's blocks in the block library and its workflow on the workflows
  page (read-only), and source-labelled release options in the stage
  pickers. The composer claims the release check only when both reads
  used the release.
- Three API Gateway resources; no IAM change.
const checkedAgainstRelease =
!!libraryRelease &&
compiled?.libraryRelease === libraryRelease.releaseId &&
(preview == null || preview.libraryRelease === libraryRelease.releaseId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Stable check label remains after both plan previews fail

When a workflow has an active scope and both the release-backed preview and its library fallback fail, the catch sets preview to null. That satisfies this condition, so a successful compiled read still leaves “Checked against … (stable)” visible even though the plan check never completed. Intent creation still validates the plan, but the authoring feedback is misleading. I’d reserve this label for a preview carrying the stable release ID and distinguish an unavailable check from a successful library fallback. A regression case with compiled succeeding and both previews rejecting would cover this.

@jeromevdl jeromevdl added area/frontend React application in frontend/ area/backend Lambda APIs, lambda/shared, v2-orchestrator area/infra Terraform, installer and deployment size/L < 3000 changed lines (lockfiles excluded) labels Oct 30, 2026

@collaborative-ai-dlc collaborative-ai-dlc Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please see the 1 inline finding(s) below.

Comment thread lambda/workflows/index.js
Comment on lines +1818 to +1825
const readableReleaseClosure = async (event, releaseId) => {
const record = await readableReleaseRecord(releaseId, { isAdmin: isPlatformAdmin(event) });
const closure = await loadReleaseClosure({
s3,
bucket: artifactsBucket(),
methodologyRelease: releasePinFromRecord(record),
ddb,
tableName: blocksTable(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[P2] Allow admins to inspect unpromoted custom releases

The contents route uses the execution-oriented loadReleaseClosure for every registered release. A newly registered custom fork is non-runnable, so its custom pin triggers release_not_runnable and the admin Contents view returns 409 before promotion.

Suggested fix: Use a digest-verifying inspection path that allows an admin-authorized registered custom closure without relaxing runtime execution checks, and test listing and body reads for an import-only custom release.

Evidence: registerCustomRelease records custom forks as runnable false; releasePinFromRecord preserves custom provenance; loadReleaseClosure rejects a custom record unless runnable is true. A direct probe reconfirmed ReleaseResolverError release_not_runnable. This is distinct from the supplied composer-label discussion because it affects backend inspection of pre-promotion custom releases.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/backend Lambda APIs, lambda/shared, v2-orchestrator area/frontend React application in frontend/ area/infra Terraform, installer and deployment size/L < 3000 changed lines (lockfiles excluded)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Show the stable release's blocks in the block library and stage editor pickers

4 participants