Hydration Architecture
Stratos uses the source field pattern to separate data storage from presentation. Full records with boundary content are stored in Stratos; when a record is hydrated, Stratos returns it wrapped with a source field that points back to the full record.
Source Field Pattern
When a user creates a record in Stratos, a single write happens:
- Full record - stored in the user's per-actor repo on Stratos (with text content, boundary, etc.). Nothing is written to the user's mainstream PDS on the record write path.
On hydration, Stratos returns the record with an added source field:
interface RecordSource {
vary: 'authenticated' | 'unauthenticated'
subject: {
uri: string // at:// URI of the full record in Stratos
cid: string // CID of the full record for integrity verification
}
service: string // DID + fragment: "did:web:stratos.example.com#atproto_pns"
}Example
Full record (in Stratos):
{
"$type": "zone.stratos.feed.post",
"text": "Private message for my community",
"boundary": {
"values": [{ "value": "did:web:stratos.example.com/fanart" }]
},
"createdAt": "2024-01-15T12:00:00.000Z"
}Hydrated record (returned by Stratos, carrying the source field):
{
"$type": "zone.stratos.feed.post",
"source": {
"vary": "authenticated",
"subject": {
"uri": "at://did:plc:abc/zone.stratos.feed.post/tid123",
"cid": "bafyreibeef..."
},
"service": "did:web:stratos.example.com#atproto_pns"
},
"createdAt": "2024-01-15T12:00:00.000Z"
}Hydration Flow
Endpoint Discovery
AppViews and clients discover the Stratos service URL through the user's zone.stratos.actor.enrollment record on their PDS:
- Fetch enrollment record from users PDS repo
- Each record has: { service: "https://stratos.example.com", ... }
- Resolve service DID from: https://stratos.example.com/.well-known/did.json
- Use service DID to hydrate records (validates source.service field matches)
The source.service field is a DID+fragment string, not a URL — the AppView resolves the full URL by looking up the DID document.
Hydration Model
Stratos com.atproto.repo.getRecord applies boundary access control:
| Scenario | Result |
|---|---|
| Caller enrolled + shares boundary | Full record returned |
| Caller enrolled but different boundary | 404 (not visible) |
| Caller not enrolled | 404 |
| Unauthenticated | 404 |
Batch Hydration (hydrateRecords)
AppViews typically use zone.stratos.repo.hydrateRecords to hydrate multiple records for a feed.
- Returns a list of successfully hydrated records.
- Records the viewer cannot access are listed in
blocked. - Missing records are listed in
notFound.
The 404 response for denied access is deliberate — it avoids leaking the existence of records to unauthorized viewers.
Viewer Identity
The viewer used for boundary scoping is derived strictly from the authenticated credential (auth.credentials.did). The hydration endpoints accept no client-supplied viewer DID, so a caller cannot spoof another identity to widen the boundary set. The viewer's boundaries are resolved from that DID, and only records sharing at least one of those boundaries are returned. This applies uniformly to user and service callers — a service identity reads only within its own enrolled boundaries.
Trust Model
The source.cid returned on hydration allows AppViews to verify the hydrated record hasn't changed:
// AppView verification after hydrating: recompute the CID from the returned
// record content and compare it against the source reference.
const computedCid = await cidForCbor(hydratedRecord.value)
if (computedCid.toString() !== hydratedRecord.source.subject.cid) {
throw new Error('Record CID mismatch — content may have been tampered with')
}Note the limits of this check: both the record value and source.subject.cid come from the same service response, so recomputing the CID proves the response is internally consistent (the content matches the reference the service claims for it) — it does not by itself prove authenticity. For that, fetch the record proof (com.atproto.sync.getRecord, which returns the signed commit and MST inclusion proof) and verify the commit signature against the user's enrolled signing key from the attestation chain below.
Combined with the enrollment attestation system (Enrollment Signing), this gives AppViews a complete verification chain:
source.cidreturned on hydration matches the hydrated record's CID- Service attestation verifies user's boundary memberships were endorsed by the service
- Record commits are signed with the user's P-256 key (enrolled key is in the attestation)