390 lines
6.3 KiB
Markdown
390 lines
6.3 KiB
Markdown
|
|
Great, let’s do this **concretely and end-to-end**, but still faithful to the specs you’ve been shaping. I’ll walk a **single artifact** all the way through its lifecycle:
|
|||
|
|
|
|||
|
|
* creation
|
|||
|
|
* witnessing (certificate case)
|
|||
|
|
* indexing
|
|||
|
|
* snapshotting
|
|||
|
|
* eviction from local storage
|
|||
|
|
* later rehydration
|
|||
|
|
* reuse in a new program
|
|||
|
|
|
|||
|
|
I’ll label **what is normative** vs **implementation choice**, and I’ll keep the mental model consistent: **blocks are physical, artifacts are semantic**.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# End-to-End Artifact Lifecycle Walkthrough
|
|||
|
|
|
|||
|
|
We’ll use a **certificate artifact** because it exercises *authority*, *witnessing*, and *reuse*.
|
|||
|
|
|
|||
|
|
Assume we are on a **personal domain** `alice.personal`, on an ASL-HOST.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 0 – Initial state (before anything happens)
|
|||
|
|
|
|||
|
|
On disk:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
/asl/domains/alice.personal/
|
|||
|
|
├── blocks/
|
|||
|
|
│ ├── open/
|
|||
|
|
│ └── sealed/
|
|||
|
|
├── index/
|
|||
|
|
├── log/
|
|||
|
|
├── snapshots/
|
|||
|
|
└── meta/
|
|||
|
|
└── dam/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Current snapshot:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
alice.personal@42
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Authority:
|
|||
|
|
|
|||
|
|
* DAM says `self-authority`
|
|||
|
|
* Host holds Alice’s private key
|
|||
|
|
* Host is **Active**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 1 – Artifact creation (certificate is generated)
|
|||
|
|
|
|||
|
|
### What happens conceptually
|
|||
|
|
|
|||
|
|
A **PEL program** is run that generates a certificate:
|
|||
|
|
|
|||
|
|
* Input: key material, policy parameters
|
|||
|
|
* Output: certificate bytes
|
|||
|
|
|
|||
|
|
This is *just data* at this stage.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### On disk: block writing (physical layer)
|
|||
|
|
|
|||
|
|
1. ASL allocates an **open block**:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
blocks/open/blk_tmp_7f3a.tmp
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. Certificate bytes are appended to the open block.
|
|||
|
|
|
|||
|
|
3. The artifact bytes occupy:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
offset = 8192
|
|||
|
|
length = 1432
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
At this moment:
|
|||
|
|
|
|||
|
|
* No artifact exists yet (semantically)
|
|||
|
|
* Bytes are **not visible**
|
|||
|
|
* Crash here is allowed
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Block sealing (normative)
|
|||
|
|
|
|||
|
|
4. Block is sealed:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
block_id = H(block_bytes)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
File moved to:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
blocks/sealed/7f/7f3a9c...blk
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Invariant satisfied:** sealed blocks are immutable.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 2 – Artifact becomes real (indexing)
|
|||
|
|
|
|||
|
|
### Artifact identity
|
|||
|
|
|
|||
|
|
Artifact key is computed from:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
H(certificate_bytes + type_tag + metadata)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
artifact_key = a9c4…
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Index entry written
|
|||
|
|
|
|||
|
|
An index entry is appended to an **open index segment**:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
index/shard-012/segment-0042.idx (open)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Entry:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
ArtifactKey → (BlockID, offset, length)
|
|||
|
|
type_tag = cert.x509
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Still **not visible**.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Log append (normative visibility point)
|
|||
|
|
|
|||
|
|
A log record is appended:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
log-0000000000001200.asl
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Record:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
ADD_INDEX_ENTRY artifact_key=a9c4… segment=0042
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Then:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
SEAL_SEGMENT segment=0042
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Now the artifact exists.**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 3 – Snapshot & witnessing
|
|||
|
|
|
|||
|
|
### Snapshot creation
|
|||
|
|
|
|||
|
|
A snapshot is emitted:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
alice.personal@43
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Snapshot pins:
|
|||
|
|
|
|||
|
|
* index segment 0042
|
|||
|
|
* block 7f3a…
|
|||
|
|
|
|||
|
|
Snapshot manifest includes:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
authority:
|
|||
|
|
domain: alice.personal
|
|||
|
|
key: alice-root-key
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Witnessing from elsewhere (certificate use case)
|
|||
|
|
|
|||
|
|
Now the **certificate is taken aboard** by another domain, say:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
common
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
How?
|
|||
|
|
|
|||
|
|
1. The certificate artifact is **published** (policy allows this)
|
|||
|
|
2. `common` imports the artifact:
|
|||
|
|
|
|||
|
|
* artifact bytes are fetched (or referenced)
|
|||
|
|
* artifact key is preserved
|
|||
|
|
3. A **cross-domain reference** is indexed in `common`
|
|||
|
|
|
|||
|
|
No copying is required if blocks are addressable, but often they are copied.
|
|||
|
|
|
|||
|
|
Witnessing here means:
|
|||
|
|
|
|||
|
|
> The certificate is now **provably present in two domains**, each with their own snapshot history.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 4 – Time passes (artifact becomes cold)
|
|||
|
|
|
|||
|
|
A week passes.
|
|||
|
|
|
|||
|
|
A **local retention policy** runs (implementation choice, but policy-guided).
|
|||
|
|
|
|||
|
|
### GC decision (normative constraints)
|
|||
|
|
|
|||
|
|
The artifact:
|
|||
|
|
|
|||
|
|
* is sealed
|
|||
|
|
* is referenced by snapshot `@43`
|
|||
|
|
* is not referenced by CURRENT workflows
|
|||
|
|
|
|||
|
|
Policy allows **cold eviction** if:
|
|||
|
|
|
|||
|
|
* snapshot still exists
|
|||
|
|
* artifact can be re-fetched from trusted domains
|
|||
|
|
|
|||
|
|
So…
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Block eviction (implementation choice)
|
|||
|
|
|
|||
|
|
Local block file is removed:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
blocks/sealed/7f/7f3a9c...blk ← deleted
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
But:
|
|||
|
|
|
|||
|
|
* index entry remains
|
|||
|
|
* snapshot remains
|
|||
|
|
* artifact is still **logically present**
|
|||
|
|
|
|||
|
|
This is allowed because:
|
|||
|
|
|
|||
|
|
> **ASL defines availability separately from existence.**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 5 – Artifact is needed again
|
|||
|
|
|
|||
|
|
Later, a new PEL program runs:
|
|||
|
|
|
|||
|
|
* Input: certificate artifact `a9c4…`
|
|||
|
|
* Purpose: sign something new
|
|||
|
|
|
|||
|
|
### Artifact lookup
|
|||
|
|
|
|||
|
|
1. Index lookup finds:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
ArtifactKey → (BlockID, offset, length)
|
|||
|
|
```
|
|||
|
|
2. Block is missing locally.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Rehydration (normative + policy)
|
|||
|
|
|
|||
|
|
ASL-HOST:
|
|||
|
|
|
|||
|
|
1. Consults **domain policy**
|
|||
|
|
2. Finds trusted source:
|
|||
|
|
|
|||
|
|
* `common`
|
|||
|
|
* or a personal mirror
|
|||
|
|
3. Fetches block by `BlockID`
|
|||
|
|
|
|||
|
|
Block is restored to:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
blocks/sealed/7f/7f3a9c...blk
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Block hash verified.**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 6 – Artifact reused in a new program
|
|||
|
|
|
|||
|
|
The certificate bytes are read from the block.
|
|||
|
|
|
|||
|
|
A new PEL program runs:
|
|||
|
|
|
|||
|
|
* Inputs:
|
|||
|
|
|
|||
|
|
* certificate artifact `a9c4…`
|
|||
|
|
* new data
|
|||
|
|
* Outputs:
|
|||
|
|
|
|||
|
|
* new artifact(s)
|
|||
|
|
* new PER
|
|||
|
|
|
|||
|
|
These outputs repeat the **same lifecycle**.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Phase 7 – Index & snapshot continuity
|
|||
|
|
|
|||
|
|
Now:
|
|||
|
|
|
|||
|
|
* Snapshot `@44` references:
|
|||
|
|
|
|||
|
|
* old certificate
|
|||
|
|
* new artifacts
|
|||
|
|
* Old artifact remains immutable
|
|||
|
|
* Provenance is intact
|
|||
|
|
|
|||
|
|
At no point did we:
|
|||
|
|
|
|||
|
|
* rewrite bytes
|
|||
|
|
* change meaning
|
|||
|
|
* trust runtime state
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## What was witnessed, exactly?
|
|||
|
|
|
|||
|
|
Three things were witnessed, independently:
|
|||
|
|
|
|||
|
|
1. **Bytes** (block hash)
|
|||
|
|
2. **Meaning** (artifact key → index)
|
|||
|
|
3. **Authority** (snapshot + DAM + signatures)
|
|||
|
|
|
|||
|
|
This is why the system holds together.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Why this works for *everything*
|
|||
|
|
|
|||
|
|
This same flow works for:
|
|||
|
|
|
|||
|
|
* certificates
|
|||
|
|
* home directory tarballs
|
|||
|
|
* shell command outputs
|
|||
|
|
* TGK edges
|
|||
|
|
* PERs
|
|||
|
|
* witness rotation artifacts
|
|||
|
|
|
|||
|
|
Nothing special happens for “important” artifacts.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## The key invariants you just saw
|
|||
|
|
|
|||
|
|
1. **Artifacts never move**
|
|||
|
|
2. **Blocks may come and go**
|
|||
|
|
3. **Snapshots pin meaning, not bytes**
|
|||
|
|
4. **Witnessing is just another artifact**
|
|||
|
|
5. **Time does not weaken correctness**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## One sentence to take away
|
|||
|
|
|
|||
|
|
> An artifact can disappear from disk, reappear a year later, and still mean exactly the same thing.
|
|||
|
|
|
|||
|
|
If you want next, we can:
|
|||
|
|
|
|||
|
|
* walk the **same artifact across two personal machines**
|
|||
|
|
* show **what breaks if someone cheats**
|
|||
|
|
* map this onto **ZFS send/receive**
|
|||
|
|
* or show **how PEL receipts stitch all this together**
|
|||
|
|
|
|||
|
|
You’re now fully “above the filesystem” — exactly where you wanted to be.
|
|||
|
|
|