Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions cmd/add/solution_documents.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,14 +418,23 @@ func solutionContract(name string) *modulecontract.Contract {
ResourceKind: name + ".page",
Actions: []string{readAction, writeAction},
}},
// installer / editor / viewer, the standard set — the same three wiki
// declares, and now every solution in the fleet.
//
// `installer` is required BY NAME: the authority refuses a solution
// without it. `viewer` is what the organization is installed as, so
// the people of an installation can open the solution at all —
// without a second role only the owner holds anything and everyone
// else is refused by name. `editor` is the write position between
// them, so a solution that grows one does not have to invent a name
// for it; proposals calls its middle role `reviewer`, which is the
// same position in its own domain's word.
//
// Every role must grant something: core refuses `role "installer"
// grants nothing`.
Roles: []modulecontract.Role{
{Name: modulecontract.InstallerRole, Scopes: ownScope},
// The role the ORGANIZATION is installed as, so the people of an
// installation can open the solution at all. Without a role
// besides installer only the owner holds anything, and everyone
// else is refused by name — "<person> holds no role on <name>" —
// which is a correct refusal and a useless scaffold. wiki and
// proposals both declare a viewer beside their installer.
{Name: "editor", Scopes: ownScope},
{Name: "viewer", Scopes: []modulecontract.CeilingScope{{
ResourceKind: name + ".page",
Actions: []string{readAction},
Expand Down
4 changes: 2 additions & 2 deletions cmd/add/solution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ func TestTheContractDeclaresARoleBesidesInstaller(t *testing.T) {
for index := range contract.Roles {
names = append(names, contract.Roles[index].Name)
}
if !slices.Contains(names, "installer") || !slices.Contains(names, "viewer") {
t.Fatalf("the contract must declare installer and viewer, got %v", names)
if !slices.Equal(names, []string{"installer", "editor", "viewer"}) {
t.Fatalf("the contract must declare the standard set installer/editor/viewer, got %v", names)
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2425,7 +2425,7 @@ What it creates:
| `services/backend` | the entry service: presents the solution's identity, serves the API the page calls, and is the workload a host installs |
| `services/web` | the shell that serves the page where no host shell mounts it — not published, because a host that federates the remote needs no shell. It **mounts the solution's own `./Page`**, the same module a host federates, and its generic login/signup routes are removed: a solution has no sign-in of its own, the authority's edge signs the person in |
| `solution.codefly.yaml` | what the solution exposes, and the route name it addresses each consumed module by |
| `module.contract.codefly.yaml` | the principal its credentials are issued to, with `owner_aware: true`, the solution's own `scope_ceilings`, and the **installer role** — the authority refuses to admit a solution that offers a person no role to hold on it |
| `module.contract.codefly.yaml` | the principal its credentials are issued to, with `owner_aware: true`, the solution's own `scope_ceilings`, and the standard roles **installer / editor / viewer** — the same three wiki declares. The authority requires `installer` by name and refuses a solution without it |
| `module.package.codefly.yaml` | the published identity; without it the render declares no presence and nobody can install the solution |
| `services/backend/solution.frontend.codefly.yaml` | the page's title, order and `./Page` remote |
| `configurations/local/fixture-composition.yaml` | who, in the development fixture, has this solution **installed**. Without it the authority refuses every capability ("not installed in this organization") and the page can only render its not-installed branch. `teams` is what admits anyone but the owner |
Expand Down
Loading