Skip to content

fix(e2e-ui): multi-workspace identity scopes and dual HMR suite - #178

Closed
patrickleet wants to merge 53 commits into
mainfrom
fix/e2e-ui-multi-workspace-identity-hmr
Closed

patrickleet wants to merge 53 commits into
mainfrom
fix/e2e-ui-multi-workspace-identity-hmr

Conversation

@patrickleet

Copy link
Copy Markdown
Collaborator

Summary

  • OIDC projectIdRef.namespace → shared Project; empty mrNamespace for worktree OIDC apps
  • Local seed Secret e2e-ui-oidc so cluster-dev pods schedule without Vault residual
  • Helm contract tests for alice/bob scopes + baseUris
  • Local dual-worktree suite: two git worktrees, gitops both, HMR beacon isolation (no CI Dory)
  • Depends on hops-cli Add SQLite bus transport #90 (--dory-name vs workspace --name)

Stack

Stacked on feat/e2e-ui-local-workbench-identity (#177).

Test plan

  • ./tests/e2e-ui/scripts/helm-contract-test.sh
  • Local dual suite on Dory: alice+bob FQDNs, beacon update, isolation, dory-name unchanged
  • Auth login smoke when shared Project/OIDC Ready (noted not Ready in local auth-smoke)

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1fd52cd5-062f-4a83-bb4a-42d675e4a68e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@patrickleet

Copy link
Copy Markdown
Collaborator Author

Depends on hops-cli stacked PR: hops-ops/hops-cli#90

Implements [[tasks/contract-lifecycle-tooling-2]]
Implements [[tasks/contract-lifecycle-tooling-2]]
Implements [[tasks/contract-lifecycle-tooling-2]]
Implements [[tasks/contract-lifecycle-tooling-2]]
Implements [[tasks/contract-lifecycle-tooling-3]]
Implements [[tasks/contract-lifecycle-tooling-3]]
Implements [[tasks/contract-lifecycle-tooling-3]]
Implements [[tasks/contract-lifecycle-tooling-9]]
Close the next-major surface identity cutover for task 9: application
surfaces carry distinct eligible_roles (who may open) and schema_roles
(privilege intersection), end-to-end across Surface IR, client manifest,
protocol authority, projection deltas, CLI selectors, and TS replica
validation/clone.

Also land remaining application composition fixtures (contract-only
artifact bin, runtime/unlisted packages, renamed-dependency trybuild)
and remove the dual manifest owner path.

Implements [[tasks/contract-lifecycle-tooling-9]]
Add the pure deployment-plan compiler for task 10: composable
MountSelector presets (Full/Writer/Projector/QueryApi), Atomic
collocation validation, explained capability closure with single
schema-lifecycle owner, topology intent inventory, and
byte-deterministic plan identity linked to ApplicationManifest.

Implements [[tasks/contract-lifecycle-tooling-10]]
Add contract lifecycle snapshot flattening, path-level semantic diffs,
distinct manifest-wire vs protocol decision classification, and no-write
predecessor chain diagnostics with owner/path/expected/observed facts.

Implements [[tasks/contract-lifecycle-tooling-4]]
Rename the standalone binary from dctl to distributed, add top-level
DistributedArgs with contracts check/accept, and implement exact-scope
accept transactions with staging, atomic replace, and rollback. Update
in-repo product docs, workflows, skills, and generated client banners
to invoke distributed.

Implements [[tasks/contract-lifecycle-tooling-5]]
Introduce the versioned command dispatch boundary used by API-only and
writer processes: object-safe CommandDispatcher, LocalCommandDispatcher
over Service, and the task-20 approved HTTPS mTLS remote profile with
loopback parity tests that strip forwarded role claims.

Implements [[tasks/contract-lifecycle-tooling-11]] and
[[tasks/contract-lifecycle-tooling-20]]
Introduce the task-12 process host skeleton: bind one DeploymentPlan
process against explicit capability providers and an optional
CommandDispatcher, failing closed when required capabilities or dispatch
are missing.

Implements [[tasks/contract-lifecycle-tooling-12]]
Add an explicit application composition module for e2e-ui surface and
module identities, re-export it from the service crate, migrate read
models to ReadModelCatalog, and update GraphQL surface registration for
eligible/schema role split.

Partial [[tasks/contract-lifecycle-tooling-13]]
Expose graphql_router_with_dispatcher as the host-facing mutation path,
keep graphql_router_with_service as the local adapter implementation, and
update dispatcher-not-configured diagnostics.

Implements [[tasks/contract-lifecycle-tooling-11]]
Add make contracts-check, e2e-ui Makefile routing, an opt-in pre-push
template, and a PR contracts job that other broad jobs can depend on.

Implements [[tasks/contract-lifecycle-tooling-6]]
Add deterministic ClientProgramDescriptor building, asset hashing, and
three-way Current / asset-only / incompatible classification, with
program:<id> accept scopes.

Implements [[tasks/contract-lifecycle-tooling-7]]
Verify application → plan → optional program predecessor links and
release program classification for CTL closeout outside K8s/Hops work.

Implements [[tasks/contract-lifecycle-tooling-8]]
Move process wiring into e2e_service::run_e2e_host with LocalCommandDispatcher
at the host boundary, shrink the runner binary to env selection + host call,
and check in selectable deployment-plan inventories for full/api/writer/
projector/mixed/split cuts.

Implements [[tasks/contract-lifecycle-tooling-13]]
Replace the ~900-line central service.rs wiring file with explicit
todo/chat/blob modules, a compose root listing them into one Service,
GraphQL/surface exports, and a thin compatibility façade. Runner remains
one-screen host invocation.

This is the DX outcome of the application-composition epic for e2e-ui:
module inventory is review-visible; infrastructure stays in host.

Implements [[tasks/contract-lifecycle-tooling-13]]
Re-export compose/graphql APIs from lib.rs and keep client-surface tests
next to graphql module. No intermediate service.rs re-export layer.

Implements [[tasks/contract-lifecycle-tooling-13]]
Add LocalProjectionMountsBuilder so apps declare program+model+epoch only,
Routes::for_aggregate to hide QueuedRepository wiring, and shared outbox/
consumer worker helpers. Rewrite e2e projection mounts and host loops to
use them — product code keeps command intent, not topology ceremony.

Implements [[tasks/contract-lifecycle-tooling-13]]
Derive client projection previews from command input, defaults, and
row-policy claims when .applies is omitted. Add command_transition and
sourced domain_commands witnesses so emit sets come from domain methods.
Migrate todo/chat/blob to that path, thin blob move to game_id+direction,
delete client simulate_move, and fix distributed client --surface to read
roles from the manifest for gen-client.
Drop simulate-move unit test, stop requiring fat blob preview fields,
and assert eligible/schema application roles on generated clients.
…tests

Workers require tokio spawn/sleep — compile them only when a feature enables
the optional tokio dep so default-feature checks pass. Rename integration
test env! paths from CARGO_BIN_EXE_dctl to CARGO_BIN_EXE_distributed after
the binary rename.
Defer --surface kind/name mismatches to the client compiler so CLI stderr
keeps client.manifest.surface_mismatch. Use Session::new() in the default-
feature typed guard dispatch test so session_with_role is not required
without the graphql feature.
Move session admission (has user / is admin) onto TypedRouteBuilder
.guarded mounts so handlers only bind principal and call domain.
Add CausalCommandContext::session, causal_has_user/causal_is_admin
helpers, and keep input/domain checks in the handler body.
Extract pure simulate_move into blob-core (no distributed host), export
it via blob-wasm, and replace the TypeScript board twin with a thin
loader that registers the same pure id for auto-optimism.

make wasm / ui-install builds pkg; CI installs wasm-pack + wasm32.
Collapse blob-core and blob-wasm into blob-domain: pure rules live in
src/core/, WASM exports in src/wasm.rs behind --features wasm, aggregate
host stays default --features domain. make wasm builds that one package.
Update blob walkthrough for known-row pure reduce + blob-domain WASM,
session guards/principal in command mounts and handlers, and add a
Service module tab on every demo (MODULE_ID, routes, compose).
Add createWasmJsonPure for load/JSON/fail-closed hosting. blobSimulateMove
now takes record+args JSON and validates inside blob-domain wasm. App
simulate-move.ts is a short pure registration only.
Declare CommandProjectionPureReduce::wasm(package, export); render_pures
emits createWasmJsonPure hosts and ensurePureFunctionsReady. Blob move
registers blob/pkg/blob_wasm; delete hand pure host. board.ts stays as
UI presentation helpers (tiles/parse), not domain pure.
Expand every Service tab with compose, host.run_e2e_host, and e2e-runner
main. Blob commands tab explains pure-reduce reasoning, benefits, gen-client
WASM host, and fail-closed authority; domain tab covers core vs wasm faces.
Add Helm deploy charts for api/ui with cluster-dev vs package
posture, local PSQLCluster for the API, and hops.local
Application YAMLs under gitops/env/local. Document hops local
up as Option A for dogfood.

Implements [[tasks/lwb-e2e-ui-gitops-charts]] [[tasks/lwb-docs-happy-path]]
When sourceDelivery.mode=sync, wait for .hops-synced / package manifest
before cargo/vite so tar/mutagen can populate emptyDir first.
api deliveryPath points at e2e-ui Cargo root; ui at ui/ with vite.
cluster-dev waits indefinitely for .hops-synced/package/Cargo before start.
…ault

Add gitops/cluster tree (packages, providers, AuthStack, PSQLStack,
e2e-identity MRs) and SecretStack vault backend claim for local workbench.
Wire app charts/env Applications for cluster-dev delivery. Keep secrets out
of YAML; document kubectl bootstrap in SECRETS.md.
Move shared Zitadel Project/roles/humans to cluster scope, keep OIDC
apps worktree-scoped for redirects and Login V2 baseUri. Restructure
cluster gitops (configurations/, stacks/, DRCs) and ExternalSecrets
hooks for OIDC + demo passwords.
Wire project id into local Application env so the API does not fall
back to DevHeaders, and drop hand-rolled deliveryPath so delivery uses
the git worktree root by default.
Manage Zitadel instance loginV2 via Features MR so authorize redirects to
this worktree's custom /login. Derive baseUri and OIDC placement from
hops --name / helm release namespace; drop hand-set residual docs.
Keep shared Project/roles/humans in default, scope OIDC to release
namespace, seed local OIDC secrets for cluster-dev pods, and add a local
dual-worktree suite that gitops alice+bob and proves UI beacon updates.
Single-file beacon sync and pause full-tree tar watchers so Vite client
HMR updates without full navigation; fail the suite on extraNav>0.
Refs: [[incidents/inc-005-e2e-ui-optimism-stalls]]
@patrickleet
patrickleet force-pushed the feat/e2e-ui-local-workbench-identity branch from 7be8ed7 to 9e48f87 Compare August 13, 2026 02:51
@patrickleet
patrickleet force-pushed the fix/e2e-ui-multi-workspace-identity-hmr branch from 5164c2b to f96887b Compare August 13, 2026 02:51
@patrickleet
patrickleet changed the base branch from feat/e2e-ui-local-workbench-identity to main August 13, 2026 03:11
patrickleet added a commit that referenced this pull request Aug 13, 2026
Squash the complete stacked change set through PR #178 after GitHub's
stack merge operation landed only the bottom layer.

Includes PRs #172, #173, #174, #177, and #178.

BREAKING CHANGE: the standalone CLI binary is named distributed instead
of dctl, and application surface roles use the eligible/schema split.
@patrickleet

Copy link
Copy Markdown
Collaborator Author

Stack merge recovery: GitHub’s stack operation partially landed the stack. The complete stack through #178 is now preserved on main as aggregate squash b97f96a, whose tree matches the original #178 head exactly. This PR is superseded by that commit; its source branch is being retained. The prior broken main is preserved at recovery/github-stack-broken-main-20260813-031051.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant