Repository navigation
Apps: the person's account decides where apps open and holds the favourites; Přístup k modulu for Owners and Stewards; the shell reports the last Environment (DEV-6639) - #159
Conversation
agentrozjedemeai
left a comment
There was a problem hiding this comment.
CHANGES_REQUESTED — exact head a86874f. One scoped correctness defect in src/launchpad/account.ts:151-182. Optimistic rollback uses only the current inclusion of the favourite; it cannot distinguish a later third click on the same key. Deterministic repro on this head: start empty; click the same star three times before replies (PUT, DELETE, PUT), leaving it visibly starred; resolve the first PUT false and the later DELETE/PUT true. The first failure removes the star, and the final visible list stays empty even though the last click and last successful PUT starred it. I ran this in the isolated checkout with bun and observed after three clicks [m:deals], first result false visible [], second/third true true final []. Please limit the fix to same-key concurrent write/rollback ordering (generation/version or serialization) and add a test covering three rapid toggles with out-of-order failure/success; preserve other keys and account fallback behavior. CI is green, but this defect blocks approval. No other scope expansion requested.
…ick wins Pablo's review of #159: the optimistic rollback looked only at whether the favourite was shown, so it could not tell a later click on the same favourite apart. Three quick clicks (PUT, DELETE, PUT) with the first PUT refused and the later writes taken removed the star, although the last click and the last successful write starred it. Concurrent writes could also reach the account out of order. Now one favourite has one write under way at a time, sent in the order of the clicks. It keeps what the account last took and what the last click wants: a click made while a write is under way is sent after it, and only if it still differs from what the account holds. A failure is put back, with the short message, only when no later click wants something else; then the favourite shows what the account holds, in its place. Different favourites, and the browser fallback, are unchanged. The tests cover the three quick clicks starring and unstarring, a click undone before its write answers, the last click's failure and its place, and two favourites written independently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
a86874f to
387fb87
Compare
|
@agentrozjedemeai Thanks, the defect was real and is fixed in 387fb87 ("Apps: one favourite's account writes go one at a time, so the last click wins"). New head: 387fb87, rebased on Fix (
Your repro (start empty, three quick clicks, the first PUT refused):
Tests (
Browser check: the same triple click in Chrome against the hosted preview sends Checks: Could you review the unchanged head 387fb87? |
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty APPROVED — exact head 4e257e9. The old three-click rollback defect is fixed by per-key serialization; the first refused PUT is followed by the still-wanted PUT, and unrelated favourites drain independently. Focused tests (57), standalone folder-prepare-change (47), lint, typecheck, and synthetic integration with #161 (47 tests plus lint/typecheck) passed in isolated checkouts. GitHub macOS and Ubuntu checks are green; zero unresolved threads. Prior CHANGES_REQUESTED on a86874f is superseded. Delivery hold: #161 merged first; the sole docs/launchpad-development.md textual conflict with live main needs a conflict-only child into this PR branch and a fresh exact-head review/check/thread gate before merging #159. This approval does not cover a changed parent head.
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty APPROVED — exact current head 514cf9b, including conflict-only #164 against main d2133f8 (#161). The merge tree is the same independently tested combined tree (9d2df9fe); the sole conflict was the docs union, with no new product intent. Three-click same-key rollback remains corrected, the hosted identity parser/producer remain fail-closed. On this exact head: 47 focused tests, lint, typecheck, check:public and git diff --check pass; GitHub macOS and Ubuntu checks green, zero unresolved conversations. My old a86874f change request and 4e257e9 approval are superseded by this exact-head review.
|
@annavesela @immakermatty Delivery hold on exact head 514cf9b: #161 is merged and conflict-only child #164 merged into this PR; current-main integration is clean. My exact-head APPROVED review is #159 (review), and both macOS/Ubuntu checks pass with zero unresolved threads. GitHub nevertheless reports reviewDecision=REVIEW_REQUIRED and mergeStateStatus=BLOCKED. The new parent head was authored by agentrozjedemeai via the integration child, so my own review cannot satisfy the remaining independent approval gate. I requested Anna as a reviewer; please check the exact current head and approve if sound. I will not merge with --admin or bypass the gate. After an independent approval, the Steward can recheck head/checks/threads/mergeability and merge with --match-head-commit. |
… canonical slug The Dashboard addresses an Organization by its canonical slug: the manifest's slug lowercased, every run of other characters one "-", none at either end, and it matches /orgs/<slug> exactly. The shell document built the page from the slug as written, so the picker's Organization head led to the Dashboard's not-found page for every Organization whose slug has capitals or other characters. dashboardSlug() follows the Dashboard's rule; a slug that reduces to nothing falls back to the Dashboard's home. "Přístup k modulu" builds on this page. The Dashboard's per-person suffix for two Organizations that reduce to the same slug cannot be known here; such a link still ends on its not-found page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Přístup k modulu" (root decision 0185 S15, issue #151) is offered to the Organization's Owners and Stewards. The Owner answer exists; a Steward's did not. GET /api/organizations/<org>/modules/<module>/maintain answers whether this Environment's GitHub identity has permissions.maintain on the module's declared repository (gh api repos/<owner>/<repo>), behind the same admission and through the same gh path as the Owner check (askGitHub, now shared): bounded by its timeout, kept five minutes per repository, one question per repository at a time, and false on every failure. It is never asked on a Team Environment, without a bound GitHub login, without a declared repository, or for a repository outside the Organization's login. The catalog now carries a module's repository page as `url`, read from its slot's git.url like a production repository's; nothing is fetched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…urites; Přístup k modulu for Owners and Stewards Root decision 0185 S12, S15 and S18, over the account document of F37's addendum. Apps reads GET /.lazurio/account/environments once per page load (same origin, no token, no redirect followed, given up after 4 s). Only a lazurio.account.v1 document counts, and Apps takes only preferences.openApps and favourites keyed by the Organization slug. Until the gateway relays the namespace (404 today) everything stays as it was: favourites in this browser, apps in a new tab. - Where apps open (S18): tiles, the column's favourites, "Otevřít aplikaci" and the lifecycle's "Otevřít" open in a new tab or navigate this window, never in a frame. A workstation opens the new tab within the click, or moves this window only after the start succeeded. - Favourites (S12): with the account they are its list, in its order; the star writes PUT/DELETE /.lazurio/account/favourites/<org slug>/<kind>/<id> at once and puts the favourite back with a short message when the account does not take it. Browser favourites are not uploaded. - "Přístup k modulu" (S15, #151): in a module tile's menu for the Organization's Owners and Stewards, asked when the person reaches for the menu, never for every tile; it opens the Organization's Dashboard page /settings?tab=modules&module=<id> in the same window, without an arrow. The preview script takes a role (owner, steward, member) for its gh answers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Root decision 0185 S8: the person lands in Apps of the Environment they had
open last, and a click on a space returns there; the Dashboard account
remembers it because every Environment has its own origin. The library now
sends PUT /.lazurio/account/last with { environment, app, organization }
(the shell document's current, the app its host names, the space's
Organization slug or null) once per full page load of Apps, Chat and
Automate. Fire and forget: keepalive, its answer not read, silent on
failure, never blocking drawing.
It lives in its own module, src/shell/last.ts, apart from the rail's merge
of the account's Environments; each element calls it with one line, the
column head by its `active` app and the rail only when its host names `app`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… account document F36's addendum gets a note: "Přístup k modulu", the report of the last Environment, favourites in the account and where module apps open are built, each waiting only for the person's account to answer on the Environment's origin; the Dashboard's canonical slug. The shell-as-built section of the Launchpad development guide names the new modules, the Steward route, the account behaviour and the preview's role argument. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ick wins Pablo's review of #159: the optimistic rollback looked only at whether the favourite was shown, so it could not tell a later click on the same favourite apart. Three quick clicks (PUT, DELETE, PUT) with the first PUT refused and the later writes taken removed the star, although the last click and the last successful write starred it. Concurrent writes could also reach the account out of order. Now one favourite has one write under way at a time, sent in the order of the clicks. It keeps what the account last took and what the last click wants: a click made while a write is under way is sent after it, and only if it still differs from what the account holds. A failure is put back, with the short message, only when no later click wants something else; then the favourite shows what the account holds, in its place. Different favourites, and the browser fallback, are unchanged. The tests cover the three quick clicks starring and unstarring, a click undone before its write answers, the last click's failure and its place, and two favourites written independently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ple) So the fixture stays valid whether this PR or #161, whose parser refuses a bare Machine name for a hosted entry, merges first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
514cf9b to
8b02667
Compare
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty APPROVED — exact head 8b02667. The author rebased onto main d2133f8; tree 9d2df9fe472c8c04429f5d8ba706cf2568058a3b is byte-identical to my previously reviewed and tested 514cf9b head (verified in an isolated clone with git diff --quiet). The prior integration-only docs resolution remains intact. The per-favourite write ordering, fail-closed account and maintainer routes, shell identity, and scope have no tree changes. Zero unresolved conversations; no competing reviewer request. New head CI and all provider gates must pass before guarded merge. This is not a release authorization.
|
@immakermatty Exact-head re-approval is posted: #159 (review) on 8b02667. Both Ubuntu and macOS checks are green, with zero unresolved threads, but live GitHub still reports REVIEW_REQUIRED / BLOCKED after the new review. The author, not the reviewer, performed the last force-push (verified in the PR timeline); the reason for the remaining provider review gate is not visible with my repository permissions. I requested @annavesela for an additional independent review. I will not bypass branch protection or merge while the gate remains blocked. Please inspect the effective Organization/repository rule if another eligible approval does not clear it; after any new push, exact-head QA and CI must be repeated. |
#161 made the shell document's `current` the Environment's base host; the two passages describing PUT /.lazurio/account/last now say so and point to the identity of an Environment entry under F37's addendum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty APPROVED — exact head 87fcb1f, based on main d2133f8. The author-only change from previously reviewed 8b02667 clarifies that the account last-Environment payload uses the shell current base host, consistent with merged #161. In an isolated checkout: lint and check:public pass; 58 targeted account/shell/Launchpad tests pass. Zero unresolved conversations and no competing reviewer request at submission. Ubuntu/macOS CI is still running; do not merge until the live exact-head checks and all provider gates pass.
Plan DEV-6639, workstream WS-E of the follow-ups of root decision 0185. Refs #148, #151, #152; fixes #158. Built on F37 (#149) and its addendum of 2026-10-04 (the account namespace
/.lazurio/account/…); the Dashboard side is HumanAndMachine-ai/Dashboard#184, #185, #194 (account API, setting, landing) and #186 (the module access page).Why
Decision 0185 moves four things of Apps into the person's Lazurio account, because every Environment has its own origin and a browser's
localStoragecannot follow the person:The Dashboard serves the account and the Environment's gateway relays it (other workstreams). This PR is the Platform's consumer side, built so that it works the day the relay goes live and changes nothing before.
What changes
The account document (
src/launchpad/account.ts). Apps readsGET /.lazurio/account/environmentsonce per page load: same origin,credentials: "same-origin", no token, no redirect followed, given up after 4 s. Onlyschema: "lazurio.account.v1"counts. Apps takespreferences.openApps("same"; anything else is"tab") andfavouriteskeyed by the Organization slug, and ignores everything else (the rail's merge reads it).Where apps open (S18,
src/launchpad/app-opening.ts). These follow the setting:"tab" opens a new tab, as today. "same" navigates this window to the app's own address. Nothing is ever framed. On a workstation the start-then-open flow keeps working in both modes: the tab is opened within the click, or this window moves only after the start succeeded. The new-tab arrow shows only with "tab".
Favourites (S12). With the account, an Organization's favourites are its list, in its order, first in their section with the star as before. The star writes
PUT/DELETE /.lazurio/account/favourites/<org slug>/<module|repository>/<id>at once (optimistic). One favourite has one write under way at a time, sent in the order of the clicks (after Pablo's review, commit 387fb87):localStoragefavourites are not uploaded.localStoragestays only as the fallback without the account, and for the Personalspace group, which is no Organization.The last Environment (S8,
src/shell/last.ts, its own module in the library). It sendsPUT /.lazurio/account/lastwith{ environment, app, organization }once per full page load of Apps, Chat and Automate:environmentis the shell document'scurrent;appis the app the host names;organizationis the space's Organization slug, or null.It uses
keepalive, does not read the answer, is silent on failure and never blocks drawing.elements.tscalls it with one line per element: the column head byactive, the rail only when its host setsapp. The rail/column-head merge code is untouched."Přístup k modulu" (S15, Apps tile menu: "Přístup k modulu" needs the Dashboard's page for Team access to one module #151). It appears in a module tile's "⋯" menu for:
GET /api/organizations/<org>/modules/<module>/maintain. It readsgh api repos/<owner>/<repo>→permissions.maintainthrough the same server-side path as the Owner check (sharedaskGitHub). It is bounded by the same timeout, cached five minutes per repository, asks one question per repository at a time, and fails closed. It is never asked on a Team Environment, without a bound login, without a declared repository, or for a repository outside the Organization's login.The item opens
https://dashboard.lazurio.ai/orgs/<dashboard slug>/settings?tab=modules&module=<module id>in the same window, without an arrow. Repository tiles and the Personalspace group never have it.The module's repository. The catalog now carries it as
url, read from the slot'sgit.url, the same way as a production repository's.The Dashboard origin and Organization slug (Shell document: an Organization's Dashboard link uses the manifest slug as written, so it hits the Dashboard's not-found page #158). The Platform knows the Dashboard origin as the constant
https://dashboard.lazurio.ai/(shell-document.ts, as for the rail's logo and account). It knows the Organization's page from the shell document'sorganizations[].dashboard./orgs/<slug>exactly against its canonical slug (canonicalSlug: lowercase, other runs →-, from the same manifest slug). The producer used the slug as written. So the picker's Organization head already led to the Dashboard's not-found page for every Organization whose slug has capitals, which covers most real ones.dashboardSlug()follows the Dashboard's rule, and the access item builds on it.--nsuffix for two Organizations that reduce to one slug cannot be known here. Such a link ends on its not-found page and never on another Organization's page. The item is absent whenever the shell document has no…/orgs/<slug>page (fail closed).Preview.
scripts/preview-launchpad.ts … [owner|steward|member]answersghby role, and its workspace modules declare repositories.Docs. The F36 addendum gets a "built behind the person's account" note, and the shell-as-built section of
docs/launchpad-development.mdis updated.What does not change
main: favourites inlocalStorage, apps in a new tab.lazurio.shell.v1, the elements' interface (Shell: the elements' interface v1 is a promise to the forks (F36 addendum, DEV-6639) #155) and the rail's merge of the account's Environments (owned by another session) are unchanged.newModuleTileandhandOver(WS-D) are untouched.Verified
Unit and HTTP tests (new):
tests/account.test.ts: the document valid, another schema, odd members, 404/401/502/HTML/network error → null, a 4 s-style timeout → null, write paths, writes, optimistic writes and rollback, and the same-favourite ordering (three quick clicks starring and unstarring with the first write refused, a click undone before its write answers, the last click's failure and its place, two favourites written independently).tests/app-opening.test.ts: both modes, including the workstation's start: the tab opened within the click, closed on failure or when blocked; "same" moves only after the start.tests/shell-last.test.ts: the body, once per load, no report without an app, silent on rejection and throw, and the default transport is a same-originPUTwithkeepalive.tests/module-maintainer.test.ts: maintain true and cached, one question at a time, and no for no maintain, a refusal, bad JSON or a timeout; no call on a Team Environment, without a login, without a repository, or for another Organization's repository.tests/launchpad-shell-routes.test.ts: the new route's admission locally and hosted, and an end-to-end answer from a real fixture Folder, including the catalog'surl.tests/apps-view.test.ts: the item's target and its absence.tests/shell.test.ts: the Dashboard's slug.Checks on head 387fb87, rebased on
main857438f (Folder: agents send the Operator to the Launchpad for the GitHub sign-in and for Composio (F19 addendum, base-instructions-20) #157):bun run check: lint and typecheck green;bun test1265 pass, 7 skip, 1 fail.tests/folder-prepare-change.test.ts"shared update holds exclusion across preparation, activation and finalization". It hung for 423 s and timed out while the machine was loaded by parallel sessions (load average about 6). Rerun alone it passes (47 pass, 0 fail). It has nothing to do with this change.ready_to_push.tests/install-script.test.tsfailed during a run while the machine's disk was nearly full, and also on a cleanorigin/maincheckout; it passed in the later green runs.Browser (decision 0178). Chrome via Playwright against the hosted preview (cs), with the account relay stood in by intercepting
/.lazurio/account/*, and against the local preview:localStoragefavourites, tiles withtarget=_blank;target, the click navigates the same page, no arrow in the column;PUT …/favourites/example/module/knowledgebase; a refusedDELETE→ the favourite back plus the message;PUT(502), thenPUT(204). The star stays and no message shows;PUT /.lazurio/account/lastper page load,{ environment, app: "apps", organization: "example" };maintain;targetand no arrow, and its click navigates the same page to…/orgs/example/settings?tab=modules&module=deals;The screenshots stay outside the repository.
Risks and follow-ups
PUT lastsends the shell document'scurrentasenvironment. Shell: an Environment's id is its base host, unique across Organizations (F37 addendum, DEV-6639) #161 makes that id the Environment's base host (<machine>.<org>, or the personal slug), unique across Organizations. This PR sends it with no change to its code. The Dashboard must derive the same value (Dashboard Reader role for installing an Organization; a read-only repository gets a proposal issue (F9 and F14 addenda, base-instructions-28) #198).slug(else the path's last segment). The Dashboard's adapter takes amodule_slotsentry's id from the path's basename (a shape-Bmodules[].slugwins). They agree for the module tiles today, but WS-C should resolvemodule=by the Lazurio module id./.lazurio/account/environments(twoGETs per page load of Apps). Reading once and handing it over, asprovideShelldoes for the shell document, is a small follow-up for whoever lands second.lazurio-accountscope falls back silently until its next sign-in.🤖 Generated with Claude Code