docs(teams): phase 3 — Teams is a contract, not a surface #156

Merged
whitlocktech merged 2 commits from docs/teams-phase3 into edge 2026-08-18 02:09:34 +00:00

2 Commits

Author SHA1 Message Date
d78cc99c80 docs(teams): Teams is a contract, not a surface — record the correction
The org lead's correction to Part 3, and the inverted extension-slot direction
it forces.

TEAMS.md: §3.1's routes, §3.4's two slots and §3.5's three nav entries are all
marked superseded in place, and Part 12's phase 3 entry gains the amendment
explaining why — core does not own the word for a Team, so the module that owns
the vocabulary owns the page. The five corrections found by building are kept
alongside it.

MODULE_API.md: 1.6.0's list swaps the two client slots for
registry.declareModuleSlot + Slot in the UI kit, and a new §3.7a documents the
inverted direction: what forced it, the enforced namespace, why core's fills are
applied at mount rather than eagerly, and why a fill for an undeclared slot is a
no-op where §3.7's unknown slot throws.

BACKEND_DESIGN.md: the by-external-id lookup route.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 20:58:40 -05:00
fd9c02130c docs(teams): Team pages and the activity feed, and what phase 3 disproved
TEAMS.md gains a dated amendment on phase 3 with five corrections, all found by
building the thing it describes:

  - §3.2 and §3.4 contradict each other about `team.member.row`'s props, and
    §3.2 wins because it is the security rule. A client slot can only receive
    what the browser was sent, so §3.4's `{ memberKey, userId, displayName }`
    means publishing both identifiers in every public roster, module installed
    or not. The slot is redeclared with what core can honestly supply.
  - §3.3's projection is an EIGHTH MODULE_API member where 1.6.0 listed seven.
    Settled by the org lead: 1.6.0 is amended in place, on the rule Protocol 4
    was given in phase 2 — a contract owes a bump only once it has reached
    `main`.
  - "the module declines" needed splitting in two before it could be built. No
    module at all withholds nothing and must serve the roster whole; a module
    whose rungs could not be consulted must serve none of it. Only the second
    fails closed, or bare core shows an empty roster on every Team page.
  - the module answers with member KEYS, not rows, so it can narrow what is
    published and cannot widen it.
  - core's five activity kinds are four until the forum lands, and a Team's
    FIRST roster emits no join items at all.

§2.11's route table gains the activity endpoint it never had, and MODULE_API.md
documents `projectRoster`, the inverted fail-closed semantics that make it
different from every other provider call, and `ctx.teams.activity.push`'s item
shape and its four contractual properties.

BACKEND_DESIGN.md: the seventh Team table, its retention, and the three public
routes' new behaviour — `enabled` on the index, the slot props on the single
Team, the per-caller row projection on the roster, and the feed.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-17 20:17:05 -05:00