diff --git a/openspec/changes/artifact-host-interface/.openspec.yaml b/openspec/changes/artifact-host-interface/.openspec.yaml new file mode 100644 index 0000000..1c37182 --- /dev/null +++ b/openspec/changes/artifact-host-interface/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-05 diff --git a/openspec/changes/artifact-host-interface/proposal.md b/openspec/changes/artifact-host-interface/proposal.md new file mode 100644 index 0000000..196d487 --- /dev/null +++ b/openspec/changes/artifact-host-interface/proposal.md @@ -0,0 +1,30 @@ +# Artifact Host Interface (rung 3) + +## Why + +Rung 1's dumb-host model pins URLs in immutable records forever — which works until a bucket dies. The foundation design already holds the answers (D14 declarations, D21's resolution waterfall, the `town.dist.host.*` federation contract); this change makes them live: hosts as first-class services, location metadata that can heal the past, and the interface dist.town's own future platform storage must itself implement (no privileged path). + +## What Changes + +- Spec and publish the `town.dist.host.*` interface: `uploadArtifact` (binary body, server-computed digest, serviceAuth-authenticated with `aud` = host DID), content-addressed retrieval by (publisher DID, digest), and a health/inventory probe — informed by what rung-1 dogfooding taught. +- Activate `#hostStorage`: releases may locate artifacts by host DID; retrieval URLs derive live from the host's DID document (endpoint migration without touching records). +- Storage declarations go live: `town.dist.storage` records (hosts array, first-primary) as the primary declaration; the `#dist_artifacts` DID-document service entry recognized as the alternative. +- Implement the resolution waterfall's step 2 in the AppView and front door: when a record's pinned location is dead or failing pins, query the publisher's declared hosts by digest; browsers still only redirect to dist.town-verified locations; `resolveRelease`'s `locations` array grows to carry every known location (rot repair becomes real: upload same bytes to a declared host, history resolves again, zero records touched). +- CLI: `disttown storage add `, host-backed publishing (upload via the interface instead of user tooling), doctor host-mode checks. + +## Capabilities + +### New Capabilities + +- `artifact-host-protocol`: the `town.dist.host.*` interface itself — upload semantics, digest handshake at ingest, retrieval addressing, auth (serviceAuth JWTs), health probe. The federation contract any host implements, dist.town's future platform storage included. + +### Modified Capabilities + +- `artifact-hosting`: ADDED requirements for waterfall step 2 (declared-host fallback resolution, per-location verification before browser redirects, multi-location `locations` responses) and declaration resolution order (record primary, DID-doc entry recognized). + +## Impact + +- New lexicons under `town.dist.host.*` (grouped per D18 — "implement `town.dist.host.*`" is the federation contract) plus the `#dist_artifacts`/`DistTownArtifactHost` DID-document conventions. +- Reference host implementation (likely a small Go service over S3-compatible storage) — the ecosystem's template and dist.town's dogfood. +- AppView/front-door changes: waterfall resolution, per-location verification generalized beyond `#urlStorage` (OCI registry probing already exists; host retrieval joins it). +- Depends on: foundation change archived; rung-1 dogfood experience (the interface hardens against real publishing friction, per the migration ladder's sequencing rationale). diff --git a/openspec/changes/broker-publishing/.openspec.yaml b/openspec/changes/broker-publishing/.openspec.yaml new file mode 100644 index 0000000..1c37182 --- /dev/null +++ b/openspec/changes/broker-publishing/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-05 diff --git a/openspec/changes/broker-publishing/proposal.md b/openspec/changes/broker-publishing/proposal.md new file mode 100644 index 0000000..a2941cd --- /dev/null +++ b/openspec/changes/broker-publishing/proposal.md @@ -0,0 +1,31 @@ +# Broker Publishing (rung 2) + +## Why + +Rung 1 publishes via app passwords — account-wide credentials in CI secrets. The design's golden path (foundation design D8) is the broker: dist.town holds a scoped OAuth session server-side and mints individually revocable deploy tokens, giving CI the smallest possible blast radius. The `publishing` spec already defines the requirements (broker credential handling, fail-fast `publishRelease`, idempotency, atomic yank); this change builds them. + +## What Changes + +- Build the broker service: ATProto OAuth client (authorization-code flow, scoped by a published `town.dist.authFull` permission set), server-side session storage with refresh rotation, deploy-token minting/listing/revocation. +- Implement the control-plane XRPC surface: `town.dist.publishRelease` (fail-fast digest verification against reachable bytes, idempotent on (project, version), atomic `applyWrites` including first-publish project creation and pointer moves) and `town.dist.yankRelease` (status record + optional pointer moves in one commit). +- Publish the `town.dist.authFull` permission set lexicon. +- Publisher-facing account surface (authenticated, control-plane territory — distinct from the public read plane per D22's boundary rule): connect account, manage deploy tokens. +- CLI grows `disttown token` and broker-backed publishing as the default path; app-password direct-write remains the documented fallback. +- Groundwork for trusted publishing (rung 5): the token-exchange endpoint slot is designed but not implemented. + +## Capabilities + +### New Capabilities + +None — the `publishing` capability (from dist-town-protocol-foundation) already carries the broker requirements; this change implements them. + +### Modified Capabilities + +- `publishing`: ADDED requirements for deploy-token lifecycle (mint, list, revoke; token storage as hashes; session revocation severing all tokens) and the authenticated account surface — behaviors the foundation spec names but does not yet detail. + +## Impact + +- New service state: OAuth sessions and deploy-token hashes (the first durable secrets dist.town holds — encryption-at-rest and revocation paths are design work). +- New lexicons: `town.dist.authFull` permission set; control-plane procedures already drafted in `lexicons/` gain server implementations. +- Depends on: ATProto OAuth with granular scopes on the publisher's PDS; foundation change archived (specs synced). +- Risk to design early: broker compromise blast radius (D8's mitigations — scope limits, PDS-side revocation, D2 mutation alarms — become operational requirements here). diff --git a/openspec/changes/dist-town-protocol-foundation/tasks.md b/openspec/changes/dist-town-protocol-foundation/tasks.md index 6347eb4..b215c6a 100644 --- a/openspec/changes/dist-town-protocol-foundation/tasks.md +++ b/openspec/changes/dist-town-protocol-foundation/tasks.md @@ -64,6 +64,6 @@ Implementation scope: migration rung 1 (dogfood-able v1 — CLI, AppView, front ## 10. Follow-up changes (carve-outs, not implemented here) -- [ ] 10.1 Draft follow-up change proposal: broker + deploy tokens + `publishRelease`/`yankRelease` control plane + `town.dist.authFull` permission set (rung 2) -- [ ] 10.2 Draft follow-up change proposal: labeler service (release-moderation requirements) -- [ ] 10.3 Draft follow-up change proposal: artifact-host interface `town.dist.host.*` + storage declarations live + resolution waterfall steps 2–3 (rung 3) +- [x] 10.1 Draft follow-up change proposal: broker + deploy tokens + `publishRelease`/`yankRelease` control plane + `town.dist.authFull` permission set (rung 2) +- [x] 10.2 Draft follow-up change proposal: labeler service (release-moderation requirements) +- [x] 10.3 Draft follow-up change proposal: artifact-host interface `town.dist.host.*` + storage declarations live + resolution waterfall steps 2–3 (rung 3) diff --git a/openspec/changes/release-labeler/.openspec.yaml b/openspec/changes/release-labeler/.openspec.yaml new file mode 100644 index 0000000..1c37182 --- /dev/null +++ b/openspec/changes/release-labeler/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-05 diff --git a/openspec/changes/release-labeler/proposal.md b/openspec/changes/release-labeler/proposal.md new file mode 100644 index 0000000..3043846 --- /dev/null +++ b/openspec/changes/release-labeler/proposal.md @@ -0,0 +1,31 @@ +# Release Labeler + +## Why + +Moderation is the one authority lane the foundation deliberately left unbuilt: publisher state lives in repos, but third-party judgment (malware, takedown, spam) belongs in label streams (foundation design D5, D17). The front door already has its takedown chokepoint; this change gives it a takedown *source*, and opens the attestation-ecosystem door (independent labelers over release records). + +## What Changes + +- Run a dist.town labeler service emitting labels on `town.dist.release` and `town.dist.project` records: vocabulary `malware`, `takedown`, `spam` (extensible). +- Wire label consumption into the AppView: subscribed label streams join current repo state as canonicality input (per D11 — canonical state is a pure function of repo state *plus label streams*); takedown labels stop front-door resolution and read-plane serving. +- Takedown process: intake (reports, legal), review, emission, and the yank-vs-takedown separation enforced end to end (publisher records untouched; resolution stops). +- Surface labels in views: `#releaseView`/`#projectView` gain label annotations (additive view fields) so the UI and third-party clients can warn. +- Anomaly feed integration: D2 mutation alarms and deletion anomalies become labeler review inputs. + +## Capabilities + +### New Capabilities + +None — `release-moderation` (from dist-town-protocol-foundation) defines the requirements; this change implements them. + +### Modified Capabilities + +- `release-moderation`: ADDED requirements for the takedown intake/review process and label-stream consumption rules (which labelers the AppView subscribes to by default; how consumers override). +- `release-indexing`: ADDED requirement detailing how label streams compose with repo state in canonicality (takedown effect on `resolveRelease` and the front door). + +## Impact + +- New service: the labeler (own DID, signing keys, label stream) — real operational and governance weight (this is the first place dist.town exercises judgment over content). +- Legal posture becomes operational: linking-level takedown per D16, documented process, jurisdiction questions. +- View lexicon additions (additive, non-breaking). +- Depends on: foundation change archived; ozone-compatible labeler tooling evaluation (run vs. build).