You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Step 0 of the order of work, D1.25,`` ratified in decision-driven-design at 799cbe84f2a010fb5b65a687eb253666948c73c8. It carries out ADR-0002, ADR-0003 and ADR-0004:
the eight layer projects, each with its public API baseline and a test that the layering analyzer refuses an upward reference;
the Native AOT publish of the host on every supported runtime in CI, with a smoke test of the published binary;
the package register: Varve, the analyzers, and the test-only packages.
It needs no sdlc: edition and adds no vocabulary, no node kind and no product behaviour.
The plan follows as a comment. No file is written until it is approved.
ADR-0001 to ADR-0012, README.md and the collected file
D1.25 in the definition
decision-driven-design main = 799cbe84f2a010fb5b65a687eb253666948c73c8 ("D1.24 met, D1.25 adds step 0 …"), order of work item 0. This PR cites that commit.
DD0001 applies to another family
yes. At tag v0.1.0-preview.10 (a041cb2), DD0001 checks, for a project with ArchFamily=F and ArchLayer=n, every referenced assembly named F.*. The referenced layer is read from [assembly: ArchLayer] in its metadata. Nothing names Varve. F = ProductCli matches ProductCli.Shapes and not ProductCliX.
DD0001 is AOT-neutral
yes, as a package. The 0.1.0-preview.10 nupkg holds only analyzers/dotnet/cs/*.dll (netstandard2.0) and build/*.props/.targets, with developmentDependency=true and no lib/. One caveat, which ADR-0013 states (question 3): its generator emits internal attribute types (DecisionDriven.ArchLayerAttribute and the citation attributes) into every compilation, plus one [assembly: ArchLayer(n)]. Those types are compiled into our assemblies. They are plain attributes, with no reflection and no AOT effect.
analyzer test harness
none for consumers. The package's own tests use Microsoft.CodeAnalysis.Testing; nothing ships for us. See question 1 for how the probes compile.
Varve, for the record: Varve.Rdf0.1.0-preview.15 is tag 6cdb402 (2026-10-26). That is 120 commits beforec0a776b, the commit the earlier canonicaliser checks ran against. No commit in that range touches src/Varve.Rdf/RdfCanonicaliser.cs or src/Varve.Turtle/. Deliverable 6 is the first check of the bytes that actually ship.
Packages, resolved from nuget.org on 2026-11-03
Package
Version
Adr=
Scope=
Referenced by
Kind
Varve.Rdf
0.1.0-preview.15 (latest)
0004
—
ProductCli.Canonical
runtime, MPL-2.0
Varve.Iri
0.1.0-preview.15
0004
—
transitive of Varve.Rdf, pinned so the register shows it
every project, from Directory.Build.props, PrivateAssets="all" IncludeAssets="analyzers;build"
build-time, MPL-2.0
Microsoft.CodeAnalysis.PublicApiAnalyzers
5.6.0 (latest stable; 5.11.0-1.x is prerelease)
0013
—
every library, PrivateAssets="all"
build-time, MIT
Microsoft.CodeAnalysis.BannedApiAnalyzers
5.6.0 (latest stable)
0013
—
every project in src/, PrivateAssets="all"
build-time, MIT
Why Adr=0004 for the test stack and 0013 for the analyzers. ADR-0004 D2 admits Varve, and "the test framework and the property-testing library … once named in slice 0's plan". ADR-0013 names those two and records the reason. The analyzers are not in ADR-0004's register, so ADR-0013 admits them.
Property testing: CsCheck, not FsCheck. CsCheck 5.0.1 has no dependencies and targets net10.0. FsCheck 3.6.0 brings FSharp.Core, a second language's runtime library in every test closure, for no capability we need. Varve chose the same, for the same reason, under its own ADR. I take the latest stable, 5.0.1, and not Varve's 4.9.1.
Nothing else enters, and no TRX or hang-dump extension. nuget.config names one source, nuget.org, with source mapping.
Deliverable 1: ADR-0013, build-time analyzers and the test stack
docs/decisions/ADR-0013-build-time-analyzers-and-test-stack.md, in the adr-shape form:
Status: Proposed. See question 5 on who writes "Accepted".
D1, the test stack:
xunit v3 (xunit.v3) on Microsoft.Testing.Platform, selected in global.json;
CsCheck. Alternatives: FsCheck (rejected for FSharp.Core), and no property library (rejected: ADR-0004 D2 asks for one).
Both are test-only. Scope="tests/" is enforced, and no test project is published with AOT.
D2, the analyzers ADR-0002 D3 requires, with a reason for each:
DecisionDriven.Analyzers for layering (DD0001);
PublicApiAnalyzers for the baselines;
BannedApiAnalyzers, because the plan adopts one banned-symbol list (below).
D3, nothing ships. No package assembly reaches the binary: every analyzer reference is PrivateAssets="all", and the packages carry no lib/. The only bytes the analyzers add to our assemblies are the DD generator's internal attribute types and [assembly: ArchLayer(n)], stated as that.
D4, the register entry is the PackageVersion (question 4).
Consequences: every DD rule of the package is on as an error, not only DD0001 (question 2).
net10.0, LangVersion latest, Nullable enable, ImplicitUsings disable, TreatWarningsAsErrors, AnalysisLevel latest-recommended, EnforceCodeStyleInBuild, GenerateDocumentationFile, Deterministic, ContinuousIntegrationBuild under CI, IsPackable false. ArchFamily=ProductCli. The supported RIDs, as ProductCliRuntimeIdentifiers = linux-x64;linux-arm64;osx-arm64;win-x64 (ADR-0003 D5). Version0.8.0-preview.2. The DD package reference.
Directory.Build.targets
Every src/ library: IsAotCompatible, IsTrimmable, the AOT, trim and single-file analyzers, PublicApi and BannedApi references, and the baseline files as AdditionalFiles. The checks below.
Directory.Packages.props
ManagePackageVersionsCentrally, CentralPackageTransitivePinningEnabled, the table above, one comment per entry giving its reason
.editorconfig
the IL2xxx and IL3xxx trim, AOT and single-file diagnostics at error, with nothing lowered; code style
.globalconfig
is_global = true, dd_require_layer = true: a ProductCli.* project with no layer is itself a DD0001 error
.gitignore
bin/, obj/, artifacts/
ProductCli.slnx
the 8 + 8 projects. The probe fixtures are not in it.
eng/BannedSymbols.txt
written here, citing ADR-0003 D4: System.Reflection.Emit; Type.GetType(string…); Activator.CreateInstance(Type…) and (string,string); Assembly.Load, LoadFrom and LoadFile. Nothing is copied from Varve's list or names its ADRs.
The build's own checks, as MSBuild <Error>s in Directory.Build.targets. They run in every project's build, before compile:
PCLI0001: a PackageVersion has no Adr=.
PCLI0002: Adr="NNNN" names no docs/decisions/ADR-NNNN-*.md.
PCLI0003: a project references a package whose Scope= does not cover the project's path. xunit.v3 from src/ fails.
PCLI0004: a src/ library lacks PublicAPI.Shipped.txt or PublicAPI.Unshipped.txt. PublicApiAnalyzers is silent without the files, so the check is needed.
PCLI0005: ProductCli.Host is built with an empty SourceRevisionId. It never prints a version without a commit.
No NoWarn, #pragma or SuppressMessage anywhere. Varve's .editorconfig sets CA1716 and CA1720 to none. I do not copy that. If a rule fires on this skeleton, the code changes.
Deliverable 3: the eight projects
Each project references only the one directly below it, so the chain is ADR-0002 D1's diagram; plus Varve and the BCL.
Each baseline holds #nullable enable only. No library has a public member in this slice, and deliverable 5 needs none: --version lives in the host.
The host is an executable, not a library, so it has no baseline.
Not created:ProductCli.Vocabulary.Generator, ProductCli.Workbench, ProductCli.Workbench.Contracts.
Test projects: tests/ProductCli.<Layer>.Tests/, one per project. Each references its own layer and xunit.v3, and is unlayered: DD0001 skips *.Tests.
Deliverable 4: the layering tests
Probe:tests/fixtures/layering/ProductCli.Probe.csproj and Probe.cs, an empty internal class. It is not in the solution. It inherits Directory.Build.props and .targets, so it compiles under the real wiring, analyzer included. ArchLayer and the referenced project are passed as properties.
Harness:tests/ProbeBuild.cs, linked into each test project. It runs dotnet build on the probe with:
--no-dependencies -p:RestoreRecursive=false, so it uses the solution's existing outputs and writes nothing under src/. The eight projects can then run probes in parallel.
its own obj and bin in a temp directory.
It returns the compiler's output bytes and exit code, and the assertions read those.
Test
Lives in
Probe
Observes
upward reference refused, ×7
ProductCli.<L>.Tests, L = 0 to 6
ArchLayer=L referencing the layer L+1 project
exit ≠ 0, and the output holds error DD0001: 'ProductCli.Probe' is at layer L and references 'ProductCli.<L+1>', which is at layer L+1
layer 7, refused
ProductCli.Host.Tests
ArchLayer=7 referencing ProductCli.Host. Nothing sits above 7, so its refusal is the same-layer case
exit ≠ 0, error DD0001 … which is at layer 7
downward reference compiles
ProductCli.Canonical.Tests
ArchLayer=1 referencing ProductCli.Vocabulary
exit 0, and no DD0001 in the output
unplaced project refused
ProductCli.Host.Tests
no ArchLayer (dd_require_layer)
exit ≠ 0, error DD0001 naming the probe
layers are the table
ProductCli.Host.Tests
none
reads [assembly: ArchLayer(n)] from each built ProductCli.*.dll with System.Reflection.Metadata, and compares it with ADR-0002's table
Deliverable 5: the host, and the AOT gate
product --version. It writes the line below to stdout, as one Write with \n so the bytes match on Windows too, and exits 0:
Both values are read from AssemblyInformationalVersionAttribute and an AssemblyMetadata("SourceCommit", …) stamped at build. That read uses GetCustomAttribute, which raises no trim or AOT diagnostic.
Every other argument, and no argument, exits 2. It writes one line to stderr and nothing to stdout:
a verb of chapter 3: product: '<verb>' arrives in step <n> of the order of work (D1.25);
anything else: product: '<arg>' is not a verb.
The verb table is my reading of the order of work. Please confirm it (question 6):
Verb
Step
init, product, domain
4
proposal, view, mcp
5
decider, projector, primitive
6
scenario, conformance
7
question
8
diff
4 (draft positions arrive with nodes)
domain export arrives with domain, at step 4. Its exporters are step 2, but step 2 adds no verb.
Runtime identifiers: all four can be built. GitHub hosts each OS and this repository is public:
RID
Runner
linux-x64
ubuntu-24.04
linux-arm64
ubuntu-24.04-arm, as Varve uses
osx-arm64
macos-15
win-x64
windows-2025
Native AOT does not cross OSes, so each publishes natively.
CI. New jobs in gates.yml. Actions are pinned by SHA: actions/setup-dotnet v6.1.0 = 0f4a354dd5547a28c70b7853dbd95d5b67886e73, with global-json-file: global.json. Checkout uses the PR head SHA, so the stamped commit is the PR head and not GitHub's merge commit.
Job
Runner
Does
build-test
ubuntu-24.04
dotnet build ProductCli.slnx -c Release (warnings are errors), then dotnet test -c Release --no-build
aot (linux-x64)
ubuntu-24.04
dotnet publish src/ProductCli.Host -c Release -r linux-x64; eng/gates/smoke.sh; prints the binary's size
aot (linux-arm64)
ubuntu-24.04-arm
same, -r linux-arm64
aot (osx-arm64)
macos-15
same, -r osx-arm64
aot (win-x64)
windows-2025
same, -r win-x64, under shell: bash
eng/gates/smoke.sh <binary> <version> <commit>, a new gate script:
it runs the binary with --version, captures stdout to a file, and cmps it byte for byte with the expected line;
it requires exit 0 and empty stderr;
it then runs <binary> domain and requires exit 2 and empty stdout.
selftest gains plants for it, each a stub binary: a wrong version, a wrong commit, a CRLF line end, exit 1, and output on stderr.
The new jobs must be added to main's required checks. That is yours to do.
Deliverable 6: the Varve admission test
tests/fixtures/ddd/acme-shop.ttl and tests/fixtures/ddd/vectors.json, from decision-driven-design 799cbe84f2a010fb5b65a687eb253666948c73c8. The paths there are applications/sdlc/what/examples/acme-shop.ttl and applications/sdlc/what/vectors.json. Both files were last changed in 0c94c32.
it parses the Turtle with Varve.Turtle and canonicalises it with RdfCanonicaliser.Canonicalise;
it asserts that the sha256 of the canonical N-Quads bytes is vectors.json's graphHash, read from the file. The expected value is sha256:10cd90893f7fadb1bdf80064a43795be95e2175684c6d3a93a7736abc7c2156b.
If it fails, I stop and file a Varve issue first (ADR-0002 D5).
Host tests (ProductCli.Host.Tests)
Each runs the built product executable as a process and reads its stdout and stderr bytes (ADR-0006):
--version: stdout equals product <v> (commit <c>)\n byte for byte. <v> is the Version the test project is stamped with, from the same props. <c> is git rev-parse HEAD, run by the test.
Verbs: each chapter-3 verb gives exit 2, empty stdout, and exactly its line on stderr.
Property, CsCheck, 100 cases: for any argument vector other than exactly ["--version"] (the empty vector included), the result is exit 2, empty stdout, and exactly one line on stderr.
The no-toolchain rule
Strictly, today's check would pass this PR. It lists only Rust, Node and Python files, and checks only the root. I still change it, because after this PR the rule should be "exactly one toolchain, .NET, pinned".
The exact rule that replaces it (eng/gates/no-toolchain.sh):
The only toolchain is .NET, pinned at the root. The check fails when:
a Rust, Node or Python toolchain file from today's list, or a requirements*.txt, is anywhere in the tree outside .git/, bin/ and obj/, not only at the root;
the root has no global.json, or its sdk.version is not 10.0.401, its sdk.rollForward is not latestFeature, or its test.runner is not Microsoft.Testing.Platform;
a global.json exists below the root.
The job keeps its name, no-toolchain, so any required-check setting still matches. Its step title changes to "The only toolchain is .NET, pinned in global.json".
selftest gains plants: package.json under src/, no global.json, a wrong SDK version, a wrong rollForward, and a second global.json in tests/. Its clean case gets a global.json.
Planted failures
Each is a commit on the PR branch, pushed alone. Its red run is linked in the PR, then the next commit removes it:
a PackageVersion with no Adr= → PCLI0001;
a PackageVersion citing Adr="0099" → PCLI0002;
xunit.v3 referenced from src/ProductCli.Draft → PCLI0003;
JsonSerializer.Serialize(object) (reflection-based) in ProductCli.Shapes → IL2026 and IL3050 as errors in build-test.
The layering plants are permanent: they are the tests in deliverable 4. See question 7 on making 1 to 4 permanent too.
Deliverable 7: updates
AGENTS.md:
build, test and publish commands;
the layer table;
the new jobs in the gates table;
the rule that a new package needs an ADR and a PackageVersion with Adr= (and Scope= if test-only);
docs(decisions): ADR-0013, build-time analyzers and the test stack
build: the build policy and the package register
ci(gates): no-toolchain allows exactly one toolchain, .NET, with its selftest plants
feat: the seven layer libraries, with their API baselines
feat(host): product --version, and exit 2 for every verb not yet built
test: the layering probes, one per layer
test(canonical): the Varve admission test, with the vendored example
test(host): the version bytes, the verb messages, the argument property
ci(gates): build-test and the AOT publish and smoke matrix
to 17. the four plants and their removals
docs: AGENTS.md and README for the build
releases: v0.8.0-preview.2, the repository skeleton
docs(traceability): the session record for #167
Questions before I start
The probes compile under dotnet build, not in-process Roslyn. Without a harness, the prompt says "compile the probes with Roslyn in the test". dotnet buildis Roslyn, but through MSBuild. I recommend it:
it observes the real wiring (Directory.Build.*, .globalconfig, the package's build/ props);
in-process compilation would need Microsoft.CodeAnalysis.CSharp as one more test package, and hand-built analyzer config to imitate MSBuild.
The cost is about 2 to 4 s per probe. Agree?
Adopting DecisionDriven.Analyzers turns on all its rules, not only DD0001. That includes DD0002 to DD0023: [Contract] on public interfaces (DD0009), no naked primitives on contracts (DD0013), no mutable statics (DD0004), and more. They can't be lowered without a suppression, which DD0008 and ADR-0007 D6 forbid. None fires on this skeleton. The first public interface will need a decision set in the package's front-matter format, beside the ADRs. That is a later slice's question, but ADR-0013 states it as a consequence. Accept?
"None ships in the binary". ADR-0013 says that no analyzer assembly ships. It also says that the DD generator adds internal attribute types and one assembly attribute to each of our assemblies. Is that wording acceptable?
The register entry is the PackageVersion. ADR-0004 D1 says "every PackageReference carries Adr=", but under central versions the register is Directory.Packages.props, Varve's form, which D1 adopts. I recommend enforcing Adr= on PackageVersion only, with ADR-0013 D4 saying so, and AGENTS.md's wording following. The alternative is to require it on both. Which?
ADR-0013's status. A session never writes an acceptance. I commit it as Proposed. Do you change it to Accepted (date) in your own commit, or should I write it, quoting your approval comment?
The verb-to-step table above. Is it right?
Plants 1 to 4 as permanent tests. They are shown red and then removed, as the brief says. I'd also keep them as permanent probe fixtures, built by a BuildPolicyTests in ProductCli.Host.Tests, so every run re-proves them, as selftest does for the gates. It costs four more probe builds. Yes or no?
The version.0.8.0-preview.2, after the descriptor v0.8.0-preview.1. Agree?
Activity
Hafeok commentedon Nov 3, 2026
Plan: slice 0, the repository skeleton
Everything below was read or resolved on 2026-11-03, 12:14 UTC. No file has been written.
Preconditions: all hold
main=53bd54758ba71f7a810f91ddf3a6c83d5e653145, exactly. Tree:AGENTS.md,CLAUDE.md,README.md,LICENSE,NOTICE,docs/,releases/,.github/workflows/gates.yml,eng/gates/, nothing elsedocs/decisions/README.mdand the collected filemain=799cbe84f2a010fb5b65a687eb253666948c73c8("D1.24 met, D1.25 adds step 0 …"), order of work item 0. This PR cites that commit.DD0001applies to another familyv0.1.0-preview.10(a041cb2), DD0001 checks, for a project withArchFamily=FandArchLayer=n, every referenced assembly namedF.*. The referenced layer is read from[assembly: ArchLayer]in its metadata. Nothing names Varve.F=ProductClimatchesProductCli.Shapesand notProductCliX.DD0001is AOT-neutral0.1.0-preview.10nupkg holds onlyanalyzers/dotnet/cs/*.dll(netstandard2.0) andbuild/*.props/.targets, withdevelopmentDependency=trueand nolib/. One caveat, which ADR-0013 states (question 3): its generator emits internal attribute types (DecisionDriven.ArchLayerAttributeand the citation attributes) into every compilation, plus one[assembly: ArchLayer(n)]. Those types are compiled into our assemblies. They are plain attributes, with no reflection and no AOT effect.Varve, for the record:
Varve.Rdf0.1.0-preview.15is tag6cdb402(2026-10-26). That is 120 commits beforec0a776b, the commit the earlier canonicaliser checks ran against. No commit in that range touchessrc/Varve.Rdf/RdfCanonicaliser.csorsrc/Varve.Turtle/. Deliverable 6 is the first check of the bytes that actually ship.Packages, resolved from nuget.org on 2026-11-03
Adr=Scope=Varve.Rdf0.1.0-preview.15(latest)ProductCli.CanonicalVarve.Iri0.1.0-preview.15Varve.Rdf, pinned so the register shows itVarve.Turtle0.1.0-preview.15tests/ProductCli.Canonical.Testsonlyxunit.v34.0.2tests/xunit.v3.mtp-v24.0.2 (Microsoft.Testing.Platform v2)CsCheck5.0.1tests/ProductCli.Host.TestsDecisionDriven.Analyzers0.1.0-preview.10(latest)Directory.Build.props,PrivateAssets="all" IncludeAssets="analyzers;build"Microsoft.CodeAnalysis.PublicApiAnalyzers5.6.0(latest stable; 5.11.0-1.x is prerelease)PrivateAssets="all"Microsoft.CodeAnalysis.BannedApiAnalyzers5.6.0(latest stable)src/,PrivateAssets="all"Why
Adr=0004for the test stack and0013for the analyzers. ADR-0004 D2 admits Varve, and "the test framework and the property-testing library … once named in slice 0's plan". ADR-0013 names those two and records the reason. The analyzers are not in ADR-0004's register, so ADR-0013 admits them.Property testing: CsCheck, not FsCheck. CsCheck 5.0.1 has no dependencies and targets net10.0. FsCheck 3.6.0 brings
FSharp.Core, a second language's runtime library in every test closure, for no capability we need. Varve chose the same, for the same reason, under its own ADR. I take the latest stable, 5.0.1, and not Varve's 4.9.1.Nothing else enters, and no TRX or hang-dump extension.
nuget.confignames one source, nuget.org, with source mapping.Deliverable 1: ADR-0013, build-time analyzers and the test stack
docs/decisions/ADR-0013-build-time-analyzers-and-test-stack.md, in theadr-shapeform:xunit.v3) on Microsoft.Testing.Platform, selected inglobal.json;FSharp.Core), and no property library (rejected: ADR-0004 D2 asks for one).Scope="tests/"is enforced, and no test project is published with AOT.DecisionDriven.Analyzersfor layering (DD0001);PublicApiAnalyzersfor the baselines;BannedApiAnalyzers, because the plan adopts one banned-symbol list (below).PrivateAssets="all", and the packages carry nolib/. The only bytes the analyzers add to our assemblies are the DD generator's internal attribute types and[assembly: ArchLayer(n)], stated as that.PackageVersion(question 4).Deliverable 2: the build policy (root files)
global.jsonsdk.version10.0.401,rollForwardlatestFeature,allowPrereleasefalse;test.runnerMicrosoft.Testing.Platformnuget.configpackageSourceMappingDirectory.Build.propsnet10.0,LangVersion latest,Nullable enable,ImplicitUsings disable,TreatWarningsAsErrors,AnalysisLevel latest-recommended,EnforceCodeStyleInBuild,GenerateDocumentationFile,Deterministic,ContinuousIntegrationBuildunder CI,IsPackable false.ArchFamily=ProductCli. The supported RIDs, asProductCliRuntimeIdentifiers=linux-x64;linux-arm64;osx-arm64;win-x64(ADR-0003 D5).Version0.8.0-preview.2. The DD package reference.Directory.Build.targetssrc/library:IsAotCompatible,IsTrimmable, the AOT, trim and single-file analyzers, PublicApi and BannedApi references, and the baseline files asAdditionalFiles. The checks below.Directory.Packages.propsManagePackageVersionsCentrally,CentralPackageTransitivePinningEnabled, the table above, one comment per entry giving its reason.editorconfigerror, with nothing lowered; code style.globalconfigis_global = true,dd_require_layer = true: aProductCli.*project with no layer is itself a DD0001 error.gitignorebin/,obj/,artifacts/ProductCli.slnxeng/BannedSymbols.txtSystem.Reflection.Emit;Type.GetType(string…);Activator.CreateInstance(Type…)and(string,string);Assembly.Load,LoadFromandLoadFile. Nothing is copied from Varve's list or names its ADRs.The build's own checks, as MSBuild
<Error>s inDirectory.Build.targets. They run in every project's build, before compile:PCLI0001: aPackageVersionhas noAdr=.PCLI0002:Adr="NNNN"names nodocs/decisions/ADR-NNNN-*.md.PCLI0003: a project references a package whoseScope=does not cover the project's path.xunit.v3fromsrc/fails.PCLI0004: asrc/library lacksPublicAPI.Shipped.txtorPublicAPI.Unshipped.txt. PublicApiAnalyzers is silent without the files, so the check is needed.PCLI0005:ProductCli.Hostis built with an emptySourceRevisionId. It never prints a version without a commit.No
NoWarn,#pragmaorSuppressMessageanywhere. Varve's.editorconfigsetsCA1716andCA1720tonone. I do not copy that. If a rule fires on this skeleton, the code changes.Deliverable 3: the eight projects
Each project references only the one directly below it, so the chain is ADR-0002 D1's diagram; plus Varve and the BCL.
ArchLayersrc/ProductCli.Vocabulary.csproj,PublicAPI.Shipped.txt,PublicAPI.Unshipped.txtsrc/ProductCli.CanonicalVarve.Rdfsrc/ProductCli.Shapessrc/ProductCli.Draftsrc/ProductCli.Simulationsrc/ProductCli.Runnersrc/ProductCli.Sessionsrc/ProductCli.HostArchCompositionRoot=true.csproj(OutputType Exe,AssemblyName product,PublishAot,InvariantGlobalization),Program.cs,Verbs.cs#nullable enableonly. No library has a public member in this slice, and deliverable 5 needs none:--versionlives in the host.ProductCli.Vocabulary.Generator,ProductCli.Workbench,ProductCli.Workbench.Contracts.Test projects:
tests/ProductCli.<Layer>.Tests/, one per project. Each references its own layer andxunit.v3, and is unlayered: DD0001 skips*.Tests.Deliverable 4: the layering tests
Probe:
tests/fixtures/layering/ProductCli.Probe.csprojandProbe.cs, an empty internal class. It is not in the solution. It inheritsDirectory.Build.propsand.targets, so it compiles under the real wiring, analyzer included.ArchLayerand the referenced project are passed as properties.Harness:
tests/ProbeBuild.cs, linked into each test project. It runsdotnet buildon the probe with:--no-dependencies -p:RestoreRecursive=false, so it uses the solution's existing outputs and writes nothing undersrc/. The eight projects can then run probes in parallel.objandbinin a temp directory.It returns the compiler's output bytes and exit code, and the assertions read those.
ProductCli.<L>.Tests, L = 0 to 6ArchLayer=Lreferencing the layer L+1 projecterror DD0001: 'ProductCli.Probe' is at layer L and references 'ProductCli.<L+1>', which is at layer L+1ProductCli.Host.TestsArchLayer=7referencingProductCli.Host. Nothing sits above 7, so its refusal is the same-layer caseerror DD0001 … which is at layer 7ProductCli.Canonical.TestsArchLayer=1referencingProductCli.VocabularyDD0001in the outputProductCli.Host.TestsArchLayer(dd_require_layer)error DD0001naming the probeProductCli.Host.Tests[assembly: ArchLayer(n)]from each builtProductCli.*.dllwithSystem.Reflection.Metadata, and compares it with ADR-0002's tableDeliverable 5: the host, and the AOT gate
product --version. It writes the line below to stdout, as oneWritewith\nso the bytes match on Windows too, and exits 0:Both values are read from
AssemblyInformationalVersionAttributeand anAssemblyMetadata("SourceCommit", …)stamped at build. That read usesGetCustomAttribute, which raises no trim or AOT diagnostic.Every other argument, and no argument, exits 2. It writes one line to stderr and nothing to stdout:
product: '<verb>' arrives in step <n> of the order of work (D1.25);product: '<arg>' is not a verb.The verb table is my reading of the order of work. Please confirm it (question 6):
init,product,domainproposal,view,mcpdecider,projector,primitivescenario,conformancequestiondiffdomain exportarrives withdomain, at step 4. Its exporters are step 2, but step 2 adds no verb.Runtime identifiers: all four can be built. GitHub hosts each OS and this repository is public:
linux-x64ubuntu-24.04linux-arm64ubuntu-24.04-arm, as Varve usesosx-arm64macos-15win-x64windows-2025Native AOT does not cross OSes, so each publishes natively.
CI. New jobs in
gates.yml. Actions are pinned by SHA:actions/setup-dotnetv6.1.0 =0f4a354dd5547a28c70b7853dbd95d5b67886e73, withglobal-json-file: global.json. Checkout uses the PR head SHA, so the stamped commit is the PR head and not GitHub's merge commit.build-testubuntu-24.04dotnet build ProductCli.slnx -c Release(warnings are errors), thendotnet test -c Release --no-buildaot (linux-x64)ubuntu-24.04dotnet publish src/ProductCli.Host -c Release -r linux-x64;eng/gates/smoke.sh; prints the binary's sizeaot (linux-arm64)ubuntu-24.04-arm-r linux-arm64aot (osx-arm64)macos-15-r osx-arm64aot (win-x64)windows-2025-r win-x64, undershell: basheng/gates/smoke.sh <binary> <version> <commit>, a new gate script:--version, captures stdout to a file, andcmps it byte for byte with the expected line;<binary> domainand requires exit 2 and empty stdout.selftestgains plants for it, each a stub binary: a wrong version, a wrong commit, a CRLF line end, exit 1, and output on stderr.The new jobs must be added to
main's required checks. That is yours to do.Deliverable 6: the Varve admission test
tests/fixtures/ddd/acme-shop.ttlandtests/fixtures/ddd/vectors.json, from decision-driven-design799cbe84f2a010fb5b65a687eb253666948c73c8. The paths there areapplications/sdlc/what/examples/acme-shop.ttlandapplications/sdlc/what/vectors.json. Both files were last changed in0c94c32.4018cb9ad45c13fceafd7e585649777e7c8b9e7231fab46a42eb3286df91b777(acme-shop.ttl)953666f42051e50632290f73200298c9b5d518d2a153c20a31f9589f94374a1d(vectors.json)tests/fixtures/ddd/SOURCE.mdstates the commit, both paths and both hashes.tests/ProductCli.Canonical.Tests/VarveAdmissionTests.cs:SOURCE.md;Varve.Turtleand canonicalises it withRdfCanonicaliser.Canonicalise;vectors.json'sgraphHash, read from the file. The expected value issha256:10cd90893f7fadb1bdf80064a43795be95e2175684c6d3a93a7736abc7c2156b.Host tests (
ProductCli.Host.Tests)Each runs the built
productexecutable as a process and reads its stdout and stderr bytes (ADR-0006):--version: stdout equalsproduct <v> (commit <c>)\nbyte for byte.<v>is theVersionthe test project is stamped with, from the same props.<c>isgit rev-parse HEAD, run by the test.["--version"](the empty vector included), the result is exit 2, empty stdout, and exactly one line on stderr.The
no-toolchainruleStrictly, today's check would pass this PR. It lists only Rust, Node and Python files, and checks only the root. I still change it, because after this PR the rule should be "exactly one toolchain, .NET, pinned".
The exact rule that replaces it (
eng/gates/no-toolchain.sh):no-toolchain, so any required-check setting still matches. Its step title changes to "The only toolchain is .NET, pinned in global.json".selftestgains plants:package.jsonundersrc/, noglobal.json, a wrong SDK version, a wrongrollForward, and a secondglobal.jsonintests/. Its clean case gets aglobal.json.Planted failures
Each is a commit on the PR branch, pushed alone. Its red run is linked in the PR, then the next commit removes it:
PackageVersionwith noAdr=→PCLI0001;PackageVersioncitingAdr="0099"→PCLI0002;xunit.v3referenced fromsrc/ProductCli.Draft→PCLI0003;JsonSerializer.Serialize(object)(reflection-based) inProductCli.Shapes→IL2026andIL3050as errors inbuild-test.The layering plants are permanent: they are the tests in deliverable 4. See question 7 on making 1 to 4 permanent too.
Deliverable 7: updates
AGENTS.md:PackageVersionwithAdr=(andScope=if test-only);README.md: build and test instructions.releases/v0.8.0-preview.2.yaml:basis: issue 167, decision-driven-design799cbe8,Varve.Rdf0.1.0-preview.15, ADR-0002, 0003, 0004 and 0013;accepted-byleft for you.docs/traceability/2026-11-03-issue-167-slice-0.md, in the shape of D1.24: remove the Rust tree frommain#165's record.Commits (one logical change each, signed,
Refs #167, DCO)docs(decisions): ADR-0013, build-time analyzers and the test stackbuild: the build policy and the package registerci(gates): no-toolchain allows exactly one toolchain, .NET, with itsselftestplantsfeat: the seven layer libraries, with their API baselinesfeat(host): product --version, and exit 2 for every verb not yet builttest: the layering probes, one per layertest(canonical): the Varve admission test, with the vendored exampletest(host): the version bytes, the verb messages, the argument propertyci(gates): build-test and the AOT publish and smoke matrixdocs: AGENTS.md and README for the buildreleases: v0.8.0-preview.2, the repository skeletondocs(traceability): the session record for #167Questions before I start
The probes compile under
dotnet build, not in-process Roslyn. Without a harness, the prompt says "compile the probes with Roslyn in the test".dotnet buildis Roslyn, but through MSBuild. I recommend it:Directory.Build.*,.globalconfig, the package'sbuild/props);Microsoft.CodeAnalysis.CSharpas one more test package, and hand-built analyzer config to imitate MSBuild.The cost is about 2 to 4 s per probe. Agree?
Adopting
DecisionDriven.Analyzersturns on all its rules, not only DD0001. That includes DD0002 to DD0023:[Contract]on public interfaces (DD0009), no naked primitives on contracts (DD0013), no mutable statics (DD0004), and more. They can't be lowered without a suppression, which DD0008 and ADR-0007 D6 forbid. None fires on this skeleton. The first public interface will need a decision set in the package's front-matter format, beside the ADRs. That is a later slice's question, but ADR-0013 states it as a consequence. Accept?"None ships in the binary". ADR-0013 says that no analyzer assembly ships. It also says that the DD generator adds internal attribute types and one assembly attribute to each of our assemblies. Is that wording acceptable?
The register entry is the
PackageVersion. ADR-0004 D1 says "everyPackageReferencecarriesAdr=", but under central versions the register isDirectory.Packages.props, Varve's form, which D1 adopts. I recommend enforcingAdr=onPackageVersiononly, with ADR-0013 D4 saying so, and AGENTS.md's wording following. The alternative is to require it on both. Which?ADR-0013's status. A session never writes an acceptance. I commit it as
Proposed. Do you change it toAccepted (date)in your own commit, or should I write it, quoting your approval comment?The verb-to-step table above. Is it right?
Plants 1 to 4 as permanent tests. They are shown red and then removed, as the brief says. I'd also keep them as permanent probe fixtures, built by a
BuildPolicyTestsinProductCli.Host.Tests, so every run re-proves them, asselftestdoes for the gates. It costs four more probe builds. Yes or no?The version.
0.8.0-preview.2, after the descriptorv0.8.0-preview.1. Agree?Generated by Claude Code
releases: v0.8.0-preview.2, the repository skeleton
docs(traceability): the session record for #167