Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conformance/protocols-and-authorization.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Use with `dwn/protocols.md` and `dwn/authorization.md`.
- [ ] Structure paths and rule sets are resolved deterministically.
- [ ] Record writes must match the declared protocol/path structure.
- [ ] Cross-context parent/path violations are rejected.
- [ ] A parent-bearing write resolves its parent from the retained initial write; a soft-deleted parent still satisfies ancestry.
- [ ] A child of a pruned parent is rejected terminally, not as a retryable missing dependency.
- [ ] Unsupported or malformed protocol definitions do not become active authorization policy.

## Actor semantics
Expand All @@ -38,4 +40,5 @@ Use with `dwn/protocols.md` and `dwn/authorization.md`.
- [ ] Wrong protocol path is rejected.
- [ ] Wrong context/parent is rejected.
- [ ] Role from another context does not leak authority.
- [ ] Parent-bearing child admission is identical across arrival permutations (parent-first, child-first, soft-delete-first, prune-first).
- [ ] Delegation outside its scope is rejected.
17 changes: 9 additions & 8 deletions decisions/0007-retained-parent-ancestry.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR 0007: Structural Parent Ancestry Uses Retained Writes; Only Prune Removes Ancestry

- Status: Accepted (2026-09-13); Enbox parity divergence tracked upstream
- Status: Accepted (2026-09-13); implemented in Enbox #1685 and Rust #304
- Date: 2026-09-13

## Context
Expand Down Expand Up @@ -84,10 +84,10 @@ Separate structural ancestry from liveness:
unchanged. A soft delete never revoked that authority.
- **Soft delete does not seal.** Existing children already survive a soft delete;
this makes the rule consistent. To remove a subtree, use `prune`, which purges
it. This is a divergence from current Enbox parity and requires a `dwn-spec`
clarification ("exist"/ancestry = retained write) and an upstream Enbox
proposal. Until Enbox agrees, a Rust implementation is an intentional,
documented divergence, not parity.
it. Current Enbox and Rust both implement this rule (`enboxorg/enbox#1685`,
`enbox-rust-core#304`), so it is no longer a parity divergence. A `dwn-spec`
clarification ("exist"/ancestry = retained write) is filed as
`enboxorg/dwn-spec#70` to make the reading explicit.
- The interim receiver-local terminal classification for soft-deleted parents is
superseded. The mechanism remains for pruned parents and for roles.

Expand All @@ -112,10 +112,11 @@ None.

- `enboxorg/enbox#991` — closure-based admission model (closed; 3b absence rule)
- `enboxorg/enbox#1679`, `enboxorg/enbox#1680` — interim terminal classification
- `enboxorg/enbox#1684` — TypeScript retained-ancestry implementation
- `enboxorg/enbox#1684` — TypeScript retained-ancestry issue (implemented, `enboxorg/enbox#1685`)
- `enboxorg/enbox-rust-core#303` — Rust parent verification and classification
- `enboxorg/enbox-rust-core#304` — Rust retained-ancestry implementation
- `enboxorg/enbox-rust-core#304` — Rust retained-ancestry implementation (merged)
- `enboxorg/knowledge#19` — knowledge adoption tracking
- `enboxorg/enbox-rust-core#188` — durable feed substrate and reconciliation
- `DWN-REC-004` (implementation-contract), `DWN-PROTO-001`, `DWN-PROTO-004`, `DWN-PROTO-005`
- `implementation/dependency-resolution.md`, `dwn/protocols.md`
- `enboxorg/dwn-spec` issue — clarify that "exist" means retained, and that prune removes ancestry
- `enboxorg/dwn-spec#70` — clarify that "exist"/ancestry means the retained write, and that prune removes ancestry
14 changes: 14 additions & 0 deletions dwn/protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ Composition turns protocol resolution into a graph rather than one self-containe

Namespaces do not simply merge across a `$ref`; the referenced position and children can have different governing protocol/type sources.

### Parent ancestry

A child's structural parent is proven by the parent's **retained initial write**
in the expected protocol, not by the parent's current liveness. A soft
`RecordsDelete` does not remove ancestry: a child may be written under a
soft-deleted parent and stays addressable by its own Record ID, protocol path,
and context, while the parent itself reads as absent. A `prune` delete removes
ancestry, because prune is the explicit subtree-removal operation; a child of a
pruned parent is terminal and unrepairable. Roles and grants are separate
concerns and remain current-state, so revocation still wins.

See `decisions/0007-retained-parent-ancestry.md`.

## Encryption policy

Protocols can require encryption and define key-agreement policy. Encryption policy belongs to protocol semantics, while actual decryption key distribution is a separate capability lifecycle.
Expand Down Expand Up @@ -99,5 +112,6 @@ Protocol directives can affect how Records are delivered or selected for visibil
- Do not evaluate historical Records only against the newest protocol configuration.
- Do not treat a protocol role as globally valid outside its context.
- Do not resolve cross-protocol parents using a same-protocol-only query.
- Do not treat a soft-deleted parent as unusable ancestry; only `prune` removes ancestry.
- Do not assume draft directive semantics exactly match current Enbox without checking known divergence issues.
- Do not merge authorization policy and encryption key possession into one concept.
15 changes: 15 additions & 0 deletions enbox/records.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,21 @@ Tracked by `enbox-rust-core#189`.

Rust implemented this ordering and store-owned atomic latest-state transitions under `enbox-rust-core#189`.

## Parent ancestry and deletes

Current TypeScript and Rust resolve a structural parent from its **retained
initial write** in the expected protocol, not from current liveness. A soft
`RecordsDelete` does not remove ancestry: a child written under a soft-deleted
parent is admitted and remains addressable by its own Record ID, path, and
context, while the parent itself reads as absent. A `prune: true` delete removes
ancestry and settles the rejected descendant terminally (replication classifies it
superseded rather than a repairable dependency), so a pruned subtree leaves no
dead letter. Role and grant lookups stay current-state, so soft-delete revocation
still wins.

Recorded as ADR 0007; implemented in `enboxorg/enbox#1685` and
`enbox-rust-core#304`.

## Visibility gap

Physical retained state and application-visible state are separate concerns. Query/Count/Subscribe route through a shared visibility model including read-time record limits, context boundaries, published selection and initial-write attachment. Rust alignment landed under `enbox-rust-core#190` (PR #262) and is pinned by `ENBOX-REC-003` and `DWN-REC-008`.
Expand Down
9 changes: 5 additions & 4 deletions implementation/dependency-resolution.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ does not seal or hide children); a `prune` removes ancestry and is terminal. See
`decisions/0007-retained-parent-ancestry.md`.

This restores `DWN-REC-004` for parent-bearing children without retraction or
trusted timestamps. An implementation that consults current liveness — current
Enbox, and the interim receiver-local terminal classification in
`enboxorg/enbox#1680` / `enboxorg/enbox-rust-core#303` — is order-dependent and
leaves a permanent dead letter when the delete precedes the child.
trusted timestamps. The interim receiver-local terminal classification for soft
deletes (`enboxorg/enbox#1679` / `#1680`, `enboxorg/enbox-rust-core#303`) is
superseded. Current Enbox and Rust both resolve parent ancestry from the retained
initial write (`enboxorg/enbox#1685`, `enboxorg/enbox-rust-core#304`); a `prune`
tombstone remains the terminal case.
Loading