diff --git a/openspec/changes/document-system-architecture/design.md b/openspec/changes/document-system-architecture/design.md index 4db0c40..e282789 100644 --- a/openspec/changes/document-system-architecture/design.md +++ b/openspec/changes/document-system-architecture/design.md @@ -122,3 +122,36 @@ pseudo-version continue to resolve until they move. rename breaks it without warning. - Should `gohai` be consumed by `osapi`, as its README describes? That is a design question, not a documentation one, and is out of scope here. + +## Correction: `replace` was specified as a single thing + +The requirement first stated that a `replace` directive may be used locally but +never merged, and that no repository contained one. Applying it found thirteen, +merged, across four repositories: + +| Repository | Directives | Target | +| -------------------- | ---------- | ----------------------- | +| `nats-client` | 5 | its own repository root | +| `nats-server` | 4 | its own repository root | +| `osapi` | 2 | its own repository root | +| `osapi-orchestrator` | 2 | its own repository root | + +Every one belongs to a nested example module pointing at the repository that +holds it. None crosses a repository boundary. + +The requirement had collapsed two unrelated uses of the same keyword. A +`replace` reaching into a sibling repository stands in for a version that should +be pinned, and leaks a developer's local layout into a merged tree. A `replace` +reaching into its own repository root is how a nested module refers to the +source beside it — remove it and the example silently compiles against whatever +version the proxy last published, which is the failure the pattern exists to +prevent. + +The corrected requirement distinguishes them by direction rather than by +mechanism. + +*Alternative considered:* exempt example modules by path convention, keying the +rule to a directory named `examples/`. Rejected — the property that matters is +whether the directive crosses a repository boundary, and a rule written against +a directory name would miss a nested tool module and would not survive anyone +choosing a different name. diff --git a/openspec/changes/document-system-architecture/specs/module-dependencies/spec.md b/openspec/changes/document-system-architecture/specs/module-dependencies/spec.md index 543155c..b0aad60 100644 --- a/openspec/changes/document-system-architecture/specs/module-dependencies/spec.md +++ b/openspec/changes/document-system-architecture/specs/module-dependencies/spec.md @@ -23,14 +23,22 @@ A Go module SHALL declare a path matching the repository that holds it. ### Requirement: Dependencies are declared by version -A repository SHALL depend on another by a released or pinned version in -`go.mod`. +A repository SHALL depend on another repository by a released or pinned version +in `go.mod`. -A `replace` directive MAY be used locally while developing against an unreleased -change in a sibling repository. It SHALL NOT be merged. +A `replace` directive pointing outside the repository that holds it MAY be used +locally while developing against an unreleased change in a sibling repository. +It SHALL NOT be merged. -No repository contains one today, and the documentation that described `replace` -as the linking mechanism was wrong. +A `replace` directive pointing within the repository that holds it is a +different thing and SHALL be merged. A nested module — an example or tool module +under a repository that already declares its own — resolves its parent through +`replace` so it compiles against the working tree rather than a published +version. Without it the example cannot demonstrate the code it ships beside. + +The distinction is direction, not mechanism: a `replace` crossing a repository +boundary substitutes for a version that should be pinned; one staying inside it +is how a nested module refers to its own repository. #### Scenario: Consumer builds without the sibling checked out @@ -38,6 +46,13 @@ as the linking mechanism was wrong. repositories - **THEN** the build resolves every dependency from the module proxy +#### Scenario: An example module ships beside the code it demonstrates + +- **WHEN** a repository carries a nested example module +- **THEN** that module declares a `replace` pointing at its own repository root, + and it is merged, because the example must build against the source it sits + next to + #### Scenario: Developing against an unreleased sibling change - **WHEN** a developer adds a `replace` directive to test against a sibling diff --git a/openspec/changes/document-system-architecture/tasks.md b/openspec/changes/document-system-architecture/tasks.md index 9741f20..b303f90 100644 --- a/openspec/changes/document-system-architecture/tasks.md +++ b/openspec/changes/document-system-architecture/tasks.md @@ -20,11 +20,13 @@ Sequenced: `osapi` renames and publishes before `osapi-orchestrator` moves. - [ ] 3.1 `gohai` — describe the consumer relationship it has, not the one intended - [ ] 3.2 Confirm no repository documents a `replace`-based linkage -- [ ] 3.3 Confirm no `go.mod` contains a `replace` directive +- [ ] 3.3 Confirm no `go.mod` contains a `replace` directive pointing outside + its own repository ## 4. Verification - [ ] 4.1 Confirm every module path matches its repository location -- [ ] 4.2 Confirm no `replace` directive points outside its own module +- [ ] 4.2 Confirm every `replace` directive points within the repository that + holds it - [ ] 4.3 Confirm every documented dependency appears in the corresponding `go.mod`