Skip to content

Launchpad home is the catalog: organization list, module list, POST /api/catalog; execution admission variant B (H1 decided) - #68

Merged
immakermatty merged 13 commits into
mainfrom
claude/DEV-6628-catalog
Sep 28, 2026
Merged

immakermatty merged 13 commits into
mainfrom
claude/DEV-6628-catalog

Conversation

@immakermatty

@immakermatty immakermatty commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Why

The Platform Launchpad is to replace the resident Launchpad on hosted Machines (root decision 0167, parity shaping #65). Its home today is a developer form with a fixture banner; it knows no Organizations and no modules. The resident's home is the catalog: every Organization under <Folder>/organizations/ and its workspace modules, grouped by Team, discovered by scanning, never from an allowlist. Slice P4 of the parity program gives the Platform that catalog, for people and for agents.

What changes

  • One core, readFolderCatalog (src/organizations/catalog.ts): every directory in <Folder>/organizations/ is a candidate, resolved by the canonical reader (read-applications, root-resolution); no allowlist, no planned slots, no launchpad.gen3*.json, no state, recomputed on every read. A candidate that cannot be read is isolated with a typed reason (canonical-documents-required, organization-conflict, organization-not-executable, template-not-runtime, organization-changed, organization-unavailable, organization-duplicate) and never breaks the list. Per module: Teams (N:M), apps, default app, root state, executable or a typed reason.
  • Teams as the resident reads them: canonical module_slots[].teams; without it the legacy alias (workspaces, then singular workspace) for compatibility; nothing declared means the default Team workspace (decision 0041). teamsSource says which. A malformed membership is teams-invalid on the module, never a block.
  • lazurio organization list [--json], lazurio module list [<org>] [--json] and POST /api/catalog answer the same catalog (tests prove CLI and HTTP output equal). Terminal columns escape control characters.
  • Launchpad home is the catalog in the T3 Code sidebar pattern: / all Organizations and modules, /o/<org> one Organization, /o/<org>/<module> one module; Settings keep their frame. The developer form and its "Development fixture only" banner are gone.
  • Execution admission, one rule (isExecutableOrganizationState, root-resolution.ts): question H1 was decided by the Principal on 2026-09-28 (F22 point 1) — variant B: canonical-only current Organizations run applications too; legacy, projection_drift, conflict, missing never do. Variant A stays one constant away for the record; tests cover both.
  • Docs: launchpad-development.md (catalog home, Teams), organization-contract.md (admission decided), module-adoption.md.

What deliberately does NOT change

No module is started, stopped or ensured from the catalog (that is P5/P6); no lease, no provider permission, no readiness is implied by executable. Organization sync is not implemented. The manifest schema is unchanged: the legacy alias is read, not written.

Verified

  • Author's read-through of catalog.ts, routes and admission against the parity shaping B1 and the H1 decision.
  • bun run check on the final head 7fba800 by the author on macOS: lint, typecheck, 773 tests pass (0 fail), check:public, build:proof, smoke:proof — exit 0; the slice's own suite tests/organization-catalog.test.ts (fixture with current, transition, conflict, duplicate slug, legacy alias Organizations), catalog-view, routes and hosted tests.

Review round 2026-09-28 (Pablo, head ab1e4c2 → 88adfef)

  • Duplicate slug on the Launchpad route: fixed — one shared pure rule selectCatalogOrganization (src/organizations/catalog-selection.ts) for the CLI and the page; an ambiguous slug (same case or case-folded) selects nothing, /o/<slug> shows the duplicate isolation with every candidate, and links use only a key that selects exactly one candidate (slug, else directory name, else no link). Tests for same-case and case-folded duplicates; page and CLI agree.
  • F12 admission still described as pending: fixed — docs/decisions.md F12 carries a dated addendum (superseded by the Principal's H1 decision, historical text labelled), docs/organization-contract.md "Exit from transition-only admission" is a labelled historical record, ARCHITECTURE.md says both transition and canonical-only current execute.
  • Hidden directories under organizations/: objection, not a change — the resident's discovery glob organizations/* never matched dot-entries, so they were never candidates; the exception is now stated explicitly in the catalog comment and docs/launchpad-development.md.
  • Author's bun run check on 88adfef: 795 pass, 0 fail, exit 0.

Risks / follow-ups

  • An Organization without declared Teams now shows a workspace group (as the resident does).
  • The legacy root's manifest compiler resolves an empty workspaces array and a default: true Team slightly differently; the catalog follows the runtime rule the resident Launchpad groups by. Recorded in the docs.

🤖 Generated with Claude Code

immakermatty and others added 11 commits September 28, 2026 13:42
…-only current executes)

The admission of resolved Organization roots lives in one constant of
root-resolution. Variant A keeps F12's transition-only gate; variant B, the
recommendation of the Launchpad parity shaping (proposed F22 point 1,
question H1, pending the Principal's answer), also executes a canonical-only
current root. Tests cover both variants of the pure rule and ask the rule
wherever the default matters, so flipping it is one line.

The observation of an Organization's applications is also available with
the canonical and inventory documents it was made from, for the catalog.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…T /api/catalog

Every directory in <Folder>/organizations/ is one candidate, resolved by the
canonical reader; a candidate that cannot be read, a template and a
duplicated slug are isolated with a typed reason and never break the list.
Per module: Organization slug, module id, apps and default app, Teams from
module_slots[].teams (N:M), root state and executable with a typed reason.
Nothing is written; the catalog is recomputed on every read.

The CLI finds the Folder with --folder, otherwise through the same lookup as
lazurio update (the supervised unit's [X-Lazurio] Folder=, then the hosted
operator's), now one shared function. The Launchpad route answers the same
catalog behind the same admission as every other route; tests compare the
two.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… sidebar pattern

The developer form and its "Development fixture only" banner leave the home
page. The sidebar lists Organizations as groups and modules as rows with a
status dot, a subheader per Team (a module of two Teams under both); routes
/, /o/<org> and /o/<org>/<module> work like the settings routes: deep links,
back and forward, focus on the heading, the breadcrumb, the narrow sheet,
light and dark, Czech and English. A module shows its name, Teams, default
app and whether it can run or why not; the place of its primary action stays
empty until the module lifecycle (P5).

The application API (/api/apps/*) and app-request stay unchanged for their
tests; the optional browser harness now drives them over the API.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ation API until P5

launchpad-development.md describes the Launchpad home as the catalog: the
core, CLI, HTTP route, routes, sidebar, what a module row shows and what the
next slice brings. organization-contract.md states the one admission rule
with its two variants and the default B as proposed, pending the
Principal's answer. module-adoption.md notes that the form left the page
while its API stays.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A slug from an Organization repository's lazurio.organization.json or a
directory name under organizations/ could send escape sequences and
newlines to the operator's terminal: hide columns, break the alignment
and forge an "executable" row. The human output of organization list and
module list now prints control, line and bidirectional formatting
characters as a visible \u{...} escape (a backslash doubled). JSON output
and the page were already safe and are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The start/prepare boundary in local-application-adapters still said a
canonical-only current root throws; it now points to the one admission
rule and its variants. docs/module-adoption.md no longer says the page
exposes the application controls or that the API serves them: the page's
form is gone since slice P4 and the operations stay reachable through
the API until P5.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Team membership of a module now resolves in the resident read model's
order (organizationSlotTeams in the legacy root): module_slots[].teams,
otherwise the legacy alias workspaces, then the singular workspace,
otherwise the default Team workspace. Each module records teamsSource
(teams | legacy-alias | default); the CLI tables and the Organization
page name the legacy alias once per Organization to help migrate its
manifest. The fixture Folder gains an Organization with both alias forms
and a slot without any; CLI and HTTP still answer the same catalog.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The catalog slice shipped the admission rule with variant B as a proposal
pending the Principal's answer. The answer came the same day: yes. The
comment and the two documents now state the decision instead of a pending
question; the constant and the tests are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@immakermatty
immakermatty marked this pull request as ready for review September 28, 2026 13:09

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@immakermatty Exact-head review of ab1e4c2 — changes requested. The two required platform checks are green on this SHA; focused local validation: 37 tests / 0 failures, Biome lint and TypeScript typecheck pass. CLI JSON and POST /api/catalog equality, read-only catalog call path, terminal control-character escaping and the central variant-B admission gate are confirmed. No merge performed.

  1. [P1] Duplicate slug is not isolated on the Launchpad route (src/launchpad/catalog-view.ts:130-136, catalog-panel.ts:214-220,288-319). isolateDuplicates correctly blocks both candidates, and CLI findCatalogOrganization refuses the slug, but routeOrganization chooses the first exact match even when two candidates declare the same slug. Reproduction with two entries whose organization is alpha: CLI lookup returns undefined while /o/alpha renders the first candidate; both sidebar links also point to the same route, and /o/alpha/<module> can show the wrong candidate. Refuse any slug with more than one matching candidate in route selection, and test both same-case and case-folded duplicates.

  2. [P2] Discovery silently excludes hidden directory candidates (src/organizations/catalog.ts:324-332). B1 and this PR explicitly require every directory under <Folder>/organizations/ as a candidate, with a typed failure if unreadable; the fixture deliberately creates .cache but asserts it is absent. Include hidden directories as blocked/unreadable candidates under the same isolation rule, or explicitly revise the agreed scope if hidden names are an exception.

  3. [P2] H1 is still presented as a pending exit gate in the authoritative docs. docs/organization-contract.md:89-99 says current becomes executable only after an upstream identity proof and Until then nothing changes, while this head already executes current. docs/decisions.md:194,555-562 still states transition-only admission as the live direction and not implemented. Mark the F12 admission gate superseded by the Principal's 2026-09-28 H1 decision; retain historical text only under an unmistakable historical label, not as current normative guidance.

Please push a new head for another exact-head review; do not inherit this SHA's checks or verdict.

@immakermatty

Copy link
Copy Markdown
Contributor Author

@agentrozjedemeai on finding 2 (hidden directories as candidates), an objection rather than a change: the purpose of B1 is parity with the resident's discovery, and the resident discovers Organizations by the shell glob organizations/*/company.gen3.json (legacy root discovery-lib.mjs), which never matches a dot-entry — .cache, .git, .DS_Store and editor folders under organizations/ have never been candidates and were never listed. Listing them as blocked candidates would add noise rows for what is the normal case, and "every directory" in B1 was written with that glob in mind. The next head states the exception explicitly (one sentence in the catalog comment and in docs/launchpad-development.md) and keeps the fixture assertion. Findings 1 and 3 are real and will be fixed in the same head. Please give your verdict on finding 2 as documented, not by inclusion.

…uperseded

- One pure rule, selectCatalogOrganization (src/organizations/catalog-selection.ts),
  serves the CLI and the Launchpad page: slug case-insensitively, an ambiguous
  slug (same case or case-folded) selects nothing, otherwise the exact directory
  name. /o/<ambiguous slug> and its module routes show the duplicate isolation
  with every candidate; the sidebar and the home link a candidate only by the
  name that selects exactly it (slug, else directory), otherwise not at all.
- Hidden entries under organizations/ stay excluded, now stated as parity with
  the resident's glob organizations/* in the reader comment and the docs.
- F12's transition-only admission is recorded as superseded by the Principal's
  2026-09-28 H1 decision (F22 point 1): dated addendum in decisions.md, the
  summary row, the organization contract section as a labelled historical
  record, and the ARCHITECTURE.md sentence that still called it today's gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@agentrozjedemeai agentrozjedemeai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@immakermatty Re-review of exact head 88adfef: APPROVED. Finding 1: CLI and page now share the pure slug/directory selection rule; duplicate slugs (same-case or case-folded) select no candidate, and links exist only for unambiguous keys. Finding 2: accepted as documented parity with the resident organizations/* glob; hidden dot-entries were never candidates, and the exclusion is explicit in the reader and Launchpad development contract (root decision 0163). Finding 3: F12 transition-only admission is clearly labeled historical/superseded in the decision and Organization contract, and ARCHITECTURE.md names the current variant-B rule. Local focused tests 20 pass; lint and typecheck pass. Broad local check encountered an unrelated 5-second install-script test timeout under host contention (794 pass, 1 fail, 4 skip); its isolated rerun with a 30-second timeout passed 10/10. Public guard, proof build and smoke passed. Both required Platform checks (ubuntu-24.04 and macos-14) are SUCCESS on this SHA; zero unresolved threads and no pending review requests. No merge performed.

@immakermatty
immakermatty merged commit 0c104cf into main Sep 28, 2026
3 checks passed
@immakermatty
immakermatty deleted the claude/DEV-6628-catalog branch September 28, 2026 13:46
immakermatty added a commit that referenced this pull request Oct 26, 2026
…nks "bot <Name>" only to it (base-instructions-78, DEV-6676)

The Organization Admin asked on 2026-10-26 that Buddy name a bot as "bot <Name>", ideally linked so that a click opens the bot in MausBot and the person sees how it works. The previous commit has the word. The Lazurio fork of MausBot now has the address the link waited for: /c/<threadId> on an Environment's MausBot origin opens that conversation (Lazurio/OpenMausBot#67, its pull request #68).

Delegace builds the link from the threadId that `openmausbot run --wait none --json` prints and the MausBot origin of the Environment where the bot runs, as that Environment declares it, never from names. Here that is the machine binding's mausbotOrigin, which the Folder records from the handover, read only from a regular file of the operator that nobody else may write. In another Environment it is entry.mausbot.external_origin of its own handover, read with `ssh <environment> lazurio machine inspect`, which prints JSON and takes no option. zadej reads it once, after the bot has started, and records it as the optional odkaz (still verze 1). Any other shape, or anything unreadable, gives no link and never fails a running bot.

The link appears in each output:
- zadej prints {id, threadId, termin, odkaz};
- the notice in the chat has "Odkaz na bota: <odkaz>" on a line of its own;
- the Telegram line ends with it when it fits whole in the 200 characters Hermes delivers;
- vysledek prints it before the bot's words, and seznam lists it.

Buddy's rule changes from "no link" to a Markdown link to exactly the odkaz Delegace gives, never one he puts together or takes from a bot's words. The skill lazurio-buddy-pomocnici shows it with and without the link. The #612 rules stay.

Template revision base-instructions-78: every Folder re-renders, and the digest of Buddy's layer changes, so F64's addendum refreshes his stored prompts. F14 gains the addendum. The link opens the conversation once an Environment runs the MausBot release with the address; until then it opens MausBot's home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants