DataLinq.Dev.CLI
DataLinq.Dev.CLI is the repo-local wrapper for dotnet restore, build, test, environment diagnosis, and controlled passthrough execution.
Use it when you want a stable execution profile, concise output, and predictable artifacts.
Why It Exists
Raw dotnet is a bad default for this repo when you care about repeatability.
The wrapper normalizes repo-local execution roots, keeps logs under artifacts/dev/, and gives you output modes that are usable in both normal terminal work and agent-driven workflows.
Commands
The command examples assume your current directory is the repo's src folder. The Dev CLI runs inner dotnet commands from the repo root, so explicit target paths passed to the Dev CLI are still repo-root-relative.
doctor
Diagnoses the local dotnet and NuGet execution environment.
dotnet run --project DataLinq.Dev.CLI -- doctor --profile repo
What it checks:
- repo-local execution roots
- writable tool paths
dotnet --version- installed SDK count
dotnet --info- workload resolver and workload auto-import presence
- NuGet sources from the repo-local
NuGet.Config - top-level cached package roots
Use this first when the environment looks suspicious.
restore
Runs dotnet restore with the repo-local execution profile.
dotnet run --project DataLinq.Dev.CLI -- restore
dotnet run --project DataLinq.Dev.CLI -- restore --output summary
build
Runs dotnet build with concise default output.
dotnet run --project DataLinq.Dev.CLI -- build
dotnet run --project DataLinq.Dev.CLI -- build --output errors
Useful options:
--configurationDefaults toDebug.--frameworkOptional target framework.--no-restoreSkips restore before build.--binlog auto|always|neverControls binary log generation.
test
Runs dotnet test with concise failure-focused output.
dotnet run --project DataLinq.Dev.CLI -- test src/DataLinq.Tests.Unit/DataLinq.Tests.Unit.csproj
dotnet run --project DataLinq.Dev.CLI -- test src/DataLinq.Generators.Tests/DataLinq.Generators.Tests.csproj --output failures
Useful options:
--configurationDefaults toDebug.--frameworkOptional target framework.--filterStandarddotnet testfilter expression.--no-buildSkips build before test.--no-restoreSkips restore before test.
The optional target defaults to src/DataLinq.sln.
size-report
Publishes the constrained-platform smoke targets and writes a repeatable compatibility payload report. --target selects a target set and still defaults to the historical phase8c set so existing commands keep their four-target SQLite behavior. Use --target v0.9 for the explicit eight-target SQLite/Memory release catalog. That catalog uses source-project references by default; pair --package-dir with --version when the release gate must exercise an exact local package candidate instead.
dotnet run --project src/DataLinq.Dev.CLI -- size-report --target phase8c
dotnet run --project src/DataLinq.Dev.CLI -- size-report --target v0.9 --targets memory --format markdown
dotnet run --project src/DataLinq.Dev.CLI -- size-report --target v0.9 --targets aot,trim
dotnet run --project src/DataLinq.Dev.CLI -- size-report --target v0.9 --clean-output --release-thresholds --fail-on-threshold --fail-on-banned-payload --format markdown
dotnet run --project src/DataLinq.Dev.CLI -- size-report --target v0.9 --package-dir artifacts/nuget-release/<exact-version> --version <exact-version> --output artifacts/release/v0.9/<exact-version>/compatibility --clean-output --release-thresholds --fail-on-threshold --fail-on-banned-payload --release-evidence --format markdown
The default phase8c target set preserves these original target ids and project graphs:
native-aotNative AOT publish ofsrc/DataLinq.AotSmoke.trimmedtrimmed self-contained publish ofsrc/DataLinq.TrimSmoke.wasmno-AOT Blazor WebAssembly publish ofsrc/DataLinq.BlazorWasm.wasm-aotBlazor WebAssembly AOT publish ofsrc/DataLinq.BlazorWasm.
The v0.9 target set adds backend identity and uses these exact ids:
sqlite-native-aotsqlite-trimmedsqlite-wasm-no-aotsqlite-wasm-aotmemory-native-aotmemory-trimmedmemory-wasm-no-aotmemory-wasm-aot
--targets accepts any exact id from the selected set. The aot, trim, wasm, and wasm-aot mode aliases select matching targets in that set; sqlite and memory select a runtime graph when that graph exists in the set; and all or the selected set name selects the complete set. Selections are deduplicated and emitted in catalog order. Alias spellings keep their alias meaning even when they overlap a historical id, while an exact id that is neither present nor a recognized alias is rejected.
Each newly generated report uses schema v0.9.compatibility-size-report.v6. It records the resolved invocation, UTC start/end timing, dependency source, output/strict-intent inputs, target results, artifacts and hashes, outcome, completeness, review state, and strict ValidForEvidence result. It also records the entry CLI and DevTools assembly names, informational versions, embedded repository commits, and build-time repository states; start and end checkout commit, dirty state, and status SHA-256; package candidate identity and end-of-run stability; runtime-graph identity; total payload size; symbol-excluded size; file count; .br and .gz asset totals; largest files; publish warnings grouped by owner; smoke status; payload inspection; and target-specific banned-runtime findings. Normal CLI and DevTools builds embed clean, dirty, or unknown from an explicit build-time Git status sample and make that value part of generated assembly-info inputs, so changing repository state forces recompilation even when source timestamps do not change. Missing, invalid, non-clean, or commit-mismatched runner attestations; start/end checkout drift; candidate/checkout mismatch; and candidate archive changes all keep an artifact out of release evidence. TargetSet records the canonical catalog id even when the CLI input uses different casing. SelectedTargetIds records the resolved request, ExpectedTargetCount records the complete selected-set cardinality, and IsFullTargetSet is true only when the reports actually produced exactly match that complete set; a selector subset or early stop is therefore never labeled full evidence. Summary failures are partitioned into product publish failures, product smoke failures, product inspection failures, environment failures, unsupported observations, and runner-state failures. Every failed or unsupported required target remains a hard report failure; environment classification explains the failure and does not turn incomplete release evidence green. A failed inspection preserves any publish, smoke, payload, threshold, warning, or package-provenance result that completed before the fault instead of relabeling it as a publish failure.
Every source-project catalog target publishes through a stable, canonical-target-set-qualified --artifacts-path under artifacts/dev/compat-size-build/<target-set>/<target-id>. Package-backed targets add a candidate-byte identity, producing artifacts/dev/compat-size-build/v0.9/packed-pkg-<identity>/<target-id>. This keeps different candidates and Native AOT, trimming, WebAssembly no-AOT, and WebAssembly AOT intermediates separate even when targets share one project. The report records that location as BuildScratchDirectory: it is mutable build cache, not timestamped release evidence. Source targets lock independently; package runs additionally hold one candidate-context lock across cache preparation, every selected publish/audit, and report creation, so the same candidate cannot be reset underneath another run. Different candidate identities remain independent. Each invocation receives a collision-resistant timestamp-and-GUID report root so concurrent processes cannot share or overwrite evidence.
Package mode validates the exact six public runtime packages before creating report artifacts. Every package must have the requested exact version and the same nonblank nuspec repository commit, and the report retains its canonical path, byte size, lowercase SHA-256, commit, and an aggregate candidate identity; symbol packages do not affect the runtime identity. Restore runs with an isolated generated NuGet.Config, package cache, user profile, temporary directories, and inherited MSBuild/NuGet redirection variables cleared. After publish and before smoke, the reporter audits the host project.assets.json: its active TFM/RID graph must contain the exact tracked shared smoke project plus exact core and graph-provider packages; no same-named substitute project is accepted; each package must resolve from the candidate directory; the cached archive must match the selected SHA-256; and every extracted package file listed by NuGet must match that archive byte-for-byte. Package contexts, cache paths, project references, and extracted files reject reparse traversal. Any provenance finding skips smoke and becomes a hard PackageProvenance inspection failure. The package directory must not overlap artifacts/dev, and package-backed mode is deliberately rejected for the historical phase8c graph.
Native executable targets run their published executable as the smoke. WebAssembly targets are served over local HTTP and opened in a headless Chromium-compatible browser through Playwright. Both SQLite and Memory browser hosts expose the same neutral smoke contract. The JSON and Markdown reports retain whether that contract was present, final status and stage, window-console entries, Playwright-console entries, and page errors. A no-AOT failure is a required-target failure rather than an automatic unsupported downgrade. Set DATALINQ_BROWSER_PATH when Edge, Chrome, or Chromium is not discoverable from the standard install paths or PATH.
Roslyn payload rules apply to every graph. Memory targets additionally scan both relative paths and binary/text content for DataLinq.SQLite, DataLinq.MySql, Microsoft.Data.Sqlite, MySqlConnector, SQLitePCLRaw, and e_sqlite3; the same provider tokens are legitimate in the SQLite graph and are not globally banned.
Useful options:
--targetsLimits the chosen set by exact target id or theaot,trim,wasm,wasm-aot,sqlite,memory, orallaliases. Comma-separated selectors may be combined.--runtimeRuntime identifier for native publish targets. Defaults to the current OS and architecture.--package-dir,--versionEnables package-backed evidence for--target v0.9. Supply both: the directory must contain exactly the six public runtime.nupkgfiles, and every nuspec must carry the requested exact version.--outputSelects a guarded, fresh report directory strictly below the repositoryartifactstree. It must not overlap the package input, mutable compatibility-build root, or report-lock root. A path-derived exclusive writer lease is held through JSON promotion. A reused directory may contain only a prior regularreport.json/report.mdpair; JSON is invalidated first, and unrelated content is rejected rather than deleted.--topNumber of largest files to list per target.--max-total-size-mb,--max-symbol-excluded-size-mb,--max-file-countAdvisory thresholds. Exceeding them is reported as a warning.--fail-on-thresholdMakes advisory threshold findings fail the command.--fail-on-banned-payloadMakes target-specific banned runtime payload findings fail the command. Use this for release payload gates after the package graph has been refreshed.--stop-on-publish-failureStops the report after a publish failure instead of continuing to later targets.--skip-smokeSkips executable and browser smoke runs after publish.--no-restoreReuses restore assets already present in the selected targets' isolated scratch roots. Package mode reuses only the scratch and cache for the same candidate-byte identity. Run those targets once without this option first. It cannot be combined with--clean-output.--clean-outputDeletes each selected source target's isolated scratch root before publishing, then restores and rebuilds its complete transitive graph. Package mode first empties the entire candidate-identity context, including its extracted package and HTTP caches, before recreating it and publishing the selected targets. Cleanup refuses a target or package context containing or reached through a symlink, junction, or other reparse point below the artifact root. Source-projectbinandobjdirectories are not the release-evidence boundary.--release-thresholdsApplies the shared, version-neutral compatibility guardrails by publish mode: Native AOT executable, Native AOT symbol-excluded folder, trimmed symbol-excluded folder, no-AOT Brotli assets, and WASM AOT Brotli assets.--release-evidenceMakes the command fail unless the completed report satisfies the strict release-evidence contract. It does not make a focused or source-project invocation canonical; it guards the report produced by the supplied invocation.--format summary|markdown|jsonControls console output. The JSON and Markdown artifacts are always written.
Without --output, reports are written under artifacts/dev/compat-size-report/<timestamp>-<guid>/ as report.json and report.md; with it, the guarded requested directory owns that pair. Raw publish logs are written under artifacts/dev/; target-specific browser smoke logs are written under the target folder inside the report directory. Markdown is promoted before JSON, so report.json is the completion marker. A report is artifact-complete only when its referenced regular, non-reparse logs/configuration files remain below the repository artifact root and still match their recorded hashes.
Outcome and IsCompleteForInvocation describe the selected diagnostic work. A focused source-project run can therefore pass and be complete while ValidForEvidence is false. Strict validity requires the exact ordered eight-target v0.9 catalog, Release configuration on the host-default RID, an explicit guarded output, package-backed input containing the exact six public packages/version, clean-output with restore and smoke enabled, release thresholds and both failure switches enabled, continuation after publish failures, complete hash-backed artifacts, clean stable commit-aligned Dev CLI/DevTools runners, a stable package candidate matching that checkout, and successful publish/smoke/inspection/provenance for every target. WebAssembly targets must also retain a passing browser contract with a final stage and no page errors. The expected SQLitePCLRaw/e_sqlite3 WASM0001 diagnostics remain visible as third-party warnings: they set ReviewRequired, so they still need an explicit release disposition, but they are not silently recast as product payload failures. Catalog registration and focused tooling tests do not by themselves prove that all eight v0.9 targets publish or execute. Source-project and package-backed runs are different evidence, and only a recorded fresh full package-backed report against the intended final candidate can support that release claim.
package-report
Inspects packed NuGet output for the public package set.
dotnet run --project DataLinq.Dev.CLI -- package-report --package-dir artifacts/nuget-release/<timestamp>
dotnet run --project DataLinq.Dev.CLI -- package-report --package-dir artifacts/nuget-release/v0.9-rc.N --version 0.9.0-rc.N --output artifacts/release/v0.9/v0.9-rc.N/packages/inspection --format markdown
Use this after publish-nuget.ps1 -PackOnly or another fresh pack output directory. Use a new, empty output directory for each pack: publish-nuget.ps1 rejects a non-empty output directory when it is packing so stale candidates cannot contaminate release evidence. -SkipPack is the explicit reuse path. Do not point package-report at a long-lived package cache; duplicate, unexpected, or version-skewed packages are findings on purpose. A release-evidence invocation supplies the exact candidate through --version, keeps the package directory beneath the repository's artifacts tree, and selects a fresh explicit --output beneath that same tree.
The default expected package set is:
DataLinqDataLinq.SQLiteDataLinq.MySqlDataLinq.MemoryDataLinq.CLIDataLinq.Tools
The default runtime package set is narrower:
DataLinqDataLinq.SQLiteDataLinq.MySqlDataLinq.Memory
For every package, the report checks:
- every expected public package is present
- expected public packages all use the same version
- when
--versionis supplied, every expected.nupkgand.snupkguses that exact candidate version - no unexpected package ids are present
- duplicate package ids are rejected
- every
.nupkghas a matching.snupkg .snupkgfiles are inventoried independently, and orphan or duplicate symbol-package ids are rejected- package filenames match the nuspec id and version, and symbol-package id/version match the runtime package
- nuspec id, version, description, repository type/URL/commit, license type/file, and readme are present
- repository metadata identifies the DataLinq GitHub repository, the license is the root
LICENSE.md, and the package readme is the rootREADME.md - both
LICENSE.mdandREADME.mdare present as root package assets - runtime package dependency groups do not reference
Microsoft.CodeAnalysis.* - runtime package dependency groups do not reference
Remotion.Linq - runtime package
lib/andruntimes/assets do not contain Roslyn payloads - runtime package
lib/andruntimes/assets do not contain Remotion payloads - the
DataLinqsource generator lives underanalyzers/dotnet/cs - analyzer payloads are not placed under runtime assets
- every
.nupkgand.snupkgrecords its byte length and SHA-256 and is re-read to prove that the archive set and bytes stayed stable during inspection - every expected public package archive and symbol archive records the canonical Git repository identity and one coherent full repository commit
DataLinq.Memory has an additional fail-closed package policy:
- its description must be exactly
Experimental read-only in-memory backend for generated DataLinq models. - its runtime archive must contain exactly
lib/net8.0/DataLinq.Memory.dll,lib/net9.0/DataLinq.Memory.dll, andlib/net10.0/DataLinq.Memory.dll - its symbol archive must contain exactly the corresponding three
DataLinq.Memory.pdbfiles - its runtime and symbol archives use explicit allowlists: the required assemblies or PDBs, their matching nuspec, the runtime license/readme, and standard NuGet structural or signature metadata are allowed; every other entry is rejected
- each expected runtime DLL must contain valid CLI assembly metadata and have the assembly definition name
DataLinq.Memory - it must have exactly one dependency group for each of
net8.0,net9.0, andnet10.0, with no other groups - each dependency group must contain only one
DataLinqdependency at the exact Memory package version, with exactlyBuild,Analyzersexcluded - analyzer, runtime, build, build-transitive, tool, and native assets are forbidden
- all non-empty runtime and symbol entries are checked for PE, ELF, Mach-O, WebAssembly, and static-archive signatures; only the validated managed DLLs at the three expected runtime paths are permitted executable images
- dependency ids, asset paths, and managed library contents are checked for
DataLinq.SQLite,DataLinq.MySql,Microsoft.Data.Sqlite,MySqlConnector,SQLitePCLRaw,e_sqlite3,Microsoft.CodeAnalysis,Remotion.Linq, andDataLinq.Generators - generator assets remain owned by the core
DataLinqpackage;DataLinq.Memorymust not duplicate them
The Memory-specific identity, metadata, framework, dependency, exclusion, asset, and banned-payload findings are always hard failures. The --allow-* switches below relax only their named general package-report policy; they do not weaken the DataLinq.Memory package contract.
Useful options:
--versionSupplies the exact package candidate version and opts into strict release-evidence intent. A versioned invocation exits unsuccessfully unless the completed report is alsoValidForEvidence.--outputSelects a guarded report directory strictly beneath the repository'sartifactstree. It must not overlap the package input and must be empty or contain only prior regularreport.jsonandreport.mdfiles.--expected-packagesOverrides the public package set with a comma-separated list, orpublic.--runtime-packagesOverrides the runtime package set with a comma-separated list, orruntime.--allow-unexpected-packagesReports unexpected package ids without failing.--allow-missing-symbolsReports missing.snupkgfiles without failing.--allow-runtime-roslynReports runtime Roslyn package dependencies or payload assets without failing.--allow-runtime-remotionReports runtime Remotion package dependencies or payload assets without failing.--allow-analyzer-leaksReports missing or misplaced analyzer assets without failing.--format summary|markdown|jsonControls console output independently of the JSON and Markdown report artifacts.
Reports use schema v0.9.package-inspection-report.v4. Without --output, they are written under artifacts/dev/package-report/<timestamp>-<guid>/; an explicit output remains strictly beneath repository artifacts. The schema records the resolved invocation and strict-policy switches, UTC timing, outcome, inspection and artifact completeness, explicit JSON/Markdown paths, per-archive byte length and SHA-256, a path-independent candidate aggregate, exact-version and repository-commit consistency, archive stability, hard-failure classification, bounded structured error details, and start/end checkout plus Dev CLI/DevTools runner provenance.
Outcome describes whether the requested inspection passed, failed findings, or encountered an inspection error. A diagnostic invocation without --version may therefore be Passed while ValidForEvidence is false. Strict validity additionally requires a completed artifact-backed inspection under the exact six-public/four-runtime package policy with every failure switch enabled, package input beneath repository artifacts, the requested version and canonical Git repository identity across every expected .nupkg/.snupkg, one coherent full commit across those archives, stable archive bytes, and a clean unchanged checkout whose Dev CLI and DevTools assemblies and package candidate all match that commit.
The writer promotes report.md first and report.json last, so report.json is the completion marker for the pair. For a safe explicit --output, action-level semantic validation invalidates only prior regular report.json/report.md files before continuing; unrelated content is rejected rather than deleted. System.CommandLine syntax/parser failures occur before the action, while pre-action setup, cancellation/fatal failures, or report-write failures may emit no JSON. Evidence consumers must require successful command exit plus the v4 schema, both completeness flags, and ValidForEvidence; file existence or Outcome: Passed alone is insufficient.
package-smoke
Restores, builds, and executes the tracked external consumer using only an exact local package candidate:
dotnet run --project DataLinq.Dev.CLI -- package-smoke --package-dir artifacts/nuget-release/0.9.0-preview.N --version 0.9.0-preview.N
dotnet run --project DataLinq.Dev.CLI -- package-smoke --package-dir artifacts/nuget-release/0.9.0-preview.N --version 0.9.0-preview.N --output artifacts/release/v0.9/0.9.0-preview.N/packages/consumer-smoke --format markdown
--package-dir and --version are required. The version must be one valid exact package version. --output must name a missing or empty directory; when omitted, the command creates a unique directory under artifacts/dev/package-smoke/. Candidate, fixture, and output paths must not traverse reparse points, and output cannot equal or sit below either source directory.
New reports use outer schema v0.9.package-consumer-smoke-report.v2; the fixture's deliberately small execution payload remains v0.9.package-consumer-execution.v1. The report records start/completion time, outcome, process exit, whether the complete five-command invocation ran, candidate and restored-package SHA-256 identities, one generated-source result for each of net8/net9/net10, command logs, and report paths. Markdown is promoted before JSON, making report.json the completion marker. A failed or incomplete invocation returns exit code 1.
This command assumes a trusted developer-controlled release machine. Its purpose is to catch wrong versions, stale or mixed package candidates, restore drift, build failures, missing generated output, and consumer regressions. It is not intended to defend against a malicious local process changing the SDK, environment, filesystem, or artifacts during execution. Stronger supply-chain guarantees belong in a controlled signed CI release workflow, not in this local smoke runner.
The tracked fixture lives under test-infra/package-consumer, outside src, and has no project references. It directly references exact bracketed versions of DataLinq, DataLinq.Memory, DataLinq.SQLite, and DataLinq.MySql. The direct core reference is deliberate: the provider packages exclude transitive build/analyzer assets, while the core package owns DataLinq.Generators and its analyzer dependencies.
The smoke fails closed unless all of these hold:
- the selected directory contains exactly one package for each consumed id at the requested version
- only the fixed four-file fixture manifest is copied, and the project must match the approved SDK/property/package/version-guard shape exactly; imports, direct references, analyzers, linked compile items, extra targets, extra packages, and extra source/build files are rejected before restore
- inherited MSBuild/NuGet redirect and import-hook variables are removed, automatic response and directory build/package imports are disabled, and restore/build explicitly pin the assets, project-extensions, package-cache, configuration, output, HTTP-cache, scratch, and temporary roots
- NuGet source mapping restricts
DataLinq*to the selected candidate directory while external dependencies use NuGet.org - the one pinned
project.assets.jsonrecords only the generated configuration and isolated package cache, has no fallback folder or project library, coversnet8.0,net9.0, andnet10.0, and resolves all four DataLinq packages as packages at the exact version - each restored DataLinq package records the selected local source and its cached
.nupkgSHA-256 matches the selected candidate - all three supported target frameworks build and each TFM's emitted compiler-generated source contains the expected generated database and mutable row
- the net10 executable passes generated-model Memory seed/find/query, real shared-cache in-memory SQLite create/insert/query, and the MySQL public-surface compilation probe; the summary reports success only after the runner validates the exit code, schema, framework, and exact payload rather than trusting the fixture's aggregate bit
This is package-consumer evidence, not packaged Native AOT, trimming, or browser evidence. Run package-report against the same fresh candidate first, then run package-backed size-report --target v0.9 --package-dir ... --version ... for the separate constrained-runtime gate.
api-report
Compares an exact freshly packed candidate with the locked published 0.8.0 package baseline by using the repo-local Microsoft.DotNet.ApiCompat.Tool manifest:
dotnet tool restore --tool-manifest ../.config/dotnet-tools.json
dotnet run --project DataLinq.Dev.CLI -- api-report --baseline-dir artifacts/api-baseline/nuget-org-0.8.0 --candidate-dir artifacts/nuget-release/0.9.0-preview.N --candidate-version 0.9.0-preview.N
dotnet run --project DataLinq.Dev.CLI -- api-report --baseline-dir artifacts/api-baseline/nuget-org-0.8.0 --candidate-dir artifacts/nuget-release/0.9.0-preview.N --candidate-version 0.9.0-preview.N --output artifacts/release/v0.9/0.9.0-preview.N/api --format markdown
--baseline-dir, --candidate-dir, and --candidate-version are required. --baseline-version defaults to 0.8.0, and --baseline-lock defaults to test-infra/api-compatibility/v0.8.0-packages.json. That lock binds the baseline to the exact NuGet.org package-byte SHA-256 values, package repository URL and commit, and the local Git tag/commit identity. The baseline directory is explicit: the command never discovers a convenient copy in a global NuGet cache or silently downloads a replacement. --output must name a missing, non-overlapping path; omitting it creates a collision-resistant directory under artifacts/dev/api-report/.
The comparison set is DataLinq, DataLinq.SQLite, DataLinq.MySql, DataLinq.Tools, and the exact tools/<tfm>/any/DataLinq.CLI.dll assets for net8.0, net9.0, and net10.0. CLI assets are compared baseline-to-candidate per TFM and candidate net8 is compared bidirectionally with net9 and net10 so a framework-only addition is not mislabeled as a harmless baseline addition. DataLinq.Memory is new in 0.9, so the command validates its current package consistency and records its first three public surfaces instead of inventing a 0.8 baseline.
After source inspection, the command copies every exact nupkg into its fresh evidence root, verifies that the aggregate identities did not change during copying, holds the copied inputs against concurrent writes, and re-inspects them after all comparisons. Snapshots and ApiCompat consume those evidence-owned bytes rather than reopening mutable ignored source directories throughout the run.
Each run retains schema v0.9.api-compatibility-report.v2 as report.json and report.md, raw standard output/error for every pinned ApiCompat invocation, generated suppression XML when ApiCompat emits it, and a human-readable metadata snapshot for every selected compile asset. A successful zero-diagnostic invocation is represented by its exit code and logs with a null suppression path because ApiCompat 10.0.302 intentionally creates no empty XML file. ApiCompat is authoritative for compatibility classification. The snapshots are supplemental review/provenance evidence: their semantic API hash excludes MVID and whole-file hash, and they are not presented as a home-grown replacement for ApiCompat.
Findings are deliberately separated:
- baseline diagnostics from the normal comparison are binary/API breaks;
CP0017parameter-name changes are called out as source-sensitive breaks - each locked baseline library package is self-validated under the same current-framework rules; an exact candidate divergence already present in that baseline is retained as an explicit inherited-divergence review item
- a new or changed non-baseline diagnostic is inconsistent API across the candidate's current target frameworks and remains a hard failure
- strict-baseline-only diagnostics are compatible or additive changes that remain visible for release review without automatically failing the command
- each first
DataLinq.Memorysurface is a review item, while an inconsistent Memory package remains a hard failure
The report also binds evidence to the start/end Git state, the Dev CLI and DevTools embedded commits and clean-build attestations, the candidate nuspec commit, and the locked baseline tag. A dirty or drifting checkout, stale runner binary, dirty-built runner, candidate/checkout mismatch, baseline/tag mismatch, package-set fault, snapshot fault, tool-version mismatch, or ApiCompat execution fault is a hard failure and returns exit code 1. This command does not prove generated-source, behavioral, wire-format, exception-behavior, or consumer-execution compatibility; those remain separate release gates.
exec
Runs an arbitrary dotnet command through the same repo-local execution profile.
dotnet run --project DataLinq.Dev.CLI -- exec -- --info
dotnet run --project DataLinq.Dev.CLI -- exec -- build src/DataLinq.sln -c Release
This is the escape hatch, not the main workflow.
Prefer the dedicated commands unless you actually need a command surface the wrapper does not expose directly.
Execution Profiles
Supported profiles:
autoDefault. Resolves the best profile for the current environment.repoNormal repo-local execution.sandboxIntended for constrained or offline-ish environments.ciCI-oriented execution profile.
Output Modes
Supported output modes:
quietDefault. One-line success and concise failure.summaryAdds a slightly richer summary.errorsFocuses on distinct compiler and NuGet errors.failuresFocuses on test failures and failing command summaries.rawPrints the underlying command output.diagUses diagnostic verbosity and preserves full detail in artifacts.
Targets and Additional Arguments
restore, build, and test all accept an optional target path.
If you omit it, the default target is src/DataLinq.sln.
Each command also accepts extra dotnet arguments after --.
Example:
dotnet run --project DataLinq.Dev.CLI -- build src/DataLinq.sln -- --no-incremental
Artifacts
Artifacts are written under artifacts/dev/.
Build runs can also emit binary logs depending on the selected --binlog mode.
If you need the full raw output, the artifact logs are the first place to look. They are the source of truth, not whatever condensed line happened to print to the terminal.