Gap analysis of docs/architecture.md against openspec/ and docs/ideas/ found the envisioned-but-uncaptured remainder. This commit captures it: New OpenSpec change (validated): - route-federation — the collaboration half of the federation vision: routes as dereferenceable trails:Route objects, Create/Update fan-out, Invite/Accept collaboration mirroring (arch decision #2), cross-instance Planner edits via HTTP-Signature-requested scoped tokens (decisions #3/#12), mirror sync healing (#16). Depends on social-federation §6 + route-sharing; carries the 2026-06-07 soak lessons as design constraints. New docs/ideas/ explorations: - instance-administration — registration toggle, suspend/ban, federation blocklists, reports (moderation now gates the federated comments idea) - social-interactions — local likes + comments (don't exist even locally; the foundation federated kudos/comments attach to) - activity-participants — group tagging with confirm/decline + federated mentions (the participants jsonb column is an untyped stub) - multi-day-collections — architecture open question #1, directions evaluated architecture.md cleanup: - Mastodon-compat section annotated with shipped/captured state + the live-soak interop lessons (attachment arrays, tombstones, 10s timeout, no backfill) - api.trails.cool removed (contradicted resolved decision #18) - Phase 1 ticked (shipped); Phase 2/3 items annotated with where each is tracked; specs/ → openspec/, activity.* → journal.*, cx21 → cx23 - brouter-web open question marked resolved-in-practice; new section pointing to where the unshipped vision is tracked Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
87 lines
4.3 KiB
Markdown
87 lines
4.3 KiB
Markdown
## Why
|
|
|
|
`social-federation` delivers the *social* half of the federation pitch:
|
|
activities federate as `Create(Note)`, Mastodon users can follow trails
|
|
users, trails users will follow each other across instances (§6/§7).
|
|
The *collaboration* half of the architecture vision — routes as
|
|
first-class federated objects — is still aspirational: `Create/Update
|
|
Route` activities, cross-instance route sharing with Invite/Accept
|
|
mirroring, and cross-instance Planner edits saved back to the owner's
|
|
instance (architecture.md Resolved Decisions #2, #3, #12, #16 and Data
|
|
Flow Scenarios 3 & 4).
|
|
|
|
This is the differentiator. Activity federation makes trails.cool a
|
|
Mastodon-compatible publisher; route federation makes it the thing the
|
|
architecture promises: collaborative route planning across self-hosted
|
|
instances, with the owner's instance as the single source of truth.
|
|
|
|
## What Changes
|
|
|
|
- **Routes federate as objects**: a public route is dereferenceable at
|
|
its canonical URL as an ActivityPub object (custom `trails:Route`
|
|
type carrying the JSON-LD metadata envelope + GPX attachment;
|
|
Mastodon-facing fallback rendering deferred — routes federate
|
|
trails-to-trails only). `Create`/`Update` activities fan out to
|
|
followers and collaborators on publish and on new versions.
|
|
- **Cross-instance sharing via Invite/Accept**: sharing a route with a
|
|
remote trails user sends an `Invite`; their `Accept` registers them
|
|
as collaborator on the owner's instance and creates a **mirror** (a
|
|
read cache: metadata + latest GPX) on theirs. Route `Update`s push
|
|
new versions to all collaborator mirrors.
|
|
- **Cross-instance edits**: a collaborator's instance requests a
|
|
**scoped edit token** from the owner's instance (HTTP-Signature
|
|
authenticated instance-to-instance request). The Planner session
|
|
opens with the owner's callback URL + that token; saves create new
|
|
versions directly on the owner's instance, crediting the
|
|
collaborator as contributor (the existing JWT callback machinery,
|
|
issued across instances).
|
|
- **Mirror healing**: a periodic sync check detects mirrors that
|
|
missed `Update`s (instance down > Fedify's retry budget) and
|
|
re-fetches the canonical object.
|
|
- **Trails-to-trails only**, enforced with the same NodeInfo
|
|
`software.name` check as outbound follows. Mastodon never sees
|
|
`trails:Route` objects (they're not Notes and aren't delivered to
|
|
non-trails inboxes).
|
|
|
|
## Capabilities
|
|
|
|
### New Capabilities
|
|
|
|
- `route-federation`: Route objects over ActivityPub — dereferenceable
|
|
routes, Create/Update fan-out, Invite/Accept collaboration
|
|
mirroring, cross-instance scoped edit tokens, mirror sync healing.
|
|
|
|
### Modified Capabilities
|
|
|
|
- `social-federation`: outbox/delivery extended beyond `Create(Note)`
|
|
with the route activity vocabulary; inbox accepts
|
|
`Invite`/`Accept(Invite)`/`Update(Route)` from trails instances.
|
|
- `route-management`: routes gain remote provenance (mirrors) and
|
|
remote collaborators; version creation accepts cross-instance
|
|
contributors.
|
|
- `route-sharing`: the share dialog can target remote trails handles
|
|
(`@bob@bob.trails.xyz`), entering the Invite lifecycle instead of a
|
|
local share row.
|
|
- `planner-callback`: callback tokens verifiable when issued by THIS
|
|
instance to a session initiated from a REMOTE instance, and the
|
|
edit-in-planner flow can carry a remote owner's callback.
|
|
|
|
## Impact
|
|
|
|
- **Dependencies**: requires `social-federation` §6 (outbound
|
|
trails-to-trails follows + NodeInfo check) and `route-sharing`
|
|
(local share model the Invite extends). Build after both.
|
|
- **Schema**: `route_mirrors` (or `routes.remote_origin_iri` +
|
|
provenance columns mirroring the activities approach),
|
|
`route_collaborators` extension for remote actor IRIs (the
|
|
exactly-one-of local/remote pattern from `follows`), token-issuance
|
|
audit table.
|
|
- **Federation surface**: new inbound activity types (gated to
|
|
verified trails instances), instance-to-instance token endpoint —
|
|
security-review before exposure; privacy manifest update (what a
|
|
collaborator instance learns and stores).
|
|
- **Out of scope**: rendering trails Route objects on Mastodon;
|
|
federated forking (fork-from-mirror can be a follow-up); real-time
|
|
*federated* presence in Planner sessions (sessions remain on one
|
|
Planner instance — federation is about where the route lives, not
|
|
where the session runs).
|