Where the mount registration gets its tier vocabulary
Status
Accepted. Supersedes the earlier state in which the registration layer kept a tier list of its own.
Context
The tier vocabulary is defined in exactly one place: the table that turns a tier into ACL lines (Domain/MountAclWriter). The registration layer (Domain/RepoMountRegistry) nevertheless checked the tier it was handed against a second list of its own, three literals long, and replaced any unknown value with the most restrictive private. While there were three tiers, the two lists agreed.
With the fourth tier, team, they drifted apart. The wizard offered team, the ACL was written according to team, and registration silently stored private. The result: the mount record and conf/acl.auth.php described different tiers — on the very screen whose Rules column exists to make that agreement visible.
The same break repeated itself two layers further down, and twice over. The storage layer keeps its own tier list in Model/AdoGitMount, and the visibility badge in the repository browser keeps another in Ui/BrowseView. Neither was extended when showcase and library arrived, and both silently substitute private for a tier they do not know rather than reporting it. After 53 namespaces were re-tiered, the storage layer therefore READ every one of them as private while conf/acl.auth.php correctly granted library — and saving anything from the mount screen would have written private back, closing publicly readable source without anyone touching a tier.
Mechanism
Registration now asks the table that writes the rules for its vocabulary instead of keeping a copy of it:
if (!MountAclWriter::isValidTier($tier)) { $tier = 'private'; }
The clamp to private stays: a tier this installation does not know must never grant more than the most restrictive one. Only the source of “known” has moved.
A regression test iterates over MountAclWriter::tiers() and asserts that every tier named there reaches storage unchanged. A fifth tier added there and forgotten here fails the test instead of disappearing silently.
Consequences
- Never give registration a tier list of its own again — not even “just to be safe”. Two lists of the same vocabulary drift apart, and the break is silent.
- Do not rewrite the regression test against fixed tier names. Its value lies in asking the table rather than its copy.
- Falling back to the most restrictive value is right; falling back silently is not. All three copies substituted an unknown tier without a word. The fallback protects, the silence hides: in operation a silently substituted value is indistinguishable from a correctly read one.
- The vocabulary sits in four places, three of which are copies. The source is the table that writes the rules. The schema constraint, the storage model and the visibility badge either ask it or are checked against it — one test compares schema and model in both directions, because a one-sided check would leave the other gap open.
teammounts registered before this change are still stored wrongly. They readprivatein the list while their rules matchteam. The correction is a one-off: chooseteamin the row menu and Save. Existing data does not migrate by itself, because nothing can tell reliably whether a storedprivatewas intended at the time or forced.- A new tier needs one entry in
MountAclWriter::TIERS. The wizard, the row menu, the tier matrix and the registration all read from there.
Related topics
- Technical reference: visibility tier – the tier table itself
- Diagnostics: an old mount reads private – the symptom on existing data
- Tutorial: visibility tier – the tier from the user's side