What does a team invitation feature need to handle?

A team invitation feature owes 17 requirements across five tiers, from “an authorized member can invite” to “every lifecycle event emits an audit record”, and it pulls in 5 other features that have to exist for acceptance to mean anything. Most of it only shows up as a bug report: the expired link that still works, the revoked invite that still joins, the second click that makes two memberships.

The 17 requirements, by tier.

This is the invitation feature from the reviewed SaaS catalog that ships with Closure Engine, quoted as committed. Each line is a requirement the catalog says the feature owes.

The tier says how deep the requirement sits. The marked lines are critical: a passing test is not admissible on its own and must be shown to fail when the behavior is broken.

COLLAB.INVITATION · 3.1.0 · 17 obligationsRecorded · 2026-10-11
  1. T1exists
    1. SEND.001An authorized inviter can create an invitation for an email address, and the system delivers a message containing a single-use acceptance link.
    2. ACCEPT.001A recipient following a valid acceptance link becomes a member of the inviting organization with the role recorded on the invitation.
    3. LIST.001An authorized member can see pending invitations for the organization, including recipient, role, inviter, and expiry.
    4. REVOKE.001An authorized member can revoke a pending invitation, after which its link no longer grants membership.
  2. T2correct
    1. SEND.002An invitation record carries inviter, organization, recipient address, role, token digest, expiry, acceptance, and revocation fields.
    2. SEND.004A created invitation expires ⟨token_ttl_hours⟩ hours after it was created.
    3. SEND.003An inviter may only assign a role at or below their own privilege level.critical · control required
  3. T3robust
    1. ACCEPT.010An acceptance attempt with an expired token is rejected and the recipient is shown a path to request a new invitation.
    2. ACCEPT.011An acceptance attempt with a revoked token is rejected and does not create a membership.
    3. ACCEPT.012An acceptance attempt with an already-accepted token does not create a second membership and does not error the recipient into a dead end.
    4. SEND.010Inviting an address that is already a member of the organization does not create a duplicate pending invitation.
    5. DELIVER.010When delivery of an invitation message hard-bounces, the invitation is marked undeliverable and the inviter can see that it failed.
    6. SEAT.010When accepting an invitation would exceed the organization's seat limit, acceptance is refused and no membership is created.critical · control required
  4. T4secure
    1. TOKEN.020Acceptance tokens are unguessable, stored only as an irreversible digest, and are single use.critical · control required
    2. RACE.020Concurrent acceptance of the same invitation yields exactly one membership.critical · control required
  5. T5observable
    1. OBS.030Invitation creation, delivery outcome, acceptance, and revocation each emit an audit event carrying actor, organization, and target address.
    2. LIFE.030Expired and revoked invitations are retained for the audit window and then purged, and purging does not remove the audit events that reference them.
Quoted from the catalog as committed. Angle brackets name a parameter the product sets; the default link lifetime is 168 hours and the shipped fixture sets 72.

What an invitation pulls in.

The part no checklist on this topic includes is the dependency. One sentence expands to 58 obligations, because the catalog records why.

Each derived feature sits under the feature that justified it, with the catalog’s reason. Seat accounting arrives through the invitation; audit events arrive through seat accounting, because seat changes affect what a customer is charged.

closure plan · 58 obligations from one sentenceRecorded · 2026-10-11
  • COLLAB.INVITATIONselected: “teams can invite people”
    • BILLING.SEAT_ACCOUNTINGseat limits must be enforced against an authoritative count
      • AUDIT.EVENTSseat changes affect what a customer is charged
    • EMAIL.DELIVERYinvitations are delivered out of band and their failures must be observable
    • IDENTITY.ACCOUNTan accepted invitation must bind to an authenticated identity
    • ORG.MEMBERSHIPacceptance creates a membership record
From closure plan on fixtures/example-saas. The counts belong to this catalog and this selection. The full plan

What a tenant policy adds.

A multi-tenant product also carries a tenant-isolation policy. The catalog applies it to every resource an invitation touches.

These obligations join the same capability. Two are critical, which is why a recorded plan for this feature shows more rows than the feature file alone.

POLICY.TENANT_ISOLATION · applied to invitationRecorded · 2026-10-11
  1. ISO.001T1 · existsFor every actor A and tenant T where A is not a member of T, no operation performed by A returns or mutates any invitation owned by T.critical · control required
  2. ISO.002T4 · secureEnumeration of invitation identifiers by an actor outside the owning tenant yields not-found rather than a distinguishable denial.critical · control required
  3. ISO.003T5 · observableCross-tenant access attempts against invitation emit an audit event.
From the same recorded plan; the policy applies to every resource an invitation touches.

How to read the tiers.

Tier 1 is existence. Tier 2 is correctness of the record and the rules. Tier 3 is the failure paths a tired user will hit. Tier 4 is security. Tier 5 is observability.

A product chooses how deep it owes; a side project may stop at tier 2 and a product with customers rarely should. Used as a checklist, the list is a reasonable definition of done. Used with Closure Engine, each line becomes an obligation the engine grades against your tests, hands to your coding agent one at a time, and will not call done until the required ones have evidence.

from a checkout to the first taskAuthored
closure init --repo .
# .closure/selection.yaml
#   concepts:
#     - concept: teams can invite people
closure observe --repo .
closure next --repo .

What this does not establish

This list is what the catalog says an invitation feature owes. It is not a claim that any product satisfies it, and reading it checks nothing. A requirement the catalog does not state, for example a product-specific approval step before an invite is sent, is not here and would need to be authored. The catalog is reviewed and versioned; it is also the work of people, and a line you believe is wrong for your product can be excluded with a recorded reason rather than silently skipped.