diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index abdaffb..ef453e4 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -2,9 +2,9 @@ GENERATED FILE - DO NOT EDIT DIRECTLY generator: gds bundle: 0.1.0-dev -source-commit: 4096db90d3a56fe60d43a98deea0eda422a35f72 -input-digest: sha256:aa682dc69f657adfe8199181f04e41d7f975179e7a097bebae65768cf7c42c72 -output-digest: sha256:398c5b72bcfc9533dadc641e25fd9a51481385304e68f8ed6317e9d40ce335b5 +source-commit: 0e64dc713c9045c69f71034f00ed176eca3e34d5 +input-digest: sha256:9035c1e5c46301ca11c9335b9fdc582d4ac1faac09b84b9f67c80240a4f3a553 +output-digest: sha256:99063599c92612eaa9d1829a06d41cfa1c5b027989ed866da243c984fb35c72c edit-source: - .gds/repository.yaml - policies/base/repository-default.yaml @@ -19,7 +19,7 @@ edit-source: ## Scope - GDS repository ID: `repo_01KX7BV07RHD6KRA4Z4J0KCHGR`. -- Roles: `control-plane`. +- Roles: `control-plane, superproject`. - Canonical repository facts: `.gds/repository.yaml`. - Applied policy bundle: `.gds/bundle.lock.yaml` (`0.1.0-dev`). - This is a first-class Claude Code projection compiled from the same typed diff --git a/.gds/bundle.lock.yaml b/.gds/bundle.lock.yaml index 2b16f50..7e2d5f5 100644 --- a/.gds/bundle.lock.yaml +++ b/.gds/bundle.lock.yaml @@ -5,18 +5,18 @@ bundle: version: "0.1.0-dev" release_sequence: 0 channel: "development" - source_commit: "4096db90d3a56fe60d43a98deea0eda422a35f72" - digest: "sha256:c5431d146bb8a8c251488ee3a96eea801ad054a0c8fecd9fbc61185791b3a991" + source_commit: "0e64dc713c9045c69f71034f00ed176eca3e34d5" + digest: "sha256:d09bd81b3f8b9cafe119d62fd9fcc549a66ce3f9b0d45d18f22b9065e5d6628d" projection: - input_digest: "sha256:aa682dc69f657adfe8199181f04e41d7f975179e7a097bebae65768cf7c42c72" - output_digest: "sha256:d51d393220248c490e77f20a57c1930a831ee667a4008559002c67fbc499a0e1" + input_digest: "sha256:9035c1e5c46301ca11c9335b9fdc582d4ac1faac09b84b9f67c80240a4f3a553" + output_digest: "sha256:50580247e105ae1e629c6eba93df9da2a65504ed8b9d1d6c7e0299717e626dc1" files: - path: ".claude/CLAUDE.md" - digest: "sha256:e063d50d8bceff8282381bdcf15bf3287726b28a7bd663b3924e47757719d1cd" + digest: "sha256:5fcaf99f4e593ebd17bf7c3100e8f94afb5e035fa914df7ba1c0ad1ce676b994" - path: ".gds/compiled-policy.json" digest: "sha256:5ce6a147f6bd0573a769cd28bc5609b16c99bbe93cbe8c233110c204bb47d5f2" - path: ".github/workflows/gds-ci.yml" - digest: "sha256:570f2b4b2f8497339017d14075b86fcc8a558ed6202e947d5d40c37f730a92ce" + digest: "sha256:8b8ee2a9d5fa42b033055d1884e38f3cf3b156c8cb40a3610b776a60460cf562" - path: "AGENTS.md" - digest: "sha256:b861c844edc2b2f3ad7a6a66fcd3a8dca187d9bfb511e6623e2c993c19a442e0" + digest: "sha256:04f0737e9d7bee60e88c6fb7d325b767701adab663b8616bd0cc2496c3445a18" diff --git a/.gds/repository.yaml b/.gds/repository.yaml index e9f16d3..867f78a 100644 --- a/.gds/repository.yaml +++ b/.gds/repository.yaml @@ -5,6 +5,7 @@ repository: display_name: "github-device-sync" roles: - "control-plane" + - "superproject" lifecycle: "active" provider: diff --git a/.github/workflows/gds-ci.yml b/.github/workflows/gds-ci.yml index 55fbe25..afcf5ff 100644 --- a/.github/workflows/gds-ci.yml +++ b/.github/workflows/gds-ci.yml @@ -1,8 +1,8 @@ # GENERATED FILE - DO NOT EDIT DIRECTLY # generator: gds # bundle: 0.1.0-dev -# source-commit: 4096db90d3a56fe60d43a98deea0eda422a35f72 -# input-digest: sha256:aa682dc69f657adfe8199181f04e41d7f975179e7a097bebae65768cf7c42c72 +# source-commit: 0e64dc713c9045c69f71034f00ed176eca3e34d5 +# input-digest: sha256:9035c1e5c46301ca11c9335b9fdc582d4ac1faac09b84b9f67c80240a4f3a553 # output-digest: sha256:7e8d64d5f0249163fa46ed044b7fb9c98cb0fb3b96445c730c49e50e89755dcb # edit-source: # - .gds/repository.yaml diff --git a/.serena/memories/core-context-resolution.md b/.serena/memories/core-context-resolution.md index e9fd953..338aef5 100644 --- a/.serena/memories/core-context-resolution.md +++ b/.serena/memories/core-context-resolution.md @@ -3,12 +3,12 @@ gds_memory_schema: 1 scope_id: repo_01KX7BV07RHD6KRA4Z4J0KCHGR status: verified visibility: private -source_commit: 91ce9ee653b7a77001a6cdcf8e60ada89f6ea53a +source_commit: 0e64dc713c9045c69f71034f00ed176eca3e34d5 source_state: committed -source_digest: sha256:bdb7c732ee1fb9806b31b3087c6128d05507a41ae4734de5d8c37b717f955f71 +source_digest: sha256:021989abfd6ca2642d0acaae77e4c433a892e7cd2a85273be788e5fc779d3cef generated_by: gds-memory-compiler bundle_version: 0.1.0-dev -verified_at: "2026-07-24T14:00:00Z" +verified_at: "2026-07-26T07:05:58Z" refresh_triggers: - context-resolver-change - estate-registration-change diff --git a/.serena/memories/core-estate-layout.md b/.serena/memories/core-estate-layout.md index a06bd01..d27304f 100644 --- a/.serena/memories/core-estate-layout.md +++ b/.serena/memories/core-estate-layout.md @@ -3,12 +3,12 @@ gds_memory_schema: 1 scope_id: repo_01KX7BV07RHD6KRA4Z4J0KCHGR status: verified visibility: private -source_commit: 1af6b65676c7fc9302764b0a0f3d4cb03e38987d +source_commit: cfabe5ec42a2c7b27a6f194ed1ee23a8ca63e70b source_state: committed -source_digest: sha256:671a4a9e2b8be92fd0bac193983830be9073a341ef12d4852311c7b27793e379 +source_digest: sha256:471caa60f6e3cbe8933517bff2a622cf78ba95053ab9586d01b6b28f398eec0e generated_by: gds-memory-compiler bundle_version: 0.1.0-dev -verified_at: "2026-07-24T18:10:00Z" +verified_at: "2026-07-26T07:20:11Z" refresh_triggers: - architecture-source-change - repository-schema-change @@ -20,6 +20,9 @@ sources: - docs/adr/0004-portfolio-and-superproject-terminology.md - docs/adr/0005-typed-relationships.md - docs/adr/0018-device-workspaces-and-metadata-repository-retirement.md + - docs/adr/0025-out-of-estate-external-workspace-root.md + - docs/adr/0026-flat-servers-workspace-root.md + - docs/adr/0027-submodule-repositories-have-no-standalone-checkout.md - docs/contracts/lifecycles-v1.md - core/estate/compiler.go - core/estate/index.go @@ -68,8 +71,11 @@ filesystem hierarchy as machine identity. device selector and provider repository name, never from an implicit four-level filesystem hierarchy. - Server selectors are higher-priority specialized non-fork selectors. A - fork whose name starts with `server-` remains in the owner's fork portfolio; - organization and personal server portfolios use distinct workspace roots. + fork whose name starts with `server-` remains in the owner's fork portfolio. + Both server selectors assign one shared `portfolio:servers`, which resolves to + a single flat `servers` workspace root regardless of owning account. Owner + splitting stays correct for forks, where cross-owner name reuse is expected, + and is deliberately absent for servers. - A device may assign each portfolio selector once, may reference only declared workspace roots, and may not reuse one root for different selectors. Go and Python validators prove these semantic rules with the same negative fixtures. @@ -81,6 +87,11 @@ filesystem hierarchy as machine identity. - An embedded submodule remains an independent repository boundary even when checked out detached. Onboarding is safe only at the exact clean stage-zero superproject gitlink; filesystem nesting never supplies identity. +- A submodule-consumed repository is materialized only as its superproject's + gitlink and never as a standalone checkout. Both together make one stable ID + resolve to two Git stores, which layout analysis rejects. Embedded placement + requires role `superproject` on the superproject and role `module` on the + module, and role `module` obliges a `module` block in the repository anchor. - Workspace audit classifies each observed boundary by actual Git mode. Standalone checkouts resolve through device selectors; embedded modules resolve through the Git-reported superproject and exactly one typed @@ -88,13 +99,20 @@ filesystem hierarchy as machine identity. - Device placement drift and gitlink OID drift are independent findings. `gds workspace audit` owns the former; `gds validate gitlinks` owns the latter. +- A repository owned outside the estate has no owner, installation, or + selector and therefore no portfolio. Its checkout is placed by convention in + the out-of-estate `external` device root, is never declared in + `workspace_roots`, and is never a materialization target. Its single expected + audit finding is `GDS_WORKSPACE_ANCHOR_REQUIRED`; that is accepted steady + state, not remediable drift. Leaving the estate root families is a + classification statement, not merely a local move. ## Sources - `.gds/repository.yaml` - `schemas/v1/repository.schema.json` - `docs/architecture/README.md` -- ADRs 0003, 0004, 0005, and 0018 +- ADRs 0003, 0004, 0005, 0018, 0025, 0026, and 0027 - `estate/devices/rldyourmnd-mac1.yaml` - `estate/devices/rldyourmnd-mac2.yaml` - `estate/selectors/organization-servers.yaml` diff --git a/.serena/memories/core-policy-projection.md b/.serena/memories/core-policy-projection.md index 18f4b4a..87594e3 100644 --- a/.serena/memories/core-policy-projection.md +++ b/.serena/memories/core-policy-projection.md @@ -3,12 +3,12 @@ gds_memory_schema: 1 scope_id: repo_01KX7BV07RHD6KRA4Z4J0KCHGR status: verified visibility: private -source_commit: 91ce9ee653b7a77001a6cdcf8e60ada89f6ea53a +source_commit: 0e64dc713c9045c69f71034f00ed176eca3e34d5 source_state: committed -source_digest: sha256:e01b4ba403cc9cff8127156084ef8d1d239fd4344c2451d9f2c5836ad18dd981 +source_digest: sha256:f7902f83d161db985501efa726aca6ad9c7713815b496ed9eeaa22936ed742f1 generated_by: gds-memory-compiler bundle_version: 0.1.0-dev -verified_at: "2026-07-24T14:00:00Z" +verified_at: "2026-07-26T07:05:58Z" refresh_triggers: - policy-compiler-change - projection-template-change diff --git a/AGENTS.md b/AGENTS.md index 9081716..56fc15a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,9 +2,9 @@ GENERATED FILE - DO NOT EDIT DIRECTLY generator: gds bundle: 0.1.0-dev -source-commit: 4096db90d3a56fe60d43a98deea0eda422a35f72 -input-digest: sha256:aa682dc69f657adfe8199181f04e41d7f975179e7a097bebae65768cf7c42c72 -output-digest: sha256:6e9805f81c23943faca08511de1521935adb2252a1eacbdce8628ed278c0ea08 +source-commit: 0e64dc713c9045c69f71034f00ed176eca3e34d5 +input-digest: sha256:9035c1e5c46301ca11c9335b9fdc582d4ac1faac09b84b9f67c80240a4f3a553 +output-digest: sha256:8ef035e28c8ee736c295069b828e70f2873be24f8f96b0cf02cf4ae223f4b9fe edit-source: - .gds/repository.yaml - policies/base/repository-default.yaml @@ -19,7 +19,7 @@ edit-source: ## Scope - Repository ID: `repo_01KX7BV07RHD6KRA4Z4J0KCHGR`. -- Roles: `control-plane`. +- Roles: `control-plane, superproject`. - Canonical repository facts: `.gds/repository.yaml`. - Applied bundle: `.gds/bundle.lock.yaml` (`0.1.0-dev`). - Compiled policy: `.gds/compiled-policy.json`. diff --git a/core/estate/compiler_test.go b/core/estate/compiler_test.go index cdbea96..f98bb0a 100644 --- a/core/estate/compiler_test.go +++ b/core/estate/compiler_test.go @@ -124,7 +124,7 @@ func TestCompileRoutesServerRepositoriesByNamePrefix(t *testing.T) { byID[assignment.ProviderID] = assignment } if got := byID[10]; got.MatchedSelector != "organization-servers" || - len(got.Portfolios) != 1 || got.Portfolios[0] != "portfolio:organization-servers" { + len(got.Portfolios) != 1 || got.Portfolios[0] != "portfolio:servers" { t.Fatalf("organization server repository = %#v", got) } if got := byID[11]; got.MatchedSelector != "organization-sources" || @@ -132,7 +132,7 @@ func TestCompileRoutesServerRepositoriesByNamePrefix(t *testing.T) { t.Fatalf("organization non-server repository = %#v", got) } if got := byID[12]; got.MatchedSelector != "personal-servers" || - len(got.Portfolios) != 1 || got.Portfolios[0] != "portfolio:personal-servers" { + len(got.Portfolios) != 1 || got.Portfolios[0] != "portfolio:servers" { t.Fatalf("personal server repository = %#v", got) } if got := byID[13]; got.MatchedSelector != "organization-forks" || diff --git a/docs/adr/0025-out-of-estate-external-workspace-root.md b/docs/adr/0025-out-of-estate-external-workspace-root.md new file mode 100644 index 0000000..71d87be --- /dev/null +++ b/docs/adr/0025-out-of-estate-external-workspace-root.md @@ -0,0 +1,71 @@ +# ADR 0025: Keep third-party collaboration checkouts in an out-of-estate external root + +Status: Accepted + +Date: 2026-07-26 + +## Context + +ADR 0018 established that device checkout placement is declared by typed +assignments in `estate/devices/*.yaml`, where a portfolio selector resolves to +one named `workspace_root`. Every selector in `estate/selectors/` matches +`owner:rldyourmnd` or `owner:nddev`, and both installations in +`estate/installations/` are scoped to those two accounts. + +A repository owned by a third-party GitHub account therefore cannot be +classified, discovered, or observed by this estate, even though work on it is +legitimate and routine — a collaborator checkout where the owner has write +access is a normal case, not an anomaly. + +Two placements were considered and rejected: + +- Placing it under an estate-managed root such as the `rldyourmnd` + (`portfolio:personal-projects`) root asserts a portfolio the repository can + never match, producing permanent classification drift. +- Forking it into the `rldyourmnd-forks` root changes the collaboration model. + The fork portfolio exists for upstreams without write access; forking a + private repository the owner can already push to adds cross-fork pull-request + friction and leaves the counterparty unable to push. + +Adding an `external` entry to `workspace_roots` was also rejected. Workspace +roots are read only through `materialization.include[].workspace_root`, so a +root no selector can reference is unreachable configuration that falsely +implies GDS materializes there. + +## Decision + +1. Checkouts of repositories owned by accounts outside the estate live under the + device-local root `${HOME}/Developer/external`. +2. That root is a convention for humans and agents only. It is deliberately not + declared in any device descriptor's `workspace_roots`, holds no portfolio + assignment, and is never a materialization target. +3. Such checkouts carry no `.gds/repository.yaml` anchor. Anchoring a repository + owned by another party would commit estate governance artifacts into a tree + this estate does not own. +4. `gds workspace audit` raises exactly one expected finding per external + checkout, `GDS_WORKSPACE_ANCHOR_REQUIRED` with `anchor_state: missing`. This + is the accepted steady state, not drift to remediate. Because the root is + outside every declared `workspace_root`, no placement finding + (`GDS_WORKSPACE_PLACEMENT_DRIFT`, `GDS_WORKSPACE_ROOT_NOT_READY`) is produced + and no bogus `expected_path` is computed. +5. Promotion out of `external` is an explicit estate change: it requires a new + owner, an installation that can observe the account, and a selector — that + is, transfer or adoption of the repository, never a local move alone. + +## Consequences + +- Third-party collaboration has one predictable device location, distinct from + the four estate-managed root families (`control-plane`, `nddev`, `rldyourmnd`, + and the owner-specific `forks` and `servers` roots). +- Estate audits stay truthful: an external checkout is reported as unanchored + rather than silently absent or wrongly classified. +- The anchor finding is permanent noise in `gds workspace audit --root + ${HOME}/Developer`. It is already the state of every unanchored boundary on + the device and is not introduced by this decision. +- No typed estate object changes, so no policy compilation, bundle, or + projection input is affected by placing a repository in `external`. + +## Rollback + +Delete or relocate the external checkout. Nothing in the estate references it, +so no plan, approval, or regeneration is required to reverse this placement. diff --git a/docs/adr/0026-flat-servers-workspace-root.md b/docs/adr/0026-flat-servers-workspace-root.md new file mode 100644 index 0000000..6441123 --- /dev/null +++ b/docs/adr/0026-flat-servers-workspace-root.md @@ -0,0 +1,63 @@ +# ADR 0026: Place every server checkout in one flat servers workspace root + +Status: Accepted + +Date: 2026-07-26 + +## Context + +ADR 0018 made fork workspaces owner-specific so equal repository names cannot +collide across owners, and the server selectors were modelled the same way: +`portfolio:organization-servers` resolved to `${HOME}/Developer/servers/nddev` +and `portfolio:personal-servers` to `${HOME}/Developer/servers/rldyourmnd`. + +That owner split was never the intended shape for servers, and it was never +materialized. On `rldyourmnd-mac1` neither subroot exists; every server +checkout lives directly in `${HOME}/Developer/servers`. The declared layout and +the actual one have disagreed since the roots were declared, which is why +`gds workspace audit` reports `GDS_WORKSPACE_PLACEMENT_DRIFT` for +`servers/ci-workflows`. + +A device may not assign one workspace root to two selectors: both +`core/validation/schema.go` and `scripts/validate_gds_schemas.py` raise +`GDS_DEVICE_WORKSPACE_ROOT_REUSED`, proven by a negative fixture in +`tests/fixtures/schemas/v1/cases.json`. Pointing the two existing server +selectors at one flat root is therefore rejected by validation, and one flat +root requires one server portfolio. + +Servers are addressed by host, not by owning account. Splitting them by owner +adds a directory level that carries no operational meaning. + +## Decision + +1. `portfolio:organization-servers` and `portfolio:personal-servers` are + replaced by a single `portfolio:servers`. +2. Both server selectors keep their own `match` blocks and IDs. Selection stays + owner-scoped and `server-`-prefixed, so a fork named `server-*` still lands + in its owner's fork portfolio; only the assigned portfolio is now shared. +3. Every device declares one `servers` workspace root at + `${HOME}/Developer/servers` and exactly one materialization assignment for + `portfolio:servers`. The per-owner `servers/nddev` and `servers/rldyourmnd` + subroots are removed. +4. Server checkout placement is `${HOME}/Developer/servers/`, + flat, regardless of owning account. + +## Consequences + +- The declared layout now matches the materialized one, removing a standing + source of placement drift. +- Two server repositories with the same name under different owners would + resolve to one path. Layout analysis already rejects duplicate local paths, so + such a collision surfaces as a finding rather than silently overwriting a + checkout. Server repositories are host-named and unique in practice. +- Owner-specific roots remain correct for forks, where cross-owner name reuse is + expected. This decision does not change fork placement. +- The estate compiler's server assignments now carry `portfolio:servers`; + `core/estate/compiler_test.go` asserts the shared portfolio while still + asserting the distinct matched selectors. + +## Rollback + +Restore the two portfolio names in the server selectors and the two per-owner +roots and assignments in each device descriptor. No provider state is involved, +so rollback is a source-only change followed by regeneration. diff --git a/docs/adr/0027-submodule-repositories-have-no-standalone-checkout.md b/docs/adr/0027-submodule-repositories-have-no-standalone-checkout.md new file mode 100644 index 0000000..2640997 --- /dev/null +++ b/docs/adr/0027-submodule-repositories-have-no-standalone-checkout.md @@ -0,0 +1,60 @@ +# ADR 0027: Give a submodule-consumed repository no standalone checkout + +Status: Accepted + +Date: 2026-07-26 + +## Context + +ADR 0018 separated logical portfolio classification from device placement and +made both standalone checkouts and embedded submodules first-class, audited +independently. Nothing forbade a repository from being materialized both ways at +once, and in practice six were: `ci-workflows`, `macos-ubuntu-bootstrap`, and +`nddev-browser` existed as gitlinks under the control plane *and* as standalone +checkouts in the `nddev` root, and the three harness apps existed as gitlinks +under `nddev-harnesses` *and* standalone. + +Every such pair made one stable repository ID resolve to two distinct Git +stores, which layout analysis rejects: twelve findings, six +`GDS_CONTEXT_IDENTITY_CONFLICT` and six `GDS_IDENTITY_INDEX_ID_CONFLICT`, held +`gds workspace audit` in `blocked`. The two stores also diverged in practice — +three of the standalone checkouts carried commits that existed nowhere else. + +These repositories have their own remotes and their own release lifecycle, but +they are developed inside their consuming superproject. A second checkout adds +no capability and guarantees drift. + +## Decision + +1. A repository consumed through a `git-submodule-consumer` relationship is + materialized only as the superproject's gitlink. It gets no standalone + checkout on any device. +2. Its checkout path is inherited from the Git-reported superproject, per ADR + 0018 point 7. Device selectors do not place it. +3. Embedded placement requires roles on both sides: the superproject declares + role `superproject` and the module declares role `module`. Declaring role + `module` obliges a `module` block in `.gds/repository.yaml`, enforced by + `schemas/v1/repository.schema.json`. +4. Before removing a redundant standalone checkout, its commits must be + preserved into the submodule's own Git store. Deleting a checkout that holds + unreachable commits is data loss, not cleanup. + +## Consequences + +- All twelve identity findings are cleared and audit leaves `blocked`. +- There is exactly one working tree per repository ID on a device, so "which + copy is current" stops being a question. +- Work on a module happens inside the superproject checkout, on the module's own + branch, and is published through the module's own remote before the gitlink + advances. +- The control plane now declares role `superproject`, which changes its + generated projections; `nddev-browser` gained role `module` and a `module` + block declaring commit-contract compatibility and no published releases. +- A device root can no longer be read as an inventory of every repository the + estate knows: submodule-consumed repositories are absent from it by design. + +## Rollback + +Re-clone the standalone checkouts and restore the removed roles. Nothing in the +provider is involved. Rollback re-introduces the identity findings, which is why +it should only follow a deliberate change to the placement model. diff --git a/estate/devices/rldyourmnd-mac1.yaml b/estate/devices/rldyourmnd-mac1.yaml index c6a177a..d2dfdd4 100644 --- a/estate/devices/rldyourmnd-mac1.yaml +++ b/estate/devices/rldyourmnd-mac1.yaml @@ -12,8 +12,7 @@ workspace_roots: nddev-forks: "${HOME}/Developer/forks/nddev" rldyourmnd: "${HOME}/Developer/rldyourmnd" rldyourmnd-forks: "${HOME}/Developer/forks/rldyourmnd" - organization-servers: "${HOME}/Developer/servers/nddev" - personal-servers: "${HOME}/Developer/servers/rldyourmnd" + servers: "${HOME}/Developer/servers" materialization: default_mode: "absent" @@ -33,11 +32,8 @@ materialization: - selector: "portfolio:personal-projects" workspace_root: "rldyourmnd" mode: "active" - - selector: "portfolio:organization-servers" - workspace_root: "organization-servers" - mode: "active" - - selector: "portfolio:personal-servers" - workspace_root: "personal-servers" + - selector: "portfolio:servers" + workspace_root: "servers" mode: "active" harnesses: diff --git a/estate/devices/rldyourmnd-mac2.yaml b/estate/devices/rldyourmnd-mac2.yaml index 7e1e7e8..ff95262 100644 --- a/estate/devices/rldyourmnd-mac2.yaml +++ b/estate/devices/rldyourmnd-mac2.yaml @@ -12,8 +12,7 @@ workspace_roots: nddev-forks: "${HOME}/Developer/forks/nddev" rldyourmnd: "${HOME}/Developer/rldyourmnd" rldyourmnd-forks: "${HOME}/Developer/forks/rldyourmnd" - organization-servers: "${HOME}/Developer/servers/nddev" - personal-servers: "${HOME}/Developer/servers/rldyourmnd" + servers: "${HOME}/Developer/servers" materialization: default_mode: "absent" @@ -33,11 +32,8 @@ materialization: - selector: "portfolio:personal-projects" workspace_root: "rldyourmnd" mode: "active" - - selector: "portfolio:organization-servers" - workspace_root: "organization-servers" - mode: "active" - - selector: "portfolio:personal-servers" - workspace_root: "personal-servers" + - selector: "portfolio:servers" + workspace_root: "servers" mode: "active" harnesses: diff --git a/estate/selectors/organization-servers.yaml b/estate/selectors/organization-servers.yaml index f1166dc..471d8af 100644 --- a/estate/selectors/organization-servers.yaml +++ b/estate/selectors/organization-servers.yaml @@ -13,7 +13,7 @@ match: assign: management_mode: "observe-only" portfolios: - - "portfolio:organization-servers" + - "portfolio:servers" policy_profiles: - "repository-default" - "organization-default" diff --git a/estate/selectors/personal-servers.yaml b/estate/selectors/personal-servers.yaml index 71e8bd8..731c0c2 100644 --- a/estate/selectors/personal-servers.yaml +++ b/estate/selectors/personal-servers.yaml @@ -13,7 +13,7 @@ match: assign: management_mode: "observe-only" portfolios: - - "portfolio:personal-servers" + - "portfolio:servers" policy_profiles: - "repository-default" - "personal-default" diff --git a/modules/nddev-browser b/modules/nddev-browser index 0e86aa6..f104852 160000 --- a/modules/nddev-browser +++ b/modules/nddev-browser @@ -1 +1 @@ -Subproject commit 0e86aa64f18375b5d2837c9ab017f73f690691b3 +Subproject commit f1048523c4054eddb2192dc65b4aa3dd08585cbd diff --git a/skills/canonical/gds-audit-estate/SKILL.md b/skills/canonical/gds-audit-estate/SKILL.md index f8fe9f2..434ffc7 100644 --- a/skills/canonical/gds-audit-estate/SKILL.md +++ b/skills/canonical/gds-audit-estate/SKILL.md @@ -52,4 +52,16 @@ rate-limit evidence, and non-mutating next actions. ## References -No additional runtime reference is required; use current structured `gds` evidence. +Per ADR 0025, a checkout under the out-of-estate `${HOME}/Developer/external` +root yields exactly one expected `GDS_WORKSPACE_ANCHOR_REQUIRED` finding with +`anchor_state: missing` in `gds workspace audit`. Report it as accepted steady +state rather than remediable drift, and do not treat it as coverage loss. +Placement findings for the same path are not expected and remain real drift. + +`GDS_CONTEXT_IDENTITY_CONFLICT` and `GDS_IDENTITY_INDEX_ID_CONFLICT` on one +repository ID mean the same repository has both a gitlink and a standalone +checkout. Per ADR 0027 the standalone copy is the defect; report it as removable +only after confirming its commits already exist in the submodule's Git store. + +Otherwise no additional runtime reference is required; use current structured +`gds` evidence. diff --git a/skills/canonical/gds-manage-module/SKILL.md b/skills/canonical/gds-manage-module/SKILL.md index 5f1d158..f485f44 100644 --- a/skills/canonical/gds-manage-module/SKILL.md +++ b/skills/canonical/gds-manage-module/SKILL.md @@ -52,4 +52,12 @@ policy, changed files, checks, and remaining consumer actions. ## References -No additional runtime reference is required; use current typed relationship policy. +Per ADR 0027, a submodule-consumed repository is materialized only as the +superproject's gitlink and never as a standalone checkout. Embedded placement +requires role `superproject` on the superproject and role `module` on the +module; declaring role `module` obliges a `module` block in +`.gds/repository.yaml`, enforced by `schemas/v1/repository.schema.json`, so add +both in one change or validation fails with `GDS_INSTANCE_INVALID`. Never delete +a redundant standalone checkout before its commits are preserved into the +submodule's own Git store. Otherwise no additional runtime reference is +required; use current typed relationship policy. diff --git a/skills/canonical/gds-materialize-workspace/SKILL.md b/skills/canonical/gds-materialize-workspace/SKILL.md index a8d680d..8f15cf0 100644 --- a/skills/canonical/gds-materialize-workspace/SKILL.md +++ b/skills/canonical/gds-materialize-workspace/SKILL.md @@ -17,6 +17,11 @@ bounded resources. - Existing checkouts only need synchronization. - No explicit repository selector or device root is available. +- The repository is owned outside the estate. Per ADR 0025 it is cloned by hand + into `${HOME}/Developer/external` and has no selector, portfolio, or + materialization assignment. +- The repository is consumed as a git submodule. Per ADR 0027 it exists only as + its superproject's gitlink and is never given a standalone checkout. ## Inputs diff --git a/skills/canonical/gds-orient/SKILL.md b/skills/canonical/gds-orient/SKILL.md index 12126bd..97420b7 100644 --- a/skills/canonical/gds-orient/SKILL.md +++ b/skills/canonical/gds-orient/SKILL.md @@ -54,4 +54,11 @@ next workflow. Do not claim that any mutation was performed. ## References -No additional runtime reference is required; use current structured `gds` output. +A resolved boundary may legitimately sit outside the estate. Per ADR 0025, +checkouts of repositories owned by accounts outside this estate live under the +device-local `${HOME}/Developer/external` root, carry no `.gds/repository.yaml` +anchor, and are never materialization targets. For such a boundary, report +`standalone` mode with a missing anchor as the expected steady state and route +the user to ordinary Git work, not to a GDS repository workflow. Do not propose +anchoring, materializing, or reclassifying it. Otherwise no additional runtime +reference is required; use current structured `gds` output. diff --git a/tests/golden/projections/control-plane/.claude/CLAUDE.md b/tests/golden/projections/control-plane/.claude/CLAUDE.md index 480edb9..89ced22 100644 --- a/tests/golden/projections/control-plane/.claude/CLAUDE.md +++ b/tests/golden/projections/control-plane/.claude/CLAUDE.md @@ -3,8 +3,8 @@ GENERATED FILE - DO NOT EDIT DIRECTLY generator: gds bundle: 0.1.0-dev source-commit: 433c46b6923f7dc1efb96713b9ffc9330ca8ba58 -input-digest: sha256:256450e100e53592836ef9f9bf7305196e002e4b52dcc676d0daed1c6aab3b53 -output-digest: sha256:398c5b72bcfc9533dadc641e25fd9a51481385304e68f8ed6317e9d40ce335b5 +input-digest: sha256:5b35960c5a72120c1e38b2e702b7442eb2eb3de2d1b6b7fc13ad85d86afa716a +output-digest: sha256:99063599c92612eaa9d1829a06d41cfa1c5b027989ed866da243c984fb35c72c edit-source: - .gds/repository.yaml - policies/base/repository-default.yaml @@ -19,7 +19,7 @@ edit-source: ## Scope - GDS repository ID: `repo_01KX7BV07RHD6KRA4Z4J0KCHGR`. -- Roles: `control-plane`. +- Roles: `control-plane, superproject`. - Canonical repository facts: `.gds/repository.yaml`. - Applied policy bundle: `.gds/bundle.lock.yaml` (`0.1.0-dev`). - This is a first-class Claude Code projection compiled from the same typed diff --git a/tests/golden/projections/control-plane/.gds/bundle.lock.yaml b/tests/golden/projections/control-plane/.gds/bundle.lock.yaml index ea45f39..075bf0a 100644 --- a/tests/golden/projections/control-plane/.gds/bundle.lock.yaml +++ b/tests/golden/projections/control-plane/.gds/bundle.lock.yaml @@ -9,14 +9,14 @@ bundle: digest: "sha256:c286b32de44516ba18c113d407d3777886129040aab2b0350a6dd0edaca398b1" projection: - input_digest: "sha256:256450e100e53592836ef9f9bf7305196e002e4b52dcc676d0daed1c6aab3b53" - output_digest: "sha256:ea6169ef587438b83907785ac62af6d5c0d058ce6766d370cfc1bb7936acecc1" + input_digest: "sha256:5b35960c5a72120c1e38b2e702b7442eb2eb3de2d1b6b7fc13ad85d86afa716a" + output_digest: "sha256:a0d39cea80752f40c2571a63482a9b506766cd46f3c3067f6d7c2afd37556fa9" files: - path: ".claude/CLAUDE.md" - digest: "sha256:a12cff41f2b077d82bfc3d948cbb286897ec6bac108deba78e49e1df627f95f4" + digest: "sha256:7c8ad2973788b441cc874a34439d4f62f05c8d73121a590f4654b4a4eda979ad" - path: ".gds/compiled-policy.json" digest: "sha256:5ce6a147f6bd0573a769cd28bc5609b16c99bbe93cbe8c233110c204bb47d5f2" - path: ".github/workflows/gds-ci.yml" - digest: "sha256:00d86ff4ddb3979b34054e8de488730785af95e817452ff8179fb9d95b95bea1" + digest: "sha256:45bb03249d53f50dc1549260e6fa7666c3783172af3bafff902f1e5b5b495d67" - path: "AGENTS.md" - digest: "sha256:d92096d09c58775f4d925babd8f28cf1c10fef22825edf8283b3dfcae6cb05f6" + digest: "sha256:f87572d1ccf6cfdc4e754df1ed3bf0cf48dc6aa6e6a0c4fb97c66d38e8751461" diff --git a/tests/golden/projections/control-plane/.github/workflows/gds-ci.yml b/tests/golden/projections/control-plane/.github/workflows/gds-ci.yml index 9a1c1d2..aa95c22 100644 --- a/tests/golden/projections/control-plane/.github/workflows/gds-ci.yml +++ b/tests/golden/projections/control-plane/.github/workflows/gds-ci.yml @@ -2,7 +2,7 @@ # generator: gds # bundle: 0.1.0-dev # source-commit: 433c46b6923f7dc1efb96713b9ffc9330ca8ba58 -# input-digest: sha256:256450e100e53592836ef9f9bf7305196e002e4b52dcc676d0daed1c6aab3b53 +# input-digest: sha256:5b35960c5a72120c1e38b2e702b7442eb2eb3de2d1b6b7fc13ad85d86afa716a # output-digest: sha256:7e8d64d5f0249163fa46ed044b7fb9c98cb0fb3b96445c730c49e50e89755dcb # edit-source: # - .gds/repository.yaml diff --git a/tests/golden/projections/control-plane/AGENTS.md b/tests/golden/projections/control-plane/AGENTS.md index 9dd5183..fc5451a 100644 --- a/tests/golden/projections/control-plane/AGENTS.md +++ b/tests/golden/projections/control-plane/AGENTS.md @@ -3,8 +3,8 @@ GENERATED FILE - DO NOT EDIT DIRECTLY generator: gds bundle: 0.1.0-dev source-commit: 433c46b6923f7dc1efb96713b9ffc9330ca8ba58 -input-digest: sha256:256450e100e53592836ef9f9bf7305196e002e4b52dcc676d0daed1c6aab3b53 -output-digest: sha256:6e9805f81c23943faca08511de1521935adb2252a1eacbdce8628ed278c0ea08 +input-digest: sha256:5b35960c5a72120c1e38b2e702b7442eb2eb3de2d1b6b7fc13ad85d86afa716a +output-digest: sha256:8ef035e28c8ee736c295069b828e70f2873be24f8f96b0cf02cf4ae223f4b9fe edit-source: - .gds/repository.yaml - policies/base/repository-default.yaml @@ -19,7 +19,7 @@ edit-source: ## Scope - Repository ID: `repo_01KX7BV07RHD6KRA4Z4J0KCHGR`. -- Roles: `control-plane`. +- Roles: `control-plane, superproject`. - Canonical repository facts: `.gds/repository.yaml`. - Applied bundle: `.gds/bundle.lock.yaml` (`0.1.0-dev`). - Compiled policy: `.gds/compiled-policy.json`.