Repository navigation
feat(accounts,frontend): installed access follows pages, a failed install retries in place, refusals and module actors read in words - #1164
Closed
antoinetoussaint-byte wants to merge 2 commits into
Conversation
…tall retries in place, refusals and module actors read in words The Modules & solutions page showed "No team" and "Grant a team" on every installed module, which reads as if every module needs people granted to it, and a failed installation offered only a bare "Retry" beside "Unavailable" and "Available after activation". - accounts: AvailableSolution.has_pages says whether the applied generation declares pages, read from the registration's frontend half (the record the navigation is built from), never from the kind. It rides on the installed rows through OrganizationInstallation.target. - accounts: the installation RPC error mappers answer with the carried status's own message (innerStatus), so a refusal no longer reads as "cannot grant scope: rpc error: code = ... desc = ...". - accounts: QueryAuditLog names a module acting on its own principal (AuditEvent.actor_module, the prefix the module principal registry declares it under) at read time; nothing is stored on the row. - frontend: the Teams column becomes Access; "Grant a team" becomes "Grant access" and the dialog asks for a holder and an access level (team and role today), so a member holder or a level ladder adds a field rather than a new shape (#1162). A row with pages and no grant says "No one has access yet"; a row without pages drops "No team" and shows one muted line saying when a grant still matters, with the action kept but secondary, because a solution may reach that module on a person's own session and the host cannot see that consumption yet (#1163). - frontend: a failed installation shows "Retry installation" as the primary action with a line saying nothing needs uninstalling; Health reads "Not running" and Access "Available once the installation succeeds". - frontend: Recent activity and the audit table name a module actor "Module <name>". - Regenerated: Go and TS bindings, OpenAPI, contracts, the package manifest and the SDK's vendored contract. AuditEvent is on @codefly-dev/saas-sdk's published surface; the unreleased 0.3.32 already on main carries it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
antoinetoussaint-byte
force-pushed
the
fix/installed-access-follows-pages
branch
from
October 18, 2026 19:26
a5d42d2 to
b1150ee
Compare
…ion dashboard names module actors too (#1164 review) - The has_pages doc comment claimed a catalogue offers a grant only where it is true; the page keeps access on headless rows because a solution may call them on a person's own session. The comment now says it reports pages only. Regenerated bindings, OpenAPI, contracts and the SDK's vendored contract. - The solution dashboard's recent events carry actorModule through newestEvents, so a module acting on its own reads "Module <name>" there as it does in Recent activity and the audit table. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
antoinetoussaint-byte
enabled auto-merge
October 18, 2026 19:40
Contributor
Author
|
Superseded in part by #1248 (a7b16db, refusals in words) and in part by the authority's installation-owned role scopes (codefly-dev/authority#7) — re-cut has_pages / retry UX on the new model if still wanted. |
auto-merge was automatically disabled
October 26, 2026 18:52
Pull request was closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What we are trying to do
An organization administrator opening Admin → Modules & solutions should see, for each installation, whether people need access to it, and should be able to recover a failed installation without uninstalling it.
Before → after
Installed table, a module with no pages (e.g. a records or tracing module)
Installed table, an installation with pages (a solution today, a module with pages tomorrow)
Failed installation
RetryInstallation) before "Uninstall". Pending rows read "Not running yet" / "Available after activation".Refusals: a host refusal on these RPCs now reads in words ("role "r" is not a role in this org") instead of
cannot grant scope: rpc error: code = FailedPrecondition desc = ….Recent activity / audit table: a module acting on its own principal reads "Module " instead of "Actor unavailable".
Why access is not hidden on headless rows
Access is keyed on pages, not on kind (a module may get pages later). But a solution can also call a module on the person's own session (no minted capability), and the host then admits that person only through a grant on the module's installation. The delivered manifest does not record that session consumption today (it carries only audience-bound bindings), so the host cannot tell which headless modules a person reaches. Hiding the action would break such a call; the page therefore keeps it, secondary, with the muted explanation. Closing that gap: #1163 (needs a handbook proposal: it moves the manifest contract).
The grant affordance is named "Grant access" and the dialog asks for a holder and an access level (team + role today) so per-member grants and read/write levels add a field, not a new shape: #1162 (also proposal-first).
Changes
AvailableSolution.has_pages(field 10), from the registration's frontend half in the catalogue statement (r.frontend_revision IS NOT NULL), carried on installed rows viaOrganizationInstallation.target.AuditEvent.actor_module(field 16), set inQueryAuditLogfrom the module principal registry at read time.mapInstallationError/mapInstallationExposureErroranswer with the carried status's own message via the existinginnerStatushelper.solution-installationsmodel (PageReach,HEADLESS_ACCESS_NOTE), page and grant dialog wording;resolveActor(actorId, directory, actorModule)used by the activity feed and the audit table.module/contracts,module.package.codefly.yaml, SDK vendored contract + bindings.AuditEventis on@codefly-dev/saas-sdk's published surface; main's unreleased 0.3.32 (since v0.0.101) already covers it, andkit-version checkpasses.module/SOLUTION_REGISTRATION.md,module/services/frontend/AGENTS.md,module/services/accounts/AGENTS.md.Reuse
Reused: the existing
RetryInstallationRPC and mutation (only relabelled and promoted), the registration's frontend half (the same fact navigation uses), the module principal registry (Service.ModulePrincipals), the adapters'innerStatushelper,GrantInstallationToTeam/RevokeInstallationFromTeamunchanged. Deliberately not done: no new grant RPC, no inference from kind or names, no synthetic principal-directory rows for modules (the directory stays stored identities only).Classification
Fix at the owner for each behaviour: the pages fact and module actor name come from accounts; the wrapped-status text is fixed in accounts' mappers rather than stripped in the browser. The headless-row explanation is an interim presentation until #1163 lets the host compute person reach; labelled as such in the code comment and docs.
Module playground / story
No new shared kit component, so no kit story. The admin page itself is where a person exercises this; the container tests drive it with the host's wire shapes.
Independent review
One fresh-context review round on the rebased head (b1150ee): merge with follow-ups, no blocker. Dispositions:
has_pagesdoc comment said a grant is offered only where it is true, contradicting the page: fixed (comment reports pages only; regenerated).actorModulethreaded throughnewestEvents).callerFacingRefusal(R1019-N10) would log and replace it: follow-up, not changed here. This PR strictly reduces exposure (before, the whole chain text was returned, inner message included), and several install-pathUnavailablestatuses carry reasons an administrator acts on (registry stale, envelope revision), so replacing them with a fixed phrase needs its own decision about which are refusals and which are failures.Verification
go test ./pkg/adapters(accounts) — includes the updated error-mapping tests andTestAuditActorModuleNamesOnlyADeclaredModulePrincipal.go test ./pkg/infra(accounts, real Postgres via Codefly) — includesTestAvailableSolutionTargetReportsDeclaredPages.go test ./...inmodule/tools;codefly generate contracts saas-starter --check,codefly generate runnables saas-starter --check; a no-change proto regeneration was clean before the edit.vitest— solution-installations (61), audit, activity-feed pass; full run 4809 pass, 4 fail inonboarding/*.pipeline.test.ts, which need a running Codefly graph ("Codefly did not provide the frontend gateway context") — not run here.tsc --noEmit,eslinton the touched trees,node scripts/ci/kit-version.mjs check, naming gate,scripts/check-boundaries.sh.Not verified: a live
codefly runof the page, and the business DB suite (go test ./pkg/business) beyond what CI runs. Rebased on main after #1160 (store pin) merged; all generated artifacts regenerated on the merged tree, not merged by hand.🤖 Generated with Claude Code