Skip to content

[3417 by Claude Opus 5.5] Fix the hosted UI release deploy (app.propr.dev) added in #3409. Check current upstream main first. - #3418

Merged
integry merged 2 commits into
mainfrom
3417/claude-opus-5-5-fix-the-hosted-ui-release-20261101-1053-g99
Nov 1, 2026
Merged

integry merged 2 commits into
mainfrom
3417/claude-opus-5-5-fix-the-hosted-ui-release-20261101-1053-g99

Conversation

@propr-dev

@propr-dev propr-dev Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

AI Implementation Summary

Closes #3417

Branch: 3417/claude-opus-5-5-fix-the-hosted-ui-release-20261101-1053-g99
Commits: ✅ Changes committed (198a34e)


AI Processing Completed

Execution Details:

Summary:
The hosted UI deploy now builds @propr/shared before the UI. There's also a new workflow to re-deploy an already-published release from main. I reproduced the original failure on the v0.9.1 tag and confirmed the fix builds there. Nothing was merged, tagged, dispatched or deployed.

Upstream main is still dcd3bb97d, the same commit this branch starts from, so there was nothing new to bring in.

Proof against the v0.9.1 tag (a copy of the tag with a fresh npm ci):

  • packages/shared/dist doesn't exist after the install.
  • npm run build -w propr-ui on its own fails with the same error as the release run: Failed to resolve entry for package "@propr/shared".
  • npm run build -w @propr/shared && npm run build -w propr-ui succeeds, and the built bundle contains "0.9.1".
  • The UI only needs @propr/shared built. @propr/client is read straight from its source through the UI's build config.

What changed

  • New .github/workflows/hosted-ui-deploy.yml: the deploy steps now live here. The release job calls it, and you can also run it by hand with a release_tag input. It:

    • refuses to run from any branch other than main.
    • requires a v<semver> tag that exists in the repo.
    • runs in hosted-ui-production, one deploy at a time.
    • checks out the tag and confirms the root package.json version matches it.
    • runs npm ci, builds shared then the UI, deploys with the pinned wrangler@4.156.0, and runs the verify script.

    Actions are pinned by SHA and permissions are read-only. The skip notice when Cloudflare credentials are missing is unchanged, and the failure summary now points to this workflow.

  • docker-images.yml: deploy-hosted-ui keeps its name, if and needs, and now just calls the new workflow with the release tag. No secrets are passed from the release workflow; the deploy job reads them from its own environment. Because the steps live in one file, the release path and the manual path can't drift.

  • package.json: deploy:hosted-ui now builds @propr/shared first.

  • Docs: hosted-ui-release.md has a new "Re-deploy a published release" section using gh workflow run hosted-ui-deploy.yml --ref main -f release_tag=v0.9.1. It also notes that tags up to v0.9.1 still have the old deploy:hosted-ui script, so a manual deploy of those needs npm run build -w @propr/shared first.

  • CHANGELOG: an entry under ## [Unreleased] → ### Fixed.

Tests: I extended test/hostedUiReleaseDeploy.test.mjs. It checks that shared is built before the UI in both the workflow and the npm script, and that the release job uses the shared workflow. It runs the tag check against a stub gh, covering bad formats, a missing tag, dispatch from a non-main branch or a tag, and the call from the release workflow. It also covers the skip and recovery messages. All 15 tests pass. actionlint 1.7.12 with shellcheck reports nothing on both workflow files. The other workflow test files I ran (dedup, runner routing, Chromium install, release validation, change classification, full-suite selection, preview CLI, nightly contract) and the docs manifest test all pass.

One thing I couldn't check offline: when the release workflow calls the deploy workflow, I'm relying on GitHub's documented behaviour that the called job reads secrets from its own environment:. If that turned out not to hold, the release job would show the "deploy skipped" notice rather than fail. Running the new workflow by hand would still deploy, because it reads the environment's secrets directly.

To deploy app.propr.dev for v0.9.1 once this is merged, run the Hosted UI Deploy workflow from main with release_tag=v0.9.1.

No preview images: nothing in this change is visible in the UI.

Detailed Logs:

  • Conversation: 78 messages
  • Session: 616eb80f-07c7-4f75-9cf8-1a3f78d74727

Log files stored at:

  • conversation: /usr/src/app/logs/executions/issue-3417-2026-11-01T11-01-20-524Z-conversation.json
  • output: /usr/src/app/logs/executions/issue-3417-2026-11-01T11-01-20-524Z-output.txt
Latest Conversation Messages
ASSISTANT: [content unavailable]

ASSISTANT: The hosted UI deploy now builds `@propr/shared` before the UI. There's also a new workflow to re-deploy an already-published release from `main`. I reproduced the original failure on the v0.9.1 tag an...


This PR was created automatically by ProPR after processing issue #3417.


💡 Need changes?

Comment on this PR to request refinements — the AI agent monitors comments and will update the implementation based on your feedback. Keep iterating until you're satisfied!

…s also a new workflow to re-deploy an already-published release from `main`. I reproduced the original failure on the v0.9.1 tag and confirmed the fix builds there. Nothing was merged, tagged, dispatched or deployed.

Upstream `main` is still `dcd3bb97d`, the same commit this branch starts from, so there was nothing new to bring in.

Proof against the v0.9.1 tag (a copy of the tag with a fresh `npm ci`):
- `packages/shared/dist` doesn't exist after the install.
- `npm run build -w propr-ui` on its own fails with the same error as the release run: `Failed to resolve entry for package "@propr/shared"`.
- `npm run build -w @propr/shared && npm run build -w propr-ui` succeeds, and the built bundle contains `"0.9.1"`.
- The UI only needs `@propr/shared` built. `@propr/client` is read straight from its source through the UI's build config.

What changed
- New `.github/workflows/hosted-ui-deploy.yml`: the deploy steps now live here. The release job calls it, and you can also run it by hand with a `release_tag` input. It:
  - refuses to run from any branch other than `main`.
  - requires a `v<semver>` tag that exists in the repo.
  - runs in `hosted-ui-production`, one deploy at a time.
  - checks out the tag and confirms the root `package.json` version matches it.
  - runs `npm ci`, builds shared then the UI, deploys with the pinned `wrangler@4.156.0`, and runs the verify script.

  Actions are pinned by SHA and permissions are read-only. The skip notice when Cloudflare credentials are missing is unchanged, and the failure summary now points to this workflow.
- `docker-images.yml`: `deploy-hosted-ui` keeps its name, `if` and `needs`, and now just calls the new workflow with the release tag. No secrets are passed from the release workflow; the deploy job reads them from its own environment. Because the steps live in one file, the release path and the manual path can't drift.
- `package.json`: `deploy:hosted-ui` now builds `@propr/shared` first.
- Docs: `hosted-ui-release.md` has a new "Re-deploy a published release" section using `gh workflow run hosted-ui-deploy.yml --ref main -f release_tag=v0.9.1`. It also notes that tags up to v0.9.1 still have the old `deploy:hosted-ui` script, so a manual deploy of those needs `npm run build -w @propr/shared` first.
- CHANGELOG: an entry under `## [Unreleased]` → `### Fixed`.

Tests: I extended `test/hostedUiReleaseDeploy.test.mjs`. It checks that shared is built before the UI in both the workflow and the npm script, and that the release job uses the shared workflow. It runs the tag check against a stub `gh`, covering bad formats, a missing tag, dispatch from a non-`main` branch or a tag, and the call from the release workflow. It also covers the skip and recovery messages. All 15 tests pass. actionlint 1.7.12 with shellcheck reports nothing on both workflow files. The other workflow test files I ran (dedup, runner routing, Chromium install, release validation, change classification, full-suite selection, preview CLI, nightly contract) and the docs manifest test all pass.

One thing I couldn't check offline: when the release workflow calls the deploy workflow, I'm relying on GitHub's documented behaviour that the called job reads secrets from its own `environment:`. If that turned out not to hold, the release job would show the "deploy skipped" notice rather than fail. Running the new workflow by hand would still deploy, because it reads the environment's secrets directly.

To deploy app.propr.dev for v0.9.1 once this is merged, run the Hosted UI Deploy workflow from `main` with `release_tag=v0.9.1`.

No preview images: nothing in this change is visible in the UI.
@integry

integry commented Nov 1, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR fixes the missing workspace build and provides a reusable recovery workflow. It needs a localized change before merge: the new manual path accepts existing tags without establishing that their releases were published.

✅ Correct build order — Both deployment paths now build @propr/shared before the UI, matching its dist/index.js package entry.

✅ Shared deployment implementation — Automatic releases and manual recovery reuse the same build, deployment, and verification steps.

✅ Focused regression coverage — Tests cover command ordering, dispatch restrictions, credential skipping, and recovery guidance.

This review is based on static inspection; no commands were run. The supplied issue objective is truncated after item 2, so unseen requirements could not be assessed. The authoritative checks show no failures and 16 pending checks.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F1: 🔴 Require a published release before deployment

  • Required behavior: The new recovery entry point is defined as redeploying an already-published release; production deployment must preserve that publication prerequisite.

  • Evidence: .github/workflows/hosted-ui-deploy.yml, Validate release tag

    1. A version tag exists with a matching root package version, but its release pipeline fails before publish-github-release—for example, during release validation.
    2. A maintainer dispatches the new workflow from main with that tag.
    3. The validation calls only git/ref/tags/$RELEASE_TAG, which succeeds because the tag exists.
    4. With configured credentials and a successful UI build, the workflow deploys that unpublished version to app.propr.dev.

    The production UI can consequently advance to a version whose release validation or publication failed. The main-ref guard, package-version comparison, and deployment concurrency do not establish publication. The automatic caller retains its publication dependency, but direct dispatch bypasses it. The new tests stub tag existence only and therefore accept this sequence.

    static trace: traced the direct-dispatch path through tag validation, checkout, version confirmation, and deployment, and compared it with the automatic caller’s publish-github-release dependency.

  • Minimum fix: Validate that the requested tag has a published, non-draft GitHub release before proceeding. Add coverage rejecting an existing tag with no published release while retaining support for published releases.

Suggestions

These are optional follow-ups and are not sent to /fix.

S1: 🟢 Clarify old-tag manual recovery guidance

The new failure summary recommends npm run deploy:hosted-ui from the selected tag, but v0.9.1 retains the broken script. The updated operations document correctly explains that older tags need npm run build -w @propr/shared first. Include that caveat or link directly to the manual instructions in the summary. This is optional because the primary recovery workflow supplies the missing build and the documentation already describes the workaround.

Score

The core build fix and reusable workflow are sound, with focused tests. The new manual path needs a publication check before it preserves the release deployment contract.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 37s
  • Tokens: 50,049 (49,238 in / 811 out)
  • Cost: $0.42

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F1 S1

🤖 Review by ProPR

@integry

integry commented Nov 1, 2026

Copy link
Copy Markdown
Owner

/fix

@propr-dev

propr-dev Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 2022eb4

Addressed 1 AI review comment (IDs: 6557065944)

Addressed finding F1

Summary of Changes

I fixed F1: the hosted UI deploy now refuses to run unless the requested tag has a published GitHub release that isn't a draft.

What changed

  • Workflow (.github/workflows/hosted-ui-deploy.yml, step Validate release tag): the tag-exists check is unchanged. After it, the step calls gh api repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_TAG --jq '.draft' and stops in two cases:
    • No release found: "has no published GitHub release". This covers a tag whose release run failed before publish-github-release.
    • Draft is anything but false: "is not published (draft: …)". That endpoint already leaves out draft releases; checking the flag as well costs nothing.
  • Both entry points: the check runs for a manual run from main and for the call from the release workflow. That call only happens after publish-github-release succeeds, so a normal release still passes.
  • Docs (hosted-ui-release.md, "Re-deploy a published release"): step 1 now says the workflow refuses a tag with no published release.

Tests (test/hostedUiReleaseDeploy.test.mjs): the fake gh now has four tags:

  • v0.9.1 and v1.0.0-rc.1 have published releases and are still accepted.
  • v0.9.2 exists but has no release, and is rejected whether run by hand or called from the release workflow.
  • v0.9.3 has a draft release and is rejected.

The tests also check that the release lookup is actually made.

Verification

  • All 15 tests in that file pass. With the workflow from the last commit put back, the tag-validation test fails (14 pass, 1 fail), so the new cases do catch the gap.
  • The docs tests pass.
  • actionlint 1.7.12 reports nothing on hosted-ui-deploy.yml or docker-images.yml. shellcheck isn't installed in this container, so the shell checks inside actionlint did not run this time.

Other findings: nothing outside F1. No other step relies on the tag existing to mean it was published: the checkout and version check use the validated tag. The remaining gap is a race no workflow can close: a release could be deleted or set back to draft after this check passes and before the deploy. No screenshots were taken because the change is workflow-only.

Gmail, Google Calendar and Google Drive need authorizing in your claude.ai connector settings before they can be used. This task didn't need them.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @integry
  • Time: 3m 1s
  • Tokens: 462,435 (457,323 in / 5,112 out)
  • Cost: $0.41

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 6557137869✓

…the requested tag has a published GitHub release that isn't a draft.

I fixed F1: the hosted UI deploy now refuses to run unless the requested tag has a published GitHub release that isn't a draft.

**What changed**
- **Workflow** (`.github/workflows/hosted-ui-deploy.yml`, step `Validate release tag`): the tag-exists check is unchanged. After it, the step calls `gh api repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_TAG --jq '.draft'` and stops in two cases:
  - **No release found:** "has no published GitHub release". This covers a tag whose release run failed before `publish-github-release`.
  - **Draft is anything but `false`:** "is not published (draft: …)". That endpoint already leaves out draft releases; checking the flag as well costs nothing.
- **Both entry points:** the check runs for a manual run from `main` and for the call from the release workflow. That call only happens after `publish-github-release` succeeds, so a normal release still passes.
- **Docs** (`hosted-ui-release.md`, "Re-deploy a published release"): step 1 now says the workflow refuses a tag with no published release.

**Tests** (`test/hostedUiReleaseDeploy.test.mjs`): the fake `gh` now has four tags:
- `v0.9.1` and `v1.0.0-rc.1` have published releases and are still accepted.
- `v0.9.2` exists but has no release, and is rejected whether run by hand or called from the release workflow.
- `v0.9.3` has a draft release and is rejected.

The tests also check that the release lookup is actually made.

**Verification**
- All 15 tests in that file pass. With the workflow from the last commit put back, the tag-validation test fails (14 pass, 1 fail), so the new cases do catch the gap.
- The docs tests pass.
- actionlint 1.7.12 reports nothing on `hosted-ui-deploy.yml` or `docker-images.yml`. shellcheck isn't installed in this container, so the shell checks inside actionlint did not run this time.

**Other findings:** nothing outside F1. No other step relies on the tag existing to mean it was published: the checkout and version check use the validated tag. The remaining gap is a race no workflow can close: a release could be deleted or set back to draft after this check passes and before the deploy. No screenshots were taken because the change is workflow-only.

Gmail, Google Calendar and Google Drive need authorizing in your claude.ai connector settings before they can be used. This task didn't need them.

PR: #3418
Comment by: @integry (ID: 6557137869)
Model: Claude Opus 5.5
@integry

integry commented Nov 1, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR fixes the missing shared-workspace build and provides a reusable deployment workflow for recovering already-published releases. It is merge-ready within the visible scope, conditional on the two pending checks completing successfully.

✅ Correct build order — Both deployment paths build @propr/shared before the UI, satisfying its dist/index.js dependency. The supplied Vite configuration confirms that @propr/client resolves directly to source.

✅ Release-aware recovery — The new workflow validates the published release, checks out its tag, confirms its version, serializes production deployments, and verifies the served bundle.

✅ Focused regression coverage — Tests exercise validation failures, caller versus direct-dispatch behavior, missing credentials, and build ordering.

This review used static analysis only; no commands were run. The original issue description is truncated, so requirements beyond its visible portion could not be assessed. The supplied current checks show no failures.

Merge blockers

No merge blockers.

Suggestions

These are optional follow-ups and are not sent to /fix.

S2: 🟢 Clarify legacy-tag recovery guidance

In .github/workflows/hosted-ui-deploy.yml, the failure summary recommends npm run deploy:hosted-ui from the release tag. For v0.9.1, that script still requires an explicit shared build first, as the updated documentation correctly explains. Include that prerequisite or link to the manual-deploy instructions. This is optional because the summary’s primary recommendation—dispatching the new workflow from main—already supplies the correct recovery path.

Score

The implementation addresses the demonstrated failure with consistent build steps and useful validation coverage. No merge-blocking regression was identified; live deployment was not independently verified, and two checks remain pending.

Score: 9/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 24s
  • Tokens: 52,041 (51,551 in / 490 out)
  • Cost: $0.43

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix S2

🤖 Review by ProPR

@integry
integry merged commit eb01269 into main Nov 1, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix the hosted UI release deploy (app.propr.dev) added in #3409. Check current upstream main first.

1 participant