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
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# ADR-0008 — Local-first release and enrollment contract family

Status: Proposed

## Context

ADR-0007 reserved the local-first control-node and image-promotion seam in `SourceOS-Linux/sourceos-spec`.

What remains missing is the first machine-readable contract family needed to make that seam executable for the thin local-first lifecycle slice:

- assign a release to a device or cohort
- optionally authorize a boot/install or recovery path
- enroll a device or session against that assignment
- realize operator/user experience and isolation posture
- emit a post-apply fingerprint suitable for compliance and rollback decisions

Without a canonical object family here, downstream repos risk re-inventing overlapping structures for release assignment, enrollment, host realization, and attestation.

## Decision

Reserve and introduce the first local-first control-plane contract family in this repository.

The initial object family is:

- `ExperienceProfile`
- `IsolationProfile`
- `ReleaseSet`
- `BootReleaseSet`
- `EnrollmentToken`
- `Fingerprint`

These objects define the minimum SourceOS local-first lifecycle seam for:

1. profile selection
2. release assignment
3. boot/recovery authorization when needed
4. enrollment and one-time redemption semantics
5. post-apply attestation and compliance comparison

## Repo ownership split

This repository owns:

- machine-readable schemas
- normative object semantics
- example payloads for the local-first lifecycle slice

This repository does not own:

- runtime execution enforcement (`SocioProphet/agentplane`)
- workspace/fabric choreography (`SocioProphet/sociosphere`)
- transport binding (`SocioProphet/TriTRPC`)

## Consequences

### Positive

- gives SourceOS a canonical typed object family for local-first release control
- avoids parallel release/enrollment/fingerprint vocabularies appearing downstream
- creates a stable seam for `agentplane` and other consumers

### Constraints

- this tranche is intentionally minimal and additive
- it does not yet define the full audit-event extension family
- it does not yet standardize every possible config-source shape

## Follow-on work

1. Bind `ReleaseSet`, `BootReleaseSet`, `EnrollmentToken`, and `Fingerprint` into `SocioProphet/agentplane` runtime evidence surfaces.
2. Add any required transport-safe references in `SocioProphet/TriTRPC` only after object semantics stabilize.
3. Add broader `ConfigSource` and lifecycle event families as follow-on contracts if the thin slice proves sound.
22 changes: 22 additions & 0 deletions examples/control-plane/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Control-plane examples — local-first release family

This directory contains example payloads for the first local-first SourceOS control-plane contract family.

## Included examples

- `experience-profile.sample.json`
- `isolation-profile.sample.json`
- `release-set.sample.json`
- `boot-release-set.sample.json`
- `enrollment-token.sample.json`
- `fingerprint.sample.json`
- `incident.freeze.sample.json` (existing)

These examples are intended to support the thin local-first lifecycle slice:

1. choose experience posture
2. choose isolation posture
3. assign a release
4. optionally authorize boot/recovery
5. redeem an enrollment token
6. emit a post-apply fingerprint
13 changes: 13 additions & 0 deletions examples/control-plane/boot-release-set.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"boot_release_set_id": "brs_local_0001",
"base_release_set_ref": "rs_local_0001",
"boot_mode": "recovery",
"status": "ready",
"artifacts": {
"kernel_ref": "artifact://boot/kernel/local-0001",
"initrd_ref": "artifact://boot/initrd/local-0001",
"rootfs_ref": "artifact://boot/rootfs/local-0001"
},
"created_at": "2026-04-15T22:05:00Z",
"notes": "Recovery boot artifacts for the assigned local release."
}
15 changes: 15 additions & 0 deletions examples/control-plane/enrollment-token.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"token_id": "tok_local_0001",
"purpose": "boot",
"audience": {
"subject_kind": "device",
"subject_id": "m2-control-node-01"
},
"release_set_ref": "rs_local_0001",
"boot_release_set_ref": "brs_local_0001",
"one_time_use": true,
"issued_at": "2026-04-15T22:06:00Z",
"expires_at": "2026-04-15T23:06:00Z",
"status": "issued",
"notes": "One-time local recovery boot token."
}
13 changes: 13 additions & 0 deletions examples/control-plane/experience-profile.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"experience_profile_id": "xp_local_0001",
"profile_name": "Local desktop profile",
"shell": "zsh",
"desktop": "gnome",
"surfaces": ["cli", "gui", "browser"],
"defaults": {
"editor": "nvim",
"theme": "dark",
"accessibility_profile": null,
"workspace_layout": "default"
}
}
24 changes: 24 additions & 0 deletions examples/control-plane/fingerprint.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"fingerprint_id": "fp_local_0001",
"subject": {
"kind": "device",
"id": "m2-control-node-01"
},
"release_set_ref": "rs_local_0001",
"experience_profile_ref": "xp_local_0001",
"isolation_profile_ref": "iso_local_0001",
"observed_at": "2026-04-15T22:10:00Z",
"integrity": {
"boot_release_set_ref": "brs_local_0001",
"image_ref": "oci://registry.example/sourceos/node-commander:2026.04.15-rc1",
"store_closure_hash": "sha256:example-closure-hash",
"boot_entry_label": "SourceOS Recovery"
},
"compliance": {
"status": "compliant",
"notes": "Observed state matches the assigned local release."
},
"evidence_refs": [
"artifact://evidence/fingerprint/fp_local_0001"
]
}
10 changes: 10 additions & 0 deletions examples/control-plane/isolation-profile.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"isolation_profile_id": "iso_local_0001",
"profile_name": "Local mediated profile",
"execution_mode": "container",
"network_mode": "filtered",
"filesystem_mode": "mediated",
"secret_mode": "brokered",
"allowed_connector_classes": ["localfs", "git", "oci-registry"],
"notes": "Default isolation posture for local release application."
}
24 changes: 24 additions & 0 deletions examples/control-plane/release-set.sample.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"release_set_id": "rs_local_0001",
"release_version": "2026.04.15-rc1",
"status": "assigned",
"source": {
"git_ref": "refs/heads/main",
"git_commit": "8945f21"
},
"targets": [
{
"target_kind": "device",
"target_id": "m2-control-node-01"
}
],
"experience_profile_ref": "xp_local_0001",
"isolation_profile_ref": "iso_local_0001",
"artifacts": {
"store_closure_hash": "sha256:example-closure-hash",
"image_ref": "oci://registry.example/sourceos/node-commander:2026.04.15-rc1",
"boot_release_set_ref": "brs_local_0001"
},
"created_at": "2026-04-15T22:00:00Z",
"notes": "First local-first release assignment sample."
}
31 changes: 31 additions & 0 deletions schemas/control-plane/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Control-plane schema tranche — local-first release family

This directory contains the first machine-readable contract family for the local-first SourceOS lifecycle slice.

## Included schemas

- `experience-profile.schema.json`
- `isolation-profile.schema.json`
- `release-set.schema.json`
- `boot-release-set.schema.json`
- `enrollment-token.schema.json`
- `fingerprint.schema.json`
- `incident-events.schema.json` (existing)

## Intent

These schemas define the minimum typed seam for:

1. selecting operator/user experience posture
2. selecting isolation posture
3. assigning a release to a device, cohort, or site
4. authorizing boot/recovery/install flows where required
5. redeeming one-time enrollment tokens
6. emitting post-apply fingerprints for compliance and rollback decisions

## Downstream consumers

- `SocioProphet/agentplane`
- `SocioProphet/sociosphere` (by reference where needed)
- `SocioProphet/TriTRPC` (transport-safe refs after stabilization)
- SourceOS realization and installer lanes
40 changes: 40 additions & 0 deletions schemas/control-plane/boot-release-set.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://socioprophet.org/schemas/control-plane/boot-release-set.schema.json",
"title": "BootReleaseSet",
"description": "Boot/install or recovery artifacts associated with a local-first release assignment.",
"type": "object",
"additionalProperties": false,
"required": [
"boot_release_set_id",
"base_release_set_ref",
"boot_mode",
"status",
"artifacts",
"created_at"
],
"properties": {
"boot_release_set_id": { "type": "string", "minLength": 1 },
"base_release_set_ref": { "type": "string", "minLength": 1 },
"boot_mode": {
"type": "string",
"enum": ["installer", "recovery", "ephemeral", "bootstrap"]
},
"status": {
"type": "string",
"enum": ["draft", "ready", "retired"]
},
"artifacts": {
"type": "object",
"additionalProperties": false,
"required": ["kernel_ref", "initrd_ref", "rootfs_ref"],
"properties": {
"kernel_ref": { "type": "string", "minLength": 1 },
"initrd_ref": { "type": "string", "minLength": 1 },
"rootfs_ref": { "type": "string", "minLength": 1 }
}
},
"created_at": { "type": "string", "format": "date-time" },
"notes": { "type": ["string", "null"] }
}
}
46 changes: 46 additions & 0 deletions schemas/control-plane/enrollment-token.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://socioprophet.org/schemas/control-plane/enrollment-token.schema.json",
"title": "EnrollmentToken",
"description": "One-time or short-lived token used to enroll or authorize a local-first boot or recovery flow.",
"type": "object",
"additionalProperties": false,
"required": [
"token_id",
"purpose",
"audience",
"issued_at",
"expires_at",
"one_time_use",
"status"
],
"properties": {
"token_id": { "type": "string", "minLength": 1 },
"purpose": {
"type": "string",
"enum": ["enroll", "boot", "repair", "recovery"]
},
"audience": {
"type": "object",
"additionalProperties": false,
"required": ["subject_kind"],
"properties": {
"subject_kind": {
"type": "string",
"enum": ["device", "user", "operator", "session"]
},
"subject_id": { "type": ["string", "null"] }
}
},
"release_set_ref": { "type": ["string", "null"] },
"boot_release_set_ref": { "type": ["string", "null"] },
"one_time_use": { "type": "boolean" },
"issued_at": { "type": "string", "format": "date-time" },
"expires_at": { "type": "string", "format": "date-time" },
"status": {
"type": "string",
"enum": ["issued", "redeemed", "expired", "revoked"]
},
"notes": { "type": ["string", "null"] }
}
}
47 changes: 47 additions & 0 deletions schemas/control-plane/experience-profile.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://socioprophet.org/schemas/control-plane/experience-profile.schema.json",
"title": "ExperienceProfile",
"description": "Local-first operator or user experience posture for a SourceOS host or release assignment.",
"type": "object",
"additionalProperties": false,
"required": [
"experience_profile_id",
"profile_name",
"shell",
"desktop",
"surfaces",
"defaults"
],
"properties": {
"experience_profile_id": { "type": "string", "minLength": 1 },
"profile_name": { "type": "string", "minLength": 1 },
"shell": {
"type": "string",
"enum": ["bash", "zsh", "fish", "none"]
},
"desktop": {
"type": "string",
"enum": ["gnome", "cosmic", "none", "custom"]
},
"surfaces": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"enum": ["cli", "gui", "browser", "agent"]
}
},
"defaults": {
"type": "object",
"additionalProperties": false,
"properties": {
"editor": { "type": ["string", "null"] },
"theme": { "type": ["string", "null"] },
"accessibility_profile": { "type": ["string", "null"] },
"workspace_layout": { "type": ["string", "null"] }
}
}
}
}
Loading
Loading