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
10 changes: 2 additions & 8 deletions .config/architecture-policy.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/purview-dev/build-sdk/main/architecture-policy.schema.json",
"version": 1,
"$schema": "https://raw.githubusercontent.com/purview-dev/architests/main/architecture-policy.schema.json",
"version": 2,
"description": "The authoritative dependency and naming policy. The architecture tests read this file, and a test asserts the wiki tables agree with it, so there is one definition of each rule rather than one in prose and one in code.",
"sourceRoots": ["src"],
"conventions": {
Expand Down Expand Up @@ -293,12 +293,6 @@
"names": ["Infrastructure", "Services", "Managers", "Models", "Helpers", "Common", "Utils", "Utilities"],
"reason": "These name a category, not a responsibility, so nothing can be excluded from them and they accumulate. Infrastructure is an architectural category covering Persistence, Providers and Adapters - not a project."
},
"rules": {
"noCycles": true,
"noProductionToTestReferences": true,
"implementationsMustNotReferenceComposition": true,
"siblingImplementationsIndependent": true
},
"waivers": [
{
"project": "Infrastructure",
Expand Down
38 changes: 19 additions & 19 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "1.3.0",
"commands": [
"csharpier"
],
"rollForward": true
},
"purview.build": {
"version": "0.5.3",
"commands": [
"purview-build"
],
"rollForward": false
}
}
}
"version": 1,
"isRoot": true,
"tools": {
"csharpier": {
"version": "1.3.0",
"commands": [
"csharpier"
],
"rollForward": true
},
"purview.build": {
"version": "0.7.1",
"commands": [
"purview-build"
],
"rollForward": false
}
}
}
6 changes: 3 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@
<MSExtensionVersion>10.10.0</MSExtensionVersion>
</PropertyGroup>
<PropertyGroup Label="Purview Versions">
<PurviewTelemetryVersion>5.0.4</PurviewTelemetryVersion>
<PurviewTelemetryVersion>5.0.5</PurviewTelemetryVersion>
<!--
The build-sdk's test-support packages ship together and track the SDK version pinned in
global.json, so they share one property: a bump cannot be applied to half the family.
-->
<PurviewBuildSdkTestingVersion>1.0.6</PurviewBuildSdkTestingVersion>
<PurviewBuildSdkTestingVersion>1.1.0</PurviewBuildSdkTestingVersion>
</PropertyGroup>
<PropertyGroup Label="Testing Versions">
<TUnitVersion>1.75.0</TUnitVersion>
<TUnitVersion>1.76.0</TUnitVersion>
</PropertyGroup>

<!-- Packages -->
Expand Down
32 changes: 16 additions & 16 deletions docs/wiki/Project-Responsibilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ it has one project carrying three responsibilities, which is usually correct. Th
what each responsibility *is* so that you can tell when splitting one out would buy something.

The authoritative definition is [`.config/architecture-policy.json`](https://github.com/purview-dev/engineering-playbook/blob/main/.config/architecture-policy.json),
described by the JSON Schema the SDK publishes at
[`architecture-policy.schema.json`](https://github.com/purview-dev/build-sdk/blob/main/architecture-policy.schema.json).
described by the JSON Schema published at
[`architecture-policy.schema.json`](https://github.com/purview-dev/architests/blob/main/architecture-policy.schema.json).
The tables on this page are checked against it — see [How it is enforced](#how-it-is-enforced).

## Why
Expand Down Expand Up @@ -328,30 +328,30 @@ is a second source of truth — a consistency test fails if the tables drift fro

### The policy format

`.config/architecture-policy.json` is described by a JSON Schema (draft 2020-12) that the SDK
publishes at
[`architecture-policy.schema.json`](https://github.com/purview-dev/build-sdk/blob/main/architecture-policy.schema.json),
`.config/architecture-policy.json` is described by a JSON Schema (draft 2020-12) that the architecture
test project publishes at
[`architecture-policy.schema.json`](https://github.com/purview-dev/architests/blob/main/architecture-policy.schema.json),
and the file points at it so an editor validates as you type:

```json
{
"$schema": "https://raw.githubusercontent.com/purview-dev/build-sdk/main/architecture-policy.schema.json",
"version": 1,
"$schema": "https://raw.githubusercontent.com/purview-dev/architests/main/architecture-policy.schema.json",
"version": 2,
"sourceRoots": ["src"]
}
```

The schema lives in the SDK's repository rather than in a copy beside the policy, because a second
copy is a second source of truth and the two drift. It is also embedded in
The schema lives in the architecture test repository rather than in a copy beside the policy, because a
second copy is a second source of truth and the two drift. It is also embedded in
`Purview.Architecture.Testing`, so validation needs no network and cannot disagree with the reader.

| Key | Purpose |
| -- | -- |
| `version` | Format version. Increment when a change would break a reader that understood the previous shape. |
| `version` | Format version. Increment when a change would break a reader that understood the previous shape. Version 2 removed the `rules` object; its flags were never consulted, so a version-1 policy deletes the block. |
| `sourceRoots` | Repo-relative folders holding the projects; defaults to `["src"]`. An empty array scans the repository root. A wrong value finds no projects, which the graph-discovery rule reports rather than letting every other rule pass vacuously. |
| `responsibilities[]` | `name`, `aliases`, `category`, `purpose`, `mayDependOn`, `mustNotDependOn`, `forbiddenPackagePrefixes`, `siblingIndependence`, and the split/combine guidance |
| `responsibilities[]` | `name`, `aliases`, `category`, `purpose`, `mayDependOn`, `mustNotDependOn`, `forbiddenPackagePrefixes`, `forbiddenFrameworkReferences`, `siblingIndependence`, and the split/combine guidance |
| `discouragedProjectNames` | Category names rejected as project names, with the reason |
| `rules` | Repository-wide switches not expressed per responsibility |
| `assemblyRules` | The optional type-level check: reads compiled assemblies and applies the same matrix to the types they reference. Off by default because it needs a build. |
| `waivers[]` | Deliberate departures — see below |

Two schema choices do real work:
Expand All @@ -364,8 +364,8 @@ Two schema choices do real work:

The schema is enforced, not decorative: `PurviewArchitectureTests` validates the policy against the
embedded schema on every run, and `PolicySchemaTests` asserts it *rejects* a document missing a
required field, a waiver with a token reason, and a misspelled key. A schema that cannot fail proves
nothing.
required field, a waiver with a token reason, a misspelled key, and the `rules` block version 2 removed.
A schema that cannot fail proves nothing.

### Adopting this in another repository

Expand All @@ -377,8 +377,8 @@ validates it as you type:

```json
{
"$schema": "https://raw.githubusercontent.com/purview-dev/build-sdk/main/architecture-policy.schema.json",
"version": 1,
"$schema": "https://raw.githubusercontent.com/purview-dev/architests/main/architecture-policy.schema.json",
"version": 2,
"sourceRoots": ["src"],
"responsibilities": [ ... ]
}
Expand Down
8 changes: 5 additions & 3 deletions global.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"sdk": {
"allowPrerelease": false
"version": "11.0.100-rc.2.26504.105",
"rollForward": "latestMajor",
"allowPrerelease": true
},
"msbuild-sdks": {
"Purview.BuildSdk": "1.0.6"
"Purview.BuildSdk": "1.1.0"
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
}
4 changes: 2 additions & 2 deletions skills/purview-architecture-testing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ validates it as you type:

```json
{
"$schema": "https://raw.githubusercontent.com/purview-dev/build-sdk/main/architecture-policy.schema.json",
"version": 1,
"$schema": "https://raw.githubusercontent.com/purview-dev/architests/main/architecture-policy.schema.json",
"version": 2,
"sourceRoots": ["src"],
"responsibilities": [
{
Expand Down
26 changes: 25 additions & 1 deletion src/tests/Architecture.UnitTests/PolicySchemaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task Schema_GivenADocumentMissingARequiredField_RejectsIt()
}

[Test]
public async Task Schema_GivenAWaiverWithNoReason_RejectsIt()
public async Task Schema_GivenAWaiverWithATokenReason_RejectsIt()
{
// The minLength on 'reason' is the rule that stops a waiver becoming a silent suppression.
await AssertRejectedAsync(
Expand Down Expand Up @@ -99,6 +99,30 @@ await AssertRejectedAsync(
);
}

[Test]
public async Task Schema_GivenTheRemovedRulesObject_RejectsIt()
{
// Version 2 removed 'rules': its flags were deserialised but never consulted, so accepting the
// block again would restore a switch that looks enforced and is not.
await AssertRejectedAsync(
"""
{
"version": 2,
"responsibilities": [
{
"name": "Core",
"category": "domain",
"purpose": "The fundamental domain model and its rules.",
"mayDependOn": [],
"mustNotDependOn": []
}
],
"rules": { "noCycles": true }
}
"""
);
}

/// <summary>Writes a candidate policy, validates it, and asserts the schema rejected it.</summary>
/// <param name="json">The malformed policy.</param>
/// <returns>A task that completes when the assertion has run.</returns>
Expand Down
10 changes: 2 additions & 8 deletions templates/architecture-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
//
// Delete the responsibilities you do not have. A small application with `Core` and a host is a
// complete and correct architecture; the catalogue is not a list of projects to create.
"$schema": "https://raw.githubusercontent.com/purview-dev/build-sdk/main/architecture-policy.schema.json",
"version": 1,
"$schema": "https://raw.githubusercontent.com/purview-dev/architests/main/architecture-policy.schema.json",
"version": 2,
// The folders holding your projects, relative to the repository root. An empty array scans the
// repository root, which suits a flat layout. Getting this wrong finds no projects - which the
// graph-discovery rule reports rather than letting every other rule pass vacuously.
Expand Down Expand Up @@ -60,11 +60,5 @@
"names": ["Infrastructure", "Services", "Managers", "Models", "Helpers", "Common", "Utils", "Utilities"],
"reason": "These name a category, not a responsibility, so nothing can be excluded from them and they accumulate. Infrastructure is an architectural category covering Persistence, Providers and Adapters - not a project."
},
"rules": {
"noCycles": true,
"noProductionToTestReferences": true,
"implementationsMustNotReferenceComposition": true,
"siblingImplementationsIndependent": true
},
"waivers": []
}
11 changes: 1 addition & 10 deletions templates/global.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
{
"sdk": {
// The SDK bootstrap writes `msbuild-sdks` and `test` only — it never writes an `sdk` block.
// Without `version` + `rollForward`, a machine with several .NET SDKs installed resolves
// latest-wins, so pin both by hand. These are two different versions: `sdk.version` is the
// .NET SDK, `msbuild-sdks` is Purview.BuildSdk.
"version": "10.0.401",
"rollForward": "disable",
"allowPrerelease": false
},
"msbuild-sdks": {
"Purview.BuildSdk": "1.0.6"
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
}
Loading