03 — Forgeyard CAS & Artifact Data Plane System Architecture
Document type: Core Infrastructure System & Architecture
Project: Forgeyard CI/CD
Subsystem: Content-addressed storage, artifact/data plane, immutable object model, local/tiered/cloud/P2P backends, transfer, replication, verification, retention, garbage collection, artifact manifests, source objects, logs/reports, cache integration, air-gap bundles, and data-plane observability
Architecture style: Content-addressed, immutable, backend-neutral, metadata-separated, integrity-first
Status: Target production architecture for the new Forgeyard repository
Relationship to prior work: Builds on 01-forgeyard-core-domain-foundation.md and 02-forgeyard-storage-metadata.md. It assumes the previously defined VCS-neutral source snapshot architecture, hermetic/reproducible build architecture, Change Proposal model, and language ecosystems. It does not redefine those systems; it defines the shared byte/object data plane they use.
1. Purpose
Forgeyard needs a single, coherent data plane for all large or immutable build-related bytes.
This includes:
source blobs
source trees
build inputs
build outputs
artifacts
package files
logs
test reports
coverage reports
SBOMs
VEX
provenance
attestations
reproduction evidence
toolchain objects
dependency archives
binary caches
release artifacts
air-gap bundles
The data plane must work in:
MODE 1
local standalone
MODE 2
distributed team
MODE 3
enterprise / HA / multi-region
without changing domain semantics.
The central rule is:
Forgeyard stores immutable bytes by content identity and stores business meaning separately as metadata references.
A second rule:
CAS verifies bytes; metadata describes what those bytes mean.
A third rule:
P2P acceleration, local caches, cloud object stores, and remote mirrors are transport/storage implementations—not sources of semantic truth.
2. Architectural Position
Domain Services
│
▼
Metadata Store
│
▼
CAS ObjectRef
│
▼
Forgeyard CAS API
│
┌────────────────┼─────────────────┐
▼ ▼ ▼
Local CAS Object Storage Iroh/P2P
│ │ │
└────────────────┼─────────────────┘
▼
Verified Immutable Bytes
3. Goals
The subsystem MUST:
- use content-addressed immutable objects;
- support BLAKE3 as default internal digest;
- support SHA-256 aliases for interoperability;
- support local standalone CAS;
- support S3-compatible object storage;
- support GCS;
- support Azure Blob-compatible storage;
- support Iroh/P2P acceleration;
- support tiered lookup;
- verify object integrity on read/write;
- support resumable transfers;
- support large objects;
- support streaming;
- support chunked transfer where useful;
- support manifests/trees;
- support source snapshot storage;
- support artifact storage;
- support log/report storage;
- support action-cache references;
- support replication;
- support multi-region storage;
- support retention;
- support GC;
- support legal hold/pinning;
- support air-gap export/import;
- support encryption in transit;
- support tenant isolation policy;
- support observability;
- support repair/reconciliation;
- avoid making any one backend authoritative by architecture.
4. Non-Goals
CAS is not:
relational metadata database
VCS history database
policy engine
scheduler
artifact catalog
search engine
Those systems store references to CAS objects.
CAS should not know:
"this object is a successful release"
unless metadata is supplied in generic object annotations outside identity.
5. Workspace Structure
crates/cas/
├── forgeyard-cas/
├── forgeyard-cas-model/
├── forgeyard-cas-local/
├── forgeyard-cas-s3/
├── forgeyard-cas-gcs/
├── forgeyard-cas-azure/
├── forgeyard-cas-iroh/
├── forgeyard-cas-tiered/
├── forgeyard-cas-transfer/
├── forgeyard-cas-chunk/
├── forgeyard-cas-manifest/
├── forgeyard-cas-replication/
├── forgeyard-cas-gc/
├── forgeyard-cas-retention/
├── forgeyard-cas-integrity/
├── forgeyard-cas-airgap/
├── forgeyard-cas-health/
├── forgeyard-cas-metrics/
└── forgeyard-cas-testkit/
Related artifact layer:
crates/artifact/
├── forgeyard-artifact/
├── forgeyard-artifact-model/
├── forgeyard-artifact-store/
├── forgeyard-artifact-manifest/
├── forgeyard-artifact-index/
├── forgeyard-artifact-retention/
├── forgeyard-artifact-download/
└── forgeyard-artifact-testkit/
6. forgeyard-cas
Primary backend-neutral interface.
It owns:
put
get
exists
head/stat
delete internal/admin
stream
batch lookup
manifest closure access
health
It MUST NOT depend on:
AWS SDK
GCS SDK
Azure SDK
Iroh implementation
filesystem-specific implementation
7. CAS Object Identity
#![allow(unused)]
fn main() {
pub struct CasObjectId {
pub digest: Digest,
}
}
Usually:
BLAKE3
Interop aliases:
SHA-256
backend-native ETag/checksum
8. Object Reference
#![allow(unused)]
fn main() {
pub struct CasObjectRef {
pub id: CasObjectId,
pub size: ByteSize,
pub media_type: Option<MediaType>,
}
}
Size is part of validation metadata but not necessarily primary identity.
9. Content Identity Rule
For raw blob object:
CasObjectId =
BLAKE3(raw bytes)
For structured manifest/tree:
CasObjectId =
BLAKE3(
schema version
+
canonical encoded manifest
)
10. Immutable Object Rule
Once stored:
object ID X
must always map to the same bytes.
If backend returns different bytes:
IntegrityViolation
and backend/object is quarantined.
11. No Mutable Overwrite
CAS API must not expose:
overwrite object X with new bytes
Mutable names belong in metadata:
artifact alias
release name
cache key
source ref
12. Digest Algorithm
Default:
BLAKE3
Reasons:
high throughput
parallel hashing
streaming
strong modern cryptographic design
efficient Rust implementation
13. SHA-256 Interop
Needed for:
OCI
Bazel RBE
SLSA/in-toto ecosystems
external checksum APIs
CAS can store:
#![allow(unused)]
fn main() {
pub struct DigestAliases {
pub primary: Digest,
pub aliases: Vec<Digest>,
}
}
14. Digest Alias Verification
Never trust declared alias.
Compute/verify:
bytes
↓
BLAKE3
SHA-256
and store mapping only after verification.
15. Blob Object
#![allow(unused)]
fn main() {
pub struct BlobObject {
pub id: CasObjectId,
pub size: ByteSize,
}
}
No semantic meaning.
16. Manifest Object
Used to represent object collections.
#![allow(unused)]
fn main() {
pub struct CasManifest {
pub schema: ManifestSchemaVersion,
pub entries: Vec<ManifestEntry>,
}
}
17. Manifest Entry
#![allow(unused)]
fn main() {
pub struct ManifestEntry {
pub name: ManifestName,
pub object: CasObjectRef,
pub role: ManifestRole,
}
}
18. Manifest Roles
Examples:
file
tree
debug-symbols
signature
SBOM
provenance
log-chunk
test-report
package
Role is metadata inside manifest; object digest remains content identity.
19. Tree Object
Source/artifact directory trees:
#![allow(unused)]
fn main() {
pub struct TreeManifest {
pub schema: TreeSchemaVersion,
pub entries: Vec<TreeEntry>,
}
}
20. Tree Entry
#![allow(unused)]
fn main() {
pub struct TreeEntry {
pub path: CanonicalPathComponent,
pub kind: TreeEntryKind,
pub object: Option<CasObjectRef>,
pub executable: bool,
pub symlink_target: Option<BoundedBytes>,
}
}
21. Canonical Tree Encoding
Rules:
sorted entries
stable schema
stable path bytes
explicit entry kind
explicit executable bit
explicit symlink handling
No filesystem iteration order.
22. Source Snapshot Integration
VCS subsystem stores:
source blobs
canonical source trees
snapshot manifests
in CAS.
Metadata DB stores:
SourceSnapshotId
root tree ref
provenance ref
23. Hermetic Store Integration
Hermetic functional store uses CAS for:
toolchains
dependency closures
fixed-output fetches
derivation outputs
binary substitutions
Do not create another independent blob store.
24. Artifact Integration
Artifact subsystem stores:
ArtifactId
type
producer
retention
CAS ref
in metadata.
CAS stores actual artifact bytes.
25. Artifact Types
#![allow(unused)]
fn main() {
pub enum ArtifactKind {
BuildOutput,
Package,
TestReport,
CoverageReport,
LogBundle,
Sbom,
Vex,
Provenance,
Attestation,
DebugSymbols,
ReproductionEvidence,
SourceBundle,
Custom(ArtifactKindId),
}
}
26. Artifact Identity vs CAS Identity
ArtifactId:
business entity identity
CasObjectId:
byte content identity
Two artifacts may point to same CAS object.
27. Deduplication
Automatic via content addressing.
If object already exists:
verify expected metadata
return existing ref
No duplicate byte storage required.
28. Cross-Project Deduplication
Physically possible.
But multi-tenant deployments must consider:
existence side channels
billing
privacy policy
retention
Logical access control remains tenant/project scoped.
29. Tenant Isolation
CAS namespace strategy can be:
global content pool
+
metadata ACL
or:
tenant-partitioned physical namespace
depending deployment security policy.
30. Default Multi-Tenant Recommendation
Enterprise hosted mode:
logical tenant ACL
+
careful object existence API
+
optional tenant storage partition
Do not expose:
"object exists globally"
to untrusted tenants.
31. CAS Backend Trait
#![allow(unused)]
fn main() {
#[async_trait]
pub trait CasBackend: Send + Sync {
async fn put(
&self,
input: CasPutRequest,
) -> Result<CasObjectRef, CasError>;
async fn get(
&self,
id: &CasObjectId,
) -> Result<CasRead, CasError>;
async fn head(
&self,
id: &CasObjectId,
) -> Result<Option<CasObjectMetadata>, CasError>;
async fn contains(
&self,
id: &CasObjectId,
) -> Result<bool, CasError>;
}
}
32. Streaming Read
#![allow(unused)]
fn main() {
pub struct CasRead {
pub metadata: CasObjectMetadata,
pub stream: CasByteStream,
}
}
Do not load large objects fully into memory.
33. Streaming Write
CasPutRequest should support stream input:
#![allow(unused)]
fn main() {
pub struct CasPutRequest {
pub expected: Option<CasExpectedObject>,
pub stream: CasInputStream,
}
}
34. Expected Object
#![allow(unused)]
fn main() {
pub struct CasExpectedObject {
pub digest: Option<Digest>,
pub size: Option<ByteSize>,
}
}
If supplied, write fails on mismatch.
35. Put Result
CAS computes authoritative digest while streaming.
36. Read Integrity
Configurable modes:
#![allow(unused)]
fn main() {
pub enum ReadVerification {
Always,
OnColdBackend,
Sampled,
BackendTrustedPlusPeriodicAudit,
}
}
Critical/release reads may force full verification.
37. Default Integrity Policy
Local/cold ingest:
verify full digest
Subsequent reads:
backend integrity + periodic/full verification policy
Do not silently trust object-store metadata as cryptographic proof.
38. Local CAS
crates/cas/forgeyard-cas-local/
Tree:
src/
├── lib.rs
├── backend.rs
├── layout.rs
├── file.rs
├── temp.rs
├── atomic.rs
├── fsync.rs
├── verify.rs
├── gc.rs
├── health.rs
└── error.rs
39. Local CAS Layout
Example:
$FORGEYARD_DATA/cas/
├── objects/
│ └── blake3/
│ ├── ab/
│ │ └── cdef...
│ └── ...
├── temp/
├── quarantine/
└── metadata/
Sharding avoids huge single directories.
40. Atomic Local Write
Correct:
write temp
↓
hash/verify
↓
fsync as required
↓
atomic rename into object path
If object already exists:
verify/accept
41. Partial File Safety
Never make partially written object visible at canonical object path.
42. Local Fsync Policy
Configurable durability:
#![allow(unused)]
fn main() {
pub enum LocalDurability {
BestEffort,
Data,
DataAndMetadata,
}
}
Standalone release artifacts should prefer stronger durability.
43. Local CAS Permissions
Use private application data permissions by default.
44. Local Quarantine
Corrupt object:
move/quarantine
mark unhealthy
attempt recovery from another backend
45. S3-Compatible Backend
forgeyard-cas-s3
Supports:
AWS S3
MinIO
compatible object stores
where API behavior fits.
46. S3 Object Key
Derived from digest.
Example:
objects/blake3/ab/cdef...
No mutable user filename as primary key.
47. S3 Metadata
Optional metadata:
digest
size
schema
but authoritative integrity remains Forgeyard digest.
48. Multipart Upload
Large objects use multipart upload.
Need:
resume state
part checks
abort stale multipart
49. Multipart Cleanup
Background reconciler removes abandoned uploads after TTL.
50. GCS Backend
Same semantic contract.
No GCS-specific fields leak into domain.
51. Azure Backend
Same semantic contract.
52. Object Backend Capability
#![allow(unused)]
fn main() {
pub struct CasBackendCapabilities {
pub ranged_read: bool,
pub multipart_upload: bool,
pub server_side_copy: bool,
pub conditional_put: bool,
pub object_lock: bool,
}
}
53. Tiered CAS
forgeyard-cas-tiered
Lookup order example:
runner local L1
↓
site/local shared L2
↓
Iroh peer
↓
regional object store
↓
remote durable object store
54. Tier Rule
Correctness never depends on earlier tiers.
All returned bytes are digest verified according to policy.
55. Tiered Read
for backend in policy order:
try head/get
verify
optionally promote to faster tier
56. Tier Promotion
When remote object read:
cloud
↓
runner local cache
may persist for future reads.
57. Tiered Write
Two strategies:
write-through
write-back
58. Default Durable Write
For important durable artifacts:
write local/temp
verify
write authoritative durable backend
acknowledge
Optionally seed faster tiers.
59. Write-Back Cache
May be used for noncritical cache objects.
But release/source/toolchain durability should not rely only on asynchronous write-back.
60. Authoritative Durable Backend
In enterprise mode, policy declares:
durability class
not a hardcoded backend name.
61. Durability Classes
#![allow(unused)]
fn main() {
pub enum DurabilityClass {
Ephemeral,
Cache,
Durable,
ReleaseCritical,
}
}
62. Storage Policy
#![allow(unused)]
fn main() {
pub struct CasStoragePolicy {
pub durability: DurabilityClass,
pub replicas_required: u8,
pub regions_required: u8,
pub retention: RetentionPolicy,
}
}
63. Ephemeral Objects
Examples:
temporary intermediate diagnostics
short-lived cache
May live only local/regional.
64. Release-Critical Objects
Examples:
signed release package
SBOM
provenance
source snapshot
reproduction evidence
Require durable verified storage.
65. Iroh CAS Integration
forgeyard-cas-iroh
Purpose:
peer discovery
P2P transfer
local-network acceleration
WAN acceleration where useful
66. Iroh Is Not Authority
Never treat:
peer has object
as equivalent to:
object durably retained
unless separate durability policy explicitly guarantees peer retention—which Forgeyard should not assume.
67. P2P Read Flow
need object X
↓
local miss
↓
trusted/eligible Iroh peers
↓
download
↓
verify digest X
↓
store local
68. P2P Security
Peers can provide malicious bytes.
Digest verification prevents content substitution.
Authorization still controls whether peer is allowed to request/serve object.
69. P2P Metadata Privacy
Do not broadcast sensitive project object IDs indiscriminately in multi-tenant deployments.
70. Chunking
Chunking can improve:
resume
parallel transfer
large-object dedup
partial recovery
but increases complexity.
71. Chunking Policy
Do not chunk every tiny object.
Possible threshold:
large object > configured threshold
72. Chunk Manifest
#![allow(unused)]
fn main() {
pub struct ChunkedObjectManifest {
pub schema: ChunkSchemaVersion,
pub total_size: ByteSize,
pub chunks: Vec<ChunkRef>,
}
}
73. Chunk Ref
#![allow(unused)]
fn main() {
pub struct ChunkRef {
pub offset: u64,
pub length: ByteSize,
pub object: CasObjectRef,
}
}
74. Whole Object Identity
Even when chunked:
whole-object digest
must be computed/verified.
Chunks are transport/storage optimization.
75. Content-Defined Chunking
Optional future optimization.
Do not require initially.
Fixed chunks are simpler.
76. Resumable Download
Client tracks:
object ID
verified ranges/chunks
temporary file
Resume only verified chunks.
77. Resumable Upload
Backend-specific multipart/session abstraction.
78. Transfer Protocol
forgeyard-cas-transfer
Internal agent/daemon transfer can use QUIC/Postcard control + streaming bytes.
79. Transfer Control Messages
Examples:
#![allow(unused)]
fn main() {
pub enum CasTransferMessage {
NeedObjects(NeedObjects),
ObjectAvailable(ObjectAvailable),
BeginUpload(BeginUpload),
UploadAccepted(UploadAccepted),
TransferComplete(TransferComplete),
}
}
80. Batch Missing Check
Before transfer:
client sends object IDs
server returns missing subset
reduces duplicate transfer.
81. Bloom Filters
Optional optimization for large peer/object sets.
Never correctness authority.
False positives must fall back to normal lookup.
82. Range Reads
Useful for:
large archives
debug symbols
log bundles
but only if consumer can validate/use safely.
83. Compression
CAS object identity should be based on logical raw content unless format itself is intentionally compressed artifact.
Transport may compress independently.
84. Transparent Compression
Backend may store compressed representation internally if it can reproduce exact logical bytes.
But this complicates ranged reads and implementation.
Initial recommendation:
store exact bytes
for simplicity.
85. Archive Artifacts
If user artifact is .tar.zst:
compressed bytes themselves
are content identity.
Do not transparently unpack and re-identify unless artifact manifest says so.
86. Artifact Manifest
#![allow(unused)]
fn main() {
pub struct ArtifactManifest {
pub schema: ArtifactManifestVersion,
pub primary: CasObjectRef,
pub attachments: Vec<ArtifactAttachment>,
}
}
87. Attachments
Examples:
debug symbols
SBOM
signature
provenance
source map
test metadata
88. Multi-File Artifact
Example desktop release:
binary
license
config template
debug symbols
represented by tree/manifest.
89. Package Identity
Package file digest is CAS identity.
Package semantic identity:
name
version
target
format
belongs in artifact/package metadata.
90. Build Output Capture
Runner:
declared output paths
↓
canonical capture
↓
files/trees hashed
↓
CAS upload
↓
output manifest
91. Undeclared Outputs
Hermetic system may ignore or flag them.
Do not silently store entire workspace as output.
92. Output Tree
Directory output becomes canonical tree object.
93. Symlink Policy
Artifact tree captures symlink semantics explicitly.
Unsafe symlinks may be rejected depending package/output policy.
94. File Metadata
CAS tree identity should include only semantically intended metadata:
path
entry type
executable bit
symlink target
content
Do not include:
mtime
uid
gid
unless explicitly required.
95. Reproducibility
Canonical tree avoids runner-specific metadata.
96. Log Data Plane
Logs can be large/high-volume.
Store them as chunked append-style objects/manifests.
97. Log Stream Model
#![allow(unused)]
fn main() {
pub struct LogStreamRef {
pub stream_id: LogStreamId,
pub manifest: CasObjectRef,
pub first_seq: LogSeq,
pub last_seq: LogSeq,
}
}
98. Log Chunk
#![allow(unused)]
fn main() {
pub struct LogChunk {
pub first_seq: LogSeq,
pub last_seq: LogSeq,
pub object: CasObjectRef,
}
}
99. Log Ordering
Sequence number is authoritative.
Wall-clock timestamps are supplementary.
100. Live Logs
Live stream:
agent -> daemon/UI
while chunks are periodically durably flushed.
101. Reconnect
Client can request:
from sequence N
Daemon fetches recent/live or CAS chunks.
102. Test Reports
Structured parsed summary in metadata DB.
Full raw report:
CAS
103. Coverage Reports
Same pattern.
104. SBOM / Provenance
Store immutable documents in CAS.
Metadata DB stores:
subject
format
digest
producer
105. Signatures
Signature bytes may be CAS objects.
But private signing keys never CAS objects.
106. Cache Integration
Action cache maps:
ActionKey -> OutputManifestRef
Metadata/cache index separate from CAS bytes.
107. Cache Hit Validation
On cache hit:
lookup mapping
↓
verify output objects available
↓
optionally integrity check
Missing object invalidates cache entry.
108. Cache Poisoning Prevention
Never trust unverified remote cache bytes.
Check:
expected digest
manifest
policy trust
109. Cross-Tenant Cache
Default:
disabled
for untrusted multi-tenant environments.
Optional trusted organization-wide cache with policy.
110. Cache Trust Level
#![allow(unused)]
fn main() {
pub enum CacheTrust {
LocalTrusted,
OrganizationTrusted,
ExternalUntrusted,
}
}
111. Toolchain Objects
Toolchains can be huge.
Store:
toolchain archive/tree
manifest
identity metadata
in CAS.
112. Toolchain Installation
Runner:
need ToolchainId
↓
resolve manifest
↓
fetch CAS closure
↓
materialize immutable store path
113. Fixed-Output Fetches
Hermetic fetcher computes known digest and imports into CAS.
114. Dependency Archives
Downloaded source archives/packages may be CAS objects.
115. Source Mirror
VCS source blobs become CAS objects, so origin outage does not block already-imported builds.
116. Replication
forgeyard-cas-replication
Responsible for durability copies.
117. Replication Record
Metadata store may track:
#![allow(unused)]
fn main() {
pub struct CasReplicaState {
pub object: CasObjectId,
pub backend: CasBackendId,
pub region: RegionId,
pub state: ReplicaState,
}
}
118. Replica States
#![allow(unused)]
fn main() {
pub enum ReplicaState {
Pending,
Available,
Degraded,
Missing,
Quarantined,
}
}
119. Replication Is Metadata
CAS backend itself only knows objects.
Replication controller tracks desired durability.
120. Replication Workflow
object committed
↓
durability policy evaluated
↓
replication tasks
↓
copy
↓
verify digest
↓
mark replica available
121. Server-Side Copy
Can optimize same-cloud-region copy.
Still verify final object identity/metadata.
122. Multi-Region
Policy may require:
2 regions
for release-critical data.
123. Region Awareness
#![allow(unused)]
fn main() {
pub struct CasBackendDescriptor {
pub id: CasBackendId,
pub region: Option<RegionId>,
pub durability: BackendDurability,
pub cost_class: CostClass,
}
}
124. Read Locality
Scheduler can prefer runner near object replicas.
125. Data Locality Score
Scheduler input:
required input digests
available regional/local replicas
Optimization only.
126. Replication Lag
Observable.
Release policy may require desired replicas before promotion.
127. Retention
forgeyard-cas-retention
Objects are retained because metadata roots reference them.
128. Retention Roots
Examples:
active run
recent run
pinned artifact
release
source snapshot
toolchain
audit/legal hold
cache
129. Retention Policy
#![allow(unused)]
fn main() {
pub enum RetentionPolicy {
Ephemeral { ttl: Duration },
Cache { ttl: Duration },
Project { ttl: Duration },
Pinned,
Release,
LegalHold,
}
}
130. Reference Counting
Do not rely exclusively on immediate reference counts in distributed systems.
GC should use mark/sweep or root-derived liveness with grace periods.
131. GC Architecture
forgeyard-cas-gc
Phases:
snapshot roots
↓
mark reachable
↓
wait grace
↓
recheck
↓
sweep
132. Why Grace Period
Protects against:
metadata/CAS race
in-flight upload
eventual replication
temporary orphan
133. GC Epoch
#![allow(unused)]
fn main() {
pub struct GcEpoch(U64);
}
Can help mark consistency.
134. GC Root Snapshot
Metadata store supplies consistent root view.
135. Recursive Mark
Manifests/trees/chunk manifests reference child objects.
GC follows closure.
136. Cycle Handling
CAS manifests should ideally be DAGs.
But marker must protect against cycles/malformed manifests.
137. Manifest Trust
Only parse manifests of known schema/media type.
Untrusted arbitrary blobs are not traversed.
138. GC Safety
Never delete object if:
legal hold
pinned
release critical
recently written within grace
replication repair pending
139. Cache GC
Cache policy may evict mappings independently.
CAS bytes become collectible only if no other roots.
140. Local LRU Eviction
Runner-local L1 cache can use:
LRU/size pressure
independently from durable CAS GC.
141. Local Cache Is Not Durability
Deleting L1 is safe if durable backend exists.
142. Offline Standalone
In Mode 1, local CAS may be only durable store.
GC must therefore respect all local metadata roots.
143. Standalone CAS Backup
Backup can include:
all rooted objects
manifest
metadata backup
144. Air-Gap Architecture
forgeyard-cas-airgap
Exports selected object closure.
145. Air-Gap Bundle
#![allow(unused)]
fn main() {
pub struct AirgapBundleManifest {
pub schema: AirgapSchemaVersion,
pub roots: Vec<CasObjectRef>,
pub objects: Vec<CasObjectRef>,
pub provenance: Vec<CasObjectRef>,
}
}
146. Export Flow
select roots
↓
walk closure
↓
verify
↓
write deterministic bundle
↓
sign bundle manifest optionally
147. Import Flow
verify bundle
↓
verify every object digest
↓
ingest CAS
↓
register metadata if authorized
148. Bundle Format
Possible:
tar.zst
Forgeyard-native packed stream
Transport format not object identity.
149. Bundle Reproducibility
Bundle ordering/timestamps should be deterministic where practical.
150. Integrity Service
forgeyard-cas-integrity
Responsibilities:
full scan
sample scan
manifest verification
replica comparison
repair
quarantine
151. Integrity States
#![allow(unused)]
fn main() {
pub enum ObjectIntegrity {
Unknown,
Verified,
Corrupt,
Missing,
Quarantined,
}
}
152. Integrity Audit
Enterprise deployments should periodically verify cold objects.
153. Bit Rot
Detected by digest mismatch.
Repair from healthy replica.
154. Replica Repair
replica A corrupt
replica B healthy
↓
copy B -> A
↓
verify
155. No Healthy Replica
If object required:
critical data loss alert
Do not fabricate.
156. Quarantine
Corrupt backend/object path is isolated from normal reads.
157. Backend Health
#![allow(unused)]
fn main() {
pub enum CasHealth {
Healthy,
Degraded,
ReadOnly,
Unavailable,
}
}
158. Read-Only Backend
Useful during:
maintenance
credential issue
capacity incident
Tiered CAS can continue reads.
159. Backpressure
CAS writes must apply bounded concurrency.
Avoid saturating:
disk
network
object-store requests
memory
160. Transfer Scheduler
Can prioritize:
job critical input
live log
release artifact
background replication
GC scan
161. Priority Classes
#![allow(unused)]
fn main() {
pub enum TransferPriority {
Interactive,
JobCritical,
ReleaseCritical,
Normal,
Background,
}
}
162. Bandwidth Limits
Per runner/site/backend.
163. Concurrency Limits
Per:
tenant
backend
runner
object size class
164. Memory Limits
Streaming buffer size bounded.
165. Zero-Copy / Efficient I/O
Where possible:
sendfile/splice
io_uring optional
mmap carefully
are performance optimizations.
Not correctness dependencies.
166. Tokio / Rayon Split
Tokio:
network
async filesystem orchestration
object-store requests
Rayon:
hashing large buffers
manifest canonicalization
compression if CPU-heavy
Use bounded pools.
167. I/O Uring
Optional Linux optimization behind:
io-uring
feature.
Fallback must remain correct.
168. Chunk Hash Parallelism
Parallel compute allowed while preserving order/whole hash.
169. Temporary Disk
Large transfers may need staging.
Runner capability reports:
temp disk available
170. Streaming Without Staging
Prefer when backend/protocol supports verified streaming safely.
But if output digest unknown until end, final visibility must wait for successful completion.
171. Upload Intent
Artifact service may create:
#![allow(unused)]
fn main() {
pub struct UploadIntent {
pub id: UploadIntentId,
pub expected_size: Option<ByteSize>,
pub expected_digest: Option<Digest>,
pub expires_at: Timestamp,
}
}
172. Upload Intent Is Metadata
CAS itself can accept direct puts.
Upload intent coordinates user/agent API lifecycle.
173. Direct-to-Object-Store Upload
Possible optimization:
daemon creates scoped upload authorization
client uploads directly
daemon verifies completion/digest
174. Presigned URLs
May be used for compatible object stores.
But:
short TTL
scoped object key
expected size/digest
no list permission
175. Client Trust
Never trust client “upload complete.”
Server verifies object metadata/content digest according to policy.
176. Download Authorization
Artifact service authorizes access first.
Then may return:
proxied stream
short-lived signed download
177. CAS API Is Not Public Artifact API
Users should not generally fetch arbitrary digest if they know it.
Access goes through artifact/source authorization.
178. Object Enumeration
CAS backend API for admin/internal may enumerate.
Do not expose globally to tenant users.
179. Media Type
#![allow(unused)]
fn main() {
pub struct MediaType(BoundedString);
}
Examples:
application/octet-stream
application/vnd.forgeyard.tree+postcard
application/vnd.forgeyard.manifest+postcard
180. Schema Registry
Structured CAS objects should have explicit media/schema IDs.
181. Postcard Structured Objects
Internal manifests may serialize using canonical/versioned Postcard-compatible representation.
But default serde output must not be assumed canonical without explicit design.
182. Canonical Manifest Encoding
Implement dedicated encoder if object identity depends on it.
183. Manifest Upgrade
Old manifest schema must remain readable while retained.
New schema gets new object ID.
184. Source Tree Upgrade
Changing tree schema produces new tree/snapshot identity.
Migration must be explicit.
185. Artifact Download Naming
Friendly filename is metadata:
forgeyard-linux-x86_64.tar.zst
not CAS key.
186. Content-Disposition
Artifact API can provide desired filename safely.
187. Duplicate Friendly Names
Allowed if underlying artifact IDs differ.
188. Artifact Index
Metadata DB supports searches:
project
run
job
type
target
created_at
release
CAS does not.
189. Artifact Lifecycle
Pending
Available
Quarantined
Expired
Deleted
Bytes may remain until GC after logical deletion.
190. Artifact Quarantine
Security scanner or integrity failure can block download/promotion.
191. Malware/Policy Scan
Artifact service can attach scan evidence.
CAS stores bytes/evidence.
192. Retention Override
Release promotion can upgrade artifact retention:
Cache -> Release
without rewriting bytes.
193. Same Bytes, New Meaning
Same object can be:
build artifact
release artifact
through different metadata references.
194. Artifact Lineage
Metadata tracks:
producer job
source snapshot
derivation
parent artifact
not CAS itself.
195. Provenance Closure
Release verification can fetch:
artifact
SBOM
provenance
source snapshot
toolchain refs
through metadata + CAS closure.
196. Data Plane Security
Threats:
content substitution
corrupt backend
unauthorized object access
cross-tenant existence leak
path traversal in materialization
archive bomb
malicious manifest
resource exhaustion
P2P malicious peer
presigned URL leakage
197. Content Substitution Defense
Digest verification.
198. Unauthorized Access Defense
Artifact/source authorization outside raw CAS.
199. Path Traversal Defense
Tree materialization validates canonical paths.
200. Archive Bomb Defense
Archive extraction is separate safe unpacking subsystem with size/file count limits.
201. Manifest Bomb Defense
Manifest parser limits:
max entries
max depth
max total closure
202. Recursive Closure Limits
Prevent malicious manifest DAG causing unbounded traversal.
203. P2P Peer Authorization
Peers authenticate via Forgeyard/transport identity.
Do not allow arbitrary internet peer to query private CAS.
204. Signed URL Leakage
Short TTL and narrow scope reduce impact.
Audit issuance for sensitive release artifacts.
205. Encryption in Transit
QUIC/TLS
HTTPS
cloud backend TLS
required in distributed production.
206. Encryption at Rest
Delegated to:
disk encryption
object-store server-side encryption
KMS-backed storage policy
Forgeyard tracks policy but does not invent custom crypto storage format initially.
207. Client-Side Encryption
Optional future capability for highly sensitive artifacts.
Complex because it affects dedup/search/range access.
Not default architecture.
208. Secret Data
Secrets must never be uploaded into normal CAS by design.
209. Secret Scan
Artifact/source scan may detect accidental secrets and quarantine according to policy.
210. Logs and Secrets
Log redaction occurs before durable storage where possible.
But treat logs as potentially sensitive.
211. Audit
CAS admin operations:
delete
repair
quarantine
air-gap export
retention pin
must be audited.
212. Normal Reads
Do not audit every internal byte read at high volume unless compliance requires it.
Use structured access logs selectively.
213. Metrics
Examples:
cas_put_bytes
cas_get_bytes
cas_put_latency
cas_get_latency
cas_hit
cas_miss
cas_integrity_failure
cas_replication_lag
cas_gc_mark_count
cas_gc_delete_count
cas_local_cache_hit
cas_p2p_hit
cas_backend_errors
214. Backend Metrics
Tag by:
backend ID
region
operation
status
Avoid high-cardinality object IDs in metrics.
215. Tracing
Spans:
cas.head
cas.get
cas.put
cas.verify
cas.replicate
cas.gc.mark
cas.gc.sweep
cas.airgap.export
216. Logging
Logs include object digest prefix only if useful and safe.
No secret URLs.
217. Health Check
Per backend:
connectivity
read test
write test optional
latency
credential validity
capacity
218. Readiness
Daemon can remain ready if one non-authoritative cache tier fails.
Not ready if required durable CAS is unavailable for operations that require writes.
219. Degraded Mode
Example:
Iroh down
S3 healthy
system remains healthy/degraded performance only.
220. Critical Degraded Mode
Example:
durable backend read-only
allow reads/builds from existing data but block new durable release artifacts if policy requires.
221. Capacity Monitoring
Local CAS:
free bytes
used bytes
inode pressure
Cloud:
quota/API throttling/cost metrics
222. Disk Pressure
Local cache eviction before catastrophic full disk.
223. Reserved Space
Keep emergency reserve to allow metadata/logging/cleanup.
224. File Descriptor Pressure
Large parallel transfers must use bounded descriptors.
225. Object Count Scaling
Directory layout and DB indexes must handle millions/billions of objects in enterprise scale.
226. Backend Enumeration Scaling
GC should not rely on naive full listing from slow backend if metadata/mark indexes can reduce work.
227. Mark Index
Optional DB/state can track known object refs and last seen root epoch.
But CAS identity remains independent.
228. GC Source of Truth
Metadata roots + known structured object graph.
Not raw backend last-access timestamp.
229. Access Timestamp
Avoid updating “last accessed” metadata for every read if it creates heavy write load.
L1 cache can track locally.
230. Retention by Metadata
Better than access-based GC for durable artifacts.
231. Background Tasks
replication
integrity scan
GC
orphan multipart cleanup
tier promotion cleanup
local cache eviction
run through worker/reconciliation subsystem.
232. Task Idempotency
All background tasks must tolerate retry.
233. Replication Idempotency
Copying existing object to target is safe after digest verification.
234. GC Idempotency
Deleting already-missing eligible object is success/no-op.
235. Repair Idempotency
Repeated repair should converge.
236. CAS Error Model
#![allow(unused)]
fn main() {
pub enum CasError {
NotFound,
AlreadyExists,
DigestMismatch,
SizeMismatch,
Corrupt,
Quarantined,
PermissionDenied,
Unavailable,
Timeout,
CapacityExceeded,
RateLimited,
Unsupported,
InvalidManifest,
Internal,
}
}
237. Retry Classification
NotFound -> no retry unless replica lookup
RateLimited -> backoff
Unavailable -> backoff/reconcile
DigestMismatch -> no blind retry from same source
CapacityExceeded -> reroute/operator
Corrupt -> quarantine/repair
238. Backend Error Translation
Cloud-specific errors stay adapter-local.
239. Download Fallback
Tiered backend:
backend A corrupt
↓
quarantine
↓
try backend B
240. Upload Fallback
If durable backend A unavailable and policy allows B:
reroute
If required replication impossible:
object may be temporarily available but durability requirement unmet
Metadata should expose state.
241. Durability State
#![allow(unused)]
fn main() {
pub enum ObjectDurabilityState {
Pending,
Satisfied,
Degraded,
Violated,
}
}
242. Release Gate
Release promotion may require:
DurabilityState::Satisfied
for all critical objects.
243. Source Durability
Imported source snapshots needed for reproducibility should be durable according to project policy.
244. Cache Object Durability
May remain Cache class.
245. Artifact Manifest Example
(
schema: 1,
artifact: (
primary: (
digest: "blake3:...",
size: 12582912,
),
attachments: [
(
role: "sbom",
digest: "blake3:...",
),
(
role: "debug-symbols",
digest: "blake3:...",
),
],
),
)
RON here is illustrative/debug representation; internal manifest identity uses canonical binary encoding.
246. CAS Configuration Example
(
cas: (
backends: [
(
id: "local",
kind: Local,
path: "/var/lib/forgeyard/cas",
),
(
id: "durable",
kind: S3,
bucket: "forgeyard-cas",
region: "region-a",
credential: Secret("cas/s3"),
),
],
tiers: [
"local",
"iroh",
"durable",
],
),
)
247. Standalone Configuration
(
cas: (
backends: [
(
id: "local",
kind: Local,
path: Auto,
),
],
durable_backend: "local",
),
)
248. Enterprise Configuration
(
cas: (
durable: [
"region-a",
"region-b",
],
p2p: (
enabled: true,
),
replication: (
release_critical: (
regions_required: 2,
),
),
),
)
249. CAS CLI
forgeyard cas status
forgeyard cas doctor
forgeyard cas put
forgeyard cas get
forgeyard cas head
forgeyard cas verify
forgeyard cas replicate
forgeyard cas repair
forgeyard cas gc
forgeyard cas pin
forgeyard cas unpin
forgeyard cas export
forgeyard cas import
forgeyard cas stats
250. cas put
Admin/dev command.
Normal artifact/source ingestion goes through subsystem services.
251. cas verify
Modes:
object
manifest closure
backend sample
full backend
252. cas gc
Support:
plan
mark
dry-run
sweep
Production should default to dry-run/plan before destructive first use.
253. cas repair
Find healthy replica and restore corrupt/missing target.
254. cas stats
Shows:
objects
bytes
backend usage
replication
GC candidates
local hit rate
P2P hit rate
255. CAS Doctor
Categories:
REQUIRED
OPTIONAL
PERFORMANCE
SECURITY
Examples:
REQUIRED: durable backend writable
SECURITY: TLS verification disabled
PERFORMANCE: local cache unavailable
OPTIONAL: Iroh disabled
256. Artifact CLI
forgeyard artifacts list
forgeyard artifacts show
forgeyard artifacts download
forgeyard artifacts verify
forgeyard artifacts pin
forgeyard artifacts provenance
257. Public Artifact API
Potential:
GET /v1/artifacts/{id}
GET /v1/artifacts/{id}/download
GET /v1/artifacts/{id}/manifest
GET /v1/artifacts/{id}/provenance
No raw unauthenticated CAS digest API.
258. Internal CAS API
Internal daemon/agent:
HEAD object
GET object
PUT object
batch missing
transfer session
over authenticated transport.
259. Direct Worker Access
Agent may access object store directly via scoped credentials/presigned requests.
But metadata/business authorization remains daemon-driven.
260. Credential Scope
Runner credentials should permit only:
specific prefix/object
short duration
required operation
where backend supports it.
261. Build Input Materialization
Runner flow:
job lease
↓
input manifest
↓
batch missing local
↓
fetch CAS
↓
verify
↓
materialize read-only source/toolchain/input paths
262. Output Upload
execute
↓
capture declared outputs
↓
hash/tree
↓
upload CAS
↓
verify
↓
send output refs
↓
daemon transactionally commits job result metadata
263. Lost Agent During Upload
Objects already uploaded may remain orphaned.
GC handles them after grace.
Job result not committed without valid lease/attempt.
264. Duplicate Upload
Safe.
Same bytes -> same ID.
265. Stale Job Completion
Even if CAS upload succeeds, daemon rejects stale lease completion.
Objects remain unreferenced/GC-eligible.
266. Build Cache Publish
Only publish action-cache mapping after all output objects verified/available.
267. Reproduction Output
Independent reproducer writes outputs to same CAS.
If bytes equal:
same CAS IDs
naturally.
268. Repro Mismatch
Different output objects preserved for diff/quarantine evidence.
269. Binary Diff Evidence
Store diff reports in CAS.
270. Release Promotion
Promotion changes metadata/retention/policy state.
Does not copy/rebuild bytes unnecessarily.
271. Cross-Region Promotion
May require replication before promotion completes.
272. Signing
Unsigned object:
CAS A
Signed object:
CAS B
Signature changes bytes, therefore new content identity.
273. Notarization
Notarized/stapled artifact likewise becomes new object if bytes change.
274. Provenance Relationship
Metadata links:
unsigned -> signed -> notarized
275. OCI Integration
OCI layers/manifests may be stored/aliased via SHA-256.
Forgeyard CAS can maintain internal BLAKE3 alias.
276. RBE Integration
Bazel RBE typically uses SHA-256 digests.
Adapter maps:
SHA-256 RBE digest
↔
Forgeyard object alias
277. Alias Lookup
Efficient alias index may live in metadata DB.
CAS backend does not need separate duplicate object.
278. Alias Collision Safety
Cryptographic collisions are treated as catastrophic integrity events.
Never map two different byte contents to same alias.
279. Backend Migration
Moving from local/S3 provider A to provider B:
replicate objects
verify
update backend policy
drain old
No domain object IDs change.
280. Backend Re-Key/Encryption Change
Storage implementation may rewrite physical object bytes encrypted at rest, while logical CAS content stays same.
281. Region Migration
Same.
282. Cost Optimization
Tiered policy may move cold cache objects to cheaper backend.
Release-critical retention policy remains stronger.
283. Storage Class
Cloud-specific storage classes stay adapter configuration.
284. Cold Retrieval
If object in archival storage:
restore pending
must be represented explicitly.
Do not pretend instant availability.
285. Availability State
#![allow(unused)]
fn main() {
pub enum ObjectAvailability {
Immediate,
Restoring,
Unavailable,
}
}
286. Scheduler Awareness
Do not schedule job requiring cold object until available unless workflow tolerates delay.
287. Prewarming
Before release/test wave:
prewarm toolchains/dependencies
to runner/site caches.
288. Predictive Cache
Can suggest prefetch.
Optimization only.
289. Site Cache
Optional shared LAN CAS proxy.
Same backend trait.
290. Edge Runner
Remote runners can use local site cache with central durable fallback.
291. Disconnected Runner
A fully offline runner can execute only if required CAS closure already present/imported.
292. Air-Gap Runner
Uses imported bundle/local CAS.
293. Source Snapshot Bundle
Air-gap source bundle includes source tree closure and provenance.
294. Toolchain Bundle
Same for toolchains/dependencies.
295. Full Build Bundle
Can combine:
source
toolchain
dependencies
pipeline inputs
for disconnected reproducibility.
296. Object Graph
Generic structured objects form DAG:
root manifest
├── object A
├── tree B
│ ├── blob C
│ └── blob D
└── evidence E
297. Graph Traversal API
#![allow(unused)]
fn main() {
pub trait CasGraph {
async fn children(
&self,
object: &CasObjectId,
) -> Result<Vec<CasObjectRef>, CasError>;
}
}
Only for known structured object types.
298. Closure Export
root(s)
↓
traverse
↓
deduplicate
↓
ordered export
299. Closure Size Calculation
Useful before:
air-gap export
replication
download
300. Storage Quotas
Optional per tenant/project:
logical artifact usage
cache usage
release storage
301. Physical vs Logical Usage
Dedup means physical bytes ≠ logical billed usage.
Define policy explicitly.
302. Default Quota Accounting
For SaaS/enterprise:
logical referenced bytes
may be easier/fairer than physical dedup share.
303. Quota Enforcement
Do not block critical release retention unexpectedly.
Use warnings/reserved policy.
304. Cache Quota
Evict cache first.
305. Release Quota
Requires explicit operator/admin policy.
306. Legal Hold
CAS object becomes non-GC while any legal-hold metadata root exists.
307. Object Deletion API
Raw delete should be restricted to:
GC
repair/admin
Normal users delete metadata references.
308. Secure Erasure
Cloud/object stores may not guarantee immediate physical erasure due to replication/versioning.
Document backend semantics.
309. Versioned Buckets
If object-store versioning enabled, GC may need lifecycle configuration to remove old physical versions eventually.
310. Object Lock
Cloud WORM/object-lock can protect release/audit artifacts optionally.
Do not require for all deployments.
311. Supply Chain WORM
High-assurance deployment may store provenance/signatures in immutable storage class.
312. CAS Testkit
forgeyard-cas-testkit/src/
├── lib.rs
├── put_get.rs
├── duplicate.rs
├── integrity.rs
├── stream.rs
├── range.rs
├── large.rs
├── concurrent.rs
├── missing.rs
├── corruption.rs
├── manifest.rs
├── gc.rs
└── replication.rs
313. Backend Conformance
Every backend must pass:
- put/get exact bytes;
- duplicate put;
- missing object;
- digest mismatch;
- large streaming object;
- concurrent put same ID;
- interrupted upload;
- read verification;
- conditional semantics;
- health/error translation.
314. Tiered CAS Tests
Test:
L1 miss/L2 hit
corrupt L1 fallback
P2P hit
durable fallback
promotion
315. GC Tests
- rooted object retained;
- child of rooted manifest retained;
- orphan retained during grace;
- orphan deleted after grace;
- legal hold retained;
- concurrent new reference protected.
316. Replication Tests
- required replica count achieved;
- corrupt replica repaired;
- region outage degrades state;
- release gate blocks insufficient durability.
317. Air-Gap Tests
- export closure complete;
- deterministic manifest;
- tampered object rejected;
- import deduplicates existing objects;
- build succeeds offline from imported closure.
318. Security Tests
- unauthorized artifact cannot download;
- raw digest cannot bypass ACL;
- P2P malicious bytes rejected;
- manifest depth bomb rejected;
- unsafe tree path rejected;
- presigned URL expires;
- secret value never enters normal CAS path.
319. Performance Benchmarks
BLAKE3 throughput
local put/get
parallel upload
manifest encode/decode
tree construction
tier lookup
chunk transfer
320. Large Object Benchmark
Test:
1 GB+
without whole-object memory loading.
321. Many Small Object Benchmark
Important for source trees/package managers.
322. Metadata Overhead
Avoid one SQL row per tiny source blob unless necessary.
CAS object index strategy should be scalable.
323. Local CAS Index
May derive path from digest without separate DB index.
324. Cloud Object Index
Same.
Metadata store only tracks semantic refs and optional replica status.
325. Object Existence Batch
Backend should support efficient batch existence if possible.
Fallback parallel bounded heads.
326. Head Storm Avoidance
For huge closures, use manifests/backend index/bloom hints where safe.
327. Transfer Plan
#![allow(unused)]
fn main() {
pub struct TransferPlan {
pub required: Vec<CasObjectRef>,
pub missing: Vec<CasObjectRef>,
pub priority: TransferPriority,
}
}
328. Transfer Resume State
Stored locally/ephemerally.
Not durable business metadata unless long-lived session requires it.
329. Agent CAS Cache
Directory:
$FORGEYARD_AGENT_DATA/cas/
Separate from workspace.
330. Workspace Materialization
Never execute directly inside raw CAS object path if process could mutate it.
Materialize/read-only mount.
331. Immutable Store Paths
Toolchain/dependency trees can be mounted read-only.
332. Copy-on-Write
Optional optimization for writable build inputs.
333. Hardlinks/Reflinks
Possible local optimization.
Must preserve CAS immutability.
Never let build mutate shared CAS file via hardlink.
334. Reflink Preferred
If filesystem supports copy-on-write safely.
335. Hardlink Hazard
Writable hardlink can corrupt CAS.
Do not use without read-only enforcement.
336. Filesystem Verification
Local CAS can mark files read-only.
Still verify permissions/security.
337. Materialization Cache
Separate from CAS.
Can cache extracted tree layout.
Must be invalidatable and verified against object ID.
338. Tree Materialization
tree manifest
↓
create temp dir
↓
materialize entries
↓
verify
↓
atomic publish cache path
339. Tree Cache Key
TreeObjectId + materialization policy
340. Platform Semantics
Windows/macOS/Linux differ in:
symlink
executable bit
case sensitivity
path rules
Canonical tree remains neutral; materializer enforces compatibility.
341. Incompatible Tree
Example case-collision on Windows:
materialization error
not silent overwrite.
342. Long Paths
Platform materializer handles/validates.
343. Extended Attributes
Default:
not part of generic CAS tree
unless artifact/platform package explicitly models them.
344. macOS Bundle Metadata
Package builder should encode required metadata in final artifact/archive format.
Not rely on host filesystem xattrs unless explicitly captured.
345. Executable Bit
Explicit tree field.
346. Ownership UID/GID
Not generic source/build tree identity.
Package format may add ownership metadata at packaging step.
347. Timestamps
Not generic tree identity.
Deterministic package builder sets them explicitly where required.
348. CAS Schema Versioning
Every structured object format has independent schema version.
349. CAS Protocol Versioning
Network transfer protocol separately versioned.
350. Backend Configuration Version
Config schema handles backend settings evolution.
351. Migration of Structured Objects
Usually:
old objects remain readable
new writes use new schema
Avoid rewriting entire CAS unless necessary.
352. Schema Decoder Registry
Known structured media types map to decoder versions.
353. Unknown Structured Object
Treat as opaque blob unless operation requires traversal.
GC roots cannot traverse unknown manifest type automatically.
Such objects must be retained via explicit root.
354. Artifact Manifest Compatibility
Keep old readers for supported retained release history.
355. Storage Backend Migration Tool
forgeyard cas replicate --from A --to B
forgeyard cas verify --backend B
forgeyard cas drain A
356. Drain Mode
Backend states:
#![allow(unused)]
fn main() {
pub enum BackendLifecycle {
Active,
ReadOnly,
Draining,
Disabled,
}
}
357. Drain Behavior
No new writes.
Reads allowed until replicas complete.
358. Backend Removal
Only after:
required objects replicated
metadata updated
verification complete
359. Cost Class
#![allow(unused)]
fn main() {
pub enum CostClass {
Local,
Low,
Standard,
High,
Archive,
}
}
Scheduler/storage policy may use it.
360. Latency Class
#![allow(unused)]
fn main() {
pub enum LatencyClass {
MemoryLike,
LocalDisk,
Lan,
Regional,
Remote,
Archive,
}
}
361. Backend Selection
Policy considers:
durability
region
cost
latency
object class
362. No Business Semantics in Backend Selection
Backend doesn’t know “release.”
Storage policy gets durability class from artifact/source metadata.
363. Data Plane API Layer
Potential internal service:
crates/data-plane/
├── forgeyard-data-plane/
├── forgeyard-data-plane-service/
└── forgeyard-data-plane-policy/
Optional if orchestration complexity warrants.
364. Initial Recommendation
Do not create separate data-plane service crate until CAS/artifact orchestration grows.
Start with CAS + artifact services.
365. Artifact Store Interface
#![allow(unused)]
fn main() {
#[async_trait]
pub trait ArtifactStore {
async fn register(
&self,
artifact: NewArtifact,
) -> Result<ArtifactRecord, ArtifactError>;
async fn resolve(
&self,
id: ArtifactId,
) -> Result<ArtifactRecord, ArtifactError>;
}
}
Metadata implementation uses ForgeyardStore.
Bytes implementation uses CasBackend.
366. Artifact Service
Coordinates:
authorization
CAS
metadata
retention
provenance
download
367. Artifact Upload Transaction
Correct:
create pending artifact metadata
↓
upload object
↓
verify
↓
transactionally mark Available + object ref
or upload first then register; exact flow depends API.
368. Pending Upload Cleanup
Expired pending artifacts removed.
Orphan CAS handled by GC.
369. Artifact Download
authorize
↓
resolve artifact
↓
resolve CAS ref
↓
stream
370. Integrity Header
Download API can expose digest headers.
371. Client Verification
CLI verifies downloaded artifact digest automatically.
372. Browser Download
Browser may rely on HTTPS + server verification, but checksum visible.
373. Release Verification CLI
forgeyard release verify
fetches artifact/provenance/signature refs and verifies content.
374. Observability Dashboard
CAS UI:
backend health
storage usage
hit rate
P2P hit rate
replication lag
GC status
integrity failures
375. Artifact UI
Shows:
artifact ID
kind
digest
size
producer
source snapshot
retention
durability
attachments
provenance
376. Raw CAS UI
Admin-only object inspector.
377. Object Inspector
Displays:
digest aliases
size
replicas
integrity
roots/reference count summary
structured type
378. Reference Summary
Do not compute expensive full reverse refs live without index.
May show known semantic references.
379. GC UI
Admin:
last mark
next sweep
candidate bytes
deleted bytes
errors
380. Replication UI
Shows object classes/regions, not individual millions of objects by default.
381. Alerting
Alert on:
durable backend unavailable
release durability violation
integrity mismatch
replication backlog
local disk nearly full
GC stalled
multipart leak
382. SLOs
Possible:
artifact durability
download availability
replication completion
Deployment-specific values.
383. Backup Relationship
CAS backup may be:
replication to independent backend
object-store versioning
snapshot/export
Metadata DB backup alone is insufficient.
384. Restore
After metadata restore:
verify referenced CAS objects
repair missing from replicas/backups
reconcile durability state
385. Disaster Recovery
If regional CAS lost:
route reads to replica
recreate region
replicate back
Object IDs unchanged.
386. Standalone Disaster Recovery
Restore local DB + local CAS backup.
387. Partial Recovery
If metadata survives but some cache objects lost:
cache miss
rebuild/refetch
If release/source critical object lost:
data loss incident
unless replica/backup exists.
388. Data Importance Classification
#![allow(unused)]
fn main() {
pub enum ObjectClass {
RebuildableCache,
SourceCritical,
ToolchainCritical,
ArtifactNormal,
ReleaseCritical,
AuditCritical,
}
}
Used to derive durability/retention policy.
389. Rebuildable Cache
Can be discarded.
390. Source Critical
Needed for reproducibility/history.
391. Toolchain Critical
Needed to reproduce locked builds.
392. Audit Critical
Evidence may require long retention.
393. Policy Mapping
ObjectClass
↓
DurabilityClass
RetentionPolicy
ReplicationPolicy
IntegrityFrequency
394. Default Policy Example
RebuildableCache -> 1 copy, TTL
ArtifactNormal -> durable 1 region
SourceCritical -> durable 2 copies
ReleaseCritical -> 2 regions + pin
AuditCritical -> durable + legal/compliance retention
Deployment can customize.
395. Implementation Phase 1 — Core CAS
Implement:
CasObjectId
CasObjectRef
CasBackend
streaming put/get
BLAKE3 verification
local backend
Exit:
standalone can persist/retrieve immutable objects
396. Phase 2 — Manifest / Tree
Implement:
canonical manifest
tree manifest
source/output tree capture
recursive closure
397. Phase 3 — Artifact Service
Implement:
ArtifactId
artifact metadata
pending/available lifecycle
upload/download
retention
398. Phase 4 — Transfer
Implement:
batch missing
QUIC streaming
resumable large transfers
agent local cache
399. Phase 5 — Tiered CAS
Implement:
L1 local
durable backend
promotion/fallback
400. Phase 6 — S3-Compatible
Implement first production remote durable backend.
Then GCS/Azure adapters.
401. Phase 7 — Iroh
Add P2P acceleration after durable CAS semantics are stable.
402. Phase 8 — Replication
Implement:
replica tracking
durability policy
regional replication
repair
403. Phase 9 — GC / Retention
Implement:
root snapshot
mark
grace
sweep
pin/legal hold
404. Phase 10 — Logs / Reports
Integrate:
log chunks
test reports
coverage
SBOM/provenance
405. Phase 11 — Air-Gap
Implement closure export/import.
406. Phase 12 — Hardening
Implement:
integrity scans
capacity controls
quota
security fuzzing
large-scale performance
multi-region failure tests
407. Acceptance Tests
- Same bytes always produce same CAS ID.
- Different bytes produce different CAS ID.
- Duplicate upload does not duplicate logical object.
- Digest mismatch is rejected.
- Partial local write never becomes visible.
- Large object streams without full memory buffering.
- Source tree manifest is deterministic.
- Case/path incompatibility fails materialization safely.
- Artifact metadata never stores artifact bytes.
- Missing CAS object invalidates cache mapping.
- Local L1 miss falls back to durable backend.
- Corrupt L1 object falls back and repairs.
- P2P malicious bytes fail digest verification.
- Iroh outage does not break durable CAS correctness.
- Required release replicas gate promotion.
- GC preserves rooted manifest closure.
- GC deletes orphan after grace.
- Legal hold prevents GC.
- Interrupted multipart upload is cleaned.
- Air-gap export/import preserves object IDs.
- Offline runner can build from imported closure.
- Stale job output upload remains unreferenced and GC-eligible.
- Signed artifact gets new content ID.
- BLAKE3↔SHA-256 alias is verified.
- Unauthorized user cannot fetch arbitrary object by digest.
- Tenant isolation prevents existence leakage through public APIs.
- Large manifest/depth bombs are bounded.
- CAS backend migration preserves object IDs.
- Metadata restore can verify referenced object availability.
- Standalone local CAS works with no network/cloud.
408. Production Readiness Gates
Do not call CAS/data plane production-ready until:
local backend durable
streaming works
digest verification works
canonical manifest/tree stable
artifact metadata separation works
agent transfer works
durable remote backend works
tier fallback works
GC is safe
retention/pin works
integrity repair works
security boundaries tested
backup/restore relationship documented
metrics/doctor exist
P2P, multi-region, and advanced chunking can mature after core production readiness.
409. Architectural Invariants
- CAS object identity is content-derived.
- CAS objects are immutable.
- Business meaning is not CAS identity.
- Metadata and bytes are separate.
- BLAKE3 is internal default.
- SHA-256 aliases are verified.
- Large objects stream.
- Partially written objects never become canonical.
- Every backend verifies/participates in integrity policy.
- Iroh/P2P is acceleration, not authority.
- Local cache is not durability unless standalone policy says so.
- Release-critical objects have explicit durability requirements.
- Source snapshots and toolchains use same CAS foundation.
- Action cache maps keys to CAS outputs; cache does not store bytes separately.
- GC derives liveness from metadata roots and structured object closure.
- GC uses grace periods.
- Legal hold/pin overrides GC.
- Raw CAS APIs do not bypass artifact/source authorization.
- Secrets never intentionally enter normal CAS.
- Structured object schemas are versioned.
- Canonical encoding is deterministic.
- Materialization never allows path traversal.
- CAS backend implementations do not leak into domain services.
- Backend migration does not change object IDs.
- Multi-region replication is policy, not identity.
- Signed/notarized changed bytes get new IDs.
- Restore includes CAS integrity reconciliation.
- Background replication/GC/repair are idempotent.
- No advanced performance feature is a correctness dependency.
- The same CAS architecture works from one local disk to enterprise multi-region storage.
410. Final Target Architecture
Forgeyard Services
│
▼
Artifact / Source
Metadata
│
▼
CasObjectRef
│
▼
Forgeyard CAS API
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
Local L1/L2 Iroh/P2P Durable Object
│ │ Storage
└───────────────────┼───────────────────┘
▼
Digest Verification
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Replication Retention GC
│ │ │
└─────────────┼─────────────┘
▼
Integrity / Repair
411. Final Architectural Position
Object ingestion:
bytes
↓
stream/hash
↓
verify expected digest/size
↓
store immutable object
↓
CasObjectRef
↓
register semantic metadata
Build input:
SourceSnapshot / Toolchain / Dependencies
↓
CAS closure
↓
runner local missing check
↓
tiered fetch
↓
digest verification
↓
read-only materialization
Build output:
declared output
↓
canonical capture
↓
CAS object/tree
↓
artifact metadata
↓
retention/durability policy
Durability:
object
↓
replication policy
↓
verified replicas
↓
DurabilityState::Satisfied
Cleanup:
metadata roots
↓
mark structured closure
↓
grace
↓
recheck
↓
sweep unreferenced objects
The key guarantee is:
Forgeyard can move the same immutable object across local disk, P2P peers, cloud object stores, regions, caches, backups, and air-gapped bundles without changing its content identity or the business meaning attached to it.
412. New-Repository Sequence
The new Forgeyard implementation sequence is now:
01 Core Domain & Foundation
02 Storage & Metadata
03 CAS & Artifact Data Plane
04 Pipeline IR / Parsing / Planning
05 Run / Job State Machine
06 Scheduler
07 Runner / Agent
08 Sandbox & Executor
09 Transport / QUIC / Protocol
10 Events / Reconciliation
11 Policy / Authorization / Identity
12 Secrets & Trust
13 Supply Chain / SBOM / Provenance / Signing
14 Packaging
15 Release
16 Deployment
17 Observability / Health / Doctor
18 API / Axum
19 Dioxus UI
20 Device Lab
21 SCM Provider Integrations
22 HA / Coordination / Raft
23 RBE Interop
24 Plugin / Extension Architecture
25 Operations / Backup / Upgrade / DR
26 Self-Hosting / Bootstrap / Release of Forgeyard
The already-completed hermetic, VCS-neutral, Change Proposal, and language ecosystem architectures plug into this sequence at their respective integration points.