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
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ Versioning.
estate, and remove the `--channel` flag and evidence inputs from
`gds-release-builder` and the release-candidate command.

## [0.9.20] - 2026-10-03

- Provider-account tenancy (ADR 0040): a tenant is the provider account — one
personal account plus each organization by its exact login. Purpose-named
portfolios such as `servers` and `forks` are no longer tenancy axes.
- `include[].match` in the device schema: repositories are placed by facts —
`owner_login`, `names`, `name_prefixes`, `visibility`, `lifecycle` — and the
first matching include wins by declaration order. `selector` includes keep
working unchanged.
- `match.name_prefixes` in the policy schema: a policy can match repository
names (for example `server-*`) without a synthetic portfolio.
- `PLACEMENT_AMBIGUOUS` is retired: ordered first-match-wins replaces the
ambiguity error.
- `match.fork` and `fork_portfolio` remain parseable for compatibility but are
no longer consulted (ADR 0040); the selector matcher reads owner,
name prefixes, lifecycle and visibility only.

## [0.9.7] - 2026-09-19

- Skip hidden directories during workspace discovery so tool-state and
Expand Down
8 changes: 4 additions & 4 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ clause stops being normative.

| ADR | Title | Status | Supersedes | Superseded by |
|---|---|---|---|---|
| [0040](0040-tenancy-is-the-provider-account.md) | Tenancy is the provider account | Accepted | — | — |
| [0040](0040-tenancy-is-the-provider-account.md) | Tenancy is the provider account | Accepted | ADR 0026 (in part), ADR 0028 (in part), ADR 0032 (in part) | — |
| [0039](0039-repo-scoped-session-evidence.md) | Repo-scoped session evidence | Accepted | — | — |
| [0038](0038-release-identity-carries-no-channel.md) | Release identity carries no channel | Accepted | ADR 0016 | — |
| [0037](0037-seven-harnesses-one-per-setup-system.md) | Seven harnesses, one per setup system | Accepted | ADR 0011 | — |
| [0036](0036-harness-identity-follows-the-consumer.md) | Harness identity follows the consumer contract | Accepted | — | — |
| [0035](0035-agent-first-explicit-control-plane.md) | Agent-first explicit control plane and evidence-bound mutation | Accepted | — | — |
| [0034](0034-gh-cli-credential-provider.md) | gh CLI credential provider and permission superset contract | Accepted | — | — |
| [0033](0033-return-the-control-plane-to-private.md) | Return the control plane to a private repository | Accepted | — | — |
| [0032](0032-flat-forks-workspace-root.md) | Place every fork checkout in one flat forks workspace root | Accepted | ADR 0018, ADR 0026 | — |
| [0032](0032-flat-forks-workspace-root.md) | Place every fork checkout in one flat forks workspace root | Accepted | ADR 0018, ADR 0026 | ADR 0040 (in part) |
| [0030](0030-solo-owner-merges-without-human-review.md) | Let the sole owner's agent merge and clean up without a second reviewer | Accepted | — | — |
| [0029](0029-harness-applications-are-out-of-estate-scope.md) | Keep harness application versions out of estate scope | Accepted | — | — |
| [0028](0028-servers-are-a-first-class-portfolio-entity.md) | Make servers a first-class portfolio entity | Accepted | — | — |
| [0028](0028-servers-are-a-first-class-portfolio-entity.md) | Make servers a first-class portfolio entity | Accepted | — | ADR 0040 (in part) |
| [0027](0027-submodule-repositories-have-no-standalone-checkout.md) | Give a submodule-consumed repository no standalone checkout | Accepted | ADR 0018 | — |
| [0026](0026-flat-servers-workspace-root.md) | Place every server checkout in one flat servers workspace root | Accepted | ADR 0025 | ADR 0032 (in part) |
| [0026](0026-flat-servers-workspace-root.md) | Place every server checkout in one flat servers workspace root | Accepted | ADR 0025 | ADR 0032 (in part), ADR 0040 (in part) |
| [0025](0025-out-of-estate-external-workspace-root.md) | Keep third-party collaboration checkouts in an out-of-estate external root | Accepted | — | ADR 0026 (in part) |
| [0024](0024-device-local-estate-registration.md) | Resolve the control plane through a device-local estate registration | Accepted | — | — |
| [0023](0023-separate-github-mutation-capability.md) | Separate GitHub mutation capability and repository-bound writes | Accepted | — | — |
Expand Down
96 changes: 84 additions & 12 deletions tests/fixtures/schemas/v1/cases.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,71 @@
{
"schema_version": 1,
"cases": [
{"id":"valid-trust-policy","schema":"trust-policy","path":"valid-trust-policy.yaml","valid":true},
{"id":"invalid-trust-policy-secret-key","schema":"trust-policy","path":"invalid-trust-policy-secret-key.yaml","valid":false,"expected_code":"GDS_INSTANCE_INVALID"},
{"id":"valid-approval","schema":"approval","path":"valid-approval.json","valid":true},
{"id":"invalid-approval-signature","schema":"approval","path":"invalid-approval-signature.json","valid":false,"expected_code":"GDS_INSTANCE_INVALID"},
{"id":"valid-plan-enablement","schema":"plan-enablement","path":"valid-plan-enablement.json","valid":true},
{"id":"invalid-plan-enablement-partial-consume","schema":"plan-enablement","path":"invalid-plan-enablement-partial-consume.json","valid":false,"expected_code":"GDS_INSTANCE_INVALID"},
{"id":"valid-freshness-policy","schema":"freshness-policy","path":"valid-freshness-policy.yaml","valid":true},
{"id":"invalid-freshness-cached-mutation","schema":"freshness-policy","path":"invalid-freshness-cached-mutation.yaml","valid":false,"expected_code":"GDS_INSTANCE_INVALID"},
{"id":"valid-field-ownership","schema":"field-ownership","path":"valid-field-ownership.json","valid":true},
{"id":"invalid-field-ownership-drop-unknown","schema":"field-ownership","path":"invalid-field-ownership-drop-unknown.json","valid":false,"expected_code":"GDS_INSTANCE_INVALID"},
{
"id": "valid-trust-policy",
"schema": "trust-policy",
"path": "valid-trust-policy.yaml",
"valid": true
},
{
"id": "invalid-trust-policy-secret-key",
"schema": "trust-policy",
"path": "invalid-trust-policy-secret-key.yaml",
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
},
{
"id": "valid-approval",
"schema": "approval",
"path": "valid-approval.json",
"valid": true
},
{
"id": "invalid-approval-signature",
"schema": "approval",
"path": "invalid-approval-signature.json",
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
},
{
"id": "valid-plan-enablement",
"schema": "plan-enablement",
"path": "valid-plan-enablement.json",
"valid": true
},
{
"id": "invalid-plan-enablement-partial-consume",
"schema": "plan-enablement",
"path": "invalid-plan-enablement-partial-consume.json",
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
},
{
"id": "valid-freshness-policy",
"schema": "freshness-policy",
"path": "valid-freshness-policy.yaml",
"valid": true
},
{
"id": "invalid-freshness-cached-mutation",
"schema": "freshness-policy",
"path": "invalid-freshness-cached-mutation.yaml",
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
},
{
"id": "valid-field-ownership",
"schema": "field-ownership",
"path": "valid-field-ownership.json",
"valid": true
},
{
"id": "invalid-field-ownership-drop-unknown",
"schema": "field-ownership",
"path": "invalid-field-ownership-drop-unknown.json",
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
},
{
"id": "valid-assurance-report",
"schema": "assurance-report",
Expand Down Expand Up @@ -273,6 +328,12 @@
"path": "valid-device.yaml",
"valid": true
},
{
"id": "valid-device-include-match",
"schema": "device",
"path": "valid-device-include-match.yaml",
"valid": true
},
{
"id": "valid-source-register",
"schema": "source-register",
Expand Down Expand Up @@ -515,7 +576,18 @@
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
},
{"id":"valid-session-evidence","schema":"session-evidence","path":"valid-session-evidence.json","valid":true},
{"id":"invalid-session-evidence-missing-fields","schema":"session-evidence","path":"invalid-session-evidence-missing-fields.json","valid":false,"expected_code":"GDS_INSTANCE_INVALID"}
{
"id": "valid-session-evidence",
"schema": "session-evidence",
"path": "valid-session-evidence.json",
"valid": true
},
{
"id": "invalid-session-evidence-missing-fields",
"schema": "session-evidence",
"path": "invalid-session-evidence-missing-fields.json",
"valid": false,
"expected_code": "GDS_INSTANCE_INVALID"
}
]
}
47 changes: 47 additions & 0 deletions tests/fixtures/schemas/v1/valid-device-include-match.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
schema_version: 1

device:
id: "device_01JEXAMPZ00000000000000004"
name: "example-workstation-match"
os: "linux"
architecture: "x86_64"

workspace_roots:
personal: "${HOME}/Developer/personal"
organization: "${HOME}/Developer/organization"
servers: "${HOME}/Developer/servers"

materialization:
default_mode: "absent"
include:
- match:
owner_login: "example-organization"
name_prefixes:
- "server-"
lifecycle:
- "active"
- "maintenance"
workspace_root: "servers"
mode: "active"
- match:
owner_login: "example-organization"
workspace_root: "organization"
mode: "active"
- match:
owner_login: "example-user"
visibility:
- "private"
workspace_root: "personal"
mode: "active"

harnesses:
- "codex"

state:
path: "${XDG_STATE_HOME}/github-device-sync"

repositories:
- provider: "example-organization/server-example"
workspace_root: "servers"
path: "servers/server-example"
materialization: "checkout"
Loading