diff --git a/.claude/probe-axes.md b/.claude/probe-axes.md deleted file mode 100644 index b19a06b0..00000000 --- a/.claude/probe-axes.md +++ /dev/null @@ -1,755 +0,0 @@ -# Probe axes: CodoMetis.TypeKit - -The `prober` agent reads this file at the start of every round. It says how to write and run a probe -here, where the claims come from, which external APIs to enumerate, which type shapes to generate, -what to compare against, and what is intended. Everything specific to this repository lives here; -the agent itself is generic. - -## Harness - -Write probes as xunit theories in **`test/CodoMetis.TypeKit.Samples`**, in a folder `Probes/` of the -scratch copy, one file per claim, class name ending in `Probe`, rows fed through `[MemberData]` from -the covering array (`prober rows`), read from a JSON file beside the probe. That project is the -closest thing to a consumer: it references every package, weaves value objects through the real -fabric, and loads the analyzer as an analyzer. A probe file may declare its own value objects -(`readonly partial record struct ProbeId : IValue;`); the declarations of the type-shape -catalogue, `tools/probe/corpus/harness/*.g.cs`, are written by the file-based apps of -`tools/probe/generators/` (`dotnet run tools/probe/generators/.cs -- ...`, its README), never by hand, -and `GeneratedHarnessTests` in the conventions tests holds each file to its app's output. - -- Start a probe with `prober new --claim ` and iterate with `prober try --probe

[--rows i,j,...]` - (tools/Prober/README.md, "Writing a probe"): `new` stages the skeleton in this harness's form, with the - claim's obligations quoted and a throwing check each, the probe's own rows and the registry entry; `try` - builds the corpus and the staging in the replay's worktree and runs that one probe, printing each row's - outcome and recording nothing. Never copy the corpus into a worktree or write a build or sync script. -- Build and run only through the verdict tool, which pins English output, builds before it tests, - names the exit codes and prints failing tests by name with their assertion: - `dotnet tools/BuildVerdict/bin/Release/net10.0/build-verdict.dll build test/CodoMetis.TypeKit.Samples` - (cold, about 1 to 2 minutes), then `dotnet tools/BuildVerdict/bin/Release/net10.0/build-verdict.dll test - --project test/CodoMetis.TypeKit.Samples --filter-class "*Probe"`. Build the tool first, `dotnet build - tools/BuildVerdict -c Release`: a fresh worktree has no dll and a stale one refuses (exit 3). - The full log is at `$(git rev-parse --absolute-git-dir)/build-verdict-last.log`. -- Warnings are errors. Add `#pragma warning disable xUnit1051` at the top of a probe that awaits - without a cancellation token; an obsolete setting (`IgnoreNullValues`) needs its `SYSLIB` id - suppressed. A probe that deliberately uses something the analyzer refuses suppresses that one CMTK - id around the line and says why. -- HTTP probes: `WebApplication.CreateBuilder(new WebApplicationOptions { EnvironmentName = - Environments.Production })` (Development adds the developer exception page, and a refusal then - arrives as a 500), `builder.WebHost.UseTestServer()`, the JSON options through - `builder.Services.ConfigureHttpJsonOptions(...)`, then `app.StartAsync()` and `app.GetTestClient()`. - The OpenAPI document is at `/openapi/v1.json` after `builder.Services.AddOpenApi(o => { - o.OpenApiVersion = ...; o.AddTypeKit(); })` and `app.MapOpenApi()`. A controller must be `internal` - and added through an `IApplicationFeatureProvider`; a public one is discovered by - every other host in the project. A host with controllers must put its own converters and resolvers - on MVC's `JsonOptions` too, or the document is refused on purpose (`DescribedOptionsAgreement`). - `test/CodoMetis.TypeKit.AspNetCore.Tests/ProbeHost.cs` is a working example to copy from. -- How a row ends: a check returns null or the failure text, and runs through `Rec.Run`, which fails the - test for a violation or a harness error and skips it, with its reasons, for any other outcome but a - pass; a check that throws ends as a harness error, never a violation, and no seed counts it caught. A check - says how it compared with `r.Note(NoteKeys.Name, detail)`. The key, a member of `NoteKeys` in `harness/Row.cs`, - alone decides the note's outcome: every key is a pass key but `framework-refuses`, the three-sided - differential's expected refusal, and a check that did not apply, refused or could not tell says so through - its scope with a citation (below), never a note key. Keys are constants the compiler checks: a new one goes - into `NoteKeys` with its outcome on one line, and a string, a misspelled member or a key built from text does - not compile (decision 103). A probe outside the namespace `Probes.Shapes` writes `using NoteKeys = Probes.Shapes.NoteKeys;`. - Never match a failure's text to excuse it. A difference the framework makes on its own is shown by a - baseline in the same row (the document as ASP.NET writes it without `AddTypeKit()`, - `Hx.DocRefusedByAspNetAlone`, a refusal compared by exception type and stage as `Sides.Alike` compares one), - not by a substring. A document both refuse alike is the framework's refusal for a check that compared nothing - else, and leaves a check that compared an answer on the wire first to be judged by that answer. A row that would fail for an open finding calls - `r.Skip("F7", why)`, the finding as a string literal: `register` and `publish` refuse a skip whose finding - is built from text or is not open in the ledger, naming the file and line. The gate refuses while any row - skips, and the replay fails a skip whose finding the ledger has fixed or dismissed. -- Checks: a comparison is `r.Check("obligation", Baseline.Twin, c => ...)` (or the `async` form), one per - obligation of the claim (`claim` for a claim without them), against one baseline of `Baseline` (`Twin`, - `Framework`, `RoundTrip`, `Model`, `Refusal`, `Cost`, `Fact("KB-031")`, `Docs("file#anchor")`). The check reads - through `c["axis"]` (or the row, inside the body: both read for the check), notes how it compared with - `c.Note(NoteKeys.Compared, ...)`, and says why it did not compare with `c.Inapplicable(Cite...)`, - `c.Refused(Cite...)` or `c.Inconclusive(reason)`, each returning null. A citation is `Cite.NotPromised("id")` (an - entry of the claim's `not-promised`), `Cite.Docs("file#anchor")`, `Cite.Fact("KB-031")` or `Cite.Record("0094")`, - written with a string literal; `register`, `publish` and the conventions tests refuse anything else and a - citation that names nothing. A failure returned is the check's violation, an exception its harness error (the - row's other checks still run), and a pass with no baseline a harness error. A row passes when no check failed - and one passed, so a check that did not apply voids no other; the ledger credits each passing check with the - axes it read and the row's, never a pair put together from two checks. A seed naming an obligation is caught - only by a check naming it. -- Two-sided checks: the twin is `Entry.Plain`, the wrapped type at the value object's nullability (a class value object over a - struct faces the struct made nullable; the closed set faces a string), written by `shapes.cs` beside the value object. Build both - sides with `Sides.Twins(position, containing, entry, plain, vo)`, which puts the row's position and containing type around each and - throws, a harness error, where the two do not hold the same shape. Under `json.TypeInfoResolver=source-generated-context` the options - resolve through `ProbeContext` alone, which lists every shape, position and containing type and each twin, with no reflection behind - it; `json.TypeInfoResolverChain=context-then-default` puts the reflection fallback after it. A shape the context does not list is a - harness error, never a fallback (tools/probe/generators/README.md, "The twin and the context"). -- EF probes: SQLite in memory (`Data Source=:memory:` with the connection held open). PostgreSQL needs - a server and is out of reach. -- Analyzer probes (what compiles and what CMTK reports): in `test/CodoMetis.TypeKit.Analyzers.Tests`, - a `CSharpCompilation` over `RealTypeKit.References` (`AnalyzerTest.cs`) with the analyzers attached, - asserting the diagnostics. The type-shape catalogue is the row there, as source text. -- Native AOT is measured only by `./test/consumer-smoke-test.sh` (minutes, needs clang). Probe it only - when the caller asks for it. - -## Seeds: every probe shows it can fail - -A probe that passes proves something only if it can fail. Every registered probe names one seeded -product defect ([decision 100](../design/adr/0100-every-probe-is-shown-to-fail-against-a-seeded-defect.md)): -a patch against `src/` that breaks what its claim promises, in `tools/probe/corpus/seeds/.patch`, -and a sentence saying what it breaks, in its registry entry: - -```json -"seed": { "patch": "seeds/L01-json-bytes.patch", "defect": "A dictionary key is written with ToString(), not the wrapped type's key converter and DictionaryKeyPolicy." } -``` - -- Write the seed with the probe. Make the defect in `src/` of the scratch copy, take `git diff -- ` - as the patch, undo it by inverse edit (`git apply -R `), and register with `prober register ... - --seed seeds/.patch --defect ""`. An environment toggle (`"env": {...}`, set for the - build and every run) is a seed too, where the product reads one; none does today. -- Seed the defect the claim is about, the one a consumer would meet: a facet dropped, a refusal that - quotes its input, a rule skipped, a key no longer generated. A seed whose build fails proves nothing, - and the command counts it as a failure. -- `prober seeds [--probe P]` applies each seed in a scratch worktree of its own (`replay --where` names - it), builds, replays the probe there and requires a row that ends as a violation the unseeded probe - does not have; a missed seed fails it. It records no evidence and takes no lock. The worktree is per - checkout, so runs in two checkouts (a linked worktree each) never meet, but two runs at once in one - checkout share it. One build per seed, so it runs locally, never in CI: after writing a probe or - changing its harness, and before a release. -- Without a build, the prober tests hold the rest on every run (`SeedsTests`): every registered probe - has a seed, and its patch touches only `src/` and still applies. A product change that moves the - patched lines fails there; make the seed again against the new code. -- A seed per obligation ([decision 104](../design/adr/0104-a-claim-states-its-obligations-and-each-has-a-seed.md)). - A seed that breaks some assertion of a probe shows the probe can fail, not that the claim is checked, so - a probe whose claim lists `obligations` carries `seeds`, one per obligation it checks, each a seed as - above with an `obligation` naming it; `seed` may name one too. A seed that names none counts only for a - claim without `obligations`. Register each with `prober register --probe P --claim C --filter "*P" - --obligation --seed seeds/-.patch --defect ""`, the command `prober new` prints - for each obligation: it replaces a seed of the entry that names the same obligation and refuses an id the - claim does not list. Never edit the staged registry by hand. `prober seeds` runs each seed of a probe on its own and reports it as - `P/`, in its output and in `seeds-last.json`; `prober status` shows per claim its obligations - and the ones no seed names; and `SeedsTests` refuses, without a build, a seed naming an obligation its - claim does not list and a listed obligation of a claim with probes that no seed of them names. - -## Claim sources - -In this order: the root `README.md` ("What TypeKit guarantees" first), `docs/*.md`, the package -READMEs (`src/*/README.md`), then `design/adr/*.md` for intent. Statements in `docs/` and the READMEs -are promises to consumers; a design record explains, and decides what is intended. - -## Axes - -The axes are data, read by `prober universe` (tools/Prober), which builds each claim's -axes from its surfaces. The prober assigns surfaces to a claim; it does not choose axes. - -- **Generated axes** come from `tools/probe/enumerate.cs`, which enumerates by reflection every - public settable property of `JsonSerializerOptions` (`json.*`), `OpenApiOptions` (`openapi.*`) and - `MvcOptions` (`mvc.*`) at the versions this repository pins. `prober replay` runs it - outside the repository (so neither `global.json` nor central package management applies to it), with - its package versions taken from `Directory.Packages.props`, whenever a dependency input changes, and - `--all` always does. A setting whose type is not a bool or an enum takes its values from `hand` below. -- Every generated axis is either reached by a surface's pattern or listed under `ignored` with the - reason. The script reports any other as **unassigned**: a setting a new framework version added, - which needs a decision here. -- `shape.*` is the type-shape catalogue: the forms a consumer's own type takes. Generate the - declarations a round needs with an app of `tools/probe/generators/` (extend one, or add one and its row - in `GeneratedHarnessTests`), once per round, as one pairwise set shared by every claim. -- A claim may drop a surface axis only by quoting the document sentence that limits it (`narrow`). -- A claim may drop pairs no row can hold, or that the documents do not promise, only with the reason - (`exclude`: a list of `{"reason": "...", "pairs": [["a=1", "b=2"], ...]}`): one sentence, citing the docs - sentence, the record or the KB fact where one applies. Nothing checks a reason mechanically, so - `prober universe` prints each one beside the claim's narrowings for a reviewer, and the prober refuses a - claims.json with any field its schema (`tools/Prober/Schemas/claims.schema.json`) does not have - ([decision 102](../design/adr/0102-an-exclusion-carries-its-reason.md)). -- An obligation may say where it does not apply, by the claim's own axis values and a citation - (`inapplicable`: a list of `{"axes": {"shape.kind": ["closed-set"]}, "cite": "not-promised:closed-set-has-no-scale"}`, - the cite `not-promised:id`, `docs:file#anchor`, `fact:KB-NNN` or `record:NNNN`). `Row.Check` reads the same - declarations and records such a check inapplicable before its body runs; a pair no obligation wants is never - put in a generated row, and the gate leaves it out as it leaves out an exclusion. A condition only the shape - instance decides at run time stays in the check's body as `c.Inapplicable(cite)`. -- `refused` drops a value the framework itself refuses on its own, so no row wastes its pairs on it. A reason that - rests on a verified fact names it (`fact:KB-NNN`), and that fact has a test: `docs-query check` fails - `fact-not-executable-cited` for a refused entry, a not-promised entry, an applicability condition or a harness - citation of a fact without one ([decision 107](../design/adr/0107-a-cited-fact-is-executable-and-seeds-run-by-footprint.md)). - `shape.refused-kind` holds the declarations the generators refuse; only the generation surface takes - it, where the refusal is the claim. Each value is a declaration and the id the Generators README's - "Build errors" table gives it, declared as C22's probe does (`harness/BuildRefusals.cs`): an unsealed - record class; a value object over another value object; over `List`; an abstract record or class with - a marker (CMTK1022 since `1ef30be`: the label keeps the id it had when C09's and C11's rows were - generated, which carry it); over `object`; over `System.Enum`; a value object named as a member the - generators add (`From`, `Parse`, `MinValue`, ...); a closed set named as one of its generated members - (`Name`, `All`, `Match`, ...); a value object with a hand-written `operator ==` and `!=` between two of - the type. The last five are the refusals of the fixes `53188ed` and `e4b751c`, which no probe reached - until C22 (design/finder-benchmark-2026-10-16.md). -- A claim lists what it promises in `obligations`, one entry per promise a probe can check on its own: an - `id`, the `sentence` quoted verbatim from the claim's source and checked as a narrowing is, and the `axes` - values it concerns where it is not the whole claim. A claim without the field has one obligation, the - claim itself, under the id `claim`. Each obligation of a claim with probes has a seed that names it - ([decision 104](../design/adr/0104-a-claim-states-its-obligations-and-each-has-a-seed.md)). -- What a claim does not promise goes in `not-promised`: an `id`, the `source` (`file#heading`) of the - document or record that makes the difference intended, its `sentence`, quoted verbatim and checked against - that source, and the `axes` values it concerns. A note of outcome expected-refusal, a narrowing or an - applicability condition cites the entry by its id. `prober universe` refuses an obligation or an entry - whose sentence its document does not hold, and an id listed twice, naming the claim and the id. -- `out-of-reach` names a surface no probe reaches, with the reason: one that needs a server, a toolchain - or minutes a replay does not have. `prober gaps` prints it beside the settings no surface reaches, the - settings without values, the refused shapes and values, and every not-promised entry and narrowing, each - with its recorded reason. It is a report for the release checklist and a feature-research round; it - decides nothing and runs no model. -- `http.host` has two values without `[ApiController]`, where MVC infers no `[FromBody]` and answers no - automatic 400. `controller-without-ApiController` is for **runtime claims only**: ASP.NET's API explorer - leaves such a controller out of the document (docs/aspnet-core.md, "Bind value objects in MVC"), so a - document check has nothing there to read. A document (OpenAPI) claim lists `http.host` in its own - `axes` in `claims.json` without it. `controller-without-ApiController-visible` hosts the same - controllers made visible by an `IApplicationModelConvention` that sets `ApiExplorer.IsVisible = true` - (`VisibleToApiExplorer` in the harness), so document checks reach them; every http claim takes it. -- `process.*` holds what other code in the same process may have done first (2026-10-15: a wrapped - type's `TypeConverter` looked up before the value object's parsing broke that parsing). - -```json probe-axes -{ - "hand": { - "json.PropertyNamingPolicy": [ - "CamelCase", - "SnakeCaseLower", - "SnakeCaseUpper", - "KebabCaseLower", - "KebabCaseUpper", - "own-upper-case" - ], - "json.DictionaryKeyPolicy": [ - "CamelCase", - "SnakeCaseLower", - "KebabCaseUpper", - "own-upper-case" - ], - "json.ReferenceHandler": [ - "Preserve", - "IgnoreCycles" - ], - "json.Converters": [ - "own-for-wrapped", - "own-for-value-object", - "JsonStringEnumConverter", - "StoredJsonConverterFactory" - ], - "json.TypeInfoResolver": [ - "source-generated-context", - "default-with-renaming-modifier" - ], - "json.TypeInfoResolverChain": [ - "context-then-default" - ], - "json.Encoder": [ - "UnsafeRelaxedJsonEscaping" - ], - "json.MaxDepth": [ - "3" - ], - "json.DefaultBufferSize": [ - "1" - ], - "json.IndentCharacter": [ - "tab" - ], - "json.IndentSize": [ - "1" - ], - "json.NewLine": [ - "lf" - ], - "openapi.CreateSchemaReferenceId": [ - "own-prefixing", - "null-inlines-all" - ], - "openapi.ShouldInclude": [ - "default-only" - ], - "openapi.transformers": [ - "own-schema-transformer", - "own-operation-transformer", - "own-document-transformer" - ], - "mvc.InputFormatters": [ - "xml-added" - ], - "mvc.OutputFormatters": [ - "xml-added" - ], - "mvc.ModelBinderProviders": [ - "own-provider-first" - ], - "mvc.Conventions": [ - "own-route-prefix" - ], - "mvc.MaxModelBindingCollectionSize": [ - "2" - ], - "mvc.MaxModelValidationErrors": [ - "1" - ], - "mvc.MaxValidationDepth": [ - "1" - ] - }, - "ignored": { - "json.WriteIndented": "layout only; JSON parity compares under the same options", - "json.IndentCharacter": "layout only", - "json.IndentSize": "layout only", - "json.NewLine": "layout only", - "json.DefaultBufferSize": "buffering only; DefaultBufferSize 1 is kept in hand for a stress round on request", - "openapi.ShouldInclude": "selects endpoints, never a schema's shape", - "mvc.EnableActionInvokers": "invocation pipeline, not binding or formatting", - "mvc.EnableEndpointRouting": "TypeKit supports endpoint routing only", - "mvc.RequireHttpsPermanent": "transport", - "mvc.SslPort": "transport", - "mvc.CacheProfiles": "caching headers", - "mvc.SuppressAsyncSuffixInActionNames": "action naming", - "mvc.SuppressInputFormatterBuffering": "buffering", - "mvc.SuppressOutputFormatterBuffering": "buffering", - "mvc.MaxIAsyncEnumerableBufferLimit": "streaming", - "mvc.MaxModelBindingRecursionDepth": "recursion limit of binding, reached only by self-referencing models", - "mvc.ModelMetadataDetailsProviders": "covered by own-provider-first on binders", - "mvc.ModelValidatorProviders": "validation providers; TypeKit validates in Create", - "mvc.ValueProviderFactories": "value sources; the binding axis covers them" - }, - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class", - "closed-set" - ], - "shape.site": [ - "top-level", - "nested-in-class", - "nested-in-struct", - "nested-two-levels", - "in-generic-type" - ], - "shape.inheritance": [ - "none", - "base-depth-1", - "base-depth-2", - "base-depth-3", - "base-explicit-IEquatable", - "explicit-interface-member" - ], - "shape.wrapped": [ - "string", - "Guid", - "int", - "long", - "byte", - "ulong", - "decimal", - "double", - "bool", - "char", - "DateTime", - "DateTimeOffset", - "DateOnly", - "TimeOnly", - "TimeSpan", - "enum", - "flags-enum", - "Uri", - "NodaTime.Instant", - "own-record-class" - ], - "shape.position": [ - "root", - "property", - "nullable-property", - "field", - "list-element", - "array-element", - "immutable-array-element", - "read-only-list-element", - "dictionary-key", - "dictionary-value", - "record-ctor-parameter", - "required-init", - "in-patch", - "polymorphic-derived-property" - ], - "shape.containing": [ - "class", - "record-class", - "struct", - "record-struct", - "generic-type" - ], - "input.json": [ - "valid", - "refused-by-create", - "wrong-token", - "null", - "empty-string", - "at-type-limit", - "quoted-number", - "escape-sequence", - "duplicate-property", - "metadata-property" - ], - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController", - "controller-without-ApiController-visible" - ], - "http.binding": [ - "route", - "query", - "header", - "body", - "form", - "as-parameters" - ], - "http.response": [ - "result-to-http-result", - "composed-fault", - "two-faults-same-name", - "group-with-fault-status", - "endpoint-without-faults", - "declared-produces-problem" - ], - "ef.query": [ - "where-equals", - "where-value-compare", - "order-by", - "contains", - "first-or-none", - "select", - "group-by", - "execute-update", - "compiled-query", - "as-no-tracking" - ], - "ef.mapping": [ - "property", - "key", - "integer-key", - "nullable", - "owned", - "complex", - "closed-set" - ], - "text.entry": [ - "Parse", - "TryParse", - "TryFrom", - "type-converter", - "IParsable", - "ISpanParsable", - "ToString-format", - "TryFormat-short-span" - ], - "text.culture": [ - "invariant", - "de-DE", - "tr-TR", - "ar-SA", - "globalization-invariant" - ], - "or.shape": [ - "Option", - "Result-T-E", - "Result-E", - "Task-of-Result", - "ValueTask-of-Result" - ], - "or.operation": [ - "Match", - "Bind-Map-chain", - "query-syntax", - "Sequence-Transpose", - "Result.Catch", - "FirstOrNone", - "default-instance", - "after-await-elsewhere" - ], - "shape.refused-kind": [ - "unsealed-record-class (CMTK1006)", - "over-value-object (CMTK1005)", - "generic-wrapped (CMTK1005)", - "abstract (CMTK1005)", - "over-object (CMTK1005)", - "over-System.Enum (CMTK1005)", - "named-as-generated-member (CMTK1005)", - "closed-set-named-as-generated-member (CMTK1021)", - "equality-operator (CMTK1011)" - ], - "process.converter-lookup": [ - "none", - "wrapped-type-converter-looked-up-first" - ], - "http.nullability": [ - "as-declared", - "nullable" - ] - }, - "surfaces": { - "json": { - "axes": [ - "json.*", - "shape.kind", - "shape.wrapped", - "shape.position", - "shape.containing", - "input.json" - ], - "watched": [ - "src/CodoMetis.TypeKit.Generators", - "src/CodoMetis.TypeKit/ValueObjects", - "src/CodoMetis.TypeKit/DecimalJsonConverters.cs", - "src/CodoMetis.TypeKit/Patch.cs" - ] - }, - "http": { - "axes": [ - "json.*", - "openapi.*", - "mvc.*", - "http.*", - "process.*", - "shape.kind", - "shape.wrapped", - "shape.position", - "shape.containing", - "input.json" - ], - "watched": [ - "src/CodoMetis.TypeKit.AspNetCore", - "src/CodoMetis.TypeKit/Fault.cs", - "src/CodoMetis.TypeKit/FaultOfSets.cs", - "src/CodoMetis.TypeKit.Generators" - ] - }, - "ef": { - "axes": [ - "ef.*", - "shape.kind", - "shape.wrapped", - "shape.site" - ], - "watched": [ - "src/CodoMetis.TypeKit.EntityFrameworkCore", - "src/CodoMetis.TypeKit.Generators" - ] - }, - "text": { - "axes": [ - "text.*", - "process.*", - "shape.kind", - "shape.wrapped" - ], - "watched": [ - "src/CodoMetis.TypeKit/StringTextExtensions.cs", - "src/CodoMetis.TypeKit/TextFault.cs", - "src/CodoMetis.TypeKit.Generators" - ] - }, - "generation": { - "axes": [ - "shape.*" - ], - "watched": [ - "src/CodoMetis.TypeKit.Generators", - "src/CodoMetis.TypeKit/ValueObjects" - ] - }, - "option-result": { - "axes": [ - "or.*", - "shape.wrapped" - ], - "watched": [ - "src/CodoMetis.TypeKit/Option.cs", - "src/CodoMetis.TypeKit/OptionExtensions.cs", - "src/CodoMetis.TypeKit/Result.cs", - "src/CodoMetis.TypeKit/ResultT.cs", - "src/CodoMetis.TypeKit/ResultExtensions.cs", - "src/CodoMetis.TypeKit/SequenceOptionExtensions.cs", - "src/CodoMetis.TypeKit/ValueTypeOptionExtensions.cs" - ] - }, - "analyzers": { - "axes": [ - "shape.*" - ], - "watched": [ - "src/CodoMetis.TypeKit.Analyzers", - "src/CodoMetis.TypeKit/TypeArgumentConstraints.cs" - ] - }, - "logging": { - "axes": [ - "shape.kind", - "shape.wrapped", - "input.json" - ], - "watched": [ - "src/CodoMetis.TypeKit.Serilog", - "src/CodoMetis.TypeKit/Refusals.cs" - ] - } - }, - "out-of-reach": { - "postgresql": "needs a server; the EF probes run SQLite in memory, and the EF translation claims are checked by translation alone", - "native-aot": "measured only by the consumer smoke test (tools/ConsumerSmokeTest), minutes and a platform linker; no probe publishes with Native AOT" - }, - "refused": { - "shape.site": { - "in-generic-type": "CMTK1005: the generators refuse a value object nested in a generic type at build (Generators README, Build errors)" - }, - "json.ReadCommentHandling": { - "Allow": "System.Text.Json refuses it on the options object" - }, - "json.DefaultIgnoreCondition": { - "Always": "System.Text.Json refuses it on the options object" - } - }, - "replay": { - "project": "test/CodoMetis.TypeKit.Samples", - "probeDir": "test/CodoMetis.TypeKit.Samples/Probes", - "prepare": [ - [ - "dotnet", - "build", - "tools/BuildVerdict", - "-c", - "Release", - "-nologo", - "-v:q" - ] - ], - "build": [ - "dotnet", - "tools/BuildVerdict/bin/Release/net10.0/build-verdict.dll", - "build", - "{project}" - ], - "test": [ - "dotnet", - "tools/BuildVerdict/bin/Release/net10.0/build-verdict.dll", - "test", - "--no-build", - "--project", - "{project}", - "--filter-class", - "{filter}", - "--", - "--results-directory", - "{results}" - ], - "coverage": [ - "--coverage", - "--coverage-output-format", - "cobertura", - "--coverage-output", - "{cobertura}" - ], - "families": { - "http": [ - "http" - ], - "ef": [ - "ef" - ], - "json": [ - "json" - ], - "text": [ - "text", - "logging" - ], - "build": [ - "generation", - "analyzers", - "option-result" - ] - }, - "include": [ - "src" - ], - "compileTimeFootprint": [ - "src/CodoMetis.TypeKit.Generators", - "Directory.Packages.props", - "Directory.Build.props", - "global.json", - "test/CodoMetis.TypeKit.Samples/CodoMetis.TypeKit.Samples.csproj" - ], - "coverageTargets": "\n \n \n \n\n", - "toolchain": { - "dotnet": [ - "dotnet", - "--version" - ] - }, - "enumerate": { - "script": "tools/probe/enumerate.cs", - "inputs": [ - "Directory.Packages.props", - "global.json" - ] - } - } -} -``` - - -## Oracles this repository promises - -- **JSON parity (differential).** A shape with a value object and the same shape with the wrapped - type, serialized under the same options, give the same bytes, and each reads the other's JSON. - `test/CodoMetis.TypeKit.Generators.Tests/JsonParityTests.cs` shows the pattern. -- **Schema parity (differential).** The OpenAPI schema of a value-object property equals the one - ASP.NET Core publishes for the wrapped type in the same position, in every document version. -- **Wire and document agree (differential).** The statuses and problem types a fault response sends - are the ones the document lists for that operation, in both hosting models. -- **Column parity (differential).** The EF model gives a value-object property the wrapped type's - column type, and a query over `.Value` translates to the same SQL as the query over the wrapped - property. -- **One set of rules (differential).** `TryFrom`, `Parse`, `TryParse`, the JSON converter, the type - converter and `FromKnownGood` accept exactly what `Create` accepts, and every refusal names the - fault `Create` returned. -- **No refusal quotes the input (exception).** Put a sentinel such as `SECRET-7f3a` in refused input; - it must not appear in any exception message, inner exception, `ToString()`, ProblemDetails body or - log line. The one exception is a dictionary key in `JsonException.Path`. -- **Off the wire (exception).** `Option` and `Result` throw `NotSupportedException` from - System.Text.Json in both directions, in every position, unless the application registered its - own converter. -- **Equality (metamorphic).** Equal value objects have equal hash codes, `CompareTo` is zero exactly - when `Equals` is true, and both agree with the wrapped type's, through every base in the - inheritance chain. -- **Round trip (metamorphic).** `Parse(x.ToString())`, a JSON write then read, and a column write - then read give back an equal value object. -- **Loud, not silent (exception).** A declaration that cannot be generated fails the build with a - CMTK id; it never compiles into a type with nothing in it. - -## Intended: a refusal or difference here is a pass - -- A `DateTime` is written as UTC; number handling set by an attribute on the containing type reaches - no converter (README, "What TypeKit guarantees"). -- A struct value object refuses a JSON `null`. -- A rejected dictionary key appears in `JsonException.Path`, and so in MVC's 400. -- Under a source-generated context, a value object over an enum needs the enum listed in the context. -- A validated value object has no `From`; an abstract value object fails with CMTK1022, and a generic - wrapped type with CMTK1005. -- A missing `Option` property, and an empty collection or dictionary of `Option` or `Result`, pass - through System.Text.Json without an exception, since no converter runs (a wording question for the - README, raised 2026-10-15, not a finding). -- The EF Core package and `StoredJsonConverterFactory` skip validation by design. -- A host whose MVC and minimal-API JSON options describe a type differently has its document refused - (`DescribedOptionsAgreement`). -- System.Text.Json refusing a combination of its own options with an exception of its own (for - example `IgnoreNullValues` together with a `DefaultIgnoreCondition`). -- Anything a record in `design/adr/` decides. Search the records before calling a refusal a finding. -- Findings already reported by `code-analyst` are in - `.claude/agent-memory-local/code-analyst/review-2-1-0-findings.md`. Do not report them again. - -## Budget - -Twelve claims a round unless the caller says otherwise. One build of the Samples project serves them -all; group the round's probes there. diff --git a/.claude/settings.json b/.claude/settings.json index 5429aeeb..4c835160 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -11,7 +11,7 @@ }, { "type": "command", - "command": "dotnet build tools/AgentTools.slnf -c Release -nologo -v q -tl:off -clp:NoSummary >/dev/null 2>&1 || PATH=\"/usr/local/share/dotnet:$PATH\" dotnet build tools/AgentTools.slnf -c Release -nologo -v q -tl:off -clp:NoSummary || echo \"Session start: the tools in $PWD (build-verdict, prober, docs-query, consumer-smoke-test) did not build with the dotnet on PATH, nor with the installer's in /usr/local/share/dotnet; a dotnet without the SDK global.json pins is the usual cause. Run dotnet build tools/AgentTools.slnf -c Release to see why, and before using them.\"", + "command": "dotnet build tools/AgentTools.slnf -c Release -nologo -v q -tl:off -clp:NoSummary >/dev/null 2>&1 || PATH=\"/usr/local/share/dotnet:$PATH\" dotnet build tools/AgentTools.slnf -c Release -nologo -v q -tl:off -clp:NoSummary || echo \"Session start: the tools in $PWD (build-verdict, docs-query, consumer-smoke-test, pr-hygiene) did not build with the dotnet on PATH, nor with the installer's in /usr/local/share/dotnet; a dotnet without the SDK global.json pins is the usual cause. Run dotnet build tools/AgentTools.slnf -c Release to see why, and before using them.\"", "timeout": 300 } ] diff --git a/.claude/skills/probe-triage/SKILL.md b/.claude/skills/probe-triage/SKILL.md deleted file mode 100644 index 1373245c..00000000 --- a/.claude/skills/probe-triage/SKILL.md +++ /dev/null @@ -1,261 +0,0 @@ ---- -name: probe-triage -description: Decide what one failing probe row means, by four questions in a fixed order — a harness error, a pinned framework fact, an intended difference the claim does not promise, or a finding for the code-analyst — stopping at the first that applies and recording the step where the corpus keeps it. Use for every failing row at the end of a probing round, for a `prober status` finding (`R--`, `F`), for a row a replay or `prober try` printed as failed, and whenever someone asks whether a probe failure is real. ---- - -# Probe triage - -A failing row is a question, not a finding. Most of what the prober has cost went into answering it by -judgement, mid-round: the gate round of 2026-10-16 wrote 18 probes, found two product defects and about -ten harness traps, and left five failing rows of C07 untriaged. This skill answers the question by -lookup, in a fixed order, so two people (or a person and an agent) reach the same answer for the same -row, and the answer is written where the next replay and the next reader find it. - -**The order is the rule.** Ask the four questions in turn and stop at the first that applies. Do not skip -ahead because a row "looks like" a product bug: a harness that compares unlike things produces the most -convincing product bugs there are. Every outcome names its step, `triage 1` to `triage 4`. - -The writer of a probe never decides what a refusal means. The probe checks; this skill decides. - -## Before the steps: get the row, and make it fail again - -You start from one of these: - -- **A finding id** from `prober status`: `R--` (the replay saw a probe that passed with the - same identity fail) or `F`. Its last line in the branch's `findings.jsonl` names the probe and the - commit. The state directory, `$STATE` below, is `PROBE_STATE_DIR` when set, else the main checkout's - `.claude/agent-memory-local/prober/`; the branch's directory is `branches//`. -- **A row a run printed:** `prober try` and `prober replay` print the failed probe and how each row ended. - A replay that says "fails after a change to its corpus, axes, environment or this tool; triage the probe, - not the product" opened no finding: start at step 1 and expect to stop there. -- **A row's evidence line:** the line `Rec.Run` writes, or the probe's evidence after a replay: - - ```bash - jq '.rows["358"] | {category, reasons, applied}' "$STATE/branches/release-2.2.0/evidence/BaseProbe.json" - ``` - -From it, write down: the claim, the probe, the row's index, its category (`violation`, `harness-error`, -`inconclusive`), its reasons, and the settings that applied. Then run the row at HEAD, three times: - -```bash -dotnet tools/Prober/bin/Release/net10.0/prober.dll try --probe BaseProbe --rows 358 -dotnet tools/Prober/bin/Release/net10.0/prober.dll try --probe BaseProbe --rows 358 --no-build # twice more -``` - -A row that passes at HEAD was fixed meanwhile: say so with the commit, and stop. A row that does not -fail every time is flaky, and flaky is not a finding: record it as `flaky` (a round's ledger line, or -your report) and stop. Only a -row that fails every time goes on to step 1. - -## 1. Is it a harness error? - -**It applies when** the row's reasons carry `harness-error`, or the failure comes from the harness rather -than from the product: - -- the category is `harness-error`: a check threw (`UNEXPECTED : ...`, which decision 103 makes - a harness error and never a violation), a check `prober new` staged and nobody wrote, or the equivalence - precondition (`inputs not equivalent: wrapped [...] vs value object [...]`), which says the two sides - were not the same shape and so were never comparable; -- a 404 on a bind route, a context type the source-generated `ProbeContext` does not list, a host that did - not start for a reason the row's settings do not explain; -- a `violation` whose whole difference lies in something the harness built or named rather than something - TypeKit wrote: a component or route name made from the twin's own type name, a twin at another - nullability, kind or position than the value object (concept H2), an input the harness placed - differently on each side. Read the two sides' answers in the reasons, or in the full log of the `try` - run, and find the first byte that differs. If it is the harness's, this step applies. - -**Then** fix the harness so the row compares like with like, and run the row again. No finding is filed. -A row that now fails with a different difference starts again at step 1. - -**Record:** - -- the harness fix, as a `test:` commit whose body names the row and says `triage 1`: what the harness - did and what it does now (94554b3 is the model). In a round, the fix goes to the staging's `harness/` - and the round's report says it; the session that publishes commits it; -- with a finding id, a line appended to the branch's `findings.jsonl`: - - ```json - {"schemaVersion":1,"id":"R-BaseProbe-1a2b3c4","status":"withdrawn","reason":"triage 1 harness-error: the /schema/ endpoint had no twin at the value object's nullability; fixed in 94554b3"} - ``` - -## 2. Does a fact at the pinned version explain it? - -**It applies when** a fact in `design/knowledge/` says the framework, without TypeKit, does what the row -saw: the same refusal at the same operation, or the same document, at the version the repository pins. -A fact about the framework explains a row only where the framework alone makes the difference. A fact -that describes how the framework treats the wrapped type, while the value object differs from it, does -not explain the row; it is the evidence of step 4. - -**Check with** the framework, the setting and the operation the row names: - -```bash -dotnet tools/DocsQuery/bin/Release/net10.0/docs-query.dll find controller API explorer document visible --kind fact -dotnet tools/DocsQuery/bin/Release/net10.0/docs-query.dll entry KB-002 -dotnet tools/DocsQuery/bin/Release/net10.0/docs-query.dll check # no fact-behind or fact-ahead for it -``` - -A miss of `find` proves nothing: try the setting's own name and the exception type too. Read the fact's -frontmatter. It is **executable** when its `test:` line names a test under `test/CodoMetis.TypeKit.Facts` -(`test: test/CodoMetis.TypeKit.Facts/KB002.cs`). Run that test: - -```bash -dotnet tools/BuildVerdict/bin/Release/net10.0/build-verdict.dll test --project test/CodoMetis.TypeKit.Facts --filter-class "*KB002" -``` - -**Then:** - -- **An executable fact that passes and explains the row** makes it a framework refusal. The check is - changed to cite the fact, no finding is filed. -- **A fact whose pin is stale**, or whose test fails, settles nothing until it is verified again - (decision 93). Verify it first. -- **A fact without a test** (`test: none, ...` or `prose`) that would explain the row is a research task: - measure the behaviour in `test/CodoMetis.TypeKit.Facts` as `KB.cs`, give the fact its `test:` - line, then cite it. A fact without a test may be cited in a reason and nothing more: it never prunes a - row and never excuses one. -- **No fact, but the row's own baseline shows the framework alone doing it** (the document - `Hx.DocRefusedByAspNetAlone` refuses for ASP.NET alone too, or the wrapped type alone refuses under the - same options): that is a new framework behaviour. It becomes a new fact with its test under - `design/knowledge/` (its README, "Adding one"), never a new note key. Then cite it. -- Otherwise go to step 3. - -**Record:** - -- the citation, where the corpus holds one: a `not-promised` entry of the claim whose `source` is the - fact's file and whose `sentence` is quoted from it (step 3's form), an `exclude` group whose `reason` - names `KB-NNN`, or a value in the axes file's `refused` object whose text names `KB-NNN`, or the check's - own `Cite.Fact("KB-NNN")`; -- with a finding id: - - ```bash - dotnet tools/Prober/bin/Release/net10.0/prober.dll dismiss --id R-C03ComposedProbe-1a2b3c4 --reason "triage 2 fact KB-002: a controller without [ApiController] is missing from the document for ASP.NET alone, so the row's document part has nothing to check" - ``` - - `dismiss` stages the line; `prober publish` puts it in `tools/probe/corpus/dismissed.jsonl`; -- in a round, a fact to measure goes in the report under "Facts to measure", with the row and the - configuration. The agent writes no test; the session that takes the report does. - -## 3. Does the claim say it does not promise this? - -**It applies when** a `not-promised` entry of the row's claim covers the row's settings, or a sentence of -the docs or of a decision record says the difference is intended. - -**Check with** the claim's entries and narrowings, and the docs: - -```bash -dotnet tools/Prober/bin/Release/net10.0/prober.dll gaps | grep 'C07-fault-responses-blanket' -jq '.[] | select(.id == "C07-fault-responses-blanket") | {narrow, "not-promised"}' tools/probe/corpus/claims.json -dotnet tools/DocsQuery/bin/Release/net10.0/docs-query.dll find nullable value object schema null --top 5 -``` - -An entry covers the row when each of its `axes` values is among the row's applied settings. A docs -sentence counts only when it says this difference, in this place, is intended. Your sense that it "must be -on purpose" does not count, and neither does the axes file's "Intended" list alone: an item there that no -document or record states is a gap of this step, not an answer. - -**Then:** - -- **An entry covers it:** the difference is intended. The row's check cites the entry by its id, no - finding is filed. -- **A document or record says so, but the claim has no entry:** that is a docs or claims gap, filed as - `docs:` work, no finding. Add the entry; if the consumer docs do not say it plainly, add the sentence - first (the `plain-docs` skill), then quote it. -- **Two documents disagree,** or a record calls intended what a consumer page promises: not this step's - to settle. It goes to the code-analyst as a question (step 4's hand-off, "a contradiction"). -- Otherwise go to step 4. - -**Record:** - -- the entry, in `claims.json` (in a round, the staging's `claims.json`), in the form of - `tools/Prober/Schemas/claims.schema.json`. `universe` refuses a sentence its `source` does not hold: - - ```json - "not-promised": [ - { - "id": "invariant-globalization-refuses-as-text", - "source": "docs/text.md#globalization-invariant-mode", - "sentence": "So `AsText()` throws `PlatformNotSupportedException` there, on its first call, whatever the string.", - "axes": { "text.culture": ["globalization-invariant"], "entry": ["AsText", "AsOptionalText"] } - } - ] - ``` - - committed as `docs:` with the sentence it quotes, beside any docs change; -- with a finding id: - - ```bash - dotnet tools/Prober/bin/Release/net10.0/prober.dll dismiss --id R-C02OptionalTextProbe-1a2b3c4 --reason "triage 3 not-promised C02-optional-text/invariant-globalization-refuses-as-text" - ``` - - and for a gap, `--reason "triage 3 docs-gap: ; entry to add"`. - -## 4. A finding: hand it to the code-analyst - -Only a row that none of steps 1 to 3 explains gets here. It is still not a finding until the -`code-analyst` agent, which reads the product path and seeds the defect in a scratch copy, confirms it. - -**Prepare the hand-off:** - -- **The row**: claim, probe, index, commit, category, the reasons, the settings that applied. -- **The shrunk row**, from the harness's `Shrinker`. There is no prober command for it yet. Run it in the - replay's worktree, which the `try` above has just built with the corpus overlaid: - - ```bash - WT=$(dotnet tools/Prober/bin/Release/net10.0/prober.dll replay --where | awk '/^replay:/ {print $2}') - cd "$WT" && PROBE_SHRINK="C07-fault-responses-blanket:358:baseline" \ - dotnet "$OLDPWD/tools/BuildVerdict/bin/Release/net10.0/build-verdict.dll" test --no-build \ - --project test/CodoMetis.TypeKit.Samples --filter-class "Probes.ShrinkProbe" - cat /tmp/shrink.txt - ``` - - `PROBE_SHRINK` is `::`: the rows file the probe reads (`Rows.Data("...")` in the - probe), the rows, and the check, `baseline` for the HTTP calibration or a name registered in - `ShrinkChecks.All` (C03, C05, L02, L03, L04). A check with no name there is handed over unshrunk, and - the hand-off says so. -- **The obligation** the failing check serves: its id and sentence from the claim's `obligations` (the - probe's header quotes them). When the check serves none of the claim's obligations, say so: "none - listed; the check holds : ". That is itself something for the analyst to - report (below). -- **Each side's answer**: the wrapped twin's with TypeKit, the value object's with TypeKit, and the - framework alone where the row ran it, each as the reasons or the log give it. -- **Why steps 1 to 3 did not apply**, one line each, with the facts and entries you looked at. - -**Hand it over** with the Agent tool, `subagent_type: code-analyst`, and a prompt that starts -`Target: triage hand-off` and carries the five items above. The analyst reads the path the row exercised, -reproduces it outside the probe, seeds the defect, and answers Confirmed, Likely or Question. Where you -cannot start an agent (the `prober` agent started as a subagent), put the hand-off in your report under -"For code-analyst", marked "awaiting confirmation", file nothing, and let the caller hand it over. - -**Then:** - -- **Confirmed:** file `F`, the next number not used in the branch's `findings.jsonl` or the corpus's - `dismissed.jsonl`. The fix is a `fix:` commit with the regression test the analyst named (the - `verify-the-guard` skill: revert it, then the variants), ending with `Defect-Class:` and - `Found-By: PR`, and its body names the analyst's confirmation. 6866822 is the model. -- **Likely or Question:** no `F`. The row stays failing, and the question goes to the maintainer in - the round's report under "For code-analyst", with the analyst's answer. -- **A missing obligation** the analyst reports (a check that holds a promise no claim lists): it is filed - as claims work, the obligation added to the claim whose source states it, or a new claim, with its seed - (decision 104). - -**Record**, only after the analyst confirms, a line appended to the branch's `findings.jsonl`, with the -shrunk probe kept in the memory's `open/`: - -```json -{"schemaVersion":1,"id":"F3","claim":"C07-fault-responses-blanket","status":"open","commit":"00d3b8f6...","probe":"open/F3NullableBodySchemaProbe.cs","reason":"triage 4 finding: an MVC [FromBody] VO? over ulong writes oneOf[null, {type:[integer,string]}] where ulong? writes [null,integer,string]; confirmed by code-analyst 2026-10-16"} -``` - -An `R-` finding that became `F` gets a `withdrawn` line whose reason is `triage 4 finding: filed as F`, -so one defect is open once. - -## What each step leaves behind - -| Step | Finding | Change | Commit | -|---|---|---|---| -| 1 harness error | `withdrawn`, `triage 1 harness-error: ...` | the harness | `test:` | -| 2 fact | `prober dismiss`, `triage 2 fact KB-NNN: ...` | the check cites the fact; a new fact gets its test first | `test:` for the citation, `docs:` or `test:` for the fact | -| 3 not promised | `prober dismiss`, `triage 3 not-promised /` or `triage 3 docs-gap: ...` | the `not-promised` entry, the docs sentence | `docs:` | -| 4 finding | `F` open, `triage 4 finding: ...; confirmed by code-analyst` | the fix and its test | `fix:` with `Found-By: PR` | - -A row without a finding id leaves the change and the commit alone. Every reason starts with -`triage `, so `grep '"triage [123]' findings.jsonl dismissed.jsonl` counts what the rounds cost -and what they found. diff --git a/.claude/skills/verify-the-guard/SKILL.md b/.claude/skills/verify-the-guard/SKILL.md index 1db2c705..b83c563d 100644 --- a/.claude/skills/verify-the-guard/SKILL.md +++ b/.claude/skills/verify-the-guard/SKILL.md @@ -51,8 +51,8 @@ before it is reported done: | `AIS`, what a type argument is | `TypeArgumentKinds`, beside it, 79 kinds and 37 pairs: classes to delegates, arrays, `dynamic`, interfaces, the abstract bases, a type built from a parameter, a parameter under each constraint and attribute, and pairs | An oracle per constraint over what each kind is, from the rule's docs, run as `TypeArgumentConstraintKindTests` runs CMTK0010 | | `AIS`, any other input | The kinds the rule registers (`Register*Action`), plus method groups, crefs, extension blocks (method, property, static member, operator, the lowered call), generic attributes, `nameof`, null-conditional access, lambdas, local functions and generated code (`GeneratedCodeTests`) | No catalogue yet: build it in `Variants/` on `TypeArgumentSites`' pattern, the subject from the rule and the shapes from the catalogue | | `EFT`, a key or a query of the EF satellite | `KeyShapes`, `QueryShapes` and `WrappedKinds` in `test/CodoMetis.TypeKit.EntityFrameworkCore.Tests/Variants/`: 13 key shapes (alone, each mapping's root, abstract or not, the dependents whose key is a foreign key, composite, configured) by 13 wrapped types on three providers; 22 wrapped types, own orderings included, by accessor, site (column, nullable, collection element, captured list, navigation, JSON, query filter), converter (TypeKit's, named, three foreign forms) and operation | A differential against the same entity over the wrapped type, with the docs' departures as the oracle, run as `KeyGenerationVariantTests` and `QueryTranslationVariantTests` do; a new case is a new value of an axis | - | `GTS` | The `shape.*` axes of `.claude/probe-axes.md` and the Samples' value objects | One declaration per value of each axis the fixed code reads (kind, site, inheritance at least), or the rows of the claim that covers it: `prober rows --claim C --full` | - | `FCI` | The settings of the API the fix touches: the `json.*`, `openapi.*`, `mvc.*` axes | The claim's pairwise rows, `prober rows --claim C`, as a theory or as the claim's probe | + | `GTS` | The declaration shapes of `test/oracles/axes.md` and the Samples' value objects | One declaration per value of each axis the fixed code reads (kind, site, inheritance at least) | + | `FCI` | The settings of the API the fix touches: the JSON, OpenAPI and host axes of `test/oracles/axes.md` | A theory over every value of the axes the fix reads, or a probe class over their product (`test/oracles/axes.md`) | Run every shape both ways where the catalogue has two: the breaking input reported (or refused) once, the meeting one never. A false report is a sibling as much as a silence is. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1b0c17ac..bd2c952d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,7 +3,7 @@ Closes # + + + + + + + + + + + + + + diff --git a/test/CodoMetis.TypeKit.Oracles.Tests/OracleCandidateTests.cs b/test/CodoMetis.TypeKit.Oracles.Tests/OracleCandidateTests.cs new file mode 100644 index 00000000..035555af --- /dev/null +++ b/test/CodoMetis.TypeKit.Oracles.Tests/OracleCandidateTests.cs @@ -0,0 +1,41 @@ +using System.Text.RegularExpressions; + +namespace CodoMetis.TypeKit.Oracles.Tests; + +///

+/// The candidate registry (test/oracles/candidates.json) names only registered oracles and tracks every entry +/// to an issue or to a labelled failure (design/adr/0112). A misspelt oracle name would match nothing, and the row +/// would silently keep failing as unknown. +/// +public sealed class OracleCandidateTests +{ + [Fact] + public void Every_candidate_names_a_registered_oracle_and_a_row() + { + var oracles = OracleCatalogue.Oracles.Select(oracle => oracle.Class).ToHashSet(StringComparer.Ordinal); + var problems = new List(); + + foreach (var candidate in Candidates.All) + { + if (!oracles.Contains(candidate.Oracle)) problems.Add($"'{candidate.Row}' names oracle '{candidate.Oracle}', which oracles.json does not register"); + if (candidate.Row.Trim().Length < 3) problems.Add($"a candidate of {candidate.Oracle} has no row text"); + if (candidate.Family.Trim().Length == 0) problems.Add($"'{candidate.Row}' has no family label"); + if (candidate.Method is { } method && !Regex.IsMatch(File.ReadAllText(SourceOf(candidate.Oracle)), $@"\b{Regex.Escape(method)}\s*\(")) + problems.Add($"'{candidate.Row}' is scoped to method '{method}', which {candidate.Oracle} does not declare"); + if (candidate.Issue.Length > 0 && !candidate.Issue.StartsWith('#') && !candidate.Issue.StartsWith("http", StringComparison.Ordinal)) + problems.Add($"'{candidate.Row}' has an issue that is neither '#' nor a URL: '{candidate.Issue}'"); + } + + problems.ShouldBeEmpty(); + } + + [Fact] + public void Candidates_are_unique_per_oracle() => + Candidates.All.GroupBy(candidate => (candidate.Oracle, candidate.Row)).Where(group => group.Count() > 1) + .Select(group => $"{group.Key.Oracle}: '{group.Key.Row}'") + .ShouldBeEmpty("Duplicate candidates."); + + private static string SourceOf(string oracle) => + Directory.EnumerateFiles(Path.Combine(OracleCatalogue.Root, "test"), oracle + ".cs", SearchOption.AllDirectories) + .First(path => !path.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", StringComparison.Ordinal)); +} diff --git a/test/CodoMetis.TypeKit.Oracles.Tests/OracleCatalogue.cs b/test/CodoMetis.TypeKit.Oracles.Tests/OracleCatalogue.cs new file mode 100644 index 00000000..9e499a07 --- /dev/null +++ b/test/CodoMetis.TypeKit.Oracles.Tests/OracleCatalogue.cs @@ -0,0 +1,187 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; + +namespace CodoMetis.TypeKit.Oracles.Tests; + +/// +/// The files under test/oracles/, loaded once: the claims the documents make, the oracle classes that hold +/// them, the seeds that prove the oracles can fail, the waivers for public members no claim covers, and the known +/// disagreements (design/adr/0112). +/// +/// +/// Everything here is data a maintainer edits by hand, and the Oracle*Tests hold it consistent with the +/// repository: a claim's quote must still be in its document, a surface must still exist, an oracle must still be a +/// test class with a seed. The tests are what make the catalogue a worklist rather than a wish list. +/// +internal static partial class OracleCatalogue +{ + // Declared first: static initializers run in textual order, and the loaders below use it. + private static readonly JsonSerializerOptions Json = new() + { + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true, + }; + + internal static string Root { get; } = FindRoot(); + + internal static string Directory { get; } = Path.Combine(Root, "test", "oracles"); + + internal static IReadOnlyList Claims { get; } = Load>("claims.json"); + + internal static IReadOnlyList Oracles { get; } = Load>("oracles.json"); + + /// Surface patterns no claim names, each with the reason it needs no oracle. + internal static IReadOnlyDictionary SurfaceWaivers { get; } = Load>("surface-waivers.json"); + + internal static IReadOnlyList Seeds { get; } = + [.. new DirectoryInfo(Path.Combine(Directory, "seeds")).EnumerateFiles("*.patch").OrderBy(file => file.Name, StringComparer.Ordinal).Select(Seed.Read)]; + + /// The documents that make promises to consumers; every one must carry at least one claim. + internal static readonly string[] PromiseDocuments = + [ + "README.md", + "docs/json.md", + "docs/text.md", + "docs/merge-patches.md", + "docs/ef-core.md", + "docs/type-constraints.md", + "src/CodoMetis.TypeKit.AspNetCore/README.md", + "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md", + "src/CodoMetis.TypeKit.Generators/README.md", + "src/CodoMetis.TypeKit.Analyzers/README.md", + "src/CodoMetis.TypeKit.Testing/README.md", + ]; + + /// Every test class under test/, a class whose file holds a [Fact] or a [Theory], with its project. + internal static IReadOnlyDictionary TestClasses { get; } = DiscoverTestClasses(); + + /// GitHub's heading slug: lower case, punctuation dropped, spaces to hyphens. + internal static string Slug(string heading) => + Regex.Replace(Regex.Replace(heading.Trim().ToLowerInvariant(), @"[^\p{L}\p{N}\s-]", ""), @"\s", "-"); + + /// Headings of a Markdown file, as slugs, in order. + internal static IReadOnlyList HeadingSlugs(string relativePath) + { + var inCode = false; + var slugs = new List(); + foreach (var line in File.ReadLines(Path.Combine(Root, relativePath))) + { + if (line.StartsWith("```", StringComparison.Ordinal)) inCode = !inCode; + if (inCode) continue; + var match = Regex.Match(line, @"^#{1,6}\s+(.*?)\s*#*\s*$"); + if (match.Success) slugs.Add(Slug(match.Groups[1].Value)); + } + + return slugs; + } + + /// A file's text with every run of whitespace collapsed to one space, for quote matching across line wraps. + internal static string Flattened(string relativePath) => Regex.Replace(File.ReadAllText(Path.Combine(Root, relativePath)), @"\s+", " "); + + private static T Load(string file) + { + var path = Path.Combine(Directory, file); + using var stream = File.OpenRead(path); + return JsonSerializer.Deserialize(stream, Json) ?? throw new InvalidOperationException($"'{path}' is empty."); + } + + private static Dictionary DiscoverTestClasses() + { + var classes = new Dictionary(StringComparer.Ordinal); + var testRoot = Path.Combine(Root, "test"); + var separator = Path.DirectorySeparatorChar; + + foreach (var file in System.IO.Directory.EnumerateFiles(testRoot, "*.cs", SearchOption.AllDirectories)) + { + if (file.Contains($"{separator}obj{separator}", StringComparison.Ordinal) || file.Contains($"{separator}bin{separator}", StringComparison.Ordinal)) continue; + + var text = File.ReadAllText(file); + if (!TestAttribute().IsMatch(text)) continue; + + var project = Path.GetRelativePath(testRoot, file).Split(separator)[0]; + foreach (Match match in ClassDeclaration().Matches(text)) + classes.TryAdd(match.Groups["name"].Value, project); + } + + return classes; + } + + private static string FindRoot() + { + const string marker = "CodoMetis.TypeKit.slnx"; + for (var directory = new DirectoryInfo(AppContext.BaseDirectory); directory is not null; directory = directory.Parent) + { + if (File.Exists(Path.Combine(directory.FullName, marker))) return directory.FullName; + } + + throw new InvalidOperationException($"Could not find '{marker}' above '{AppContext.BaseDirectory}'."); + } + + [GeneratedRegex(@"\[(Fact|Theory)\b")] + private static partial Regex TestAttribute(); + + [GeneratedRegex(@"(?m)^(?:public|internal)\s+(?:sealed\s+|static\s+|partial\s+|abstract\s+)*class\s+(?\w+)")] + private static partial Regex ClassDeclaration(); + + /// A sentence a document states about the library's behaviour, and what holds it. + internal sealed class Claim + { + public string Id { get; init; } = ""; + + /// file#heading-slug: where the sentence is. + public string Source { get; init; } = ""; + + /// The sentence, verbatim, so the catalogue test can find it in the file. + public string Quote { get; init; } = ""; + + /// The restatement as "under conditions, observable result". + [JsonPropertyName("claim")] + public string Statement { get; init; } = ""; + + /// claim, differential, metamorphic, exception or silent-default. + public string Oracle { get; init; } = ""; + + /// The public members a test of the claim calls, as patterns. + public IReadOnlyList Surfaces { get; init; } = []; + + /// The test classes that assert the claim; empty is the worklist. + public IReadOnlyList HeldBy { get; init; } = []; + + /// The source file, before the #. + internal string File => Source.Split('#')[0]; + + /// The heading slug after the #, or null for a claim about the whole file. + internal string? Heading => Source.Contains('#') ? Source[(Source.IndexOf('#') + 1)..] : null; + } + + /// A test class that checks the library against an independent answer over many cases. + internal sealed record Oracle(string Class, string Project, string Kind, string Against); + + /// A patch under seeds/: its header lines, the oracles it names and the files it changes. + internal sealed record Seed(FileInfo File, string Defect, IReadOnlyList Oracles, string Body) + { + internal static Seed Read(FileInfo file) + { + var text = System.IO.File.ReadAllText(file.FullName); + var diffAt = text.IndexOf("diff --git", StringComparison.Ordinal); + var header = diffAt < 0 ? text : text[..diffAt]; + return new Seed( + file, + HeaderValue(header, "Seed"), + HeaderValue(header, "Oracles").Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries), + diffAt < 0 ? "" : text[diffAt..]); + } + + /// The a/ paths the diff changes. + internal IReadOnlyList ChangedFiles => + [.. Regex.Matches(Body, @"^diff --git a/(?\S+) b/", RegexOptions.Multiline).Select(match => match.Groups["path"].Value)]; + + private static string HeaderValue(string header, string key) + { + var match = Regex.Match(header, $@"^{key}:\s*(?.+?)\s*$", RegexOptions.Multiline); + return match.Success ? match.Groups["value"].Value : ""; + } + } +} diff --git a/test/CodoMetis.TypeKit.Oracles.Tests/OracleCatalogueTests.cs b/test/CodoMetis.TypeKit.Oracles.Tests/OracleCatalogueTests.cs new file mode 100644 index 00000000..3fe3a0b8 --- /dev/null +++ b/test/CodoMetis.TypeKit.Oracles.Tests/OracleCatalogueTests.cs @@ -0,0 +1,118 @@ +using System.Text.RegularExpressions; + +namespace CodoMetis.TypeKit.Oracles.Tests; + +/// +/// The claim catalogue (test/oracles/claims.json) stays true to the documents it quotes and to the tests it +/// names (design/adr/0112). +/// +/// +/// A claim is a sentence a consumer-facing document states about the library, in a form a test can decide, with the +/// oracle kind, the public members a test of it calls and the test classes that hold it. The catalogue is only worth +/// keeping if it cannot drift: a reworded sentence stales its claim, a renamed test class is found, a surface that no +/// longer exists is noticed. A claim with an empty heldBy is allowed: that is the worklist. +/// +public sealed class OracleCatalogueTests +{ + /// 150 at the first catalogue (2026-10-28). A floor, not a target: discovery would otherwise pass on an empty array. + private const int KnownClaims = 150; + + private static readonly string[] Kinds = ["claim", "differential", "metamorphic", "exception", "silent-default"]; + + [Fact] + public void The_catalogue_is_not_empty_and_its_ids_are_unique_and_sorted() + { + var ids = OracleCatalogue.Claims.Select(claim => claim.Id).ToList(); + + ids.Count.ShouldBeGreaterThanOrEqualTo(KnownClaims); + ids.Distinct(StringComparer.Ordinal).Count().ShouldBe(ids.Count, "Duplicate claim ids."); + ids.ShouldBe(ids.Order(StringComparer.Ordinal).ToList(), "Claims are sorted by id."); + ids.Where(id => !Regex.IsMatch(id, @"^[A-Z]\d{2}-[a-z0-9-]+$")) + .ShouldBeEmpty("Every id is a letter, two digits, a hyphen and a kebab-case slug."); + } + + [Fact] + public void Every_claim_names_an_oracle_kind() => + OracleCatalogue.Claims.Where(claim => !Kinds.Contains(claim.Oracle)).Select(claim => $"{claim.Id}: '{claim.Oracle}'") + .ShouldBeEmpty("The oracle kind is one of " + string.Join("|", Kinds) + "."); + + [Fact] + public void Every_claim_quotes_its_source_verbatim() + { + var problems = new List(); + var flattened = new Dictionary(StringComparer.Ordinal); + var headings = new Dictionary>(StringComparer.Ordinal); + + foreach (var claim in OracleCatalogue.Claims) + { + if (!File.Exists(Path.Combine(OracleCatalogue.Root, claim.File))) + { + problems.Add($"{claim.Id}: source file '{claim.File}' does not exist"); + continue; + } + + if (claim.Heading is { } heading) + { + if (!headings.TryGetValue(claim.File, out var slugs)) headings[claim.File] = slugs = OracleCatalogue.HeadingSlugs(claim.File); + if (!slugs.Contains(heading)) problems.Add($"{claim.Id}: '{claim.File}' has no heading '#{heading}'"); + } + + if (!flattened.TryGetValue(claim.File, out var text)) flattened[claim.File] = text = OracleCatalogue.Flattened(claim.File); + + var quote = Regex.Replace(claim.Quote, @"\s+", " ").Trim(); + if (quote.Length < 20) + problems.Add($"{claim.Id}: the quote is too short to pin a sentence: '{quote}'"); + else if (!text.Contains(quote, StringComparison.Ordinal)) + problems.Add($"{claim.Id}: '{claim.File}' no longer contains the quoted sentence; reword the claim or retire it: '{quote}'"); + } + + problems.ShouldBeEmpty("Claims out of step with their documents."); + } + + [Fact] + public void Every_claim_names_test_classes_that_exist() + { + OracleCatalogue.TestClasses.Count.ShouldBeGreaterThanOrEqualTo(200, "Too few test classes were discovered under test/."); + + OracleCatalogue.Claims.SelectMany(claim => claim.HeldBy.Select(held => (claim.Id, held))) + .Where(pair => !OracleCatalogue.TestClasses.ContainsKey(pair.held)) + .Select(pair => $"{pair.Id} -> {pair.held}") + .ShouldBeEmpty("heldBy names a test class that does not exist."); + } + + [Fact] + public void Every_claim_names_surfaces_that_exist() => + OracleCatalogue.Claims.SelectMany(claim => claim.Surfaces.Select(surface => (claim.Id, surface))) + .Where(pair => ApiSurface.Matching(pair.surface).Count == 0) + .Select(pair => $"{pair.Id} -> '{pair.surface}'") + .ShouldBeEmpty("A claim names a public member that does not exist (keys are TypeName.Member, nested types with '+', '*' is a wildcard)."); + + [Fact] + public void Every_claim_names_at_least_one_surface() => + OracleCatalogue.Claims.Where(claim => claim.Surfaces.Count == 0).Select(claim => claim.Id) + .ShouldBeEmpty("A claim with no surface cannot be tested."); + + [Fact] + public void Every_promise_document_carries_a_claim() + { + var claimed = OracleCatalogue.Claims.Select(claim => claim.File).ToHashSet(StringComparer.Ordinal); + + OracleCatalogue.PromiseDocuments.Where(document => !claimed.Contains(document)) + .ShouldBeEmpty("A consumer-facing document has no claim in the catalogue."); + } + + /// + /// heldBy may name any test class, but a class named like an oracle, a sweep over generated cases or a probe over + /// the product of consumer settings (test/oracles/axes.md), is registered, so that it has a seed. + /// + [Fact] + public void A_class_named_like_an_oracle_that_holds_a_claim_is_registered() + { + var oracles = OracleCatalogue.Oracles.Select(oracle => oracle.Class).ToHashSet(StringComparer.Ordinal); + + OracleCatalogue.Claims.SelectMany(claim => claim.HeldBy).Distinct() + .Where(held => held.EndsWith("OracleTests", StringComparison.Ordinal) || held.EndsWith("ParityTests", StringComparison.Ordinal) || held.EndsWith("ProbeTests", StringComparison.Ordinal)) + .Where(held => !oracles.Contains(held)) + .ShouldBeEmpty("A class named like an oracle holds a claim but is not in oracles.json, so no seed is required of it."); + } +} diff --git a/test/CodoMetis.TypeKit.Oracles.Tests/OracleSeedTests.cs b/test/CodoMetis.TypeKit.Oracles.Tests/OracleSeedTests.cs new file mode 100644 index 00000000..40070919 --- /dev/null +++ b/test/CodoMetis.TypeKit.Oracles.Tests/OracleSeedTests.cs @@ -0,0 +1,94 @@ +using System.Diagnostics; + +namespace CodoMetis.TypeKit.Oracles.Tests; + +/// +/// Every registered oracle ships a seed, and every seed still plants its defect (design/adr/0112). +/// +/// +/// +/// A test that passes with and without a defect is not a guard. The rule has always been to prove a guard by +/// reverting its fix (.claude/skills/verify-the-guard); a seed is that revert kept as a file. +/// test/oracles/seeds/<defect>.patch changes src/ only, names the oracle classes it fails in an +/// Oracles: header line, and was shown to fail them by oracles seeds. +/// +/// +/// These tests build nothing: an oracle without a seed, a seed that names no oracle, a seed that touches a test, and a +/// seed a refactor has stranded all fail here. Whether a seed is still caught is the local tool's job, a copy, a build +/// of one project and a run of one class per seed, before a release. +/// +/// +public sealed class OracleSeedTests +{ + private const int KnownOracles = 5; + + [Fact] + public void Every_oracle_is_a_test_class_in_its_project() + { + OracleCatalogue.Oracles.Count.ShouldBeGreaterThanOrEqualTo(KnownOracles); + + OracleCatalogue.Oracles + .Where(oracle => !OracleCatalogue.TestClasses.TryGetValue(oracle.Class, out var project) || project != oracle.Project) + .Select(oracle => $"{oracle.Class} (registered in {oracle.Project}, found in {(OracleCatalogue.TestClasses.TryGetValue(oracle.Class, out var found) ? found : "no project")})") + .ShouldBeEmpty("oracles.json names a class that is not a test class in that project."); + } + + [Fact] + public void Every_oracle_has_a_seed() + { + var seeded = OracleCatalogue.Seeds.SelectMany(seed => seed.Oracles).ToHashSet(StringComparer.Ordinal); + + OracleCatalogue.Oracles.Select(oracle => oracle.Class).Where(oracle => !seeded.Contains(oracle)) + .ShouldBeEmpty("An oracle has no seed: add test/oracles/seeds/.patch with an 'Oracles:' line naming it, and show it caught with `oracles seeds`."); + } + + [Fact] + public void Every_seed_names_a_defect_and_registered_oracles() + { + OracleCatalogue.Seeds.ShouldNotBeEmpty("No seeds under test/oracles/seeds/."); + + var oracles = OracleCatalogue.Oracles.Select(oracle => oracle.Class).ToHashSet(StringComparer.Ordinal); + var problems = new List(); + foreach (var seed in OracleCatalogue.Seeds) + { + if (seed.Defect.Length == 0) problems.Add($"{seed.File.Name}: no 'Seed:' header line describing the defect"); + if (seed.Oracles.Count == 0) problems.Add($"{seed.File.Name}: no 'Oracles:' header line naming the classes it fails"); + problems.AddRange(seed.Oracles.Where(oracle => !oracles.Contains(oracle)).Select(oracle => $"{seed.File.Name}: names '{oracle}', which oracles.json does not register")); + if (seed.Body.Length == 0) problems.Add($"{seed.File.Name}: holds no diff"); + } + + problems.ShouldBeEmpty(); + } + + [Fact] + public void Every_seed_touches_only_source() => + OracleCatalogue.Seeds.SelectMany(seed => seed.ChangedFiles.Select(file => (seed.File.Name, file))) + .Where(pair => !pair.file.StartsWith("src/", StringComparison.Ordinal)) + .Select(pair => $"{pair.Name} changes '{pair.file}'") + .ShouldBeEmpty("A seed plants a defect in the library, never in a test."); + + [Fact] + public void Every_seed_applies_to_the_current_tree() + { + var problems = new List(); + foreach (var seed in OracleCatalogue.Seeds) + { + var (exit, output) = Git("apply", "--check", seed.File.FullName); + if (exit != 0) problems.Add($"{seed.File.Name} no longer applies; refresh it against src/: {output.Trim()}"); + } + + problems.ShouldBeEmpty(); + } + + private static (int Exit, string Output) Git(params string[] arguments) + { + var info = new ProcessStartInfo("git") { WorkingDirectory = OracleCatalogue.Root, RedirectStandardOutput = true, RedirectStandardError = true }; + foreach (var argument in arguments) info.ArgumentList.Add(argument); + + using var git = Process.Start(info) ?? throw new InvalidOperationException("git could not be started; the seed checks need it on PATH."); + var error = git.StandardError.ReadToEndAsync(); + var output = git.StandardOutput.ReadToEnd(); + git.WaitForExit(); + return (git.ExitCode, output + error.Result); + } +} diff --git a/test/CodoMetis.TypeKit.Oracles.Tests/OracleSurfaceCoverageTests.cs b/test/CodoMetis.TypeKit.Oracles.Tests/OracleSurfaceCoverageTests.cs new file mode 100644 index 00000000..cc46ca96 --- /dev/null +++ b/test/CodoMetis.TypeKit.Oracles.Tests/OracleSurfaceCoverageTests.cs @@ -0,0 +1,59 @@ +namespace CodoMetis.TypeKit.Oracles.Tests; + +/// +/// Every public member of the shipping libraries is named by a claim's surfaces or waived with a reason, so the API +/// cannot grow without deciding which oracle holds it (design/adr/0112). +/// +/// +/// enumerates the members by reflection, test/oracles/claims.json says which a claim +/// covers, and test/oracles/surface-waivers.json says which need no oracle and why. A waiver that no longer +/// matches an unclaimed member is stale and fails too, so the list shrinks as the claims grow. +/// +public sealed class OracleSurfaceCoverageTests +{ + /// A floor against the enumeration going quiet. + private const int KnownMembers = 300; + + [Fact] + public void The_surface_is_enumerated() + { + ApiSurface.Members.Count.ShouldBeGreaterThanOrEqualTo(KnownMembers); + ApiSurface.Members.ShouldContain("Result.CatchAsync"); + ApiSurface.Members.ShouldContain("Option.Some"); + ApiSurface.Members.ShouldContain("FaultResponse.WithType"); + } + + [Fact] + public void Every_public_member_is_claimed_or_waived() + { + var claimed = Claimed(); + var waived = OracleCatalogue.SurfaceWaivers.Keys.SelectMany(ApiSurface.Matching).ToHashSet(StringComparer.Ordinal); + + ApiSurface.Members.Where(member => !claimed.Contains(member) && !waived.Contains(member)) + .ShouldBeEmpty("These public members are named by no claim and no waiver. Either a document promises something about " + + "them, and the claim goes into test/oracles/claims.json, or they need no oracle, and test/oracles/surface-waivers.json says why."); + } + + [Fact] + public void No_waiver_is_stale() + { + var claimed = Claimed(); + var stale = new List(); + + foreach (var (glob, reason) in OracleCatalogue.SurfaceWaivers) + { + var members = ApiSurface.Matching(glob); + if (members.Count == 0) + stale.Add($"'{glob}' matches no public member"); + else if (members.All(claimed.Contains)) + stale.Add($"'{glob}' matches only members a claim already covers ({members.Count}): remove the waiver"); + if (reason.Trim().Length < 10) + stale.Add($"'{glob}' needs a reason"); + } + + stale.ShouldBeEmpty("Waivers to clean up."); + } + + private static HashSet Claimed() => + OracleCatalogue.Claims.SelectMany(claim => claim.Surfaces).Distinct().SelectMany(ApiSurface.Matching).ToHashSet(StringComparer.Ordinal); +} diff --git a/test/CodoMetis.TypeKit.Oracles.Tests/SeedVerdictTests.cs b/test/CodoMetis.TypeKit.Oracles.Tests/SeedVerdictTests.cs new file mode 100644 index 00000000..70830918 --- /dev/null +++ b/test/CodoMetis.TypeKit.Oracles.Tests/SeedVerdictTests.cs @@ -0,0 +1,65 @@ +namespace CodoMetis.TypeKit.Oracles.Tests; + +/// +/// The rule oracles seeds judges a failed test by (), fed the messages +/// writes: a seed is caught when one row of a failed test is not a known candidate, +/// whatever else shares its message. +/// +public sealed class SeedVerdictTests +{ + private static readonly Candidates.Candidate Unfiled = new("AnyOracle", "row 1:", "a known disagreement", Issue: ""); + + [Fact] + public void A_message_with_a_known_row_and_another_row_catches() => + SeedVerdict.Catches(MessageOf([Unfiled], ["row 1: expected 1, got 2", "row 2: expected 1, got 3"])).ShouldBeTrue(); + + [Fact] + public void A_message_whose_every_row_is_known_does_not_catch() => + SeedVerdict.Catches(MessageOf([Unfiled], ["row 1: expected 1, got 2"])).ShouldBeFalse(); + + /// The other rows come first, so a message cut short still shows one; known rows are what is cut. + [Fact] + public void A_message_cut_short_still_shows_the_row_that_catches() + { + var message = MessageOf([Unfiled], [.. Enumerable.Range(0, 30).Select(i => $"row 1: known variant {i}"), "row 2: expected 1, got 3"], shown: 5); + + message.ShouldContain("… and 26 more"); + SeedVerdict.Catches(message).ShouldBeTrue(); + } + + [Fact] + public void A_message_cut_short_whose_every_row_is_known_does_not_catch() + { + var message = MessageOf([Unfiled], [.. Enumerable.Range(0, 30).Select(i => $"row 1: known variant {i}")], shown: 5); + + message.ShouldContain("… and 25 more"); + SeedVerdict.Catches(message).ShouldBeFalse(); + } + + /// A known row whose text spans lines is still one known row: its continuation has no marker and read as a caught row. + [Fact] + public void A_known_row_spanning_lines_does_not_catch() + { + var unfiled = new Candidates.Candidate("AnyOracle", "text {1,", "a known disagreement", Issue: ""); + var message = MessageOf([unfiled], ["text {1,\n2}: expected {1,2}, refused"]); + + SeedVerdict.Catches(message).ShouldBeFalse(message); + message.ShouldContain("{1,⏎2}"); + } + + /// A seed that makes a known row agree changes what the sweep answers, which is a catch. + [Fact] + public void A_candidate_fixed_catches() => SeedVerdict.Catches(MessageOf([Unfiled], [])).ShouldBeTrue(); + + [Theory] + [InlineData("Shouldly.ShouldAssertException: value should be 1 but was 2")] + [InlineData("Assert.Fail: the text '[known candidate: x]' appears inside a line, not as a row")] + public void Any_other_assertion_catches(string message) => SeedVerdict.Catches(message).ShouldBeTrue(); + + [Fact] + public void A_sweep_with_no_failure_and_no_candidate_passes() => + Should.NotThrow(() => Candidates.Judge([], [], "a sweep")); + + private static string MessageOf(IReadOnlyList known, IReadOnlyList failures, int shown = 25) => + Should.Throw(() => Candidates.Judge(known, failures, "a sweep", shown)).Message; +} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/ClaimsFileTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/ClaimsFileTests.cs deleted file mode 100644 index c7fa558b..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/ClaimsFileTests.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// claims.json is read against its schema, and each exclusion carries the reason a reviewer reads (decision 102): -/// a field nobody reads is refused, not kept, and a publish rewrites the file only where it changed. -/// -public sealed class ClaimsFileTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private void Claims(JsonObject claim) - { - var c = new JsonObject { ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s") }; - foreach (var (key, value) in claim) c[key] = value?.DeepClone(); - fx.Write("tools/probe/corpus/claims.json", new JsonArray(c).ToJsonString()); - } - - private static JsonArray Pairs(params (string A, string B)[] pairs) => new([.. pairs.Select(p => (JsonNode)new JsonArray(p.A, p.B))]); - - [Theory] - [InlineData(null, "claim C1: exclude[0].reason is required")] - [InlineData("", "claim C1: exclude[0].reason does not match")] - [InlineData(" ", "claim C1: exclude[0].reason does not match")] - public void An_exclusion_without_a_reason_is_refused_naming_the_claim(string? reason, string expected) - { - var exclusion = new JsonObject { ["pairs"] = Pairs(("x=1", "y=2")) }; - if (reason is not null) exclusion["reason"] = reason; - Claims(new JsonObject { ["exclude"] = new JsonArray(exclusion) }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain(expected); - } - - [Fact] - public void A_bare_pair_is_refused_as_an_exclusion_without_its_reason() - { - Claims(new JsonObject { ["exclude"] = Pairs(("x=1", "y=2")) }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain("claim C1: exclude[0] is not an object"); - } - - [Theory] - [InlineData("excludeReasons")] - [InlineData("excludeWhy")] - public void A_reason_field_of_its_own_is_refused(string field) - { - Claims(new JsonObject - { - ["exclude"] = new JsonArray(new JsonObject { ["reason"] = "No row holds both.", ["pairs"] = Pairs(("x=1", "y=2")) }), - [field] = new JsonArray(new JsonObject { ["match"] = "x=1 x y=2", ["reason"] = "No row holds both." }), - }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain($"claim C1: {field} is not a field the schema has"); - } - - [Fact] - public void A_field_of_its_own_in_an_exclusion_is_refused() - { - Claims(new JsonObject - { - ["exclude"] = new JsonArray(new JsonObject { ["reason"] = "No row holds both.", ["why"] = "twice", ["pairs"] = Pairs(("x=1", "y=2")) }), - }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain("claim C1: exclude[0].why is not a field the schema has"); - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void The_universe_shows_each_exclusion_with_its_reason(string newLine) - { - Claims(new JsonObject - { - ["exclude"] = new JsonArray(new JsonObject { ["reason"] = "No row holds x=1 with y=2.", ["pairs"] = Pairs(("y=2", "x=1")) }), - }); - var (exit, output, error) = fx.LedgerEnding([], newLine, "universe", "--base", "HEAD"); - exit.ShouldBe(0, error); - output.ReplaceLineEndings("\n").ShouldContain("C1: 2 axes, 3 pairs\n exclude 1 pair(s), first x=1 y=2: No row holds x=1 with y=2.\n"); - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void The_universe_shows_each_narrowing_with_its_quote(string newLine) - { - Claims(new JsonObject { ["narrow"] = new JsonObject { ["y"] = "The claim." } }); - var (exit, output, error) = fx.LedgerEnding([], newLine, "universe", "--base", "HEAD"); - exit.ShouldBe(0, error); - output.ReplaceLineEndings("\n").ShouldContain("C1: 1 axes, 0 pairs\n narrow y: \"The claim.\"\n"); - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void A_publish_that_changes_nothing_keeps_the_file_as_it_is(string staged) - { - // The form publish writes, by hand: a reason with a backtick, a plus and angle brackets, all literal, and \n line - // ends, whatever this source file was checked out with. The staged copy may come with either line end. - var tracked = """ - [ - { - "id": "C1", - "source": "README.md#a", - "surfaces": [ - "s" - ], - "exclude": [ - { - "reason": "A `+` row and an Option row cannot meet.", - "pairs": [ - [ - "x=1", - "y=2" - ] - ] - } - ] - } - ] - - """.ReplaceLineEndings("\n"); - fx.Write("tools/probe/corpus/claims.json", tracked); - fx.Commit("claims"); - fx.Write(".claude/agent-memory-local/prober/branches/main/staging/claims.json", tracked.ReplaceLineEndings(staged)); - var (exit, _, error) = fx.Ledger("publish"); - exit.ShouldBe(0, error); - fx.Sh("git", "diff", "--exit-code", "--", "tools/probe/corpus/claims.json"); - File.ReadAllText(Path.Combine(fx.Root, "tools/probe/corpus/claims.json")).ShouldBe(tracked, "byte for byte: the escapes and the line ends are the ones publish writes"); - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void The_corpus_claims_match_their_schema_in_the_form_publish_writes(string checkedOut) - { - var root = AppContext.BaseDirectory; - while (!File.Exists(Path.Combine(root, "CodoMetis.TypeKit.slnx"))) root = Path.GetDirectoryName(root) ?? throw new InvalidOperationException("no CodoMetis.TypeKit.slnx above the test output"); - var path = Path.Combine(root, "tools/probe/corpus/claims.json"); - var claims = Ledger.ReadClaims(path, "tools/probe/corpus/claims.json"); - claims.ShouldNotBeEmpty(); - // Git may check the file out with either line end (core.autocrlf on Windows); what it stores, and diffs, has \n. - var text = File.ReadAllText(path).ReplaceLineEndings(checkedOut); - Files.Format(JsonNode.Parse(text)!).ShouldBe(text.ReplaceLineEndings("\n"), "claims.json is in the form `prober publish` writes, so a publish diffs only what it changes"); - } - - [Fact] - public void A_schema_keyword_the_check_does_not_read_is_an_error_not_a_pass() - { - var schema = new JsonObject { ["type"] = "string", ["maxLength"] = 3 }; - Should.Throw(() => SchemaCheck.Problems("abcd", schema)).Message.ShouldContain("maxLength"); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/CodoMetis.TypeKit.Prober.Tests.csproj b/test/CodoMetis.TypeKit.Prober.Tests/CodoMetis.TypeKit.Prober.Tests.csproj deleted file mode 100644 index 2126c5f2..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/CodoMetis.TypeKit.Prober.Tests.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - <_Parameter1>ToolOutput - <_Parameter2>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)../../tools/Prober/bin/$(Configuration)/$(TargetFramework)/')) - - - - diff --git a/test/CodoMetis.TypeKit.Prober.Tests/CoveringTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/CoveringTests.cs deleted file mode 100644 index 0a824ae1..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/CoveringTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// The covering array never puts an excluded pair or one no obligation wants in a row, not even to fill an axis whose every -/// value would bring one (#54 and #59 saw `rows` place them): such an axis is left out of that row, and an axis with no wanted -/// pair at all is left out of every row. -/// -public sealed class CoveringTests -{ - private static Inapplicability Declared(string cite, params (string Axis, string[] Values)[] axes) => - new(axes.ToDictionary(a => a.Axis, a => a.Values.ToList(), StringComparer.Ordinal), cite); - - private static Claim Over(string[] axes, IEnumerable? excluded = null, params Inapplicability[] declared) => new() - { - Id = "C1", Source = "README.md#a", Surfaces = ["s"], Watched = [], Excluded = [.. excluded ?? []], - Obligations = declared.Length == 0 ? [] : [new("keys", "The claim.", new SortedDictionary>(StringComparer.Ordinal)) { Inapplicable = declared }], - Axes = new(axes.ToDictionary(a => a, _ => new List { "1", "2" }), StringComparer.Ordinal), - }; - - private static bool Holds(IReadOnlyDictionary row, Pair pair) => - new[] { pair.A, pair.B }.All(item => row.TryGetValue(item[..item.IndexOf('=', StringComparison.Ordinal)], out var v) && v == item[(item.IndexOf('=', StringComparison.Ordinal) + 1)..]); - - private static IEnumerable Shown(IEnumerable pairs) => pairs.Select(p => p.ToString()).Order(StringComparer.Ordinal); - - [Fact] - public void An_axis_whose_every_value_brings_an_excluded_pair_is_left_out_of_the_row() - { - // x=1 goes with no y (as shape.containing goes with no shape.position=root): a row holding x=1 holds no y. - Pair[] excluded = [new("x=1", "y=1"), new("x=1", "y=2")]; - var claim = Over(["x", "y", "z"], excluded); - for (var seed = 1; seed <= 20; seed++) - { - var rows = Covering.Rows(claim, claim.Pairs(), 2000, seed); - rows.ShouldNotContain(r => excluded.Any(p => Holds(r.Row, p)), $"seed {seed}"); - rows.Where(r => r.Row["x"] == "1").ShouldAllBe(r => !r.Row.ContainsKey("y"), $"seed {seed}"); - Shown(rows.SelectMany(r => r.Pairs)).ShouldBe(Shown(claim.Pairs()), $"seed {seed}: every pair once, x=1 with z among them"); - } - } - - [Fact] - public void An_axis_whose_every_value_brings_a_pair_no_obligation_wants_is_left_out_of_the_row() - { - var claim = Over(["x", "y", "z"], null, Declared("record:0001", ("x", ["1"]), ("y", ["1", "2"]))); - var dead = claim.DeclaredInapplicable().Keys.ToList(); - dead.Count.ShouldBe(2); - for (var seed = 1; seed <= 20; seed++) - { - var rows = Covering.Rows(claim, claim.PairsWanted(), 2000, seed); - rows.ShouldNotContain(r => dead.Any(p => Holds(r.Row, p)), $"seed {seed}"); - Shown(rows.SelectMany(r => r.Pairs)).ShouldBe(Shown(claim.PairsWanted()), $"seed {seed}"); - } - } - - [Fact] - public void An_axis_with_no_wanted_pair_is_in_no_row() - { - // every pair of z is excluded (as shape.refused-kind is where the refusal is not the claim): rows over x and y alone. - var claim = Over(["x", "y", "z"], [.. from x in new[] { "x=1", "x=2", "y=1", "y=2" } from z in new[] { "z=1", "z=2" } select new Pair(x, z)]); - for (var seed = 1; seed <= 5; seed++) - { - var rows = Covering.Rows(claim, claim.Pairs(), 2000, seed); - rows.ShouldAllBe(r => !r.Row.ContainsKey("z"), $"seed {seed}"); - Shown(rows.SelectMany(r => r.Pairs)).ShouldBe(["x=1 y=1", "x=1 y=2", "x=2 y=1", "x=2 y=2"], $"seed {seed}"); - } - } - - [Fact] - public void A_seeded_row_leaves_out_an_axis_no_value_of_which_can_join_it() - { - // c=1 goes with no d: the row seeded from a=1 c=1 is a, b and c. - var claim = Over(["a", "b", "c", "d"], [new("c=1", "d=1"), new("c=1", "d=2")]); - Covering.Seeded(claim, new Pair("a=1", "c=1"), claim.DeclaredInapplicable()) - .ShouldBe(new SortedDictionary(StringComparer.Ordinal) { ["a"] = "1", ["b"] = "1", ["c"] = "1" }); - Covering.Seeded(claim, new Pair("a=1", "b=2"), claim.DeclaredInapplicable()) - .ShouldBe(new SortedDictionary(StringComparer.Ordinal) { ["a"] = "1", ["b"] = "2", ["c"] = "1" }, - "c=1 is c's first value, and d then has none"); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/DeclaredApplicabilityTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/DeclaredApplicabilityTests.cs deleted file mode 100644 index aae5e585..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/DeclaredApplicabilityTests.cs +++ /dev/null @@ -1,439 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; -using Probes.Shapes; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// An obligation declares where it does not apply, as axis values with a citation: Axes.Build holds the -/// declaration to the claim's axes, values and not-promised list; a pair is wanted by an obligation unless one of -/// its declarations matches it, and a pair no obligation wants is declared inapplicable, which `universe`, `gaps` -/// and `status` show with its citations, the gate leaves out as it leaves out an exclusion, and the covering -/// generator never puts in a row. Fixture: C1 over x and y, each 1 and 2, so four pairs. -/// -public sealed class DeclaredApplicabilityTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private static JsonObject Declared(string cite, params (string Axis, string[] Values)[] axes) => new() - { - ["axes"] = new JsonObject(axes.Select(a => KeyValuePair.Create(a.Axis, (JsonNode?)new JsonArray([.. a.Values.Select(v => (JsonNode)v)])))), - ["cite"] = cite, - }; - - private static JsonObject Obligation(string id, params JsonObject[] inapplicable) - { - var o = new JsonObject { ["id"] = id, ["sentence"] = "The claim." }; - if (inapplicable.Length > 0) o["inapplicable"] = new JsonArray([.. inapplicable]); - return o; - } - - /// C1 with the obligations given and one not-promised entry, no-one. - private void Claim(params JsonObject[] obligations) => - fx.Write("tools/probe/corpus/claims.json", new JsonArray(new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["obligations"] = new JsonArray([.. obligations]), - ["not-promised"] = new JsonArray(new JsonObject { ["id"] = "no-one", ["source"] = "README.md#a", ["sentence"] = "The claim." }), - }).ToJsonString()); - - /// - /// keys does not apply where x=1 and y=1 (one declaration over both axes), nulls nowhere x=1: the pair x=1 y=1 is - /// wanted by neither, x=1 y=2 by keys alone. - /// - private void OnePairWantedByNone() => Claim( - Obligation("keys", Declared("docs:README.md#a", ("x", ["1"]), ("y", ["1"]))), - Obligation("nulls", Declared("not-promised:no-one", ("x", ["1"])))); - - private string Refused() - { - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - return error; - } - - [Fact] - public void A_declaration_naming_an_axis_the_claim_does_not_have_is_refused() - { - Claim(Obligation("keys", Declared("not-promised:no-one", ("z", ["1"])))); - Refused().ShouldContain("claim C1: obligation keys: inapplicable[0] names axis z, which the claim does not have"); - } - - [Fact] - public void A_declaration_naming_a_value_the_claim_does_not_list_is_refused() - { - Claim(Obligation("keys", Declared("not-promised:no-one", ("x", ["1"]))), Obligation("nulls", Declared("not-promised:no-one", ("x", ["3"])))); - Refused().ShouldContain("claim C1: obligation nulls: inapplicable[0] names x=3, a value the claim does not list for x"); - } - - [Theory] - [InlineData("fact:KB-31", "is not a knowledge entry's id (fact:KB-031)")] - [InlineData("record:94", "is not a decision record's number (record:0094)")] - [InlineData("docs:../README.md#a", "is not a docs source (docs:docs/json.md#decimals-in-one-spelling)")] - [InlineData("not-promised:No-one", "is not a not-promised id (not-promised:closed-set-has-no-text)")] - public void A_malformed_cite_is_refused(string cite, string why) - { - Claim(Obligation("keys", Declared(cite, ("x", ["1"])))); - Refused().ShouldContain($"claim C1: obligation keys: inapplicable[0]: cite {cite} {why}"); - } - - [Fact] - public void A_cite_of_a_not_promised_id_the_claim_lacks_is_refused() - { - Claim(Obligation("keys", Declared("not-promised:no-such-entry", ("x", ["1"])))); - Refused().ShouldContain("claim C1: obligation keys: inapplicable[0] cites not-promised:no-such-entry, which the claim's not-promised list does not hold"); - } - - [Fact] - public void A_field_a_declaration_does_not_have_is_refused_by_the_schema() - { - var declaration = Declared("not-promised:no-one", ("x", ["1"])); - declaration["reason"] = "x=1 has no key"; - Claim(Obligation("keys", declaration)); - Refused().ShouldContain("claim C1: obligations[0].inapplicable[0].reason is not a field the schema has"); - } - - [Fact] - public void A_pair_wanted_by_no_obligation_is_listed_by_universe_with_its_citations_and_the_claim_keeps_its_pairs() - { - OnePairWantedByNone(); - var (exit, output, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(0, error); - output.ReplaceLineEndings("\n").ShouldContain( - "C1: 2 axes, 4 pairs\n inapplicable 1 pair(s), wanted by no obligation, first x=1 y=1: docs:README.md#a, not-promised:no-one\n"); - } - - [Fact] - public void Gaps_lists_the_pairs_no_obligation_wants_under_their_own_heading() - { - OnePairWantedByNone(); - var (exit, output, error) = fx.Ledger("gaps", "--base", "HEAD"); - exit.ShouldBe(0, error); - output.ReplaceLineEndings("\n").ShouldContain( - "pairs no obligation wants (declared inapplicable): 1\n C1: inapplicable 1 pair(s), wanted by no obligation, first x=1 y=1: docs:README.md#a, not-promised:no-one\n"); - } - - private static Dictionary R(string x, string y) => new(StringComparer.Ordinal) { ["x"] = x, ["y"] = y }; - - /// P passes rows over the three pairs some obligation wants, never x=1 y=1. - private void RecordTheWantedPairs() - { - fx.Rows([("1", "2"), ("2", "1"), ("2", "2")]); - fx.Commit("claims and rows"); - fx.Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - fx.Footprint(); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", fx.Evidence([R("1", "2"), R("2", "1"), R("2", "2")])).Exit.ShouldBe(0); - } - - [Fact] - public void Status_reports_the_inapplicable_pairs_and_is_done_once_every_wanted_pair_is_current() - { - OnePairWantedByNone(); - RecordTheWantedPairs(); - var (exit, output, error) = fx.Ledger("status", "--json"); - exit.ShouldBe(0, error); - var status = JsonNode.Parse(output)!; - var c1 = status["claims"]!["C1"]!; - c1["pairs"]!.GetValue().ShouldBe(4, "the claim's pairs stay its pairs"); - c1["current"]!.GetValue().ShouldBe(3); - c1["inapplicable_pairs"]!.GetValue().ShouldBe(1); - status["inapplicable_pairs"]!.GetValue().ShouldBe(1); - status["done"]!.GetValue().ShouldBeTrue("the one pair not current is wanted by no obligation"); - fx.Ledger("status").Out.ShouldContain(" C1: 3/4, 1 inapplicable"); - } - - [Fact] - public void Status_is_not_done_while_a_wanted_pair_is_not_current() - { - Claim(Obligation("keys"), Obligation("nulls")); - RecordTheWantedPairs(); - var status = JsonNode.Parse(fx.Ledger("status", "--json").Out)!; - status["claims"]!["C1"]!["inapplicable_pairs"]!.GetValue().ShouldBe(0); - status["done"]!.GetValue().ShouldBeFalse("x=1 y=1 is wanted and not current"); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void The_gate_leaves_out_a_pair_wanted_by_no_obligation_as_it_leaves_out_an_exclusion(bool declared) - { - fx.Sh("git", "tag", "v1"); - if (declared) OnePairWantedByNone(); else Claim(Obligation("keys"), Obligation("nulls")); - RecordTheWantedPairs(); - fx.Write("README.md", "# a\n\nThe claim.\n\nMore words.\n"); - fx.Commit("touch the claim"); - - var (exit, output, _) = fx.Ledger("gate", "--since", "v1", "--json"); - var gate = JsonNode.Parse(output)!; - gate["touched"]!.AsArray().Select(c => c!.GetValue()).ShouldBe(["C1"]); - if (declared) - { - exit.ShouldBe(0, output); - gate["uncovered_pairs"]!.GetValue().ShouldBe(0); - gate["inapplicable_pairs"]!.GetValue().ShouldBe(1); - } - else - { - exit.ShouldBe(1); - gate["reasons"]!.AsArray().Select(r => r!.GetValue()).ShouldContain("C1: 1 of 4 pairs uncovered (touched since v1)"); - } - } - - [Fact] - public void Rows_for_a_claim_ask_for_no_pair_no_obligation_wants() - { - OnePairWantedByNone(); - fx.Commit("claims"); - fx.Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - var rows = JsonNode.Parse(fx.Ledger("rows", "--claim", "C1", "--full").Out)!; - rows["rows"]!.AsArray().Select(r => $"{r!["row"]!["x"]} {r["row"]!["y"]}").ShouldNotContain("1 1"); - rows["uncovered_after"]!.GetValue().ShouldBe(0, "a pair wanted by no obligation is not left uncovered"); - } - - [Fact] - public void A_declaration_changes_the_identity_of_its_claim_s_probes() - { - Claim(Obligation("keys"), Obligation("nulls")); - fx.Commit("claims"); - var before = fx.Ledger("identity", "--probe", "P").Out; - OnePairWantedByNone(); - fx.Commit("declared"); - fx.Ledger("identity", "--probe", "P").Out.ShouldNotBe(before, "Row.Check applies the declarations, so a result under others is not this one"); - } - - [Fact] - public void The_overlay_stages_the_claims_beside_the_rows_with_the_staging_s_over_the_corpus_s() - { - Claim(Obligation("keys"), Obligation("nulls")); - fx.Commit("claims"); - var ledger = new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), "main"); - var staged = new JsonArray(new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["obligations"] = new JsonArray(Obligation("keys", Declared("docs:README.md#a", ("x", ["1"])))), - }); - fx.Write(Path.GetRelativePath(fx.Root, Path.Combine(ledger.StagingDir, "claims.json")), staged.ToJsonString()); - var worktree = fx.Root + "-overlay"; - try - { - var probeDir = global::Prober.Replay.Overlay(ledger, new JsonObject { ["probeDir"] = "probes" }, worktree); - var claims = JsonNode.Parse(File.ReadAllText(Path.Combine(probeDir, "claims.json")))!.AsArray(); - JsonNode.DeepEquals(claims, staged).ShouldBeTrue(claims.ToJsonString()); - global::Prober.Replay.Overlay(ledger, new JsonObject { ["probeDir"] = "probes" }, worktree); - File.Exists(Path.Combine(probeDir, "claims.json")).ShouldBeTrue("a second overlay keeps it"); - } - finally - { - try { Directory.Delete(worktree, recursive: true); } catch (IOException) { } - } - } -} - -/// The wanted pairs of a claim, computed on the claim itself, and the covering generator over them. -public sealed class WantedPairsTests -{ - private static Inapplicability Declared(string cite, params (string Axis, string[] Values)[] axes) => - new(axes.ToDictionary(a => a.Axis, a => a.Values.ToList(), StringComparer.Ordinal), cite); - - private static global::Prober.Obligation Obligation(string id, params Inapplicability[] inapplicable) => - new(id, "The claim.", new SortedDictionary>(StringComparer.Ordinal)) { Inapplicable = inapplicable }; - - private static Claim Over(int axes, params global::Prober.Obligation[] obligations) => new() - { - Id = "C1", Source = "README.md#a", Surfaces = ["s"], Watched = [], Excluded = [], Obligations = obligations, - Axes = new(new[] { "x", "y", "z" }.Take(axes).ToDictionary(a => a, _ => new List { "1", "2" }), StringComparer.Ordinal), - }; - - private static IEnumerable Shown(IEnumerable pairs) => pairs.Select(p => p.ToString()).Order(StringComparer.Ordinal); - - [Fact] - public void An_obligation_wants_the_pairs_none_of_its_declarations_matches_on_either_side() - { - // keys: not where x=1 (the first of a pair, ordinally); nulls: not where y=1 (the second); counts: nowhere declared. - var claim = Over(2, Obligation("keys", Declared("record:0001", ("x", ["1"]))), Obligation("nulls", Declared("record:0002", ("y", ["1"]))), Obligation("counts")); - Shown(claim.PairsWantedBy("keys")).ShouldBe(["x=2 y=1", "x=2 y=2"]); - Shown(claim.PairsWantedBy("nulls")).ShouldBe(["x=1 y=2", "x=2 y=2"]); - Shown(claim.PairsWantedBy("counts")).ShouldBe(["x=1 y=1", "x=1 y=2", "x=2 y=1", "x=2 y=2"]); - claim.Pairs().Count.ShouldBe(4, "the claim's pairs stay its pairs"); - claim.DeclaredInapplicable().ShouldBeEmpty("counts wants every pair"); - } - - [Fact] - public void A_pair_no_obligation_wants_is_declared_inapplicable_with_the_citations_that_match_it() - { - // keys wants x=2 y=1 alone, nulls x=1 y=2 alone. - var claim = Over(2, - Obligation("keys", Declared("record:0001", ("x", ["1"])), Declared("record:0003", ("y", ["2"]))), - Obligation("nulls", Declared("record:0002", ("y", ["1"])), Declared("record:0004", ("x", ["2"])))); - Shown(claim.PairsWanted()).ShouldBe(["x=1 y=2", "x=2 y=1"]); - var dead = claim.DeclaredInapplicable(); - Shown(dead.Keys).ShouldBe(["x=1 y=1", "x=2 y=2"]); - dead[new Pair("x=1", "y=1")].ShouldBe(["record:0001", "record:0002"]); - dead[new Pair("x=2", "y=2")].ShouldBe(["record:0003", "record:0004"]); - } - - [Fact] - public void A_declaration_over_two_axes_matches_only_the_pair_holding_both() - { - var claim = Over(3, Obligation("keys", Declared("record:0001", ("x", ["1"]), ("y", ["1"])))); - Shown(claim.DeclaredInapplicable().Keys).ShouldBe(["x=1 y=1"], "x=1 with z, or y=1 with z, is in rows where the other axis is 2"); - } - - [Fact] - public void The_covering_rows_never_hold_a_pair_no_obligation_wants_and_count_each_wanted_pair_once() - { - // Both obligations want the same eleven pairs: none of x=1 with y=1. - var claim = Over(3, Obligation("keys", Declared("record:0001", ("x", ["1"]), ("y", ["1"]))), Obligation("nulls", Declared("record:0002", ("x", ["1"]), ("y", ["1"])))); - for (var seed = 1; seed <= 20; seed++) - { - var rows = Covering.Rows(claim, claim.Pairs(), 2000, seed); - rows.ShouldNotContain(r => r.Row["x"] == "1" && r.Row["y"] == "1", $"seed {seed}"); - var gained = rows.SelectMany(r => r.Pairs).ToList(); - gained.Count.ShouldBe(11, $"seed {seed}: each wanted pair once"); - Shown(gained).ShouldBe(Shown(claim.PairsWanted()), $"seed {seed}"); - } - } - - [Fact] - public void A_seeded_row_fills_each_other_axis_with_a_value_that_puts_no_unwanted_pair_in_it() - { - var claim = Over(3, Obligation("keys", Declared("record:0001", ("x", ["1"]), ("z", ["1"])))); - var row = Covering.Seeded(claim, new Pair("y=1", "z=1"), claim.DeclaredInapplicable()); - row.ShouldBe(new SortedDictionary(StringComparer.Ordinal) { ["x"] = "2", ["y"] = "1", ["z"] = "1" }); - } - - [Theory] - [InlineData("not-promised:closed-set-has-no-text")] - [InlineData("not-promised:Closed")] - [InlineData("docs:docs/json.md#decimals-in-one-spelling")] - [InlineData("docs:README.md")] - [InlineData("docs:README.md#What TypeKit guarantees")] - [InlineData("docs:/etc/passwd.md")] - [InlineData("docs:../README.md#a")] - [InlineData("fact:KB-031")] - [InlineData("fact:KB-31")] - [InlineData("record:0094")] - [InlineData("record:94")] - [InlineData("README.md#a")] - [InlineData("note:x")] - public void A_cite_the_universe_accepts_is_one_the_harness_can_cite(string cite) - { - var harness = Record.Exception(() => Cite.Parse(cite)) is null; - (Axes.CiteProblem(cite) is null).ShouldBe(harness, harness ? "the harness cites it" : "the harness refuses it"); - } -} - -/// -/// The harness applies the claim's declarations before a check's body runs: where one matches the row's values the -/// check is inapplicable with the declaration's citation, for that check only, and the body does not run. Without a -/// staged claims file, as for a probe these tests run in-process, no claim declares anything. -/// -[Collection(nameof(ProbeOut))] -public sealed class DeclaredCheckTests : IDisposable -{ - private readonly string dir = Path.Combine(Path.GetTempPath(), "prober-tests", Guid.NewGuid().ToString("N")); - private readonly string? before = Rows.ClaimsFile; - - public DeclaredCheckTests() - { - Directory.CreateDirectory(dir); - File.WriteAllText(Path.Combine(dir, "claims.json"), new JsonArray(new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["obligations"] = new JsonArray( - new JsonObject - { - ["id"] = "keys", ["sentence"] = "The claim.", - ["inapplicable"] = new JsonArray( - new JsonObject { ["axes"] = new JsonObject { ["x"] = new JsonArray("1"), ["y"] = new JsonArray("2") }, ["cite"] = "not-promised:no-key-here" }, - new JsonObject { ["axes"] = new JsonObject { ["y"] = new JsonArray("3") }, ["cite"] = "fact:KB-031" }), - }, - new JsonObject { ["id"] = "nulls", ["sentence"] = "The claim." }), - }).ToJsonString()); - Rows.ClaimsFile = Path.Combine(dir, "claims.json"); - } - - public void Dispose() - { - Rows.ClaimsFile = before; - try { Directory.Delete(dir, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - /// Runs one row of C1 through Rec.Run with a check of keys and one of nulls, synchronous or not; which bodies ran, and the line written. - private (List Ran, Exception? Ended, JsonObject Line) Run(string x, string y, bool async = false, string? claim = "C1") - { - var ran = new List(); - var outDir = Path.Combine(dir, "out"); - var previous = Environment.GetEnvironmentVariable("PROBE_OUT"); - Environment.SetEnvironmentVariable("PROBE_OUT", outDir); - Exception? ended = null; - try - { - Rec.Run("P", new Row(0, new Dictionary { ["x"] = x, ["y"] = y }, claim), async r => - { - foreach (var obligation in new[] { "keys", "nulls" }) - _ = async - ? await r.Check(obligation, Baseline.Twin, c => { ran.Add(obligation); return Task.FromResult(c["x"] == "0" ? "differs" : null); }) - : r.Check(obligation, Baseline.Twin, c => { ran.Add(obligation); return c["x"] == "0" ? "differs" : null; }); - return null; - }).GetAwaiter().GetResult(); - } - catch (Exception e) { ended = e; } - finally { Environment.SetEnvironmentVariable("PROBE_OUT", previous); } - var line = File.ReadAllLines(Path.Combine(outDir, "P.jsonl")).Select(l => JsonNode.Parse(l)!.AsObject()).Last(); - File.Delete(Path.Combine(outDir, "P.jsonl")); - return (ran, ended, line); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void A_check_its_claim_declares_inapplicable_for_the_row_s_values_does_not_run_and_records_the_cite(bool async) - { - var (ran, ended, line) = Run("1", "2", async); - ran.ShouldBe(["nulls"], "keys does not apply where x=1 and y=2"); - ended.ShouldBeNull("nulls compared and passed; keys did not apply, which voids nothing"); - var keys = HarnessRun.Check(line, "keys"); - Files.Str(keys["category"]).ShouldBe("inapplicable"); - Files.Strings(keys["reasons"]).ShouldBe(["inapplicable:not-promised:no-key-here(declared x=1 y=2)"]); - Files.StringMap(keys["applied"]).ShouldBe(new Dictionary { ["x"] = "1", ["y"] = "2" }, "the axes the declaration matched"); - Files.Str(HarnessRun.Check(line, "nulls")["category"]).ShouldBe("pass", "the declaration is keys', for that check only"); - } - - [Fact] - public void Each_declaration_of_the_obligation_is_applied_and_one_over_two_axes_needs_both() - { - Run("1", "1").Ran.ShouldBe(["keys", "nulls"], "x=1 with y=1 is not x=1 with y=2"); - Run("2", "2").Ran.ShouldBe(["keys", "nulls"], "x=2 with y=2 is not x=1 with y=2"); - var (ran, _, line) = Run("2", "3"); - ran.ShouldBe(["nulls"]); - Files.Strings(HarnessRun.Check(line, "keys")["reasons"]).ShouldBe(["inapplicable:fact:KB-031(declared y=3)"]); - } - - [Fact] - public void A_row_in_hand_without_a_claim_or_without_a_staged_claims_file_sees_no_declarations() - { - Run("1", "2", claim: null).Ran.ShouldBe(["keys", "nulls"]); - Rows.ClaimsFile = null; - Run("1", "2").Ran.ShouldBe(["keys", "nulls"]); - Rows.ClaimsFile = Path.Combine(dir, "none.json"); - Run("1", "2").Ran.ShouldBe(["keys", "nulls"]); - } - - [Fact] - public void A_copy_of_a_row_keeps_its_claim() - { - var row = new Row(0, new Dictionary { ["x"] = "1", ["y"] = "2" }, "C1"); - row.Fresh().Claim.ShouldBe("C1"); - row.With("y", "1").Claim.ShouldBe("C1"); - } - - [Fact] - public void A_row_of_a_rows_file_holds_the_file_s_claim() - { - var path = Path.Combine(dir, "P.json"); - File.WriteAllText(path, """{"claim": "C1", "rows": [{"row": {"x": "1", "y": "2"}}]}"""); - Rows.Read(path).ShouldHaveSingleItem().Claim.ShouldBe("C1"); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/DotnetTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/DotnetTests.cs deleted file mode 100644 index 40c07acf..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/DotnetTests.cs +++ /dev/null @@ -1,73 +0,0 @@ -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// Which dotnet a tool starts (tools/Shared/Dotnet.cs, design/adr/0105): the one on PATH when it satisfies -/// global.json, the SDK installer's when only that one does, and otherwise the one on PATH, whose own error then -/// reaches whoever reads the output. -/// -public sealed class DotnetTests : IDisposable -{ - private readonly string installer = Directory.CreateTempSubdirectory("dotnet-installer-").FullName; - public void Dispose() => Directory.Delete(installer, recursive: true); - - private string Executable => Path.Combine(installer, OperatingSystem.IsWindows() ? "dotnet.exe" : "dotnet"); - - private void Install() => File.WriteAllText(Executable, ""); - - [Fact] - public void The_one_on_path_when_it_satisfies_the_pin() - { - Install(); - var asked = new List(); - Dotnet.Choose(installer, d => { asked.Add(d); return true; }).ShouldBe(("dotnet", null)); - asked.ShouldBe(["dotnet"], "the installer's is not even asked"); - } - - [Fact] - public void The_installers_when_only_it_satisfies_the_pin() - { - Install(); - Dotnet.Choose(installer, d => d != "dotnet").ShouldBe((Executable, installer)); - } - - [Fact] - public void The_one_on_path_when_neither_does() - { - Install(); - Dotnet.Choose(installer, _ => false).ShouldBe(("dotnet", null)); - } - - [Fact] - public void The_one_on_path_when_the_installer_put_none() - { - var asked = new List(); - Dotnet.Choose(installer, d => { asked.Add(d); return d != "dotnet"; }).ShouldBe(("dotnet", null)); - asked.ShouldBe(["dotnet"]); - } - - [Fact] - public void A_dotnet_satisfies_a_directory_whose_pin_it_has_and_not_one_whose_pin_it_lacks() - { - Dotnet.Satisfies("dotnet", installer).ShouldBeTrue("no global.json: any SDK"); - File.WriteAllText(Path.Combine(installer, "global.json"), """{"sdk": {"version": "0.0.1", "rollForward": "disable"}}"""); - Dotnet.Satisfies("dotnet", installer).ShouldBeFalse("an SDK no dotnet has"); - } - - [Fact] - public void A_program_that_does_not_start_satisfies_nothing() => - Dotnet.Satisfies(Path.Combine(installer, "no-such-dotnet"), installer).ShouldBeFalse(); - - [Fact] - public void A_child_is_pointed_at_the_chosen_directory() - { - var environment = new Dictionary { ["PATH"] = "/usr/bin" }; - Dotnet.Apply(installer, environment); - environment["PATH"].ShouldBe(installer + Path.PathSeparator + "/usr/bin"); - environment["DOTNET_ROOT"].ShouldBe(installer); - - var untouched = new Dictionary { ["PATH"] = "/usr/bin" }; - Dotnet.Apply(null, untouched); - untouched.Keys.ShouldBe(["PATH"]); - untouched["PATH"].ShouldBe("/usr/bin"); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/FixTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/FixTests.cs deleted file mode 100644 index 38cf460c..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/FixTests.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// prober fix F --commit SHA writes the fixed line of findings.jsonl as finding-line.schema.json wants it, where a -/// fixed finding was a line written by hand (F3, #45): the open line's claim and probe, the commit's full id. -/// -public sealed class FixTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private string Findings => Path.Combine(fx.BranchDir, "findings.jsonl"); - - private void Open(string id) => - File.AppendAllText(Findings, new JsonObject - { - ["schemaVersion"] = 1, ["id"] = id, ["claim"] = "C1", ["status"] = "open", ["probe"] = "P", ["reason"] = "row 3 differs", - }.ToJsonString() + "\n"); - - private JsonObject Last() => JsonNode.Parse(File.ReadAllLines(Findings)[^1])!.AsObject(); - - private Ledger Ledger() => new(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null); - - [Fact] - public void It_writes_the_fixed_line_with_the_open_lines_claim_and_probe_and_the_full_commit() - { - Open("F9"); - var head = fx.Sh("git", "rev-parse", "HEAD").Trim(); - var (exit, output, error) = fx.Ledger("fix", "F9", "--commit", head[..7], "--reason", "fixed by the converter's null"); - exit.ShouldBe(0, error); - output.ShouldBe($"F9 fixed at {head[..7]}{Environment.NewLine}"); - var line = Last(); - line.Select(kv => kv.Key).ShouldBe(["schemaVersion", "id", "claim", "status", "commit", "probe", "reason"]); - line["schemaVersion"]!.GetValue().ShouldBe(1); - line["id"]!.GetValue().ShouldBe("F9"); - line["claim"]!.GetValue().ShouldBe("C1"); - line["status"]!.GetValue().ShouldBe("fixed"); - line["commit"]!.GetValue().ShouldBe(head); - line["probe"]!.GetValue().ShouldBe("P"); - line["reason"]!.GetValue().ShouldBe("fixed by the converter's null"); - Ledger().OpenFindings().ShouldBeEmpty(); - Ledger().Findings()["F9"]["status"]!.GetValue().ShouldBe("fixed"); - } - - [Fact] - public void A_commit_outside_heads_history_is_recorded_and_counts_once_it_is_in_it() - { - Open("F9"); - fx.Sh("git", "checkout", "-q", "-b", "fix"); - fx.Write("src/a.cs", "class A { }\n"); - fx.Sh("git", "-c", "user.name=t", "-c", "user.email=t@t", "commit", "-qam", "the fix"); // the state stays untracked - var fix = fx.Sh("git", "rev-parse", "HEAD").Trim(); - fx.Sh("git", "checkout", "-q", "main"); - var (exit, output, error) = fx.Ledger("fix", "F9", "--commit", fix); - exit.ShouldBe(0, error); - output.ShouldContain($"F9 fixed at {fix[..7]}; it counts once that commit is in HEAD's history"); - Ledger().OpenFindings().ShouldBe(["F9"]); - fx.Sh("git", "merge", "-q", "--ff-only", "fix"); - Ledger().OpenFindings().ShouldBeEmpty(); - } - - [Theory] - [InlineData("F8", "HEAD", 1, "F8 is no finding of this ledger")] - [InlineData("F9", "0123456789abcdef0123456789abcdef01234567", 1, "--commit 0123456789abcdef0123456789abcdef01234567 is no commit of this repository")] - [InlineData("F9", "", 2, "--commit is required")] - public void It_refuses_a_finding_the_ledger_does_not_hold_and_a_commit_the_repository_lacks(string id, string commit, int code, string message) - { - Open("F9"); - var before = File.ReadAllText(Findings); - var (exit, _, error) = commit.Length > 0 ? fx.Ledger("fix", id, "--commit", commit) : fx.Ledger("fix", id); - exit.ShouldBe(code); - error.ShouldContain(message); - File.ReadAllText(Findings).ShouldBe(before); - } - - [Fact] - public void It_refuses_a_finding_already_fixed_and_a_call_without_one_id() - { - Open("F9"); - fx.Ledger("fix", "F9", "--commit", "HEAD").Exit.ShouldBe(0); - var (exit, _, error) = fx.Ledger("fix", "F9", "--commit", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain("F9 is fixed, not open"); - fx.Ledger("fix", "--commit", "HEAD").Exit.ShouldBe(2); - fx.Ledger("fix", "F9", "F10", "--commit", "HEAD").Exit.ShouldBe(2); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/Fixture.cs b/test/CodoMetis.TypeKit.Prober.Tests/Fixture.cs deleted file mode 100644 index b388e557..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/Fixture.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System.Diagnostics; -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// A repository with one claim C1 over axes x and y (values 1 and 2) and one probe P covering it. -internal sealed class Fixture : IDisposable -{ - public Fixture() - { - Root = Path.Combine(Path.GetTempPath(), "prober-tests", Guid.NewGuid().ToString("N")); - Directory.CreateDirectory(Root); - Memory = Path.Combine(Root, ".claude", "agent-memory-local", "prober"); - BranchDir = Path.Combine(Memory, "branches", "main"); - Sh("git", "init", "-q", "-b", "main"); - Write("README.md", "# a\n\nThe claim.\n"); - Write("src/a.cs", "class A {}\n"); - Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - }.ToJsonString() + "\n```\n"); - Write("tools/probe/corpus/claims.json", """[{"id": "C1", "source": "README.md#a", "surfaces": ["s"]}]"""); - Write("tools/probe/corpus/registry.json", """{"probes": {"P": {"claim": "C1", "filter": "*P"}}}"""); - Write("tools/probe/corpus/harness/P.cs", "// probe P\n"); - Rows([("1", "1"), ("2", "2")]); - Commit("init"); - Directory.CreateDirectory(BranchDir); - File.WriteAllText(Path.Combine(Memory, "axes-generated.json"), """{"axes": {}, "needsValues": []}"""); - Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - } - - public string Root { get; } - public string Memory { get; } - public string BranchDir { get; } - - public void Write(string relative, string text) - { - var path = Path.Combine(Root, relative); - Directory.CreateDirectory(Path.GetDirectoryName(path)!); - File.WriteAllText(path, text); - } - - /// P's rows: each probe has a rows file of its own, its claim inside. - public void Rows(IEnumerable<(string X, string Y)> rows) => - Write("tools/probe/corpus/rows/P.json", new JsonObject - { - ["claim"] = "C1", - ["rows"] = new JsonArray([.. rows.Select(r => (JsonNode)new JsonObject { ["row"] = new JsonObject { ["x"] = r.X, ["y"] = r.Y } })]), - }.ToJsonString()); - - public void Commit(string message) - { - Sh("git", "add", "-A"); - Sh("git", "-c", "user.name=t", "-c", "user.email=t@t", "commit", "-qm", message); - } - - public string Sh(string file, params string[] args) - { - var start = new ProcessStartInfo(file) { WorkingDirectory = Root, RedirectStandardOutput = true, RedirectStandardError = true }; - foreach (var a in args) start.ArgumentList.Add(a); - using var p = Process.Start(start)!; - var output = p.StandardOutput.ReadToEnd(); var error = p.StandardError.ReadToEnd(); - p.WaitForExit(); - p.ExitCode.ShouldBe(0, $"{file} {string.Join(' ', args)}: {output}{error}"); - return output; - } - - /// Runs a prober command in-process, in this repository, with the environment given. - public (int Exit, string Out, string Err) Ledger(params string[] args) => LedgerWith(new Dictionary(), args); - - public (int Exit, string Out, string Err) LedgerWith(Dictionary env, params string[] args) => LedgerEnding(env, Environment.NewLine, args); - - /// As , with the line end the output writers use, so a test sees Windows' output on any OS. - public (int Exit, string Out, string Err) LedgerEnding(Dictionary env, string newLine, params string[] args) - { - var output = new StringWriter { NewLine = newLine }; var error = new StringWriter { NewLine = newLine }; - var exit = Program.Run(new Context(Root, env, output, error), args); - return (exit, output.ToString(), error.ToString()); - } - - /// Runs a prober command in-process in another checkout of this repository (a linked worktree). - public (int Exit, string Out, string Err) LedgerIn(string checkout, params string[] args) - { - var output = new StringWriter(); var error = new StringWriter(); - var exit = Program.Run(new Context(checkout, new Dictionary(), output, error), args); - return (exit, output.ToString(), error.ToString()); - } - - /// A linked worktree of this repository (git worktree add) on a new branch, beside it; removed with the fixture. - public string Linked(string branch) - { - var path = Root + "-" + branch; - Sh("git", "worktree", "add", "-q", "-b", branch, path); - linked.Add(path); - return path; - } - - private readonly List linked = []; - - /// The lock file of a branch's state, wherever the tool puts it. - public string LockFile(string branch = "main") => - RoundLock.LockPath(new Ledger(new Context(Root, new Dictionary(), TextWriter.Null, TextWriter.Null), branch)); - - /// Runs the built dll as its own process: for the tests that race several takers. - public Process Spawn(params string[] args) - { - var start = new ProcessStartInfo("dotnet") { WorkingDirectory = Root, RedirectStandardOutput = true, RedirectStandardError = true }; - start.ArgumentList.Add(typeof(Program).Assembly.Location); - foreach (var a in args) start.ArgumentList.Add(a); - return Process.Start(start)!; - } - - public void Footprint() - { - var blob = Sh("git", "rev-parse", "HEAD:src/a.cs").Trim(); - File.AppendAllText(Path.Combine(BranchDir, "footprints.jsonl"), - new JsonObject { ["probe"] = "P", ["footprint"] = new JsonObject { ["src/a.cs"] = blob }, ["compileTime"] = new JsonObject(), ["toolchain"] = new JsonObject() }.ToJsonString() + "\n"); - } - - /// - /// What a replay of P records: the rows it ran, how each ended and the settings that applied; outcomes, when - /// given, sets each row's category and the finding it skips for. - /// - public string Evidence(IReadOnlyList> applied, string category = "pass", int[]? executed = null, - IReadOnlyList<(string Category, string? Finding)>? outcomes = null) - { - var idx = Enumerable.Range(0, applied.Count).ToArray(); - var path = Path.Combine(Root, "evidence.json"); - File.WriteAllText(path, new JsonObject - { - ["variants"] = new JsonArray(new JsonObject - { - ["env"] = new JsonObject(), ["expected"] = new JsonArray([.. idx.Select(i => (JsonNode)i)]), - ["executed"] = new JsonArray([.. (executed ?? idx).Select(i => (JsonNode)i)]), - }), - ["rows"] = new JsonObject(idx.Select(i => KeyValuePair.Create(i.ToString(System.Globalization.CultureInfo.InvariantCulture), (JsonNode?)new JsonObject - { - ["category"] = outcomes?[i].Category ?? category, ["applied"] = new JsonObject(applied[i].Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)kv.Value))), - ["findings"] = outcomes?[i].Finding is { } finding ? new JsonArray(finding) : new JsonArray(), - }))), - }.ToJsonString()); - return path; - } - - public int Covered() - { - var (exit, output, error) = Ledger("status", "--json"); - exit.ShouldBe(0, error); - return (int)JsonNode.Parse(output)!["claims"]!["C1"]!["current"]!.GetValue(); - } - - public void AgeTheLock() - { - var path = LockFile(); - var held = JsonNode.Parse(File.ReadAllText(path))!.AsObject(); - held["heartbeat"] = held["heartbeat"]!.GetValue() - 21 * 60; - File.WriteAllText(path, held.ToJsonString()); - } - - public void Dispose() - { - foreach (var dir in linked.Append(Root)) - try { Directory.Delete(dir, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/FreshnessTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/FreshnessTests.cs deleted file mode 100644 index c71a4a7a..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/FreshnessTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// The dll refuses to answer from other sources than the ones it was built from, its schemas among them, -/// as every tool does (tools/Directory.Build.targets, tools/Shared/SourceFingerprint.cs). -/// -public sealed class FreshnessTests -{ - [Fact] - public void The_stamp_covers_the_schemas() => - SourceFingerprint.Embedded.ShouldContain(line => line.StartsWith("tools/Prober/Schemas/", StringComparison.Ordinal) && line.Contains(".json|", StringComparison.Ordinal)); - - [Theory] - [InlineData("tools/Prober/Program.cs")] - [InlineData("tools/Prober/Schemas/round.schema.json")] - public void A_stale_dll_refuses_and_names_the_rebuild(string source) - { - using var sandbox = new ToolSandbox("Prober", "prober"); - File.AppendAllText(Path.Combine(sandbox.Repo, source), "\n"); - - var (code, _, error) = sandbox.Run(arguments: ["status"]); - - code.ShouldBe(3); - error.ShouldContain($"({source} differs)"); - error.ShouldContain("Run `dotnet build tools/Prober -c "); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/GapsTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/GapsTests.cs deleted file mode 100644 index d9db71e3..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/GapsTests.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System.Text.Json.Nodes; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// `prober gaps` prints what the corpus leaves out, each under its heading with its recorded reason, and says -/// none under a heading with nothing: a report from the tracked corpus and the generated axes that decides -/// nothing (decision 104). -/// -public sealed class GapsTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - /// The output after its first line, which names the branch and the commit. - private string Gaps(string newLine) - { - var (exit, output, error) = fx.LedgerEnding([], newLine, "gaps", "--base", "HEAD"); - exit.ShouldBe(0, "a report decides nothing: " + error); - var text = output.ReplaceLineEndings("\n"); - text.ShouldStartWith("prober gaps: main at "); - return text[(text.IndexOf('\n', StringComparison.Ordinal) + 1)..]; - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void Each_gap_is_listed_under_its_heading_with_its_reason(string newLine) - { - fx.Write("design/adr/0001-limits.md", "# 1. Limits\n\nAn ordering of keys is not promised.\n\nNo culture but the invariant one is promised.\n"); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject - { - ["x"] = new JsonArray("1", "2", "3"), ["y"] = new JsonArray("1", "2"), - ["shape.refused-kind"] = new JsonArray("in-generic-type"), - }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["refused"] = new JsonObject { ["x"] = new JsonObject { ["3"] = "the framework refuses 3 on its own (KB-001)" } }, - ["out-of-reach"] = new JsonObject { ["postgresql"] = "needs a server" }, - }.ToJsonString() + "\n```\n"); - File.WriteAllText(Path.Combine(fx.Memory, "axes-generated.json"), new JsonObject - { - ["axes"] = new JsonObject { ["json.z"] = new JsonArray("true", "false") }, - ["needsValues"] = new JsonArray("json.w"), - ["versions"] = new JsonObject { ["System.Text.Json"] = "10.0.0" }, - }.ToJsonString()); - fx.Write("tools/probe/corpus/claims.json", new JsonArray(new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["narrow"] = new JsonObject { ["y"] = "The claim." }, - ["not-promised"] = new JsonArray( - new JsonObject - { - ["id"] = "order", ["source"] = "design/adr/0001-limits.md#1-limits", ["sentence"] = "An ordering of keys is not promised.", - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2") }, - }, - new JsonObject { ["id"] = "culture", ["source"] = "design/adr/0001-limits.md#1-limits", ["sentence"] = "No culture but the invariant one is promised." }), - }).ToJsonString()); - - Gaps(newLine).ShouldBe(""" - settings no surface reaches and nothing ignores (enumerated at System.Text.Json 10.0.0): 1 - json.z (no surface reaches it and it is not ignored) - settings without values: 1 - json.w (no hand values and not ignored) - declarations the generators refuse (shape.refused-kind): 1 - in-generic-type - values the frameworks refuse on their own: 1 - x=3: the framework refuses 3 on its own (KB-001) - not promised, by what it concerns: 3 - the whole claim: C1/culture "No culture but the invariant one is promised." (design/adr/0001-limits.md#1-limits) - x=1|2: C1/order "An ordering of keys is not promised." (design/adr/0001-limits.md#1-limits) - y: C1 narrows it, "The claim." (README.md#a) - pairs no obligation wants (declared inapplicable): none - pairs no passing check read both axes of (the last replay's evidence): none - out of reach: 1 - postgresql: needs a server - - """.ReplaceLineEndings("\n")); - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void A_corpus_without_gaps_says_none_under_each_heading(string newLine) => - Gaps(newLine).ShouldBe(""" - settings no surface reaches and nothing ignores: none - settings without values: none - declarations the generators refuse (shape.refused-kind): none - values the frameworks refuse on their own: none - not promised, by what it concerns: none - pairs no obligation wants (declared inapplicable): none - pairs no passing check read both axes of (the last replay's evidence): none - out of reach: none - - """.ReplaceLineEndings("\n")); - - /// - /// C1 over x, y and z: shape wants every pair and its passing checks read x and y; parse does not apply where x=1 and - /// z=1 and its passing checks read x and z. x=1 z=1 is wanted by shape alone, which never read z, and no passing check - /// read y with z: those five pairs are listed. A check that did not pass reads nothing for the listing. - /// - [Fact] - public void The_pairs_no_obligation_wanting_them_read_both_axes_of_are_listed() - { - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2"), ["z"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y", "z"), ["watched"] = new JsonArray("src") } }, - }.ToJsonString() + "\n```\n"); - fx.Write("tools/probe/corpus/claims.json", new JsonArray(new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["obligations"] = new JsonArray( - new JsonObject { ["id"] = "shape", ["sentence"] = "The claim." }, - new JsonObject - { - ["id"] = "parse", ["sentence"] = "The claim.", - ["inapplicable"] = new JsonArray(new JsonObject { ["axes"] = new JsonObject { ["x"] = new JsonArray("1"), ["z"] = new JsonArray("1") }, ["cite"] = "docs:README.md#a" }), - }), - }).ToJsonString()); - fx.Commit("three axes"); - fx.Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - Gaps("\n").ShouldContain("pairs no passing check read both axes of (the last replay's evidence): none\n", Case.Sensitive, "no evidence yet: nothing to say"); - - static JsonObject Check(string obligation, string category, params (string Axis, string Value)[] read) => new() - { - ["obligation"] = obligation, ["category"] = category, ["baseline"] = "twin", - ["applied"] = new JsonObject(read.Select(r => KeyValuePair.Create(r.Axis, (JsonNode?)r.Value))), - }; - var evidence = Path.Combine(fx.Root, "evidence.json"); - File.WriteAllText(evidence, new JsonObject - { - ["variants"] = new JsonArray(new JsonObject { ["env"] = new JsonObject(), ["expected"] = new JsonArray(0), ["executed"] = new JsonArray(0) }), - ["rows"] = new JsonObject - { - ["0"] = new JsonObject - { - ["category"] = "pass", ["applied"] = new JsonObject(), ["findings"] = new JsonArray(), - ["checks"] = new JsonArray( - Check("shape", "pass", ("x", "1"), ("y", "1")), - Check("parse", "pass", ("x", "2"), ("z", "1")), - Check("parse", "inapplicable", ("y", "2"), ("z", "2"))), - }, - }, - }.ToJsonString()); - fx.Footprint(); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", evidence).Exit.ShouldBe(0); - - Gaps("\n").ShouldContain(""" - pairs no passing check read both axes of (the last replay's evidence): 5 - C1: x=1 z=1 - C1: y=1 z=1 - C1: y=1 z=2 - C1: y=2 z=1 - C1: y=2 z=2 - - """.ReplaceLineEndings("\n")); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/HarnessErrorTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/HarnessErrorTests.cs deleted file mode 100644 index be0ec024..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/HarnessErrorTests.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; -using Probes.Shapes; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// The harness writes rows to the process's PROBE_OUT, so its tests run one at a time. -[CollectionDefinition(nameof(ProbeOut), DisableParallelization = true)] -public sealed class ProbeOut; - -/// -/// A harness error is never a catch (decision 103): the probe corpus's own Rec.Run (harness/Row.cs, -/// compiled in) ends a row whose check throws as a harness error, not as a violation, and `seeds`, reading -/// the lines it writes, counts no such row caught, nor a violation whose reasons carry a harness error. -/// -[Collection(nameof(ProbeOut))] -public sealed class HarnessErrorTests : IDisposable -{ - private readonly Fixture fx = new(); - private readonly string cache; - - public HarnessErrorTests() - { - cache = fx.Root + "-cache"; - fx.Sh("git", "config", "core.autocrlf", "false"); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src") }, - }.ToJsonString() + "\n```\n"); - fx.Write("src/a.cs", "class A { /* DEFECT */ }\n"); - fx.Write("tools/probe/corpus/seeds/C1.patch", fx.Sh("git", "diff", "--", "src/a.cs")); - fx.Write("src/a.cs", "class A {}\n"); - fx.Write("tools/probe/corpus/registry.json", new JsonObject - { - ["probes"] = new JsonObject - { - ["P"] = new JsonObject { ["claim"] = "C1", ["filter"] = "*P", ["seed"] = new JsonObject { ["defect"] = "A holds the defect.", ["patch"] = "seeds/C1.patch" } }, - }, - }.ToJsonString()); - fx.Commit("seed"); - } - - public void Dispose() - { - fx.Dispose(); - try { Directory.Delete(cache, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - /// Runs one row through the harness's Rec.Run, writing to ; the exception it ends the test with, if any. - private static Exception? Harness(string outDir, int idx, Func> check) - { - var previous = Environment.GetEnvironmentVariable("PROBE_OUT"); - Environment.SetEnvironmentVariable("PROBE_OUT", outDir); - try - { - Rec.Run("C1", new Row(idx, new Dictionary { ["x"] = "1", ["y"] = "1" }), check).GetAwaiter().GetResult(); - return null; - } - catch (Exception ended) { return ended; } - finally { Environment.SetEnvironmentVariable("PROBE_OUT", previous); } - } - - private static Task Throws(Row _) => throw new InvalidOperationException("the check broke"); - - [Fact] - public void A_check_that_throws_ends_as_a_harness_error_and_fails_the_test_naming_the_exception() - { - var outDir = Path.Combine(fx.Root, "rows-out"); - var ended = Harness(outDir, 1, Throws); - ended.ShouldNotBeNull().Message.ShouldContain("UNEXPECTED InvalidOperationException: the check broke"); - - var line = JsonNode.Parse(File.ReadAllLines(Path.Combine(outDir, "C1.jsonl")).ShouldHaveSingleItem())!; - Files.Str(line["category"]).ShouldBe("harness-error", "an exception is the harness breaking, never the claim's check firing"); - Files.Strings(line["reasons"]).ShouldBe(["harness-error:UNEXPECTED InvalidOperationException: the check broke"]); - Files.Str(line["status"]).ShouldBe("fail"); - } - - [Fact] - public void A_seed_that_only_makes_a_check_throw_is_missed_not_caught() - { - var (exit, output) = Seeds(new HarnessAdapter(Throws)); - exit.ShouldBe(1, output); - output.ShouldContain("P (C1): missed, no row violates that did not already (2 rows: harness-error 1, pass 1; 1 ended in a harness error, which is no catch;"); - output.ShouldNotContain("caught,"); - } - - [Fact] - public void A_violation_whose_reasons_carry_a_harness_error_is_no_catch() - { - var (exit, output) = Seeds(new HarnessAdapter(r => - { - r.Outcome("harness-error", "the check could not tell"); - return Task.FromResult("and failed anyway"); - })); - exit.ShouldBe(1, output); - output.ShouldContain("P (C1): missed, no row violates that did not already (2 rows: pass 1, violation 1; 1 ended in a harness error, which is no catch;"); - } - - [Fact] - public void A_violation_through_the_harness_is_a_catch() - { - var (exit, output) = Seeds(new HarnessAdapter(_ => Task.FromResult("the claim does not hold"))); - exit.ShouldBe(0, output); - output.ShouldContain("P (C1): caught, 1 of 2 rows violate; e.g. #1: violation:the claim does not hold"); - } - - private (int Exit, string Out) Seeds(IProbeAdapter adapter) - { - var output = new StringWriter(); - var context = new Context(fx.Root, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, output, output); - int exit; - try { exit = global::Prober.Seeds.Run(context, new Args([], new HashSet(StringComparer.Ordinal)), adapter); } - catch (Refusal refusal) { output.WriteLine(refusal.Message); exit = refusal.ExitCode; } - return (exit, output.ToString()); - } - - /// - /// The probe P over C1's two rows, each run through the real harness: row 0 passes, and row 1 runs - /// while src/a.cs holds DEFECT. - /// - private sealed class HarnessAdapter(Func> seeded) : IProbeAdapter - { - public Ran Build(string worktree, IReadOnlyDictionary environment) => new(0, "Build: OK", ""); - - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - var defect = File.ReadAllText(Path.Combine(worktree, "src", "a.cs")).Contains("DEFECT", StringComparison.Ordinal); - var outDir = environment["PROBE_OUT"]!; - var failed = false; - for (var idx = 0; idx < 2; idx++) - failed |= Harness(outDir, idx, idx == 1 && defect ? seeded : _ => Task.FromResult(null)) is not null; - return new Ran(failed ? 1 : 0, "", ""); - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) => (null, "none"); - - public IReadOnlyDictionary Environment(string cacheDirectory) => new Dictionary(); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/LedgerTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/LedgerTests.cs deleted file mode 100644 index 62ec4ad4..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/LedgerTests.cs +++ /dev/null @@ -1,350 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// Coverage is earned only by replayed evidence, bound to the identity it ran under (the review's priority 1). -public sealed class AccountingTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private static Dictionary R(string x, string y) => new(StringComparer.Ordinal) { ["x"] = x, ["y"] = y }; - private static readonly IReadOnlyList> TwoRows = [R("1", "1"), R("2", "2")]; - - private void RecordPass(IReadOnlyList> applied, string category = "pass", int[]? executed = null) - { - fx.Footprint(); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", fx.Evidence(applied, category, executed)).Exit.ShouldBe(0); - } - - [Fact] - public void A_pass_credits_the_pairs_of_the_rows_it_ran() - { - RecordPass(TwoRows); - fx.Covered().ShouldBe(2); - } - - [Fact] - public void The_status_line_counts_what_the_json_counts() - { - RecordPass(TwoRows); - fx.Ledger("status").Out.ShouldStartWith("main at "); - fx.Ledger("status").Out.ShouldContain(": 2 of 4 pairs current (50.0%), 0 open finding(s)"); - } - - [Fact] - public void An_old_pass_does_not_credit_a_row_added_since() - { - RecordPass(TwoRows); - fx.Rows([("1", "1"), ("2", "2"), ("1", "2")]); - fx.Commit("a new row"); - fx.Covered().ShouldBe(0, "the pass was for another corpus: nothing of it may count now"); - } - - [Fact] - public void A_changed_harness_voids_the_pass() - { - RecordPass(TwoRows); - fx.Write("tools/probe/corpus/harness/P.cs", "// probe P, changed\n"); - fx.Commit("harness"); - fx.Covered().ShouldBe(0); - } - - [Fact] - public void A_changed_axes_file_voids_the_pass() - { - RecordPass(TwoRows); - var path = Path.Combine(fx.Root, ".claude/probe-axes.md"); - fx.Write(".claude/probe-axes.md", File.ReadAllText(path).Replace("\"watched\":[\"src\"]", "\"watched\":[\"src\",\"README.md\"]", StringComparison.Ordinal)); - fx.Commit("axes"); - fx.Covered().ShouldBe(0); - } - - [Fact] - public void Only_the_settings_that_applied_earn_credit() - { - RecordPass([R("1", "1"), R("1", "2")]); // row 2 asked for x=2 and ran as x=1 - fx.Covered().ShouldBe(2, "x1y1 and the applied x1y2, never the requested x2y2"); - var rows = JsonNode.Parse(fx.Ledger("rows", "--claim", "C1").Out)!["rows"]!.AsArray(); - rows.SelectMany(r => r!["pairs"]!.AsArray()).Select(p => $"{p![0]} {p[1]}").ShouldContain("x=2 y=2"); - } - - [Fact] - public void An_axis_the_harness_never_read_earns_nothing() - { - RecordPass([new(StringComparer.Ordinal) { ["x"] = "1" }, new(StringComparer.Ordinal) { ["x"] = "2" }]); - fx.Covered().ShouldBe(0); - } - - [Fact] - public void A_refusal_is_no_evidence_of_success() - { - RecordPass(TwoRows, category: "expected-refusal"); - fx.Covered().ShouldBe(0); - } - - [Fact] - public void A_row_that_did_not_run_is_never_credited() - { - RecordPass(TwoRows, executed: [0]); - fx.Covered().ShouldBe(1); - } -} - -/// -/// What earned nothing is counted where the coverage is read, and a row that steps around a finding binds: the -/// gate refuses while one does, and the ledger names a skip whose finding is fixed or dismissed. -/// -public sealed class OutcomeTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private static Dictionary R(string x, string y) => new(StringComparer.Ordinal) { ["x"] = x, ["y"] = y }; - - private string Record(params (string Category, string? Finding)[] outcomes) - { - fx.Footprint(); - var evidence = fx.Evidence([R("1", "1"), R("2", "2")], outcomes: outcomes); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", evidence).Exit.ShouldBe(0); - return evidence; - } - - private List StaleSkips(string evidence) => - new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null) - .StaleSkips(JsonNode.Parse(File.ReadAllText(evidence)) as JsonObject); - - private void Finding(string status, string commit) => - File.AppendAllText(Path.Combine(fx.BranchDir, "findings.jsonl"), - new JsonObject { ["id"] = "F9", ["claim"] = "C1", ["status"] = status, ["commit"] = commit }.ToJsonString() + "\n"); - - [Fact] - public void Status_counts_how_the_rows_of_a_claim_ended() - { - Record(("pass", null), ("expected-refusal", null)); - var outcomes = JsonNode.Parse(fx.Ledger("status", "--json").Out)!["claims"]!["C1"]!["outcomes"]!; - outcomes["pass"]!.GetValue().ShouldBe(1); - outcomes["expected-refusal"]!.GetValue().ShouldBe(1); - fx.Ledger("status").Out.ShouldContain("C1: 1/4 (rows: expected-refusal 1, pass 1; checks: expected-refusal 1, pass 1)"); - } - - [Fact] - public void A_skip_for_a_finding_is_shown_and_refused_by_the_gate_without_any_ledger_of_findings() - { - fx.Sh("git", "tag", "v1"); - Record(("pass", null), ("known-finding", "F9")); - fx.Ledger("status").Out.ShouldContain("1 row(s) skip for finding F9"); - var (exit, output, _) = fx.Ledger("gate", "--since", "v1", "--json"); - exit.ShouldNotBe(0); - JsonNode.Parse(output)!["reasons"]!.AsArray().Select(r => r!.GetValue()).ShouldContain("P: 1 row(s) skip for finding F9; fix it and remove the skip, or dismiss it"); - } - - [Fact] - public void A_skip_for_an_open_finding_stands() - { - var evidence = Record(("known-finding", "F9"), ("pass", null)); - Finding("open", ""); - StaleSkips(evidence).ShouldBeEmpty(); - } - - [Fact] - public void A_skip_for_a_fixed_finding_is_stale() - { - var evidence = Record(("known-finding", "F9"), ("pass", null)); - var head = fx.Sh("git", "rev-parse", "HEAD").Trim(); - Finding("open", ""); - Finding("fixed", head); - StaleSkips(evidence).ShouldBe([$"1 row(s) skip for F9, which is fixed at {head[..7]}: remove the skip"]); - } - - [Fact] - public void A_skip_for_a_dismissed_finding_is_stale() - { - var evidence = Record(("known-finding", "F9"), ("pass", null)); - Finding("open", ""); - fx.Write("tools/probe/corpus/dismissed.jsonl", new JsonObject { ["id"] = "F9", ["reason"] = "intended", ["date"] = "2026-10-15" }.ToJsonString() + "\n"); - StaleSkips(evidence).ShouldBe(["1 row(s) skip for F9, which is dismissed: remove the skip"]); - } -} - -/// One round at a time, on every OS: an exclusive create, liveness by heartbeat, a mutex for takeovers. -public sealed class LockTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - [Fact] - public void A_second_holder_is_refused_while_the_first_is_alive() - { - fx.Ledger("lock", "--holder", "a", "--mode", "explore").Exit.ShouldBe(0); - fx.Ledger("lock", "--holder", "b", "--mode", "replay").Exit.ShouldNotBe(0); - } - - [Fact] - public void A_holder_whose_heartbeat_stopped_is_taken_over() - { - fx.Ledger("lock", "--holder", "a", "--mode", "explore").Exit.ShouldBe(0); - fx.AgeTheLock(); - fx.Ledger("lock", "--holder", "b", "--mode", "replay").Exit.ShouldBe(0); - } - - [Fact] - public void A_heartbeat_keeps_the_holder_alive() - { - fx.Ledger("lock", "--holder", "a", "--mode", "explore").Exit.ShouldBe(0); - fx.AgeTheLock(); - fx.Ledger("heartbeat", "--holder", "a").Exit.ShouldBe(0); - fx.Ledger("lock", "--holder", "b", "--mode", "replay").Exit.ShouldNotBe(0); - } - - [Fact] - public void Two_takers_at_once_get_one_lock() => RaceOf(8).ShouldBe(1); - - [Fact] - public void Racing_takers_of_a_dead_holder_get_one_lock() - { - fx.Ledger("lock", "--holder", "dead", "--mode", "explore").Exit.ShouldBe(0); - fx.AgeTheLock(); - RaceOf(8).ShouldBe(1); - } - - [Fact] - public void Racing_threads_over_a_dead_holder_get_one_lock() - { - // Threads released together by a barrier collide in the critical section far more tightly than - // processes can; ten rounds, each must end with exactly one holder. - for (var round = 0; round < 10; round++) - { - fx.Ledger("lock", "--holder", $"dead{round}", "--mode", "explore").Exit.ShouldBe(0); - fx.AgeTheLock(); - const int takers = 16; - using var barrier = new Barrier(takers); - var exits = new int[takers]; - var threads = Enumerable.Range(0, takers).Select(i => new Thread(() => - { - barrier.SignalAndWait(); - exits[i] = fx.Ledger("lock", "--holder", $"t{round}-{i}", "--mode", "replay").Exit; - })).ToList(); - threads.ForEach(t => t.Start()); - threads.ForEach(t => t.Join()); - exits.Count(e => e == 0).ShouldBe(1, $"round {round}"); - File.Delete(fx.LockFile()); - } - } - - /// - /// What crashed the test host on windows-latest (run 38732628888): a taker creating round.lock.mutex while - /// its last holder's delete was still pending got UnauthorizedAccessException, which Windows throws there - /// instead of IOException, and the mutex loop let it through. Here the OS refuses the create every time, - /// the same exception on every platform: a directory in the mutex's place on Windows, a state directory - /// without write permission elsewhere. A taker waits, then refuses; it never throws. - /// - [Fact] - public void A_mutex_the_OS_refuses_to_create_is_waited_for_and_refused_not_thrown() - { - var directory = Path.GetDirectoryName(fx.LockFile())!; - Directory.CreateDirectory(directory); - var mutex = fx.LockFile() + ".mutex"; - if (OperatingSystem.IsWindows()) Directory.CreateDirectory(mutex); - else File.SetUnixFileMode(directory, UnixFileMode.UserRead | UnixFileMode.UserExecute); - try - { - var (exit, _, error) = fx.Ledger("lock", "--holder", "a", "--mode", "explore"); - - exit.ShouldNotBe(0); - error.ShouldContain("mutex"); - } - finally - { - if (OperatingSystem.IsWindows()) Directory.Delete(mutex); - else File.SetUnixFileMode(directory, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute); - } - } - - [Fact] - public void A_lock_of_one_branch_leaves_another_branchs_lock_free() - { - var other = fx.Linked("other"); - fx.Ledger("lock", "--holder", "a", "--mode", "explore").Exit.ShouldBe(0); - - var (exit, output, error) = fx.LedgerIn(other, "lock", "--holder", "b", "--mode", "explore"); - - exit.ShouldBe(0, error + output); - File.Exists(fx.LockFile("other")).ShouldBeTrue(); - File.Exists(fx.LockFile("main")).ShouldBeTrue("a's lock is still held"); - } - - [Fact] - public void A_second_lock_of_one_branch_is_refused_from_another_checkout() - { - var other = fx.Linked("other"); - fx.Ledger("lock", "--holder", "a", "--mode", "explore").Exit.ShouldBe(0); - - fx.LedgerIn(other, "lock", "--branch", "main", "--holder", "b", "--mode", "replay").Exit.ShouldNotBe(0); - } - - private int RaceOf(int takers) - { - var processes = Enumerable.Range(0, takers).Select(i => fx.Spawn("lock", "--holder", $"h{i}", "--mode", "replay")).ToList(); - foreach (var p in processes) { p.StandardOutput.ReadToEnd(); p.StandardError.ReadToEnd(); p.WaitForExit(); } - return processes.Count(p => p.ExitCode == 0); - } -} - -/// The release gate needs no model: every obligation is a probe or a reviewed waiver. -public sealed class GateTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private void TouchTheClaim() - { - fx.Write("README.md", "# a\n\nThe claim, reworded.\n"); - fx.Commit("docs"); - } - - [Fact] - public void An_unprobed_touched_claim_fails_with_what_is_missing() - { - fx.Sh("git", "tag", "v1"); - TouchTheClaim(); - var (exit, output, _) = fx.Ledger("gate", "--since", "v1", "--json"); - exit.ShouldNotBe(0); - JsonNode.Parse(output)!["reasons"]!.AsArray().Select(r => r!.GetValue()).ShouldContain(r => r.StartsWith("C1:", StringComparison.Ordinal)); - } - - [Fact] - public void A_reviewed_waiver_meets_the_obligation_without_a_probe() - { - fx.Sh("git", "tag", "v1"); - fx.Write("tools/probe/corpus/registry.json", """{"probes": {}}"""); - fx.Write("tools/probe/corpus/waivers.json", """[{"claim": "C1", "reason": "covered by the suite's C1Tests", "reviewed_by": "maintainer", "date": "2026-10-15"}]"""); - TouchTheClaim(); - var (exit, _, error) = fx.Ledger("gate", "--since", "v1"); - exit.ShouldBe(0, error); - } - - [Fact] - public void An_unsigned_waiver_meets_nothing() - { - fx.Sh("git", "tag", "v1"); - fx.Write("tools/probe/corpus/registry.json", """{"probes": {}}"""); - fx.Write("tools/probe/corpus/waivers.json", """[{"claim": "C1", "reason": "later"}]"""); - TouchTheClaim(); - fx.Ledger("gate", "--since", "v1").Exit.ShouldNotBe(0); - } - - [Fact] - public void State_goes_where_PROBE_STATE_DIR_says() - { - var state = Path.Combine(Path.GetTempPath(), "prober-state-" + Guid.NewGuid().ToString("N")); - try - { - fx.LedgerWith(new() { ["PROBE_STATE_DIR"] = state }, "lock", "--holder", "ci", "--mode", "replay").Exit.ShouldBe(0); - Directory.EnumerateFiles(state, "round.lock", SearchOption.AllDirectories).ShouldNotBeEmpty(); - File.Exists(fx.LockFile()).ShouldBeFalse(); - } - finally { if (Directory.Exists(state)) Directory.Delete(state, recursive: true); } - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/NewProbeTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/NewProbeTests.cs deleted file mode 100644 index 2d9071e6..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/NewProbeTests.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// `new` stages what a probe writer used to do by hand: the skeleton in the harness's form with the claim's -/// obligations quoted and one throwing check each, the claim's rows, and the registry entry with no seed yet, -/// so the seeds every obligation owes are named. C1 lists two obligations; C7-two-words lists none. -/// -public sealed class NewProbeTests : IDisposable -{ - private readonly Fixture fx = new(); - - public NewProbeTests() - { - fx.Write("README.md", "# a\n\nThe claim.\n\nA key is written as the wrapped type writes it.\n\nA null is refused.\n"); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src"), ["families"] = new JsonObject { ["f"] = new JsonArray("s") } }, - }.ToJsonString() + "\n```\n"); - fx.Write("tools/probe/corpus/claims.json", new JsonArray( - new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["obligations"] = new JsonArray( - new JsonObject { ["id"] = "keys", ["sentence"] = "A key is written as the wrapped type writes it." }, - new JsonObject { ["id"] = "nulls", ["sentence"] = "A null is refused." }), - }, - new JsonObject { ["id"] = "C7-two-words", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s") }).ToJsonString()); - fx.Commit("claims with obligations"); - fx.Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - } - - public void Dispose() => fx.Dispose(); - - private string Staged(string relative) => Path.Combine(fx.BranchDir, "staging", relative); - - [Fact] - public void It_stages_the_skeleton_the_rows_and_the_registry_entry() - { - var (exit, output, error) = fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe"); - exit.ShouldBe(0, output + error); - - var source = File.ReadAllText(Staged("probes/C1KeysProbe.cs")); - source.ShouldContain("// Claim C1 (README.md#a), surfaces s, family f."); - source.ShouldContain("// keys: \"A key is written as the wrapped type writes it.\""); - source.ShouldContain("// nulls: \"A null is refused.\""); - source.ShouldContain("// TODO keys: \"A key is written as the wrapped type writes it.\""); - source.ShouldContain("// TODO nulls: \"A null is refused.\""); - - // The probe's own rows, C1's other probe P's untouched: P has covered nothing, so a covering array over all four pairs. - var staged = JsonNode.Parse(File.ReadAllText(Staged("rows/C1KeysProbe.json")))!; - staged["claim"]!.GetValue().ShouldBe("C1"); - staged["rows"]!.AsArray().Select(r => $"{r!["row"]!["x"]}{r["row"]!["y"]}").Order().ShouldBe(["11", "12", "21", "22"]); - File.Exists(Staged("rows/P.json")).ShouldBeFalse("a new probe leaves its sibling's rows as they are"); - - var entry = JsonNode.Parse(File.ReadAllText(Staged("registry.json")))!["probes"]!["C1KeysProbe"]!.AsObject(); - entry["claim"]!.GetValue().ShouldBe("C1"); - entry["filter"]!.GetValue().ShouldBe("*C1KeysProbe"); - entry["seeds"]!.AsArray().ShouldBeEmpty(); - entry.ContainsKey("seed").ShouldBeFalse(); - - output.ShouldContain("still owed, per obligation:"); - output.ShouldContain(" keys: the check CheckKeys"); - output.ShouldContain(" nulls: the check CheckNulls"); - } - - [Fact] - public void The_seeds_each_obligation_owes_are_named() - { - fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe").Exit.ShouldBe(0); - var problems = global::Prober.Seeds.Problems(new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null)); - problems.ShouldContain("C1KeysProbe: no seed, its registry entry names none"); - problems.ShouldContain("C1: obligation keys has no seed in any of its probes"); - problems.ShouldContain("C1: obligation nulls has no seed in any of its probes"); - - var (exit, output, _) = fx.Ledger("seeds", "--dry-run"); - exit.ShouldBe(0); - output.ShouldContain(" C1KeysProbe/keys: (none)"); - output.ShouldContain(" C1KeysProbe/nulls: (none)"); - } - - [Fact] - public void A_claim_not_in_the_claims_is_refused_and_nothing_staged() - { - var (exit, _, error) = fx.Ledger("new", "--claim", "C9"); - exit.ShouldBe(1); - error.ShouldContain("no claim C9 in claims.json"); - Directory.Exists(Path.Combine(fx.BranchDir, "staging")).ShouldBeFalse(); - } - - [Fact] - public void A_name_a_probe_has_is_refused_and_nothing_changes() - { - fx.Write("tools/probe/corpus/registry.json", """{"probes": {"P": {"claim": "C1", "filter": "*P"}, "C1OldProbe": {"claim": "C1", "filter": "*C1OldProbe"}}}"""); - fx.Commit("a second probe of C1"); - var (exit, _, error) = fx.Ledger("new", "--claim", "C1", "--probe", "C1OldProbe"); - exit.ShouldBe(1); - error.ShouldContain("a probe C1OldProbe exists already (in the registry)"); - fx.Ledger("new", "--claim", "C1", "--probe", "P").Exit.ShouldBe(2, "a name that does not end in Probe"); - Directory.Exists(Path.Combine(fx.BranchDir, "staging")).ShouldBeFalse(); - - fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe").Exit.ShouldBe(0); - var registry = File.ReadAllText(Staged("registry.json")); - var source = File.ReadAllText(Staged("probes/C1KeysProbe.cs")); - fx.Ledger("new", "--claim", "C7-two-words", "--probe", "C1KeysProbe").Exit.ShouldBe(1, "a second `new` of one name"); - File.ReadAllText(Staged("registry.json")).ShouldBe(registry); - File.ReadAllText(Staged("probes/C1KeysProbe.cs")).ShouldBe(source); - } - - [Theory] - [InlineData("C20-testing-shouldhold", "C20TestingShouldholdProbe")] - [InlineData("E02-value-translates-to-column", "E02ValueTranslatesToColumnProbe")] - [InlineData("L01-json-bytes", "L01JsonBytesProbe")] - public void The_name_defaults_to_the_claim_s_prefix_and_words(string claim, string probe) => NewProbe.DefaultName(claim).ShouldBe(probe); - - [Fact] - public void Without_a_name_the_default_is_staged() - { - fx.Ledger("new", "--claim", "C7-two-words").Exit.ShouldBe(0); - // The registry's key, not the file: a file system that ignores case finds the file under another spelling. - JsonNode.Parse(File.ReadAllText(Staged("registry.json")))!["probes"]!.AsObject().Select(kv => kv.Key).ShouldBe(["C7TwoWordsProbe"]); - File.ReadAllText(Staged("probes/C7TwoWordsProbe.cs")).ShouldContain("// claim: the claim as a whole"); - } - - [Fact] - public void A_family_that_is_not_the_claim_s_is_refused() - { - var (exit, _, error) = fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe", "--family", "g"); - exit.ShouldBe(2); - error.ShouldContain("claim C1 is of family f (its first surface, s), not g"); - fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe", "--family", "f").Exit.ShouldBe(0); - } - - /// - /// The lines that make a probe a probe of this harness, with its own names taken out: the namespace, the - /// class, the rows as member data, the theory and the row's run through Rec.Run with a check of the row. - /// - private static List Form(string source) => - [.. source.Split('\n').Select(line => line.Trim()).Select(line => line switch - { - _ when line.StartsWith("namespace ", StringComparison.Ordinal) => line, - _ when Regex.IsMatch(line, @"^public sealed class \w+Probe$") => "public sealed class {probe}", - _ when line.StartsWith("public static TheoryData Data()", StringComparison.Ordinal) => - Regex.Replace(line, @"Rows\.Data\(""[^""]+""\)", "Rows.Data({probe})"), - _ when line.StartsWith("[Theory", StringComparison.Ordinal) => line, - _ when line.StartsWith("public Task ", StringComparison.Ordinal) => Regex.Replace(line, @"Rec\.Run\(probe, idx, [^;]+\);$", "Rec.Run(probe, idx, {check});"), - _ => null, - }).OfType()]; - - private static readonly string Corpus = Path.Combine(RepositoryRoot(), "tools", "probe", "corpus", "probes"); - - [Theory] - [InlineData("C08SameNameWarningProbe")] - [InlineData("C12DescribedConverterProbe")] - [InlineData("C20ShouldHoldProbe")] - public void The_skeleton_has_the_form_of_the_corpus_s_probes(string probe) - { - fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe").Exit.ShouldBe(0); - var skeleton = File.ReadAllText(Staged("probes/C1KeysProbe.cs")); - var corpus = File.ReadAllText(Path.Combine(Corpus, probe + ".cs")); - Form(skeleton).ShouldBe(Form(corpus)); - Form(skeleton).Count.ShouldBe(5, "namespace, class, rows, theory and run"); - var usings = corpus.Split('\n').Where(l => l.StartsWith("using ", StringComparison.Ordinal)).Select(l => l.Trim()).ToList(); - skeleton.Split('\n').Where(l => l.StartsWith("using ", StringComparison.Ordinal)).ShouldAllBe(l => usings.Contains(l.Trim())); - } - - [Fact] - public void Every_obligation_s_check_throws_until_it_is_written() - { - fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe").Exit.ShouldBe(0); - var skeleton = File.ReadAllText(Staged("probes/C1KeysProbe.cs")); - foreach (var method in new[] { "CheckKeys", "CheckNulls" }) - { - skeleton.ShouldContain($"static Task {method}(Row r) => throw new NotImplementedException("); - Regex.IsMatch(skeleton, $@"static async Task Check\(Row r\) =>[^;]*await {method}\(r\)").ShouldBeTrue($"Check runs {method}"); - } - Regex.Matches(skeleton, @"=> throw new NotImplementedException\(").Count.ShouldBe(2); - skeleton.ShouldNotContain("return null"); - skeleton.ShouldNotContain("FromResult"); - } - - private static string RepositoryRoot() - { - var root = AppContext.BaseDirectory; - while (!File.Exists(Path.Combine(root, "CodoMetis.TypeKit.slnx"))) root = Path.GetDirectoryName(root) ?? throw new InvalidOperationException("no CodoMetis.TypeKit.slnx above the test output"); - return root; - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/ObligationsTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/ObligationsTests.cs deleted file mode 100644 index 94369bb4..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/ObligationsTests.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// A claim lists what it promises, each obligation a sentence quoted from its source, and what it does not -/// promise, each with the sentence that makes it intended; every obligation of a claim with probes has a seed -/// that names it (decision 104). The probe here is a fake adapter: row N of C1 violates while SEED_ROW is N. -/// -public sealed class ObligationsTests : IDisposable -{ - private readonly Fixture fx = new(); - private readonly string cache; - private readonly FakeAdapter adapter = new(); - - public ObligationsTests() - { - cache = fx.Root + "-cache"; - fx.Sh("git", "config", "core.autocrlf", "false"); - fx.Write("README.md", "# a\n\nThe claim.\n\nA key is written as the wrapped type writes it.\n\nA null is refused.\n"); - fx.Write("design/adr/0001-limits.md", "# 1. Limits\n\nAn ordering of keys is not promised.\n"); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src") }, - }.ToJsonString() + "\n```\n"); - fx.Commit("sources and replay configuration"); - } - - public void Dispose() - { - fx.Dispose(); - try { Directory.Delete(cache, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - private static JsonObject Obligation(string id, string sentence) => new() { ["id"] = id, ["sentence"] = sentence }; - - private static JsonArray TwoObligations() => new( - Obligation("keys", "A key is written as the wrapped type writes it."), - Obligation("nulls", "A null is refused.")); - - private void Claims(JsonObject claim) - { - var c = new JsonObject { ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s") }; - foreach (var (key, value) in claim) c[key] = value?.DeepClone(); - fx.Write("tools/probe/corpus/claims.json", new JsonArray(c).ToJsonString()); - } - - /// Registers P for C1 with the seeds given, each an environment toggle that makes the check of its obligation violate in row row. - private void Register(JsonObject? seed = null, params (string Obligation, string Row)[] seeds) - { - var entry = new JsonObject { ["claim"] = "C1", ["filter"] = "*P" }; - if (seed is not null) entry["seed"] = seed; - if (seeds.Length > 0) - entry["seeds"] = new JsonArray([.. seeds.Select(s => (JsonNode)new JsonObject - { - ["obligation"] = s.Obligation, ["env"] = new JsonObject { ["SEED_ROW"] = s.Row, ["SEED_CHECK"] = s.Obligation }, ["defect"] = $"{s.Obligation} is broken.", - })]); - fx.Write("tools/probe/corpus/registry.json", new JsonObject { ["probes"] = new JsonObject { ["P"] = entry } }.ToJsonString()); - fx.Commit("register"); - } - - private static JsonObject EnvSeed() => new() { ["env"] = new JsonObject { ["SEED_ROW"] = "1" }, ["defect"] = "Row 1 is broken." }; - - private List Problems() => Seeds.Problems(new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null)); - - private JsonObject Status() - { - var (exit, output, error) = fx.Ledger("status", "--json"); - exit.ShouldBe(0, error); - return JsonNode.Parse(output)!["claims"]!["C1"]!.AsObject(); - } - - /// Each obligation of the claim in `status --json`, as "id: the probes whose seeds break it". - private static List ObligationsOf(JsonObject claim) => - [.. claim["obligations"]!.AsArray().Select(o => $"{o!["id"]!.GetValue()}: {string.Join(", ", o["seeded_by"]!.AsArray().Select(p => p!.GetValue()))}")]; - - [Fact] - public void An_obligation_quoting_a_sentence_its_source_does_not_hold_is_refused() - { - Claims(new JsonObject { ["obligations"] = new JsonArray(Obligation("keys", "A key is written by ToString().")) }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain("claim C1: obligation keys quotes a sentence not found in README.md"); - } - - [Fact] - public void A_not_promised_entry_is_checked_against_its_own_source() - { - // The sentence is in the claim's README, not in the record the entry names, so it is refused. - Claims(new JsonObject - { - ["not-promised"] = new JsonArray(new JsonObject { ["id"] = "order", ["source"] = "design/adr/0001-limits.md#1-limits", ["sentence"] = "A null is refused." }), - }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain("claim C1: not-promised order quotes a sentence not found in design/adr/0001-limits.md"); - } - - [Fact] - public void A_not_promised_entry_its_source_holds_is_kept() - { - Claims(new JsonObject - { - ["not-promised"] = new JsonArray(new JsonObject { ["id"] = "order", ["source"] = "design/adr/0001-limits.md#1-limits", ["sentence"] = "An ordering of keys is not promised." }), - }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(0, error); - } - - [Fact] - public void A_duplicate_obligation_id_is_refused() - { - Claims(new JsonObject - { - ["obligations"] = new JsonArray(Obligation("keys", "A key is written as the wrapped type writes it."), Obligation("keys", "A null is refused.")), - }); - var (exit, _, error) = fx.Ledger("universe", "--base", "HEAD"); - exit.ShouldBe(1); - error.ShouldContain("claim C1: obligation keys is listed twice"); - } - - [Fact] - public void A_claim_without_obligations_has_one_the_claim_seeded_by_a_seed_naming_none() - { - Register(EnvSeed()); - ObligationsOf(Status()).ShouldBe(["claim: P"]); - Problems().ShouldBeEmpty(); - } - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void Status_shows_the_obligations_no_seed_breaks(string newLine) - { - Claims(new JsonObject { ["obligations"] = TwoObligations() }); - Register(null, ("keys", "1")); - ObligationsOf(Status()).ShouldBe(["keys: P", "nulls: "]); - var (exit, output, error) = fx.LedgerEnding([], newLine, "status"); - exit.ShouldBe(0, error); - output.ReplaceLineEndings("\n").ShouldContain("\n C1: 0/4 obligations 2 (1 without a seed: nulls), 2 uncredited\n"); - - Register(null, ("keys", "1"), ("nulls", "0")); - fx.LedgerEnding([], newLine, "status").Out.ReplaceLineEndings("\n").ShouldContain("\n C1: 0/4 obligations 2, each seeded, 2 uncredited\n"); - } - - [Fact] - public void The_check_without_a_build_names_an_obligation_no_seed_breaks() - { - Claims(new JsonObject { ["obligations"] = TwoObligations() }); - Register(EnvSeed(), ("keys", "1")); - Problems().ShouldBe(["C1: obligation nulls has no seed in any of its probes"], "a seed naming no obligation proves the probe, not an obligation the claim lists"); - Register(null, ("keys", "1"), ("nulls", "0")); - Problems().ShouldBeEmpty(); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void The_check_without_a_build_names_a_seed_naming_an_obligation_the_claim_does_not_list(bool listed) - { - if (listed) Claims(new JsonObject { ["obligations"] = new JsonArray(Obligation("keys", "A key is written as the wrapped type writes it.")) }); - Register(null, ("keys", "1"), ("kyes", "0")); - Problems().ShouldBe(listed - ? ["P/kyes: names obligation kyes, which claim C1 does not list"] - : ["P/keys: names obligation keys, which claim C1 does not list", "P/kyes: names obligation kyes, which claim C1 does not list"]); - } - - [Fact] - public void Seeds_runs_each_seed_under_its_obligation() - { - Claims(new JsonObject { ["obligations"] = TwoObligations() }); - Register(null, ("keys", "1"), ("nulls", "7")); - var output = new StringWriter(); var error = new StringWriter(); - var context = new Context(fx.Root, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, output, error); - var exit = Seeds.Run(context, new Args([], new HashSet(StringComparer.Ordinal) { "dry-run" }), adapter); - - exit.ShouldBe(1, "the nulls seed makes no row violate, so it is missed and fails the command"); - var text = output.ToString().ReplaceLineEndings("\n"); - text.ShouldContain(": 2 seeds of 1 probes, in "); - text.ShouldContain("\n P/keys (C1): caught, 1 of 2 rows violate; e.g. #1 keys: violation:row 1 is broken\n"); - text.ShouldContain("\n P/nulls (C1): missed, no row violates that did not already (2 rows: pass 2;"); - var last = JsonNode.Parse(File.ReadAllText(Path.Combine(fx.BranchDir, "seeds-last.json")))!["seeds"]!.AsArray() - .Select(s => (s!["probe"]!.GetValue(), s["obligation"]!.GetValue(), s["seed"]!.GetValue(), s["result"]!.GetValue())); - last.ShouldBe([("P", "keys", "SEED_ROW=1,SEED_CHECK=keys", "caught"), ("P", "nulls", "SEED_ROW=7,SEED_CHECK=nulls", "missed")]); - } - - /// - /// The probe P over C1's two rows, without a build: row N violates where SEED_ROW is N, by its check of the - /// obligation SEED_CHECK names where it names one (each row then runs that check), else as a row without checks. - /// - private sealed class FakeAdapter : IProbeAdapter - { - public Ran Build(string worktree, IReadOnlyDictionary environment) => new(0, "Build: OK", ""); - - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - var broken = environment.GetValueOrDefault("SEED_ROW"); - var check = environment.GetValueOrDefault("SEED_CHECK"); - var outDir = environment["PROBE_OUT"]!; - Directory.CreateDirectory(outDir); - var lines = Enumerable.Range(0, 2).Select(idx => - { - var violates = broken == idx.ToString(System.Globalization.CultureInfo.InvariantCulture); - var line = new JsonObject - { - ["idx"] = idx, ["category"] = violates ? "violation" : "pass", - ["reasons"] = violates && check is null ? new JsonArray($"violation:row {idx} is broken") : new JsonArray(), - }; - if (check is not null) - line["checks"] = new JsonArray(new JsonObject - { - ["obligation"] = check, ["baseline"] = "twin", ["category"] = violates ? "violation" : "pass", - ["reasons"] = violates ? new JsonArray($"violation:row {idx} is broken") : new JsonArray(), - }); - return line.ToJsonString(); - }).ToList(); - File.WriteAllText(Path.Combine(outDir, "C1.jsonl"), string.Join('\n', lines) + "\n"); - return new Ran(lines.Any(l => l.Contains("\"violation\"", StringComparison.Ordinal)) ? 1 : 0, "", ""); - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) => (null, "none"); - - public IReadOnlyDictionary Environment(string cacheDirectory) => new Dictionary(); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/PerCheckTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/PerCheckTests.cs deleted file mode 100644 index 6602c34b..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/PerCheckTests.cs +++ /dev/null @@ -1,492 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; -using Probes.Shapes; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// Runs rows through the probe corpus's own harness (harness/Row.cs, compiled in) and reads the lines it writes. -internal static class HarnessRun -{ - /// - /// Runs one row of axes x and y through Rec.Run, writing to : the exception the - /// test ends with (a failure or a skip), if any, and the line the harness wrote for the row. - /// - public static (Exception? Ended, JsonObject Line) Row(string outDir, int idx, Func> check, string x = "1", string y = "1") - { - var previous = Environment.GetEnvironmentVariable("PROBE_OUT"); - Environment.SetEnvironmentVariable("PROBE_OUT", outDir); - Exception? ended = null; - try { Rec.Run("C1", new Row(idx, new Dictionary { ["x"] = x, ["y"] = y }), check).GetAwaiter().GetResult(); } - catch (Exception e) { ended = e; } - finally { Environment.SetEnvironmentVariable("PROBE_OUT", previous); } - var line = File.ReadAllLines(Path.Combine(outDir, "C1.jsonl")).Select(l => JsonNode.Parse(l)!.AsObject()).Last(l => (int)Files.Num(l["idx"]) == idx); - return (ended, line); - } - - public static JsonObject Check(JsonObject line, string obligation) => - line["checks"]!.AsArray().OfType().Single(c => Files.Str(c["obligation"]) == obligation); -} - -/// -/// A check of a row (Row.Check) has one obligation, one baseline, and reads, notes and an outcome of its own: a -/// failure it returns is a violation, an exception a harness error that the other checks of the row survive, and a -/// pass with no baseline a harness error. The row passes when no check failed and one passed, and is skipped, each -/// check's outcome listed, when none passed. -/// -[Collection(nameof(ProbeOut))] -public sealed class CheckHarnessTests : IDisposable -{ - private readonly string outDir = Path.Combine(Path.GetTempPath(), "prober-tests", Guid.NewGuid().ToString("N")); - - public void Dispose() - { - try { Directory.Delete(outDir, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - [Fact] - public void A_failure_a_check_returns_is_its_violation_with_its_own_reads() - { - string? returned = "not run"; - var (ended, line) = HarnessRun.Row(outDir, 0, async r => - { - _ = r["x"]; - returned = await r.Check("keys", Baseline.Twin, c => Task.FromResult(c["y"] == "1" ? "the key differs" : null)); - return returned; - }); - returned.ShouldBe("the key differs", "Check returns the failure, so a probe can stop the row at it"); - ended.ShouldNotBeNull().Message.ShouldContain("keys violation: the key differs"); - Files.Str(line["category"]).ShouldBe("violation"); - Files.StringMap(line["applied"]).ShouldBe(new Dictionary { ["x"] = "1" }, "the row's own reads are those outside any check"); - Files.Strings(line["reasons"]).ShouldBeEmpty("the failure is the check's, not the row's own"); - var check = HarnessRun.Check(line, "keys"); - Files.Str(check["baseline"]).ShouldBe("twin"); - Files.Str(check["category"]).ShouldBe("violation"); - Files.StringMap(check["applied"]).ShouldBe(new Dictionary { ["y"] = "1" }); - Files.Strings(check["reasons"]).ShouldBe(["violation:the key differs"]); - } - - [Fact] - public void An_exception_in_a_check_is_a_harness_error_the_other_checks_survive() - { - string? returned = "not run"; - var (ended, line) = HarnessRun.Row(outDir, 0, async r => - { - returned = await r.Check("keys", Baseline.Twin, (Func>)(_ => throw new InvalidOperationException("the check broke"))); - return r.Check("nulls", Baseline.RoundTrip, c => c.Is("x", "1") ? null : "never"); - }); - returned.ShouldBeNull("an exception never reads as a failure, so a probe returning it makes no violation"); - ended.ShouldNotBeNull().Message.ShouldContain("keys harness-error: UNEXPECTED InvalidOperationException: the check broke"); - Files.Str(line["category"]).ShouldBe("harness-error"); - Files.Str(HarnessRun.Check(line, "keys")["category"]).ShouldBe("harness-error"); - Files.Str(HarnessRun.Check(line, "nulls")["category"]).ShouldBe("pass", "the next check of the row still ran"); - } - - [Fact] - public void The_synchronous_form_keeps_an_exception_from_the_row_too() - { - var (ended, line) = HarnessRun.Row(outDir, 0, r => - { - var returned = r.Check("keys", Baseline.Twin, (Func)(_ => throw new FormatException("bad"))); - return Task.FromResult(returned); - }); - ended.ShouldNotBeNull().Message.ShouldContain("keys harness-error: UNEXPECTED FormatException: bad"); - Files.Strings(line["reasons"]).ShouldBeEmpty("the exception stayed in the check"); - } - - [Fact] - public void A_pass_without_a_baseline_is_a_harness_error() - { - var (ended, line) = HarnessRun.Row(outDir, 0, r => Task.FromResult(r.Check("keys", null, c => c.Is("x", "1") ? null : "differs"))); - ended.ShouldNotBeNull().Message.ShouldContain("keys harness-error: pass-without-baseline"); - Files.Str(HarnessRun.Check(line, "keys")["category"]).ShouldBe("harness-error"); - HarnessRun.Check(line, "keys")["baseline"].ShouldBeNull(); - } - - [Fact] - public void A_row_with_a_passing_check_and_one_that_did_not_apply_passes() - { - var (ended, line) = HarnessRun.Row(outDir, 0, r => - { - r.Check("keys", Baseline.Twin, c => c.Is("x", "1") ? null : "differs"); - r.Check("nulls", Baseline.Twin, c => c.Inapplicable(Cite.NotPromised("closed-set-has-no-null"), "x=1")); - return Task.FromResult(null); - }); - ended.ShouldBeNull("one check compared and passed; the other did not apply, which voids nothing"); - Files.Str(line["status"]).ShouldBe("pass"); - Files.Str(line["category"]).ShouldBe("inapplicable", "the row's category is the highest of its checks'"); - Files.Strings(HarnessRun.Check(line, "nulls")["reasons"]).ShouldBe(["inapplicable:not-promised:closed-set-has-no-null(x=1)"]); - Files.Str(HarnessRun.Check(line, "nulls")["notes"]).ShouldBe("not-promised:closed-set-has-no-null(x=1)"); - } - - [Fact] - public void A_row_where_no_check_passed_is_skipped_listing_each_check() - { - var (ended, line) = HarnessRun.Row(outDir, 0, r => - { - r.Check("smallest-scale", Baseline.Twin, c => c.Inapplicable(Cite.NotPromised("closed-set-has-no-scale"))); - r.Check("number-is-a-number", Baseline.Fact("KB-031"), c => c.Refused(Cite.Fact("KB-031"))); - r.Check("reads-a-number", Baseline.Model, c => c.Inconclusive("both threw, not alike")); - r.Check("covers", Baseline.Docs("docs/json.md#decimals-in-one-spelling"), c => c.Refused(Cite.Docs("docs/json.md#decimals-in-one-spelling"))); - r.Check("keeps", Baseline.Cost, c => c.Inapplicable(Cite.Record("0094"))); - return Task.FromResult(null); - }); - ended.ShouldNotBeNull().GetType().Name.ShouldBe("SkipException"); - ended.Message.ShouldContain("smallest-scale inapplicable: not-promised:closed-set-has-no-scale; number-is-a-number expected-refusal: fact:KB-031; " + - "reads-a-number inconclusive: both threw, not alike; covers expected-refusal: docs:docs/json.md#decimals-in-one-spelling; " + - "keeps inapplicable: record:0094"); - Files.Str(line["status"]).ShouldBe("fail"); - Files.Str(line["category"]).ShouldBe("inconclusive"); - line["checks"]!.AsArray().Select(c => Files.Str(c!["baseline"])).ShouldBe(["twin", "fact:KB-031", "model", "docs:docs/json.md#decimals-in-one-spelling", "cost"]); - } - - [Fact] - public void A_violation_fails_the_row_even_beside_a_passing_check() - { - var (ended, line) = HarnessRun.Row(outDir, 0, r => - { - r.Check("keys", Baseline.Twin, _ => (string?)null); - r.Check("nulls", Baseline.Twin, _ => "a null was written"); - return Task.FromResult(null); - }); - ended.ShouldNotBeNull().GetType().Name.ShouldNotBe("SkipException"); - ended.Message.ShouldContain("nulls violation: a null was written"); - ended.Message.ShouldNotContain("keys pass"); - Files.Str(line["status"]).ShouldBe("fail"); - } - - [Fact] - public void A_row_that_runs_no_check_is_written_as_before() - { - var (ended, line) = HarnessRun.Row(outDir, 0, r => Task.FromResult(r["x"] == "1" ? null : "differs")); - ended.ShouldBeNull(); - line.ContainsKey("checks").ShouldBeFalse(); - line.Select(kv => kv.Key).ShouldBe(["idx", "status", "category", "completed", "applied", "reasons", "findings", "note"]); - } - - [Fact] - public void Reads_notes_and_substitutions_through_the_row_inside_a_check_are_the_checks() - { - var (ended, line) = HarnessRun.Row(outDir, 0, async r => - { - await r.Check("keys", Baseline.Twin, async c => - { - await Task.Yield(); - _ = r["y"]; // a helper handed the row, inside the check - _ = r.Get("x"); - r.Substituted("x", "2", "the options ran as x=2"); - r.Note(NoteKeys.Compared, "write"); - return null; - }); - return null; - }); - ended.ShouldBeNull(); - Files.StringMap(line["applied"]).ShouldBeEmpty("the row read nothing outside the check"); - Files.Str(line["note"]).ShouldBeEmpty(); - var check = HarnessRun.Check(line, "keys"); - Files.StringMap(check["applied"]).OrderBy(kv => kv.Key, StringComparer.Ordinal).Select(kv => $"{kv.Key}={kv.Value}").ShouldBe(["x=2", "y=1"]); - Files.Str(check["notes"]).ShouldBe("substituted(x=2, the options ran as x=2);compared(write)"); - } - - [Fact] - public void A_malformed_citation_or_baseline_is_refused_at_construction() - { - Should.Throw(() => Cite.Fact("KB-31")); - Should.Throw(() => Cite.Record("94")); - Should.Throw(() => Cite.NotPromised("Closed set")); - Should.Throw(() => Cite.Docs("README.md#What TypeKit guarantees")); - Should.Throw(() => Cite.Docs("../outside.md")); - Should.Throw(() => Baseline.Fact("fact:KB-031")); - Should.Throw(() => Baseline.Docs("#anchor-alone")); - new[] { Baseline.Twin, Baseline.Framework, Baseline.RoundTrip, Baseline.Model, Baseline.Refusal, Baseline.Cost, Baseline.Fact("KB-031"), Baseline.Docs("README.md") } - .Select(b => b.Spelling).ShouldBe(["twin", "framework", "round-trip", "model", "refusal", "cost", "fact:KB-031", "docs:README.md"]); - new[] { Cite.NotPromised("a-b"), Cite.Docs("CHANGELOG.md#2.1.0-fixed"), Cite.Fact("KB-001"), Cite.Record("0094") } - .Select(c => c.Spelling).ShouldBe(["not-promised:a-b", "docs:CHANGELOG.md#2.1.0-fixed", "fact:KB-001", "record:0094"]); - - var (ended, line) = HarnessRun.Row(outDir, 0, r => Task.FromResult(r.Check("keys", Baseline.Twin, c => c.Refused(Cite.Fact("KB-31"))))); - ended.ShouldNotBeNull().Message.ShouldContain("keys harness-error: UNEXPECTED ArgumentException:"); - Files.Str(HarnessRun.Check(line, "keys")["category"]).ShouldBe("harness-error"); - } -} - -/// -/// The ledger credits checks, not rows: a passing check earns the pairs of the settings it ran under (the row's, its -/// own laid over them) whatever another check of the row ended as, never a pair put together from two checks' reads, -/// and `status` says per obligation what current checks earned and which no passing check named. The evidence is the -/// harness's own lines, copied as the replay copies them. -/// -[Collection(nameof(ProbeOut))] -public sealed class CheckLedgerTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - /// Runs P's two rows (x=1 y=1, x=2 y=2) through the harness and records the run as the replay would. - private JsonObject Record(Func> check) - { - var outDir = Path.Combine(fx.Root, "rows-out"); - var rows = new JsonObject(); - foreach (var (idx, v) in new[] { (0, "1"), (1, "2") }) - rows[idx.ToString(System.Globalization.CultureInfo.InvariantCulture)] = Replay.EvidenceRow(HarnessRun.Row(outDir, idx, check, v, v).Line); - var path = Path.Combine(fx.Root, "evidence.json"); - File.WriteAllText(path, new JsonObject - { - ["variants"] = new JsonArray(new JsonObject { ["env"] = new JsonObject(), ["expected"] = new JsonArray(0, 1), ["executed"] = new JsonArray(0, 1) }), - ["rows"] = rows, - }.ToJsonString()); - fx.Footprint(); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", path).Exit.ShouldBe(0); - return JsonNode.Parse(File.ReadAllText(Path.Combine(fx.BranchDir, "evidence", "P.json")))!.AsObject(); - } - - private void Obligations() - { - fx.Write("README.md", "# a\n\nThe claim.\n\nA key is written as the wrapped type writes it.\n\nA null is refused.\n"); - fx.Write("tools/probe/corpus/claims.json", """ - [{"id": "C1", "source": "README.md#a", "surfaces": ["s"], "obligations": [ - {"id": "keys", "sentence": "A key is written as the wrapped type writes it."}, - {"id": "nulls", "sentence": "A null is refused."}]}] - """); - fx.Commit("obligations"); - fx.Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - } - - private JsonObject Status() - { - var (exit, output, error) = fx.Ledger("status", "--json"); - exit.ShouldBe(0, error); - return JsonNode.Parse(output)!["claims"]!["C1"]!.AsObject(); - } - - [Fact] - public void A_passing_check_earns_its_pairs_beside_a_check_that_did_not_apply() - { - var evidence = Record(r => - { - r.Check("keys", Baseline.Twin, c => c["x"] == c["y"] ? null : "differs"); - r.Check("nulls", Baseline.Twin, c => c.Inapplicable(Cite.NotPromised("no-null-here"))); - return Task.FromResult(null); - }); - Files.Num(evidence["schemaVersion"]).ShouldBe(2); - fx.Covered().ShouldBe(2, "x1y1 and x2y2, each read by the passing check, though every row ended inapplicable"); - } - - [Fact] - public void A_pair_is_never_put_together_from_two_checks_reads() - { - Record(r => - { - r.Check("keys", Baseline.Twin, c => c["x"] is not null ? null : "never"); - if (r.Index == 0) r.Check("nulls", Baseline.Twin, c => c["y"] is not null ? null : "never"); - else r.Check("nulls", Baseline.Twin, c => c["x"] is not null && c["y"] is not null ? null : "never"); - return Task.FromResult(null); - }); - fx.Covered().ShouldBe(1, "row 0's checks read x and y apart, which credits no pair; row 1's second check read both"); - } - - [Fact] - public void The_rows_own_reads_are_what_every_check_ran_under() - { - Record(r => - { - _ = r["x"]; - r.Check("keys", Baseline.Twin, c => c["y"] is not null ? null : "never"); - return Task.FromResult(null); - }); - fx.Covered().ShouldBe(2); - } - - [Fact] - public void A_row_without_checks_is_one_check_of_the_claim() - { - Record(r => Task.FromResult(r["x"] == r["y"] ? null : "differs")); - fx.Covered().ShouldBe(2); - var obligation = Status()["obligations"]!.AsArray().ShouldHaveSingleItem()!; - Files.Str(obligation["id"]).ShouldBe("claim"); - Files.Num(obligation["current"]).ShouldBe(2); - } - - [Fact] - public void Status_gives_each_obligation_its_current_pairs_and_counts_those_no_passing_check_named() - { - Obligations(); - Record(r => - { - r.Check("keys", Baseline.Twin, c => c["x"] == c["y"] ? null : "differs"); - r.Check("nulls", Baseline.Twin, c => c.Inapplicable(Cite.NotPromised("no-null-here"))); - return Task.FromResult(null); - }); - var claim = Status(); - claim["obligations"]!.AsArray().Select(o => $"{Files.Str(o!["id"])} {Files.Num(o["current"])} {o["passed"]!.GetValue()}").ShouldBe(["keys 2 True", "nulls 0 False"]); - claim["check_outcomes"]!.AsObject().Select(kv => $"{kv.Key} {Files.Num(kv.Value)}").ShouldBe(["inapplicable 2", "pass 2"]); - claim["outcomes"]!.AsObject().Select(kv => $"{kv.Key} {Files.Num(kv.Value)}").ShouldBe(["inapplicable 2"]); - fx.Ledger("status").Out.ReplaceLineEndings("\n") - .ShouldContain("\n C1: 2/4 (rows: inapplicable 2; checks: inapplicable 2, pass 2) obligations 2 (2 without a seed: keys, nulls), 1 uncredited\n"); - } - - [Fact] - public void The_replay_keeps_each_checks_fields_and_six_reasons() - { - var line = JsonNode.Parse(""" - {"idx": 0, "category": "inapplicable", "applied": {"x": "1"}, "reasons": [], "findings": [], "note": "", - "checks": [{"obligation": "keys", "baseline": "twin", "category": "inapplicable", "applied": {"y": "1"}, - "reasons": ["inapplicable:1", "inapplicable:2", "inapplicable:3", "inapplicable:4", "inapplicable:5", "inapplicable:6", "inapplicable:7"], "notes": "n"}, - {"obligation": "nulls", "baseline": null, "category": "harness-error", "applied": {}, "reasons": [], "notes": ""}]} - """)!.AsObject(); - var row = Replay.EvidenceRow(line); - var checks = row["checks"]!.AsArray(); - checks.Count.ShouldBe(2); - Files.Str(checks[0]!["obligation"]).ShouldBe("keys"); - Files.Str(checks[0]!["baseline"]).ShouldBe("twin"); - Files.StringMap(checks[0]!["applied"]).ShouldBe(new Dictionary { ["y"] = "1" }); - Files.Strings(checks[0]!["reasons"]).Count().ShouldBe(6); - Files.Str(checks[0]!["notes"]).ShouldBe("n"); - checks[1]!["baseline"].ShouldBeNull(); - Replay.EvidenceRow(JsonNode.Parse("""{"idx": 0, "category": "pass", "applied": {}}""")!.AsObject()).ContainsKey("checks").ShouldBeFalse(); - } -} - -/// -/// `seeds` judges a seed by the checks it fires: a seed naming obligation O is caught only by a clean violation of a -/// check naming O, in a row whose unseeded run had no violation of O; a seed naming none by any check. P's rows run a -/// check of each obligation through the real harness; SEED names the check the seeded build breaks. -/// -[Collection(nameof(ProbeOut))] -public sealed class CheckSeedsTests : IDisposable -{ - private readonly Fixture fx = new(); - private readonly string cache; - - public CheckSeedsTests() - { - cache = fx.Root + "-cache"; - fx.Sh("git", "config", "core.autocrlf", "false"); - fx.Write("README.md", "# a\n\nThe claim.\n\nA key is written as the wrapped type writes it.\n\nA null is refused.\n"); - fx.Write("tools/probe/corpus/claims.json", """ - [{"id": "C1", "source": "README.md#a", "surfaces": ["s"], "obligations": [ - {"id": "keys", "sentence": "A key is written as the wrapped type writes it."}, - {"id": "nulls", "sentence": "A null is refused."}]}] - """); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src") }, - }.ToJsonString() + "\n```\n"); - fx.Commit("obligations and the replay configuration"); - } - - public void Dispose() - { - fx.Dispose(); - try { Directory.Delete(cache, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - /// Registers P with one seed per (obligation, SEED value): the seed names the obligation, and its build breaks the check SEED names. - private void Register(params (string? Obligation, string Breaks)[] seeds) - { - fx.Write("tools/probe/corpus/registry.json", new JsonObject - { - ["probes"] = new JsonObject - { - ["P"] = new JsonObject - { - ["claim"] = "C1", ["filter"] = "*P", - ["seeds"] = new JsonArray([.. seeds.Select(s => (JsonNode)new JsonObject - { - ["obligation"] = s.Obligation, ["env"] = new JsonObject { ["SEED"] = s.Breaks }, ["defect"] = $"{s.Breaks} breaks.", - })]), - }, - }, - }.ToJsonString()); - fx.Commit("register"); - } - - private (int Exit, string Out) Seeds(HarnessAdapter adapter) - { - var output = new StringWriter(); - var context = new Context(fx.Root, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, output, output); - int exit; - try { exit = global::Prober.Seeds.Run(context, new Args([], new HashSet(StringComparer.Ordinal)), adapter); } - catch (Refusal refusal) { output.WriteLine(refusal.Message); exit = refusal.ExitCode; } - return (exit, output.ToString().ReplaceLineEndings("\n")); - } - - /// Row 1 runs a check of keys and one of nulls; the one SEED names fails. fails a check of row 1 without a seed. - private static Func> TwoChecks(string? unseeded = null) => (r, seed) => - { - foreach (var obligation in new[] { "keys", "nulls" }) - r.Check(obligation, Baseline.Twin, _ => r.Index == 1 && (seed == obligation || unseeded == obligation) ? $"{obligation} broke" : null); - return Task.FromResult(null); - }; - - [Fact] - public void A_seed_naming_an_obligation_is_caught_only_by_a_check_naming_it() - { - Register(("keys", "nulls"), ("nulls", "nulls")); - var (exit, output) = Seeds(new HarnessAdapter(TwoChecks())); - exit.ShouldBe(1, output); - output.ShouldContain("\n P/keys (C1): missed, no row violates that did not already (2 rows: pass 1, violation 1; 1 violate by a check naming nulls, not keys;"); - output.ShouldContain("\n P/nulls (C1): caught, 1 of 2 rows violate; e.g. #1 nulls: violation:nulls broke\n"); - } - - [Fact] - public void The_baseline_is_per_row_and_obligation() - { - Register(("keys", "keys")); - var (exit, output) = Seeds(new HarnessAdapter(TwoChecks(unseeded: "nulls"))); - exit.ShouldBe(0, output); - output.ShouldContain("\n P/keys (C1): caught, 1 of 2 rows violate; e.g. #1 keys: violation:keys broke\n", - Case.Sensitive, "row 1 violated nulls unseeded, which takes nothing from a violation of keys there"); - } - - [Fact] - public void A_seed_naming_none_is_caught_by_any_check() - { - Register((null, "nulls")); - var (exit, output) = Seeds(new HarnessAdapter(TwoChecks())); - exit.ShouldBe(0, output); - output.ShouldContain("\n P (C1): caught, 1 of 2 rows violate; e.g. #1 nulls: violation:nulls broke\n"); - } - - [Fact] - public void A_harness_error_of_the_row_outside_its_checks_makes_no_check_a_catch() - { - Register(("keys", "keys")); - var (exit, output) = Seeds(new HarnessAdapter((r, seed) => - { - if (seed is not null && r.Index == 1) r.Outcome("harness-error", "the host did not start"); - return TwoChecks()(r, seed); - })); - exit.ShouldBe(1, output); - output.ShouldContain("\n P/keys (C1): missed, no row violates that did not already (2 rows: pass 1, violation 1; 1 ended in a harness error, which is no catch;"); - } - - [Fact] - public void A_row_without_checks_catches_no_seed_naming_an_obligation() - { - Register(("keys", "keys")); - var (exit, output) = Seeds(new HarnessAdapter((r, seed) => Task.FromResult(seed is not null && r.Index == 1 ? "row 1 broke" : null))); - exit.ShouldBe(1, output); - output.ShouldContain("1 violate by a check naming claim, not keys;"); - } - - /// The probe P over two rows, each run through the real harness with the value of SEED (null unseeded). - private sealed class HarnessAdapter(Func> check) : IProbeAdapter - { - public Ran Build(string worktree, IReadOnlyDictionary environment) => new(0, "Build: OK", ""); - - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - var seed = environment.GetValueOrDefault("SEED"); - var outDir = environment["PROBE_OUT"]!; - var failed = false; - for (var idx = 0; idx < 2; idx++) - failed |= HarnessRun.Row(outDir, idx, r => check(r, seed)).Ended is not null; - return new Ran(failed ? 1 : 0, "", ""); - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) => (null, "none"); - - public IReadOnlyDictionary Environment(string cacheDirectory) => new Dictionary(); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/RegisterTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/RegisterTests.cs deleted file mode 100644 index a8e95229..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/RegisterTests.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// `register --obligation O` writes a seed per obligation (decision 104) into the entry's `seeds`, in place of -/// any seed that names O already, and refuses an O the claim does not list; `new` prints that command for each -/// listed obligation, so no seed is written into the registry by hand. C1 lists keys and nulls; C7 lists none. -/// -public sealed class RegisterTests : IDisposable -{ - private readonly Fixture fx = new(); - - public RegisterTests() - { - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src"), ["families"] = new JsonObject { ["f"] = new JsonArray("s") } }, - }.ToJsonString() + "\n```\n"); - fx.Write("tools/probe/corpus/claims.json", new JsonArray( - new JsonObject - { - ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["obligations"] = new JsonArray( - new JsonObject { ["id"] = "keys", ["sentence"] = "The claim." }, - new JsonObject { ["id"] = "nulls", ["sentence"] = "The claim." }), - }, - new JsonObject { ["id"] = "C7", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s") }).ToJsonString()); - fx.Commit("claims with obligations"); - fx.Ledger("universe", "--base", "HEAD").Exit.ShouldBe(0); - } - - public void Dispose() => fx.Dispose(); - - private string StagedRegistry => Path.Combine(fx.BranchDir, "staging", "registry.json"); - - private JsonObject Entry(string probe = "P") => JsonNode.Parse(File.ReadAllText(StagedRegistry))!["probes"]![probe]!.AsObject(); - - private (int Exit, string Out, string Err) Register(params string[] more) => - fx.Ledger(["register", "--probe", "P", "--claim", "C1", "--filter", "*P", .. more]); - - private static string Seeds(JsonObject entry) => - string.Join("; ", entry["seeds"]!.AsArray().Select(s => $"{s!["obligation"]}={s["patch"]}:{s["defect"]}")); - - [Fact] - public void An_obligation_s_seed_goes_into_seeds() - { - var (exit, output, error) = Register("--obligation", "keys", "--seed", "seeds/C1-keys.patch", "--defect", "A key is written with ToString()."); - exit.ShouldBe(0, output + error); - var entry = Entry(); - entry["seeds"]!.ToJsonString().ShouldBe("""[{"obligation":"keys","patch":"seeds/C1-keys.patch","defect":"A key is written with ToString()."}]"""); - entry.ContainsKey("seed").ShouldBeFalse("a seed naming an obligation is not the probe's one `seed`"); - output.ShouldContain("seed for obligation keys of P"); - } - - [Fact] - public void A_seed_for_an_obligation_that_has_one_replaces_it() - { - Register("--obligation", "keys", "--seed", "seeds/C1-keys.patch", "--defect", "first").Exit.ShouldBe(0); - Register("--obligation", "nulls", "--seed", "seeds/C1-nulls.patch", "--defect", "nulls").Exit.ShouldBe(0); - var (exit, output, _) = Register("--obligation", "keys", "--seed", "seeds/C1-keys-2.patch", "--defect", "second"); - exit.ShouldBe(0); - output.ShouldContain("seed for obligation keys of P, in place of the 1 it had"); - Seeds(Entry()).ShouldBe("nulls=seeds/C1-nulls.patch:nulls; keys=seeds/C1-keys-2.patch:second"); - } - - [Fact] - public void The_one_seed_naming_the_obligation_is_replaced_and_one_naming_another_kept() - { - fx.Write("tools/probe/corpus/registry.json", """ - {"probes": { - "P": {"claim": "C1", "filter": "*P", "seed": {"patch": "seeds/C1.patch", "defect": "old", "obligation": "keys"}}, - "Q": {"claim": "C1", "filter": "*Q", "seed": {"patch": "seeds/C1-q.patch", "defect": "kept", "obligation": "nulls"}}}} - """); - fx.Commit("probes whose one seed names an obligation"); - - Register("--obligation", "keys", "--seed", "seeds/C1-keys.patch", "--defect", "new").Exit.ShouldBe(0); - Entry().ContainsKey("seed").ShouldBeFalse("the seed that named keys is replaced, not kept beside the new one"); - Seeds(Entry()).ShouldBe("keys=seeds/C1-keys.patch:new"); - - fx.Ledger("register", "--probe", "Q", "--claim", "C1", "--filter", "*Q", "--obligation", "keys", "--seed", "seeds/C1-qk.patch", "--defect", "q").Exit.ShouldBe(0); - Entry("Q")["seed"]!["obligation"]!.GetValue().ShouldBe("nulls"); - Seeds(Entry("Q")).ShouldBe("keys=seeds/C1-qk.patch:q"); - } - - [Theory] - [InlineData("C1", "kyes", "claim C1 lists no obligation kyes (it lists keys, nulls)")] - [InlineData("C1", "claim", "claim C1 lists no obligation claim (it lists keys, nulls)")] - [InlineData("C7", "keys", "claim C7 lists no obligation keys (it lists claim)")] - public void An_obligation_the_claim_does_not_list_is_refused_and_nothing_staged(string claim, string obligation, string message) - { - var (exit, _, error) = fx.Ledger("register", "--probe", "P", "--claim", claim, "--filter", "*P", "--obligation", obligation, "--seed", "seeds/x.patch", "--defect", "d"); - exit.ShouldBe(2); - error.ShouldContain(message); - File.Exists(StagedRegistry).ShouldBeFalse(); - } - - [Fact] - public void A_claim_without_obligations_takes_a_seed_for_its_one() - { - fx.Ledger("register", "--probe", "P", "--claim", "C7", "--filter", "*P", "--obligation", "claim", "--seed", "seeds/C7.patch", "--defect", "d").Exit.ShouldBe(0); - Seeds(Entry()).ShouldBe("claim=seeds/C7.patch:d"); - } - - [Fact] - public void A_claim_that_is_not_in_the_claims_is_refused() - { - var (exit, _, error) = fx.Ledger("register", "--probe", "P", "--claim", "C9", "--filter", "*P", "--obligation", "keys", "--seed", "seeds/x.patch", "--defect", "d"); - exit.ShouldBe(1); - error.ShouldContain("no claim C9 in claims.json"); - File.Exists(StagedRegistry).ShouldBeFalse(); - } - - [Fact] - public void An_obligation_without_a_seed_or_a_defect_is_refused() - { - var (exit, _, error) = Register("--obligation", "keys", "--defect", "d"); - exit.ShouldBe(2); - error.ShouldContain("give the seed with --seed PATCH or --seed-env NAME=VALUE"); - Register("--obligation", "keys", "--seed", "seeds/C1-keys.patch").Exit.ShouldBe(2, "a seed without its defect"); - File.Exists(StagedRegistry).ShouldBeFalse(); - } - - [Fact] - public void An_environment_toggle_is_a_seed_too() - { - Register("--obligation", "nulls", "--seed-env", "A=1", "B=x=y", "--defect", "d").Exit.ShouldBe(0); - Entry()["seeds"]!.ToJsonString().ShouldBe("""[{"obligation":"nulls","env":{"A":"1","B":"x=y"},"defect":"d"}]"""); - Register("--seed-env", "C=2", "--defect", "one").Exit.ShouldBe(0); - Entry()["seed"]!.ToJsonString().ShouldBe("""{"env":{"C":"2"},"defect":"one"}"""); - Register("--obligation", "nulls", "--seed-env", "=1", "--defect", "d").Exit.ShouldBe(2, "a toggle without a name"); - } - - [Fact] - public void A_seed_stales_no_result() - { - var before = new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null).Identity("P"); - Register("--obligation", "keys", "--seed", "seeds/C1-keys.patch", "--defect", "d").Exit.ShouldBe(0); - Register("--seed", "seeds/C1.patch", "--defect", "d").Exit.ShouldBe(0); - Entry().ContainsKey("seeds").ShouldBeTrue(); - new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null).Identity("P").ShouldBe(before); - } - - [Fact] - public void The_commands_new_prints_register_each_obligation_s_seed() - { - var (exit, output, _) = fx.Ledger("new", "--claim", "C1", "--probe", "C1KeysProbe"); - exit.ShouldBe(0); - var commands = Regex.Matches(output, @"`prober (register [^`]*)`").Select(m => m.Groups[1].Value).ToList(); - commands.Count.ShouldBe(2, output); - output.ShouldNotContain("in the entry's `seeds`"); - foreach (var command in commands) - { - var args = Regex.Matches(command, @"""([^""]*)""|(\S+)").Select(m => m.Groups[1].Success ? m.Groups[1].Value : m.Groups[2].Value) - .Select(arg => arg == "..." ? "What the seed breaks." : arg).ToArray(); - var (registered, said, error) = fx.Ledger(args); - registered.ShouldBe(0, command + ": " + said + error); - } - - var entry = Entry("C1KeysProbe"); - entry["filter"]!.GetValue().ShouldBe("*C1KeysProbe"); - Seeds(entry).ShouldBe("keys=seeds/C1-keys.patch:What the seed breaks.; nulls=seeds/C1-nulls.patch:What the seed breaks."); - var problems = global::Prober.Seeds.Problems(new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null)); - problems.ShouldNotContain(p => p.StartsWith("C1KeysProbe: no seed", StringComparison.Ordinal)); - problems.ShouldNotContain(p => p.StartsWith("C1: obligation", StringComparison.Ordinal)); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/ReplayTemplateTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/ReplayTemplateTests.cs deleted file mode 100644 index 6c0b723b..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/ReplayTemplateTests.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// The replay's templates name only what the repository has. A tool that moves (a script ported to a tool -/// project) must not leave the replay starting a file that is gone: that fails only on the next replay, far -/// from the commit that caused it. -/// -public sealed class ReplayTemplateTests -{ - private static string RepositoryRoot() - { - for (var dir = new DirectoryInfo(AppContext.BaseDirectory); dir is not null; dir = dir.Parent) - if (File.Exists(Path.Combine(dir.FullName, "CodoMetis.TypeKit.slnx"))) return dir.FullName; - throw new InvalidOperationException("no CodoMetis.TypeKit.slnx above the test output"); - } - - /// - /// Every path a template names: a file must be tracked in the repository; a dll under a project's bin/ must - /// come from a project there that a "prepare" command builds (a fresh worktree has no build output). - /// - internal static List Problems(string root, JsonObject replay) - { - var problems = new List(); - var prepared = (replay["prepare"] as JsonArray ?? []).OfType() - .SelectMany(c => c.Select(a => a?.GetValue() ?? "")).ToHashSet(StringComparer.Ordinal); - var templates = new List<(string Name, IEnumerable Args)>(); - foreach (var name in new[] { "build", "test" }) - templates.Add((name, (replay[name] as JsonArray ?? []).Select(a => a?.GetValue() ?? ""))); - foreach (var (i, command) in (replay["prepare"] as JsonArray ?? []).OfType().Index()) - templates.Add(($"prepare[{i}]", command.Select(a => a?.GetValue() ?? ""))); - if (replay["enumerate"]?["script"]?.GetValue() is { } script) templates.Add(("enumerate", [script])); - - foreach (var (name, args) in templates) - foreach (var arg in args.Where(a => a.Contains('/') && !a.Contains('{'))) - { - var bin = arg.IndexOf("/bin/", StringComparison.Ordinal); - if (bin >= 0) - { - var project = arg[..bin]; - if (!Directory.Exists(Path.Combine(root, project)) || !Directory.EnumerateFiles(Path.Combine(root, project), "*.csproj").Any()) - problems.Add($"{name}: {arg} comes from {project}, which is no project in the repository"); - else if (!prepared.Contains(project)) - problems.Add($"{name}: {arg} is build output of {project}, which no \"prepare\" command builds"); - } - else if (!File.Exists(Path.Combine(root, arg)) && !Directory.Exists(Path.Combine(root, arg))) - problems.Add($"{name}: {arg} is not in the repository"); - } - return problems; - } - - private static JsonObject RepositoryReplay(string root) => - Axes.Block(Path.Combine(root, ".claude", "probe-axes.md"))["replay"] as JsonObject ?? throw new InvalidOperationException("no replay object"); - - [Fact] - public void The_replay_templates_name_only_what_the_repository_has() - { - var root = RepositoryRoot(); - Problems(root, RepositoryReplay(root)).ShouldBeEmpty(); - } - - [Fact] - public void A_template_naming_a_removed_script_is_caught() - { - // The seed: the templates as they were before the verdict script became a tool project. - var root = RepositoryRoot(); - var replay = (JsonObject)RepositoryReplay(root).DeepClone(); - replay["build"] = new JsonArray("tools/build-verdict.sh", "build", "{project}"); - Problems(root, replay).ShouldContain(p => p.Contains("tools/build-verdict.sh is not in the repository", StringComparison.Ordinal)); - } - - [Fact] - public void A_tool_dll_no_prepare_command_builds_is_caught() - { - var root = RepositoryRoot(); - var replay = (JsonObject)RepositoryReplay(root).DeepClone(); - replay.Remove("prepare"); - Problems(root, replay).ShouldContain(p => p.Contains("which no \"prepare\" command builds", StringComparison.Ordinal)); - } - - [Fact] - public void A_bare_command_is_found_on_PATH_and_a_path_must_exist_in_the_worktree() - { - var worktree = Path.Combine(Path.GetTempPath(), "prober-exe-" + Guid.NewGuid().ToString("N")); - Directory.CreateDirectory(Path.Combine(worktree, "tools")); - try - { - DotNetAdapter.Executable(worktree, "dotnet").ShouldBe("dotnet"); - File.WriteAllText(Path.Combine(worktree, "tools", "run.sh"), ""); - DotNetAdapter.Executable(worktree, "tools/run.sh").ShouldBe(Path.Combine(worktree, "tools/run.sh")); - Should.Throw(() => DotNetAdapter.Executable(worktree, "tools/build-verdict.sh")) - .Message.ShouldContain("tools/build-verdict.sh"); - } - finally { Directory.Delete(worktree, recursive: true); } - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/ReplayTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/ReplayTests.cs deleted file mode 100644 index b4502eec..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/ReplayTests.cs +++ /dev/null @@ -1,368 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// The replay runs probes in parallel, by family, with or without a footprint, and `merge` joins the states -/// of a replay split by family (decision 101). The probes here are a fake adapter: P covers C1 (surface s) -/// and Q covers C2 (surface t); a run writes its rows and, when asked for one, a coverage report that names -/// src/a.cs. -/// -public sealed class ReplayTests : IDisposable -{ - private readonly Fixture fx = new(); - private readonly string cache; - private readonly FakeAdapter adapter = new(); - private readonly List states = []; - - public ReplayTests() - { - cache = fx.Root + "-cache"; - fx.Sh("git", "config", "core.autocrlf", "false"); - Axes(new JsonObject { ["a"] = new JsonArray("s"), ["b"] = new JsonArray("t") }); - fx.Write("tools/probe/corpus/claims.json", """[{"id": "C1", "source": "README.md#a", "surfaces": ["s"]}, {"id": "C2", "source": "README.md#a", "surfaces": ["t"]}]"""); - fx.Write("tools/probe/corpus/registry.json", """{"probes": {"P": {"claim": "C1", "filter": "*P"}, "Q": {"claim": "C2", "filter": "*Q"}}}"""); - fx.Write("tools/probe/corpus/harness/Q.cs", "// probe Q\n"); - fx.Write("tools/probe/corpus/rows/Q.json", new JsonObject - { - ["claim"] = "C2", ["rows"] = new JsonArray(new JsonObject { ["row"] = new JsonObject { ["x"] = "1", ["y"] = "1" } }), - }.ToJsonString()); - fx.Commit("two probes of two families"); - } - - public void Dispose() - { - fx.Dispose(); - foreach (var dir in states.Append(cache)) - try { Directory.Delete(dir, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - /// The axes file with a replay configuration; its families are the given ones, or none. - private void Axes(JsonObject? families) - { - var replay = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src") }; - if (families is not null) replay["families"] = families; - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject - { - ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") }, - ["t"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") }, - }, - ["replay"] = replay, - }.ToJsonString() + "\n```\n"); - } - - /// A state directory of its own, as a leg of a matrix or the job that merges them has. - private string State(string name) - { - var dir = fx.Root + "-" + name; - states.Add(dir); - return dir; - } - - private static readonly HashSet Flags = new(StringComparer.Ordinal) { "all", "dry-run", "where", "no-footprint" }; - - private (int Exit, string Out, string Err) Replay(string? state, params string[] args) - { - var output = new StringWriter(); var error = new StringWriter(); - var env = new Dictionary { ["PROBE_CACHE_DIR"] = cache }; - if (state is not null) env["PROBE_STATE_DIR"] = state; - int exit; - try { exit = global::Prober.Replay.Run(new Context(fx.Root, env, output, error), new Args(args, Flags), adapter); } - catch (Refusal refusal) { error.WriteLine(refusal.Message); exit = refusal.ExitCode; } - return (exit, output.ToString(), error.ToString()); - } - - /// A replay in another checkout of the repository, a linked worktree, with the fake adapter. - private (int Exit, string Out, string Err) ReplayIn(string checkout, params string[] args) - { - var output = new StringWriter(); var error = new StringWriter(); - int exit; - try { exit = global::Prober.Replay.Run(new Context(checkout, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, output, error), new Args(args, Flags), adapter); } - catch (Refusal refusal) { error.WriteLine(refusal.Message); exit = refusal.ExitCode; } - return (exit, output.ToString(), error.ToString()); - } - - private string Home(string checkout) => - global::Prober.Replay.Home(new Context(checkout, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, TextWriter.Null, TextWriter.Null), - new global::Prober.Ledger(new Context(checkout, new Dictionary(), TextWriter.Null, TextWriter.Null), null)); - - private (int Exit, string Out, string Err) Ledger(string? state, params string[] args) => - state is null ? fx.Ledger(args) : fx.LedgerWith(new Dictionary { ["PROBE_STATE_DIR"] = state }, args); - - private string BranchDir(string? state) => Path.Combine(state ?? fx.Memory, "branches", "main"); - private bool HasEvidence(string? state, string probe) => File.Exists(Path.Combine(BranchDir(state), "evidence", probe + ".json")); - private JsonObject Last(string? state) => (JsonObject)JsonNode.Parse(File.ReadAllText(Path.Combine(BranchDir(state), "replay-last.json")))!; - private int Lines(string? state, string file) => - File.Exists(Path.Combine(BranchDir(state), file)) ? File.ReadAllLines(Path.Combine(BranchDir(state), file)).Count(l => l.Trim().Length > 0) : 0; - - [Fact] - public void A_family_replays_the_probes_whose_claim_surface_it_holds() - { - var (exit, output, error) = Replay(null, "--all", "--family", "a"); - exit.ShouldBe(0, error + output); - output.ShouldContain("1 of 1 probes to replay (family a)"); - HasEvidence(null, "P").ShouldBeTrue(); - HasEvidence(null, "Q").ShouldBeFalse("Q's claim is of surface t, family b"); - Files.Strings(Last(null)["selected"]).ShouldBe(["P"]); - Files.Str(Last(null)["family"]).ShouldBe("a"); - - Replay(null, "--all", "--family", "b").Exit.ShouldBe(0); - HasEvidence(null, "Q").ShouldBeTrue(); - } - - [Fact] - public void A_probe_whose_surface_is_in_no_family_refuses_the_replay() - { - Axes(new JsonObject { ["a"] = new JsonArray("s") }); - fx.Commit("family b dropped"); - var (exit, _, error) = Replay(null, "--all", "--family", "a"); - exit.ShouldBe(1, "a matrix by family would never run Q"); - error.ShouldContain("Q"); - error.ShouldContain("in no family"); - HasEvidence(null, "P").ShouldBeFalse("nothing ran"); - } - - [Fact] - public void An_unknown_family_and_a_bad_parallel_are_usage_errors() - { - Replay(null, "--all", "--family", "c").Exit.ShouldBe(2); - Replay(null, "--all", "--parallel", "0").Exit.ShouldBe(2); - Replay(null, "--all", "--parallel", "two").Exit.ShouldBe(2); - Axes(null); - fx.Commit("no families"); - var (exit, _, error) = Replay(null, "--all", "--family", "a"); - exit.ShouldBe(2); - error.ShouldContain("names no families"); - } - - [Fact] - public void A_replay_without_a_footprint_records_evidence_and_leaves_the_probes_stale() - { - var (exit, output, error) = Replay(null, "--all", "--no-footprint"); - exit.ShouldBe(0, error + output); - adapter.CoverageAsked.ShouldBeEmpty("no coverage report is asked for without a footprint"); - output.ShouldContain("footprint: not recorded (--no-footprint)"); - HasEvidence(null, "P").ShouldBeTrue(); - HasEvidence(null, "Q").ShouldBeTrue(); - Lines(null, "footprints.jsonl").ShouldBe(0); - Last(null)["footprint"]!.GetValue().ShouldBeFalse(); - Ledger(null, "stale").Out.ShouldStartWith("2 of 2 probes to replay"); - - Replay(null, "--all").Exit.ShouldBe(0); - adapter.CoverageAsked.Count.ShouldBe(2); - Lines(null, "footprints.jsonl").ShouldBe(2); - Ledger(null, "stale").Out.ShouldStartWith("0 of 2 probes to replay"); - } - - [Fact] - public void The_rows_a_probe_is_expected_to_run_are_those_of_its_own_rows_file() - { - Replay(null, "--all", "--no-footprint").Exit.ShouldBe(0); - List Expected(string probe) => - [.. JsonNode.Parse(File.ReadAllText(Path.Combine(BranchDir(null), "evidence", probe + ".json")))!["variants"]![0]!["expected"]!.AsArray().Select(i => i!.GetValue())]; - Expected("P").ShouldBe([0, 1], "rows/P.json holds two rows"); - Expected("Q").ShouldBe([0], "rows/Q.json holds one"); - } - - [Fact] - public void Probes_run_as_many_at_a_time_as_asked_without_a_footprint_and_are_recorded_in_registry_order() - { - var (exit, output, error) = Replay(null, "--all", "--no-footprint", "--parallel", "2"); - exit.ShouldBe(0, error + output); - adapter.MostAtOnce.ShouldBe(2); - output.IndexOf(" P:", StringComparison.Ordinal).ShouldBeLessThan(output.IndexOf(" Q:", StringComparison.Ordinal)); - Last(null)["parallel"]!.GetValue().ShouldBe(2); - - adapter.MostAtOnce = 0; - Replay(null, "--all", "--no-footprint", "--parallel", "1").Exit.ShouldBe(0); - adapter.MostAtOnce.ShouldBe(1); - } - - /// - /// The coverage collector rewrites the assemblies on disk, so two hosts from one output directory corrupt - /// each other (KB-025): a replay that records a footprint runs one host at a time, whatever --parallel says. - /// - [Fact] - public void A_replay_with_a_footprint_runs_one_host_at_a_time() - { - var (exit, output, error) = Replay(null, "--all", "--parallel", "2"); - exit.ShouldBe(0, error + output); - adapter.MostAtOnce.ShouldBe(1); - output.ShouldContain("one at a time (the coverage collector rewrites the assemblies on disk)"); - Last(null)["parallel"]!.GetValue().ShouldBe(1); - } - - [Fact] - public void Merge_joins_the_legs_and_refuses_a_probe_no_leg_saw() - { - var legA = State("leg-a"); var legB = State("leg-b"); var merged = State("merged"); - Replay(legA, "--all", "--family", "a").Exit.ShouldBe(0); - Replay(legB, "--all", "--family", "b").Exit.ShouldBe(0); - - var (exit, output, error) = Ledger(merged, "merge", "--from", legA, legB); - exit.ShouldBe(0, error + output); - output.ShouldContain("2 leg(s)"); - HasEvidence(merged, "P").ShouldBeTrue(); - HasEvidence(merged, "Q").ShouldBeTrue(); - Lines(merged, "runs.jsonl").ShouldBe(2); - Lines(merged, "footprints.jsonl").ShouldBe(2); - Files.Strings(Last(merged)["selected"]).ShouldBe(["P", "Q"]); - Files.Strings(Last(merged)["legs"]).ShouldBe(["a", "b"]); - Ledger(merged, "stale").Out.ShouldStartWith("0 of 2 probes to replay"); - - Ledger(merged, "merge", "--from", legA, legB).Exit.ShouldBe(0); - Lines(merged, "runs.jsonl").ShouldBe(2, "a line a leg carried is added once"); - - var (shortExit, _, shortError) = Ledger(State("short"), "merge", "--from", legA); - shortExit.ShouldBe(1, "Q was in no leg"); - shortError.ShouldContain("Q"); - - var (noneExit, _, noneError) = Ledger(State("none"), "merge", "--from", State("empty")); - noneExit.ShouldBe(1); - noneError.ShouldContain("no replay of main"); - } - - [Fact] - public void Merge_fails_when_a_leg_failed() - { - adapter.Violating.Add("C1"); - var legA = State("leg-a"); var legB = State("leg-b"); var merged = State("merged"); - var (legExit, legOutput, _) = Replay(legA, "--all", "--family", "a"); - legExit.ShouldBe(1, "P violates"); - File.Exists(Path.Combine(BranchDir(legA), "logs", "P-0-host.log")).ShouldBeTrue("a failed run's full log is kept in the state"); - legOutput.ShouldContain(" log: "); - Replay(legB, "--all", "--family", "b").Exit.ShouldBe(0); - Directory.Exists(Path.Combine(BranchDir(legB), "logs")).ShouldBeFalse("a passing run keeps no log"); - - var (exit, output, _) = Ledger(merged, "merge", "--from", legA, legB); - exit.ShouldBe(1); - output.ShouldContain("failed: P"); - Files.Strings(Last(merged)["failed"]).ShouldBe(["P"]); - HasEvidence(merged, "Q").ShouldBeTrue("the merge still joined every leg"); - File.Exists(Path.Combine(BranchDir(merged), "logs", "P-0-host.log")).ShouldBeTrue("the merge carries the legs' logs"); - } - - [Fact] - public void Two_checkouts_of_one_repository_get_scratch_worktrees_of_their_own() - { - var other = fx.Linked("other"); - - var (main, linked) = (Home(fx.Root), Home(other)); - - linked.ShouldNotBe(main); - Path.GetFileName(linked).ShouldStartWith(Path.GetFileName(other) + "-"); - ReplayIn(other, "--where").Out.ShouldContain(Path.Combine(linked, "seeds")); - } - - /// Removing a linked worktree leaves its cache behind; the line `--where` prints removes it, worktrees first. - [Fact] - public void The_remove_line_of_where_removes_the_cache_and_its_worktrees() - { - var other = fx.Linked("other"); - var home = Home(other); - fx.Sh("git", "worktree", "add", "-q", "--detach", Path.Combine(home, "seeds"), "HEAD"); - var line = ReplayIn(other, "--where").Out.Split('\n').Single(l => l.StartsWith("remove:", StringComparison.Ordinal))["remove:".Length..].Trim(); - - static string Slashed(string path) => path.Replace('\\', '/'); - Slashed(line).ShouldContain($"'{Slashed(home)}'"); - fx.Sh("sh", "-c", line); - - Directory.Exists(home).ShouldBeFalse(); - Slashed(fx.Sh("git", "worktree", "list", "--porcelain")).ShouldNotContain(Slashed(home)); - } - - /// The main checkout's cache is keyed as it was before linked worktrees had their own, so its warm copy is kept. - [Fact] - public void The_main_checkout_keeps_the_cache_it_had() - { - var root = Path.GetDirectoryName(fx.Sh("git", "rev-parse", "--path-format=absolute", "--git-common-dir").Trim().TrimEnd('/', '\\'))!; - var key = Convert.ToHexStringLower(System.Security.Cryptography.SHA1.HashData(System.Text.Encoding.UTF8.GetBytes(root)))[..8]; - - Home(fx.Root).ShouldBe(Path.Combine(cache, $"{Path.GetFileName(root)}-{key}")); - } - - [Fact] - public void A_round_on_one_branch_does_not_skip_a_replay_of_another() - { - var other = fx.Linked("other"); - fx.Ledger("lock", "--holder", "round-explore-1", "--mode", "explore").Exit.ShouldBe(0); - - var (exit, output, error) = ReplayIn(other, "--all"); - - exit.ShouldBe(0, error + output); - output.ShouldNotContain("skipped"); - File.Exists(Path.Combine(fx.Memory, "branches", "other", "evidence", "P.json")).ShouldBeTrue(output); - } - - /// - /// The lock is per branch and the replay worktree per checkout: a replay of another branch in this checkout (the - /// branch switched while the post-commit replay runs) skips while one holds the worktree, and never shares it. - /// - [Fact] - public void A_replay_skips_while_another_branchs_replay_in_its_checkout_holds_the_worktree() - { - using (global::Prober.Replay.HoldWorktree(Home(fx.Root))) - { - var (exit, output, error) = Replay(null, "--all", "--branch", "other"); - - exit.ShouldBe(0, error); - output.ShouldContain("skipped, another branch's replay in this checkout"); - File.Exists(Path.Combine(fx.Memory, "branches", "other", "evidence", "P.json")).ShouldBeFalse(); - } - Replay(null, "--all", "--branch", "other").Out.ShouldNotContain("skipped"); - } - - /// P over C1's two rows and Q over C2's one; a run takes a moment, so runs at once can be counted. - private sealed class FakeAdapter : IProbeAdapter - { - private int running; - public int MostAtOnce; - public List CoverageAsked { get; } = []; - public HashSet Violating { get; } = new(StringComparer.Ordinal); - - public Ran Build(string worktree, IReadOnlyDictionary environment) => new(0, "Build: OK", ""); - - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - var now = Interlocked.Increment(ref running); - lock (this) MostAtOnce = Math.Max(MostAtOnce, now); - try - { - Thread.Sleep(300); - var claim = filter.EndsWith('P') ? "C1" : "C2"; - var violates = Violating.Contains(claim); - var outDir = environment["PROBE_OUT"]!; - Directory.CreateDirectory(outDir); - var lines = Enumerable.Range(0, claim == "C1" ? 2 : 1).Select(idx => new JsonObject - { - ["idx"] = idx, ["category"] = violates ? "violation" : "pass", ["applied"] = new JsonObject { ["x"] = "1", ["y"] = "1" }, - ["reasons"] = violates ? new JsonArray("violation:seeded") : new JsonArray(), - }.ToJsonString()); - File.WriteAllText(Path.Combine(outDir, claim + ".jsonl"), string.Join('\n', lines) + "\n"); - if (violates) - { - Directory.CreateDirectory(environment["PROBE_LOG_DIR"]!); - File.WriteAllText(Path.Combine(environment["PROBE_LOG_DIR"]!, "host.log"), "the host's full output"); - } - if (coverageFile.Length > 0) - { - lock (this) CoverageAsked.Add(coverageFile); - Directory.CreateDirectory(results); - File.WriteAllText(Path.Combine(results, coverageFile), - $"{worktree}" + - ""); - } - return new Ran(violates ? 1 : 0, violates ? "TESTS FAILED" : "TESTS OK", ""); - } - finally { Interlocked.Decrement(ref running); } - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) => (null, "none"); - - public IReadOnlyDictionary Environment(string cacheDirectory) => new Dictionary(); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/RowsPerProbeTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/RowsPerProbeTests.cs deleted file mode 100644 index c52e5b5d..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/RowsPerProbeTests.cs +++ /dev/null @@ -1,299 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// Rows are per probe: each probe of a claim runs a rows file of its own, its identity reads that file only, and -/// rows --probe P writes it whole, over the claim's pairs the other probes of the claim have not credited. -/// -public sealed class RowsPerProbeTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private static Dictionary R(string x, string y) => new(StringComparer.Ordinal) { ["x"] = x, ["y"] = y }; - - /// C1 gets a second probe, Q, with a rows file of its own; P credits the pairs of rows 11 and 22. - public RowsPerProbeTests() - { - fx.Write("tools/probe/corpus/registry.json", """{"probes": {"P": {"claim": "C1", "filter": "*P"}, "Q": {"claim": "C1", "filter": "*Q"}}}"""); - QRows("1", "2"); - fx.Commit("a second probe of C1"); - fx.Footprint(); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", fx.Evidence([R("1", "1"), R("2", "2")])).Exit.ShouldBe(0); - } - - private void QRows(string x, string y) => - fx.Write("tools/probe/corpus/rows/Q.json", $$$"""{"claim": "C1", "rows": [{"row": {"x": "{{{x}}}", "y": "{{{y}}}"}}]}"""); - - private string Staged(string relative) => Path.Combine(fx.BranchDir, "staging", relative); - - private List StagedRows(string probe) - { - var staged = JsonNode.Parse(File.ReadAllText(Staged($"rows/{probe}.json")))!; - staged["claim"]!.GetValue().ShouldBe("C1", "a probe's rows file keeps its claim inside"); - return [.. staged["rows"]!.AsArray().Select(r => $"{r!["row"]!["x"]}{r["row"]!["y"]}").Order(StringComparer.Ordinal)]; - } - - private string Identity(string probe) - { - var (exit, output, error) = fx.Ledger("identity", "--probe", probe); - exit.ShouldBe(0, error); - return output.Trim(); - } - - [Fact] - public void Rows_for_a_probe_leave_out_the_pairs_its_siblings_credited() - { - var (exit, output, error) = fx.Ledger("rows", "--probe", "Q"); - exit.ShouldBe(0, output + error); - StagedRows("Q").ShouldBe(["12", "21"], "P credited the pairs of 11 and 22, so Q's rows cover the other two"); - File.Exists(Staged("rows/P.json")).ShouldBeFalse("writing one probe's rows leaves its sibling's as they are"); - } - - [Fact] - public void Rows_for_a_probe_do_not_subtract_its_own_credit() - { - fx.Ledger("rows", "--probe", "P").Exit.ShouldBe(0); - StagedRows("P").ShouldBe(["11", "12", "21", "22"], "P's credit came from the rows the file replaces, so it would end with them"); - } - - [Fact] - public void The_file_is_written_whole_never_appended() - { - fx.Write(Path.GetRelativePath(fx.Root, Staged("rows/Q.json")), """{"claim": "C1", "rows": [{"row": {"x": "2", "y": "1"}}, {"row": {"x": "1", "y": "2"}}, {"row": {"x": "1", "y": "2"}}]}"""); - fx.Ledger("rows", "--probe", "Q").Exit.ShouldBe(0); - StagedRows("Q").ShouldBe(["12", "21"], "the staged rows are regenerated, not kept and added to"); - } - - [Fact] - public void A_probe_that_is_not_registered_is_refused() - { - var (exit, _, error) = fx.Ledger("rows", "--probe", "Nope"); - exit.ShouldBe(2); - error.ShouldContain("no probe Nope in the registry"); - } - - [Fact] - public void Publish_moves_the_staged_rows_by_probe_with_their_claim() - { - fx.Ledger("rows", "--probe", "Q").Exit.ShouldBe(0); - fx.Ledger("publish").Exit.ShouldBe(0); - JsonNode published; - using (var gz = new System.IO.Compression.GZipStream(File.OpenRead(Path.Combine(fx.Root, "tools/probe/corpus/rows/Q.json.gz")), System.IO.Compression.CompressionMode.Decompress)) - published = JsonNode.Parse(gz)!; - published["claim"]!.GetValue().ShouldBe("C1"); - published["rows"]!.AsArray().Select(r => $"{r!["row"]!["x"]}{r["row"]!["y"]}").Order(StringComparer.Ordinal).ShouldBe(["12", "21"]); - File.Exists(Path.Combine(fx.Root, "tools/probe/corpus/rows/C1.json.gz")).ShouldBeFalse("rows are published under the probe's name, not the claim's"); - } - - [Fact] - public void A_sibling_s_rows_changing_leaves_the_probe_s_identity_and_credit() - { - var before = Identity("P"); - QRows("2", "1"); - fx.Commit("Q's rows changed"); - Identity("P").ShouldBe(before, "P's identity reads P's rows, not Q's"); - fx.Covered().ShouldBe(2, "P's pass still counts"); - } - - [Fact] - public void The_overlay_unpacks_each_probe_s_rows_and_drops_a_file_the_corpus_no_longer_has() - { - var worktree = fx.Root + "-overlay"; - try - { - var ledger = new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), "main"); - var config = new JsonObject { ["probeDir"] = "probes" }; - var rows = Path.Combine(global::Prober.Replay.Overlay(ledger, config, worktree), "rows"); - Directory.EnumerateFiles(rows).Select(Path.GetFileName).Order(StringComparer.Ordinal).ShouldBe(["P.json", "Q.json"]); - File.Delete(Path.Combine(fx.Root, "tools/probe/corpus/rows/Q.json")); - global::Prober.Replay.Overlay(ledger, config, worktree); - Directory.EnumerateFiles(rows).Select(Path.GetFileName).ShouldBe(["P.json"], "a rows file left from an earlier overlay would be read by a probe of that name"); - } - finally - { - try { Directory.Delete(worktree, recursive: true); } catch (IOException) { } - } - } - - [Fact] - public void The_probe_s_own_rows_changing_moves_its_identity() - { - var before = Identity("P"); - fx.Rows([("1", "1"), ("2", "2"), ("1", "2")]); - fx.Commit("P's rows changed"); - Identity("P").ShouldNotBe(before); - fx.Covered().ShouldBe(0); - } -} - -/// -/// A registry entry's watched paths stale its footprint: what the probe's result depends on that the footprint, -/// the paths its own process ran under src/, cannot see. -/// -public sealed class WatchedTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private const string Catalogue = "test/Variants/Catalogue.cs"; - - private static Dictionary R(string x, string y) => new(StringComparer.Ordinal) { ["x"] = x, ["y"] = y }; - - private void Registry(bool watched) => - fx.Write("tools/probe/corpus/registry.json", watched - ? $$$$"""{"probes": {"P": {"claim": "C1", "filter": "*P", "watched": ["{{{{Catalogue}}}}"]}}}""" - : """{"probes": {"P": {"claim": "C1", "filter": "*P"}}}"""); - - private void ChangeTheCatalogue() - { - fx.Write(Catalogue, "class Catalogue { int Site; }\n"); - fx.Commit("the catalogue gains a site"); - } - - /// A replay's record of P: the footprint from a coverage report of src/a.cs, through the command the replay runs, and a pass. - private void Replayed() - { - var report = Path.Combine(fx.Root, "coverage.cobertura.xml"); - File.WriteAllText(report, $"""{fx.Root}"""); - var (exit, output, error) = fx.Ledger("footprint", "--probe", "P", "--root", fx.Root, "--cobertura", report); - exit.ShouldBe(0, output + error); - File.Delete(report); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", fx.Evidence([R("1", "1"), R("2", "2")])).Exit.ShouldBe(0); - } - - private bool Stale() - { - var (exit, output, error) = fx.Ledger("stale", "--json"); - exit.ShouldBe(0, error); - return JsonNode.Parse(output)!.AsArray().Single(s => s!["probe"]!.GetValue() == "P")!["stale"]!.GetValue(); - } - - private Ledger Ledger() => new(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), "main"); - - [Fact] - public void The_footprint_records_each_watched_path_with_its_id() - { - Registry(watched: true); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching a catalogue"); - Replayed(); - var line = JsonNode.Parse(File.ReadLines(Path.Combine(fx.BranchDir, "footprints.jsonl")).Last())!; - line["watched"]![Catalogue]!.GetValue().ShouldBe(fx.Sh("git", "rev-parse", $"HEAD:{Catalogue}").Trim()); - Stale().ShouldBeFalse(); - fx.Covered().ShouldBe(2); - } - - [Fact] - public void A_change_to_a_watched_path_stales_the_footprint() - { - Registry(watched: true); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching a catalogue"); - Replayed(); - ChangeTheCatalogue(); - Stale().ShouldBeTrue("the catalogue P watches changed"); - fx.Covered().ShouldBe(0); - } - - [Fact] - public void Without_watched_the_footprint_does_not_see_the_path() - { - Registry(watched: false); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching nothing"); - Replayed(); - ChangeTheCatalogue(); - Stale().ShouldBeFalse("the control: nothing P ran or watches changed, which is the gap watched closes"); - fx.Covered().ShouldBe(2); - } - - [Fact] - public void A_watched_path_the_footprint_did_not_record_is_not_current() - { - Registry(watched: true); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching a catalogue"); - fx.Footprint(); - var ledger = Ledger(); - ledger.FootprintCurrent("P", ledger.Footprints()).ShouldBeFalse("the footprint line records nothing of the catalogue P watches"); - } - - [Fact] - public void A_change_to_a_watched_path_changes_the_footprint_since_a_release() - { - Registry(watched: true); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching a catalogue"); - Replayed(); - fx.Sh("git", "tag", "v1"); - var ledger = Ledger(); - ledger.FootprintChangedSince("P", "v1", ledger.Footprints()).ShouldBeFalse(); - ChangeTheCatalogue(); - ledger = Ledger(); - ledger.FootprintChangedSince("P", "v1", ledger.Footprints()).ShouldBeTrue(); - } - - /// A replay's record of a probe that runs nothing under src/ in its own process, as C22, which builds its consumer in a child process. - private (int Exit, string Output, string Error) RanNothingUnderSrc() - { - var report = Path.Combine(fx.Root, "coverage.cobertura.xml"); - File.WriteAllText(report, $"""{fx.Root}"""); - var result = fx.Ledger("footprint", "--probe", "P", "--root", fx.Root, "--cobertura", report); - File.Delete(report); - return result; - } - - [Fact] - public void A_probe_that_ran_nothing_under_src_is_recorded_by_what_it_watches() - { - Registry(watched: true); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching a catalogue, building in a child process"); - var (exit, output, error) = RanNothingUnderSrc(); - exit.ShouldBe(0, output + error); - var line = JsonNode.Parse(File.ReadLines(Path.Combine(fx.BranchDir, "footprints.jsonl")).Last())!; - line["footprint"]!.AsObject().Count.ShouldBe(0); - line["watched"]![Catalogue]!.GetValue().ShouldBe(fx.Sh("git", "rev-parse", $"HEAD:{Catalogue}").Trim()); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", fx.Evidence([R("1", "1"), R("2", "2")])).Exit.ShouldBe(0); - Stale().ShouldBeFalse("what P watches is unchanged"); - fx.Covered().ShouldBe(2); - ChangeTheCatalogue(); - Stale().ShouldBeTrue("the catalogue P watches changed"); - fx.Covered().ShouldBe(0); - } - - [Fact] - public void A_probe_that_ran_nothing_under_src_and_watches_nothing_is_refused() - { - Registry(watched: false); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe watching nothing, building in a child process"); - var (exit, output, error) = RanNothingUnderSrc(); - exit.ShouldBe(1, output + error); - (output + error).ShouldContain("refusing to record an empty footprint"); - File.Exists(Path.Combine(fx.BranchDir, "footprints.jsonl")).ShouldBeFalse(); - } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public void The_gate_counts_a_change_to_a_watched_path_as_touching_the_claim(bool watched) - { - Registry(watched); - fx.Write(Catalogue, "class Catalogue {}\n"); - fx.Commit("a probe and a catalogue"); - fx.Footprint(); - fx.Sh("git", "tag", "v1"); - ChangeTheCatalogue(); - var (_, output, _) = fx.Ledger("gate", "--since", "v1", "--json"); - var gate = JsonNode.Parse(output)!; - static List Names(JsonNode? list) => [.. list!.AsArray().Select(x => x!.GetValue())]; - Names(gate["touched"]).ShouldBe(watched ? ["C1"] : [], "a change to what a probe of the claim watches touches the claim, and nothing else does here"); - // The conservative rule and the footprint agree: neither selects the claim without the other. - Names(gate["selected_by_footprint_only"]).ShouldBeEmpty(); - Names(gate["missed_by_footprint_alone"]).ShouldBeEmpty(); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/SeedsTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/SeedsTests.cs deleted file mode 100644 index 2fce1dab..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/SeedsTests.cs +++ /dev/null @@ -1,408 +0,0 @@ -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// A probe proves it can fail (decision 100): `seeds` applies the defect its registry entry names in a scratch -/// worktree, runs the probe there, and counts the seed caught only for a violation the unseeded probe does -/// not have. The probe here is a fake adapter: row 1 of C1 violates while the product holds DEFECT. -/// -public sealed class SeedsTests : IDisposable -{ - private readonly Fixture fx = new(); - private readonly string cache; - private readonly FakeAdapter adapter = new(); - - public SeedsTests() - { - cache = fx.Root + "-cache"; - fx.Sh("git", "config", "core.autocrlf", "false"); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src") }, - }.ToJsonString() + "\n```\n"); - fx.Commit("replay configuration"); - } - - public void Dispose() - { - fx.Dispose(); - try { Directory.Delete(cache, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - /// Writes the seed for P: a patch made by editing the file and taking the diff, and the registry entry naming it. - private void Seed(string? file = "src/a.cs", string? edit = "class A { /* DEFECT */ }\n", JsonObject? env = null) - { - var seed = new JsonObject { ["defect"] = "A holds the defect." }; - if (file is not null) - { - var original = File.ReadAllText(Path.Combine(fx.Root, file)); - fx.Write(file, edit!); - fx.Write("tools/probe/corpus/seeds/C1.patch", fx.Sh("git", "diff", "--", file)); - fx.Write(file, original); - seed["patch"] = "seeds/C1.patch"; - } - if (env is not null) seed["env"] = env; - fx.Write("tools/probe/corpus/registry.json", new JsonObject - { - ["probes"] = new JsonObject { ["P"] = new JsonObject { ["claim"] = "C1", ["filter"] = "*P", ["seed"] = seed } }, - }.ToJsonString()); - fx.Commit("seed"); - } - - private (int Exit, string Out, string Err) Seeds(params string[] args) - { - var output = new StringWriter(); var error = new StringWriter(); - var context = new Context(fx.Root, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, output, error); - int exit; - try { exit = global::Prober.Seeds.Run(context, new Args(args, new HashSet(StringComparer.Ordinal) { "dry-run", "all" }), adapter); } - catch (Refusal refusal) { error.WriteLine(refusal.Message); exit = refusal.ExitCode; } - return (exit, output.ToString(), error.ToString()); - } - - private string Worktree => Directory.GetDirectories(cache).Single() is var home ? Path.Combine(home, "seeds") : ""; - - [Fact] - public void A_seed_the_probe_catches_passes() - { - Seed(); - var (exit, output, error) = Seeds(); - exit.ShouldBe(0, output + error); - output.ShouldContain("P (C1): caught, 1 of 2 rows violate; e.g. #1: violation:"); - output.ShouldContain("1 caught"); - } - - [Fact] - public void A_seed_the_probe_misses_fails_the_command() - { - Seed(edit: "class A { /* harmless */ }\n"); - var (exit, output, _) = Seeds(); - exit.ShouldBe(1); - output.ShouldContain("P (C1): missed, no row violates that did not already (2 rows: pass 2;"); - } - - [Fact] - public void A_violation_the_probe_has_without_the_seed_is_not_the_seeds() - { - adapter.AlwaysViolates = 1; - Seed(); - var (exit, output, _) = Seeds(); - exit.ShouldBe(1, "row 1 fails unseeded too, so the seed proved nothing"); - output.ShouldContain("1 violations unseeded"); - output.ShouldContain("P (C1): missed"); - } - - [Fact] - public void A_probe_without_a_seed_fails_the_command() - { - var (exit, output, _) = Seeds(); - exit.ShouldBe(1); - output.ShouldContain("P (C1): no seed, its registry entry names none"); - } - - [Fact] - public void An_environment_toggle_is_a_seed() - { - Seed(file: null, env: new JsonObject { ["SEED_DEFECT"] = "1" }); - var (exit, output, error) = Seeds(); - exit.ShouldBe(0, output + error); - output.ShouldContain("P (C1): caught"); - } - - [Fact] - public void A_seed_outside_the_product_files_is_refused() - { - Seed(file: "README.md", edit: "# a\n\nThe claim, DEFECT.\n"); - var (exit, output, _) = Seeds(); - exit.ShouldBe(1); - output.ShouldContain("P (C1): does not apply, it patches README.md, outside the product files (src)"); - } - - [Fact] - public void A_seed_that_no_longer_applies_fails_the_command() - { - Seed(); - fx.Write("src/a.cs", "class B {}\n"); - fx.Commit("the product moved on"); - var (exit, output, _) = Seeds(); - exit.ShouldBe(1); - output.ShouldContain("P (C1): does not apply"); - } - - [Fact] - public void A_seed_that_breaks_the_build_proves_nothing() - { - adapter.BreaksOn = "DEFECT"; - Seed(); - var (exit, output, _) = Seeds(); - exit.ShouldBe(1); - output.ShouldContain("P (C1): build failed"); - } - - [Fact] - public void The_seed_is_applied_only_in_the_scratch_worktree_and_undone() - { - Seed(); - Seeds().Exit.ShouldBe(0); - File.ReadAllText(Path.Combine(fx.Root, "src/a.cs")).ShouldBe("class A {}\n"); - File.ReadAllText(Path.Combine(Worktree, "src/a.cs")).ShouldBe("class A {}\n"); - adapter.Worktrees.ShouldAllBe(w => w == Worktree); - } - - [Fact] - public void A_seeded_run_is_never_evidence() - { - Seed(); - Seeds().Exit.ShouldBe(0); - File.Exists(Path.Combine(fx.BranchDir, "runs.jsonl")).ShouldBeFalse(); - Directory.Exists(Path.Combine(fx.BranchDir, "evidence")).ShouldBeFalse(); - File.Exists(Path.Combine(fx.BranchDir, "seeds-last.json")).ShouldBeTrue(); - } - - [Fact] - public void The_seed_is_not_part_of_the_probe_s_identity() - { - var before = fx.Ledger("identity", "--probe", "P").Out; - Seed(); - fx.Ledger("identity", "--probe", "P").Out.ShouldBe(before, "a seed proves the probe; adding or changing one must not stale its results"); - } - - /// What the replay records for P: the product files it ran, at HEAD. - private void Footprint(params string[] files) => - File.AppendAllText(Path.Combine(fx.BranchDir, "footprints.jsonl"), new JsonObject - { - ["probe"] = "P", - ["footprint"] = new JsonObject(files.Select(f => KeyValuePair.Create(f, (JsonNode?)fx.Sh("git", "rev-parse", "HEAD:" + f).Trim()))), - ["compileTime"] = new JsonObject(), ["toolchain"] = new JsonObject(), - }.ToJsonString() + "\n"); - - /// P seeded and caught once, with a footprint over src/a.cs and src/b.cs or the files given, so the next run has a record to skip by. - private void CaughtOnce(params string[] footprint) - { - fx.Write("src/b.cs", "class B {}\n"); - fx.Commit("a second product file"); - Seed(); - Footprint(footprint.Length > 0 ? footprint : ["src/a.cs", "src/b.cs"]); - var (exit, output, error) = Seeds(); - exit.ShouldBe(0, output + error); - output.ShouldContain(" runs P: no run caught every seed of it yet"); - output.ShouldContain("P (C1): caught"); - } - - private JsonObject Last() => (JsonObject)JsonNode.Parse(File.ReadAllText(Path.Combine(fx.BranchDir, "seeds-last.json")))!; - - [Fact] - public void An_unchanged_probe_is_skipped_and_says_why() - { - CaughtOnce(); - var builds = adapter.Worktrees.Count; - - var (exit, output, error) = Seeds(); - - exit.ShouldBe(0, output + error); - output.ShouldContain(" skips P: every seed caught at " + fx.Sh("git", "rev-parse", "--short=7", "HEAD").Trim() + ", and neither its identity nor its product footprint changed since"); - output.ShouldContain("0 seeds of 0 probes"); - output.ShouldContain("1 probes skipped"); - adapter.Worktrees.Count.ShouldBe(builds, "nothing built or ran"); - Last()["skipped"]!.AsArray().Single()!["probe"]!.GetValue().ShouldBe("P"); - Last()["probes"]!["P"]!["commit"]!.GetValue().ShouldBe(fx.Sh("git", "rev-parse", "HEAD").Trim(), "a skipped probe's record is carried forward"); - } - - [Fact] - public void A_changed_identity_reruns() - { - CaughtOnce(); - fx.Write("tools/probe/corpus/harness/P.cs", "// probe P, changed\n"); - fx.Commit("the harness changed"); - - var (_, output, _) = Seeds(); - - output.ShouldContain(" runs P: its identity or its seeds changed since they were caught at "); - output.ShouldContain("P (C1): caught"); - } - - [Fact] - public void A_changed_seed_reruns() - { - CaughtOnce(); - Seed(edit: "class A { /* DEFECT, another */ }\n"); - - Seeds().Out.ShouldContain(" runs P: its identity or its seeds changed since they were caught at "); - } - - [Fact] - public void A_changed_product_footprint_reruns() - { - CaughtOnce(); - fx.Write("src/b.cs", "class B { int changed; }\n"); - fx.Commit("the product changed where P runs"); - - var (_, output, _) = Seeds(); - - output.ShouldContain(" runs P: its product footprint changed since "); - output.ShouldContain("P (C1): caught"); - } - - /// The seed's own file may be outside what the probe ran; a change there may leave the seed behind, so it reruns. - [Fact] - public void A_change_to_the_file_the_seed_patches_reruns() - { - CaughtOnce("src/b.cs"); - fx.Write("src/a.cs", "class A {}\n// moved on\n"); - fx.Commit("the seeded file changed"); - - Seeds().Out.ShouldContain(" runs P: a file its seeds patch changed since "); - } - - [Fact] - public void A_change_outside_the_footprint_skips() - { - CaughtOnce(); - fx.Write("src/c.cs", "class C {}\n"); - fx.Commit("the product changed where P does not run"); - - Seeds().Out.ShouldContain(" skips P: "); - } - - [Fact] - public void A_probe_without_a_recorded_footprint_runs() - { - Seed(); - Seeds().Exit.ShouldBe(0); - - Seeds().Out.ShouldContain(" runs P: no product footprint recorded for it (a replay records one)"); - } - - [Fact] - public void All_ignores_the_record() - { - CaughtOnce(); - - var (exit, output, _) = Seeds("--all"); - - exit.ShouldBe(0); - output.ShouldNotContain("skips P"); - output.ShouldContain("P (C1): caught"); - Last()["all"]!.GetValue().ShouldBeTrue(); - } - - [Fact] - public void A_probe_named_runs_whatever_its_record_says() - { - CaughtOnce(); - - Seeds("--probe", "P").Out.ShouldContain("P (C1): caught"); - } - - [Fact] - public void A_missed_seed_is_never_skipped_next_time() - { - fx.Write("src/b.cs", "class B {}\n"); - fx.Commit("a second product file"); - Seed(edit: "class A { /* harmless */ }\n"); - Footprint("src/a.cs", "src/b.cs"); - Seeds().Exit.ShouldBe(1); - Last()["probes"]!.AsObject().ShouldBeEmpty(); - - var (exit, output, _) = Seeds(); - - exit.ShouldBe(1); - output.ShouldContain(" runs P: no run caught every seed of it yet"); - output.ShouldContain("P (C1): missed"); - } - - [Fact] - public void A_seed_missed_after_a_catch_drops_the_record() - { - CaughtOnce(); - Seed(edit: "class A { /* harmless */ }\n"); - Seeds().Exit.ShouldBe(1); - - Last()["probes"]!.AsObject().ContainsKey("P").ShouldBeFalse(); - Seeds().Out.ShouldContain(" runs P: no run caught every seed of it yet"); - } - - [Fact] - public void The_record_is_what_its_schema_says() - { - CaughtOnce(); - Seeds(); - var root = AppContext.BaseDirectory; - while (!File.Exists(Path.Combine(root, "CodoMetis.TypeKit.slnx"))) root = Path.GetDirectoryName(root) ?? throw new InvalidOperationException("no CodoMetis.TypeKit.slnx above the test output"); - var schema = (JsonObject)JsonNode.Parse(File.ReadAllText(Path.Combine(root, "tools", "Prober", "Schemas", "seeds-run.schema.json")))!["properties"]!; - - foreach (var field in new[] { "probes", "skipped", "all" }) - SchemaCheck.Problems(Last()[field], (JsonObject)schema[field]!, field).ShouldBeEmpty(field); - Last()["probes"]!["P"]!["identity"]!.GetValue().ShouldBe(global::Prober.Seeds.SeedsIdentity(new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null), "P")); - } - - private List Problems() => global::Prober.Seeds.Problems(new Ledger(new Context(fx.Root, new Dictionary(), TextWriter.Null, TextWriter.Null), null)); - - [Fact] - public void The_check_without_a_build_names_a_probe_without_a_seed() - { - Problems().ShouldBe(["P: no seed, its registry entry names none"]); - Seed(); - Problems().ShouldBeEmpty(); - } - - [Fact] - public void The_check_without_a_build_names_a_seed_the_product_left_behind() - { - Seed(); - fx.Write("src/a.cs", "class B {}\n"); - fx.Commit("the product moved on"); - Problems().ShouldHaveSingleItem().ShouldStartWith("P: does not apply, "); - } - - [Fact] - public void Every_probe_in_the_repository_has_a_seed_that_applies() - { - var root = AppContext.BaseDirectory; - while (!File.Exists(Path.Combine(root, "CodoMetis.TypeKit.slnx"))) root = Path.GetDirectoryName(root) ?? throw new InvalidOperationException("no CodoMetis.TypeKit.slnx above the test output"); - global::Prober.Seeds.Problems(new Ledger(new Context(root, new Dictionary(), TextWriter.Null, TextWriter.Null), null)).ShouldBeEmpty(); - } - - /// The probe P over C1's two rows, without a build: row 1 violates where src/a.cs holds DEFECT or SEED_DEFECT is set. - private sealed class FakeAdapter : IProbeAdapter - { - public int? AlwaysViolates { get; set; } - public string? BreaksOn { get; set; } - public List Worktrees { get; } = []; - - public Ran Build(string worktree, IReadOnlyDictionary environment) - { - Worktrees.Add(worktree); - return BreaksOn is { } marker && File.ReadAllText(Path.Combine(worktree, "src", "a.cs")).Contains(marker, StringComparison.Ordinal) - ? new Ran(1, "Build: FAILED", "") - : new Ran(0, "Build: OK", ""); - } - - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - Worktrees.Add(worktree); - var defect = File.ReadAllText(Path.Combine(worktree, "src", "a.cs")).Contains("DEFECT", StringComparison.Ordinal) - || environment.GetValueOrDefault("SEED_DEFECT") == "1"; - var outDir = environment["PROBE_OUT"]!; - Directory.CreateDirectory(outDir); - var lines = Enumerable.Range(0, 2).Select(idx => - { - var violates = idx == AlwaysViolates || (defect && idx == 1); - return new JsonObject - { - ["idx"] = idx, ["category"] = violates ? "violation" : "pass", - ["reasons"] = violates ? new JsonArray("violation:A holds the defect") : new JsonArray(), - }.ToJsonString(); - }); - File.WriteAllText(Path.Combine(outDir, "C1.jsonl"), string.Join('\n', lines) + "\n"); - return new Ran(lines.Any(l => l.Contains("violation", StringComparison.Ordinal)) ? 1 : 0, "", ""); - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) => (null, "none"); - - public IReadOnlyDictionary Environment(string cacheDirectory) => new Dictionary(); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/SourceLintTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/SourceLintTests.cs deleted file mode 100644 index 7e28922b..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/SourceLintTests.cs +++ /dev/null @@ -1,231 +0,0 @@ -using System.Text.Json.Nodes; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// `register` and `publish` read the staged sources before anything is built (decision 103): a note names a -/// key of the catalogue as NoteKeys.Name, the harness's two-argument skip names an open finding of -/// this ledger as a string literal, and a check's Inapplicable or Refused cites by a Cite -/// factory with a string literal something that exists. Each refusal names the file and the line. -/// -public sealed class SourceLintTests : IDisposable -{ - private readonly Fixture fx = new(); - - public SourceLintTests() - { - fx.Write("tools/probe/corpus/harness/Row.cs", """ - public sealed class NoteKeys - { - // public static readonly NoteKeys InAComment = new("in-a-comment", Pass); - public static readonly NoteKeys Compared = new("compared", Pass); - public static readonly NoteKeys BothThrew = new("both-threw", ExpectedRefusal); - } - """); - // C1's not-promised entry, C2's, and what a citation may name besides: a file of the docs, a knowledge entry, a record. - fx.Write("tools/probe/corpus/claims.json", new JsonArray( - new JsonObject { ["id"] = "C1", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["not-promised"] = new JsonArray(new JsonObject { ["id"] = "c1-limit", ["source"] = "README.md#a", ["sentence"] = "The claim." }) }, - new JsonObject { ["id"] = "C2", ["source"] = "README.md#a", ["surfaces"] = new JsonArray("s"), - ["not-promised"] = new JsonArray(new JsonObject { ["id"] = "c2-limit", ["source"] = "README.md#a", ["sentence"] = "The claim." }) }).ToJsonString()); - fx.Write("design/knowledge/KB-007-a-fact.md", "# KB-007\n"); - fx.Write("design/adr/0094-a-record.md", "# 94\n"); - fx.Commit("the catalogue"); - } - - public void Dispose() => fx.Dispose(); - - private string Staged => Path.Combine(fx.BranchDir, "staging"); - - private void Stage(string body) => - fx.Write(Path.GetRelativePath(fx.Root, Path.Combine(Staged, "probes", "C1Probe.cs")), $$""" - public sealed class C1Probe - { - static string? Check(Row r, string x) - { - var rest = new[] { 1, 2 }.Skip(x.Length); - // r.Note("a comment is no call", x); - var text = "r.Note(\"a string is no call\")"; - {{body}} - return null; - } - } - """); - - /// Stages a source of the probe P (C1's), or a harness source no one probe owns, holding in a check. - private void StageCheck(string body, string file = "probes/P.cs") => - fx.Write(Path.GetRelativePath(fx.Root, Path.Combine(Staged, file)), $$""" - public sealed class P - { - static string? Check(Check c, string x) - { - var refused = new Entry().Refused(); - // c.Inapplicable(Cite.NotPromised("in-a-comment")); - var text = "c.Refused(Cite.Docs(\"in-a-string.md\"))"; - {{body}} - return null; - } - } - """); - - private (int Exit, string Out, string Err) Register() => fx.Ledger("register", "--probe", "P", "--claim", "C1", "--filter", "*C1Probe"); - - private void Finding(string id, string status) => - File.AppendAllText(Path.Combine(fx.BranchDir, "findings.jsonl"), - new JsonObject { ["id"] = id, ["claim"] = "C1", ["status"] = status }.ToJsonString() + "\n"); - - [Fact] - public void A_probe_whose_notes_and_skips_are_written_out_registers() - { - Finding("F7", "open"); - Stage(""" - r.Note(NoteKeys.Compared, $"{x}: {(x.Length > 1 ? "long" : "short")}"); - r.Note(NoteKeys.BothThrew); - r.Skip("F7", "the open finding"); - """); - var (exit, output, error) = Register(); - exit.ShouldBe(0, output + error); - } - - [Fact] - public void A_note_key_built_from_text_is_refused_by_file_and_line() - { - Stage(""" r.Note("msg:" + x, "detail");"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("staging/probes/C1Probe.cs:8: Note(\"msg:\" + x, ...) does not name a key of NoteKeys"); - } - - [Fact] - public void A_note_key_the_catalogue_does_not_declare_is_refused() - { - Stage(""" r.Note(NoteKeys.InAComment);"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("C1Probe.cs:8: Note(NoteKeys.InAComment, ...) names no key of NoteKeys"); - } - - [Fact] - public void A_finding_built_from_text_is_refused() - { - Stage(""" r.Skip("F" + x, "why");"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("C1Probe.cs:8: Skip(\"F\" + x, ...) does not name its finding as a string literal"); - } - - [Fact] - public void A_skip_for_a_finding_that_is_not_open_is_refused() - { - Finding("F7", "open"); - Finding("F7", "withdrawn"); - Stage(""" - r.Skip("F7", "withdrawn since"); - r.Skip("F8", "never filed"); - """); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("C1Probe.cs:8: Skip(\"F7\", ...) names finding F7, which is withdrawn"); - error.ShouldContain("C1Probe.cs:9: Skip(\"F8\", ...) names no finding this ledger has"); - } - - [Fact] - public void Publish_refuses_what_register_refuses_and_moves_nothing() - { - Stage(""" r.Note("msg:" + x, "detail");"""); - var (exit, _, error) = fx.Ledger("publish"); - exit.ShouldBe(1); - error.ShouldContain("publish: "); - error.ShouldContain("C1Probe.cs:8: Note(\"msg:\" + x, ...)"); - File.Exists(Path.Combine(fx.Root, "tools/probe/corpus/probes/C1Probe.cs")).ShouldBeFalse(); - } - - [Fact] - public void A_check_citing_what_exists_registers() - { - StageCheck(""" - c.Inapplicable(Cite.NotPromised("c1-limit"), x); - c.Refused(Cite.Docs("README.md#a")); - c.Refused(Cite.Docs("README.md")); - c.Inapplicable(Cite.Fact("KB-007")); - c.Refused(Cite.Record( "0094" ), "detail"); - """); - var (exit, output, error) = Register(); - exit.ShouldBe(0, output + error); - } - - [Fact] - public void A_citation_that_is_not_a_factory_with_a_string_literal_is_refused() - { - StageCheck(""" - var cite = Cite.NotPromised("c1-limit"); - c.Inapplicable(cite); - c.Refused(Cite.NotPromised("c1-" + x)); - c.Inapplicable(Cite.Text("c1-limit")); - """); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("staging/probes/P.cs:9: Inapplicable(cite, ...) does not cite by a Cite factory with a string literal"); - error.ShouldContain("P.cs:10: Refused(Cite.NotPromised(\"c1-\" + x), ...) does not cite by a Cite factory with a string literal"); - error.ShouldContain("P.cs:11: Inapplicable(Cite.Text(\"c1-limit\"), ...) does not cite by a Cite factory with a string literal"); - } - - [Fact] - public void A_not_promised_id_the_probes_claim_does_not_list_is_refused() - { - StageCheck(""" c.Inapplicable(Cite.NotPromised("c2-limit"));"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("P.cs:8: Inapplicable(Cite.NotPromised(\"c2-limit\"), ...) names no not-promised entry of its claim C1"); - } - - [Fact] - public void A_harness_source_cites_any_claims_not_promised_entry_and_none_that_no_claim_lists() - { - StageCheck(""" - c.Inapplicable(Cite.NotPromised("c2-limit")); - c.Inapplicable(Cite.NotPromised("no-claim-lists-it")); - """, "harness/Shared.cs"); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldNotContain("Shared.cs:8:"); - error.ShouldContain("staging/harness/Shared.cs:9: Inapplicable(Cite.NotPromised(\"no-claim-lists-it\"), ...) names no not-promised entry of any claim"); - } - - [Fact] - public void A_docs_source_naming_no_file_is_refused() - { - StageCheck(""" c.Refused(Cite.Docs("docs/gone.md#a"));"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("P.cs:8: Refused(Cite.Docs(\"docs/gone.md#a\"), ...) names no file docs/gone.md in the repository"); - } - - [Fact] - public void A_fact_with_no_knowledge_entry_is_refused() - { - StageCheck(""" c.Refused(Cite.Fact("KB-070"));"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("P.cs:8: Refused(Cite.Fact(\"KB-070\"), ...) names no entry under design/knowledge/"); - } - - [Fact] - public void A_record_with_no_file_under_design_adr_is_refused() - { - StageCheck(""" c.Inapplicable(Cite.Record("0095"));"""); - var (exit, _, error) = Register(); - exit.ShouldBe(1); - error.ShouldContain("P.cs:8: Inapplicable(Cite.Record(\"0095\"), ...) names no record under design/adr/"); - } - - [Fact] - public void Publish_refuses_a_citation_that_names_nothing() - { - StageCheck(""" c.Inapplicable(Cite.Record("0095"));"""); - var (exit, _, error) = fx.Ledger("publish"); - exit.ShouldBe(1); - error.ShouldContain("publish: "); - error.ShouldContain("P.cs:8: Inapplicable(Cite.Record(\"0095\"), ...) names no record under design/adr/"); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/ToolchainTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/ToolchainTests.cs deleted file mode 100644 index 3c22bc0d..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/ToolchainTests.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.Text.Json.Nodes; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// A result is bound to what the axes file's toolchain commands print. A command that cannot say it refuses, by -/// name: hashed into the identity, its error text made every result read as stale, so `status` showed 0% current -/// when the dotnet first on PATH had no SDK global.json accepts. -/// -public sealed class ToolchainTests : IDisposable -{ - private readonly Fixture fx = new(); - public void Dispose() => fx.Dispose(); - - private static Dictionary R(string x, string y) => new(StringComparer.Ordinal) { ["x"] = x, ["y"] = y }; - - private void Toolchain(params string[] command) - { - var path = Path.Combine(fx.Root, ".claude/probe-axes.md"); - var text = File.ReadAllText(path); - var block = text[(text.IndexOf('\n') + 1)..text.LastIndexOf("```", StringComparison.Ordinal)]; - var axes = JsonNode.Parse(block)!.AsObject(); - axes["replay"] = new JsonObject { ["toolchain"] = new JsonObject { ["sdk"] = new JsonArray([.. command.Select(c => (JsonNode)c)]) } }; - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + axes.ToJsonString() + "\n```\n"); - fx.Commit("toolchain"); - } - - /// A pass recorded under a toolchain that names itself, then read under one that cannot. - private void RecordedThenBroken(params string[] command) - { - Toolchain("git", "--version"); - RecordPass(); - Toolchain(command); - } - - private void RecordPass() - { - fx.Footprint(); - fx.Ledger("record-run", "--probe", "P", "--result", "pass", "--evidence", fx.Evidence([R("1", "1"), R("2", "2")])).Exit.ShouldBe(0); - } - - /// The ways a toolchain command fails to name the toolchain, each with what the refusal must say. - public static TheoryData Failing() => new() - { - { ["git", "no-such-subcommand"], "exited 1" }, - { ["cmtk-no-such-program"], "did not start" }, - { ["git", "diff", "--quiet"], "printed nothing" }, - { [], "is empty" }, - }; - - [Theory, MemberData(nameof(Failing))] - public void A_toolchain_command_that_cannot_name_the_toolchain_refuses(string[] command, string reason) - { - RecordedThenBroken(command); - var (exit, output, error) = fx.Ledger("status"); - exit.ShouldBe(1, output); - error.ShouldContain("the toolchain command sdk"); - error.ShouldContain(reason); - output.ShouldNotContain("pairs current", Case.Sensitive, "a refusal, never a status of 0% current"); - } - - /// - /// The case that was found: a dotnet with no SDK global.json accepts lists the installed SDKs on stdout, which - /// reads like a version, and says why on stderr. The refusal quotes the why. - /// - [Fact] - public void A_dotnet_without_the_pinned_sdk_refuses_with_its_error_not_its_sdk_list() - { - fx.Write("global.json", """{"sdk": {"version": "0.0.1"}}"""); - RecordedThenBroken("dotnet", "--version"); - var (exit, output, error) = fx.Ledger("status"); - exit.ShouldBe(1, output); - error.ShouldContain("the toolchain command sdk (`dotnet --version`) exited"); - error.ShouldNotContain("sdk]", Case.Insensitive, "the installed SDKs on stdout are not the reason"); - } - - /// Every command that reads an identity, not only status. - [Theory] - [InlineData("status")] - [InlineData("gate")] - [InlineData("stale")] - [InlineData("rows", "--claim", "C1")] - [InlineData("identity", "--probe", "P")] - public void Every_reader_of_an_identity_refuses(params string[] command) - { - RecordedThenBroken("git", "no-such-subcommand"); - var (exit, _, error) = fx.Ledger(command); - exit.ShouldBe(1, error); - error.ShouldContain("the toolchain command sdk"); - } - - /// - /// The case that was found next: Homebrew's dotnet first on PATH (10.0.401 against the 10.0.402 pin) made every - /// `dotnet` the prober starts fail, though the SDK installer's had the pinned SDK. Here the dotnet that runs the - /// built prober has no SDK the pin accepts, and a stub in the installer's place (TOOLS_DOTNET_FALLBACK_DIR) answers: - /// the prober falls back to it, records the pass under what it prints, and keeps the pass current. - /// - [Fact] - public void A_dotnet_without_the_pinned_sdk_falls_back_to_the_installers() - { - Assert.SkipWhen(OperatingSystem.IsWindows(), "the stub installer is a shell script"); - Toolchain("dotnet", "--version"); - fx.Write("global.json", """{"sdk": {"version": "0.0.1", "rollForward": "disable"}}"""); - fx.Commit("a pin no dotnet here has"); - fx.Footprint(); - var evidence = fx.Evidence([R("1", "1"), R("2", "2")]); - - var installer = Directory.CreateTempSubdirectory("prober-installer-").FullName; - try - { - var stub = Path.Combine(installer, "dotnet"); - File.WriteAllText(stub, "#!/bin/sh\necho 0.0.1\n"); - if (!OperatingSystem.IsWindows()) File.SetUnixFileMode(stub, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute); - using var sandbox = new ToolSandbox("Prober", "prober"); - // The prober runs as its own process, so the caller's state settings would reach it: under a PROBE_STATE_DIR it - // recorded the run there, not in this repository's state, and status found no claim (#58). None reaches it. - var environment = new Dictionary - { - ["TOOLS_DOTNET_FALLBACK_DIR"] = installer, ["PROBE_STATE_DIR"] = null, ["PROBE_CACHE_DIR"] = null, ["PROBE_HOLDER"] = null, - }; - (int, string, string) Prober(params string[] arguments) => ToolSandbox.RunProcess("dotnet", [sandbox.Dll, .. arguments], fx.Root, environment); - - var (recorded, _, why) = Prober("record-run", "--probe", "P", "--result", "pass", "--evidence", evidence); - recorded.ShouldBe(0, why); - var (exit, output, error) = Prober("status", "--json"); - exit.ShouldBe(0, error); - ((int)JsonNode.Parse(output)!["claims"]!["C1"]!["current"]!.GetValue()).ShouldBe(2, "the pass, recorded under the fallback, is current"); - } - finally - { - Directory.Delete(installer, recursive: true); - } - } - - [Fact] - public void A_toolchain_that_names_itself_keeps_the_result_current() - { - Toolchain("git", "--version"); - RecordPass(); - fx.Covered().ShouldBe(2); - } -} diff --git a/test/CodoMetis.TypeKit.Prober.Tests/TryProbeTests.cs b/test/CodoMetis.TypeKit.Prober.Tests/TryProbeTests.cs deleted file mode 100644 index 7b0076f4..00000000 --- a/test/CodoMetis.TypeKit.Prober.Tests/TryProbeTests.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using System.Text.Json.Nodes; -using Prober; - -namespace CodoMetis.TypeKit.Prober.Tests; - -/// -/// `try` is the writer's loop for one probe: it builds once in the replay's worktree, runs that probe alone, -/// prints how each row ended and exits with the probe's code, and records nothing. The probes here are a fake -/// adapter: P runs C1's three rows (row 1 violates, and the run then exits 7) and Q runs C2's. -/// -public sealed class TryProbeTests : IDisposable -{ - private readonly Fixture fx = new(); - private readonly string cache; - private readonly FakeAdapter adapter = new(); - - public TryProbeTests() - { - cache = fx.Root + "-cache"; - fx.Sh("git", "config", "core.autocrlf", "false"); - fx.Write(".claude/probe-axes.md", "```json probe-axes\n" + new JsonObject - { - ["axes"] = new JsonObject { ["x"] = new JsonArray("1", "2"), ["y"] = new JsonArray("1", "2") }, - ["surfaces"] = new JsonObject { ["s"] = new JsonObject { ["axes"] = new JsonArray("x", "y"), ["watched"] = new JsonArray("src") } }, - ["replay"] = new JsonObject { ["probeDir"] = "probes", ["include"] = new JsonArray("src") }, - }.ToJsonString() + "\n```\n"); - fx.Write("tools/probe/corpus/claims.json", """[{"id": "C1", "source": "README.md#a", "surfaces": ["s"]}, {"id": "C2", "source": "README.md#a", "surfaces": ["s"]}]"""); - fx.Write("tools/probe/corpus/rows/Q.json", """{"claim": "C2", "rows": [{"row": {"x": "1", "y": "1"}}]}"""); - fx.Write("tools/probe/corpus/harness/Q.cs", "// probe Q\n"); - Registry(new JsonObject { ["claim"] = "C1", ["filter"] = "*P" }); - fx.Rows([("1", "1"), ("2", "2"), ("1", "2")]); - fx.Commit("two probes, C1 of three rows"); - } - - public void Dispose() - { - fx.Dispose(); - try { Directory.Delete(cache, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - - private void Registry(JsonObject p) => - fx.Write("tools/probe/corpus/registry.json", new JsonObject - { - ["probes"] = new JsonObject { ["P"] = p, ["Q"] = new JsonObject { ["claim"] = "C2", ["filter"] = "*Q" } }, - }.ToJsonString()); - - private (int Exit, string Out, string Err) Try(params string[] args) => TryEnding(Environment.NewLine, args); - - /// As , with the line end the output writers use, so a test sees Windows' output on any OS. - private (int Exit, string Out, string Err) TryEnding(string newLine, params string[] args) - { - var output = new StringWriter { NewLine = newLine }; var error = new StringWriter { NewLine = newLine }; - var context = new Context(fx.Root, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, output, error); - int exit; - try { exit = TryProbe.Run(context, new Args(args, new HashSet(StringComparer.Ordinal) { "no-build" }), adapter); } - catch (Refusal refusal) { error.WriteLine(refusal.Message); exit = refusal.ExitCode; } - return (exit, output.ToString(), error.ToString()); - } - - /// The output's lines, whatever line end the writer used. - private static string[] Lines(string output) => output.ReplaceLineEndings("\n").Split('\n'); - - [Theory] - [InlineData("\n")] - [InlineData("\r\n")] - public void It_runs_the_one_probe_and_prints_how_each_row_ended(string newLine) - { - var (exit, output, error) = TryEnding(newLine, "--probe", "P"); - exit.ShouldBe(7, output + error); - adapter.Builds.ShouldBe(1); - adapter.Runs.ShouldHaveSingleItem().Filter.ShouldBe("*P"); - adapter.Runs[0].Rows.ShouldBeNull("every row, as the registry runs it"); - var lines = Lines(output); - lines.ShouldContain(l => l.StartsWith(" P: Tests: 1 failed of 3 (exit 7, ", StringComparison.Ordinal)); - lines.ShouldContain(" #0 pass"); - lines.ShouldContain(" #1 violation: row 1 breaks the claim"); - lines.ShouldContain(" #2 pass"); - lines.ShouldContain("prober try: P: pass 2, violation 1; exit 7"); - } - - [Fact] - public void A_probe_that_passes_exits_0() - { - adapter.Violates = null; - var (exit, output, _) = Try("--probe", "P"); - exit.ShouldBe(0, output); - output.ShouldContain("prober try: P: pass 3; exit 0"); - } - - [Fact] - public void It_records_nothing_under_the_state_directory() - { - // A staged probe and a ledger with runs and evidence, as a round leaves them. - fx.Write(".claude/agent-memory-local/prober/branches/main/staging/probes/R.cs", "// staged\n"); - fx.Write(".claude/agent-memory-local/prober/branches/main/runs.jsonl", """{"probe": "P", "result": "pass"}""" + "\n"); - var before = Hash(fx.Memory); - Try("--probe", "P").Exit.ShouldBe(7); - Try("--probe", "P", "--rows", "0").Exit.ShouldBe(0); - Hash(fx.Memory).ShouldBe(before); - } - - [Fact] - public void Rows_runs_the_rows_given_one_stretch_at_a_time() - { - var (exit, output, _) = Try("--probe", "P", "--rows", "0,2"); - exit.ShouldBe(0, output); - adapter.Runs.Select(r => r.Rows).ShouldBe(["0-0", "2-2"]); - output.ShouldContain("#0 pass"); - output.ShouldContain("#2 pass"); - output.ShouldNotContain("#1 "); - Try("--probe", "P", "--rows", "1,2").Exit.ShouldBe(7); - adapter.Runs.Skip(2).Select(r => r.Rows).ShouldBe(["1-2"]); - } - - [Fact] - public void Rows_runs_each_row_in_the_variant_that_selects_it() - { - Registry(new JsonObject - { - ["claim"] = "C1", ["filter"] = "*P", - ["variants"] = new JsonArray(new JsonObject { ["PROBE_ONLY"] = "x=1" }, new JsonObject { ["PROBE_ONLY"] = "x=2" }), - }); - fx.Commit("variants"); - var (exit, output, _) = Try("--probe", "P", "--rows", "1,2"); - exit.ShouldBe(7, output); - adapter.Runs.Select(r => (r.Only, r.Rows)).ShouldBe([("x=1", "2-2"), ("x=2", "1-1")]); - output.ShouldContain(" P [PROBE_ONLY=x=1] rows 2-2: "); - } - - [Fact] - public void A_row_the_claim_does_not_have_is_refused_before_anything_runs() - { - var (exit, _, error) = Try("--probe", "P", "--rows", "3"); - exit.ShouldBe(2); - error.ShouldContain("--rows 3: the claim has 3 row(s), 0 to 2"); - adapter.Builds.ShouldBe(0); - adapter.Runs.ShouldBeEmpty(); - } - - [Fact] - public void A_probe_not_in_the_registry_is_refused() - { - var (exit, _, error) = Try("--probe", "Nope"); - exit.ShouldBe(2); - error.ShouldContain("no probe Nope in the registry"); - } - - [Fact] - public void No_build_runs_without_building() - { - Try("--probe", "P", "--no-build").Exit.ShouldBe(2, "no worktree yet, so nothing was ever built"); - Try("--probe", "P").Exit.ShouldBe(7); - Try("--probe", "P", "--no-build").Exit.ShouldBe(7); - adapter.Builds.ShouldBe(1); - adapter.Runs.Count.ShouldBe(2); - } - - [Fact] - public void A_failed_build_runs_nothing() - { - adapter.BuildFails = true; - var (exit, output, _) = Try("--probe", "P"); - exit.ShouldBe(1); - output.ShouldContain("Build: FAILED"); - adapter.Runs.ShouldBeEmpty(); - } - - [Fact] - public void The_staging_is_overlaid_where_the_probe_runs() - { - fx.Write(".claude/agent-memory-local/prober/branches/main/staging/probes/R.cs", "// staged\n"); - Try("--probe", "P").Exit.ShouldBe(7); - var worktree = Path.Combine(Directory.GetDirectories(cache).Single(), "wt"); - adapter.Worktrees.ShouldAllBe(w => w == worktree); - File.ReadAllText(Path.Combine(worktree, "probes", "R.cs")).ShouldBe("// staged\n"); - File.Exists(Path.Combine(worktree, "probes", "P.cs")).ShouldBeTrue(); - } - - /// Every file and directory under , by relative path and content. - private static string Hash(string dir) => - Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(string.Join("\n", - Directory.EnumerateFileSystemEntries(dir, "*", SearchOption.AllDirectories).Order(StringComparer.Ordinal) - .Select(p => Path.GetRelativePath(dir, p) + ":" + (File.Exists(p) ? Convert.ToHexString(SHA256.HashData(File.ReadAllBytes(p))) : "dir")))))); - - [Fact] - public void It_holds_the_replay_worktree_while_it_runs() - { - var (exit, output, error) = Try("--probe", "P"); - exit.ShouldBe(7, output + error); - adapter.WorktreeFreeDuringRun.ShouldBe([false], "a replay of the same checkout must not take the worktree while a try runs in it"); - } - - [Fact] - public void It_refuses_while_a_replay_holds_the_worktree_and_runs_nothing() - { - var context = new Context(fx.Root, new Dictionary { ["PROBE_CACHE_DIR"] = cache }, TextWriter.Null, TextWriter.Null); - var home = global::Prober.Replay.Home(context, new Ledger(context, null)); - using (global::Prober.Replay.HoldWorktree(home).ShouldNotBeNull()) - { - var (exit, _, error) = Try("--probe", "P"); - exit.ShouldBe(1); - error.ShouldContain($"a replay in this checkout is using {Path.Combine(home, "wt")}; run `prober try` when it ends"); - adapter.Runs.ShouldBeEmpty(); - } - Try("--probe", "P").Exit.ShouldBe(7, "the worktree is free again once the replay ends"); - } - - /// - /// Runs the probe the filter names over its claim's rows in the worktree, as the harness does: PROBE_ONLY and - /// PROBE_ROWS select, and each row it ran is one line of PROBE_OUT's jsonl. Row 1 of C1 violates. - /// - private sealed class FakeAdapter : IProbeAdapter - { - public int? Violates { get; set; } = 1; - public bool BuildFails { get; set; } - public int Builds { get; private set; } - public List<(string Filter, string? Only, string? Rows)> Runs { get; } = []; - public List Worktrees { get; } = []; - /// For each run, whether a replay could have taken the worktree (replay.lock beside it) while the probe ran. - public List WorktreeFreeDuringRun { get; } = []; - - public Ran Build(string worktree, IReadOnlyDictionary environment) - { - Builds++; - Worktrees.Add(worktree); - return BuildFails ? new Ran(1, "Build: FAILED\nerror X", "") : new Ran(0, "Build: OK", ""); - } - - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - Worktrees.Add(worktree); - using (var replay = global::Prober.Replay.HoldWorktree(Path.GetDirectoryName(worktree)!)) WorktreeFreeDuringRun.Add(replay is not null); - var only = environment.GetValueOrDefault("PROBE_ONLY"); - var range = environment.GetValueOrDefault("PROBE_ROWS"); - Runs.Add((filter, only, range)); - coverageFile.ShouldBeEmpty("try asks for no coverage"); - // The probe's own rows: P's are C1's, Q's C2's. - var probe = filter.TrimStart('*'); - var rows = JsonNode.Parse(File.ReadAllText(Path.Combine(worktree, "probes", "rows", probe + ".json")))!["rows"]!.AsArray(); - var (lo, hi) = range is null ? (0, int.MaxValue) : (int.Parse(range.Split('-')[0]), int.Parse(range.Split('-')[1])); - var lines = new List(); var failed = 0; - for (var i = 0; i < rows.Count; i++) - { - if (i < lo || i > hi || !global::Prober.Replay.Selected(Files.StringMap(rows[i]!["row"]), only ?? "")) continue; - var violates = probe == "P" && i == Violates; - if (violates) failed++; - lines.Add(new JsonObject - { - ["idx"] = i, ["category"] = violates ? "violation" : "pass", - ["reasons"] = violates ? new JsonArray("violation:row 1 breaks the claim") : new JsonArray(), ["note"] = "compared", - }.ToJsonString()); - } - var outDir = environment["PROBE_OUT"]!; - Directory.CreateDirectory(outDir); - File.WriteAllText(Path.Combine(outDir, probe + ".jsonl"), string.Join('\n', lines) + "\n"); - return failed > 0 ? new Ran(7, $"Tests: {failed} failed of {lines.Count}\n", "") : new Ran(0, $"Tests: {lines.Count} passed\n", ""); - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) => (null, "none"); - - public IReadOnlyDictionary Environment(string cacheDirectory) => new Dictionary(); - } -} diff --git a/test/CodoMetis.TypeKit.Samples/CodoMetis.TypeKit.Samples.csproj b/test/CodoMetis.TypeKit.Samples/CodoMetis.TypeKit.Samples.csproj index 8116a63d..12da029c 100644 --- a/test/CodoMetis.TypeKit.Samples/CodoMetis.TypeKit.Samples.csproj +++ b/test/CodoMetis.TypeKit.Samples/CodoMetis.TypeKit.Samples.csproj @@ -35,27 +35,4 @@ - - - - - - - - - - - - - diff --git a/test/oracles/Candidates.cs b/test/oracles/Candidates.cs new file mode 100644 index 00000000..52aa41ef --- /dev/null +++ b/test/oracles/Candidates.cs @@ -0,0 +1,112 @@ +using System.Text.Json; + +namespace CodoMetis.TypeKit.Oracles; + +/// +/// The known disagreements of an oracle, read from test/oracles/candidates.json, and the verdict a sweep +/// reaches once its failures are matched against them (design/adr/0112). +/// +/// +/// +/// An oracle sweep collects one line per disagreement and hands them here instead of asserting the list empty. +/// A line that matches no candidate fails. A line that matches a candidate whose issue is still empty fails too, +/// labelled [known candidate: family], so nothing is quarantined before it is filed. A line that matches a +/// candidate with an issue is written as SKIPPED [known candidate: family, issue] and does not fail. A +/// candidate that no line matched fails with candidate fixed: remove the entry, so the registry cannot +/// outlive the defect it recorded. +/// +/// +/// A candidate matches a failure line when the line contains the candidate's row text (ordinal): the stable +/// prefix of the sweep's own line, the operands and the operation, never the actual value, which changes with the fix. +/// This file is linked into every test project that holds an oracle rather than referenced. +/// +/// +public static class Candidates +{ + /// + /// One known disagreement: the oracle class, the row's stable text, its family and the issue that tracks it. + /// scopes the row to one test method of the class. + /// + public sealed record Candidate(string Oracle, string Row, string Family, string Issue, string? Method = null); + + private static readonly Lazy> All_ = new(Load); + + /// Every registered candidate. + public static IReadOnlyList All => All_.Value; + + /// Candidates registered for . + public static IReadOnlyList For(string oracle) => + [.. All.Where(candidate => string.Equals(candidate.Oracle, oracle, StringComparison.Ordinal))]; + + /// + /// Passes when every failure line is a filed candidate and every candidate of the oracle still fails; + /// otherwise fails with followed by the offending lines. + /// + /// The oracle class, as registered in test/oracles/oracles.json. + /// The sweep's disagreements, one line each. + /// The first line of the failure message, naming the sweep. + /// How many lines of the failure message to show. + /// The calling test method; a candidate scoped to another method is not this sweep's. + public static void Verdict(string oracle, IReadOnlyList failures, string header, int shown = 25, string? method = null) => + Judge([.. For(oracle).Where(candidate => candidate.Method is null || method is null || string.Equals(candidate.Method, method, StringComparison.Ordinal))], + failures, header, shown); + + /// over the candidates given directly, as SeedVerdictTests drives it. + internal static void Judge(IReadOnlyList known, IReadOnlyList failures, string header, int shown = 25) + { + var failing = new List(); + var unfiled = new List(); + var matched = new HashSet(); + + foreach (var line in failures) + { + var candidate = known.FirstOrDefault(c => line.Contains(c.Row, StringComparison.Ordinal)); + if (candidate is null) + { + failing.Add(OneLine(line)); + continue; + } + + matched.Add(candidate); + if (candidate.Issue.Length == 0) + unfiled.Add($"{SeedVerdict.KnownMarker} {candidate.Family}] {OneLine(line.TrimStart())}"); + else + Console.WriteLine($"SKIPPED [known candidate: {candidate.Family}, {candidate.Issue}] {OneLine(line.TrimStart())}"); + } + + foreach (var fixedCandidate in known.Where(candidate => !matched.Contains(candidate))) + failing.Add($"candidate fixed: remove the entry for '{fixedCandidate.Row}' ({fixedCandidate.Family}) from test/oracles/candidates.json"); + + // Known rows last, so a message cut short hides them first (SeedVerdict). + failing.AddRange(unfiled); + if (failing.Count == 0) return; + + Assert.Fail( + $"{OneLine(header)} ({failing.Count} failures):" + Environment.NewLine + + string.Join(Environment.NewLine, failing.Take(shown)) + + (failing.Count > shown ? $"{Environment.NewLine}{SeedVerdict.MorePrefix}{failing.Count - shown} more" : "")); + } + + /// A row as one line, line breaks shown as ⏎: the message is one row per line, and SeedVerdict reads it so. + private static string OneLine(string text) => + text.Contains('\n') || text.Contains('\r') ? text.Replace("\r\n", "⏎").Replace('\n', '⏎').Replace('\r', '⏎') : text; + + private static IReadOnlyList Load() + { + var path = Path.Combine(RepositoryRoot(), "test", "oracles", "candidates.json"); + using var stream = File.OpenRead(path); + return JsonSerializer.Deserialize>(stream, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }) + ?? throw new InvalidOperationException($"'{path}' holds no array."); + } + + private static string RepositoryRoot() + { + const string marker = "CodoMetis.TypeKit.slnx"; + for (var directory = new DirectoryInfo(AppContext.BaseDirectory); directory is not null; directory = directory.Parent) + { + if (File.Exists(Path.Combine(directory.FullName, marker))) return directory.FullName; + } + + throw new InvalidOperationException($"Could not find '{marker}' above '{AppContext.BaseDirectory}'."); + } +} diff --git a/test/oracles/README.md b/test/oracles/README.md new file mode 100644 index 00000000..4b325bb1 --- /dev/null +++ b/test/oracles/README.md @@ -0,0 +1,38 @@ +# Oracles + +How bug-finding works here as a system rather than one sweep per bug (design/adr/0112): a catalogue of what the +documents promise, an enumeration of what the API offers, oracle tests that check the library against an +independent answer, seeds that prove each oracle can fail, and a registry of the disagreements found but not yet +fixed. It is CodoMetis.ValueRanges' kit, kept to what pays for itself: no covering arrays, no ledger, no replay by +footprint, no agent. The oracles are ordinary tests in the projects that already have their harness, and run with +the suite. + +| File | What it holds | Held by | +|---|---|---| +| `claims.json` | One entry per sentence a consumer-facing document promises: its `source` heading, the `quote` verbatim, the `oracle` kind, the `surfaces` (public members, `TypeName.Member`, `*` a wildcard) and `heldBy`, the test classes that assert it. An empty `heldBy` is the worklist. | `OracleCatalogueTests` | +| `surface-waivers.json` | The public members no claim names, each with why it needs no oracle. A reason that starts `unread:` names a document not yet read for claims (#98). | `OracleSurfaceCoverageTests` | +| `oracles.json` | The test classes that are oracles: checks against an independent answer over many cases, not worked examples. | `OracleSeedTests` | +| `seeds/*.patch` | A defect in `src/` with a `Seed:` line, the `Oracles:` it fails and what `Fails:`. Every oracle has one. | `OracleSeedTests`, and `oracles seeds` | +| `candidates.json` | Disagreements an oracle found that are not fixed yet, each tied to an issue (`Candidates.Verdict`). | `OracleCandidateTests` | +| `axes.md` | What a consumer varies, which tests vary it, and the pairs none varies yet. | read by hand | + +`test/CodoMetis.TypeKit.Oracles.Tests` holds all of it in CI without building anything but itself: a quote its +document no longer holds, a surface or a test class that does not exist, a public member neither claimed nor +waived, an oracle without a seed, and a seed that no longer applies all fail there. + +Whether a seed is still **caught** takes a build, so it is a local tool, run before a release and after changing an +oracle or the code a seed patches: + +```bash +dotnet tools/Oracles/bin/Release/net10.0/oracles.dll seeds [name filter] # each seed: a copy, the patch, one project built, one class run +dotnet tools/Oracles/bin/Release/net10.0/oracles.dll status # the worklist: unheld claims, unread waivers, unseeded oracles, candidates +``` + +`seeds` copies the working tree (without `bin/`, `obj/` and `.git/`, so uncommitted work is included), applies the +patch, builds each named oracle's project and runs that one class. A seed is caught when one of the class's tests +fails with a row that is not a known candidate (`SeedVerdict`). One line per seed and oracle, `CAUGHT`, `MISSED` or +`ERROR`, and exit code 1 unless every pair is caught. + +To add an oracle: write the test class, register it in `oracles.json`, write a seed by planting the defect it +guards against, `git diff` it into `seeds/.patch` under its header lines, undo the edit, and run +`oracles seeds `. diff --git a/test/oracles/SeedVerdict.cs b/test/oracles/SeedVerdict.cs new file mode 100644 index 00000000..4fcd1c85 --- /dev/null +++ b/test/oracles/SeedVerdict.cs @@ -0,0 +1,41 @@ +namespace CodoMetis.TypeKit.Oracles; + +/// +/// Whether a test that failed with a seed planted caught it: the rule oracles seeds applies to each +/// failed test, compiled into tools/Oracles and linked into CodoMetis.TypeKit.Oracles.Tests +/// (SeedVerdictTests), so the two cannot disagree (design/adr/0112). +/// +/// +/// +/// A sweep reports through Candidates.Verdict: a header line, then one line per failing row, where a +/// row that matches an unfiled candidate starts with . A failed test catches the +/// seed when at least one of its rows is not a known candidate. Counting a test as known whenever its +/// message held the marker anywhere read a seed that broke a row beside a known one as missed, as +/// CodoMetis.ValueRanges found (its #55). +/// +/// +/// Candidates.Verdict lists the other rows before the known ones, so a message cut short +/// (… and N more) hides known rows first: when every row shown is known, the hidden ones are too. +/// A message with no known row at all is any other assertion, and catches. +/// +/// +public static class SeedVerdict +{ + /// The prefix Candidates.Verdict gives a row that matches an unfiled candidate. + public const string KnownMarker = "[known candidate:"; + + /// The line Candidates.Verdict ends a cut-short message with. + public const string MorePrefix = "… and "; + + /// Whether a failed test's message holds at least one row that is not a known candidate. + public static bool Catches(string message) + { + var lines = message.Split('\n').Select(line => line.Trim()).Where(line => line.Length > 0).ToList(); + if (!lines.Any(IsKnown)) return true; + + // A Verdict message: the first line is its header, the last may say how many rows were cut. + return lines.Skip(1).Any(line => !IsKnown(line) && !line.StartsWith(MorePrefix, StringComparison.Ordinal)); + } + + private static bool IsKnown(string line) => line.StartsWith(KnownMarker, StringComparison.Ordinal); +} diff --git a/test/oracles/axes.md b/test/oracles/axes.md new file mode 100644 index 00000000..e5851d9e --- /dev/null +++ b/test/oracles/axes.md @@ -0,0 +1,44 @@ +# What a consumer varies + +The claims say what is promised, and the surface says what is offered. Neither says which settings a consumer +combines: the JSON options of the host, the OpenAPI version, MVC or a minimal API, the EF provider, the shape of +their own type. This is the hand-written list (design/adr/0112): one section per surface family, each axis with +its values, the tests that already vary it, and the pairs no test varies yet, which are the next probe class. + +A **probe class** (`*ProbeTests`) is an ordinary test over the full product of a few axes, in the project that +already has the harness. Its oracle is the document's promise, it ends in `Candidates.Verdict`, and it is +registered in `oracles.json` with a seed like every other oracle. It stays under a minute: nothing replays it by +footprint, it runs with the suite. + +## The oracles this repository promises + +- **JSON parity (differential).** A shape with a value object and the same shape with the wrapped type serialize + to the same bytes, as a value, a property and a dictionary key. `JsonParityTests`. +- **Schema parity (differential).** The OpenAPI schema of a value-object property equals the wrapped type's. + `SchemaTests`, `NullablePositionTests`. +- **Column parity (differential).** The EF model gives a value-object property the wrapped type's column, and a + key the wrapped type's generation. `MappingTests`, `KeyGenerationVariantTests`, `ColumnFacetVariantTests`. +- **One set of rules (differential).** `TryFrom`, `Parse`, the JSON converter, the type converter and the + binders refuse what `Create` refuses. `EntryPointValidationTests`. +- **No refusal quotes the input (exception).** A sentinel in refused input never reaches a message. + `UnreadableInputTests`. +- **Off the wire (exception).** `Option` and `Result` refuse System.Text.Json in both directions. `NotWireTypeTests`. +- **Every member, by reflection (completeness).** A null delegate on every branch, an uninitialized result, the + context an asynchronous callback runs on. `NullDelegateTests`, `UninitializedResultTests`, `AsynchronousContextTests`. + +## The axes + +| Family | Axis | Values | Varied by | Pairs no test varies yet | +|---|---|---|---|---| +| JSON | the host's options | defaults, Web, a naming policy, a dictionary-key policy, number handling, a host converter | `JsonParityTests` | reference preservation beside a dictionary key | +| JSON | the wrapped type | every built-in the generators wrap, nullable or not | `JsonParityTests`, `JsonTests` | | +| OpenAPI | the version | 3.1, 3.0, 2.0 | `SchemaTests`, `FaultResponseTests` | a withheld fault name under 2.0 | +| HTTP | the host | minimal API, MVC with `[ApiController]`, MVC without | `MvcBindingTests`, `FaultStatusScopeTests` | | +| EF | the provider | SQLite, Npgsql, SQL Server | `KeyGenerationVariantTests`, `QueryTranslationVariantTests` | | +| EF | where a key sits | `KeyShapes` (`test/CodoMetis.TypeKit.EntityFrameworkCore.Tests/Variants/`) | `KeyGenerationVariantTests` | | +| EF | the query | `QueryShapes` | `QueryTranslationVariantTests` | | +| Analyzers | where a type argument is written, and what it is | `TypeArgumentSites`, `TypeArgumentKinds` (`test/CodoMetis.TypeKit.Analyzers.Tests/Variants/`) | `TypeArgumentConstraintVariantTests` | | +| Generation | the declaration's shape | record struct, record class, struct, class; sealed or not; over each wrapped kind | `BuildOutcomeTests`, `GeneratedSurfaceTests` | | + +An empty last column means nobody has looked yet, not that nothing is missing. Fill it when a feature lands or a +finding names a combination no test varied. diff --git a/test/oracles/candidates.json b/test/oracles/candidates.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/test/oracles/candidates.json @@ -0,0 +1 @@ +[] diff --git a/test/oracles/claims.json b/test/oracles/claims.json new file mode 100644 index 00000000..9859384a --- /dev/null +++ b/test/oracles/claims.json @@ -0,0 +1,2029 @@ +[ + { + "id": "C01-covers-every-decimal", + "source": "docs/json.md#decimals-in-one-spelling", + "quote": "Register either one once, and it covers every decimal: nullable ones, dictionary keys, and every value object over a decimal, since its JSON is the underlying type's.", + "claim": "Register either one once, and it covers every decimal: nullable ones, dictionary keys, and every value object over a decimal, since its JSON is the underlying type's.", + "oracle": "claim", + "surfaces": [ + "DecimalNumberJsonConverter.*", + "DecimalStringJsonConverter.*" + ], + "heldBy": [ + "DecimalJsonConvertersTests" + ] + }, + { + "id": "C01-number-is-a-number", + "source": "docs/json.md#decimals-in-one-spelling", + "quote": "**`DecimalNumberJsonConverter`** writes it as a number.", + "claim": "**`DecimalNumberJsonConverter`** writes it as a number.", + "oracle": "claim", + "surfaces": [ + "DecimalNumberJsonConverter.*", + "DecimalStringJsonConverter.*" + ], + "heldBy": [ + "DecimalJsonConvertersTests" + ] + }, + { + "id": "C01-reads-a-number-or-a-string", + "source": "docs/json.md#decimals-in-one-spelling", + "quote": "Both read a number, or a string holding one, and keep the scale they read.", + "claim": "Both read a number, or a string holding one, and keep the scale they read.", + "oracle": "claim", + "surfaces": [ + "DecimalNumberJsonConverter.*", + "DecimalStringJsonConverter.*" + ], + "heldBy": [ + "DecimalJsonConvertersTests" + ] + }, + { + "id": "C01-smallest-scale", + "source": "docs/json.md#decimals-in-one-spelling", + "quote": "Two converters write the smallest scale instead:", + "claim": "Two converters write the smallest scale instead:", + "oracle": "claim", + "surfaces": [ + "DecimalNumberJsonConverter.*", + "DecimalStringJsonConverter.*" + ], + "heldBy": [ + "DecimalJsonConvertersTests" + ] + }, + { + "id": "C01-string-is-a-string", + "source": "docs/json.md#decimals-in-one-spelling", + "quote": "**`DecimalStringJsonConverter`** writes it as a string.", + "claim": "**`DecimalStringJsonConverter`** writes it as a string.", + "oracle": "claim", + "surfaces": [ + "DecimalNumberJsonConverter.*", + "DecimalStringJsonConverter.*" + ], + "heldBy": [ + "DecimalJsonConvertersTests" + ] + }, + { + "id": "C02-hidden-is-an-error-in-both", + "source": "docs/text.md#required-and-optional", + "quote": "`Hidden` is an error in both cases.", + "claim": "`Hidden` is an error in both cases.", + "oracle": "claim", + "surfaces": [ + "StringTextExtensions.*", + "TextFault.*" + ], + "heldBy": [ + "StringTextExtensionsTests" + ] + }, + { + "id": "C02-null-is-blank", + "source": "docs/text.md#required-and-optional", + "quote": "A null string is `Blank`.", + "claim": "A null string is `Blank`.", + "oracle": "claim", + "surfaces": [ + "StringTextExtensions.*", + "TextFault.*" + ], + "heldBy": [ + "StringTextExtensionsTests" + ] + }, + { + "id": "C02-optional-blank-is-no-value", + "source": "docs/text.md#required-and-optional", + "quote": "For an optional one, a blank means \"no value\", and `AsOptionalText()` and `AsOptionalIdentifier()` return a `Result, TextFault>`.", + "claim": "For an optional one, a blank means \"no value\", and `AsOptionalText()` and `AsOptionalIdentifier()` return a `Result, TextFault>`.", + "oracle": "claim", + "surfaces": [ + "StringTextExtensions.*", + "TextFault.*" + ], + "heldBy": [ + "StringTextExtensionsTests" + ] + }, + { + "id": "C02-required-blank-is-an-error", + "source": "docs/text.md#required-and-optional", + "quote": "For a required field, `Blank` is an error.", + "claim": "For a required field, `Blank` is an error.", + "oracle": "claim", + "surfaces": [ + "StringTextExtensions.*", + "TextFault.*" + ], + "heldBy": [ + "StringTextExtensionsTests" + ] + }, + { + "id": "C03-detail-and-rule-intact", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "`Fault` (from CodoMetis.TypeKit) holds one error of either set, with its detail and rule intact.", + "claim": "`Fault` (from CodoMetis.TypeKit) holds one error of either set, with its detail and rule intact.", + "oracle": "claim", + "surfaces": [ + "TypeKitHttpResultExtensions.ToHttpResult", + "Fault.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C03-each-error-own-set", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "Each error is answered as its own set maps it.", + "claim": "Each error is answered as its own set maps it.", + "oracle": "claim", + "surfaces": [ + "TypeKitHttpResultExtensions.ToHttpResult", + "Fault.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C03-statuses-ascending", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "So its operation lists the statuses of both sets, in ascending order, with the problem types of both where they share a status.", + "claim": "So its operation lists the statuses of both sets, in ascending order, with the problem types of both where they share a status.", + "oracle": "claim", + "surfaces": [ + "Fault.*", + "TypeKitHttpResultExtensions.ToHttpResult" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C03-unmapped-set-stops-start", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "The host doesn't start while either set is unmapped.", + "claim": "The host doesn't start while either set is unmapped.", + "oracle": "claim", + "surfaces": [ + "TypeKitHttpResultExtensions.ToHttpResult", + "Fault.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C04-doc-omits-left-out", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#leaving-out-what-a-route-cannot-answer", + "quote": "The operation then lists no status and no problem type for a member left out.", + "claim": "The operation then lists no status and no problem type for a member left out.", + "oracle": "exception", + "surfaces": [ + "WithoutFaultsAttribute.*", + "TypeKitWithoutFaultsEndpointConventionBuilderExtensions.*" + ], + "heldBy": [ + "FaultExclusionTests" + ] + }, + { + "id": "C04-left-out-everywhere-stops-start", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#leaving-out-what-a-route-cannot-answer", + "quote": "**These stop the host from starting**, as for a status: a value or a name no member has, a status that every endpoint it's set on leaves out (on the endpoint itself, or on a group whose endpoints all leave the member out), and a group or a controller none of whose endpoints answers with the type.", + "claim": "**These stop the host from starting**, as for a status: a value or a name no member has, a status that every endpoint it's set on leaves out (on the endpoint itself, or on a group whose endpoints all leave the member out), and a group or a controller none of whose endpoints answers with the type.", + "oracle": "exception", + "surfaces": [ + "WithoutFaultsAttribute.*", + "TypeKitWithoutFaultsEndpointConventionBuilderExtensions.*" + ], + "heldBy": [ + "FaultExclusionTests" + ] + }, + { + "id": "C04-narrows-wider-status", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#leaving-out-what-a-route-cannot-answer", + "quote": "If a group gives `NotFound` a status and one endpoint inside leaves `NotFound` out, that endpoint drops it, and the group's other endpoints keep the status.", + "claim": "If a group gives `NotFound` a status and one endpoint inside leaves `NotFound` out, that endpoint drops it, and the group's other endpoints keep the status.", + "oracle": "exception", + "surfaces": [ + "WithoutFaultsAttribute.*", + "TypeKitWithoutFaultsEndpointConventionBuilderExtensions.*" + ], + "heldBy": [ + "FaultExclusionTests" + ] + }, + { + "id": "C04-reporting-left-out-throws", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#leaving-out-what-a-route-cannot-answer", + "quote": "Reporting a member left out anyway throws an `InvalidOperationException` naming the endpoint and the member, rather than answering with a status the document doesn't list.", + "claim": "Reporting a member left out anyway throws an `InvalidOperationException` naming the endpoint and the member, rather than answering with a status the document doesn't list.", + "oracle": "exception", + "surfaces": [ + "WithoutFaultsAttribute.*", + "TypeKitWithoutFaultsEndpointConventionBuilderExtensions.*" + ], + "heldBy": [ + "FaultExclusionTests" + ] + }, + { + "id": "C05-nested-chain", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused", + "quote": "A rule of a nested type is named after its nesting chain, whatever `QualifiedFaultNames` says.", + "claim": "A rule of a nested type is named after its nesting chain, whatever `QualifiedFaultNames` says.", + "oracle": "claim", + "surfaces": [ + "FaultRuleExtensions.*", + "FaultClosedSetRuleExtensions.*" + ], + "heldBy": [ + "FaultResponsePartsTests" + ] + }, + { + "id": "C05-no-namespace", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused", + "quote": "**The name carries no namespace**, which would publish your application's structure to every client.", + "claim": "**The name carries no namespace**, which would publish your application's structure to every client.", + "oracle": "claim", + "surfaces": [ + "FaultRuleExtensions.*", + "FaultClosedSetRuleExtensions.*" + ], + "heldBy": [ + "FaultResponsePartsTests" + ] + }, + { + "id": "C05-rule-qualified", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused", + "quote": "The problem carries it as `rule`, qualified with its type's name, so two types' `Blank` can be told apart:", + "claim": "The problem carries it as `rule`, qualified with its type's name, so two types' `Blank` can be told apart:", + "oracle": "claim", + "surfaces": [ + "FaultRuleExtensions.*", + "FaultClosedSetRuleExtensions.*" + ], + "heldBy": [ + "FaultResponsePartsTests" + ] + }, + { + "id": "C05-stays-the-errors", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused", + "quote": "The status, the mapping and the document stay the error's.", + "claim": "The status, the mapping and the document stay the error's.", + "oracle": "claim", + "surfaces": [ + "FaultRuleExtensions.*", + "FaultClosedSetRuleExtensions.*" + ], + "heldBy": [ + "FaultResponsePartsTests" + ] + }, + { + "id": "C05-unnamed-value-throws", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused", + "quote": "A value no member names, such as a combination of flags or a cast number, throws where it's given.", + "claim": "A value no member names, such as a combination of flags or a cast number, throws where it's given.", + "oracle": "claim", + "surfaces": [ + "FaultRuleExtensions.*", + "FaultClosedSetRuleExtensions.*" + ], + "heldBy": [ + "FaultResponsePartsTests" + ] + }, + { + "id": "C06-description-as-detail", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#a-closed-set-as-the-fault-type", + "quote": "The description becomes the problem's `detail`, so a client can show it.", + "claim": "The description becomes the problem's `detail`, so a client can show it.", + "oracle": "claim", + "surfaces": [ + "FaultKind.*", + "IFault.*", + "FaultResponse.For" + ], + "heldBy": [] + }, + { + "id": "C06-kind-gives-status", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#a-closed-set-as-the-fault-type", + "quote": "The kind gives the status:", + "claim": "The kind gives the status:", + "oracle": "claim", + "surfaces": [ + "FaultKind.*", + "IFault.*", + "FaultResponse.For" + ], + "heldBy": [] + }, + { + "id": "C06-member-must-have-kind", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#a-closed-set-as-the-fault-type", + "quote": "**A member must have a kind.** A member whose kind is `default`, which is no kind, fails this call.", + "claim": "**A member must have a kind.** A member whose kind is `default`, which is no kind, fails this call.", + "oracle": "claim", + "surfaces": [ + "FaultKind.*", + "IFault.*", + "FaultResponse.For" + ], + "heldBy": [] + }, + { + "id": "C06-no-description-no-detail", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#a-closed-set-as-the-fault-type", + "quote": "A member without one has no `detail`.", + "claim": "A member without one has no `detail`.", + "oracle": "claim", + "surfaces": [ + "FaultKind.*", + "IFault.*", + "FaultResponse.For" + ], + "heldBy": [] + }, + { + "id": "C07-by-kind", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#every-fault-set-at-once", + "quote": "every fault set an endpoint answers with, by its kind", + "claim": "every fault set an endpoint answers with, by its kind", + "oracle": "claim", + "surfaces": [ + "TypeKitFaultResponsesServiceCollectionExtensions.*", + "TypeKitClosedSetFaultResponsesServiceCollectionExtensions.*" + ], + "heldBy": [ + "FaultSetDefaultTests" + ] + }, + { + "id": "C07-enum-needs-own-mapping", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#every-fault-set-at-once", + "quote": "Neither has a kind, and the host doesn't start while an endpoint answers with one that's unmapped.", + "claim": "Neither has a kind, and the host doesn't start while an endpoint answers with one that's unmapped.", + "oracle": "claim", + "surfaces": [ + "TypeKitFaultResponsesServiceCollectionExtensions.*", + "TypeKitClosedSetFaultResponsesServiceCollectionExtensions.*" + ], + "heldBy": [ + "FaultSetDefaultTests" + ] + }, + { + "id": "C07-member-without-kind-stops-start", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#every-fault-set-at-once", + "quote": "A member with no kind stops the start, and so does one the mapping throws for or gives a status that isn't an error.", + "claim": "A member with no kind stops the start, and so does one the mapping throws for or gives a status that isn't an error.", + "oracle": "claim", + "surfaces": [ + "TypeKitClosedSetFaultResponsesServiceCollectionExtensions.*", + "TypeKitFaultResponsesServiceCollectionExtensions.*" + ], + "heldBy": [ + "FaultSetDefaultTests" + ] + }, + { + "id": "C07-own-mapping", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#every-fault-set-at-once", + "quote": "The mapping can be your own. It reads each member's kind and description through `IFault`:", + "claim": "The mapping can be your own. It reads each member's kind and description through `IFault`:", + "oracle": "claim", + "surfaces": [ + "TypeKitFaultResponsesServiceCollectionExtensions.*", + "TypeKitClosedSetFaultResponsesServiceCollectionExtensions.*" + ], + "heldBy": [ + "FaultSetDefaultTests" + ] + }, + { + "id": "C07-own-set-keeps-mapping", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#every-fault-set-at-once", + "quote": "A set mapped on its own keeps its mapping.", + "claim": "A set mapped on its own keeps its mapping.", + "oracle": "claim", + "surfaces": [ + "TypeKitFaultResponsesServiceCollectionExtensions.*", + "TypeKitClosedSetFaultResponsesServiceCollectionExtensions.*" + ], + "heldBy": [ + "FaultSetDefaultTests" + ] + }, + { + "id": "C08-bare-names-warn", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "With bare names, the default, that's `AccountFault.NotFound` beside an `EditFault.NotFound`.", + "claim": "With bare names, the default, that's `AccountFault.NotFound` beside an `EditFault.NotFound`.", + "oracle": "claim", + "surfaces": [ + "FaultResponseOptions.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C08-qualified-chain-warns", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "With qualified names, it's two sets with one nesting chain in two namespaces, since the name carries no namespace.", + "claim": "With qualified names, it's two sets with one nesting chain in two namespaces, since the name carries no namespace.", + "oracle": "claim", + "surfaces": [ + "FaultResponseOptions.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C08-qualified-names-fix", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "Fix it with `QualifiedFaultNames`, a rename, or by leaving one out of the route", + "claim": "Fix it with `QualifiedFaultNames`, a rename, or by leaving one out of the route", + "oracle": "claim", + "surfaces": [ + "FaultResponseOptions.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C08-warning-names-both", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", + "quote": "A client reads the two errors as one, so the host logs a warning at startup naming both.", + "claim": "A client reads the two errors as one, so the host logs a warning at startup naming both.", + "oracle": "claim", + "surfaces": [ + "FaultResponseOptions.*" + ], + "heldBy": [ + "ComposedFaultResponseTests" + ] + }, + { + "id": "C09-equal-by-the-wrapped-value", + "source": "CHANGELOG.md", + "quote": "Over a base record, a value object's equality is its wrapped value's", + "claim": "Over a base record, a value object's equality is its wrapped value's", + "oracle": "metamorphic", + "surfaces": [ + "IValueObject.*" + ], + "heldBy": [] + }, + { + "id": "C09-in-a-collection-of-the-base", + "source": "CHANGELOG.md", + "quote": "in a collection of the base too, whatever equality the base declares.", + "claim": "in a collection of the base too, whatever equality the base declares.", + "oracle": "metamorphic", + "surfaces": [ + "IValueObject.*" + ], + "heldBy": [] + }, + { + "id": "C10-ignore-cycles-unaffected", + "source": "src/CodoMetis.TypeKit.Generators/README.md#json", + "quote": "a struct of such values, and `ReferenceHandler.IgnoreCycles`.", + "claim": "a struct of such values, and `ReferenceHandler.IgnoreCycles`.", + "oracle": "claim", + "surfaces": [ + "GeneratedJson.*" + ], + "heldBy": [ + "ReferenceHandlingTests" + ] + }, + { + "id": "C10-own-converters-unaffected", + "source": "src/CodoMetis.TypeKit.Generators/README.md#json", + "quote": "anything a converter of your own writes, on the options or on one property", + "claim": "anything a converter of your own writes, on the options or on one property", + "oracle": "claim", + "surfaces": [ + "GeneratedJson.*" + ], + "heldBy": [ + "ReferenceHandlingTests" + ] + }, + { + "id": "C10-refused-where-references-could-be-written", + "source": "src/CodoMetis.TypeKit.Generators/README.md#json", + "quote": "**Preserved references** (`ReferenceHandler.Preserve`) throw a `NotSupportedException` where the serializer could write `$id` or `$ref` inside the underlying value.", + "claim": "**Preserved references** (`ReferenceHandler.Preserve`) throw a `NotSupportedException` where the serializer could write `$id` or `$ref` inside the underlying value.", + "oracle": "claim", + "surfaces": [ + "GeneratedJson.*" + ], + "heldBy": [ + "ReferenceHandlingTests" + ] + }, + { + "id": "C10-value-converters-unaffected", + "source": "src/CodoMetis.TypeKit.Generators/README.md#json", + "quote": "These are unaffected: a value the serializer writes with a value converter (a number, a string, a `Guid`, a `Uri`)", + "claim": "These are unaffected: a value the serializer writes with a value converter (a number, a string, a `Guid`, a `Uri`)", + "oracle": "claim", + "surfaces": [ + "GeneratedJson.*" + ], + "heldBy": [ + "ReferenceHandlingTests" + ] + }, + { + "id": "C11-abstract-string-constructor", + "source": "CHANGELOG.md", + "quote": "or an abstract class's string constructor, no longer breaks the build; the value object has no parsing.", + "claim": "or an abstract class's string constructor, no longer breaks the build; the value object has no parsing.", + "oracle": "claim", + "surfaces": [ + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "C11-implicit-result", + "source": "CHANGELOG.md", + "quote": "A wrapped type's `Parse` whose result can't be assigned to it", + "claim": "A wrapped type's `Parse` whose result can't be assigned to it", + "oracle": "claim", + "surfaces": [ + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "C11-parsing-where-it-can-be-parsed", + "source": "CHANGELOG.md", + "quote": "`IParsable`/`ISpanParsable`/`IUtf8SpanParsable`, formatting in the invariant culture", + "claim": "`IParsable`/`ISpanParsable`/`IUtf8SpanParsable`, formatting in the invariant culture", + "oracle": "claim", + "surfaces": [ + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "C11-ref-text", + "source": "CHANGELOG.md", + "quote": "or that takes its text by `ref`", + "claim": "or that takes its text by `ref`", + "oracle": "claim", + "surfaces": [ + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "C12-every-position", + "source": "docs/json.md#describing-what-a-converter-writes", + "quote": "With CodoMetis.TypeKit.AspNetCore, `AddTypeKit()` writes the same descriptions into the OpenAPI document, in every position, a list's elements and a dictionary's values included.", + "claim": "With CodoMetis.TypeKit.AspNetCore, `AddTypeKit()` writes the same descriptions into the OpenAPI document, in every position, a list's elements and a dictionary's values included.", + "oracle": "claim", + "surfaces": [ + "IDescribedJsonConverter.*", + "JsonSchemaDescriptions.*", + "JsonSchemaDescription.*" + ], + "heldBy": [ + "DescribedSchemaTests" + ] + }, + { + "id": "C12-options-describe", + "source": "docs/json.md#describing-what-a-converter-writes", + "quote": "**A converter someone else wrote**, or the serializer's own enum converter, is described in the options by `JsonSchemaDescriptions`.", + "claim": "**A converter someone else wrote**, or the serializer's own enum converter, is described in the options by `JsonSchemaDescriptions`.", + "oracle": "claim", + "surfaces": [ + "IDescribedJsonConverter.*", + "JsonSchemaDescriptions.*", + "JsonSchemaDescription.*" + ], + "heldBy": [ + "DescribedSchemaTests" + ] + }, + { + "id": "C12-own-converter-describes-itself", + "source": "docs/json.md#describing-what-a-converter-writes", + "quote": "**Your own converter** implements `IDescribedJsonConverter` and describes itself, as both decimal converters do.", + "claim": "**Your own converter** implements `IDescribedJsonConverter` and describes itself, as both decimal converters do.", + "oracle": "claim", + "surfaces": [ + "IDescribedJsonConverter.*", + "JsonSchemaDescriptions.*", + "JsonSchemaDescription.*" + ], + "heldBy": [ + "DescribedSchemaTests" + ] + }, + { + "id": "C12-parameter-keeps-aspnet", + "source": "docs/json.md#describing-what-a-converter-writes", + "quote": "So it keeps the description ASP.NET gives the type without your converters", + "claim": "So it keeps the description ASP.NET gives the type without your converters", + "oracle": "claim", + "surfaces": [ + "IDescribedJsonConverter.*", + "JsonSchemaDescriptions.*", + "JsonSchemaDescription.*" + ], + "heldBy": [ + "DescribedSchemaTests" + ] + }, + { + "id": "C13-absent-is-default", + "source": "docs/merge-patches.md#required-constructor-parameters", + "quote": "a property the request leaves out keeps its default, which is `Absent`.", + "claim": "a property the request leaves out keeps its default, which is `Absent`.", + "oracle": "claim", + "surfaces": [ + "PatchJsonConverterFactory.*", + "PatchState.*" + ], + "heldBy": [ + "PatchSchemaTests" + ] + }, + { + "id": "C13-doc-optional-where-absent", + "source": "docs/merge-patches.md#required-constructor-parameters", + "quote": "`AddTypeKit()` leaves a patch out of `required` where the serializer lets it be absent, and keeps it there where the options reject a body without it.", + "claim": "`AddTypeKit()` leaves a patch out of `required` where the serializer lets it be absent, and keeps it there where the options reject a body without it.", + "oracle": "claim", + "surfaces": [ + "PatchJsonConverterFactory.*", + "PatchState.*" + ], + "heldBy": [ + "PatchSchemaTests" + ] + }, + { + "id": "C13-doc-required-where-rejected", + "source": "docs/merge-patches.md#required-constructor-parameters", + "quote": "So the document never calls a field optional when the endpoint rejects a request without it.", + "claim": "So the document never calls a field optional when the endpoint rejects a request without it.", + "oracle": "claim", + "surfaces": [ + "PatchJsonConverterFactory.*", + "PatchState.*" + ], + "heldBy": [ + "PatchSchemaTests" + ] + }, + { + "id": "C14-application-json-declared", + "source": "CHANGELOG.md", + "quote": "OpenAPI: a problem response an endpoint declares as `application/json`, such as `Produces(404)` or `[ProducesResponseType(404)]`, describes `fault` and `rule` and names its problem types, and keeps its media type", + "claim": "OpenAPI: a problem response an endpoint declares as `application/json`, such as `Produces(404)` or `[ProducesResponseType(404)]`, describes `fault` and `rule` and names its problem types, and keeps its media type", + "oracle": "claim", + "surfaces": [ + "FaultProblem.*", + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [ + "FaultResponseTests" + ] + }, + { + "id": "C14-ascending-with-declared", + "source": "CHANGELOG.md", + "quote": "OpenAPI: an operation with fault responses lists every status ascending, the ones its endpoint declares itself among them", + "claim": "OpenAPI: an operation with fault responses lists every status ascending, the ones its endpoint declares itself among them", + "oracle": "claim", + "surfaces": [ + "FaultProblem.*", + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [ + "FaultResponseTests" + ] + }, + { + "id": "C14-declared-describes-fault", + "source": "CHANGELOG.md", + "quote": "OpenAPI: a problem response an endpoint declares itself (`ProducesProblem`, `[ProducesResponseType]`) describes `fault`, and names its problem types.", + "claim": "OpenAPI: a problem response an endpoint declares itself (`ProducesProblem`, `[ProducesResponseType]`) describes `fault`, and names its problem types.", + "oracle": "claim", + "surfaces": [ + "FaultProblem.*", + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [ + "FaultResponseTests" + ] + }, + { + "id": "C15-builder-reaches-doc", + "source": "CHANGELOG.md", + "quote": "OpenAPI: a `WithFaultStatus` on the builder `MapControllers()` returns reaches the document, as it reached the response.", + "claim": "OpenAPI: a `WithFaultStatus` on the builder `MapControllers()` returns reaches the document, as it reached the response.", + "oracle": "claim", + "surfaces": [ + "FaultStatusAttribute.*", + "TypeKitFaultStatusEndpointConventionBuilderExtensions.*" + ], + "heldBy": [] + }, + { + "id": "C15-status-per-scope", + "source": "CHANGELOG.md", + "quote": "`WithFaultStatus`/`[FaultStatus]` per endpoint, group or controller", + "claim": "`WithFaultStatus`/`[FaultStatus]` per endpoint, group or controller", + "oracle": "claim", + "surfaces": [ + "FaultStatusAttribute.*", + "TypeKitFaultStatusEndpointConventionBuilderExtensions.*" + ], + "heldBy": [] + }, + { + "id": "C15-without-faults-leaves-doc", + "source": "CHANGELOG.md", + "quote": "**`WithoutFaults`** and `[WithoutFaults]`: a route leaves out of its document the members it never answers with, and reporting one throws", + "claim": "**`WithoutFaults`** and `[WithoutFaults]`: a route leaves out of its document the members it never answers with, and reporting one throws", + "oracle": "claim", + "surfaces": [ + "FaultStatusAttribute.*", + "TypeKitFaultStatusEndpointConventionBuilderExtensions.*" + ], + "heldBy": [] + }, + { + "id": "C16-differing-refused", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", + "quote": "Otherwise building the document fails rather than describe JSON the controllers don't write.", + "claim": "Otherwise building the document fails rather than describe JSON the controllers don't write.", + "oracle": "claim", + "surfaces": [ + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [] + }, + { + "id": "C16-error-names-type-and-descriptions", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", + "quote": "The error names the type and what each set of options says of it, also for a type held only inside a patch.", + "claim": "The error names the type and what each set of options says of it, also for a type held only inside a patch.", + "oracle": "claim", + "surfaces": [ + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [] + }, + { + "id": "C16-same-converters-build", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", + "quote": "A host with controllers registers the same converters and descriptions on both, in the same order.", + "claim": "A host with controllers registers the same converters and descriptions on both, in the same order.", + "oracle": "claim", + "surfaces": [ + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [] + }, + { + "id": "C17-a-cast-naming-no-member", + "source": "src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0014", + "quote": "A `FaultKind` or a `ConstructorAccessibility` that names no member: a cast", + "claim": "A `FaultKind` or a `ConstructorAccessibility` that names no member: a cast", + "oracle": "exception", + "surfaces": [ + "FaultKind.*", + "ConstructorAccessibility.*", + "RequireParameterlessConstructorAttribute.*" + ], + "heldBy": [ + "UndefinedEnumValueAnalyzerTests" + ] + }, + { + "id": "C17-a-member-is-silent", + "source": "src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0014", + "quote": "public static readonly ImportFault Duplicate = new(FaultKind.Conflict);", + "claim": "public static readonly ImportFault Duplicate = new(FaultKind.Conflict);", + "oracle": "exception", + "surfaces": [ + "FaultKind.*", + "ConstructorAccessibility.*", + "RequireParameterlessConstructorAttribute.*" + ], + "heldBy": [ + "UndefinedEnumValueAnalyzerTests" + ] + }, + { + "id": "C17-constructor-accessibility-too", + "source": "src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0014", + "quote": "[RequireParameterlessConstructor((ConstructorAccessibility)7)] // CMTK0014: no member, read as public", + "claim": "[RequireParameterlessConstructor((ConstructorAccessibility)7)] // CMTK0014: no member, read as public", + "oracle": "exception", + "surfaces": [ + "FaultKind.*", + "ConstructorAccessibility.*", + "RequireParameterlessConstructorAttribute.*" + ], + "heldBy": [ + "UndefinedEnumValueAnalyzerTests" + ] + }, + { + "id": "C17-default-and-zero", + "source": "src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0014", + "quote": "`default(FaultKind)`, a zero", + "claim": "`default(FaultKind)`, a zero", + "oracle": "exception", + "surfaces": [ + "FaultKind.*", + "ConstructorAccessibility.*", + "RequireParameterlessConstructorAttribute.*" + ], + "heldBy": [ + "UndefinedEnumValueAnalyzerTests" + ] + }, + { + "id": "C17-reported-where-written", + "source": "src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0014", + "quote": "Both are reported where the value is written:", + "claim": "Both are reported where the value is written:", + "oracle": "exception", + "surfaces": [ + "FaultKind.*", + "ConstructorAccessibility.*", + "RequireParameterlessConstructorAttribute.*" + ], + "heldBy": [ + "UndefinedEnumValueAnalyzerTests" + ] + }, + { + "id": "C18-a-warning-and-generated", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "A warning, and the value object is generated.", + "claim": "A warning, and the value object is generated.", + "oracle": "exception", + "surfaces": [ + "IValueObject.*" + ], + "heldBy": [] + }, + { + "id": "C18-generated-equality-never-calls-the-base", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "Over a base record, the generated `Equals(TSelf)` and `GetHashCode()` compare the underlying value alone, and never call the base's.", + "claim": "Over a base record, the generated `Equals(TSelf)` and `GetHashCode()` compare the underlying value alone, and never call the base's.", + "oracle": "exception", + "surfaces": [ + "IValueObject.*" + ], + "heldBy": [] + }, + { + "id": "C18-names-each-base-member", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "So a hand-written `Equals(TBase)`, `GetHashCode()` or `IEquatable.Equals` on a base record isn't used, and a warning names it (CMTK1023).", + "claim": "So a hand-written `Equals(TBase)`, `GetHashCode()` or `IEquatable.Equals` on a base record isn't used, and a warning names it (CMTK1023).", + "oracle": "exception", + "surfaces": [ + "IValueObject.*" + ], + "heldBy": [] + }, + { + "id": "C19-a-pair-once-at-the-later-argument", + "source": "docs/type-constraints.md#the-kind-of-a-type-argument", + "quote": "A breach is reported once, at the later argument.", + "claim": "A breach is reported once, at the later argument.", + "oracle": "exception", + "surfaces": [ + "InterfaceAttribute.*", + "UnsealedAttribute.*", + "ValueObjectAttribute.*", + "FlagsEnumAttribute.*", + "ReadOnlyStructAttribute.*", + "SealedAttribute.*", + "RecordAttribute.*", + "UnrelatedAttribute.*" + ], + "heldBy": [ + "TypeArgumentConstraintKindTests" + ] + }, + { + "id": "C19-flags-enum-and-read-only-struct", + "source": "docs/type-constraints.md#the-kind-of-a-type-argument", + "quote": "**`[FlagsEnum]` and `[ReadOnlyStruct]`** narrow what `where T : Enum` and `where T : struct` admit.", + "claim": "**`[FlagsEnum]` and `[ReadOnlyStruct]`** narrow what `where T : Enum` and `where T : struct` admit.", + "oracle": "exception", + "surfaces": [ + "InterfaceAttribute.*", + "UnsealedAttribute.*", + "ValueObjectAttribute.*", + "FlagsEnumAttribute.*", + "ReadOnlyStructAttribute.*", + "SealedAttribute.*", + "RecordAttribute.*", + "UnrelatedAttribute.*" + ], + "heldBy": [ + "TypeArgumentConstraintKindTests" + ] + }, + { + "id": "C19-interface-and-unsealed", + "source": "docs/type-constraints.md#the-kind-of-a-type-argument", + "quote": "**`[Interface]` and `[Unsealed]`** are what a proxy needs: a contract to implement, or a class to derive from.", + "claim": "**`[Interface]` and `[Unsealed]`** are what a proxy needs: a contract to implement, or a class to derive from.", + "oracle": "exception", + "surfaces": [ + "InterfaceAttribute.*", + "UnsealedAttribute.*", + "ValueObjectAttribute.*", + "FlagsEnumAttribute.*", + "ReadOnlyStructAttribute.*", + "SealedAttribute.*", + "RecordAttribute.*", + "UnrelatedAttribute.*" + ], + "heldBy": [ + "TypeArgumentConstraintKindTests" + ] + }, + { + "id": "C19-methods-the-compiler-calls", + "source": "docs/type-constraints.md#the-kind-of-a-type-argument", + "quote": "**Methods the compiler calls for you:** a `foreach`'s `GetEnumerator`, an `await`'s `GetAwaiter`, a `Deconstruct` (in `var (a, b) = x`, a `foreach`, or a pattern like `x is (1, 2)`), and a collection expression's `Add` or builder method.", + "claim": "**Methods the compiler calls for you:** a `foreach`'s `GetEnumerator`, an `await`'s `GetAwaiter`, a `Deconstruct` (in `var (a, b) = x`, a `foreach`, or a pattern like `x is (1, 2)`), and a collection expression's `Add` or builder method.", + "oracle": "exception", + "surfaces": [ + "InterfaceAttribute.*", + "UnsealedAttribute.*", + "ValueObjectAttribute.*", + "FlagsEnumAttribute.*", + "ReadOnlyStructAttribute.*", + "SealedAttribute.*", + "RecordAttribute.*", + "UnrelatedAttribute.*" + ], + "heldBy": [ + "TypeArgumentConstraintKindTests" + ] + }, + { + "id": "C19-value-object-and-closed-set", + "source": "docs/type-constraints.md#the-kind-of-a-type-argument", + "quote": "**`[ValueObject]` and `[ClosedSet]`** accept their marker interface with any type argument.", + "claim": "**`[ValueObject]` and `[ClosedSet]`** accept their marker interface with any type argument.", + "oracle": "exception", + "surfaces": [ + "InterfaceAttribute.*", + "UnsealedAttribute.*", + "ValueObjectAttribute.*", + "FlagsEnumAttribute.*", + "ReadOnlyStructAttribute.*", + "SealedAttribute.*", + "RecordAttribute.*", + "UnrelatedAttribute.*" + ], + "heldBy": [ + "TypeArgumentConstraintKindTests" + ] + }, + { + "id": "C20-a-failure-says-the-outcome", + "source": "src/CodoMetis.TypeKit.Testing/README.md", + "quote": "**A failure says what the outcome was**", + "claim": "**A failure says what the outcome was**", + "oracle": "claim", + "surfaces": [ + "FaultAssertions.*" + ], + "heldBy": [ + "ComposedFaultAssertionTests" + ] + }, + { + "id": "C20-fails-unless-it-holds-that-reason", + "source": "src/CodoMetis.TypeKit.Testing/README.md", + "quote": "`ShouldHold(reason)` fails unless the fault holds that reason, whichever of its types the reason belongs to.", + "claim": "`ShouldHold(reason)` fails unless the fault holds that reason, whichever of its types the reason belongs to.", + "oracle": "claim", + "surfaces": [ + "FaultAssertions.*" + ], + "heldBy": [ + "ComposedFaultAssertionTests" + ] + }, + { + "id": "C20-hands-back-detail-and-rule", + "source": "src/CodoMetis.TypeKit.Testing/README.md", + "quote": "It hands back the `Fault` with its detail and rule intact.", + "claim": "It hands back the `Fault` with its detail and rule intact.", + "oracle": "claim", + "surfaces": [ + "FaultAssertions.*" + ], + "heldBy": [ + "ComposedFaultAssertionTests" + ] + }, + { + "id": "C20-uninitialized-fails", + "source": "src/CodoMetis.TypeKit.Testing/README.md", + "quote": "**An uninitialized result fails every assertion.**", + "claim": "**An uninitialized result fails every assertion.**", + "oracle": "claim", + "surfaces": [ + "FaultAssertions.*" + ], + "heldBy": [ + "ComposedFaultAssertionTests" + ] + }, + { + "id": "C20-whichever-of-its-types", + "source": "src/CodoMetis.TypeKit.Testing/README.md", + "quote": "whichever of its types the reason belongs to", + "claim": "whichever of its types the reason belongs to", + "oracle": "claim", + "surfaces": [ + "FaultAssertions.*" + ], + "heldBy": [ + "ComposedFaultAssertionTests" + ] + }, + { + "id": "C21-nullable-admits-null-as-the-wrapped-does", + "source": "README.md#what-you-get", + "quote": "Its OpenAPI schema is the one ASP.NET Core publishes for the underlying type.", + "claim": "Its OpenAPI schema is the one ASP.NET Core publishes for the underlying type.", + "oracle": "differential", + "surfaces": [ + "GeneratedJsonPlan.*", + "TypeKitOpenApiOptionsExtensions.AddTypeKit" + ], + "heldBy": [] + }, + { + "id": "C21-the-underlying-types-schema", + "source": "README.md#what-you-get", + "quote": "The JSON, the database column and the OpenAPI schema are the same as the underlying type's.", + "claim": "The JSON, the database column and the OpenAPI schema are the same as the underlying type's.", + "oracle": "differential", + "surfaces": [ + "TypeKitOpenApiOptionsExtensions.AddTypeKit", + "GeneratedJsonPlan.*" + ], + "heldBy": [] + }, + { + "id": "C22-abstract", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "An abstract type with a value-object marker. It would get no member, and a value held as it, of a type derived from it, would have no `Value` and be written as `{}`.", + "claim": "An abstract type with a value-object marker. It would get no member, and a value held as it, of a type derived from it, would have no `Value` and be written as `{}`.", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-closed-set-named-as-generated-member", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "a set itself named as one of them (a member can't have the name of its type)", + "claim": "a set itself named as one of them (a member can't have the name of its type)", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-equality-operator", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "So a hand-written `Equals(TSelf)`, `GetHashCode()`, `IEquatable.Equals`, or `operator ==` or `!=` between two of the type, fails the build (CMTK1011).", + "claim": "So a hand-written `Equals(TSelf)`, `GetHashCode()`, `IEquatable.Equals`, or `operator ==` or `!=` between two of the type, fails the build (CMTK1011).", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-every-error-links-the-table", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "Every error ends with a link to this table.", + "claim": "Every error ends with a link to this table.", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-generic-wrapped", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "A generic underlying type, a tuple included, fails the build (CMTK1005).", + "claim": "A generic underlying type, a tuple included, fails the build (CMTK1005).", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-named-as-generated-member", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "named `Value` or as another member the generators add (`From`, `TryFrom`, `FromKnownGood`, `Revalidate`, `Parse`, `TryParse`, `TryFormat`, `MinValue`, `MaxValue`, `CompareTo`)", + "claim": "named `Value` or as another member the generators add (`From`, `TryFrom`, `FromKnownGood`, `Revalidate`, `Parse`, `TryParse`, `TryFormat`, `MinValue`, `MaxValue`, `CompareTo`)", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-no-type-half-generated", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "A declaration that can't be generated fails the build, so no type is left half-generated.", + "claim": "A declaration that can't be generated fails the build, so no type is left half-generated.", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-over-object", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "or wrapping `object`, `System.Enum`, an array, a pointer, a nullable type, a generic type (a tuple included) or a value object (itself included).", + "claim": "or wrapping `object`, `System.Enum`, an array, a pointer, a nullable type, a generic type (a tuple included) or a value object (itself included).", + "oracle": "exception", + "surfaces": [ + "IClosedSet.*", + "IPlainValueObject.*", + "IValidatedValue.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-over-value-object", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "or a value object (itself included). Wrap what the other value object wraps instead.", + "claim": "or a value object (itself included). Wrap what the other value object wraps instead.", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C22-unsealed-record-class", + "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", + "quote": "A record class not declared `sealed`.", + "claim": "A record class not declared `sealed`.", + "oracle": "exception", + "surfaces": [ + "IPlainValueObject.*", + "IValidatedValue.*", + "IClosedSet.*" + ], + "heldBy": [ + "BuildOutcomeTests" + ] + }, + { + "id": "C23-withheld-host-sees", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-a-client-must-not-tell-apart", + "quote": "**Your host still sees the fault.** `IFaultFeature` carries its name, and `NameWithheld` says the mapping keeps it from the client", + "claim": "**Your host still sees the fault.** `IFaultFeature` carries its name, and `NameWithheld` says the mapping keeps it from the client", + "oracle": "claim", + "surfaces": [ + "IFaultFeature.*" + ], + "heldBy": [ + "WithheldFaultNameTests" + ] + }, + { + "id": "C23-withheld-says-nothing", + "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-a-client-must-not-tell-apart", + "quote": "**The problem says nothing of the member**: no `fault`, no `rule`, and no fault set member's description as its `detail`.", + "claim": "**The problem says nothing of the member**: no `fault`, no `rule`, and no fault set member's description as its `detail`.", + "oracle": "claim", + "surfaces": [ + "FaultResponse.*" + ], + "heldBy": [ + "WithheldFaultNameTests" + ] + }, + { + "id": "C24-content-comes-back", + "source": "src/CodoMetis.TypeKit.Testing/README.md", + "quote": "**The content comes back.** `ShouldBeSome()`, `ShouldBeSuccess()`, `ShouldBeError()` and `ShouldBeValue()` return the value or the error.", + "claim": "**The content comes back.** `ShouldBeSome()`, `ShouldBeSuccess()`, `ShouldBeError()` and `ShouldBeValue()` return the value or the error.", + "oracle": "claim", + "surfaces": [ + "OptionAssertions.*", + "ResultAssertions.*", + "PatchAssertions.*" + ], + "heldBy": [ + "AssertionTests", + "PatchAssertionTests" + ] + }, + { + "id": "E01-column-type", + "source": "docs/ef-core.md#the-model", + "quote": "Every property maps as a column of the underlying type, nullable where the property is.", + "claim": "Every property maps as a column of the underlying type, nullable where the property is.", + "oracle": "differential", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit", + "ValueObjectConverter.*" + ], + "heldBy": [ + "MappingTests" + ] + }, + { + "id": "E01-facet-kept", + "source": "docs/ef-core.md#the-model", + "quote": "A facet you configure on it is kept: a precision, a length, a column type.", + "claim": "A facet you configure on it is kept: a precision, a length, a column type.", + "oracle": "differential", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit", + "ValueObjectConverter.*" + ], + "heldBy": [ + "MappingTests" + ] + }, + { + "id": "E01-nullable", + "source": "docs/ef-core.md#the-model", + "quote": "nullable where the property is", + "claim": "nullable where the property is", + "oracle": "differential", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit", + "ValueObjectConverter.*" + ], + "heldBy": [ + "MappingTests" + ] + }, + { + "id": "E02-column-not-cast", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "A table's column is re-typed, not cast, so an index on it still serves the query.", + "claim": "A table's column is re-typed, not cast, so an index on it still serves the query.", + "oracle": "differential", + "surfaces": [ + "TranslatedAsWrappedValueAttribute.*", + "IValueObject.Value" + ], + "heldBy": [ + "SqlTranslationTests" + ] + }, + { + "id": "E02-get-value", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "db.Orders.Where(o => o.Total.GetValue() > 100m);", + "claim": "db.Orders.Where(o => o.Total.GetValue() > 100m);", + "oracle": "differential", + "surfaces": [ + "TranslatedAsWrappedValueAttribute.*", + "IValueObject.Value" + ], + "heldBy": [ + "SqlTranslationTests" + ] + }, + { + "id": "E02-value", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "`.Value`, `GetValue()` and `ValueOrNull()` translate to the column itself.", + "claim": "`.Value`, `GetValue()` and `ValueOrNull()` translate to the column itself.", + "oracle": "differential", + "surfaces": [ + "TranslatedAsWrappedValueAttribute.*", + "IValueObject.Value" + ], + "heldBy": [ + "SqlTranslationTests" + ] + }, + { + "id": "E02-value-or-null", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "Use `ValueOrNull()` for an optional value object, where `.Value` would first unwrap the `Nullable`.", + "claim": "Use `ValueOrNull()` for an optional value object, where `.Value` would first unwrap the `Nullable`.", + "oracle": "differential", + "surfaces": [ + "TranslatedAsWrappedValueAttribute.*", + "IValueObject.Value" + ], + "heldBy": [ + "SqlTranslationTests" + ] + }, + { + "id": "E03-keys", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#what-maps", + "quote": "Keys, foreign keys, nullable properties, primitive collections and query parameters all map as plain columns of the underlying type.", + "claim": "Keys, foreign keys, nullable properties, primitive collections and query parameters all map as plain columns of the underlying type.", + "oracle": "metamorphic", + "surfaces": [ + "ValueObjectConverter.*" + ], + "heldBy": [ + "PostgreSqlRoundTripTests" + ] + }, + { + "id": "E03-stored-as-underlying", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#what-maps", + "quote": "Every value object is stored in a plain column of its underlying type", + "claim": "Every value object is stored in a plain column of its underlying type", + "oracle": "metamorphic", + "surfaces": [ + "ValueObjectConverter.*" + ], + "heldBy": [ + "PostgreSqlRoundTripTests" + ] + }, + { + "id": "E04-byte-not-generated", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "That's EF's own list: `int`, `long`, `short`, `sbyte`, `uint`, `ulong` and `ushort`, and not `byte`.", + "claim": "That's EF's own list: `int`, `long`, `short`, `sbyte`, `uint`, `ulong` and `ushort`, and not `byte`.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E04-char-key-yours", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "A key over `char` is yours to assign.", + "claim": "A key over `char` is yours to assign.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E04-generated-on-add", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "A single-column key over an integer is generated on add, like a key of that integer type.", + "claim": "A single-column key over an integer is generated on add, like a key of that integer type.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E04-guid-key-yours", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "A key over a `Guid` is yours to assign", + "claim": "A key over a `Guid` is yours to assign", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E04-own-configuration-wins", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "A configuration you write yourself always wins over these defaults.", + "claim": "A configuration you write yourself always wins over these defaults.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E05-comparison", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "a comparison (`<`, `>`, `<=`, `>=`, `CompareTo`);", + "claim": "a comparison (`<`, `>`, `<=`, `>=`, `CompareTo`);", + "oracle": "exception", + "surfaces": [ + "HandWrittenOrderingAttribute.*" + ], + "heldBy": [ + "HandWrittenOrderingTests" + ] + }, + { + "id": "E05-equality-allowed", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "Equality isn't ordering, and stays allowed.", + "claim": "Equality isn't ordering, and stays allowed.", + "oracle": "exception", + "surfaces": [ + "HandWrittenOrderingAttribute.*" + ], + "heldBy": [ + "HandWrittenOrderingTests" + ] + }, + { + "id": "E05-ordering", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "an ordering (`OrderBy`, `ThenBy`, their descending forms, `Order`);", + "claim": "an ordering (`OrderBy`, `ThenBy`, their descending forms, `Order`);", + "oracle": "exception", + "surfaces": [ + "HandWrittenOrderingAttribute.*" + ], + "heldBy": [ + "HandWrittenOrderingTests" + ] + }, + { + "id": "E05-query-filter", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "A query filter (`HasQueryFilter`, named or not) that does the same fails when the model is built, naming the entity type, since it applies to every query of that type.", + "claim": "A query filter (`HasQueryFilter`, named or not) that does the same fails when the model is built, naming the entity type, since it applies to every query of that type.", + "oracle": "exception", + "surfaces": [ + "HandWrittenOrderingAttribute.*" + ], + "heldBy": [ + "HandWrittenOrderingTests" + ] + }, + { + "id": "E05-value-order-allowed", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "Compare or order by `.Value` where the underlying value's order is what you mean", + "claim": "Compare or order by `.Value` where the underlying value's order is what you mean", + "oracle": "exception", + "surfaces": [ + "HandWrittenOrderingAttribute.*" + ], + "heldBy": [ + "HandWrittenOrderingTests" + ] + }, + { + "id": "E06-value-not-translated", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "So a filter, a sort, a grouping or an aggregate that reads `.Value` there fails with EF's \"could not be translated\", rather than comparing against what the column really holds.", + "claim": "So a filter, a sort, a grouping or an aggregate that reads `.Value` there fails with EF's \"could not be translated\", rather than comparing against what the column really holds.", + "oracle": "exception", + "surfaces": [ + "ValueObjectConverter.*" + ], + "heldBy": [ + "ForeignConverterTests" + ] + }, + { + "id": "E06-value-object-comparison", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "Comparing the value object itself (`o.Code == code`) goes through that converter and still works.", + "claim": "Comparing the value object itself (`o.Code == code`) goes through that converter and still works.", + "oracle": "exception", + "surfaces": [ + "ValueObjectConverter.*" + ], + "heldBy": [ + "ForeignConverterTests" + ] + }, + { + "id": "E07-in-collections-and-json", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#closed-sets", + "quote": "That holds in a table, in a primitive collection of names (`text[]` on PostgreSQL, a JSON array elsewhere) and in a JSON column alike, with nothing registered per set.", + "claim": "That holds in a table, in a primitive collection of names (`text[]` on PostgreSQL, a JSON array elsewhere) and in a JSON column alike, with nothing registered per set.", + "oracle": "claim", + "surfaces": [ + "ClosedSetConverter.*" + ], + "heldBy": [ + "ClosedSetMappingTests" + ] + }, + { + "id": "E07-non-member-throws", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#closed-sets", + "quote": "An instance that isn't a member throws when it's written.", + "claim": "An instance that isn't a member throws when it's written.", + "oracle": "claim", + "surfaces": [ + "ClosedSetConverter.*" + ], + "heldBy": [ + "ClosedSetMappingTests" + ] + }, + { + "id": "E07-stored-as-name", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#closed-sets", + "quote": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", + "claim": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", + "oracle": "claim", + "surfaces": [ + "ClosedSetConverter.*" + ], + "heldBy": [ + "ClosedSetMappingTests" + ] + }, + { + "id": "E07-unknown-name-throws", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#closed-sets", + "quote": "A name the set no longer has throws when it's read, rather than reading as null.", + "claim": "A name the set no longer has throws when it's read, rather than reading as null.", + "oracle": "claim", + "surfaces": [ + "ClosedSetConverter.*" + ], + "heldBy": [ + "ClosedSetMappingTests" + ] + }, + { + "id": "E08-error-says-so", + "source": "docs/ef-core.md#option-and-result", + "quote": "building the model fails with an error that says so", + "claim": "building the model fails with an error that says so", + "oracle": "exception", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit" + ], + "heldBy": [] + }, + { + "id": "E08-model-fails", + "source": "docs/ef-core.md#option-and-result", + "quote": "EF can't map an `Option` or a `Result` property", + "claim": "EF can't map an `Option` or a `Result` property", + "oracle": "exception", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit" + ], + "heldBy": [] + }, + { + "id": "E09-element-at-skips", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", + "quote": "skips to its row: `OFFSET @p`.", + "claim": "skips to its row: `OFFSET @p`.", + "oracle": "claim", + "surfaces": [ + "TypeKitQueryableExtensions.*", + "Option.FirstOrNone", + "Option.SingleOrNone" + ], + "heldBy": [ + "QueryOptionTests" + ] + }, + { + "id": "E09-first-reads-one-row", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", + "quote": "read one row: `WHERE ... LIMIT @p`.", + "claim": "read one row: `WHERE ... LIMIT @p`.", + "oracle": "claim", + "surfaces": [ + "TypeKitQueryableExtensions.*", + "Option.FirstOrNone", + "Option.SingleOrNone" + ], + "heldBy": [ + "QueryOptionTests" + ] + }, + { + "id": "E09-single-asks-for-two", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", + "quote": "ask for two rows, and throw for more than one.", + "claim": "ask for two rows, and throw for more than one.", + "oracle": "claim", + "surfaces": [ + "TypeKitQueryableExtensions.*", + "Option.FirstOrNone", + "Option.SingleOrNone" + ], + "heldBy": [ + "QueryOptionTests" + ] + }, + { + "id": "E10-reads-without-create", + "source": "docs/ef-core.md#reading-back-without-validation", + "quote": "EF reads a column back without validation, through the value object's `Materialize` rather than `Create`.", + "claim": "EF reads a column back without validation, through the value object's `Materialize` rather than `Create`.", + "oracle": "claim", + "surfaces": [ + "IValueObjectMaterializer.*", + "ValueObjectConverter.Materialize" + ], + "heldBy": [] + }, + { + "id": "E10-revalidate-finds", + "source": "docs/ef-core.md#reading-back-without-validation", + "quote": "`Revalidate()` finds the rows that today's rules reject, as above.", + "claim": "`Revalidate()` finds the rows that today's rules reject, as above.", + "oracle": "claim", + "surfaces": [ + "IValueObjectMaterializer.*", + "ValueObjectConverter.Materialize" + ], + "heldBy": [] + }, + { + "id": "E11-order-does-not-matter", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#setup", + "quote": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`", + "claim": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`", + "oracle": "claim", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit" + ], + "heldBy": [] + }, + { + "id": "E12-underlying-type-does-not-reach", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#model-wide-conventions-follow-the-propertys-type", + "quote": "So `configurationBuilder.Properties().HavePrecision(18, 2)` reaches `decimal` properties, and not an `Amount` that wraps one.", + "claim": "So `configurationBuilder.Properties().HavePrecision(18, 2)` reaches `decimal` properties, and not an `Amount` that wraps one.", + "oracle": "claim", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit" + ], + "heldBy": [] + }, + { + "id": "E12-value-object-type-reaches", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#model-wide-conventions-follow-the-propertys-type", + "quote": "Configure the value object instead: `configurationBuilder.Properties().HavePrecision(18, 2)`.", + "claim": "Configure the value object instead: `configurationBuilder.Properties().HavePrecision(18, 2)`.", + "oracle": "claim", + "surfaces": [ + "TypeKitDbContextOptionsBuilderExtensions.UseTypeKit" + ], + "heldBy": [] + }, + { + "id": "E13-contains", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "db.Orders.Where(o => o.Tags.Contains(tag));", + "claim": "db.Orders.Where(o => o.Tags.Contains(tag));", + "oracle": "claim", + "surfaces": [ + "ValueObjectConverter.*" + ], + "heldBy": [] + }, + { + "id": "E13-element-value", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", + "quote": "db.Orders.Where(o => o.Tags.Any(t => t.Value == \"x\"));", + "claim": "db.Orders.Where(o => o.Tags.Any(t => t.Value == \"x\"));", + "oracle": "claim", + "surfaces": [ + "ValueObjectConverter.*" + ], + "heldBy": [] + }, + { + "id": "E14-tpc-assign-on-sqlite", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "SQLite has no such sequence, so there you assign it.", + "claim": "SQLite has no such sequence, so there you assign it.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E14-tph-tpt-root", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "The root of an inheritance hierarchy follows the same rules under TPH and TPT.", + "claim": "The root of an inheritance hierarchy follows the same rules under TPH and TPT.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "E15-as-for-primitives", + "source": "docs/ef-core.md#keys", + "quote": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives.", + "claim": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [] + }, + { + "id": "E16-column-type", + "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", + "quote": "A facet you configure on the property, such as a maximum length or a column type, is kept.", + "claim": "A facet you configure on the property, such as a maximum length or a column type, is kept.", + "oracle": "claim", + "surfaces": [ + "WrappedTypeValueGeneratorFactory.*" + ], + "heldBy": [ + "KeyGenerationTests" + ] + }, + { + "id": "L01-read-as-the-underlying-type-reads", + "source": "README.md#what-typekit-guarantees", + "quote": "**Swapping a primitive for a value object keeps the JSON, the column and the schema.**", + "claim": "**Swapping a primitive for a value object keeps the JSON, the column and the schema.**", + "oracle": "differential", + "surfaces": [ + "GeneratedJson.*", + "GeneratedJsonPlan.*", + "StoredJsonConverterFactory.*" + ], + "heldBy": [ + "JsonParityTests" + ] + }, + { + "id": "L01-the-underlying-types-json", + "source": "README.md#what-typekit-guarantees", + "quote": "Its JSON is the underlying type's under your options", + "claim": "Its JSON is the underlying type's under your options", + "oracle": "differential", + "surfaces": [ + "GeneratedJson.*", + "GeneratedJsonPlan.*", + "StoredJsonConverterFactory.*" + ], + "heldBy": [ + "JsonParityTests" + ] + }, + { + "id": "L02-json-never-repeats", + "source": "README.md#what-typekit-guarantees", + "quote": "A JSON or parsing rejection names the value object and the rule, or the underlying type it could not read.", + "claim": "A JSON or parsing rejection names the value object and the rule, or the underlying type it could not read.", + "oracle": "exception", + "surfaces": [ + "GeneratedParsing.*", + "GeneratedFactories.*" + ], + "heldBy": [ + "UnreadableInputTests" + ] + }, + { + "id": "L02-no-inner-that-quotes", + "source": "README.md#what-typekit-guarantees", + "quote": "It carries no inner exception that quotes the text.", + "claim": "It carries no inner exception that quotes the text.", + "oracle": "exception", + "surfaces": [ + "GeneratedParsing.*", + "GeneratedFactories.*" + ], + "heldBy": [ + "UnreadableInputTests" + ] + }, + { + "id": "L02-parsing-never-repeats", + "source": "README.md#what-typekit-guarantees", + "quote": "**Rejections never repeat the input.**", + "claim": "**Rejections never repeat the input.**", + "oracle": "exception", + "surfaces": [ + "GeneratedParsing.*", + "GeneratedFactories.*" + ], + "heldBy": [ + "UnreadableInputTests" + ] + }, + { + "id": "L03-refusals-name-the-fault", + "source": "README.md#what-typekit-guarantees", + "quote": "the `JsonException`, the `FormatException` and the `FromKnownGood` exception all name your `EmailFault.NoAt`", + "claim": "the `JsonException`, the `FormatException` and the `FromKnownGood` exception all name your `EmailFault.NoAt`", + "oracle": "claim", + "surfaces": [ + "IValidatedValue.Create", + "GeneratedFactories.*" + ], + "heldBy": [ + "EntryPointValidationTests" + ] + }, + { + "id": "L03-tryfrom-runs-create", + "source": "README.md#what-typekit-guarantees", + "quote": "The generated `TryFrom`, `FromKnownGood`, JSON converter, parsing and type converter all run it", + "claim": "The generated `TryFrom`, `FromKnownGood`, JSON converter, parsing and type converter all run it", + "oracle": "claim", + "surfaces": [ + "GeneratedFactories.*", + "IValidatedValue.Create" + ], + "heldBy": [ + "EntryPointValidationTests" + ] + }, + { + "id": "L04-invariant-whatever-the-culture", + "source": "src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting", + "quote": "A null `IFormatProvider` means the invariant culture in every generated `Parse`, `TryParse`, `ToString` and `TryFormat`, so the text doesn't depend on the culture the process runs in.", + "claim": "A null `IFormatProvider` means the invariant culture in every generated `Parse`, `TryParse`, `ToString` and `TryFormat`, so the text doesn't depend on the culture the process runs in.", + "oracle": "metamorphic", + "surfaces": [ + "GeneratedFormatting.*", + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "L04-json-refusal-is-a-json-exception", + "source": "src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting", + "quote": "Input it can't read throws a `JsonException` naming the value object and the underlying type", + "claim": "Input it can't read throws a `JsonException` naming the value object and the underlying type", + "oracle": "metamorphic", + "surfaces": [ + "GeneratedFormatting.*", + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "L04-text-reads-back", + "source": "src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting", + "quote": "That text reads back as the same value wherever the underlying type's own does", + "claim": "That text reads back as the same value wherever the underlying type's own does", + "oracle": "metamorphic", + "surfaces": [ + "GeneratedFormatting.*", + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "L04-the-type-converter-writes-the-same", + "source": "src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting", + "quote": "`ToString()` is the underlying type's own default text under the invariant culture, and the type converter and `$\"{x}\"` write the same.", + "claim": "`ToString()` is the underlying type's own default text under the invariant culture, and the type converter and `$\"{x}\"` write the same.", + "oracle": "metamorphic", + "surfaces": [ + "GeneratedFormatting.*", + "GeneratedParsing.*" + ], + "heldBy": [] + }, + { + "id": "L05-equality-is-the-underlying-values", + "source": "src/CodoMetis.TypeKit.Generators/README.md#equality", + "quote": "Equality is the underlying value's, like the ordering, the JSON and the column.", + "claim": "Equality is the underlying value's, like the ordering, the JSON and the column.", + "oracle": "metamorphic", + "surfaces": [ + "IValueObject.op_Equality", + "IValueObject.op_Inequality" + ], + "heldBy": [] + }, + { + "id": "L05-ordering-follows-the-underlying-type", + "source": "src/CodoMetis.TypeKit.Generators/README.md#equality", + "quote": "`CompareTo` and the operators follow the underlying type's ordering, ordinal for a string.", + "claim": "`CompareTo` and the operators follow the underlying type's ordering, ordinal for a string.", + "oracle": "metamorphic", + "surfaces": [ + "IValueObject.op_Equality", + "IValueObject.op_Inequality" + ], + "heldBy": [] + }, + { + "id": "L05-through-every-base", + "source": "src/CodoMetis.TypeKit.Generators/README.md#equality", + "quote": "The value object implements each base's `IEquatable` again (`IReimplementedEquatable`), so a collection of the base compares it the way the value object does.", + "claim": "The value object implements each base's `IEquatable` again (`IReimplementedEquatable`), so a collection of the base compares it the way the value object does.", + "oracle": "metamorphic", + "surfaces": [ + "IValueObject.op_Equality", + "IValueObject.op_Inequality" + ], + "heldBy": [] + }, + { + "id": "L06-never-written", + "source": "README.md#what-typekit-guarantees", + "quote": "System.Text.Json throws `NotSupportedException` for either, in both directions, instead of writing `{}` that reads back as `None`.", + "claim": "System.Text.Json throws `NotSupportedException` for either, in both directions, instead of writing `{}` that reads back as `None`.", + "oracle": "exception", + "surfaces": [ + "NotWireTypeJsonConverterFactory.*" + ], + "heldBy": [ + "NotWireTypeTests" + ] + } +] diff --git a/test/oracles/oracles.json b/test/oracles/oracles.json new file mode 100644 index 00000000..e631ccad --- /dev/null +++ b/test/oracles/oracles.json @@ -0,0 +1,32 @@ +[ + { + "class": "AsynchronousContextTests", + "project": "CodoMetis.TypeKit.Tests", + "kind": "completeness", + "against": "every public member of the base package that returns a task, by reflection: a callback runs where the task it waited for completed, and nothing resumes on the caller's context" + }, + { + "class": "JsonParityTests", + "project": "CodoMetis.TypeKit.Generators.Tests", + "kind": "differential", + "against": "the wrapped type's own JSON under the same options, as a value, a property and a dictionary key" + }, + { + "class": "KeyGenerationVariantTests", + "project": "CodoMetis.TypeKit.EntityFrameworkCore.Tests", + "kind": "differential", + "against": "the same key shape keyed by the wrapped type, on SQLite, Npgsql and SQL Server" + }, + { + "class": "NotWireTypeTests", + "project": "CodoMetis.TypeKit.Tests", + "kind": "completeness", + "against": "every exported struct of the base package, by reflection: System.Text.Json refuses it in both directions" + }, + { + "class": "NullDelegateTests", + "project": "CodoMetis.TypeKit.Tests", + "kind": "completeness", + "against": "every delegate parameter of the base package, by reflection, on every branch of its receiver" + } +] diff --git a/tools/probe/corpus/seeds/L01-json-bytes-as-a-dictionary-key-too.patch b/test/oracles/seeds/json-key-written-by-to-string.patch similarity index 77% rename from tools/probe/corpus/seeds/L01-json-bytes-as-a-dictionary-key-too.patch rename to test/oracles/seeds/json-key-written-by-to-string.patch index 832c2257..0e656c20 100644 --- a/tools/probe/corpus/seeds/L01-json-bytes-as-a-dictionary-key-too.patch +++ b/test/oracles/seeds/json-key-written-by-to-string.patch @@ -1,3 +1,7 @@ +Seed: A value object as a dictionary key is written by the wrapped value's ToString(), not by its converter's WriteAsPropertyName +Oracles: JsonParityTests +Fails: every dictionary-key row whose wrapped type's key is not its ToString(): dates, decimals, a host converter's keys + diff --git a/src/CodoMetis.TypeKit/CompilerServices/GeneratedJsonPlan.cs b/src/CodoMetis.TypeKit/CompilerServices/GeneratedJsonPlan.cs index 8597206..1990a4a 100644 --- a/src/CodoMetis.TypeKit/CompilerServices/GeneratedJsonPlan.cs diff --git a/test/oracles/seeds/patch-traverse-takes-a-null-selector.patch b/test/oracles/seeds/patch-traverse-takes-a-null-selector.patch new file mode 100644 index 00000000..cbe223a7 --- /dev/null +++ b/test/oracles/seeds/patch-traverse-takes-a-null-selector.patch @@ -0,0 +1,17 @@ +Seed: Patch.Traverse checks its selector only where it calls it, so a null passes on a clear and an absent field +Oracles: NullDelegateTests +Fails: Result.Traverse(Patch, ...): selector, on the Null and Absent branches + +diff --git a/src/CodoMetis.TypeKit/ResultExtensions.cs b/src/CodoMetis.TypeKit/ResultExtensions.cs +index a4394be..1568b0a 100644 +--- a/src/CodoMetis.TypeKit/ResultExtensions.cs ++++ b/src/CodoMetis.TypeKit/ResultExtensions.cs +@@ -1568,8 +1568,6 @@ public static class Result + where TResult : notnull + where TError : notnull + { +- ArgumentNullException.ThrowIfNull(selector); +- + if (!patch.TryGetValue(out var value)) + return Result, TError>.Success(patch.State == PatchState.Null ? Patch.Null() : Patch.Absent()); + diff --git a/test/oracles/seeds/result-reads-as-json.patch b/test/oracles/seeds/result-reads-as-json.patch new file mode 100644 index 00000000..2f2b00ad --- /dev/null +++ b/test/oracles/seeds/result-reads-as-json.patch @@ -0,0 +1,16 @@ +Seed: Result loses the converter that refuses System.Text.Json, so a success is written as {} and read back as uninitialized +Oracles: NotWireTypeTests +Fails: the completeness row for Result, and its write and read + +diff --git a/src/CodoMetis.TypeKit/Result.cs b/src/CodoMetis.TypeKit/Result.cs +index b92fd68..1f7da85 100644 +--- a/src/CodoMetis.TypeKit/Result.cs ++++ b/src/CodoMetis.TypeKit/Result.cs +@@ -29,7 +29,6 @@ namespace CodoMetis.TypeKit; + /// + /// The type of the error. + [RequireCustomInitialization("Use Result.Success() or Result.Error(error).")] +-[JsonConverter(typeof(NotWireTypeJsonConverterFactory))] + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public readonly record struct Result where TError : notnull + { diff --git a/test/oracles/seeds/traverse-async-resumes-on-the-caller-s-context.patch b/test/oracles/seeds/traverse-async-resumes-on-the-caller-s-context.patch new file mode 100644 index 00000000..cbb6029a --- /dev/null +++ b/test/oracles/seeds/traverse-async-resumes-on-the-caller-s-context.patch @@ -0,0 +1,17 @@ +Seed: The sequence's TraverseAsync awaits each operation without ConfigureAwait(false), so it resumes on the caller's SynchronizationContext +Oracles: AsynchronousContextTests +Fails: Result.TraverseAsync(IEnumerable, Func>>), with the first operation pending + +diff --git a/src/CodoMetis.TypeKit/ResultExtensions.cs b/src/CodoMetis.TypeKit/ResultExtensions.cs +index a4394be..b2eae14 100644 +--- a/src/CodoMetis.TypeKit/ResultExtensions.cs ++++ b/src/CodoMetis.TypeKit/ResultExtensions.cs +@@ -1286,7 +1286,7 @@ public static class Result + + foreach (var element in source) + { +- var result = await ThrowHelper.Awaitable(selector(element), nameof(TraverseAsync), nameof(selector)).ConfigureAwait(false); ++ var result = await ThrowHelper.Awaitable(selector(element), nameof(TraverseAsync), nameof(selector)); + if (!result.TryGetValue(out var value, out var error)) return Result, TError>.Error(error); + + values.Add(value); diff --git a/tools/probe/corpus/seeds/E04-integer-key-generated-not-on-efs-list.patch b/test/oracles/seeds/ushort-key-not-generated.patch similarity index 74% rename from tools/probe/corpus/seeds/E04-integer-key-generated-not-on-efs-list.patch rename to test/oracles/seeds/ushort-key-not-generated.patch index 8791b695..1d97a4cc 100644 --- a/tools/probe/corpus/seeds/E04-integer-key-generated-not-on-efs-list.patch +++ b/test/oracles/seeds/ushort-key-not-generated.patch @@ -1,5 +1,9 @@ +Seed: A value-object key over ushort is not declared generated, where a ushort key is +Oracles: KeyGenerationVariantTests +Fails: every key shape over ushort, on the three providers + diff --git a/src/CodoMetis.TypeKit.EntityFrameworkCore/ValueObjectKeyValueGenerationConvention.cs b/src/CodoMetis.TypeKit.EntityFrameworkCore/ValueObjectKeyValueGenerationConvention.cs -index c64d73e..afedaa5 100644 +index c64d73e..be3d015 100644 --- a/src/CodoMetis.TypeKit.EntityFrameworkCore/ValueObjectKeyValueGenerationConvention.cs +++ b/src/CodoMetis.TypeKit.EntityFrameworkCore/ValueObjectKeyValueGenerationConvention.cs @@ -77,7 +77,7 @@ internal sealed class ValueObjectKeyValueGenerationConvention : IModelFinalizing @@ -7,7 +11,7 @@ index c64d73e..afedaa5 100644 private static bool IsGeneratedByTheDatabase(Type wrapped) => wrapped == typeof(int) || wrapped == typeof(long) || wrapped == typeof(short) || wrapped == typeof(sbyte) - || wrapped == typeof(uint) || wrapped == typeof(ulong) || wrapped == typeof(ushort); -+ || wrapped == typeof(uint) || wrapped == typeof(ulong) || wrapped == typeof(ushort) || wrapped == typeof(string); ++ || wrapped == typeof(uint) || wrapped == typeof(ulong); } /// diff --git a/test/oracles/surface-waivers.json b/test/oracles/surface-waivers.json new file mode 100644 index 00000000..7b89a2d0 --- /dev/null +++ b/test/oracles/surface-waivers.json @@ -0,0 +1,28 @@ +{ + "Error.*": "the error marker's record equality and printing, compiler-generated; the conversions it exists for are claimed through Result", + "None.*": "the None marker's record equality and printing, compiler-generated", + "Success.*": "the success marker's record equality and printing, compiler-generated", + "ResultState.*": "enum members; what each state means is claimed through the members that read it", + "AbstractAttribute..ctor": "a constraint attribute's constructor; what it constrains is CMTK0010's, held by the analyzer tests", + "ConcreteAttribute..ctor": "a constraint attribute's constructor; what it constrains is CMTK0010's, held by the analyzer tests", + "DistinctAttribute..ctor": "a constraint attribute's constructor; what it constrains is CMTK0010's, held by the analyzer tests", + "ClosedSetAttribute..ctor": "a constraint attribute's constructor; what it constrains is CMTK0010's, held by the analyzer tests", + "GeneratedClosedSetAttribute.*": "plumbing the generators write on a closed set, read by the satellites through Accept", + "GeneratedValueObjectAttribute.*": "plumbing the generators write on a value object, read by the satellites through Accept", + "GeneratedClosedSets.*": "refusal helpers that generated closed-set code calls; what they refuse is claimed through Parse and the JSON reads", + "IClosedSetVisitor.Visit": "the visitor GeneratedClosedSetAttribute.Accept calls, plumbing", + "IValueObjectVisitor.Visit": "the visitor GeneratedValueObjectAttribute.Accept calls, plumbing", + "IStoredJsonConverterSource.CreateStoredJsonConverter": "plumbing StoredJsonConverterFactory calls on a generated converter", + "DescribedJsonSchema.ExporterOptions": "the exporter options the schema descriptions are read with, plumbing", + "TypeKitServiceCollectionExtensions.AddEntityFrameworkTypeKit": "the internal-service-provider form of UseTypeKit, whose claims hold it", + "TypeKitAssertionException..ctor": "the exception the assertions throw; its messages are claimed through the assertions", + "Option.*": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "Result.*": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "Patch.*": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "SequenceOptionExtensions.Choose": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "ValueTypeOptionExtensions.OrNull": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "GuidValueExtensions.New": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "TypeKitSerilogExtensions.WithTypeKit": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "TypeKitClosedSetHttpResultExtensions.ToHttpResult": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile", + "RequireCustomInitializationAttribute.*": "unread: the document that promises its behaviour has not been read for claims yet (#98); the core tests hold it meanwhile" +} diff --git a/tools/AgentTools.slnf b/tools/AgentTools.slnf index d3b8e907..a2b4a1c0 100644 --- a/tools/AgentTools.slnf +++ b/tools/AgentTools.slnf @@ -5,8 +5,8 @@ "tools/BuildVerdict/BuildVerdict.csproj", "tools/ConsumerSmokeTest/ConsumerSmokeTest.csproj", "tools/DocsQuery/DocsQuery.csproj", - "tools/PrHygiene/PrHygiene.csproj", - "tools/Prober/Prober.csproj" + "tools/Oracles/Oracles.csproj", + "tools/PrHygiene/PrHygiene.csproj" ] } } diff --git a/tools/BuildVerdict/BuildVerdict.csproj b/tools/BuildVerdict/BuildVerdict.csproj index 6d4ac2f5..56d0c520 100644 --- a/tools/BuildVerdict/BuildVerdict.csproj +++ b/tools/BuildVerdict/BuildVerdict.csproj @@ -3,7 +3,7 @@ Exe diff --git a/tools/Directory.Build.props b/tools/Directory.Build.props index e87f7909..443b70ff 100644 --- a/tools/Directory.Build.props +++ b/tools/Directory.Build.props @@ -9,7 +9,7 @@ false false - + **/*.cs diff --git a/tools/DocsQuery/Citations.cs b/tools/DocsQuery/Citations.cs deleted file mode 100644 index ef97fba4..00000000 --- a/tools/DocsQuery/Citations.cs +++ /dev/null @@ -1,260 +0,0 @@ -using System.Globalization; -using System.Text; -using System.Text.Json; -using System.Text.RegularExpressions; - -namespace DocsQuery; - -/// -/// Where the probe corpus leans on a verified fact to prune a row or excuse one (design/adr/0107): a refused -/// entry of the axes file whose reason names KB-NNN, a not-promised entry of claims.json whose -/// source is a fact's file or which says fact:KB-NNN, an obligation's declaration of where it does not -/// apply whose cite is fact:KB-NNN, and a Cite.Fact("KB-NNN") or Baseline.Fact("KB-NNN") -/// literal in the harness and probe sources, read as text with comments blanked out. Each is read from the checkout -/// at every check, never from the index. -/// -internal static partial class FactCitations -{ - public const string AxesFile = ".claude/probe-axes.md", ClaimsFile = "tools/probe/corpus/claims.json"; - - public static readonly string[] SourceDirectories = ["tools/probe/corpus/harness", "tools/probe/corpus/probes"]; - - /// The four places, in the order check counts them. - public static readonly string[] Kinds = [Refused, NotPromised, Obligation, Harness]; - - public const string Refused = "refused", NotPromised = "not-promised", Obligation = "obligation", Harness = "harness"; - - /// - /// One citation: the kind of place, where it is written (path:line), the fact's id, the place in words, and - /// whether it reads the fact's fixture as a baseline (Baseline.Fact), which takes a fixture as well as a test. - /// - internal sealed record Citation(string Kind, string At, string Fact, string Place, bool Baseline = false); - - /// What a scan read: every citation, and how many places of each kind it looked at, cited or not. - internal sealed record Scan(IReadOnlyList Citations, IReadOnlyDictionary Read) - { - public int Of(string kind) => Citations.Count(citation => citation.Kind == kind); - } - - public static Scan Find(string root) - { - var citations = new List(); - var read = Kinds.ToDictionary(kind => kind, _ => 0, StringComparer.Ordinal); - - ReadAxes(root, citations, read); - ReadClaims(root, citations, read); - ReadSources(root, citations, read); - - return new Scan(citations, read); - } - - /// The axes file's refused entries: axis to value to the reason the framework refuses it. - private static void ReadAxes(string root, List citations, Dictionary read) - { - var path = Path.Combine(root, AxesFile); - if (!File.Exists(path)) return; - - const string marker = "```json probe-axes"; - var text = File.ReadAllText(path).ReplaceLineEndings("\n"); - var start = text.IndexOf(marker, StringComparison.Ordinal); - if (start < 0) return; - start += marker.Length; - var end = text.IndexOf("```", start, StringComparison.Ordinal); - if (end < 0) return; - - using var block = JsonDocument.Parse(text[start..end]); - if (!block.RootElement.TryGetProperty("refused", out var refused) || refused.ValueKind != JsonValueKind.Object) return; - - var cursor = new Cursor(AxesFile, text, text.IndexOf("\"refused\"", start, StringComparison.Ordinal)); - foreach (var axis in refused.EnumerateObject().Where(axis => axis.Value.ValueKind == JsonValueKind.Object)) - { - foreach (var value in axis.Value.EnumerateObject()) - { - read[Refused]++; - var place = $"the refused entry {axis.Name}={value.Name}"; - cursor.Seek($"\"{value.Name}\""); - foreach (var fact in FactIds(value.Value.ValueKind == JsonValueKind.String ? value.Value.GetString()! : value.Value.GetRawText())) - citations.Add(new Citation(Refused, cursor.At(fact), fact, place)); - } - } - } - - /// Each claim's not-promised entries and its obligations' inapplicable declarations. - private static void ReadClaims(string root, List citations, Dictionary read) - { - var path = Path.Combine(root, ClaimsFile); - if (!File.Exists(path)) return; - - var text = File.ReadAllText(path).ReplaceLineEndings("\n"); - using var claims = JsonDocument.Parse(text); - if (claims.RootElement.ValueKind != JsonValueKind.Array) return; - - // Walked in the file's order, so each citation's line is the next occurrence of its id from the last one. - var cursor = new Cursor(ClaimsFile, text, 0); - foreach (var claim in claims.RootElement.EnumerateArray()) - { - var id = Str(claim, "id"); - cursor.Seek($"\"{id}\""); - - foreach (var property in claim.EnumerateObject()) - { - if (property.NameEquals("obligations") && property.Value.ValueKind == JsonValueKind.Array) - { - foreach (var obligation in property.Value.EnumerateArray()) - { - cursor.Seek($"\"{Str(obligation, "id")}\""); - var number = 0; - foreach (var declaration in Array(obligation, "inapplicable")) - { - read[Obligation]++; - number++; - if (FactOf(Str(declaration, "cite")) is not { } fact) continue; - citations.Add(new Citation(Obligation, cursor.At("fact:" + fact), fact, - $"claim {id}, obligation {Str(obligation, "id")}, inapplicable declaration {number.ToString(CultureInfo.InvariantCulture)}")); - } - } - } - else if (property.NameEquals("not-promised") && property.Value.ValueKind == JsonValueKind.Array) - { - foreach (var entry in property.Value.EnumerateArray()) - { - read[NotPromised]++; - cursor.Seek($"\"{Str(entry, "id")}\""); - var place = $"claim {id}, not-promised {Str(entry, "id")}"; - var facts = new List(); - if (KnowledgeSource().Match(Str(entry, "source")) is { Success: true } source) facts.Add(source.Groups["id"].Value); - foreach (var field in entry.EnumerateObject().Where(field => field.Value.ValueKind == JsonValueKind.String)) - facts.AddRange(CiteFact().Matches(field.Value.GetString()!).Select(match => match.Groups["id"].Value)); - - foreach (var fact in facts.Distinct(StringComparer.Ordinal)) - citations.Add(new Citation(NotPromised, cursor.At(fact), fact, place)); - } - } - } - } - } - - /// The harness's and the probes' Cite.Fact and Baseline.Fact literals, comments blanked out. - private static void ReadSources(string root, List citations, Dictionary read) - { - foreach (var directory in SourceDirectories.Select(directory => Path.Combine(root, directory)).Where(Directory.Exists)) - { - foreach (var file in Directory.EnumerateFiles(directory, "*.cs").Order(StringComparer.Ordinal)) - { - read[Harness]++; - var path = Corpus.Relative(root, file); - var source = File.ReadAllText(file).ReplaceLineEndings("\n"); - foreach (Match match in FactLiteral().Matches(WithoutComments(source))) - { - var line = 1 + source.AsSpan(0, match.Index).Count('\n'); - citations.Add(new Citation(Harness, $"{path}:{line.ToString(CultureInfo.InvariantCulture)}", match.Groups["id"].Value, - $"{match.Groups["factory"].Value}.Fact(\"{match.Groups["id"].Value}\")", match.Groups["factory"].Value == "Baseline")); - } - } - } - } - - /// - /// The source with each comment's content replaced by spaces, newlines kept, and string literals as they are, so a - /// citation written in a comment does not count and a line number still holds. - /// - internal static string WithoutComments(string source) - { - var result = new StringBuilder(source); - for (var i = 0; i < source.Length; i++) - { - if (source[i] == '/' && i + 1 < source.Length && source[i + 1] == '/') - { - for (; i < source.Length && source[i] != '\n'; i++) result[i] = ' '; - } - else if (source[i] == '/' && i + 1 < source.Length && source[i + 1] == '*') - { - var close = source.IndexOf("*/", i + 2, StringComparison.Ordinal); - var stop = close < 0 ? source.Length : close + 2; - for (; i < stop; i++) if (source[i] != '\n') result[i] = ' '; - i--; - } - else if (source[i] == '"') - { - i = AfterString(source, i); - } - else if (source[i] == '\'') - { - // A character literal: '"' must not open a string. - var j = i + 1; - if (j < source.Length && source[j] == '\\') j++; - if (j + 1 < source.Length && source[j + 1] == '\'') i = j + 1; - } - } - - return result.ToString(); - } - - /// The index of the closing quote of the string literal opened at : raw, verbatim or regular. - private static int AfterString(string source, int i) - { - var quotes = 0; - while (i + quotes < source.Length && source[i + quotes] == '"') quotes++; - - if (quotes >= 3) - { - var close = source.IndexOf(new string('"', quotes), i + quotes, StringComparison.Ordinal); - return close < 0 ? source.Length : close + quotes - 1; - } - - if (quotes == 2) return i + 1; // "" - - var verbatim = i > 0 && source[i - 1] == '@' || i > 1 && source[i - 1] == '$' && source[i - 2] == '@'; - for (var j = i + 1; j < source.Length; j++) - { - if (verbatim && source[j] == '"' && j + 1 < source.Length && source[j + 1] == '"') { j++; continue; } - if (!verbatim && source[j] == '\\') { j++; continue; } - if (source[j] == '"' || !verbatim && source[j] == '\n') return j; - } - - return source.Length; - } - - /// The ids a refused entry's reason names, as fact:KB-NNN or plain KB-NNN. - private static IEnumerable FactIds(string text) => AnyFact().Matches(text).Select(match => match.Value).Distinct(StringComparer.Ordinal); - - private static string? FactOf(string cite) => cite.StartsWith("fact:", StringComparison.Ordinal) ? cite["fact:".Length..] : null; - - private static string Str(JsonElement element, string name) => - element.ValueKind == JsonValueKind.Object && element.TryGetProperty(name, out var value) && value.ValueKind == JsonValueKind.String ? value.GetString()! : ""; - - private static IEnumerable Array(JsonElement element, string name) => - element.ValueKind == JsonValueKind.Object && element.TryGetProperty(name, out var value) && value.ValueKind == JsonValueKind.Array ? value.EnumerateArray() : []; - - /// Line numbers for places read in a file's order: each needle is looked for from the last place found. - private sealed class Cursor(string path, string text, int offset) - { - private int at = Math.Max(0, offset); - - public void Seek(string needle) - { - var found = text.IndexOf(needle, at, StringComparison.Ordinal); - if (found >= 0) at = found; - } - - public string At(string needle) - { - var found = text.IndexOf(needle, at, StringComparison.Ordinal); - var line = 1 + text.AsSpan(0, found >= 0 ? found : at).Count('\n'); - if (found >= 0) at = found + needle.Length; - return $"{path}:{line.ToString(CultureInfo.InvariantCulture)}"; - } - } - - [GeneratedRegex(@"\bKB-\d{3}\b")] - private static partial Regex AnyFact(); - - [GeneratedRegex(@"\bfact:\s?(?KB-\d{3})\b")] - private static partial Regex CiteFact(); - - [GeneratedRegex(@"^design/knowledge/(?KB-\d{3})-[^/#]*\.md(#.*)?$")] - private static partial Regex KnowledgeSource(); - - [GeneratedRegex(@"\b(?Cite|Baseline)\s*\.\s*Fact\s*\(\s*""(?KB-\d{3})""\s*\)")] - private static partial Regex FactLiteral(); -} diff --git a/tools/DocsQuery/Facts.cs b/tools/DocsQuery/Facts.cs index 9f5d81ec..af86c6c1 100644 --- a/tools/DocsQuery/Facts.cs +++ b/tools/DocsQuery/Facts.cs @@ -125,9 +125,7 @@ public static int CompareVersions(string left, string right) /// The rules a verified fact is held to (design/adr/0093): its frontmatter is complete and plain, each pin /// matches what is installed, and its test: names the characterization test that observes it, or says /// none and why. A test of the facts project that no fact names is a problem too. A fixture:, the -/// measured answer of the fact's test as data, sits beside that test and exists (design/adr/0107). A fact the probe -/// corpus cites to prune or excuse a row () is executable: its test exists, and where the -/// harness reads it as a baseline, its fixture too. +/// measured answer of the fact's test as data, sits beside that test and exists (design/adr/0107). /// internal static partial class FactRules { @@ -139,9 +137,7 @@ internal sealed record Problem(string At, string Kind, string Target, string Det public const string FixtureSuffix = ".fixture.json"; - public static IReadOnlyList Check(DocIndex index, string root, out int facts) => Check(index, root, out facts, out _); - - public static IReadOnlyList Check(DocIndex index, string root, out int facts, out FactCitations.Scan cited) + public static IReadOnlyList Check(DocIndex index, string root, out int facts) { var problems = new List(); var installed = Installed.Read(root); @@ -149,7 +145,6 @@ public static IReadOnlyList Check(DocIndex index, string root, out int var fixtures = new HashSet(StringComparer.Ordinal); // Why each fact cannot settle a pruning or an excuse, or null where its test exists; and its fixture, where one exists. var notExecutable = new Dictionary(StringComparer.Ordinal); - var fixtureOf = new Dictionary(StringComparer.Ordinal); facts = 0; for (var d = 0; d < index.Docs.Count; d++) @@ -221,7 +216,6 @@ public static IReadOnlyList Check(DocIndex index, string root, out int } } - fixtureOf[doc.Id!] = null; if (doc.Meta.FirstOrDefault(field => field.Key == "fixture") is { } fixture) { var expected = $"{FactsProject}/{className}{FixtureSuffix}"; @@ -235,23 +229,9 @@ public static IReadOnlyList Check(DocIndex index, string root, out int problems.Add(new Problem(At(fixture.Line), "fact-fixture", fixture.Value, $"write it beside the test, as {expected}")); else if (!File.Exists(Path.Combine(root, fixture.Value))) problems.Add(new Problem(At(fixture.Line), "fact-fixture-missing", fixture.Value, "the file does not exist")); - else - fixtureOf[doc.Id!] = fixture.Value; } } - cited = FactCitations.Find(root); - foreach (var citation in cited.Citations) - { - var why = !notExecutable.TryGetValue(citation.Fact, out var reason) ? "there is no such fact under design/knowledge/" - : reason is not null ? reason - : citation.Baseline && fixtureOf[citation.Fact] is null ? "the harness reads its fixture as a baseline, and it names no fixture: that exists" - : null; - if (why is not null) - problems.Add(new Problem(citation.At, "fact-not-executable-cited", citation.Fact, - $"{citation.Place} cites {citation.Fact}, and {why}: a fact without its test explains only, never prunes or excuses a row; write its test in {FactsProject}/, or cite a docs sentence")); - } - var project = Path.Combine(root, FactsProject); if (Directory.Exists(project)) { diff --git a/tools/DocsQuery/Queries.cs b/tools/DocsQuery/Queries.cs index ec174ae0..849dc9a2 100644 --- a/tools/DocsQuery/Queries.cs +++ b/tools/DocsQuery/Queries.cs @@ -206,8 +206,7 @@ public Answer Claims(string? page, string? kind) /// /// Links whose file or anchor does not exist, ids that name no record, diagnostic or fact, and the facts' /// rules (): a pin behind or ahead of what is installed, or naming nothing installed, - /// a fact without its test, a test without its fact, a fixture missing, and a fact the probe corpus cites to prune - /// or excuse a row that has no test. + /// a fact without its test, a test without its fact, and a fixture missing. /// public Answer Check() { @@ -239,12 +238,9 @@ public Answer Check() } } - rows.AddRange(FactRules.Check(index, root, out var facts, out var cited).Select(problem => Row.Of(("at", problem.At), ("kind", problem.Kind), ("target", problem.Target), ("detail", problem.Detail)))); + rows.AddRange(FactRules.Check(index, root, out var facts).Select(problem => Row.Of(("at", problem.At), ("kind", problem.Kind), ("target", problem.Target), ("detail", problem.Detail)))); - // Each kind of citation counted, so a scan that found none of a kind it should have is seen in the summary. - var citations = string.Join(", ", FactCitations.Kinds.Select(kind => $"{cited.Of(kind).ToString(CultureInfo.InvariantCulture)} {kind}")); - - return new Answer(Answer.Exact, "check", "", $"{Count(rows.Count, "problem")} in {links} links, {ids} ids, {Count(cited.Citations.Count, "fact citation")} ({citations}) and {Count(facts, "fact")}", rows, rows.Count == 0 ? 0 : 1); + return new Answer(Answer.Exact, "check", "", $"{Count(rows.Count, "problem")} in {links} links, {ids} ids and {Count(facts, "fact")}", rows, rows.Count == 0 ? 0 : 1); Row Problem(Edge edge, string kind, string detail) => Row.Of(("at", At(edge.Doc, edge.Line)), ("kind", kind), ("target", edge.Written), ("detail", detail)); diff --git a/tools/DocsQuery/README.md b/tools/DocsQuery/README.md index 6e8e666e..7ba3f264 100644 --- a/tools/DocsQuery/README.md +++ b/tools/DocsQuery/README.md @@ -54,11 +54,8 @@ rules: | `fact-orphan-test` | A `KBNNN.cs` in the facts project that no fact names | | `fact-fixture-missing`, `fact-fixture` | A `fixture:` whose file does not exist; one that is not `KBNNN.fixture.json` beside the test, or belongs to a fact without a test | | `fact-orphan-fixture` | A `KBNNN.fixture.json` in the facts project that no fact names | -| `fact-not-executable-cited` | The probe corpus cites a fact that has no test: a `refused` entry of `.claude/probe-axes.md` whose reason names `KB-NNN`, a `not-promised` entry of `tools/probe/corpus/claims.json` whose `source` is the fact's file or which says `fact:KB-NNN`, an obligation's `inapplicable` declaration citing `fact:KB-NNN`, or a `Cite.Fact("KB-NNN")` or `Baseline.Fact("KB-NNN")` literal in the harness and probe sources (comments blanked out). No test means `none, …`, no file, a file that does not exist or declares no class of the id; a `Baseline.Fact` takes a fixture as well. Reported at the citing place | -The pins and the corpus's citations are read from the checkout at each `check`, never from the index. The summary -counts the citations of each kind (`4 fact citations (0 refused, 2 not-promised, 0 obligation, 2 harness)`), and -`RepositoryTests` holds floors on them, so a scan that finds nothing cannot pass for a clean one. +The pins are read from the checkout at each `check`, never from the index. ## Freshness diff --git a/tools/Oracles/Oracles.csproj b/tools/Oracles/Oracles.csproj new file mode 100644 index 00000000..3ee2c980 --- /dev/null +++ b/tools/Oracles/Oracles.csproj @@ -0,0 +1,22 @@ + + + + + Exe + oracles + Oracles + **/*.cs;../../test/oracles/SeedVerdict.cs + + + + + + + diff --git a/tools/Oracles/Program.cs b/tools/Oracles/Program.cs new file mode 100644 index 00000000..f3321288 --- /dev/null +++ b/tools/Oracles/Program.cs @@ -0,0 +1,215 @@ +// The oracle kit's local tool (design/adr/0112, test/oracles/README.md). Never part of CI. +// +// dotnet tools/Oracles/bin/Release/net10.0/oracles.dll seeds [name filter] show that every seed is caught +// dotnet tools/Oracles/bin/Release/net10.0/oracles.dll status the catalogue's worklist +// +// `seeds`: for each test/oracles/seeds/.patch whose file name holds the filter, a copy of the working tree +// (bin/, obj/, .git/ and the agents' worktrees left out, so uncommitted work is included) under the temp directory, +// the patch applied, each oracle project its `Oracles:` line names built once in Release, and each named class run +// alone. An oracle catches a seed when one of its tests fails with a row that is not a known candidate +// (SeedVerdict). One line per (seed, oracle), CAUGHT, MISSED or ERROR, and exit code 1 unless every pair is caught. +// +// Exit 0 is a pass, 1 a seed not caught (or a status that could not read the catalogue), 2 a usage error, 3 a tool +// built from other sources than the checkout holds, which names the command that rebuilds it. +using System.Diagnostics; +using System.Text.Json; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using CodoMetis.TypeKit.Oracles; + +Console.Out.NewLine = "\n"; + +var root = SourceFingerprint.FindRoot(); +var stale = SourceFingerprint.Difference(root); +if (stale is not null) +{ + Console.WriteLine($"TOOL STALE: {SourceFingerprint.Project} was built from other sources than the checkout holds ({stale})"); + Console.WriteLine($" rebuild it: {SourceFingerprint.RebuildCommand}"); + return SourceFingerprint.StaleExitCode; +} + +var oraclesDirectory = Path.Combine(root!, "test", "oracles"); +var json = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }; + +return args switch +{ + ["seeds"] => Seeds(""), + ["seeds", var filter] => Seeds(filter), + ["status"] or [] => Status(), + _ => Usage(), +}; + +int Usage() +{ + Console.Error.WriteLine("usage: dotnet tools/Oracles/bin/Release/net10.0/oracles.dll seeds [filter] | status"); + return 2; +} + +int Seeds(string filter) +{ + var oracles = Read>("oracles.json").ToDictionary(oracle => oracle.Class, StringComparer.Ordinal); + var seeds = Directory.GetFiles(Path.Combine(oraclesDirectory, "seeds"), "*.patch") + .Where(seed => Path.GetFileName(seed).Contains(filter, StringComparison.OrdinalIgnoreCase)) + .Order(StringComparer.Ordinal) + .ToList(); + if (seeds.Count == 0) + { + Console.WriteLine($"no seed matches '{filter}' in test/oracles/seeds"); + return 1; + } + + var allCaught = true; + foreach (var seed in seeds) + { + var name = Path.GetFileName(seed); + var named = Header(File.ReadAllText(seed), "Oracles").Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + var scratch = Path.Combine(Path.GetTempPath(), $"typekit-seed-{Guid.NewGuid():N}"); + var started = Stopwatch.StartNew(); + try + { + CopyTree(root!, scratch); + Require(RunProcess(scratch, "git", null, ["apply", "--whitespace=nowarn", seed]), "apply the patch"); + + foreach (var group in named.Select(oracle => oracles.TryGetValue(oracle, out var registered) ? registered : throw new SeedError($"'{oracle}' is not in oracles.json")) + .GroupBy(oracle => oracle.Project)) + { + var project = Path.Combine("test", group.Key); + Require(RunDotnet(scratch, "build", project, "-c", "Release", "-nologo", "-v", "q"), $"build {group.Key}"); + foreach (var oracle in group) + { + var results = Path.Combine(scratch, "SeedResults", oracle.Class); + RunDotnet(scratch, "test", "--project", project, "-c", "Release", "--no-build", + "--filter-class", $"*.{oracle.Class}", "--report-xunit-trx", "--report-xunit-trx-filename", $"{oracle.Class}.trx", + "--results-directory", results); + var verdict = Verdict(Path.Combine(results, $"{oracle.Class}.trx"), oracle.Class); + allCaught &= verdict.StartsWith("CAUGHT", StringComparison.Ordinal); + Console.WriteLine($"{verdict[..8]}{name} -> {oracle.Class}: {verdict[8..]} ({started.Elapsed.TotalSeconds:F0} s)"); + } + } + } + catch (SeedError error) + { + allCaught = false; + Console.WriteLine($"ERROR {name}: {error.Message}"); + } + finally + { + try { Directory.Delete(scratch, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } + } + } + + Console.WriteLine(allCaught ? "every seed is caught" : "A SEED IS NOT CAUGHT: the oracle it names cannot fail for that defect"); + return allCaught ? 0 : 1; +} + +string Verdict(string trx, string oracle) +{ + if (!File.Exists(trx)) return "ERROR no test results written (did the class run?)"; + + XNamespace ns = "http://microsoft.com/schemas/VisualStudio/TeamTest/2010"; + var results = XDocument.Load(trx).Descendants(ns + "UnitTestResult").ToList(); + if (results.Count == 0) return $"ERROR no test of {oracle} ran"; + + var failed = results.Where(result => (string?)result.Attribute("outcome") == "Failed") + .Select(result => (Test: (string?)result.Attribute("testName") ?? "?", Message: result.Descendants(ns + "Message").FirstOrDefault()?.Value ?? "")) + .ToList(); + var caught = failed.Where(failure => SeedVerdict.Catches(failure.Message)).ToList(); + if (caught.Count > 0) return $"CAUGHT {caught.Count} of {results.Count} tests fail, e.g. {caught[0].Test}"; + return failed.Count == 0 + ? $"MISSED all {results.Count} tests pass with the defect planted" + : $"MISSED {failed.Count} of {results.Count} tests fail, every row a known candidate"; +} + +int Status() +{ + var claims = Read>("claims.json"); + var oracles = Read>("oracles.json"); + var waivers = Read>("surface-waivers.json"); + var candidates = Read>("candidates.json"); + var seeds = Directory.GetFiles(Path.Combine(oraclesDirectory, "seeds"), "*.patch") + .Select(seed => Header(File.ReadAllText(seed), "Oracles").Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)) + .ToList(); + + var unheld = claims.Where(claim => claim.HeldBy is not { Count: > 0 }).ToList(); + Console.WriteLine($"claims: {claims.Count}, held by a test: {claims.Count - unheld.Count}, unheld (the worklist): {unheld.Count}"); + foreach (var claim in unheld) Console.WriteLine($" UNHELD {claim.Id,-40} {claim.Source}"); + + var unread = waivers.Where(waiver => waiver.Value.StartsWith("unread:", StringComparison.Ordinal)).ToList(); + Console.WriteLine($"surface waivers: {waivers.Count}, unread (members whose document has no claims yet): {unread.Count}"); + foreach (var waiver in unread) Console.WriteLine($" UNREAD {waiver.Key}"); + + var seeded = seeds.SelectMany(names => names).ToHashSet(StringComparer.Ordinal); + Console.WriteLine($"oracles: {oracles.Count}, seeds: {seeds.Count}, oracles without a seed: {oracles.Count(oracle => !seeded.Contains(oracle.Class))}"); + foreach (var oracle in oracles.Where(oracle => !seeded.Contains(oracle.Class))) Console.WriteLine($" UNSEEDED {oracle.Class}"); + + Console.WriteLine($"candidates: {candidates.Count} ({candidates.Count(candidate => candidate.Issue.Length == 0)} without an issue)"); + foreach (var candidate in candidates) Console.WriteLine($" {candidate.Oracle}: '{candidate.Row}' [{candidate.Family}] {(candidate.Issue.Length == 0 ? "NOT FILED" : candidate.Issue)}"); + + return 0; +} + +T Read(string file) +{ + using var stream = File.OpenRead(Path.Combine(oraclesDirectory, file)); + return JsonSerializer.Deserialize(stream, json) ?? throw new InvalidOperationException($"test/oracles/{file} is empty."); +} + +static string Header(string text, string key) => + Regex.Match(text, $@"^{key}:\s*(?.+?)\s*$", RegexOptions.Multiline) is { Success: true } match ? match.Groups["value"].Value : ""; + +static void CopyTree(string from, string to) +{ + string[] skipped = ["bin", "obj", ".git", "SeedResults", "TestResults", "dist", ".codebase-memory"]; + foreach (var directory in Directory.EnumerateDirectories(from, "*", SearchOption.TopDirectoryOnly)) + { + var name = Path.GetFileName(directory); + if (skipped.Contains(name, StringComparer.Ordinal)) continue; + if (name == ".claude") { CopyClaude(directory, Path.Combine(to, name)); continue; } + CopyTree(directory, Path.Combine(to, name)); + } + + Directory.CreateDirectory(to); + foreach (var file in Directory.EnumerateFiles(from, "*", SearchOption.TopDirectoryOnly)) + File.Copy(file, Path.Combine(to, Path.GetFileName(file))); +} + +// The agents' worktrees under .claude/worktrees are whole checkouts; nothing a seed builds reads them. +static void CopyClaude(string from, string to) +{ + Directory.CreateDirectory(to); + foreach (var file in Directory.EnumerateFiles(from)) File.Copy(file, Path.Combine(to, Path.GetFileName(file))); + foreach (var directory in Directory.EnumerateDirectories(from).Where(directory => Path.GetFileName(directory) != "worktrees")) + CopyTree(directory, Path.Combine(to, Path.GetFileName(directory))); +} + +static (int Exit, string Output) RunDotnet(string directory, params string[] arguments) +{ + var (dotnet, home) = Dotnet.For(directory); + return RunProcess(directory, dotnet, home, arguments); +} + +static (int Exit, string Output) RunProcess(string directory, string file, string? dotnetHome, string[] arguments) +{ + var start = new ProcessStartInfo(file) { WorkingDirectory = directory, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false }; + foreach (var argument in arguments) start.ArgumentList.Add(argument); + Dotnet.Apply(dotnetHome, start.Environment); + + using var process = Process.Start(start) ?? throw new SeedError($"{file} could not be started"); + var error = process.StandardError.ReadToEndAsync(); + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + return (process.ExitCode, output + error.Result); +} + +static void Require((int Exit, string Output) result, string step) +{ + if (result.Exit != 0) throw new SeedError($"{step} failed (exit {result.Exit}): {string.Join(" | ", result.Output.Split('\n').Where(line => line.Contains("error", StringComparison.OrdinalIgnoreCase)).Take(3).Select(line => line.Trim()))}"); +} + +internal sealed record Claim(string Id, string Source, IReadOnlyList? HeldBy); + +internal sealed record Oracle(string Class, string Project, string Kind, string Against); + +internal sealed record Candidate(string Oracle, string Row, string Family, string Issue); + +internal sealed class SeedError(string message) : Exception(message); diff --git a/tools/Prober/Axes.cs b/tools/Prober/Axes.cs deleted file mode 100644 index e37f6a46..00000000 --- a/tools/Prober/Axes.cs +++ /dev/null @@ -1,386 +0,0 @@ -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; - -namespace Prober; - -/// Two settings of one row, "axis=value" each, held in ordinal order so a pair has one form. -internal readonly record struct Pair -{ - public string A { get; } - public string B { get; } - - public Pair(string x, string y) - { - if (string.CompareOrdinal(x, y) <= 0) { A = x; B = y; } else { A = y; B = x; } - } - - public override string ToString() => $"{A} {B}"; -} - -/// Pairs a claim excludes, and the one sentence that says why no row can hold them or the documents do not promise them. -internal sealed record Exclusion(string Reason, IReadOnlyList Pairs); - -/// One thing a claim promises, checkable on its own: a sentence quoted from the claim's source, under an id a seed names (decision 104). -internal sealed record Obligation(string Id, string Sentence, IReadOnlyDictionary> Axes) -{ - /// Where the obligation does not apply, each declaration with its citation; the harness's Row.Check reads the same ones. - public IReadOnlyList Inapplicable { get; init; } = []; -} - -/// -/// Where an obligation does not apply: every axis of the declaration at one of the values it lists, and the citation -/// that says why (not-promised:id, docs:file#anchor, fact:KB-NNN, record:NNNN). A row -/// matches when it holds each axis at a listed value; a pair matches when every row holding it does, so when each -/// axis of the declaration is one of the pair's two at a listed value. -/// -internal sealed record Inapplicability(IReadOnlyDictionary> Axes, string Cite) -{ - public bool Matches(Pair pair) => Axes.All(axis => Holds(pair.A, axis) || Holds(pair.B, axis)); - - private static bool Holds(string setting, KeyValuePair> axis) - { - var at = setting.IndexOf('=', StringComparison.Ordinal); - return at > 0 && string.Equals(setting[..at], axis.Key, StringComparison.Ordinal) && axis.Value.Contains(setting[(at + 1)..]); - } - - public JsonObject ToJson() => new() - { - ["axes"] = new JsonObject(Axes.Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)new JsonArray([.. kv.Value.Select(v => (JsonNode)v)])))), - ["cite"] = Cite, - }; -} - -/// One thing a claim does not promise: the sentence of the document or record that makes the difference intended, and what it concerns. -internal sealed record NotPromised(string Id, string Source, string Sentence, IReadOnlyDictionary> Axes); - -/// One claim of the universe: its axes and values, its watched paths, and the pairs it excludes. -internal sealed class Claim -{ - public required string Id { get; init; } - public required string Source { get; init; } - public required IReadOnlyList Surfaces { get; init; } - public required IReadOnlyList Watched { get; init; } - public required SortedDictionary> Axes { get; init; } - public required HashSet Excluded { get; init; } - - /// The claim's exclusions with their reasons, as claims.json holds them; universe.json keeps only . - public IReadOnlyList Exclusions { get; init; } = []; - - /// Each axis the claim drops, with the document sentence that limits it; universe.json does not keep these. - public IReadOnlyDictionary Narrowed { get; init; } = new SortedDictionary(StringComparer.Ordinal); - - /// What the claim promises, each checkable on its own, as claims.json lists them (empty: one implicit obligation, the claim); universe.json does not keep these. - public IReadOnlyList Obligations { get; init; } = []; - - /// What the claim does not promise, each with the sentence that makes it intended; universe.json does not keep these. - public IReadOnlyList NotPromised { get; init; } = []; - - /// The id of a claim's one obligation where claims.json lists none: the claim itself. - public const string ImplicitObligation = "claim"; - - /// The obligation ids of a claim as claims.json holds it: the listed ones, or the implicit one. - public static List ObligationIds(JsonObject claim) - { - var ids = (claim["obligations"] as JsonArray ?? []).OfType().Select(o => Files.Str(o["id"])).Where(id => id.Length > 0).ToList(); - return ids.Count > 0 ? ids : [ImplicitObligation]; - } - - /// The ids of the claim's obligations as built: the listed ones, or the implicit one. - public IEnumerable ObligationIdsBuilt => Obligations.Count > 0 ? Obligations.Select(o => o.Id) : [ImplicitObligation]; - - /// - /// The pairs wants: the claim's pairs less those a declaration of that obligation - /// matches on either side. An obligation that declares nothing, the implicit one among them, wants them all. - /// - public HashSet PairsWantedBy(string obligation) - { - var declared = Obligations.FirstOrDefault(o => o.Id == obligation)?.Inapplicable ?? []; - var result = Pairs(); - if (declared.Count > 0) result.RemoveWhere(p => declared.Any(d => d.Matches(p))); - return result; - } - - /// The pairs at least one obligation wants: the union of , each pair once. - public HashSet PairsWanted() - { - if (!Obligations.Any(o => o.Inapplicable.Count > 0)) return Pairs(); - var result = new HashSet(); - foreach (var id in ObligationIdsBuilt) result.UnionWith(PairsWantedBy(id)); - return result; - } - - /// - /// The pairs no obligation wants, each with the citations of the declarations that match it: declared - /// inapplicable, so no row is generated for them and the gate leaves them out as it leaves out an exclusion. - /// - public Dictionary> DeclaredInapplicable() - { - var result = new Dictionary>(); - var wanted = PairsWanted(); - foreach (var pair in Pairs()) - if (!wanted.Contains(pair)) - result[pair] = new SortedSet(Obligations.SelectMany(o => o.Inapplicable).Where(d => d.Matches(pair)).Select(d => d.Cite), StringComparer.Ordinal); - return result; - } - - public HashSet Pairs() - { - var result = new HashSet(); - var names = Axes.Keys.ToList(); - for (var i = 0; i < names.Count; i++) - for (var j = i + 1; j < names.Count; j++) - foreach (var va in Axes[names[i]]) - foreach (var vb in Axes[names[j]]) - { - var pair = new Pair($"{names[i]}={va}", $"{names[j]}={vb}"); - if (!Excluded.Contains(pair)) result.Add(pair); - } - return result; - } - - /// The pairs one row sets, restricted to the claim's axes and values (an applied value the claim does not list earns nothing). - public HashSet PairsOfRow(IReadOnlyDictionary row) - { - var items = row.Where(kv => Axes.TryGetValue(kv.Key, out var values) && values.Contains(kv.Value)) - .OrderBy(kv => kv.Key, StringComparer.Ordinal).ToList(); - var result = new HashSet(); - for (var i = 0; i < items.Count; i++) - for (var j = i + 1; j < items.Count; j++) - result.Add(new Pair($"{items[i].Key}={items[i].Value}", $"{items[j].Key}={items[j].Value}")); - return result; - } - - public JsonObject ToJson() - { - var o = new JsonObject - { - ["id"] = Id, ["source"] = Source, ["surfaces"] = new JsonArray([.. Surfaces.Select(s => (JsonNode)s)]), - ["watched"] = new JsonArray([.. Watched.Select(s => (JsonNode)s)]), - ["axes"] = new JsonObject(Axes.Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)new JsonArray([.. kv.Value.Select(v => (JsonNode)v)])))), - }; - if (Excluded.Count > 0) o["exclude"] = new JsonArray([.. Excluded.Select(p => (JsonNode)new JsonArray(p.A, p.B))]); - // Every obligation's id with its declarations, written only where one declares something, so the covering - // generator and the gate, which read universe.json, know which pairs each wants. - if (Obligations.Any(ob => ob.Inapplicable.Count > 0)) - o["obligations"] = new JsonArray([.. Obligations.Select(ob => - { - var item = new JsonObject { ["id"] = ob.Id }; - if (ob.Inapplicable.Count > 0) item["inapplicable"] = new JsonArray([.. ob.Inapplicable.Select(d => (JsonNode)d.ToJson())]); - return (JsonNode)item; - })]); - return o; - } - - public static Claim FromJson(JsonObject o) => new() - { - Id = Files.Str(o["id"]), Source = Files.Str(o["source"]), Surfaces = [.. Files.Strings(o["surfaces"])], - Watched = [.. Files.Strings(o["watched"])], - Axes = new((o["axes"] as JsonObject ?? []).ToDictionary(kv => kv.Key, kv => Files.Strings(kv.Value).ToList(), StringComparer.Ordinal), StringComparer.Ordinal), - Excluded = [.. (o["exclude"] as JsonArray ?? []).OfType().Where(p => p.Count == 2).Select(p => new Pair(Files.Str(p[0]), Files.Str(p[1])))], - Obligations = [.. (o["obligations"] as JsonArray ?? []).OfType().Select(ob => new Obligation(Files.Str(ob["id"]), "", new SortedDictionary>(StringComparer.Ordinal)) - { - Inapplicable = [.. (ob["inapplicable"] as JsonArray ?? []).OfType().Select(Prober.Axes.Declaration)], - })], - }; -} - -internal sealed class Universe -{ - public required string Base { get; init; } - public required string Commit { get; init; } - public required JsonObject GeneratedVersions { get; init; } - public required List Claims { get; init; } - public Dictionary ById => field ??= Claims.ToDictionary(c => c.Id, StringComparer.Ordinal); - - public JsonObject ToJson() => new() - { - ["schemaVersion"] = Files.SchemaVersion, ["base"] = Base, ["commit"] = Commit, - ["generated_versions"] = GeneratedVersions.DeepClone(), ["claims"] = new JsonArray([.. Claims.Select(c => (JsonNode)c.ToJson())]), - }; - - public static Universe? Load(string path) => Files.ReadJson(path) is JsonObject o ? new Universe - { - Base = Files.Str(o["base"]), Commit = Files.Str(o["commit"]), GeneratedVersions = o["generated_versions"] as JsonObject is { } g ? (JsonObject)g.DeepClone() : [], - Claims = [.. (o["claims"] as JsonArray ?? []).OfType().Select(Claim.FromJson)], - } : null; -} - -internal static class Axes -{ - /// The fenced ```json probe-axes block of the axes file: hand, ignored, refused, axes, surfaces, replay. - public static JsonObject Block(string path) - { - if (!File.Exists(path)) throw new Refusal($"no axes file at {path}"); - var text = File.ReadAllText(path); - const string marker = "```json probe-axes"; - var at = text.IndexOf(marker, StringComparison.Ordinal); - if (at < 0) throw new Refusal($"{path} has no {marker} block"); - var body = text[(at + marker.Length)..]; - body = body[..body.IndexOf("```", StringComparison.Ordinal)]; - return JsonNode.Parse(body) as JsonObject ?? throw new Refusal($"the {marker} block of {path} is not a JSON object"); - } - - /// fnmatch's "*" (any run of characters), the only wildcard the axes file uses. - public static bool Matches(string pattern, string name) => - Regex.IsMatch(name, "^" + Regex.Escape(pattern).Replace("\\*", ".*", StringComparison.Ordinal) + "$", RegexOptions.CultureInvariant); - - private static string Collapse(string s) => Regex.Replace(s, @"\s+", " "); - - /// An axis-to-values object of claims.json (an obligation's or a not-promised entry's `axes`), or none. - private static SortedDictionary> AxesOf(JsonNode? node) - { - var result = new SortedDictionary>(StringComparer.Ordinal); - foreach (var (name, values) in node as JsonObject ?? []) result[name] = [.. Files.Strings(values)]; - return result; - } - - /// A declaration of where an obligation does not apply, as claims.json and universe.json hold it. - internal static Inapplicability Declaration(JsonObject d) => new(AxesOf(d["axes"]), Files.Str(d["cite"])); - - private static readonly Regex CiteId = new("^[a-z0-9][a-z0-9-]*$"); - private static readonly Regex CiteSource = new(@"^(?!/)(?!.*(^|/)\.\.?(/|#|$))[A-Za-z0-9_./-]+\.[A-Za-z0-9]+(#[A-Za-z0-9][A-Za-z0-9._-]*)?$"); - private static readonly Regex CiteFact = new(@"^KB-\d{3}$"); - private static readonly Regex CiteRecord = new(@"^\d{4}$"); - - /// - /// What is wrong with a citation's form, or null: the forms the harness's Cite (harness/Row.cs) accepts, so - /// every declaration the universe reads, the harness can cite (CiteFormTests holds the two alike). - /// - internal static string? CiteProblem(string cite) - { - var at = cite.IndexOf(':', StringComparison.Ordinal); - var (kind, value) = at < 0 ? ("", cite) : (cite[..at], cite[(at + 1)..]); - return kind switch - { - "not-promised" => CiteId.IsMatch(value) ? null : "is not a not-promised id (not-promised:closed-set-has-no-text)", - "docs" => CiteSource.IsMatch(value) ? null : "is not a docs source (docs:docs/json.md#decimals-in-one-spelling)", - "fact" => CiteFact.IsMatch(value) ? null : "is not a knowledge entry's id (fact:KB-031)", - "record" => CiteRecord.IsMatch(value) ? null : "is not a decision record's number (record:0094)", - _ => "is not a citation (not-promised:id, docs:file#anchor, fact:KB-NNN or record:NNNN)", - }; - } - - /// Builds the universe: each claim takes every axis of its surfaces, minus quoted narrowings, plus its own axes. - public static (Universe Universe, List Problems) Build(Ledger ledger, string baseRef, List? claimsOverride = null, JsonObject? generatedOverride = null) - { - var block = ledger.AxesBlock(); - var generated = generatedOverride ?? Files.ReadJson(Path.Combine(ledger.Memory, "axes-generated.json")) as JsonObject - ?? throw new Refusal("no axes-generated.json; run `prober replay --all`, which derives the axes"); - var claims = claimsOverride ?? ledger.Claims(); - if (claims.Count == 0) throw new Refusal("no claims (tools/probe/corpus/claims.json, or the branch's staging)"); - - var ignored = block["ignored"] as JsonObject ?? []; - var hand = block["hand"] as JsonObject ?? []; - var axes = new SortedDictionary>(StringComparer.Ordinal); - foreach (var (name, values) in generated["axes"] as JsonObject ?? []) - if (!ignored.ContainsKey(name)) axes[name] = [.. Files.Strings(values)]; - var problems = new List(); - foreach (var name in Files.Strings(generated["needsValues"])) - { - if (ignored.ContainsKey(name)) continue; - if (hand[name] is JsonArray h) axes[name] = ["default", .. Files.Strings(h)]; - else problems.Add($"needs values: {name} (no hand values and not ignored)"); - } - foreach (var (name, values) in hand) - if (!axes.ContainsKey(name) && !ignored.ContainsKey(name)) axes[name] = ["default", .. Files.Strings(values)]; - foreach (var (name, values) in block["axes"] as JsonObject ?? []) axes[name] = [.. Files.Strings(values)]; - foreach (var (name, refused) in block["refused"] as JsonObject ?? []) - if (axes.TryGetValue(name, out var list) && refused is JsonObject r) axes[name] = [.. list.Where(v => !r.ContainsKey(v))]; - - var surfaces = block["surfaces"] as JsonObject ?? throw new Refusal("the axes block has no surfaces"); - var reached = new HashSet(StringComparer.Ordinal); - foreach (var (_, surface) in surfaces) - foreach (var pattern in Files.Strings(surface?["axes"])) - reached.UnionWith(axes.Keys.Where(k => Matches(pattern, k))); - var allGenerated = (generated["axes"] as JsonObject ?? []).Select(kv => kv.Key).Concat(Files.Strings(generated["needsValues"])); - foreach (var name in allGenerated.Distinct(StringComparer.Ordinal).Order(StringComparer.Ordinal)) - if (!ignored.ContainsKey(name) && axes.ContainsKey(name) && !reached.Contains(name)) - problems.Add($"unassigned: {name} (no surface reaches it and it is not ignored)"); - - var built = new List(); - foreach (var c in claims) - { - var id = Files.Str(c["id"]); var source = Files.Str(c["source"]); var sourceFile = source.Split('#')[0]; - var mine = new SortedDictionary>(StringComparer.Ordinal); - var watched = new List(); - foreach (var surfaceName in Files.Strings(c["surfaces"])) - { - if (surfaces[surfaceName] is not JsonObject surface) throw new Refusal($"claim {id} names unknown surface {surfaceName}"); - foreach (var pattern in Files.Strings(surface["axes"])) - foreach (var name in axes.Keys.Where(k => Matches(pattern, k))) mine[name] = axes[name]; - watched.AddRange(Files.Strings(surface["watched"])); - } - var sourcePath = Path.Combine(ledger.Top, sourceFile); - var sourceText = File.Exists(sourcePath) ? Collapse(File.ReadAllText(sourcePath)) : ""; - var narrowed = new SortedDictionary(StringComparer.Ordinal); - foreach (var (name, quote) in c["narrow"] as JsonObject ?? []) - { - if (!sourceText.Contains(Collapse(Files.Str(quote)), StringComparison.Ordinal)) - throw new Refusal($"claim {id} narrows {name} by a quote not found in {sourceFile}"); - mine.Remove(name); - narrowed[name] = Files.Str(quote); - } - foreach (var (name, values) in c["axes"] as JsonObject ?? []) mine[name] = [.. Files.Strings(values)]; - // What the claim promises and what it does not, each a sentence quoted from its document, checked as a - // narrowing is: a sentence the document no longer holds is a refusal, never a stale promise (decision 104). - var obligations = new List(); - var notPromisedIds = (c["not-promised"] as JsonArray ?? []).OfType().Select(n => Files.Str(n["id"])).ToHashSet(StringComparer.Ordinal); - foreach (var o in (c["obligations"] as JsonArray ?? []).OfType()) - { - var oid = Files.Str(o["id"]); - if (obligations.Any(x => x.Id == oid)) throw new Refusal($"claim {id}: obligation {oid} is listed twice"); - if (!sourceText.Contains(Collapse(Files.Str(o["sentence"])), StringComparison.Ordinal)) - throw new Refusal($"claim {id}: obligation {oid} quotes a sentence not found in {sourceFile}"); - // Where the obligation does not apply, said by the claim's own axes and values and cited: the covering - // generator, the gate and the harness read the same declarations, so they never disagree. - var declared = new List(); - foreach (var (d, i) in (o["inapplicable"] as JsonArray ?? []).OfType().Select((d, i) => (d, i))) - { - var at = $"claim {id}: obligation {oid}: inapplicable[{i}]"; - var declaration = Declaration(d); - if (declaration.Axes.Count == 0) throw new Refusal($"{at} names no axis"); - foreach (var (name, values) in declaration.Axes) - { - if (!mine.TryGetValue(name, out var listed)) throw new Refusal($"{at} names axis {name}, which the claim does not have"); - if (values.Count == 0) throw new Refusal($"{at} names no value of {name}"); - foreach (var value in values.Where(v => !listed.Contains(v))) - throw new Refusal($"{at} names {name}={value}, a value the claim does not list for {name}"); - } - if (CiteProblem(declaration.Cite) is { } problem) throw new Refusal($"{at}: cite {declaration.Cite} {problem}"); - if (declaration.Cite.StartsWith("not-promised:", StringComparison.Ordinal) && !notPromisedIds.Contains(declaration.Cite["not-promised:".Length..])) - throw new Refusal($"{at} cites {declaration.Cite}, which the claim's not-promised list does not hold"); - declared.Add(declaration); - } - obligations.Add(new Obligation(oid, Files.Str(o["sentence"]), AxesOf(o["axes"])) { Inapplicable = declared }); - } - var notPromised = new List(); - foreach (var n in (c["not-promised"] as JsonArray ?? []).OfType()) - { - var nid = Files.Str(n["id"]); var nsource = Files.Str(n["source"]); var nfile = nsource.Split('#')[0]; - if (notPromised.Any(x => x.Id == nid)) throw new Refusal($"claim {id}: not-promised {nid} is listed twice"); - var npath = Path.Combine(ledger.Top, nfile); - var ntext = File.Exists(npath) ? Collapse(File.ReadAllText(npath)) : ""; - if (!ntext.Contains(Collapse(Files.Str(n["sentence"])), StringComparison.Ordinal)) - throw new Refusal($"claim {id}: not-promised {nid} quotes a sentence not found in {nfile}"); - notPromised.Add(new NotPromised(nid, nsource, Files.Str(n["sentence"]), AxesOf(n["axes"]))); - } - // The claims file's schema holds the form (Ledger.ReadClaims): each entry a reason and its pairs. - List exclusions = [.. (c["exclude"] as JsonArray ?? []).OfType().Select(e => new Exclusion(Files.Str(e["reason"]), - [.. (e["pairs"] as JsonArray ?? []).OfType().Select(p => new Pair(Files.Str(p[0]), Files.Str(p[1])))]))]; - built.Add(new Claim - { - Id = id, Source = source, Surfaces = [.. Files.Strings(c["surfaces"])], - Watched = [.. watched.Append(sourceFile).Distinct(StringComparer.Ordinal).Order(StringComparer.Ordinal)], Axes = mine, - Excluded = [.. exclusions.SelectMany(e => e.Pairs)], Exclusions = exclusions, Narrowed = narrowed, - Obligations = obligations, NotPromised = notPromised, - }); - } - var universe = new Universe - { - Base = Git.Out(ledger.Top, "merge-base", "HEAD", baseRef), Commit = ledger.Head, - GeneratedVersions = generated["versions"] as JsonObject is { } v ? (JsonObject)v.DeepClone() : [], Claims = built, - }; - Files.WriteJson(ledger.P("universe.json"), universe.ToJson()); - return (universe, problems); - } -} diff --git a/tools/Prober/Commands.cs b/tools/Prober/Commands.cs deleted file mode 100644 index 91cc7df3..00000000 --- a/tools/Prober/Commands.cs +++ /dev/null @@ -1,747 +0,0 @@ -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Xml.Linq; - -namespace Prober; - -/// The command line: a command, then --name value options and --flag switches. -internal sealed class Args -{ - private readonly Dictionary> options = new(StringComparer.Ordinal); - public List Positional { get; } = []; - - public Args(IEnumerable argv, IReadOnlySet flags) - { - var list = argv.ToList(); - for (var i = 0; i < list.Count; i++) - { - var a = list[i]; - if (!a.StartsWith("--", StringComparison.Ordinal)) { Positional.Add(a); continue; } - var name = a[2..]; - if (flags.Contains(name)) { Add(name, "true"); continue; } - // A multi-value option takes values until the next option. - var any = false; - while (i + 1 < list.Count && !list[i + 1].StartsWith("--", StringComparison.Ordinal)) { Add(name, list[++i]); any = true; if (!Multi.Contains(name)) break; } - if (!any) Add(name, ""); - } - } - - private static readonly HashSet Multi = new(StringComparer.Ordinal) { "cobertura", "include", "compile-time", "from", "seed-env" }; - private void Add(string name, string value) { if (!options.TryGetValue(name, out var l)) options[name] = l = []; l.Add(value); } - public string? Get(string name) => options.TryGetValue(name, out var l) ? l[^1] : null; - public string Need(string name) => Get(name) is { Length: > 0 } v ? v : throw new Refusal($"--{name} is required", 2); - public bool Flag(string name) => options.ContainsKey(name); - public List All(string name) => options.TryGetValue(name, out var l) ? l : []; -} - -internal static class Commands -{ - private static readonly JsonSerializerOptions Pretty = new() { WriteIndented = true }; - private static string Today => DateTime.Now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); - - public static int Rows(Ledger l, Args a) - { - if (a.Get("probe") is not { Length: > 0 } probe) - { - l.Ctx.Out.WriteLine(CoveringRows(l, a.Need("claim"), a.Flag("full"), a.Get("max"), a.Get("seed")).ToJsonString(Pretty)); - return 0; - } - if (!l.Registry().TryGetValue(probe, out var entry)) throw new Refusal($"no probe {probe} in the registry, tracked or staged; `prober new` stages one", 2); - var claimId = Files.Str(entry["claim"]); - if (a.Get("claim") is { Length: > 0 } named && named != claimId) throw new Refusal($"{probe} is a probe of {claimId}, not of {named}", 2); - var (rows, uncovered) = StageRows(l, probe, claimId, a.Flag("full"), a.Get("max"), a.Get("seed")); - l.Ctx.Out.WriteLine($"rows/{probe}.json: {rows} rows for claim {claimId} over its pairs{(a.Flag("full") ? "" : " its other probes have not covered")}" + - $"{(uncovered > 0 ? $", {uncovered} left uncovered" : "")}; staged in {l.StagingDir}, the file written whole. " + - "`prober publish` moves it into the corpus"); - return 0; - } - - /// - /// Writes a probe's rows file in the staging, whole, never appended: a covering array over its claim's pairs (all of - /// them with ) less those the claim's other probes have credited. The probe's own credit is - /// not subtracted, since it came from the rows this file replaces and ends with them. The stored rows are - /// definitions; the evidence is in the state. - /// - internal static (int Rows, int Uncovered) StageRows(Ledger l, string probe, string claimId, bool full, string? max = null, string? seed = null) - { - var covering = CoveringRows(l, claimId, full, max, seed, except: probe); - var rows = new JsonArray([.. (covering["rows"] as JsonArray ?? []).Select(r => (JsonNode)new JsonObject { ["row"] = r?["row"]?.DeepClone() })]); - Files.WriteJson(Path.Combine(l.StagingDir, "rows", probe + ".json"), new JsonObject { ["claim"] = claimId, ["rows"] = rows }); - return (rows.Count, (int)Files.Num(covering["uncovered_after"])); - } - - /// - /// What `rows` prints: a pairwise covering array over the claim's pairs not yet covered (all of them with - /// ), each row with the pairs it covers. Inside a capped round the claim counts toward - /// the round's cap, and past the deadline or the cap this refuses. - /// - public static JsonObject CoveringRows(Ledger l, string claimId, bool full, string? max = null, string? seed = null, string? except = null) - { - var universe = Universe.Load(l.P("universe.json")) ?? throw new Refusal("no universe.json for this branch yet; run `universe` first"); - if (!universe.ById.TryGetValue(claimId, out var claim)) throw new Refusal($"no claim {claimId} in the universe"); - if (!full && ActiveRound(l) is { } round) - { - if (RoundLock.Now() > Files.Num(round["deadline"])) - throw new Refusal("the round's time is spent; start no new work. Record what ran, hand the corpus off, and report."); - var started = round["claims"] as JsonArray ?? []; - if (!Files.Strings(started).Contains(claimId)) - { - if (round["max_claims"] is JsonValue m && m.TryGetValue(out var cap) && started.Count >= cap) - throw new Refusal($"the round's cap of {cap} claim(s) is reached ({string.Join(", ", Files.Strings(started))}); finish those and report."); - started.Add(claimId); - round["claims"] = started.DeepClone(); - Files.WriteJson(l.P("round.json"), round); - } - } - var covered = full ? [] : l.Covered(universe, claimId, except); - // The pairs some obligation wants: a pair declared inapplicable for every obligation is asked for by no row. - var todo = claim.PairsWanted().Where(p => !covered.Contains((claimId, p))).ToHashSet(); - var rows = Covering.Rows(claim, todo, int.Parse(max ?? "2000", CultureInfo.InvariantCulture), int.Parse(seed ?? "1", CultureInfo.InvariantCulture)); - return new JsonObject - { - ["claim"] = claimId, - ["rows"] = new JsonArray([.. rows.Select(r => (JsonNode)new JsonObject - { - ["row"] = new JsonObject(r.Row.Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)kv.Value))), - ["pairs"] = new JsonArray([.. r.Pairs.Select(p => (JsonNode)new JsonArray(p.A, p.B))]), - })]), - ["uncovered_after"] = todo.Count - rows.Sum(r => r.Pairs.Count), - }; - } - - public static int UniverseCommand(Ledger l, Args a) - { - var claims = a.Get("claims") is { } cp ? Ledger.ReadClaims(cp, cp) : null; - var generated = a.Get("generated") is { } gp ? Files.ReadJson(gp) as JsonObject : null; - var (universe, problems) = Axes.Build(l, a.Get("base") ?? "origin/main", claims, generated); - var total = 0; - foreach (var c in universe.Claims) - { - var n = c.Pairs().Count; total += n; - l.Ctx.Out.WriteLine($"{c.Id}: {c.Axes.Count} axes, {n} pairs"); - // What the claim leaves out and why: a narrowing's quote is checked against its document, an exclusion's reason by a reviewer only. - foreach (var (axis, quote) in c.Narrowed) l.Ctx.Out.WriteLine($" narrow {axis}: \"{quote}\""); - foreach (var e in c.Exclusions) - l.Ctx.Out.WriteLine($" exclude {e.Pairs.Count} pair(s), first {e.Pairs[0]}: {e.Reason}"); - if (Inapplicable(c) is { } line) l.Ctx.Out.WriteLine($" {line}"); - } - l.Ctx.Out.WriteLine($"universe: {universe.Claims.Count} claims, {total} pairs"); - foreach (var p in problems) l.Ctx.Out.WriteLine($" {p}"); - return 0; - } - - /// - /// The pairs of a claim no obligation wants, as one line: their count, the first, and the citations of the - /// declarations that leave them out; null where there are none. - /// - private static string? Inapplicable(Claim c) - { - var dead = c.DeclaredInapplicable(); - if (dead.Count == 0) return null; - var first = dead.Keys.OrderBy(p => p.A, StringComparer.Ordinal).ThenBy(p => p.B, StringComparer.Ordinal).First(); - var cites = new SortedSet(dead.Values.SelectMany(x => x), StringComparer.Ordinal); - return $"inapplicable {dead.Count} pair(s), wanted by no obligation, first {first}: {string.Join(", ", cites)}"; - } - - public static JsonObject ComputeStatus(Ledger l) - { - var universe = Universe.Load(l.P("universe.json")); - if (universe is null) return new JsonObject { ["branch"] = l.Branch, ["done"] = false, ["reason"] = "no universe.json: run `universe` (no round has run here)" }; - var credits = l.Credits(universe); - var done = credits.Select(x => (x.Claim, x.Pair)).ToHashSet(); - // How the rows and the checks of each claim's probes ended at their last replay: only a passing check earns - // pairs, so the rest is what the claim's coverage loses, and a skip for a finding is an open finding the corpus - // records. A row without checks counts as its one check. - var outcomes = new Dictionary>(StringComparer.Ordinal); - var checkOutcomes = new Dictionary>(StringComparer.Ordinal); - var passed = new Dictionary>(StringComparer.Ordinal); - var skips = new SortedDictionary(StringComparer.Ordinal); - foreach (var (probe, entry) in l.Registry()) - { - var evidence = Files.ReadJson(l.EvidencePath(probe)) as JsonObject; - var claim = Files.Str(entry["claim"]); - var sum = outcomes.TryGetValue(claim, out var o) ? o : outcomes[claim] = new(StringComparer.Ordinal); - foreach (var (category, n) in Ledger.Outcomes(evidence)) sum[category] = sum.GetValueOrDefault(category) + n; - var checkSum = checkOutcomes.TryGetValue(claim, out var co) ? co : checkOutcomes[claim] = new(StringComparer.Ordinal); - if (evidence is not null) foreach (var (category, n) in Ledger.CheckOutcomes(evidence)) checkSum[category] = checkSum.GetValueOrDefault(category) + n; - (passed.TryGetValue(claim, out var p) ? p : passed[claim] = new(StringComparer.Ordinal)).UnionWith(Ledger.PassedObligations(evidence)); - foreach (var (finding, n) in Ledger.FindingSkips(evidence)) skips[finding] = skips.GetValueOrDefault(finding) + n; - } - // Each claim's obligations (decision 104), the probes registered for the claim, and the probes whose seeds - // break each obligation: the claim's promise is checked only where a probe can be shown to fail on it. - var listed = l.Claims().ToDictionary(c => Files.Str(c["id"]), Claim.ObligationIds, StringComparer.Ordinal); - var registry = l.Registry(); - var claims = new JsonObject(); var total = 0; var current = 0; var inapplicableTotal = 0; var wantedTotal = 0; var wantedCurrent = 0; - foreach (var c in universe.Claims) - { - var pairs = c.Pairs(); var hit = pairs.Count(p => done.Contains((c.Id, p))); - // The pairs no obligation wants are declared inapplicable: left out of what is still to cover, as the gate leaves them out. - var wanted = c.PairsWanted(); var inapplicable = pairs.Count - wanted.Count; - inapplicableTotal += inapplicable; wantedTotal += wanted.Count; wantedCurrent += wanted.Count(p => done.Contains((c.Id, p))); - var probes = registry.Where(kv => Files.Str(kv.Value["claim"]) == c.Id).ToList(); - var ids = listed.GetValueOrDefault(c.Id) ?? [Claim.ImplicitObligation]; - var obligations = new JsonArray(); - foreach (var id in ids) - { - var seededBy = probes.Where(kv => Seeds.SeedsOf(kv.Value).Any(s => (s.Obligation ?? (ids is [Claim.ImplicitObligation] ? Claim.ImplicitObligation : null)) == id)) - .Select(kv => (JsonNode)kv.Key).ToList(); - // current: the claim's pairs credited by current checks naming this obligation; passed: whether any check - // named it and passed at the last replay, current or not (status's "K uncredited" counts those that did not). - obligations.Add(new JsonObject - { - ["id"] = id, ["seeded_by"] = new JsonArray([.. seededBy]), - ["current"] = pairs.Count(p => credits.Contains((c.Id, id, p))), - ["passed"] = passed.GetValueOrDefault(c.Id)?.Contains(id) ?? false, - }); - } - claims[c.Id] = new JsonObject - { - ["pairs"] = pairs.Count, ["current"] = hit, ["inapplicable_pairs"] = inapplicable, - ["outcomes"] = new JsonObject((outcomes.GetValueOrDefault(c.Id) ?? []).Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)kv.Value))), - ["check_outcomes"] = new JsonObject((checkOutcomes.GetValueOrDefault(c.Id) ?? []).Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)kv.Value))), - ["probes"] = new JsonArray([.. probes.Select(kv => (JsonNode)kv.Key)]), ["obligations"] = obligations, - }; - total += pairs.Count; current += hit; - } - var open = l.OpenFindings(); - return new JsonObject - { - ["branch"] = l.Branch, ["head"] = l.Head, ["universe_commit"] = universe.Commit, ["pairs"] = total, ["current"] = current, - ["inapplicable_pairs"] = inapplicableTotal, - ["share"] = total > 0 ? Math.Round((double)current / total, 4) : 1.0, - ["open_findings"] = new JsonArray([.. open.Select(f => (JsonNode)f)]), - ["skipped_for_findings"] = new JsonObject(skips.Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)kv.Value))), ["claims"] = claims, - ["done"] = total > 0 && wantedCurrent == wantedTotal && open.Count == 0, - }; - } - - public static int Status(Ledger l, Args a) - { - var s = ComputeStatus(l); - if (a.Flag("json")) { l.Ctx.Out.WriteLine(s.ToJsonString(Pretty)); return 0; } - if (s["reason"] is { } reason) { l.Ctx.Out.WriteLine($"{l.Branch}: not done ({Files.Str(reason)})"); return 0; } - var open = Files.Strings(s["open_findings"]).ToList(); - l.Ctx.Out.WriteLine($"{l.Branch} at {Files.Str(s["head"])[..7]}: {Files.Num(s["current"])} of {Files.Num(s["pairs"])} pairs current " + - $"({(Files.Num(s["share"]) * 100).ToString("F1", CultureInfo.InvariantCulture)}%), {open.Count} open finding(s)" + - (open.Count > 0 ? ": " + string.Join(", ", open) : "") + $" -> {(s["done"]!.GetValue() ? "DONE" : "not done")}"); - foreach (var (finding, rows) in (s["skipped_for_findings"] as JsonObject)!) - l.Ctx.Out.WriteLine($" {rows} row(s) skip for finding {finding}"); - foreach (var (id, c) in (s["claims"] as JsonObject)!.OrderBy(kv => kv.Key, StringComparer.Ordinal)) - { - var rows = (c!["outcomes"] as JsonObject)!.Select(kv => $"{kv.Key} {Files.Num(kv.Value)}").ToList(); - var checks = (c["check_outcomes"] as JsonObject ?? []).Select(kv => $"{kv.Key} {Files.Num(kv.Value)}").ToList(); - var obligations = (c["obligations"] as JsonArray ?? []).OfType().ToList(); - var unseeded = obligations.Where(o => (o["seeded_by"] as JsonArray ?? []).Count == 0).Select(o => Files.Str(o["id"])).ToList(); - // K uncredited: the obligations no passing check named at the last replay. - var uncredited = obligations.Count(o => o["passed"] is not JsonValue v || !v.GetValue()); - var promise = obligations.Count == 0 ? "" : $" obligations {obligations.Count}" + (unseeded.Count > 0 ? $" ({unseeded.Count} without a seed: {string.Join(", ", unseeded)})" : ", each seeded") - + $", {uncredited} uncredited"; - var inapplicable = Files.Num(c["inapplicable_pairs"]) is var n and > 0 ? $", {n} inapplicable" : ""; - l.Ctx.Out.WriteLine($" {id}: {Files.Num(c["current"])}/{Files.Num(c["pairs"])}{inapplicable}" + (rows.Count > 0 ? $" (rows: {string.Join(", ", rows)}; checks: {string.Join(", ", checks)})" : "") + promise); - } - return 0; - } - - /// - /// What the corpus leaves out, each with its recorded reason, from the tracked corpus and the generated axes - /// alone: the settings no surface reaches and nothing ignores, the settings without values, the declarations - /// the generators refuse, the values the frameworks refuse on their own, what the claims say they do not - /// promise (their not-promised entries and narrowings), and the surfaces the axes file declares out of reach. - /// A report for the release checklist and a feature-research round; it decides nothing (decision 104). - /// - public static int Gaps(Ledger l, Args a) - { - var (universe, problems) = Axes.Build(l, a.Get("base") ?? "origin/main"); - var block = l.AxesBlock(); - var generated = Files.ReadJson(Path.Combine(l.Memory, "axes-generated.json")) as JsonObject ?? []; - var versions = string.Join(", ", (generated["versions"] as JsonObject ?? []).Select(kv => $"{kv.Key} {Files.Str(kv.Value)}")); - l.Ctx.Out.WriteLine($"prober gaps: {l.Branch} at {l.Head[..7]}: what the corpus leaves out, each with its recorded reason; a report, no decision"); - Section("settings no surface reaches and nothing ignores" + (versions.Length > 0 ? $" (enumerated at {versions})" : ""), - problems.Where(p => p.StartsWith("unassigned: ", StringComparison.Ordinal)).Select(p => p["unassigned: ".Length..])); - Section("settings without values", problems.Where(p => p.StartsWith("needs values: ", StringComparison.Ordinal)).Select(p => p["needs values: ".Length..])); - Section("declarations the generators refuse (shape.refused-kind)", Files.Strings(block["axes"]?["shape.refused-kind"])); - Section("values the frameworks refuse on their own", - (block["refused"] as JsonObject ?? []).SelectMany(axis => (axis.Value as JsonObject ?? []).Select(v => $"{axis.Key}={v.Key}: {Files.Str(v.Value)}"))); - Section("not promised, by what it concerns", - universe.Claims.SelectMany(c => c.NotPromised.Select(n => (Key: Concerns(n.Axes), Line: $"{Concerns(n.Axes)}: {c.Id}/{n.Id} \"{n.Sentence}\" ({n.Source})")) - .Concat(c.Narrowed.Select(kv => (Key: kv.Key, Line: $"{kv.Key}: {c.Id} narrows it, \"{kv.Value}\" ({c.Source})")))) - .OrderBy(x => x.Key, StringComparer.Ordinal).ThenBy(x => x.Line, StringComparer.Ordinal).Select(x => x.Line)); - Section("pairs no obligation wants (declared inapplicable)", - universe.Claims.Select(c => Inapplicable(c) is { } line ? $"{c.Id}: {line}" : null).OfType()); - Section("pairs no passing check read both axes of (the last replay's evidence)", Unread(l, universe)); - Section("out of reach", (block["out-of-reach"] as JsonObject ?? []).Select(kv => $"{kv.Key}: {Files.Str(kv.Value)}")); - return 0; - - void Section(string title, IEnumerable items) - { - var list = items.ToList(); - l.Ctx.Out.WriteLine($"{title}: {(list.Count == 0 ? "none" : list.Count.ToString(CultureInfo.InvariantCulture))}"); - foreach (var item in list) l.Ctx.Out.WriteLine($" {item}"); - } - - static string Concerns(IReadOnlyDictionary> axes) => - axes.Count == 0 ? "the whole claim" : string.Join(" ", axes.Select(kv => $"{kv.Key}={string.Join("|", kv.Value)}")); - } - - /// - /// The wanted pairs of each claim with evidence that no passing check could earn: no obligation that wants the pair - /// has a passing check, in its probes' last replay, that read both of the pair's axes. More rows cannot cover such a - /// pair; a check that reads both axes, an exclusion or a declaration can (#54's four C11 pairs, wanted by obligations - /// whose checks never read shape.wrapped). A claim whose probes have no evidence is left out. - /// - private static IEnumerable Unread(Ledger l, Universe universe) - { - var registry = l.Registry(); - foreach (var claim in universe.Claims.OrderBy(c => c.Id, StringComparer.Ordinal)) - { - // The axes each obligation's passing checks read together, as "a\nb" with a before b. - var read = new Dictionary>(StringComparer.Ordinal); - var any = false; - foreach (var (probe, entry) in registry) - { - if (Files.Str(entry["claim"]) != claim.Id || Files.ReadJson(l.EvidencePath(probe)) is not JsonObject evidence) continue; - any = true; - foreach (var (_, row) in evidence["rows"] as JsonObject ?? []) - if (row is JsonObject r) - foreach (var check in Ledger.ChecksOf(r).Where(c => c.Category == "pass")) - { - if (!read.TryGetValue(check.Obligation, out var axes)) read[check.Obligation] = axes = new(StringComparer.Ordinal); - var names = check.Applied.Keys.Order(StringComparer.Ordinal).ToList(); - for (var i = 0; i < names.Count; i++) - for (var j = i + 1; j < names.Count; j++) axes.Add(names[i] + "\n" + names[j]); - } - } - if (!any) continue; - var wantedBy = claim.ObligationIdsBuilt.Concat(read.Keys).Distinct(StringComparer.Ordinal).ToDictionary(o => o, claim.PairsWantedBy, StringComparer.Ordinal); - foreach (var pair in claim.PairsWanted().OrderBy(p => p.A, StringComparer.Ordinal).ThenBy(p => p.B, StringComparer.Ordinal)) - { - var (a, b) = (Axis(pair.A), Axis(pair.B)); - var both = string.CompareOrdinal(a, b) <= 0 ? a + "\n" + b : b + "\n" + a; - if (!wantedBy.Any(o => o.Value.Contains(pair) && read.TryGetValue(o.Key, out var axes) && axes.Contains(both))) - yield return $"{claim.Id}: {pair.A} {pair.B}"; - } - } - - static string Axis(string setting) => setting[..setting.IndexOf('=', StringComparison.Ordinal)]; - } - - public static int Gate(Ledger l, Args a) => ReleaseGate.Run(l, a.Get("since"), a.Flag("json")); - - public static int Footprint(Ledger l, Args a) - { - var worktree = Path.GetFullPath(a.Need("root")); - var include = a.All("include") is { Count: > 0 } inc ? inc : ["src"]; - var hit = new SortedSet(StringComparer.Ordinal); - foreach (var report in a.All("cobertura")) - { - var doc = XDocument.Load(report); - var sources = doc.Descendants("source").Select(s => Path.GetFullPath(s.Value)).ToList(); - foreach (var cls in doc.Descendants("class")) - { - if (!cls.Descendants("line").Any(line => int.TryParse((string?)line.Attribute("hits"), out var h) && h > 0)) continue; - var name = (string?)cls.Attribute("filename") ?? ""; - var candidates = Path.IsPathRooted(name) ? [name] : sources.Count > 0 ? sources.Select(s => Path.Combine(s, name)).ToList() : [name]; - foreach (var candidate in candidates) - { - var full = Path.GetFullPath(candidate); - if (!full.StartsWith(worktree + Path.DirectorySeparatorChar, StringComparison.Ordinal)) continue; - var rel = Path.GetRelativePath(worktree, full).Replace('\\', '/'); - if (include.Any(p => rel == p || rel.StartsWith(p.TrimEnd('/') + "/", StringComparison.Ordinal))) hit.Add(rel); - break; - } - } - } - // A probe whose own process runs nothing under the include paths (one that builds a consumer in a child process, as C22 - // does) is recorded by what its registry entry watches; with nothing watched either, the footprint would never go stale. - var watchedPaths = l.Watched(a.Need("probe")); - if (hit.Count == 0 && watchedPaths.Count == 0) - throw new Refusal("the coverage report shows no executed file under " + string.Join(", ", include) + - " and the registry entry watches nothing; refusing to record an empty footprint (it would never go stale): name what the probe depends on in its entry's watched"); - var rev = Git.Out(worktree, "rev-parse", "HEAD"); - var footprint = new JsonObject(hit.Select(p => KeyValuePair.Create(p, (JsonNode?)Git.ObjectId(worktree, p)))); - var compileTime = new JsonObject(a.All("compile-time").Select(p => KeyValuePair.Create(p, (JsonNode?)Git.ObjectId(worktree, p)))); - // What the probe's registry entry watches beyond what ran: recorded with the ids it ran at, so a change stales it. - var watched = new JsonObject(watchedPaths.Select(p => KeyValuePair.Create(p, (JsonNode?)Git.ObjectId(worktree, p)))); - Files.AppendLine(l.P("footprints.jsonl"), new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["probe"] = a.Need("probe"), ["commit"] = rev, ["footprint"] = footprint, - ["compileTime"] = compileTime, ["watched"] = watched, ["toolchain"] = l.Toolchain().DeepClone(), ["date"] = a.Get("date") ?? Today, - }); - l.Ctx.Out.WriteLine($"{a.Need("probe")}: {footprint.Count} src files, {compileTime.Count} compile-time paths" + - $"{(watched.Count > 0 ? $", {watched.Count} watched" : "")} at {rev[..Math.Min(7, rev.Length)]}"); - return 0; - } - - public static int Stale(Ledger l, Args a) - { - var states = l.ProbeStates(a.Flag("include-retired")); - if (a.Flag("json")) - { - l.Ctx.Out.WriteLine(new JsonArray([.. states.Select(s => (JsonNode)new JsonObject - { - ["probe"] = s.Probe, ["claim"] = s.Claim, ["filter"] = s.Filter, ["variants"] = s.Variants.DeepClone(), ["stale"] = s.Stale, - ["retired"] = s.Retired, ["passes"] = s.Passes, ["replay"] = s.Replay, - })]).ToJsonString(Pretty)); - return 0; - } - var todo = states.Where(s => s.Replay).ToList(); - l.Ctx.Out.WriteLine($"{todo.Count} of {states.Count} probes to replay{(a.Flag("include-retired") ? " (retired included)" : "")}"); - foreach (var s in todo) l.Ctx.Out.WriteLine($" {s.Probe} {s.Filter}"); - return 0; - } - - public static int RecordRun(Ledger l, Args a) - { - var probe = a.Need("probe"); var result = a.Need("result"); - if (result is not ("pass" or "fail")) throw new Refusal("--result is pass or fail", 2); - var rev = l.Head; var identity = l.Identity(probe); - // A regression is a probe that passed with this very identity and fails now; after any change to its - // corpus, axes, environment or this tool, a failure is the probe's to triage, not the product's. - var passes = Files.ReadLines(l.P("runs.jsonl")).Where(x => Files.Str(x["probe"]) == probe && Files.Str(x["result"]) == "pass").ToList(); - var passedBefore = passes.Any(x => Files.Str(x["identity"]) == identity); - Files.AppendLine(l.P("runs.jsonl"), new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["probe"] = probe, ["result"] = result, ["commit"] = rev, ["date"] = a.Get("date") ?? Today, - ["seconds"] = a.Get("seconds") is { } s ? double.Parse(s, CultureInfo.InvariantCulture) : null, ["identity"] = identity, - }); - if (a.Get("evidence") is { } evidencePath) - { - var evidence = Files.ReadJson(evidencePath) as JsonObject ?? []; - evidence["schemaVersion"] = Files.EvidenceSchemaVersion; evidence["probe"] = probe; evidence["identity"] = identity; - evidence["commit"] = rev; evidence["result"] = result; evidence["date"] = a.Get("date") ?? Today; - Files.WriteJson(l.EvidencePath(probe), evidence); - } - if (result == "fail" && passes.Count > 0 && !passedBefore) - l.Ctx.Out.WriteLine($"{probe}: fails after a change to its corpus, axes, environment or this tool; triage the probe, not the product"); - if (result == "fail" && passedBefore) - Files.AppendLine(l.P("findings.jsonl"), new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["id"] = $"R-{probe}-{rev[..7]}", ["claim"] = Files.Str(l.Registry().GetValueOrDefault(probe)?["claim"]), - ["status"] = "open", ["commit"] = rev, ["probe"] = probe, ["reason"] = "replay: a probe that passed with this identity fails at this commit", - }); - return 0; - } - - public static int IdentityCommand(Ledger l, Args a) { l.Ctx.Out.WriteLine(l.Identity(a.Need("probe"))); return 0; } - - public static int Register(Ledger l, Args a) - { - // A note or a skip built from text fails at run time after a build and a replay; the staged sources are read first. - SourceLint.Refuse(l, "register"); - var path = Path.Combine(l.StagingDir, "registry.json"); - var staged = Files.ReadJson(path) as JsonObject ?? new JsonObject { ["probes"] = new JsonObject() }; - var probes = staged["probes"] as JsonObject ?? []; - var entry = l.Registry().GetValueOrDefault(a.Need("probe")) ?? []; - entry["claim"] = a.Need("claim"); entry["filter"] = a.Need("filter"); - if (a.Get("variants") is { Length: > 0 } v) entry["variants"] = JsonNode.Parse(v); - // The defect `seeds` applies to prove the probe can fail (decision 100): a patch under the corpus, an - // environment toggle, or both, and what it breaks. - var seed = new JsonObject(); - if (a.Get("seed") is { Length: > 0 } patch) seed["patch"] = patch; - if (a.All("seed-env") is { Count: > 0 } toggles) seed["env"] = SeedEnv(toggles); - if (a.Get("obligation") is { } obligation) - { - // A seed per obligation (decision 104): into `seeds`, in place of any seed that names the same obligation. - if (obligation.Length == 0) throw new Refusal("--obligation needs the id of one of the claim's obligations", 2); - if (seed.Count == 0) throw new Refusal("--obligation names the obligation of a seed: give the seed with --seed PATCH or --seed-env NAME=VALUE", 2); - var claim = l.Claims().FirstOrDefault(c => Files.Str(c["id"]) == a.Need("claim")) - ?? throw new Refusal($"no claim {a.Need("claim")} in claims.json (tracked or staged), so obligation {obligation} cannot be checked"); - var ids = Claim.ObligationIds(claim); - if (!ids.Contains(obligation)) - throw new Refusal($"claim {a.Need("claim")} lists no obligation {obligation} (it lists {string.Join(", ", ids)})", 2); - var named = new JsonObject { ["obligation"] = obligation }; - foreach (var (key, value) in seed) named[key] = value?.DeepClone(); - named["defect"] = a.Need("defect"); - var kept = (entry["seeds"] as JsonArray ?? []).Where(s => Files.Str(s?["obligation"]) != obligation).Select(s => s?.DeepClone()).ToList(); - var replaced = (entry["seeds"] as JsonArray ?? []).Count - kept.Count; - entry["seeds"] = new JsonArray([.. kept, named]); - if (entry["seed"] is JsonObject one && Files.Str(one["obligation"]) == obligation) { entry.Remove("seed"); replaced++; } - l.Ctx.Out.WriteLine($"seed for obligation {obligation} of {a.Need("probe")}" + (replaced > 0 ? $", in place of the {replaced} it had" : "")); - } - else if (seed.Count > 0) { seed["defect"] = a.Need("defect"); entry["seed"] = seed; } - probes[a.Need("probe")] = entry; - staged["probes"] = probes.DeepClone(); - Files.WriteJson(path, staged); - l.Ctx.Out.WriteLine($"registered {a.Need("probe")} (staged; `publish` moves it into the corpus)"); - return 0; - } - - /// A seed's environment toggle from --seed-env NAME=VALUE ...; a toggle without a name or an = is refused. - private static JsonObject SeedEnv(List toggles) - { - var env = new JsonObject(); - foreach (var toggle in toggles) - { - var eq = toggle.IndexOf('=', StringComparison.Ordinal); - if (eq <= 0) throw new Refusal($"--seed-env {toggle}: a toggle is NAME=VALUE", 2); - env[toggle[..eq]] = toggle[(eq + 1)..]; - } - return env; - } - - public static int Publish(Ledger l, Args a) - { - if (!Directory.Exists(l.StagingDir)) { l.Ctx.Out.WriteLine("nothing staged"); return 0; } - SourceLint.Refuse(l, "publish"); - var moved = new List(); - foreach (var src in Directory.EnumerateFiles(l.StagingDir, "*", SearchOption.AllDirectories).Order(StringComparer.Ordinal)) - { - var rel = Path.GetRelativePath(l.StagingDir, src).Replace('\\', '/'); - var dst = Path.Combine(l.CorpusDir, rel); - if (rel == "registry.json") - { - var tracked = Files.ReadJson(dst) as JsonObject ?? new JsonObject { ["probes"] = new JsonObject() }; - var probes = tracked["probes"] as JsonObject ?? []; - foreach (var (name, e) in Files.ReadJson(src)?["probes"] as JsonObject ?? []) probes[name] = e?.DeepClone(); - tracked["probes"] = new JsonObject(probes.OrderBy(kv => kv.Key, StringComparer.Ordinal).Select(kv => KeyValuePair.Create(kv.Key, kv.Value?.DeepClone()))); - Files.WriteJson(dst, tracked); - } - else if (rel == "claims.json") - { - var merged = new SortedDictionary(StringComparer.Ordinal); - foreach (var c in Ledger.ReadClaims(dst, "the corpus's claims.json").Concat(Ledger.ReadClaims(src, "the staged claims.json"))) - merged[Files.Str(c["id"])] = c.DeepClone(); - Files.WriteJson(dst, new JsonArray([.. merged.Values])); - } - else if (rel.StartsWith("rows/", StringComparison.Ordinal) && rel.EndsWith(".json", StringComparison.Ordinal)) - { - // A probe's rows, by probe: the file keeps the claim it names, else its probe's registry entry's. - var probe = Path.GetFileNameWithoutExtension(rel); - var claim = Files.Str(Files.ReadJson(src)?["claim"]) is { Length: > 0 } named ? named - : l.Registry().GetValueOrDefault(probe)?["claim"] is { } registered ? Files.Str(registered) - : throw new Refusal($"the staged {rel} names no claim and {probe} is no registered probe; a rows file is a probe's, its claim inside"); - Files.WriteRowsGzipped(dst + ".gz", claim, Files.ReadRows(src).OfType().Select(r => r["row"] as JsonObject ?? r)); - rel += ".gz"; - } - else if (rel.EndsWith(".jsonl", StringComparison.Ordinal)) - { - Directory.CreateDirectory(Path.GetDirectoryName(dst)!); - Files.WriteAtomically(dst, (File.Exists(dst) ? SharedFile.ReadAllText(dst) : "") + SharedFile.ReadAllText(src)); - } - else - { - Directory.CreateDirectory(Path.GetDirectoryName(dst)!); - File.Copy(src, dst, overwrite: true); - } - moved.Add(rel); - } - Directory.Delete(l.StagingDir, recursive: true); - l.Ctx.Out.WriteLine($"published {moved.Count} file(s) into {Path.GetRelativePath(l.Top, l.CorpusDir).Replace('\\', '/')}:"); - foreach (var rel in moved) l.Ctx.Out.WriteLine($" {rel}"); - return 0; - } - - public static int Mark(Ledger l, Args a) - { - if (a.Positional.FirstOrDefault() != "retired") throw new Refusal("mark takes `retired`", 2); - var probe = a.Need("probe"); - if (!l.Registry().TryGetValue(probe, out var entry)) throw new Refusal($"no probe {probe} in the registry"); - var path = Path.Combine(l.StagingDir, "registry.json"); - var staged = Files.ReadJson(path) as JsonObject ?? new JsonObject { ["probes"] = new JsonObject() }; - entry["retired"] = true; - (staged["probes"] as JsonObject)![probe] = entry; - Files.WriteJson(path, staged); - l.Ctx.Out.WriteLine($"{probe} retired (staged)"); - return 0; - } - - public static int Dismiss(Ledger l, Args a) - { - Files.AppendLine(Path.Combine(l.StagingDir, "dismissed.jsonl"), - new JsonObject { ["schemaVersion"] = Files.SchemaVersion, ["id"] = a.Need("id"), ["reason"] = a.Need("reason"), ["date"] = a.Get("date") ?? Today }); - l.Ctx.Out.WriteLine($"{a.Need("id")} dismissed (staged; `publish` puts it in the corpus)"); - return 0; - } - - /// - /// Records an open finding fixed at a commit: the fixed line of findings.jsonl (finding-line.schema.json), with the - /// open line's claim and probe and the commit's full id. It refuses an id this ledger does not hold open and a - /// commit the repository does not have; a commit outside HEAD's history is recorded and counts once it is in it. - /// - public static int Fix(Ledger l, Args a) - { - var id = a.Positional is [var only] ? only : throw new Refusal("fix takes one finding id: fix F --commit ", 2); - var given = a.Need("commit"); - var resolved = Git.Run(l.Top, "rev-parse", "-q", "--verify", given + "^{commit}"); - if (resolved.ExitCode != 0) throw new Refusal($"--commit {given} is no commit of this repository"); - var commit = resolved.Stdout.Trim(); - if (!l.Findings().TryGetValue(id, out var open)) throw new Refusal($"{id} is no finding of this ledger"); - if (Files.Str(open["status"]) is var status and not "open") throw new Refusal($"{id} is {status}, not open"); - var line = new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["id"] = id, ["claim"] = open["claim"]?.DeepClone(), ["status"] = "fixed", ["commit"] = commit, - }; - if (Files.Str(open["probe"]) is { Length: > 0 } probe) line["probe"] = probe; - if (a.Get("reason") is { Length: > 0 } reason) line["reason"] = reason; - Files.AppendLine(l.P("findings.jsonl"), line); - var inHistory = Git.Run(l.Top, "merge-base", "--is-ancestor", commit, "HEAD").ExitCode == 0; - l.Ctx.Out.WriteLine($"{id} fixed at {commit[..7]}" + (inHistory ? "" : "; it counts once that commit is in HEAD's history")); - return 0; - } - - public static int Lock(Ledger l, Args a) - { - var holder = a.Need("holder"); var mode = a.Need("mode"); - if (mode is not ("replay" or "explore" or "full")) throw new Refusal("--mode is replay, explore or full", 2); - var pid = a.Get("pid") is { Length: > 0 } p ? long.Parse(p, CultureInfo.InvariantCulture) : (long?)null; - var (taken, previous) = RoundLock.Take(l, holder, mode, pid); - if (!taken) - { - var since = DateTimeOffset.FromUnixTimeMilliseconds((long)(Files.Num(previous!["since"]) * 1000)).ToLocalTime().ToString("HH:mm", CultureInfo.InvariantCulture); - l.Ctx.Error.WriteLine($"prober: locked by {Files.Str(previous["holder"])} ({Files.Str(previous["mode"])}) since {since}"); - return 1; - } - var over = previous is not null && Files.Str(previous["holder"]) != holder ? $" (took over from {Files.Str(previous["holder"])}, whose heartbeat stopped)" : ""; - l.Ctx.Out.WriteLine($"locked for {mode} by {holder}{over}"); - return 0; - } - - public static int Unlock(Ledger l, Args a) - { - var owed = RoundLock.Release(l, a.Need("holder")); - l.Ctx.Out.WriteLine(owed ? "unlocked; a replay was skipped while locked: run `prober replay` now" : "unlocked"); - return 0; - } - - public static int HeartbeatCommand(Ledger l, Args a) { RoundLock.Beat(l, a.Need("holder")); return 0; } - - public static int OweReplay(Ledger l, Args a) { RoundLock.OweReplay(l); return 0; } - - public static JsonObject? ActiveRound(Ledger l) - { - var round = Files.ReadJson(l.P("round.json")) as JsonObject; - var held = RoundLock.Holder(l); - return round is not null && held is not null && Files.Str(held["holder"]) == Files.Str(round["holder"]) ? round : null; - } - - public static int RoundStart(Ledger l, Args a) - { - var holder = a.Need("holder"); - if (RoundLock.Holder(l) is not { } held || Files.Str(held["holder"]) != holder) - throw new Refusal("take the lock first; round-start records the caps of the lock's holder"); - var minutes = double.Parse(a.Need("minutes"), CultureInfo.InvariantCulture); - var claims = a.Get("claims") is { Length: > 0 } c ? int.Parse(c, CultureInfo.InvariantCulture) : (int?)null; - Files.WriteJson(l.P("round.json"), new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["holder"] = holder, ["started"] = RoundLock.Now(), - ["deadline"] = RoundLock.Now() + minutes * 60, ["max_claims"] = claims, ["claims"] = new JsonArray(), - }); - l.Ctx.Out.WriteLine($"round capped at {minutes.ToString(CultureInfo.InvariantCulture)} min" + (claims is { } n ? $" and {n} claim(s)" : "")); - return 0; - } - - public static int RoundEnd(Ledger l, Args a) - { - if (Files.ReadJson(l.P("round.json")) is JsonObject round && Files.Str(round["holder"]) == a.Need("holder")) - { - File.Delete(l.P("round.json")); - l.Ctx.Out.WriteLine($"round ended: claims {(Files.Strings(round["claims"]).Any() ? string.Join(", ", Files.Strings(round["claims"])) : "none")}"); - } - return 0; - } - - public static int Repair(Ledger l, Args a) - { - var fixedCount = 0; - if (Directory.Exists(l.Dir)) - foreach (var path in Directory.EnumerateFiles(l.Dir, "*.jsonl", SearchOption.AllDirectories)) - { - var data = File.ReadAllText(path); - if (data.Length > 0 && !data.EndsWith('\n')) - { - Files.WriteAtomically(path, data[..(data.LastIndexOf('\n') + 1)]); - fixedCount++; - l.Ctx.Out.WriteLine($" removed a partial last line from {Path.GetRelativePath(l.Dir, path)}"); - } - } - l.Ctx.Out.WriteLine($"repair: {fixedCount} file(s) fixed"); - return 0; - } - - public static int Abandon(Ledger l, Args a) - { - Repair(l, a); - if (Files.ReadJson(l.P("round.json")) is JsonObject round) - { - File.Delete(l.P("round.json")); - l.Ctx.Out.WriteLine($"round caps cleared ({Files.Str(round["holder"])})"); - } - var held = RoundLock.Abandon(l); - l.Ctx.Out.WriteLine(held is null ? "no lock was held" : $"lock of {Files.Str(held["holder"])} ({Files.Str(held["mode"])}) released"); - return 0; - } - - /// - /// Joins the states of a replay split by family (replay --family F, one state directory per leg) into - /// this branch's state: each leg's evidence files are copied in, its run, footprint, finding and ledger lines - /// are added where this state lacks them (a line a leg carried over from a restored state is not added - /// twice), and one replay-last.json sums the legs. It refuses while a probe the registry lists was neither - /// replayed nor skipped by any leg, which is how a matrix that leaves a family out fails instead of passing - /// on what it ran, and it fails (exit 1) when any leg failed, so the job that merges fails as the legs did. - /// - public static int Merge(Ledger l, Args a) - { - var sources = a.All("from").Where(x => x.Length > 0).ToList(); - if (sources.Count == 0) throw new Refusal("--from DIR... is required: the state directories of the legs to join into this one", 2); - var branchDir = Path.GetFileName(l.Dir); - Directory.CreateDirectory(Path.Combine(l.Dir, "evidence")); - var legs = new List(); - var seen = new SortedSet(StringComparer.Ordinal); - foreach (var from in sources) - { - var root = Path.GetFullPath(from); - var dir = Path.Combine(root, "branches", branchDir); - var last = Files.ReadJson(Path.Combine(dir, "replay-last.json")) as JsonObject - ?? throw new Refusal($"{from} holds no replay of {l.Branch}: no branches/{branchDir}/replay-last.json"); - if (legs.Count > 0 && Files.Str(last["commit"]) != Files.Str(legs[0]["commit"])) - throw new Refusal($"{from} replayed {Files.Str(last["commit"])[..7]}, another leg {Files.Str(legs[0]["commit"])[..7]}; the legs of one replay share a commit"); - legs.Add(last); - foreach (var name in new[] { "runs.jsonl", "footprints.jsonl", "findings.jsonl", "ledger.jsonl" }) UnionLines(Path.Combine(dir, name), l.P(name)); - foreach (var sub in new[] { "evidence", "logs" }) - { - var source = Path.Combine(dir, sub); - if (!Directory.Exists(source)) continue; - Directory.CreateDirectory(l.P(sub)); - foreach (var file in Directory.EnumerateFiles(source)) File.Copy(file, l.P(Path.Combine(sub, Path.GetFileName(file))), overwrite: true); - } - foreach (var name in new[] { "universe.json" }) - if (File.Exists(Path.Combine(dir, name)) && !File.Exists(l.P(name))) File.Copy(Path.Combine(dir, name), l.P(name)); - var axes = Path.Combine(root, "axes-generated.json"); - if (File.Exists(axes) && !File.Exists(Path.Combine(l.Memory, "axes-generated.json"))) File.Copy(axes, Path.Combine(l.Memory, "axes-generated.json")); - foreach (var probe in Files.Strings(last["selected"]).Concat(Files.Strings(last["skipped"]))) seen.Add(probe); - } - - var all = legs.Any(x => x["all"] is JsonValue v && v.TryGetValue(out var b) && b); - var selected = new SortedSet(legs.SelectMany(x => Files.Strings(x["selected"])), StringComparer.Ordinal); - var skipped = new SortedSet(legs.SelectMany(x => Files.Strings(x["skipped"])).Where(p => !selected.Contains(p)), StringComparer.Ordinal); - var failed = new SortedSet(legs.SelectMany(x => Files.Strings(x["failed"])), StringComparer.Ordinal); - static JsonArray Names(IEnumerable names) => new([.. names.Select(x => (JsonNode)x)]); - Files.WriteJson(l.P("replay-last.json"), new JsonObject - { - ["branch"] = l.Branch, ["commit"] = Files.Str(legs[0]["commit"]), ["replayed"] = selected.Count, ["failed"] = Names(failed), - ["seconds"] = Math.Round(legs.Max(x => Files.Num(x["seconds"])), 1), ["build_seconds"] = Math.Round(legs.Max(x => Files.Num(x["build_seconds"])), 1), - ["all"] = all, ["legs"] = Names(legs.Select(x => Files.Str(x["family"], "all"))), ["footprint"] = legs.All(x => x["footprint"] is not JsonValue f || !f.TryGetValue(out var ft) || ft), - ["selected"] = Names(selected), ["skipped"] = Names(skipped), - }); - l.Ctx.Out.WriteLine($"prober merge: {legs.Count} leg(s) into {l.Dir}: {selected.Count} replayed, {failed.Count} failed, {skipped.Count} current"); - - var missing = l.Registry().Where(kv => all || kv.Value["retired"] is not JsonValue r || !r.TryGetValue(out var retired) || !retired) - .Select(kv => kv.Key).Where(p => !seen.Contains(p)).ToList(); - if (missing.Count > 0) - throw new Refusal($"no leg replayed or skipped {string.Join(", ", missing)}: every probe's family is a leg of the matrix, or the merged state is short"); - if (failed.Count > 0) { l.Ctx.Out.WriteLine($" failed: {string.Join(", ", failed)}"); return 1; } - return 0; - } - - /// Adds to every line of it does not already hold, in order. - private static void UnionLines(string source, string target) - { - if (!File.Exists(source)) return; - var have = File.Exists(target) ? SharedFile.ReadAllLines(target).Where(x => x.Trim().Length > 0).ToList() : []; - var known = new HashSet(have, StringComparer.Ordinal); - var added = SharedFile.ReadAllLines(source).Where(x => x.Trim().Length > 0 && known.Add(x)).ToList(); - if (added.Count == 0 && File.Exists(target)) return; - Files.WriteAtomically(target, string.Join('\n', have.Concat(added)) + (have.Count + added.Count > 0 ? "\n" : "")); - } -} diff --git a/tools/Prober/Context.cs b/tools/Prober/Context.cs deleted file mode 100644 index 605654a5..00000000 --- a/tools/Prober/Context.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Diagnostics; -using System.Text; - -namespace Prober; - -/// -/// Everything a command reads from its surroundings: the directory it runs in, the environment and where -/// it writes. Commands never touch the process's own current directory or environment, so tests run -/// them in-process, side by side, each in a checkout of its own. -/// -internal sealed class Context(string workingDirectory, IReadOnlyDictionary environment, TextWriter output, TextWriter error) -{ - public string WorkingDirectory { get; } = workingDirectory; - public TextWriter Out { get; } = output; - public TextWriter Error { get; } = error; - - public string? Env(string name) => environment.TryGetValue(name, out var value) && !string.IsNullOrEmpty(value) ? value : null; - - public static Context FromProcess() => - new(Directory.GetCurrentDirectory(), - System.Environment.GetEnvironmentVariables().Cast() - .ToDictionary(e => (string)e.Key, e => (string?)e.Value, StringComparer.Ordinal), - Console.Out, Console.Error); - - public IReadOnlyDictionary Environment => environment; -} - -/// A child process's result. -internal sealed record Ran(int ExitCode, string Stdout, string Stderr); - -internal static class Proc -{ - /// - /// Runs a program to completion, capturing its output. Never through a shell. `dotnet` is the one that - /// satisfies the directory's global.json, the installer's when the one on PATH cannot (Dotnet). - /// - public static Ran Run(string fileName, IEnumerable arguments, string workingDirectory, - IReadOnlyDictionary? environment = null, TimeSpan? timeout = null) - { - string? dotnetDirectory = null; - if (fileName == "dotnet") (fileName, dotnetDirectory) = Dotnet.For(workingDirectory); - var start = new ProcessStartInfo(fileName) - { - WorkingDirectory = workingDirectory, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, - StandardOutputEncoding = Encoding.UTF8, StandardErrorEncoding = Encoding.UTF8, - }; - foreach (var argument in arguments) start.ArgumentList.Add(argument); - if (environment is not null) - foreach (var (name, value) in environment) - if (value is null) start.Environment.Remove(name); else start.Environment[name] = value; - Dotnet.Apply(dotnetDirectory, start.Environment); - - using var process = Process.Start(start) ?? throw new InvalidOperationException($"could not start {fileName}"); - var stdout = process.StandardOutput.ReadToEndAsync(); - var stderr = process.StandardError.ReadToEndAsync(); - if (timeout is { } limit && !process.WaitForExit(limit)) - { - // The whole tree: a test host or a headless agent starts children of its own. Portable, no signals. - try { process.Kill(entireProcessTree: true); } catch (InvalidOperationException) { } - process.WaitForExit(); - return new Ran(-1, stdout.Result, stderr.Result + "\n(stopped at the time limit)"); - } - process.WaitForExit(); - return new Ran(process.ExitCode, stdout.Result, stderr.Result); - } -} - -internal static class Git -{ - public static Ran Run(string workingDirectory, params string[] arguments) => Proc.Run("git", arguments, workingDirectory); - - public static string Out(string workingDirectory, params string[] arguments) => Run(workingDirectory, arguments).Stdout.Trim(); - - /// The object id of a file (blob) or a directory (tree) at a revision, or null when it does not exist there. - public static string? ObjectId(string workingDirectory, string path, string revision = "HEAD") - { - var ran = Run(workingDirectory, "rev-parse", "-q", "--verify", $"{revision}:{path}"); - return ran.ExitCode == 0 ? ran.Stdout.Trim() : null; - } -} diff --git a/tools/Prober/Covering.cs b/tools/Prober/Covering.cs deleted file mode 100644 index d4cfd13c..00000000 --- a/tools/Prober/Covering.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Prober; - -/// -/// A greedy pairwise covering array: each row is the best of a few randomized greedy candidates, and the -/// rows together cover every pair asked for that at least one of the claim's obligations wants. A pair no -/// obligation wants (declared inapplicable) is never asked for, and neither it nor an excluded pair is ever put -/// in a row, not even to fill an axis: every check of such a row would be inapplicable, and an excluded pair is -/// one the claim says no row can run. An axis none of whose values can join a row without one is left out of -/// that row: shape.containing beside shape.position=root, and shape.refused-kind wherever the claim excludes each of -/// its pairs. Deterministic for a seed. -/// -internal static class Covering -{ - public static List<(SortedDictionary Row, List Pairs)> Rows(Claim claim, IReadOnlySet wanted, int max, int seed) - { - var dead = claim.DeclaredInapplicable(); - bool Blocked(Pair pair) => claim.Excluded.Contains(pair) || dead.ContainsKey(pair); - // The pairs asked for, each once however many obligations want it, so a row's gain counts it once. - var todo = new HashSet(wanted); - todo.RemoveWhere(Blocked); - var names = claim.Axes.Keys.ToList(); - var random = new Random(seed); - var rows = new List<(SortedDictionary, List)>(); - while (todo.Count > 0 && rows.Count < max) - { - SortedDictionary? best = null; var bestGain = -1; - for (var attempt = 0; attempt < 30; attempt++) - { - var order = names.OrderBy(_ => random.Next()).ToList(); - var row = new SortedDictionary(StringComparer.Ordinal); - foreach (var name in order) - { - var options = claim.Axes[name].OrderBy(_ => random.Next()).ToList(); - string? pick = null; var pickGain = -1; - foreach (var v in options) - { - var gain = 0; - foreach (var (n, w) in row) - { - var pair = new Pair($"{name}={v}", $"{n}={w}"); - if (Blocked(pair)) { gain = -1; break; } - if (todo.Contains(pair)) gain++; - } - if (gain > pickGain) { pick = v; pickGain = gain; } - } - // Every value of this axis puts a blocked pair in the row: the axis is left out of it. - if (pick is not null) row[name] = pick; - } - var g = Gained(row, todo).Count; - if (g > bestGain) { best = row; bestGain = g; } - } - if (bestGain <= 0) - { - // Seed a row from one uncovered pair so progress never stalls. - best = Seeded(claim, todo.OrderBy(p => p.A, StringComparer.Ordinal).ThenBy(p => p.B, StringComparer.Ordinal).First(), dead); - } - var newly = Gained(best!, todo); - todo.ExceptWith(newly); - rows.Add((best!, newly)); - } - return rows; - } - - static string Axis(string setting) => setting[..setting.IndexOf('=', StringComparison.Ordinal)]; - - /// - /// A row seeded from one pair: the pair's two settings, and each other axis at its first value that puts neither an excluded pair - /// nor a pair no obligation wants () in the row, or left out where none does. - /// - internal static SortedDictionary Seeded(Claim claim, Pair pair, IReadOnlyDictionary> dead) - { - bool Blocked(Pair p) => claim.Excluded.Contains(p) || dead.ContainsKey(p); - var row = new SortedDictionary(StringComparer.Ordinal); - foreach (var item in new[] { pair.A, pair.B }) row[Axis(item)] = item[(item.IndexOf('=', StringComparison.Ordinal) + 1)..]; - foreach (var name in claim.Axes.Keys.Where(n => !row.ContainsKey(n)).ToList()) - if (claim.Axes[name].FirstOrDefault(v => !row.Any(kv => Blocked(new Pair($"{name}={v}", $"{kv.Key}={kv.Value}")))) is { } value) - row[name] = value; - return row; - } - - private static List Gained(SortedDictionary row, HashSet todo) - { - var result = new List(); - var items = row.ToList(); - for (var i = 0; i < items.Count; i++) - for (var j = i + 1; j < items.Count; j++) - { - var pair = new Pair($"{items[i].Key}={items[i].Value}", $"{items[j].Key}={items[j].Value}"); - if (todo.Contains(pair)) result.Add(pair); - } - return result; - } -} diff --git a/tools/Prober/Files.cs b/tools/Prober/Files.cs deleted file mode 100644 index 51f83769..00000000 --- a/tools/Prober/Files.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System.IO.Compression; -using System.Text; -using System.Text.Encodings.Web; -using System.Text.Json; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// Reading and writing the ledger's files. Every write goes to a temp file renamed over the target, so a -/// reader sees the file before or after a change, never half of it, on every OS; reads and the rename go -/// through SharedFile, which Windows needs while another process reads the target. A partial or unreadable -/// line in a JSON-lines file is skipped, never fatal (a writer killed mid-write in an older version). -/// -internal static class Files -{ - /// The schema version this tool writes. A file or line without one is version 1. - public const int SchemaVersion = 1; - - /// - /// The version of evidence/<probe>.json this tool writes: 2 records each row's checks, one entry per check - /// with its own obligation, baseline, outcome and settings. A version-1 file reads as rows without checks, each one - /// check of the obligation claim. - /// - public const int EvidenceSchemaVersion = 2; - - /// - /// Indented, and with only what JSON itself requires escaped: the tracked corpus is read in a diff, where - /// the default encoder's six-character escapes for +, a backtick and < made every publish a - /// rewrite (decision 102). No reader here or in the harness parses these files as - /// anything but JSON, and an identity hashes , not the file's text. - /// - private static readonly JsonSerializerOptions Indented = new() { WriteIndented = true, NewLine = "\n", Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; - - public static JsonNode? ReadJson(string path) - { - if (!File.Exists(path)) return null; - try { return JsonNode.Parse(SharedFile.ReadAllText(path)); } - catch (JsonException) { return null; } // a file another process is creating this instant: not there yet - catch (IOException) { return null; } - catch (UnauthorizedAccessException) { return null; } // Windows: a file being replaced this instant - } - - public static void WriteJson(string path, JsonNode value) => WriteAtomically(path, Format(value)); - - /// The text writes: a tracked file in this form is unchanged by a publish that changes nothing in it. - public static string Format(JsonNode value) => value.ToJsonString(Indented) + "\n"; - - public static List ReadLines(string path) - { - var result = new List(); - if (!File.Exists(path)) return result; - foreach (var line in SharedFile.ReadAllLines(path)) - { - if (line.Trim().Length == 0) continue; - try { if (JsonNode.Parse(line) is JsonObject o) result.Add(o); } - catch (JsonException) { } - } - return result; - } - - /// Appends one line by writing the whole file anew and renaming it over the old one. - public static void AppendLine(string path, JsonObject value) - { - var old = File.Exists(path) ? SharedFile.ReadAllText(path) : ""; - if (old.Length > 0 && !old.EndsWith('\n')) old = old[..(old.LastIndexOf('\n') + 1)]; - WriteAtomically(path, old + value.ToJsonString() + "\n"); - } - - public static void WriteAtomically(string path, string text) - { - Directory.CreateDirectory(Path.GetDirectoryName(path)!); - var tmp = $"{path}.{Environment.ProcessId}.{Guid.NewGuid():N}.tmp"; - File.WriteAllText(tmp, text, new UTF8Encoding(false)); - SharedFile.Replace(tmp, path); - } - - /// A rows file, plain (staging) or gzipped (the corpus). - public static JsonArray ReadRows(string path) - { - if (File.Exists(path)) return ReadJson(path)?["rows"] as JsonArray ?? []; - if (File.Exists(path + ".gz")) - { - using var gz = new GZipStream(SharedFile.OpenRead(path + ".gz"), CompressionMode.Decompress); - using var reader = new StreamReader(gz, Encoding.UTF8); - return JsonNode.Parse(reader.ReadToEnd())?["rows"] as JsonArray ?? []; - } - return []; - } - - public static byte[] Gunzip(string path) - { - using var gz = new GZipStream(SharedFile.OpenRead(path), CompressionMode.Decompress); - using var memory = new MemoryStream(); - gz.CopyTo(memory); - return memory.ToArray(); - } - - /// Writes rows gzipped and reproducibly: one row per line, keys sorted, no timestamp in the header. - public static void WriteRowsGzipped(string path, string claim, IEnumerable rows) - { - var body = new StringBuilder(); - body.Append("{\"claim\": ").Append(JsonSerializer.Serialize(claim)).Append(", \"rows\": [\n"); - body.Append(string.Join(",\n", rows.Select(r => "{\"row\":" + Canonical(r) + "}"))); - body.Append("\n]}\n"); - var tmp = $"{path}.{Environment.ProcessId}.tmp"; - Directory.CreateDirectory(Path.GetDirectoryName(path)!); - using (var file = File.Create(tmp)) - using (var gz = new GZipStream(file, CompressionLevel.SmallestSize)) - gz.Write(Encoding.UTF8.GetBytes(body.ToString())); - SharedFile.Replace(tmp, path); - } - - /// A JSON object with its keys in ordinal order, recursively: the form hashed for an identity. - public static string Canonical(JsonNode? node) => node switch - { - JsonObject o => "{" + string.Join(",", o.OrderBy(kv => kv.Key, StringComparer.Ordinal) - .Select(kv => JsonSerializer.Serialize(kv.Key) + ":" + Canonical(kv.Value))) + "}", - JsonArray a => "[" + string.Join(",", a.Select(Canonical)) + "]", - null => "null", - _ => node.ToJsonString(), - }; - - public static string Str(JsonNode? node, string fallback = "") => node is JsonValue v && v.TryGetValue(out var s) ? s : fallback; - - /// A number, whether parsed from text or built in memory from any numeric type. - public static double Num(JsonNode? node, double fallback = 0) - { - if (node is not JsonValue v) return fallback; - if (v.TryGetValue(out var d)) return d; - if (v.TryGetValue(out var l)) return l; - if (v.TryGetValue(out var i)) return i; - if (v.TryGetValue(out var m)) return (double)m; - return double.TryParse(v.ToJsonString(), System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var p) ? p : fallback; - } - - public static IEnumerable Strings(JsonNode? node) => node is JsonArray a ? a.Select(x => Str(x)) : []; - - public static Dictionary StringMap(JsonNode? node) => - node is JsonObject o ? o.Where(kv => kv.Value is JsonValue).ToDictionary(kv => kv.Key, kv => Str(kv.Value, kv.Value!.ToJsonString()), StringComparer.Ordinal) - : new(StringComparer.Ordinal); -} diff --git a/tools/Prober/Ledger.cs b/tools/Prober/Ledger.cs deleted file mode 100644 index 50673244..00000000 --- a/tools/Prober/Ledger.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// One branch's ledger. Tracked, in the repository: the corpus under tools/probe/corpus (claims, registry, -/// harness and probe sources, rows, waivers, dismissed findings) and the axes file. Local, under the state -/// directory: the universe, evidence, footprints, runs, findings, the round's caps and the lock. A pair is -/// covered only by evidence a replay recorded under an identity that still holds. -/// -internal sealed class Ledger -{ - public Context Ctx { get; } - public string Root { get; } // the main checkout, also from a linked worktree - public string Top { get; } // this checkout - public bool Linked { get; } // a linked worktree (git worktree add), not the main checkout - public string Branch { get; } - public string Memory { get; } // PROBE_STATE_DIR, else the main checkout's prober memory - public string Dir { get; } // the branch's directory under Memory - public string CorpusDir => Path.Combine(Top, "tools", "probe", "corpus"); - public string AxesFile => Path.Combine(Top, ".claude", "probe-axes.md"); - public string StagingDir => Path.Combine(Dir, "staging"); - - public Ledger(Context ctx, string? branch) - { - Ctx = ctx; - var dirs = Git.Run(ctx.WorkingDirectory, "rev-parse", "--path-format=absolute", "--git-common-dir", "--git-dir"); - if (dirs.ExitCode != 0) throw new Refusal("not inside a git repository"); - var lines = dirs.Stdout.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Select(d => d.TrimEnd('/', '\\')).ToArray(); - if (lines is not [var common, var own]) throw new Refusal("git rev-parse named no git directory"); - Root = Path.GetDirectoryName(common)!; - Linked = own != common; - Top = Git.Out(ctx.WorkingDirectory, "rev-parse", "--show-toplevel"); - Branch = branch ?? Git.Out(ctx.WorkingDirectory, "rev-parse", "--abbrev-ref", "HEAD"); - Memory = ctx.Env("PROBE_STATE_DIR") ?? Path.Combine(Root, ".claude", "agent-memory-local", "prober"); - Dir = Path.Combine(Memory, "branches", Branch.Replace('/', '-')); - } - - public string Head => Git.Out(Top, "rev-parse", "HEAD"); - public string P(string name) => Path.Combine(Dir, name); - - // ---- the corpus, tracked, overlaid by the branch's unpublished staging ------------------------------ - - public string CorpusPath(string relative) - { - var staged = Path.Combine(StagingDir, relative); - return File.Exists(staged) ? staged : Path.Combine(CorpusDir, relative); - } - - public SortedDictionary Registry() - { - var merged = new SortedDictionary(StringComparer.Ordinal); - foreach (var path in new[] { Path.Combine(CorpusDir, "registry.json"), Path.Combine(StagingDir, "registry.json") }) - if (Files.ReadJson(path)?["probes"] is JsonObject probes) - foreach (var (name, entry) in probes) - if (entry is JsonObject e) merged[name] = (JsonObject)e.DeepClone(); - return merged; - } - - public List Claims() - { - var merged = new SortedDictionary(StringComparer.Ordinal); - foreach (var path in new[] { Path.Combine(CorpusDir, "claims.json"), Path.Combine(StagingDir, "claims.json") }) - foreach (var c in ReadClaims(path, Path.GetRelativePath(Top, path).Replace('\\', '/'))) - merged[Files.Str(c["id"])] = (JsonObject)c.DeepClone(); - return [.. merged.Values]; - } - - /// - /// A claims file, refused unless it matches Schemas/claims.schema.json, each problem named by its claim and - /// field (decision 102). No file is no claims. - /// - public static List ReadClaims(string path, string shown) - { - if (!File.Exists(path)) return []; - if (Files.ReadJson(path) is not JsonArray claims) throw new Refusal($"{shown} is not a JSON list of claims"); - var schema = SchemaCheck.Load("claims.schema.json")["items"] as JsonObject ?? throw new InvalidOperationException("claims.schema.json has no items"); - var problems = new List(); - for (var i = 0; i < claims.Count; i++) - { - var id = claims[i] is JsonObject o && Files.Str(o["id"]) is { Length: > 0 } s ? s : $"#{i}"; - problems.AddRange(SchemaCheck.Problems(claims[i], schema).Select(p => $"claim {id}: {p}")); - } - if (problems.Count > 0) - throw new Refusal($"{shown} does not match tools/Prober/Schemas/claims.schema.json:\n " + string.Join("\n ", problems)); - return [.. claims.OfType()]; - } - - /// - /// A probe's own rows (rows/P.json, staged, else the corpus's rows/P.json.gz). Each probe has a file of its own, its claim - /// inside, so the rows of one probe of a claim never move another's identity. - /// - public JsonArray RowsOf(string probe) - { - var relative = Path.Combine("rows", probe + ".json"); - var staged = Path.Combine(StagingDir, relative); - return File.Exists(staged) ? Files.ReadRows(staged) : Files.ReadRows(Path.Combine(CorpusDir, relative)); - } - - /// - /// The paths a probe's registry entry watches: what its result depends on that the footprint cannot see, such as a - /// variant catalogue under test/ compiled into the probes or a build input a child process reads. They stale its - /// footprint like the paths it ran. - /// - public IReadOnlyList Watched(string probe) => [.. Files.Strings(Registry().GetValueOrDefault(probe)?["watched"])]; - - public JsonObject AxesBlock() => Axes.Block(AxesFile); - - // ---- identity -------------------------------------------------------------------------------------- - - /// - /// What a probe's result depends on besides the product footprint: its registry entry (not its seed), every source - /// compiled with it (the harness and all probes), its own rows (not a sibling's), the axes file, the build environment - /// (SDK, central package versions, build props, global.json), this tool's version and the schema version, and - /// where its claim declares where an obligation does not apply, those declarations, which the harness reads. - /// A result counts only while this is unchanged. - /// - public string Identity(string probe) - { - using var sha = IncrementalHash.CreateHash(HashAlgorithmName.SHA256); - void Add(string s) => sha.AppendData(Encoding.UTF8.GetBytes(s + "\0")); - var entry = Registry().GetValueOrDefault(probe) ?? []; - // The seeds prove the probe; a result of the probe depends on none of them (decisions 100 and 104). - var registered = (JsonObject)entry.DeepClone(); - registered.Remove("seed"); - registered.Remove("seeds"); - Add(Files.Canonical(registered)); - var sources = new SortedDictionary(StringComparer.Ordinal); - foreach (var baseDir in new[] { CorpusDir, StagingDir }) - foreach (var sub in new[] { "harness", "probes" }) - { - var folder = Path.Combine(baseDir, sub); - if (Directory.Exists(folder)) - foreach (var file in Directory.EnumerateFiles(folder, "*.cs")) sources[Path.GetFileName(file)] = file; - } - foreach (var (name, file) in sources) { Add(name); sha.AppendData(File.ReadAllBytes(file)); } - Add(Files.Canonical(RowsOf(probe))); - // The declarations Row.Check applies before a check's body runs: a change to one changes what the probe's rows - // check. Added only where the claim declares something, so a claim without declarations leaves the identity as it was. - if (Declarations(Files.Str(entry["claim"])) is { } declared) Add("inapplicable:" + Files.Canonical(declared)); - try { Add(Files.Canonical(AxesBlock())); } catch (Refusal) { Add("no axes file"); } - foreach (var path in new[] { "Directory.Packages.props", "Directory.Build.props", "global.json" }) - Add(path + (Git.ObjectId(Top, path) ?? "-")); - Add(Files.Canonical(Toolchain())); - Add("tool:" + SourceFingerprint.ToolVersion[..16]); - Add("schema:" + Files.SchemaVersion); - return Convert.ToHexStringLower(sha.GetHashAndReset())[..16]; - } - - private Dictionary? declarations; - - /// A claim's declarations of where its obligations do not apply, as claims.json holds them, by obligation; null where it declares none. - private JsonArray? Declarations(string claim) - { - declarations ??= Claims().ToDictionary(c => Files.Str(c["id"]), c => new JsonArray([.. (c["obligations"] as JsonArray ?? []).OfType() - .Where(o => o["inapplicable"] is JsonArray { Count: > 0 }) - .Select(o => (JsonNode)new JsonObject { ["obligation"] = Files.Str(o["id"]), ["inapplicable"] = o["inapplicable"]!.DeepClone() })]), StringComparer.Ordinal); - return declarations.TryGetValue(claim, out var declared) && declared.Count > 0 ? declared : null; - } - - private JsonObject? toolchain; - - /// - /// What no file in the repository records: the SDK a global.json roll-forward picked, say. A command that cannot - /// say it (it does not start, exits non-zero or prints nothing) is a refusal: its error text in every identity - /// would read as a toolchain change, and every result as stale, without a word why. - /// - public JsonObject Toolchain() - { - if (toolchain is not null) return toolchain; - JsonObject? commands; - try { commands = AxesBlock()["replay"]?["toolchain"] as JsonObject; } catch (Refusal) { commands = null; } - var result = new JsonObject(); - foreach (var (name, argv) in (commands ?? []).OrderBy(kv => kv.Key, StringComparer.Ordinal)) - { - var parts = Files.Strings(argv).ToArray(); - var shown = $"the toolchain command {name} (`{string.Join(' ', parts)}`)"; - if (parts.Length == 0) throw new Refusal($"{shown} is empty"); - Ran ran; - try { ran = Proc.Run(parts[0], parts[1..], Top); } - catch (System.ComponentModel.Win32Exception e) { throw new Refusal($"{shown} did not start: {e.Message}"); } - static string FirstLine(string s) => s.Trim().Split('\n')[0].Trim(); - // A failing `dotnet --version` lists the installed SDKs on stdout ("10.0.401 [path]", a version to look at) - // and says why on stderr. - if (ran.ExitCode != 0) - { - var why = FirstLine(ran.Stderr) is { Length: > 0 } err ? err : FirstLine(ran.Stdout); - throw new Refusal($"{shown} exited {ran.ExitCode}: {(why.Length > 0 ? why : "no output")}. A result is bound to what it prints, " + - "so none could be current; put the toolchain global.json asks for first on PATH, or install it where " + - $"the SDK installer puts it ({Dotnet.InstallerDirectory}), which `dotnet` falls back to"); - } - var first = FirstLine(ran.Stdout.Trim().Length > 0 ? ran.Stdout : ran.Stderr); - if (first.Length == 0) throw new Refusal($"{shown} printed nothing, so a result could be bound to no toolchain"); - result[name] = first; - } - return toolchain = result; - } - - // ---- footprints, evidence, coverage ------------------------------------------------------------------ - - public Dictionary Footprints() => - Files.ReadLines(P("footprints.jsonl")).GroupBy(l => Files.Str(l["probe"]), StringComparer.Ordinal) - .ToDictionary(g => g.Key, g => g.Last(), StringComparer.Ordinal); - - private readonly Dictionary currentCache = new(StringComparer.Ordinal); - - /// - /// A probe's footprint is current when every path it ran, every compile-time path, every path its registry entry - /// watches and the toolchain are unchanged at HEAD. A watched path the footprint did not record (one added to the - /// entry since) is not current. A footprint that ran nothing under src/ is current only by watched paths it recorded. - /// - public bool FootprintCurrent(string probe, Dictionary footprints) - { - if (currentCache.TryGetValue(probe, out var cached)) return cached; - var ok = false; - if (footprints.TryGetValue(probe, out var r) && r["footprint"] is JsonObject fp && (fp.Count > 0 || r["watched"] is JsonObject { Count: > 0 })) - { - var watched = r["watched"] as JsonObject ?? []; - ok = Watched(probe).All(watched.ContainsKey) - && fp.Concat(r["compileTime"] as JsonObject ?? []).Concat(watched).All(kv => Git.ObjectId(Top, kv.Key) == Files.Str(kv.Value, null!)); - if (ok) - { - var now = Toolchain(); - ok = (r["toolchain"] as JsonObject ?? []).All(kv => Files.Str(now[kv.Key]) == Files.Str(kv.Value)); - } - } - return currentCache[probe] = ok; - } - - public bool FootprintChangedSince(string probe, string since, Dictionary footprints) - { - if (!footprints.TryGetValue(probe, out var r)) return true; - var paths = (r["footprint"] as JsonObject ?? []).Select(kv => kv.Key).Concat((r["compileTime"] as JsonObject ?? []).Select(kv => kv.Key)) - .Concat((r["watched"] as JsonObject ?? []).Select(kv => kv.Key)).Concat(Watched(probe)) - .Distinct(StringComparer.Ordinal).ToArray(); - if (paths.Length == 0) return true; - return Git.Run(Top, ["diff", "--quiet", since, "HEAD", "--", .. paths]).ExitCode != 0; - } - - public string EvidencePath(string probe) => P(Path.Combine("evidence", probe + ".json")); - - /// A check that earned credit: the obligation it named and the settings it ran under. - public sealed record Credit(string Obligation, Dictionary Applied); - - /// - /// The checks of one probe's evidence that earn credit, each with its obligation and settings: only while the - /// probe's identity and product footprint are current, and only checks that ended as a pass in rows that were - /// expected and executed. A check's settings are the row's (read outside any check, so every check ran under them) - /// with its own laid over them; a row without checks is one check of the obligation claim, credited when - /// the row passed. - /// - public List CreditedChecks(string probe, JsonObject? evidence, Dictionary? footprints) - { - var result = new List(); - if (evidence is null || Files.Str(evidence["identity"]) != Identity(probe)) return result; - if (footprints is not null && !FootprintCurrent(probe, footprints)) return result; - var expected = new HashSet(); var executed = new HashSet(); - foreach (var v in (evidence["variants"] as JsonArray ?? []).OfType()) - { - foreach (var i in v["expected"] as JsonArray ?? []) expected.Add((int)Files.Num(i)); - foreach (var i in v["executed"] as JsonArray ?? []) executed.Add((int)Files.Num(i)); - } - foreach (var (key, row) in evidence["rows"] as JsonObject ?? []) - { - var i = int.Parse(key, System.Globalization.CultureInfo.InvariantCulture); - if (row is not JsonObject r || !expected.Contains(i) || !executed.Contains(i)) continue; - foreach (var check in ChecksOf(r)) - if (check.Category == "pass" && check.Applied.Count > 0) result.Add(new Credit(check.Obligation, check.Applied)); - } - return result; - } - - /// One check of an evidence row as the ledger reads it. - public sealed record CheckRead(string Obligation, string Category, Dictionary Applied, string? Baseline); - - /// - /// The checks of one evidence row: each with its obligation, category and settings (the row's, the check's laid - /// over them). A row without checks, every row of a version-1 file among them, is one check of the implicit - /// obligation claim with the row's category and settings and no baseline. - /// - public static List ChecksOf(JsonObject row) - { - var applied = row["applied"] is JsonObject a ? Files.StringMap(a) : new Dictionary(StringComparer.Ordinal); - if (row["checks"] is not JsonArray { Count: > 0 } checks) - return [new CheckRead(Claim.ImplicitObligation, Files.Str(row["category"], "violation"), applied, null)]; - var result = new List(); - foreach (var c in checks.OfType()) - { - var own = new Dictionary(applied, StringComparer.Ordinal); - if (c["applied"] is JsonObject ca) foreach (var (axis, value) in Files.StringMap(ca)) own[axis] = value; - result.Add(new CheckRead(Files.Str(c["obligation"]), Files.Str(c["category"], "violation"), own, c["baseline"] is JsonValue b ? Files.Str(b) : null)); - } - return result; - } - - /// - /// (claim, obligation, pair) for every pair a current check earned, leaving out the probe - /// names. Each check's settings alone make its pairs: a pair is never put together from two checks' settings. - /// - public HashSet<(string Claim, string Obligation, Pair Pair)> Credits(Universe universe, string? claimId = null, string? except = null) - { - var footprints = Footprints(); - var done = new HashSet<(string, string, Pair)>(); - foreach (var (name, entry) in Registry()) - { - var cid = Files.Str(entry["claim"]); - if (name == except || (claimId is not null && cid != claimId) || !universe.ById.TryGetValue(cid, out var claim)) continue; - var evidence = Files.ReadJson(EvidencePath(name)) as JsonObject; - foreach (var credit in CreditedChecks(name, evidence, footprints)) - foreach (var pair in claim.PairsOfRow(credit.Applied)) done.Add((cid, credit.Obligation, pair)); - } - return done; - } - - /// - /// (claim, pair) for every pair current evidence earned, leaving out the probe names. A round's - /// own ledger lines earn nothing. - /// - public HashSet<(string Claim, Pair Pair)> Covered(Universe universe, string? claimId = null, string? except = null) => - [.. Credits(universe, claimId, except).Select(x => (x.Claim, x.Pair))]; - - /// The last event per finding; a fixed line counts once its commit is in HEAD's history, a dismissal in the corpus everywhere. - public Dictionary Findings() - { - var last = new Dictionary(StringComparer.Ordinal); - foreach (var f in Files.ReadLines(P("findings.jsonl"))) - { - if (Files.Str(f["status"]) == "fixed" && Files.Str(f["commit"]) is { Length: > 0 } c - && Git.Run(Top, "merge-base", "--is-ancestor", c, "HEAD").ExitCode != 0) continue; - last[Files.Str(f["id"])] = f; - } - foreach (var f in Files.ReadLines(CorpusPath("dismissed.jsonl"))) - { - var d = (JsonObject)f.DeepClone(); d["status"] = "dismissed"; - last[Files.Str(f["id"])] = d; - } - return last; - } - - /// The findings one probe's evidence steps around, with the number of rows that skip for each. - public static SortedDictionary FindingSkips(JsonObject? evidence) - { - var skips = new SortedDictionary(StringComparer.Ordinal); - foreach (var (_, row) in evidence?["rows"] as JsonObject ?? []) - foreach (var f in Files.Strings(row?["findings"])) skips[f] = skips.GetValueOrDefault(f) + 1; - return skips; - } - - /// - /// The skips of one probe's evidence that no longer stand: a finding this ledger has fixed (in HEAD's history) - /// or the corpus has dismissed. Such a skip would hide the defect coming back, so the replay fails the probe. - /// A finding this ledger has never seen (a fresh state, as in CI) is left to the gate, which refuses any skip. - /// - public List StaleSkips(JsonObject? evidence) - { - var findings = Findings(); - var stale = new List(); - foreach (var (id, rows) in FindingSkips(evidence)) - { - if (!findings.TryGetValue(id, out var f)) continue; - var status = Files.Str(f["status"]); - if (status == "fixed" && Files.Str(f["commit"]) is { Length: >= 7 } commit) status += " at " + commit[..7]; - if (status != "open") stale.Add($"{rows} row(s) skip for {id}, which is {status}: remove the skip"); - } - return stale; - } - - /// How the rows of one probe's evidence ended, by category. - public static SortedDictionary Outcomes(JsonObject? evidence) - { - var outcomes = new SortedDictionary(StringComparer.Ordinal); - foreach (var (_, row) in evidence?["rows"] as JsonObject ?? []) - { - var category = Files.Str(row?["category"], "violation"); - outcomes[category] = outcomes.GetValueOrDefault(category) + 1; - } - return outcomes; - } - - /// How the checks of one probe's evidence ended, by category; a row without checks counts as its one check claim. - public static SortedDictionary CheckOutcomes(JsonObject? evidence) - { - var outcomes = new SortedDictionary(StringComparer.Ordinal); - foreach (var (_, row) in evidence?["rows"] as JsonObject ?? []) - if (row is JsonObject r) - foreach (var check in ChecksOf(r)) outcomes[check.Category] = outcomes.GetValueOrDefault(check.Category) + 1; - return outcomes; - } - - /// The obligations a check of one probe's evidence passed for at its last replay, current or not. - public static HashSet PassedObligations(JsonObject? evidence) - { - var passed = new HashSet(StringComparer.Ordinal); - foreach (var (_, row) in evidence?["rows"] as JsonObject ?? []) - if (row is JsonObject r) - foreach (var check in ChecksOf(r).Where(c => c.Category == "pass")) passed.Add(check.Obligation); - return passed; - } - - public List OpenFindings() => [.. Findings().Where(kv => Files.Str(kv.Value["status"]) == "open").Select(kv => kv.Key).Order(StringComparer.Ordinal)]; - - public sealed record ProbeState(string Probe, string Claim, string Filter, JsonArray Variants, bool Stale, bool Retired, int Passes, bool Replay); - - /// A registry entry's process variants: its own, or one that sets nothing. - public static JsonArray VariantsOf(JsonObject entry) => entry["variants"] is JsonArray va && va.Count > 0 ? (JsonArray)va.DeepClone() : [new JsonObject()]; - - public List ProbeStates(bool includeRetired) - { - var footprints = Footprints(); - var runs = Files.ReadLines(P("runs.jsonl")); - var states = new List(); - foreach (var (probe, r) in Registry()) - { - var passes = runs.Count(x => Files.Str(x["probe"]) == probe && Files.Str(x["result"]) == "pass"); - var retired = r["retired"] is JsonValue rv && rv.TryGetValue(out var b) && b; - var evidence = Files.ReadJson(EvidencePath(probe)); - var stale = !FootprintCurrent(probe, footprints) || evidence is null || Files.Str(evidence["identity"]) != Identity(probe); - var variants = VariantsOf(r); - states.Add(new ProbeState(probe, Files.Str(r["claim"]), Files.Str(r["filter"]), variants, stale, retired, passes, stale && (includeRetired || !retired))); - } - return states; - } -} - -/// A refusal the user acts on: printed as "prober: ...", exit 1. Never a stack trace. -internal sealed class Refusal(string message, int exitCode = 1) : Exception(message) -{ - public int ExitCode { get; } = exitCode; -} diff --git a/tools/Prober/NewProbe.cs b/tools/Prober/NewProbe.cs deleted file mode 100644 index 97047dcd..00000000 --- a/tools/Prober/NewProbe.cs +++ /dev/null @@ -1,166 +0,0 @@ -using System.Text; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; - -namespace Prober; - -/// -/// new: the mechanical half of writing a probe, done the same way every time, into the branch's staging. -/// It writes the probe's skeleton in the harness's form (probes/P.cs), headed by the claim's source and -/// every obligation's id and sentence, with one check per obligation that throws until it is written; stages the -/// probe's own rows (a covering array over its claim's pairs the claim's other probes have not covered, as -/// rows --probe P writes); -/// and registers the probe with an empty seeds, so seeds and Seeds.Problems name each -/// obligation's seed as owed. The skeleton builds, so the other probes keep building beside it, and every row of -/// it ends as a harness error, which fails the row, earns nothing and is never a seed's catch (decision 103). -/// It refuses, writing nothing, a claim that is not in the claims, a name a probe has already, and a claim -/// whose first surface is in no family of the replay configuration (or not in the one --family names). -/// -internal static partial class NewProbe -{ - [GeneratedRegex("^[A-Za-z_][A-Za-z0-9_]*Probe$")] - private static partial Regex ProbeName(); - - [GeneratedRegex("^([A-Za-z]+[0-9]+)(?:-(.*))?$")] - private static partial Regex ClaimPrefix(); - - [GeneratedRegex("[^A-Za-z0-9]+")] - private static partial Regex NotAlphanumeric(); - - public static int Run(Ledger l, Args a) - { - var claimId = a.Need("claim"); - var claim = l.Claims().FirstOrDefault(c => Files.Str(c["id"]) == claimId) - ?? throw new Refusal($"no claim {claimId} in claims.json (tracked or staged)"); - var probe = a.Get("probe") is { Length: > 0 } named ? named : DefaultName(claimId); - if (!ProbeName().IsMatch(probe)) throw new Refusal($"{probe} is not a probe's name: a C# class name ending in Probe", 2); - if (Taken(l, probe) is { } where) throw new Refusal($"a probe {probe} exists already ({where}); name another with --probe"); - var family = Family(l, claim, a.Get("family")); - var obligations = Obligations(claim); - - var source = Path.Combine(l.StagingDir, "probes", probe + ".cs"); - Files.WriteAtomically(source, Skeleton(claim, probe, family, obligations)); - // The probe's own rows, its claim's other probes' untouched: a covering array over the pairs they have not covered. - var (rows, _) = Commands.StageRows(l, probe, claimId, full: false); - var registry = Path.Combine(l.StagingDir, "registry.json"); - var staged = Files.ReadJson(registry) as JsonObject ?? new JsonObject { ["probes"] = new JsonObject() }; - var probes = staged["probes"] as JsonObject ?? []; - probes[probe] = new JsonObject { ["claim"] = claimId, ["filter"] = "*" + probe, ["seeds"] = new JsonArray() }; - staged["probes"] = probes.DeepClone(); - Files.WriteJson(registry, staged); - - var o = l.Ctx.Out; - o.WriteLine($"prober new: {probe} for claim {claimId}{(family is null ? "" : $" (family {family})")}, staged in {l.StagingDir}"); - o.WriteLine($" probes/{probe}.cs: the skeleton; it builds, and every row ends as a harness error until each obligation's check is written"); - o.WriteLine($" rows/{probe}.json: {rows} rows over the claim's pairs its other probes have not covered" + - (rows == 0 ? "; with no row the probe has no test to run" : "")); - o.WriteLine($" registry.json: {probe}, claim {claimId}, filter *{probe}, no seed yet"); - o.WriteLine("still owed, per obligation:"); - foreach (var (id, sentence, method) in obligations) - o.WriteLine($" {id}: the check {method} ({(sentence is null ? "the claim as a whole" : $"\"{sentence}\"")}), and a seed that breaks it " + - (id == Claim.ImplicitObligation && sentence is null - ? $"(`prober register --probe {probe} --claim {claimId} --filter \"*{probe}\" --seed seeds/{claimId}.patch --defect \"...\"`)" - : $"(`prober register --probe {probe} --claim {claimId} --filter \"*{probe}\" --obligation {id} --seed seeds/{claimId}-{id}.patch --defect \"...\"`)")); - o.WriteLine($"then: `prober try --probe {probe}` until each row ends as it should, `prober seeds --probe {probe}`, `prober register` (it lints the staged sources), `prober publish`"); - return 0; - } - - /// The claim id's letter-digit prefix, then its words run together, then Probe: C20-testing-shouldhold is C20TestingShouldholdProbe. - internal static string DefaultName(string claimId) - { - var m = ClaimPrefix().Match(claimId); - var (prefix, rest) = m.Success ? (m.Groups[1].Value, m.Groups[2].Value) : ("", claimId); - return Pascal(prefix) + Pascal(rest) + "Probe"; - } - - private static string Pascal(string text) => - string.Concat(NotAlphanumeric().Split(text).Where(w => w.Length > 0).Select(w => char.ToUpperInvariant(w[0]) + w[1..])); - - /// Where a probe of that name is already: the registry, a source file of that name, or a class of that name in any corpus source. - private static string? Taken(Ledger l, string probe) - { - if (l.Registry().ContainsKey(probe)) return "in the registry"; - var declares = new Regex($@"\b(class|record|struct)\s+{probe}\b"); - foreach (var dir in new[] { l.CorpusDir, l.StagingDir }) - foreach (var sub in new[] { "harness", "probes" }) - { - var folder = Path.Combine(dir, sub); - if (!Directory.Exists(folder)) continue; - foreach (var file in Directory.EnumerateFiles(folder, "*.cs")) - if (Path.GetFileNameWithoutExtension(file) == probe || declares.IsMatch(File.ReadAllText(file))) return file; - } - return null; - } - - /// - /// The family the replay runs the probe in, its claim's first surface's (decision 101), checked against - /// --family. Null where the replay configuration names no families and none was asked for. - /// - private static string? Family(Ledger l, JsonObject claim, string? asked) - { - var families = (l.AxesBlock()["replay"] as JsonObject)?["families"] as JsonObject; - if (families is null) - return asked is null ? null : throw new Refusal($"--family {asked}: the replay configuration names no families", 2); - var surface = Files.Strings(claim["surfaces"]).FirstOrDefault() ?? ""; - var family = families.FirstOrDefault(kv => Files.Strings(kv.Value).Contains(surface)).Key - ?? throw new Refusal($"the first surface of claim {Files.Str(claim["id"])} ({surface}) is in no family of the replay configuration, so a replay by family would never run its probe"); - if (asked is not null && asked != family) - throw new Refusal($"claim {Files.Str(claim["id"])} is of family {family} (its first surface, {surface}), not {asked}", 2); - return family; - } - - /// Each obligation of the claim with its sentence and the check method the skeleton gives it; a claim without obligations has one, the claim itself, with no sentence. - internal static List<(string Id, string? Sentence, string Method)> Obligations(JsonObject claim) - { - var listed = (claim["obligations"] as JsonArray ?? []).OfType() - .Select(o => (Id: Files.Str(o["id"]), Sentence: (string?)OneLine(Files.Str(o["sentence"])))).ToList(); - if (listed.Count == 0) listed = [(Claim.ImplicitObligation, null)]; - var methods = new HashSet(StringComparer.Ordinal); - var result = new List<(string, string?, string)>(); - foreach (var (id, sentence) in listed) - { - var method = "Check" + Pascal(id); - for (var n = 2; !methods.Add(method); n++) method = "Check" + Pascal(id) + n; - result.Add((id, sentence, method)); - } - return result; - } - - /// The probe's source: the form of the corpus's probes (Rows.Data, [Theory, MemberData(nameof(Data))], Rec.Run), one throwing check per obligation. - internal static string Skeleton(JsonObject claim, string probe, string? family, List<(string Id, string? Sentence, string Method)> obligations) - { - var id = Files.Str(claim["id"]); - var literal = JsonSerializer.Serialize(probe); - var b = new StringBuilder(); - void Line(string text = "") => b.Append(text).Append('\n'); - Line($"// Claim {id} ({Files.Str(claim["source"])}), surfaces {string.Join(", ", Files.Strings(claim["surfaces"]))}{(family is null ? "" : $", family {family}")}."); - Line("// Obligations (claims.json), each with a check below and a seed of its own in the registry entry (decision 104):"); - foreach (var (oid, sentence, _) in obligations) - Line($"// {oid}: {(sentence is null ? "the claim as a whole (claims.json lists no obligations for it)" : $"\"{sentence}\"")}"); - Line("// Oracle: TODO: what each row is compared against, and the result it expects."); - Line("// Written by `prober new`: it builds, and every row ends as a harness error until each obligation's check is written."); - Line("using Probes.Shapes;"); - Line("namespace Probes;"); - Line($"public sealed class {probe}"); - Line("{"); - Line($" public static TheoryData Data() => Rows.Data({literal});"); - Line(" [Theory, MemberData(nameof(Data))]"); - Line(" public Task Row(string probe, int idx) => Rec.Run(probe, idx, Check);"); - Line(); - Line(" static async Task Check(Row r) =>"); - for (var i = 0; i < obligations.Count; i++) - Line($" {(i == 0 ? "" : "?? ")}await {obligations[i].Method}(r){(i == obligations.Count - 1 ? ";" : "")}"); - foreach (var (oid, sentence, method) in obligations) - { - Line(); - Line($" // TODO {oid}: {(sentence is null ? "the claim as a whole" : $"\"{sentence}\"")}"); - Line(" // Return the failure text, or null where the row holds it; say how it was compared with r.Note(NoteKeys.Compared, detail)."); - Line($" static Task {method}(Row r) => throw new NotImplementedException({JsonSerializer.Serialize($"{id}/{oid}: its check is not written yet")});"); - } - Line("}"); - return b.ToString(); - } - - private static string OneLine(string text) => string.Join(" ", text.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)); -} diff --git a/tools/Prober/ProbeAdapter.cs b/tools/Prober/ProbeAdapter.cs deleted file mode 100644 index fc993e87..00000000 --- a/tools/Prober/ProbeAdapter.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; - -namespace Prober; - -/// -/// What the core needs from a repository's toolchain, and nothing more: build the probes, run one probe in -/// one process with an environment (writing its rows' outcomes and a coverage report), and derive the -/// generated axes. The core holds nothing of .NET's; a repository on another stack plugs in its own. -/// -internal interface IProbeAdapter -{ - /// Builds what the probes need in the worktree. The first line of the output is shown. - Ran Build(string worktree, IReadOnlyDictionary environment); - - /// Runs one probe (by its filter) with the environment given; the coverage report goes to under . - Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment); - - /// The generated axes (settings of the option types the features read), or null with a reason. - (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory); - - /// The environment every build and run of the probes needs (for .NET: the coverage extension). - IReadOnlyDictionary Environment(string cacheDirectory); -} - -/// -/// The .NET adapter, configured by the "replay" object of the axes file: argv templates for the build and -/// the test run (through the repository's verdict tool), the commands that prepare the worktree first (building -/// that tool), the coverage extension referenced from a targets file outside the worktree, and the reflection -/// enumerator run with the repository's package versions. -/// -internal sealed class DotNetAdapter(JsonObject config) : IProbeAdapter -{ - private string Project => Files.Str(config["project"]); - - private static string[] Expand(JsonNode? template, Dictionary values) => - [.. Files.Strings(template).Select(arg => Regex.Replace(arg, @"\{(\w+)\}", m => values.TryGetValue(m.Groups[1].Value, out var v) ? v : m.Value))]; - - /// - /// The program a template starts: a bare name (no path separator, dotnet) is found on PATH; a path is - /// relative to the replay worktree and must exist there, so a template naming a file the repository no longer - /// has fails by name, never as a puzzling exit code. - /// - internal static string Executable(string worktree, string program) - { - if (program.IndexOfAny(['/', '\\']) < 0) return program; - var path = Path.Combine(worktree, program); - return File.Exists(path) ? path : throw new Refusal($"the replay template names {program}, which the worktree does not have"); - } - - private static Ran Start(string worktree, string[] argv, IReadOnlyDictionary environment) => - Proc.Run(Executable(worktree, argv[0]), argv[1..], worktree, environment); - - /// Prepares the worktree (the "prepare" commands: building the verdict tool, which a fresh or moved worktree lacks or holds stale), then builds the probes. - public Ran Build(string worktree, IReadOnlyDictionary environment) - { - foreach (var command in (config["prepare"] as JsonArray ?? []).OfType()) - { - var prepared = Start(worktree, Expand(command, new() { ["project"] = Project }), environment); - if (prepared.ExitCode != 0) - return prepared with { Stdout = $"PREPARE FAILED: {string.Join(' ', Files.Strings(command))}\n" + prepared.Stdout + prepared.Stderr }; - } - return Start(worktree, Expand(config["build"], new() { ["project"] = Project }), environment); - } - - /// - /// The "test" template, then the "coverage" arguments when a coverage file is asked for. A replay without a - /// footprint asks for none, so a template that carries the coverage arguments itself is refused rather than - /// run with an empty file name. - /// - public Ran RunProbe(string worktree, string filter, string results, string coverageFile, IReadOnlyDictionary environment) - { - var values = new Dictionary { ["project"] = Project, ["filter"] = filter, ["results"] = results, ["cobertura"] = coverageFile }; - if (coverageFile.Length == 0 && Files.Strings(config["test"]).Any(arg => arg.Contains("{cobertura}", StringComparison.Ordinal))) - throw new Refusal("the replay's test template carries the coverage arguments itself; move them to a \"coverage\" array of the replay configuration, so a run without a footprint can leave them out"); - string[] argv = coverageFile.Length > 0 ? [.. Expand(config["test"], values), .. Expand(config["coverage"], values)] : Expand(config["test"], values); - // The template runs the verdict tool, which keeps its full log where BUILD_VERDICT_LOG_DIR says: the - // directory the replay offers as PROBE_LOG_DIR, whose files it keeps for a failed run. - if (environment.TryGetValue("PROBE_LOG_DIR", out var logDir) && logDir is { Length: > 0 }) - environment = new Dictionary(environment, StringComparer.Ordinal) { ["BUILD_VERDICT_LOG_DIR"] = logDir }; - return Start(worktree, argv, environment); - } - - public IReadOnlyDictionary Environment(string cacheDirectory) - { - var result = new Dictionary(StringComparer.Ordinal); - if (Files.Str(config["coverageTargets"]) is { Length: > 0 } targets) - { - var path = Path.Combine(cacheDirectory, "coverage.targets"); - if (!File.Exists(path) || SharedFile.ReadAllText(path) != targets) Files.WriteAtomically(path, targets); - result["CustomAfterMicrosoftCommonTargets"] = path; - } - return result; - } - - public (JsonObject? Axes, string? Error) DeriveAxes(string checkout, string workDirectory) - { - if (config["enumerate"] is not JsonObject enumerate) return (null, "no enumerator configured"); - // The enumerator pins its packages in #:package directives; each version comes from the repository's - // central package versions, so the axes follow a dependency update without anyone editing the script. - var script = File.ReadAllText(Path.Combine(checkout, Files.Str(enumerate["script"]))); - var props = Path.Combine(checkout, "Directory.Packages.props"); - var versions = File.Exists(props) - ? Regex.Matches(File.ReadAllText(props), " m.Groups[1].Value, m => m.Groups[2].Value, StringComparer.Ordinal) - : new Dictionary(StringComparer.Ordinal); - script = Regex.Replace(script, @"^#:package ([^@\s]+)@(\S+)", m => $"#:package {m.Groups[1].Value}@{(versions.TryGetValue(m.Groups[1].Value, out var v) ? v : m.Groups[2].Value)}", RegexOptions.Multiline); - Directory.CreateDirectory(workDirectory); - var file = Path.Combine(workDirectory, Path.GetFileName(Files.Str(enumerate["script"]))); - Files.WriteAtomically(file, script); - var ran = Proc.Run("dotnet", ["run", file], workDirectory); - if (ran.ExitCode != 0) return (null, "the enumerator failed: " + ran.Stderr.Trim().Split('\n')[^1]); - var json = ran.Stdout[ran.Stdout.IndexOf('{')..]; - return (JsonNode.Parse(json) as JsonObject, null); - } -} diff --git a/tools/Prober/ProbeRun.cs b/tools/Prober/ProbeRun.cs deleted file mode 100644 index 484fc507..00000000 --- a/tools/Prober/ProbeRun.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// What replay, seeds and try share to run a probe: the worktree moved to HEAD, the -/// environment every build and run gets, one run of a probe in one process, and how each row of it ended, read -/// from the jsonl the harness writes under PROBE_OUT. -/// -internal static class ProbeRun -{ - /// - /// A row's outcome under one run: its category, the first reason given, whether any reason of the row or of a check - /// of it was a harness error, and its checks. A row that ran no check is one check of the obligation claim. - /// - internal sealed record RowOutcome(string Category, string Reason, bool HarnessError, IReadOnlyList Checks); - - /// - /// One check of a row under one run: its obligation, category and first reason, and whether a harness error broke it - /// or its row outside any check. Only a clean violation, one with no harness error, says the check fired (decision 103). - /// - internal sealed record CheckOutcome(string Obligation, string Category, string Reason, bool HarnessError) - { - public bool CleanViolation => Category == "violation" && !HarnessError; - } - - /// - /// Adds the worktree at ("cold"), or moves it there without force ("warm"): files the - /// commits did not change keep their mtimes, so the build stays incremental. - /// - public static string Ready(Ledger ledger, string worktree, string head) - { - if (!Directory.Exists(worktree)) - { - var added = Git.Run(ledger.Root, "worktree", "add", "--detach", worktree, head); - if (added.ExitCode != 0) throw new Refusal("could not add the worktree: " + added.Stderr.Trim(), 2); - return "cold"; - } - if (Git.Run(worktree, "checkout", "--detach", head).ExitCode != 0) Git.Run(worktree, "reset", "--hard", head); - return "warm"; - } - - /// The process's environment with what the adapter adds for every build and run of the probes. - public static Dictionary Environment(Context ctx, IProbeAdapter adapter, string home) - { - var environment = new Dictionary(ctx.Environment, StringComparer.Ordinal); - foreach (var (k, v) in adapter.Environment(home)) environment[k] = v; - return environment; - } - - /// The environment of one variant: the base, then the variant's own settings, then the extra ones (a seed's toggle). - public static Dictionary Variant(IReadOnlyDictionary environment, JsonObject variant, JsonObject? extra = null) - { - var env = new Dictionary(environment, StringComparer.Ordinal); - foreach (var (k, v) in variant) env[k] = Files.Str(v); - foreach (var (k, v) in extra ?? []) env[k] = Files.Str(v); - return env; - } - - /// - /// Runs the probe the filter selects once, with its rows written to {results}/{name}-rows, and reads how - /// each row ended. empty asks for no coverage. - /// - public static (Ran Ran, Dictionary Rows) Once(IProbeAdapter adapter, string worktree, string filter, string results, string name, - string coverageFile, Dictionary env) - { - var outDir = Path.Combine(results, name + "-rows"); - env["PROBE_OUT"] = outDir; - var ran = adapter.RunProbe(worktree, filter, results, coverageFile, env); - return (ran, Outcomes(outDir)); - } - - /// How each row ended, from every jsonl under ; a line without a category is a violation. - public static Dictionary Outcomes(string outDir) - { - var rows = new Dictionary(); - if (!Directory.Exists(outDir)) return rows; - foreach (var file in Directory.EnumerateFiles(outDir, "*.jsonl")) - foreach (var line in Files.ReadLines(file)) - { - var category = Files.Str(line["category"], "violation"); - var reasons = Files.Strings(line["reasons"]).ToList(); - var reason = reasons.FirstOrDefault(r => r.StartsWith(category + ":", StringComparison.Ordinal)) ?? Files.Str(line["note"]); - static bool Broken(IEnumerable reasons) => reasons.Any(r => r.StartsWith("harness-error:", StringComparison.Ordinal)); - var checks = new List(); - if (line["checks"] is JsonArray { Count: > 0 } ran) - { - // The row's own harness error (outside any check) breaks every check of it; a check's breaks that check. - var rowBroken = Broken(reasons); - foreach (var c in ran.OfType()) - { - var cc = Files.Str(c["category"], "violation"); - var cr = Files.Strings(c["reasons"]).ToList(); - checks.Add(new CheckOutcome(Files.Str(c["obligation"]), cc, cr.FirstOrDefault(r => r.StartsWith(cc + ":", StringComparison.Ordinal)) ?? Files.Str(c["notes"]), - rowBroken || cc == "harness-error" || Broken(cr))); - } - } - else checks.Add(new CheckOutcome(Claim.ImplicitObligation, category, reason, category == "harness-error" || Broken(reasons))); - var harnessError = Broken(reasons) || checks.Any(c => c.HarnessError); - rows[(int)Files.Num(line["idx"])] = new RowOutcome(category, reason, harnessError, checks); - } - return rows; - } - - /// The first line of a run's output (the verdict's), or its exit code where it printed nothing. - public static string FirstLine(Ran ran) => ran.Stdout.Split('\n')[0].Trim() is { Length: > 0 } line ? line : $"exit {ran.ExitCode}"; -} diff --git a/tools/Prober/Prober.csproj b/tools/Prober/Prober.csproj deleted file mode 100644 index ba12505a..00000000 --- a/tools/Prober/Prober.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Exe - prober - Prober - - false - $(ToolSourcePatterns);Schemas/*.json - - - - - - - - - - - - diff --git a/tools/Prober/Program.cs b/tools/Prober/Program.cs deleted file mode 100644 index 7b62b3ae..00000000 --- a/tools/Prober/Program.cs +++ /dev/null @@ -1,135 +0,0 @@ -namespace Prober; - -internal static class Program -{ - private const string Usage = - """ - prober: the probing workflow's core. No command starts a model; only `round` does, locally. - - Ledger (any checkout of the repository; --branch B, default the checked-out branch): - universe [--base REF] each claim's axes, from the claims, the axes file and the generated axes - rows --claim C [--full] a pairwise covering array over the claim's pairs not yet covered; - inside a capped round it refuses past the deadline or the claim cap - rows --probe P [--full] writes P's rows file whole into the staging: a covering array over its - claim's pairs less those the claim's other probes have credited - status [--json] coverage from current evidence, open findings, done or not; per claim - its obligations and which have a seed - gaps [--base REF] what the corpus leaves out, each with its reason: unassigned settings, - refused shapes and values, what claims do not promise, out of reach, and - the wanted pairs no passing check of the last replay read both axes of - gate [--since REF] [--json] the release gate (needs only the tracked corpus and a replay) - stale [--json] [--include-retired] the probes a replay would run - identity --probe P what a result of P is bound to - record-run --probe P --result pass|fail [--evidence F] [--seconds S] - footprint --probe P --cobertura F... --root WT [--include src] [--compile-time PATH...] - register --probe P --claim C --filter F [--variants JSON] [--seed PATCH] [--seed-env NAME=VALUE...] [--defect TEXT] - [--obligation O]: the seed (a patch, a toggle or both) into `seed`, or with - --obligation into `seeds`, in place of a seed naming O; refuses an O that - claim C does not list - publish | dismiss --id F --reason TEXT | mark retired --probe P - fix F --commit SHA [--reason TEXT] records open finding F fixed at the commit (findings.jsonl); refuses - an id this ledger does not hold open and a commit the repository lacks - lock --holder H --mode replay|explore|full [--pid N] | unlock --holder H | heartbeat --holder H - round-start --holder H --minutes M [--claims N] | round-end --holder H | repair | abandon - merge --from DIR... joins the states of a replay split by family (one DIR per leg) into - this one; refuses while a registered probe was in no leg - - Writing a probe (into the branch's staging): - new --claim C [--probe P] [--family F] stages P's skeleton (the claim's source and obligations quoted, one - check per obligation that throws until written), the claim's rows and P's - registry entry with no seed yet; P defaults to the claim's prefix and words - (C20-testing-shouldhold: C20TestingShouldholdProbe); refuses a claim not in - the claims, a name taken, a family that is not the claim's - try --probe P [--rows i,j,...] [--no-build] builds once in the replay's worktree and runs P alone, every - variant or the rows given, printing how each row ended; records nothing, - holds the worktree from a replay, exits with the probe's exit code - - Running probes: - replay [--all] [--family F] [--parallel N] [--no-footprint] [--holder H] [--dry-run] [--where] - replays the corpus with no model: the stale probes, or all; one family - of the replay configuration; N probe processes at a time (default: - the cores); without coverage or footprint, for a state nobody keeps - round explore|full [--minutes M] [--claims N] [--usd X] a capped exploration round (local only) - seeds [--all] [--probe P] [--dry-run] applies each probe's seeded defect in a scratch worktree, replays the - probe there and requires a violation it causes (local only, a build per - seed): the probes whose identity or footprint changed since every seed of - theirs was caught, or all of them, as a release runs it - - State goes under PROBE_STATE_DIR when set (CI), else the main checkout's prober memory. - Exit codes: 0 done, 1 refused or failed, 2 usage, 3 this dll is stale; `try` exits with the probe's own. - """; - - private static readonly HashSet Flags = new(StringComparer.Ordinal) - { "json", "full", "all", "include-retired", "dry-run", "where", "no-footprint", "no-build" }; - - private static int Main(string[] args) - { - Console.OutputEncoding = new System.Text.UTF8Encoding(false); - if (args.Length == 0 || args[0] is "help" or "-h" or "--help") { Console.Write(Usage); return args.Length == 0 ? 2 : 0; } - var home = FindRoot(AppContext.BaseDirectory); - if (home is not null && SourceFingerprint.Difference(home) is { } stale) - { - Console.Error.WriteLine($"prober: this dll was built from other sources than the checkout holds ({stale}). Run `{SourceFingerprint.RebuildCommand}`."); - return SourceFingerprint.StaleExitCode; - } - return Run(Context.FromProcess(), args); - } - - /// Runs one command against a context: the process's, or a test's. - public static int Run(Context ctx, string[] args) - { - try - { - var command = args[0]; - var a = new Args(args[1..], Flags); - if (command == "replay") return Replay.Run(ctx, a); - if (command == "round") return Round.Run(ctx, a); - if (command == "seeds") return Seeds.Run(ctx, a); - if (command == "try") return TryProbe.Run(ctx, a); - var ledger = new Ledger(ctx, a.Get("branch")); - // Commands run under a round keep its lock alive. - if (command is not ("lock" or "unlock" or "abandon" or "heartbeat") && ctx.Env("PROBE_HOLDER") is { } holder) - RoundLock.Beat(ledger, holder); - return command switch - { - "universe" => Commands.UniverseCommand(ledger, a), - "rows" => Commands.Rows(ledger, a), - "status" => Commands.Status(ledger, a), - "gate" => Commands.Gate(ledger, a), - "stale" => Commands.Stale(ledger, a), - "identity" => Commands.IdentityCommand(ledger, a), - "record-run" => Commands.RecordRun(ledger, a), - "footprint" => Commands.Footprint(ledger, a), - "new" => NewProbe.Run(ledger, a), - "register" => Commands.Register(ledger, a), - "publish" => Commands.Publish(ledger, a), - "dismiss" => Commands.Dismiss(ledger, a), - "fix" => Commands.Fix(ledger, a), - "mark" => Commands.Mark(ledger, a), - "lock" => Commands.Lock(ledger, a), - "unlock" => Commands.Unlock(ledger, a), - "heartbeat" => Commands.HeartbeatCommand(ledger, a), - "owe-replay" => Commands.OweReplay(ledger, a), - "round-start" => Commands.RoundStart(ledger, a), - "round-end" => Commands.RoundEnd(ledger, a), - "repair" => Commands.Repair(ledger, a), - "abandon" => Commands.Abandon(ledger, a), - "merge" => Commands.Merge(ledger, a), - "gaps" => Commands.Gaps(ledger, a), - _ => throw new Refusal($"unknown command {command}; see `prober help`", 2), - }; - } - catch (Refusal refusal) - { - ctx.Error.WriteLine("prober: " + refusal.Message); - return refusal.ExitCode; - } - } - - private static string? FindRoot(string start) - { - for (var dir = new DirectoryInfo(start); dir is not null; dir = dir.Parent) - if (File.Exists(Path.Combine(dir.FullName, "CodoMetis.TypeKit.slnx"))) return dir.FullName; - return null; - } -} diff --git a/tools/Prober/README.md b/tools/Prober/README.md deleted file mode 100644 index 3abf10f2..00000000 --- a/tools/Prober/README.md +++ /dev/null @@ -1,181 +0,0 @@ -# prober - -The probing workflow's core: the ledger of what the documents claim and what the probes have shown, the -replay of the probe corpus, the release gate, and the capped exploration round. Repository tooling, not -a package. It references the base class library only and is built with the solution. - -```text -dotnet tools/Prober/bin/Release/net10.0/prober.dll help -``` - -## What runs where - -| Command | Model | Where | -|---|---|---| -| `replay [--all] [--family F] [--parallel N] [--no-footprint]` | none | anywhere, CI included: the probes whose identity or footprint changed, or all of them; one family of the replay configuration; N probe processes at a time (the cores by default); without coverage or a footprint, for a state nobody keeps (decision 101) | -| `merge --from DIR...` | none | anywhere, CI included: joins the states of a replay split by family, and refuses while a registered probe was in no leg | -| `gate [--since REF]` | none | anywhere, CI included: needs only the tracked corpus and a replay | -| `status`, `stale`, `universe`, `rows [--claim C \| --probe P]`, … | none | anywhere | -| `gaps [--base REF]` | none | anywhere: what the corpus leaves out, each with its recorded reason, and, from the last replay's evidence, each wanted pair no obligation wanting it has a passing check that read both its axes of (more rows cannot cover it); a report that decides nothing (decision 104) | -| `fix F --commit SHA [--reason TEXT]` | none | anywhere: records an open finding fixed at a commit, the fixed line of the state's `findings.jsonl` as `finding-line.schema.json` wants it; it counts once the commit is in HEAD's history | -| `new --claim C [--probe P] [--family F]` | none | anywhere: stages a probe's skeleton, its own rows and its registry entry with no seed yet, and prints what the writer still owes | -| `try --probe P [--rows i,j,...] [--no-build]` | none | locally: builds once in the replay's worktree and runs that one probe, every row or the rows given; records nothing, and holds the worktree from a replay while it runs | -| `round explore\|full` | the `prober` agent | locally only, under caps it cannot overrun | -| `seeds [--all] [--probe P]` | none | locally only: one build per seed, in a scratch worktree (decision 100); the probes whose seeds identity or product footprint changed since every seed was caught, or all of them, as a release runs it (decision 107) | - -No command in the gate's path needs a login, an API key or a Claude executable. A gate obligation is met -by a probe in the corpus, written by hand or by a round, or by a reviewed waiver in -`tools/probe/corpus/waivers.json`. - -## Files - -The corpus is tracked under `tools/probe/corpus/`: claims, the probe registry, harness and probe sources, -rows (gzipped), waivers and dismissed findings. State goes under `PROBE_STATE_DIR` when set (CI sets it), -else the main checkout's `.claude/agent-memory-local/prober/`. Every file's shape is in `Schemas/`, versioned; -a file or line without `schemaVersion` is version 1. `claims.json` is checked against its schema wherever it is -read, and a field the schema does not have is refused with the claim and the field named; each `exclude` entry -is a reason and its pairs, which `universe` prints beside the claim's narrowings. The JSON files the prober -writes keep `+`, backticks and `<` literal, so a `publish` that changes nothing in a tracked file leaves it as -it is (decision 102). The harness's generated declarations, `harness/*.g.cs`, are written by the file-based -apps of `tools/probe/generators/` from the rows and the axes file, and `GeneratedHarnessTests` in the -conventions tests holds each to its app's output (that directory's README). - -Rows are per probe: `rows/.json.gz`, one file for each registered probe, its claim inside (`claim`), so -two probes of one claim (C07's `BaseProbe` and `C07BlanketMappingProbe`) each run rows of their own, and a -probe's identity reads its own file only: a sibling's rows changing leaves it as it was. The probe's -`Rows.Data("P")` names the file, and the replay, `try` and the identity read it. `rows --probe P` writes P's file -whole into the staging, never appended: a covering array over its claim's pairs less those the claim's other -probes have credited (P's own credit is not subtracted, since it came from the rows the file replaces), and -`publish` moves it into the corpus by probe; `rows --claim C` only prints such an array. The stored rows are -definitions, the evidence is in the state. `ProbeRowsTests` in the conventions tests refuses two rows of one -file with the same axis map, a file whose `claim` is not in `claims.json` or is not its probe's, a file that -names no registered probe, and a registered probe without a file. - -A registry entry may list `watched`: paths, files or directories, that the probe's result depends on and its -footprint cannot see, since the footprint is what ran in the probe's own process under `src/` beside the -`compileTimeFootprint` paths. A variant catalogue under `test/` compiled into the probes is one (C19 builds -over the analyzer tests' `TypeArgumentSites` and `TypeArgumentKinds`), a build input a child process reads is -another (C18's consumer build compiles against the base package and evaluates `src/Directory.Build.*`). The -replay records each with its object id in the footprint line, a change to one stales the footprint like a path -the probe ran, and the gate counts it as touching the probe's claim. A probe whose own process runs nothing under `src/` -(C22 builds its consumer in a child process) is recorded by what its entry watches alone; where nothing ran and nothing -is watched, `footprint` refuses to record an empty footprint, which would never go stale. - -The round lock, `round.lock` and its mutex, sits in the branch's directory (`branches//`), beside -everything a round or a replay writes, so rounds and replays of two branches run at once and two of one branch -never do. The scratch worktrees, `wt` (the replay's), `seeds`, `explore` (the `prober` agent's) and `enumerate`, -are per checkout: under `PROBE_CACHE_DIR` when set, else `~/.cache/probe-replay/-`, -and `replay --where` prints them. So a linked worktree (`git worktree add`, as each session under -`.claude/worktrees/` is) builds a warm copy of its own, about a gigabyte of disk, and two sessions never reset -each other's copy; the main checkout keeps the directory it had before. Since the lock is per branch and the -worktree per checkout, a replay also holds `replay.lock` beside them (an OS lock, gone with its process), and a -replay of another branch in the same checkout, after a branch switch, is skipped while one runs. Removing a -linked worktree leaves its cache behind: before you remove it, run there the `remove:` line that `replay --where` -prints, which removes the cache's worktrees (`git worktree remove`) and then its directory, every path written out. - -A claim lists what it promises in `obligations`, each an id and a sentence quoted verbatim from the claim's -source, and what it does not promise in `not-promised`, each an id and the sentence of the document or record -that makes the difference intended, quoted from that source. `universe` checks every quote as it checks a -narrowing's and refuses a sentence its document does not hold, or an id listed twice. A claim without -`obligations` has one, the claim itself, under the id `claim`. `status` shows per claim its obligations and the -ones no seed names, and `gaps` prints every not-promised entry and narrowing beside the settings no surface -reaches, the refused shapes and values, and the axes file's `out-of-reach` surfaces (decision 104). - -An obligation may declare where it does not apply: `inapplicable`, each entry the claim's own axis values -(`axes`) and a citation (`cite`: `not-promised:id` of the claim's list, `docs:file#anchor`, `fact:KB-NNN` or -`record:NNNN`). A row holding every axis of a declaration at one of its values runs no check of that -obligation: `Row.Check` records the check inapplicable with the cite before its body runs, for that check only. -The replay stages the claims beside the rows (`claims.json` in the probe directory) for the harness's -`Rows.Claim`, and a probe's identity takes its claim's declarations. A pair a declaration matches is not wanted -by that obligation (`Claim.PairsWantedBy`); a pair no obligation wants is declared inapplicable: `universe` -prints each claim's count with the citations, `gaps` lists them under a heading of their own, `status --json` -gives `inapplicable_pairs` per claim, the covering generator never puts one in a row, and the gate leaves them -out as it leaves out an exclusion. A claim's pairs stay its pairs. `universe` refuses a declaration whose axis -or value the claim does not list, whose cite is malformed, or whose not-promised id the claim lacks. - -A pair of a claim's axes counts as covered only by evidence a replay recorded: a check that ended as a pass, in a -row that was expected and executed, for the settings that actually applied, while the result's identity holds -(the probe, every compiled corpus source, the rows, the axes file, the build environment, this tool's -version and the schema version) and the product files the probe ran are unchanged. A row's checks -(`Row.Check` in the harness) each name an obligation and a baseline and record the axes they read; a check is -credited with those and the row's own (read outside any check), and a pair is never put together from two -checks' axes. A row without checks is one check of the obligation `claim` with the row's category. Evidence is -version 2 (`Schemas/evidence.schema.json`): the replay copies each row's `checks` beside its `applied` and -`reasons`. `status --json` gives each obligation `current`, the pairs current checks naming it earned, and -`passed`; the text line counts rows and checks by outcome and ends with the obligations no passing check named -at the last replay (`K uncredited`). - -## Seeds - -Each probe's registry entry names a seeded product defect: a patch under `seeds/` against the product -files (the replay's `include`), an environment toggle, or both, and the sentence `defect`. Where its claim -lists obligations, the entry's `seeds` holds one such seed per obligation the probe checks, each naming it in -`obligation`, and every listed obligation of a claim with probes has a seed in one of them (decision 104). -`seeds` applies each seed on its own in the `seeds` worktree beside the replay's, builds, runs the probe -and counts the seed caught only for a check that ends as a violation, with no harness error in it or in its -row outside its checks (decision 103), in a row whose unseeded run had no violation of the same obligation; a -seed naming an obligation is caught only by a check naming it, so a probe whose rows run no checks (each the -one check `claim`) catches only seeds that name none. The unseeded rows come from the ledger where the probe's -evidence is current, else from an unseeded run first. Nothing it runs is evidence; it -writes `seeds-last.json` (`Schemas/seeds-run.schema.json`), one outcome per seed, reported as -`P/` where the seed names one. `register --obligation O --seed PATCH --defect TEXT` (or -`--seed-env NAME=VALUE...` for a toggle) writes a seed into `seeds`, in place of any seed of the entry that -names O, `seed` included, and refuses an O that the claim's entry in `claims.json` does not list; without -`--obligation`, `--seed` and `--seed-env` set the one `seed`. No seed is written into the registry by hand. -Without `--all`, `seeds` runs only the probes that changed since the run that caught every one of their seeds -(design/adr/0107), as `replay` runs only the stale ones: a probe runs when its seeds identity (the probe's identity, -its seeds and the content of their patches) differs from the one recorded, when the product footprint its last -replay recorded or a file its seeds patch changed since the recorded commit, when no footprint is recorded, and when -no run caught all its seeds. It prints each probe it runs or skips with the reason. `seeds-last.json` keeps, per probe, -the identity and the commit of the run that caught them all, carried forward for the probes a run skips; a missed seed -drops the probe's record, so it is never skipped next time. `--all` runs every probe whatever the record says, and a -release runs it before the tag; `--probe P` runs P. -A seed is not part of a probe's identity, neither `seed` nor `seeds`. Without a build, -`Seeds.Problems`, which the prober tests run over the repository, refuses a probe without a seed, a seed that -does not apply, a seed naming an obligation its claim does not list, and a listed obligation no seed names. - -## Writing a probe - -`new --claim C` starts one in the branch's staging, whose path it prints. It writes `probes/P.cs` in the form -the corpus's probes have (`Rows.Data`, `[Theory, MemberData(nameof(Data))]`, `Rec.Run`), headed by the claim's -source and each obligation's id and sentence, with one check per obligation that throws until it is written: -the probe builds beside the others, and every row of it ends as a harness error, which fails the row, earns -nothing and is never a seed's catch. It stages the probe's own rows, a covering array over its claim's pairs the -claim's other probes have not covered, as `rows --probe P` writes them, and the registry entry with an empty -`seeds`, so `seeds` and `Seeds.Problems` name the seed each obligation owes. P defaults to the claim id's -prefix and words (`C20-testing-shouldhold` is `C20TestingShouldholdProbe`); it refuses a claim that is not in -the claims, a name a probe has, and a claim whose first surface is in no family, or not in `--family`'s. - -Then fill each check and run `try --probe P` until each row ends as it should. It moves the replay's worktree -to HEAD, overlays the corpus and the staging as the replay does, builds once through the adapter (not with -`--no-build`), and runs P alone in each of its registry variants, or only the rows `--rows` names, through the -harness's `PROBE_ROWS`, within the rows each variant's `PROBE_ONLY` selects. It prints each run's verdict line -and how each row ended, and exits with the probe's code (1 when the build fails). It records no evidence, -footprint or run and takes no round lock, but holds the replay's worktree (`replay.lock`) while it runs, so a try -refuses while a replay of the checkout runs, and a replay skips while a try does. Then write a seed per -obligation and register it with the command `new` printed for that obligation (`register --obligation O`, -under "Seeds"), show each caught with `seeds --probe P`, and `publish`. `register` lints the staged sources -first (below). A writer needs no build or sync script of their own. - -## Register and publish - -`register` and `publish` read the staged harness and probe sources first and refuse, by file and line, a -`Note` whose first argument is not a `NoteKeys` member the corpus declares, a harness `Skip` whose finding -is not a string literal naming a finding this ledger holds open (decision 103), and a check's `Inapplicable` or -`Refused` whose first argument is not a `Cite` factory with a string literal, or names what does not exist: a -not-promised entry the probe's claim does not list (any claim's, for a harness source no one probe owns), a docs -file, a knowledge entry under `design/knowledge/`, a record under `design/adr/`. `ProbeCiteTests` in the -conventions tests holds the same over the tracked corpus. The scan blanks out comments -and string literals and reads text, since this tool references the base class library only. - -## The adapter - -Building the probes, running one probe in one process, and deriving the generated axes go through -`IProbeAdapter` (`ProbeAdapter.cs`), configured by the `replay` object of `.claude/probe-axes.md`. The .NET -adapter is the only one; the core holds nothing of .NET's, so another stack can plug in its own. - -## Freshness - -The dll hashes its own sources, the schemas among them, at build time and checks them at startup, as every -tool does (`tools/Directory.Build.targets`): a changed, added or removed source makes it refuse with exit 3 -and name the command that rebuilds it, `dotnet build tools/Prober -c Release`. Content hashes, never times. diff --git a/tools/Prober/ReleaseGate.cs b/tools/Prober/ReleaseGate.cs deleted file mode 100644 index 42caea16..00000000 --- a/tools/Prober/ReleaseGate.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// The release gate. It needs nothing but the tracked corpus and a replay: no model, no login, no local -/// memory of a developer's machine. It refuses while the staging is unpublished, a finding is open or a row -/// skips for one, a probe has not passed at its current identity and footprint, an expected row did not run, or a claim touched -/// since the release has pairs no probe covers and no reviewed waiver. Touched is chosen conservatively: the -/// claim's source document, its surfaces' source areas, the paths its probes watch or the build inputs changed; footprints only add. -/// -internal static class ReleaseGate -{ - private static readonly string[] BuildInputs = ["Directory.Packages.props", "Directory.Build.props", "global.json"]; - - public static int Run(Ledger l, string? sinceArg, bool json) - { - var since = sinceArg ?? Git.Out(l.Top, "describe", "--tags", "--abbrev=0"); - var (universe, _) = Axes.Build(l, since); - var footprints = l.Footprints(); - var reasons = new List(); - if (Directory.Exists(l.StagingDir) && Directory.EnumerateFiles(l.StagingDir, "*", SearchOption.AllDirectories).Any()) - reasons.Add("the staging corpus is not published (run `publish` and commit tools/probe/corpus)"); - var open = l.OpenFindings(); - if (open.Count > 0) reasons.Add($"open findings: {string.Join(", ", open)}"); - - var runs = Files.ReadLines(l.P("runs.jsonl")).GroupBy(r => Files.Str(r["probe"]), StringComparer.Ordinal).ToDictionary(g => g.Key, g => g.Last(), StringComparer.Ordinal); - foreach (var s in l.ProbeStates(includeRetired: true)) - { - if (s.Stale) { reasons.Add($"{s.Probe}: not replayed at its current identity and footprint (run `prober replay --all`)"); continue; } - if (Files.Str(runs.GetValueOrDefault(s.Probe)?["result"]) != "pass") { reasons.Add($"{s.Probe}: its last replay failed"); continue; } - var evidence = Files.ReadJson(l.EvidencePath(s.Probe)) as JsonObject; - var expected = new HashSet(); var executed = new HashSet(); - foreach (var v in (evidence?["variants"] as JsonArray ?? []).OfType()) - { - foreach (var i in v["expected"] as JsonArray ?? []) expected.Add((int)Files.Num(i)); - foreach (var i in v["executed"] as JsonArray ?? []) executed.Add((int)Files.Num(i)); - } - expected.ExceptWith(executed); - if (expected.Count > 0) reasons.Add($"{s.Probe}: {expected.Count} expected row(s) did not run"); - // A skip is an open finding the corpus itself records, so it binds where the ledger has none (CI). - foreach (var (finding, rows) in Ledger.FindingSkips(evidence)) - reasons.Add($"{s.Probe}: {rows} row(s) skip for finding {finding}; fix it and remove the skip, or dismiss it"); - } - - var done = l.Covered(universe); - var byClaim = l.Registry().GroupBy(kv => Files.Str(kv.Value["claim"]), StringComparer.Ordinal).ToDictionary(g => g.Key, g => g.Select(kv => kv.Key).ToList(), StringComparer.Ordinal); - var changed = Git.Out(l.Top, "diff", "--name-only", since, "HEAD").Split('\n', StringSplitOptions.RemoveEmptyEntries); - bool Under(IEnumerable paths) => paths.Any(w => changed.Any(f => f == w || f.StartsWith(w.TrimEnd('/') + "/", StringComparison.Ordinal))); - - // A reviewed waiver meets an obligation without a probe; one without a reason or a reviewer meets nothing. - var waivers = (Files.ReadJson(l.CorpusPath("waivers.json")) as JsonArray ?? []).OfType() - .Where(w => Files.Str(w["claim"]).Length > 0 && Files.Str(w["reason"]).Length > 0 && Files.Str(w["reviewed_by"]).Length > 0) - .Select(w => Files.Str(w["claim"])).ToHashSet(StringComparer.Ordinal); - - var required = new List(); var waived = new List(); var missedByFootprint = new List(); var footprintOnly = new List(); - var missingTotal = 0; var inapplicableTotal = 0; - foreach (var claim in universe.Claims) - { - var probes = byClaim.GetValueOrDefault(claim.Id) ?? []; - // What the claim's surfaces watch, and what its probes' registry entries watch beyond their footprints. - var conservative = Under([claim.Source.Split('#')[0]]) || Under(claim.Watched) || Under(probes.SelectMany(l.Watched)) || Under(BuildInputs); - var footprint = probes.Count > 0 && probes.Any(p => l.FootprintChangedSince(p, since, footprints)); - if (probes.Count > 0 && conservative && !footprint) missedByFootprint.Add(claim.Id); - if (footprint && !conservative) footprintOnly.Add(claim.Id); - if (!(conservative || footprint)) continue; - if (waivers.Contains(claim.Id)) { waived.Add(claim.Id); continue; } - // The pairs some obligation wants; one no obligation wants is declared inapplicable and left out, as an exclusion is. - var pairs = claim.PairsWanted(); - inapplicableTotal += claim.Pairs().Count - pairs.Count; - var missing = pairs.Count(p => !done.Contains((claim.Id, p))); - required.Add(claim.Id); missingTotal += missing; - if (missing > 0) reasons.Add($"{claim.Id}: {missing} of {pairs.Count} pairs uncovered (touched since {since})"); - } - - if (json) - { - l.Ctx.Out.WriteLine(new JsonObject - { - ["since"] = since, ["touched"] = new JsonArray([.. required.Select(x => (JsonNode)x)]), ["uncovered_pairs"] = missingTotal, ["inapplicable_pairs"] = inapplicableTotal, - ["reasons"] = new JsonArray([.. reasons.Select(x => (JsonNode)x)]), - ["selected_by_footprint_only"] = new JsonArray([.. footprintOnly.Select(x => (JsonNode)x)]), - ["waived"] = new JsonArray([.. waived.Select(x => (JsonNode)x)]), - ["missed_by_footprint_alone"] = new JsonArray([.. missedByFootprint.Select(x => (JsonNode)x)]), ["passes"] = reasons.Count == 0, - }.ToJsonString(new JsonSerializerOptions { WriteIndented = true })); - return reasons.Count == 0 ? 0 : 1; - } - if (reasons.Count > 0) - { - l.Ctx.Error.WriteLine($"probe gate: refused for {l.Branch} since {since} ({required.Count} claim(s) touched, {missingTotal} pair(s) uncovered):"); - foreach (var r in reasons) l.Ctx.Error.WriteLine($" {r}"); - return 1; - } - l.Ctx.Out.WriteLine($"probe gate: {l.Branch} passes since {since}: {required.Count} claim(s) touched and fully covered" + - (waived.Count > 0 ? $", {waived.Count} waived ({string.Join(", ", waived)})" : "") + - ", every probe replayed and passing, no open finding."); - return 0; - } -} diff --git a/tools/Prober/Replay.cs b/tools/Prober/Replay.cs deleted file mode 100644 index eba97a0f..00000000 --- a/tools/Prober/Replay.cs +++ /dev/null @@ -1,440 +0,0 @@ -using System.Diagnostics; -using System.Globalization; -using System.Security.Cryptography; -using System.Text; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// Replays the written probes with no model in the loop. Per commit it runs only the probes whose identity or -/// footprint changed; --all runs every probe, retired ones included (the release run). Each probe runs -/// once per process variant, and the replay records each probe in registry order whatever order the runs -/// finished in: per-row evidence (rows expected, rows executed, each row's outcome and applied settings), the -/// result, and the fresh footprint. --no-footprint runs without coverage and records no footprint, for a -/// state nobody keeps (a pull request's); only then do the variants of every selected probe run -/// --parallel N at a time (the machine's cores by default), since the coverage collector rewrites the -/// assemblies on disk and two hosts from one output directory corrupt each other (KB-025). -/// --family F replays the probes whose claim's first surface the -/// replay configuration's families puts under F, so a matrix of jobs can split the corpus and -/// merge join their states; it refuses while any probe's surface is in no family, so a matrix cannot -/// quietly leave a probe out. It works in one warm worktree kept between runs and moved to HEAD without force, -/// so only what changed is rebuilt. A dependency input that changed stales every probe, and the axes are -/// derived again. Only one round runs at a time. -/// -internal static class Replay -{ - /// How this replay was asked to run, recorded in replay-last.json for merge to read. - internal sealed record Options(bool All, string? Family, int Parallel, bool Footprint); - - public static int Run(Context ctx, Args a, IProbeAdapter? adapter = null) - { - var ledger = new Ledger(ctx, a.Get("branch")); - var config = ledger.AxesBlock()["replay"] as JsonObject ?? throw new Refusal("the axes file's block has no \"replay\" configuration"); - adapter ??= new DotNetAdapter(config); - var home = Home(ctx, ledger); - if (a.Flag("where")) - { - ctx.Out.WriteLine($"replay: {Path.Combine(home, "wt")}\nexplore: {Path.Combine(home, "explore")}\nseeds: {Path.Combine(home, "seeds")}"); - ctx.Out.WriteLine($"remove: {RemoveCommand(home)}"); - return 0; - } - - // With a footprint the coverage collector instruments the assemblies on disk, so two hosts from one - // output directory corrupt each other (KB-025): one at a time, whatever --parallel says. - var footprint = !a.Flag("no-footprint"); - var asked = Parallelism(a.Get("parallel")); - var options = new Options(a.Flag("all"), a.Get("family"), footprint ? 1 : asked, footprint); - var states = ledger.ProbeStates(options.All); - var scope = options.Family is null ? states : OfFamily(config, ledger, states, options.Family); - var todo = options.All ? scope : [.. scope.Where(s => s.Replay)]; - var skipped = scope.Where(s => !todo.Contains(s)).Select(s => s.Probe).ToList(); - var head = ledger.Head; - ctx.Out.WriteLine($"prober replay: {ledger.Branch} at {head[..7]}: {todo.Count} of {scope.Count} probes to replay" + - $"{(options.Family is null ? "" : $" (family {options.Family})")}, " + - (footprint ? "one at a time (the coverage collector rewrites the assemblies on disk)" : $"{options.Parallel} at a time, no footprint")); - if (a.Flag("dry-run")) { foreach (var s in todo) ctx.Out.WriteLine($" {s.Probe}"); return 0; } - - Directory.CreateDirectory(home); - var holder = a.Get("holder") ?? $"replay-{System.Environment.ProcessId}"; - // Under a round's lock (--holder) the replay takes nothing: re-locking would tie the round's liveness to - // this shorter-lived process. On its own it locks with its own process as the owner. - if (a.Get("holder") is null && !RoundLock.Take(ledger, holder, "replay", System.Environment.ProcessId).Taken) - { - RoundLock.OweReplay(ledger); - ctx.Out.WriteLine($"prober replay: skipped, the ledger is locked by another round; its unlock will say a replay is owed"); - return 0; - } - try - { - using var beat = new RoundLock.Heartbeat(ledger, holder); - using var held = HoldWorktree(home); - if (held is null) - { - ctx.Out.WriteLine($"prober replay: skipped, another branch's replay in this checkout is using {home}; run `prober replay` when it ends"); - return 0; - } - var axes = Rederive(ledger, adapter, config, Path.Combine(home, "enumerate"), force: options.All); - if (axes is not null) - { - if (axes["error"] is { } error) ctx.Out.WriteLine($" axes: {Files.Str(error)}"); - else - { - ctx.Out.WriteLine($" axes: re-derived ({(axes["added"] as JsonArray)!.Count} added, {(axes["removed"] as JsonArray)!.Count} removed)"); - foreach (var x in Files.Strings(axes["added"])) ctx.Out.WriteLine($" + {x}"); - foreach (var x in Files.Strings(axes["removed"])) ctx.Out.WriteLine($" - {x}"); - } - } - if (todo.Count == 0) - { - Summary(ledger, head, warmth: null, buildSeconds: 0, todo, skipped, failed: [], seconds: 0, axes, options); - return 0; - } - return Probes(ctx, ledger, adapter, config, home, Path.GetFullPath(a.Get("worktree") ?? Path.Combine(home, "wt")), head, todo, skipped, axes, options); - } - finally - { - if (a.Get("holder") is null) RoundLock.Release(ledger, holder); - } - } - - /// How many probe processes run at once: --parallel N, else one per core. - internal static int Parallelism(string? given) - { - if (given is null) return Math.Max(1, System.Environment.ProcessorCount); - if (!int.TryParse(given, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n) || n < 1) throw new Refusal("--parallel takes a whole number of 1 or more", 2); - return n; - } - - /// - /// The probes of one family: those whose claim's first surface the replay configuration's families - /// (name to surfaces) puts under it. Every probe of the registry must have a family, or a matrix of jobs by - /// family would never run the one that has none; so this refuses for the whole registry, not only the family - /// asked for. - /// - internal static List OfFamily(JsonObject config, Ledger ledger, List states, string family) - { - var families = config["families"] as JsonObject ?? throw new Refusal("the replay configuration names no families; add \"families\" (a name to the surfaces it holds) to the axes file's replay block", 2); - if (families[family] is not JsonArray) throw new Refusal($"no family {family}; the replay configuration has {string.Join(", ", families.Select(kv => kv.Key))}", 2); - var bySurface = new Dictionary(StringComparer.Ordinal); - foreach (var (name, surfaces) in families) - foreach (var surface in Files.Strings(surfaces)) - { - if (bySurface.TryGetValue(surface, out var other) && other != name) throw new Refusal($"the surface {surface} is in two families, {other} and {name}", 2); - bySurface[surface] = name; - } - var firstSurface = ledger.Claims().ToDictionary(c => Files.Str(c["id"]), c => Files.Strings(c["surfaces"]).FirstOrDefault() ?? "", StringComparer.Ordinal); - var result = new List(); - foreach (var s in states) - { - var surface = firstSurface.GetValueOrDefault(s.Claim) ?? ""; - if (!bySurface.TryGetValue(surface, out var f)) - throw new Refusal($"{s.Probe}: the first surface of its claim {s.Claim} ({(surface.Length > 0 ? surface : "none")}) is in no family of the replay configuration, so a replay by family would never run it"); - if (f == family) result.Add(s); - } - return result; - } - - /// Derives the generated axes again when a dependency input or the toolchain changed, or always when forced. - private static JsonObject? Rederive(Ledger ledger, IProbeAdapter adapter, JsonObject config, string work, bool force) - { - if (config["enumerate"] is not JsonObject enumerate) return null; - var stampInput = Files.Canonical(new JsonArray( - new JsonArray([.. Files.Strings(enumerate["inputs"]).Select(p => (JsonNode?)(Git.ObjectId(ledger.Top, p) ?? ""))]), - ledger.Toolchain().DeepClone())); - var stamp = Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(stampInput))); - var path = Path.Combine(ledger.Memory, "axes-generated.json"); - var old = Files.ReadJson(path) as JsonObject ?? []; - if (!force && Files.Str(old["inputsStamp"]) == stamp) return null; - var (generated, error) = adapter.DeriveAxes(ledger.Top, work); - if (generated is null) return new JsonObject { ["error"] = error }; - generated["inputsStamp"] = stamp; - static SortedSet Settings(JsonObject o) => - new((o["axes"] as JsonObject ?? []).SelectMany(kv => Files.Strings(kv.Value).Select(v => $"{kv.Key}={v}")).Concat(Files.Strings(o["needsValues"])), StringComparer.Ordinal); - var before = Settings(old); var after = Settings(generated); - Files.WriteJson(path, generated); - return new JsonObject - { - ["added"] = new JsonArray([.. after.Except(before, StringComparer.Ordinal).Select(x => (JsonNode)x)]), - ["removed"] = new JsonArray([.. before.Except(after, StringComparer.Ordinal).Select(x => (JsonNode)x)]), - ["versions"] = generated["versions"]?.DeepClone(), - }; - } - - /// One process variant of a probe, run: what it was asked, what it answered, and where its rows, coverage and logs went. - private sealed record VariantRun(JsonObject Variant, int Index, Ran Ran, double Seconds, string OutDir, string Coverage, string LogDir); - - /// - /// Starts every variant of a probe, each on a thread of its own that waits its turn at the gate, so the - /// variants of all selected probes share the --parallel slots in the order they were started. - /// - private static List> Start(IProbeAdapter adapter, string worktree, string results, IReadOnlyDictionary environment, - Ledger.ProbeState s, SemaphoreSlim gate, bool coverage) - { - var pending = new List>(); - var index = 0; - foreach (var variant in s.Variants.OfType()) - { - var i = index++; - var coverageFile = coverage ? $"{s.Probe}-{i}.cobertura.xml" : ""; - var outDir = Path.Combine(results, $"{s.Probe}-{i}-rows"); - // PROBE_LOG_DIR: where the run may leave its full logs; a failed run's are kept in the state. - var logDir = Path.Combine(results, $"{s.Probe}-{i}-log"); - var env = new Dictionary(environment, StringComparer.Ordinal) { ["PROBE_OUT"] = outDir, ["PROBE_LOG_DIR"] = logDir }; - foreach (var (k, v) in variant) env[k] = Files.Str(v); - pending.Add(Task.Factory.StartNew(() => - { - gate.Wait(); - try - { - var clock = Stopwatch.StartNew(); - var ran = adapter.RunProbe(worktree, s.Filter, results, coverageFile, env); - return new VariantRun(variant, i, ran, clock.Elapsed.TotalSeconds, outDir, coverageFile, logDir); - } - finally { gate.Release(); } - }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default)); - } - return pending; - } - - private static int Probes(Context ctx, Ledger ledger, IProbeAdapter adapter, JsonObject config, string home, string worktree, string head, - List todo, List skipped, JsonObject? axes, Options options) - { - var clock = Stopwatch.StartNew(); - var warmth = ProbeRun.Ready(ledger, worktree, head); - var probeDir = Overlay(ledger, config, worktree); - var environment = ProbeRun.Environment(ctx, adapter, home); - var results = Directory.CreateTempSubdirectory("prober-replay-").FullName; - - var buildClock = Stopwatch.StartNew(); - var build = adapter.Build(worktree, environment); - var buildSeconds = buildClock.Elapsed.TotalSeconds; - ctx.Out.WriteLine($" build ({warmth}): {buildSeconds.ToString("F1", CultureInfo.InvariantCulture)} s, {FirstLine(build)}"); - if (build.ExitCode != 0) { ctx.Out.WriteLine(build.Stdout); return 2; } - - // Every variant of every probe is started now and runs when a slot frees; the probes are then read, - // reported and recorded one by one in registry order, each once all its variants have ended. - using var gate = new SemaphoreSlim(options.Parallel); - var started = todo.Select(s => Start(adapter, worktree, results, environment, s, gate, options.Footprint)).ToList(); - - var failed = new List(); - foreach (var (s, pending) in todo.Zip(started)) - { - var variants = pending.Select(t => t.GetAwaiter().GetResult()).OrderBy(v => v.Index).ToList(); - var probeRows = Files.ReadRows(Path.Combine(probeDir, "rows", s.Probe + ".json")); - var evidence = new JsonObject { ["variants"] = new JsonArray(), ["rows"] = new JsonObject() }; - var result = "pass"; var seconds = 0.0; var reports = new List(); - foreach (var v in variants) - { - seconds += v.Seconds; - var label = v.Variant.Count > 0 ? " [" + string.Join(", ", v.Variant.Select(kv => $"{kv.Key}={Files.Str(kv.Value)}")) + "]" : ""; - ctx.Out.WriteLine($" {s.Probe}{label}: {FirstLine(v.Ran)} ({v.Seconds.ToString("F1", CultureInfo.InvariantCulture)} s)"); - if (v.Ran.ExitCode != 0) { result = "fail"; ctx.Out.WriteLine(string.Join('\n', v.Ran.Stdout.Split('\n').Skip(1).Take(11))); } - // A failed run's full logs, kept under the state's logs/ for triage: in CI the state is the artifact. - if (v.Ran.ExitCode != 0 && Directory.Exists(v.LogDir)) - foreach (var file in Directory.EnumerateFiles(v.LogDir)) - { - var kept = ledger.P(Path.Combine("logs", $"{s.Probe}-{v.Index}-{Path.GetFileName(file)}")); - Directory.CreateDirectory(Path.GetDirectoryName(kept)!); - File.Copy(file, kept, overwrite: true); - ctx.Out.WriteLine($" log: {kept}"); - } - if (v.Coverage.Length > 0) reports.AddRange(Directory.EnumerateFiles(results, v.Coverage, SearchOption.AllDirectories)); - - // Execution evidence: the rows this variant should run, the rows it did, how each ended and the - // settings that applied. A row missing here, or recorded without its settings, earns nothing. - var only = Files.Str(v.Variant["PROBE_ONLY"]); - var expected = new JsonArray(); var executed = new SortedSet(); - for (var i = 0; i < probeRows.Count; i++) - if (Selected(Files.StringMap(probeRows[i]?["row"] ?? probeRows[i]), only)) expected.Add(i); - if (Directory.Exists(v.OutDir)) - foreach (var file in Directory.EnumerateFiles(v.OutDir, "*.jsonl")) - foreach (var line in Files.ReadLines(file)) - { - var idx = (int)Files.Num(line["idx"]); - executed.Add(idx); - (evidence["rows"] as JsonObject)![idx.ToString(CultureInfo.InvariantCulture)] = EvidenceRow(line); - } - (evidence["variants"] as JsonArray)!.Add(new JsonObject - { - ["env"] = v.Variant.DeepClone(), ["expected"] = expected, ["executed"] = new JsonArray([.. executed.Select(x => (JsonNode)x)]), - }); - var missing = expected.Select(x => (int)Files.Num(x)).Where(x => !executed.Contains(x)).ToList(); - if (missing.Count > 0) ctx.Out.WriteLine($" {missing.Count} expected row(s) did not run: [{string.Join(", ", missing.Take(10))}]"); - } - foreach (var stale in ledger.StaleSkips(evidence)) { result = "fail"; ctx.Out.WriteLine($" {stale}"); } - if (result == "fail") failed.Add(s.Probe); - var evidencePath = Path.Combine(results, $"{s.Probe}-evidence.json"); - Files.WriteJson(evidencePath, evidence); - var categories = (evidence["rows"] as JsonObject)!.GroupBy(kv => Files.Str(kv.Value!["category"]), StringComparer.Ordinal) - .OrderBy(g => g.Key, StringComparer.Ordinal).Select(g => $"{g.Key} {g.Count()}"); - // Checks beside rows, once a row of the probe ran any: until then every row is its one check and the line says nothing more. - var checks = (evidence["rows"] as JsonObject)!.Any(kv => kv.Value?["checks"] is JsonArray { Count: > 0 }) - ? "; checks: " + string.Join(", ", Ledger.CheckOutcomes(evidence).Select(kv => $"{kv.Key} {kv.Value}")) : ""; - ctx.Out.WriteLine(" outcomes: " + string.Join(", ", categories) + checks); - var record = new StringWriter(); - Program.Run(new Context(ledger.Top, ctx.Environment, record, ctx.Error), - ["record-run", "--branch", ledger.Branch, "--probe", s.Probe, "--result", result, - "--seconds", seconds.ToString("F1", CultureInfo.InvariantCulture), "--evidence", evidencePath]); - if (record.ToString().Trim() is { Length: > 0 } said) ctx.Out.WriteLine(" " + said); - // The footprint is what ran, pass or fail: a probe failing for an open finding is skipped like any - // other until its footprint changes (a fix touches it). Without one the probe stays stale, which is - // right for a state nobody keeps. - if (!options.Footprint) ctx.Out.WriteLine(" footprint: not recorded (--no-footprint)"); - else if (reports.Count > 0) - { - var fp = new StringWriter(); var fpError = new StringWriter(); - Program.Run(new Context(ledger.Top, ctx.Environment, fp, fpError), - ["footprint", "--branch", ledger.Branch, "--probe", s.Probe, "--root", worktree, "--cobertura", .. reports, - "--include", .. (Files.Strings(config["include"]).ToArray() is { Length: > 0 } inc ? inc : ["src"]), - "--compile-time", .. Files.Strings(config["compileTimeFootprint"])]); - ctx.Out.WriteLine($" footprint: {(fp.ToString() + fpError.ToString()).Trim()}"); - } - else ctx.Error.WriteLine(" footprint: no coverage report found; the probe stays stale"); - } - - Summary(ledger, head, warmth, buildSeconds, todo, skipped, failed, clock.Elapsed.TotalSeconds, axes, options); - ctx.Out.WriteLine($"prober replay: {todo.Count - failed.Count} passed, {failed.Count} failed, {clock.Elapsed.TotalSeconds.ToString("F1", CultureInfo.InvariantCulture)} s in all"); - try { Directory.Delete(results, recursive: true); } catch (IOException) { } - return failed.Count > 0 ? 1 : 0; - } - - /// - /// replay-last.json: what this replay did, and how it was asked to run. selected and skipped - /// together are the probes in its scope (its family, or all), so merge can tell a probe no leg saw. - /// - private static void Summary(Ledger ledger, string head, string? warmth, double buildSeconds, List todo, List skipped, - List failed, double seconds, JsonObject? axes, Options options) - { - static JsonArray Names(IEnumerable names) => new([.. names.Select(x => (JsonNode)x)]); - Files.WriteJson(ledger.P("replay-last.json"), new JsonObject - { - ["branch"] = ledger.Branch, ["commit"] = head, ["build"] = warmth, ["build_seconds"] = Math.Round(buildSeconds, 1), - ["replayed"] = todo.Count, ["failed"] = Names(failed), ["seconds"] = Math.Round(seconds, 1), ["axes"] = axes?.DeepClone(), - ["all"] = options.All, ["family"] = options.Family, ["parallel"] = options.Parallel, ["footprint"] = options.Footprint, - ["selected"] = Names(todo.Select(s => s.Probe)), ["skipped"] = Names(skipped), - }); - } - - /// - /// The cache directory of this checkout's scratch worktrees (wt, seeds, explore, enumerate) under - /// PROBE_CACHE_DIR, else ~/.cache/probe-replay: the checkout's directory name and a hash of its path. A linked worktree - /// has one of its own, so sessions in two checkouts never reset each other's copy; the main checkout is keyed on - /// , as it was before, so its warm copy stays where it is. - /// - internal static string Home(Context ctx, Ledger ledger) - { - var checkout = ledger.Linked ? ledger.Top : ledger.Root; - var key = Convert.ToHexStringLower(SHA1.HashData(Encoding.UTF8.GetBytes(checkout)))[..8]; - return Path.Combine(ctx.Env("PROBE_CACHE_DIR") ?? Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile), ".cache", "probe-replay"), - $"{Path.GetFileName(checkout)}-{key}"); - } - - /// - /// The command that removes this checkout's cache, its worktrees first (for git worktree list) and then the - /// directory, every path literal: removing a linked worktree leaves its cache behind. - /// - internal static string RemoveCommand(string home) - { - // Forward slashes on Windows, which git and the sh of Git for Windows both read. - static string Quoted(string path) => "'" + (Path.DirectorySeparatorChar == '\\' ? path.Replace('\\', '/') : path).Replace("'", "'\\''") + "'"; - var worktrees = new[] { "wt", "seeds", "explore" }.Select(w => Path.Combine(home, w)).Where(w => File.Exists(Path.Combine(w, ".git"))); - return string.Join("; ", worktrees.Select(w => $"git worktree remove --force {Quoted(w)}").Append($"rm -rf {Quoted(home)}")); - } - - /// - /// Holds this checkout's replay worktree for one replay: the lock is per branch, the worktree per checkout, so two - /// branches' replays in one checkout (a branch switched while the post-commit replay runs) would otherwise share it. - /// An OS lock on replay.lock beside it, released by the OS when its process ends; null when another holds it. - /// - internal static FileStream? HoldWorktree(string home) - { - Directory.CreateDirectory(home); - try { return new FileStream(Path.Combine(home, "replay.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); } - catch (IOException) { return null; } - } - - /// - /// Copies the corpus into the worktree's probe directory: tracked, overlaid by the branch's unpublished staging; rows - /// unpacked, one file per probe, and a rows file the corpus no longer has removed; and the claims as claims.json, - /// whose declarations of where an obligation does not apply the harness reads. - /// - internal static string Overlay(Ledger ledger, JsonObject config, string worktree) - { - var probeDir = Path.Combine(worktree, Files.Str(config["probeDir"])); - Directory.CreateDirectory(Path.Combine(probeDir, "rows")); - var wanted = new SortedDictionary(StringComparer.Ordinal); - var rows = new SortedDictionary(StringComparer.Ordinal); - foreach (var source in new[] { ledger.CorpusDir, ledger.StagingDir }) - { - foreach (var sub in new[] { "harness", "probes" }) - if (Directory.Exists(Path.Combine(source, sub))) - foreach (var f in Directory.EnumerateFiles(Path.Combine(source, sub), "*.cs")) wanted[Path.GetFileName(f)] = f; - if (Directory.Exists(Path.Combine(source, "rows"))) - foreach (var f in Directory.EnumerateFiles(Path.Combine(source, "rows")).Where(f => f.EndsWith(".json", StringComparison.Ordinal) || f.EndsWith(".json.gz", StringComparison.Ordinal))) - rows[Path.GetFileName(f).Replace(".gz", "", StringComparison.Ordinal)] = f; - } - foreach (var existing in Directory.EnumerateFiles(probeDir)) if (!wanted.ContainsKey(Path.GetFileName(existing)) && Path.GetFileName(existing) != "claims.json") File.Delete(existing); - foreach (var existing in Directory.EnumerateFiles(Path.Combine(probeDir, "rows"))) if (!rows.ContainsKey(Path.GetFileName(existing))) File.Delete(existing); - foreach (var (name, src) in wanted) - { - var dst = Path.Combine(probeDir, name); - if (!File.Exists(dst) || !File.ReadAllBytes(dst).AsSpan().SequenceEqual(File.ReadAllBytes(src))) File.Copy(src, dst, overwrite: true); - } - foreach (var (name, src) in rows) - { - var data = src.EndsWith(".gz", StringComparison.Ordinal) ? Files.Gunzip(src) : File.ReadAllBytes(src); - var dst = Path.Combine(probeDir, "rows", name); - if (!File.Exists(dst) || !File.ReadAllBytes(dst).AsSpan().SequenceEqual(data)) File.WriteAllBytes(dst, data); - } - // The claims beside the rows, the corpus's with the staging's over them: the harness's Rows.Claim reads each - // obligation's declarations from here, so Row.Check skips a check where its claim declares it inapplicable. - var claims = Path.Combine(probeDir, "claims.json"); - var text = new JsonArray([.. ledger.Claims().Select(c => (JsonNode)c)]).ToJsonString(); - if (!File.Exists(claims) || File.ReadAllText(claims) != text) File.WriteAllText(claims, text); - return probeDir; - } - - /// - /// One row of the harness's jsonl as evidence keeps it: its category, the settings that applied, six reasons, the - /// findings it skipped for, and each check it ran with the same fields (obligation, baseline, category, its own - /// settings, six reasons, notes). A row that ran no check keeps no checks. - /// - internal static JsonObject EvidenceRow(JsonObject line) - { - static JsonArray Six(JsonNode? reasons) => new([.. Files.Strings(reasons).Take(6).Select(x => (JsonNode)x)]); - var row = new JsonObject - { - ["category"] = Files.Str(line["category"], "violation"), ["applied"] = line["applied"]?.DeepClone() ?? new JsonObject(), - ["reasons"] = Six(line["reasons"]), - ["findings"] = new JsonArray([.. Files.Strings(line["findings"]).Select(x => (JsonNode)x)]), - }; - if (line["checks"] is JsonArray checks && checks.Count > 0) - row["checks"] = new JsonArray([.. checks.OfType().Select(c => (JsonNode)new JsonObject - { - ["obligation"] = Files.Str(c["obligation"]), ["baseline"] = c["baseline"] is JsonValue b ? Files.Str(b) : null, - ["category"] = Files.Str(c["category"], "violation"), ["applied"] = c["applied"]?.DeepClone() ?? new JsonObject(), - ["reasons"] = Six(c["reasons"]), ["notes"] = Files.Str(c["notes"]), - })]); - return row; - } - - /// The harness's PROBE_ONLY filter, replicated: the rows a variant is expected to run. - internal static bool Selected(IReadOnlyDictionary row, string only) - { - if (only.Length == 0) return true; - foreach (var condition in only.Split(',')) - { - var neq = condition.IndexOf("!=", StringComparison.Ordinal); - if (neq >= 0) { if (row.TryGetValue(condition[..neq], out var v) && v == condition[(neq + 2)..]) return false; } - else - { - var eq = condition.IndexOf('='); - if (!row.TryGetValue(condition[..eq], out var v) || v != condition[(eq + 1)..]) return false; - } - } - return true; - } - - private static string FirstLine(Ran ran) => ProbeRun.FirstLine(ran); -} diff --git a/tools/Prober/Round.cs b/tools/Prober/Round.cs deleted file mode 100644 index 9bbf4057..00000000 --- a/tools/Prober/Round.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System.Diagnostics; -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// One exploration round (explore or full) under caps the model cannot overrun, run locally only: never in -/// CI, which needs no model. The wall clock is enforced here (the process tree is stopped at the deadline -/// plus a grace), the claim cap and the deadline by `rows`, which refuses new work, and the spend by -/// `--max-budget-usd`. The round always ends cleanly: partial lines repaired, caps cleared, lock released. -/// -internal static class Round -{ - public static int Run(Context ctx, Args a) - { - var mode = a.Positional.FirstOrDefault() ?? throw new Refusal("round takes explore or full", 2); - if (mode is not ("explore" or "full")) throw new Refusal("round takes explore or full", 2); - var minutes = a.Get("minutes") is { Length: > 0 } m ? double.Parse(m, CultureInfo.InvariantCulture) : mode == "explore" ? 10 : 30; - int? claims = a.Get("claims") is { Length: > 0 } c ? int.Parse(c, CultureInfo.InvariantCulture) : mode == "explore" ? 2 : null; - var grace = double.Parse(ctx.Env("PROBE_GRACE") ?? "60", CultureInfo.InvariantCulture); - var ledger = new Ledger(ctx, a.Get("branch")); - var holder = $"round-{mode}-{System.Environment.ProcessId}"; - - if (!RoundLock.Take(ledger, holder, mode, System.Environment.ProcessId).Taken) - { - ctx.Out.WriteLine("prober round: the ledger is locked by another round"); - return 1; - } - var clock = Stopwatch.StartNew(); - string outcome = "completed"; int? exit = null; JsonObject usage = []; var report = ""; - string roundEnded = "", repaired = "", unlocked; - try - { - Program.Run(new Context(ledger.Top, ctx.Environment, TextWriter.Null, ctx.Error), - ["round-start", "--branch", ledger.Branch, "--holder", holder, "--minutes", minutes.ToString(CultureInfo.InvariantCulture), - .. (claims is { } n ? new[] { "--claims", n.ToString(CultureInfo.InvariantCulture) } : [])]); - var caps = $"{minutes.ToString(CultureInfo.InvariantCulture)} minutes" + (claims is { } k ? $" and {k} claim(s)" : ""); - var prompt = - $"Mode: {mode}. Repository {ledger.Top}, branch {ledger.Branch}, base {a.Get("base") ?? "main"}.\n" + - $"This round runs under caps enforced outside you ({caps}). The round runner holds the lock as `{holder}`: do not lock, " + - $"unlock or start a round yourself, and pass `--holder {holder}` to `prober replay`. `prober rows` refuses new work once " + - "the time is spent or the claim cap is reached; when it refuses, start nothing new: record what ran, hand the corpus off " + - "to staging, and report. The process is stopped at the deadline whatever you are doing, so record each claim's results " + - "as soon as its rows have run."; - var argv = new List { "-p", prompt, "--agent", "prober", "--permission-mode", "auto", "--output-format", "json" }; - if (a.Get("usd") is { Length: > 0 } usd) argv.AddRange(["--max-budget-usd", usd]); - var env = new Dictionary(ctx.Environment, StringComparer.Ordinal) { ["PROBE_HOLDER"] = holder }; - - using (new RoundLock.Heartbeat(ledger, holder)) - { - var ran = Proc.Run(FindClaude(ctx), argv, ledger.Top, env, TimeSpan.FromSeconds(minutes * 60 + grace)); - exit = ran.ExitCode; - if (ran.ExitCode == -1) outcome = "stopped at the cap"; - else - { - try - { - if (JsonNode.Parse(ran.Stdout) is JsonObject result) - { - foreach (var key in new[] { "total_cost_usd", "num_turns", "duration_ms", "usage", "subtype" }) usage[key] = result[key]?.DeepClone(); - report = Files.Str(result["result"]); - } - } - catch (JsonException) { report = ran.Stdout.Length > 4000 ? ran.Stdout[^4000..] : ran.Stdout; } - if (ran.ExitCode != 0) outcome = "failed"; - if ((ran.Stdout + ran.Stderr).Contains("Not logged in", StringComparison.Ordinal)) - { - outcome = "not logged in"; - report = "The headless claude CLI is not authenticated. Log it in once (`claude`, then /login, or ANTHROPIC_API_KEY), or start the round from a Claude session with the /probe skill, which caps it with `prober round-start` and stops it at the deadline."; - } - } - } - } - catch (System.ComponentModel.Win32Exception) - { - outcome = "no claude executable"; report = "No claude executable was found; set CLAUDE_BIN. Exploration needs a model and runs locally only."; - } - finally - { - var w = new StringWriter(); - Program.Run(new Context(ledger.Top, ctx.Environment, w, ctx.Error), ["repair", "--branch", ledger.Branch]); repaired = w.ToString().Trim(); - w = new StringWriter(); - Program.Run(new Context(ledger.Top, ctx.Environment, w, ctx.Error), ["round-end", "--branch", ledger.Branch, "--holder", holder]); roundEnded = w.ToString().Trim(); - w = new StringWriter(); - Program.Run(new Context(ledger.Top, ctx.Environment, w, ctx.Error), ["unlock", "--branch", ledger.Branch, "--holder", holder]); unlocked = w.ToString().Trim(); - } - if (unlocked.Contains("replay was skipped", StringComparison.Ordinal)) - Replay.Run(new Context(ledger.Top, ctx.Environment, TextWriter.Null, ctx.Error), new Args(["--branch", ledger.Branch], new HashSet(StringComparer.Ordinal))); - var status = new StringWriter(); - Program.Run(new Context(ledger.Top, ctx.Environment, status, ctx.Error), ["status", "--branch", ledger.Branch]); - var summary = new JsonObject - { - ["mode"] = mode, ["branch"] = ledger.Branch, - ["caps"] = new JsonObject { ["minutes"] = minutes, ["claims"] = claims, ["usd"] = a.Get("usd") }, - ["outcome"] = outcome, ["exit"] = exit, ["seconds"] = Math.Round(clock.Elapsed.TotalSeconds, 1), ["usage"] = usage, - ["round"] = roundEnded, ["repair"] = repaired, ["status"] = status.ToString().Split('\n')[0].Trim(), - }; - var full = (JsonObject)summary.DeepClone(); full["report"] = report; - Files.WriteJson(ledger.P("round-last.json"), full); - ctx.Out.WriteLine(summary.ToJsonString(new JsonSerializerOptions { WriteIndented = true })); - if (report.Length > 0) ctx.Out.WriteLine("\n" + report); - return outcome == "completed" ? 0 : 1; - } - - /// $CLAUDE_BIN, else claude on PATH, else the desktop app's bundled copy. - private static string FindClaude(Context ctx) - { - if (ctx.Env("CLAUDE_BIN") is { } bin) return bin; - foreach (var dir in (ctx.Env("PATH") ?? "").Split(Path.PathSeparator)) - foreach (var name in new[] { "claude", "claude.exe" }) - if (dir.Length > 0 && File.Exists(Path.Combine(dir, name))) return Path.Combine(dir, name); - var bundled = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Claude", "claude-code"); - if (Directory.Exists(bundled)) - { - var found = Directory.EnumerateFiles(bundled, "claude", SearchOption.AllDirectories) - .Where(p => p.Contains("Contents/MacOS", StringComparison.Ordinal)).Order(StringComparer.Ordinal).LastOrDefault(); - if (found is not null) return found; - } - throw new System.ComponentModel.Win32Exception("no claude executable"); - } -} diff --git a/tools/Prober/RoundLock.cs b/tools/Prober/RoundLock.cs deleted file mode 100644 index e3e16831..00000000 --- a/tools/Prober/RoundLock.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// One round at a time per branch. The lock file sits in the branch's directory (branches/<branch>/round.lock), -/// beside everything a round or a replay writes, so two branches' rounds may run at once and two of one branch never do. -/// It is created exclusively, with its holder's owner and a heartbeat inside; a holder is alive while its heartbeat is -/// younger than . Liveness is the heartbeat alone (no process is probed, no signal sent), -/// which is the same on every OS. Every read-judge-write of the lock runs under an exclusive file create (the mutex), so -/// two takers can never both see it free, or both take over a holder whose heartbeat stopped. -/// -internal static class RoundLock -{ - public const int HeartbeatMinutes = 20; - public static readonly TimeSpan BeatEvery = TimeSpan.FromSeconds(30); - private const int MutexStaleSeconds = 60; - - public static string LockPath(Ledger l) => Path.Combine(l.Dir, "round.lock"); - - public static double Now() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() / 1000.0; - - public static bool Alive(JsonObject held) => - Now() - Files.Num(held["heartbeat"], Files.Num(held["since"])) < HeartbeatMinutes * 60; - - public static JsonObject? Holder(Ledger l) => Files.ReadJson(LockPath(l)) is JsonObject held && Alive(held) ? held : null; - - /// - /// The mutex: a file created with , which fails when it exists, atomically - /// on every OS. A crashed writer's mutex goes stale after a minute and is removed. - /// - public static T WithMutex(Ledger l, Func body) - { - Directory.CreateDirectory(l.Dir); - var path = LockPath(l) + ".mutex"; - var deadline = DateTime.UtcNow.AddSeconds(10); - while (true) - { - try - { - using (new FileStream(path, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { } - break; - } - catch (Exception busy) when (busy is IOException or UnauthorizedAccessException) - { - // It exists (or vanished an instant ago, when its holder released it): either way, look again. - // Windows says UnauthorizedAccess, not IOException, for a name whose file is being deleted. - try - { - if (File.Exists(path) && (DateTime.UtcNow - File.GetLastWriteTimeUtc(path)).TotalSeconds > MutexStaleSeconds) File.Delete(path); - } - catch (Exception gone) when (gone is IOException or UnauthorizedAccessException) { } - if (DateTime.UtcNow > deadline) throw new Refusal("the lock's mutex is held for over 10 s; another command is stuck"); - Thread.Sleep(Random.Shared.Next(5, 25)); - } - } - try { return body(); } - finally { try { File.Delete(path); } catch (Exception e) when (e is IOException or UnauthorizedAccessException) { } } - } - - public static void WithMutex(Ledger l, Action body) => WithMutex(l, () => { body(); return 0; }); - - public static (bool Taken, JsonObject? Previous) Take(Ledger l, string holder, string mode, long? pid) - { - var now = Now(); - var record = new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["holder"] = holder, ["mode"] = mode, - ["owner"] = new JsonObject { ["pid"] = pid ?? Environment.ProcessId, ["host"] = Environment.MachineName }, - ["since"] = now, ["heartbeat"] = now, ["pending_replay"] = false, - }; - return WithMutex(l, () => - { - var held = Files.ReadJson(LockPath(l)) as JsonObject; - if (held is not null && Files.Str(held["holder"]) != holder && Alive(held)) return (false, held); - if (held is not null) - { - record["pending_replay"] = held["pending_replay"] is JsonValue p && p.TryGetValue(out var b) && b; - Files.WriteJson(LockPath(l), record); // a holder taking it again, or one whose heartbeat stopped - } - else - { - // No lock: an exclusive create, so even a writer that bypasses the mutex cannot overwrite one. - using var stream = new FileStream(LockPath(l), FileMode.CreateNew, FileAccess.Write, FileShare.None); - using var writer = new StreamWriter(stream); - writer.Write(record.ToJsonString()); - } - return (true, held); - }); - } - - public static void Beat(Ledger l, string holder) => WithMutex(l, () => - { - if (Files.ReadJson(LockPath(l)) is JsonObject held && Files.Str(held["holder"]) == holder) - { - held["heartbeat"] = Now(); - Files.WriteJson(LockPath(l), held); - } - }); - - public static void OweReplay(Ledger l) => WithMutex(l, () => - { - if (Files.ReadJson(LockPath(l)) is JsonObject held) - { - held["pending_replay"] = true; - Files.WriteJson(LockPath(l), held); - } - }); - - /// Releases the lock; returns whether a replay was owed. Refuses another holder's lock. - public static bool Release(Ledger l, string holder) => WithMutex(l, () => - { - var held = Files.ReadJson(LockPath(l)) as JsonObject; - if (held is not null && Files.Str(held["holder"]) != holder) - throw new Refusal($"the lock is {Files.Str(held["holder"])}'s, not {holder}'s"); - if (held is not null) File.Delete(LockPath(l)); - return held?["pending_replay"] is JsonValue p && p.TryGetValue(out var b) && b; - }); - - public static JsonObject? Abandon(Ledger l) => WithMutex(l, () => - { - var held = Files.ReadJson(LockPath(l)) as JsonObject; - if (held is not null) File.Delete(LockPath(l)); - return held; - }); - - /// Keeps a lock alive while a long step runs: a timer beats every 30 s. - public sealed class Heartbeat(Ledger ledger, string holder) : IDisposable - { - private readonly Timer timer = new(_ => { try { Beat(ledger, holder); } catch (Exception) { } }, null, BeatEvery, BeatEvery); - public void Dispose() => timer.Dispose(); - } -} diff --git a/tools/Prober/SchemaCheck.cs b/tools/Prober/SchemaCheck.cs deleted file mode 100644 index 56725a7d..00000000 --- a/tools/Prober/SchemaCheck.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; - -namespace Prober; - -/// -/// The part of JSON Schema the tracked files' schemas use, checked where a file is read, so a field nobody -/// reads is refused instead of kept (decision 102: three invented fields for an exclusion's reason sat in -/// claims.json unread). A keyword outside this part throws: a schema that says more than is checked would be -/// a check that silently does less than it reads. -/// -internal static class SchemaCheck -{ - private static readonly HashSet Annotations = ["$schema", "$id", "title", "description"]; - - /// The schema of Schemas/{name}, embedded in the dll, so it is the one the dll's fingerprint covers. - public static JsonObject Load(string name) - { - using var stream = typeof(SchemaCheck).Assembly.GetManifestResourceStream(name) - ?? throw new InvalidOperationException($"no embedded schema {name}"); - return JsonNode.Parse(stream) as JsonObject ?? throw new InvalidOperationException($"the schema {name} is not a JSON object"); - } - - /// What in the schema refuses, each at its path (exclude[0].reason). - public static List Problems(JsonNode? node, JsonObject schema, string path = "") - { - var problems = new List(); - Check(node, schema, path, problems); - return problems; - } - - private static void Check(JsonNode? node, JsonObject schema, string path, List problems) - { - var at = path.Length == 0 ? "the value" : path; - foreach (var (keyword, _) in schema) - if (!Annotations.Contains(keyword) && keyword is not ("type" or "const" or "required" or "properties" or "additionalProperties" - or "items" or "minItems" or "maxItems" or "minLength" or "pattern")) - throw new InvalidOperationException($"a schema uses {keyword}, which SchemaCheck does not check"); - - if (schema["type"] is JsonValue type && !IsType(node, Files.Str(type))) - { - problems.Add($"{at} is not {Article(Files.Str(type))}"); - return; - } - if (schema["const"] is { } constant && !JsonNode.DeepEquals(node, constant)) problems.Add($"{at} is not {constant.ToJsonString()}"); - - if (node is JsonObject o) - { - foreach (var name in Files.Strings(schema["required"])) - if (!o.ContainsKey(name)) problems.Add($"{Join(path, name)} is required"); - var properties = schema["properties"] as JsonObject ?? []; - foreach (var (name, value) in o) - { - if (properties[name] is JsonObject property) Check(value, property, Join(path, name), problems); - else if (schema["additionalProperties"] is JsonObject rest) Check(value, rest, Join(path, name), problems); - else if (schema["additionalProperties"] is JsonValue allowed && allowed.TryGetValue(out var b) && !b) - problems.Add($"{Join(path, name)} is not a field the schema has"); - } - } - if (node is JsonArray a) - { - if (schema["minItems"] is { } min && a.Count < Files.Num(min)) problems.Add($"{at} has {a.Count} item(s), fewer than {Files.Num(min)}"); - if (schema["maxItems"] is { } max && a.Count > Files.Num(max)) problems.Add($"{at} has {a.Count} item(s), more than {Files.Num(max)}"); - if (schema["items"] is JsonObject items) - for (var i = 0; i < a.Count; i++) Check(a[i], items, $"{path}[{i}]", problems); - } - if (node is JsonValue v && v.TryGetValue(out var s)) - { - if (schema["minLength"] is { } length && s.Length < Files.Num(length)) problems.Add($"{at} is shorter than {Files.Num(length)}"); - if (schema["pattern"] is JsonValue pattern && !Regex.IsMatch(s, Files.Str(pattern), RegexOptions.CultureInvariant)) - problems.Add($"{at} does not match {Files.Str(pattern)}"); - } - } - - private static string Join(string path, string name) => path.Length == 0 ? name : $"{path}.{name}"; - - private static string Article(string type) => type is "object" or "array" or "integer" ? $"an {type}" : $"a {type}"; - - private static bool IsType(JsonNode? node, string type) => type switch - { - "object" => node is JsonObject, - "array" => node is JsonArray, - "string" => node is JsonValue v && v.TryGetValue(out _), - "integer" => node is JsonValue v && v.TryGetValue(out _), - "boolean" => node is JsonValue v && v.TryGetValue(out _), - _ => throw new InvalidOperationException($"a schema names type {type}, which SchemaCheck does not check"), - }; -} diff --git a/tools/Prober/Schemas/claims.schema.json b/tools/Prober/Schemas/claims.schema.json deleted file mode 100644 index 3c944f19..00000000 --- a/tools/Prober/Schemas/claims.schema.json +++ /dev/null @@ -1,189 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/claims.schema.json", - "title": "Claims", - "description": "Tracked (corpus/claims.json): the claims the documents make, each naming the surfaces whose axes it takes. The prober refuses a file that does not match this schema when it reads one (decision 102).", - "type": "array", - "items": { - "type": "object", - "required": [ - "id", - "source", - "surfaces" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "id": { - "type": "string", - "minLength": 1 - }, - "source": { - "type": "string", - "description": "file#heading of the document that states it" - }, - "surfaces": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1 - }, - "axes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - }, - "description": "claim-local axes" - }, - "narrow": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "axis dropped, with the source sentence that limits it (checked verbatim)" - }, - "obligations": { - "type": "array", - "minItems": 1, - "description": "what the claim promises, each checkable on its own: a sentence quoted verbatim from the claim's source document (checked as a narrowing is), under an id a probe's seed names (decision 104); a claim without the field has one obligation, the claim itself, under the id `claim`", - "items": { - "type": "object", - "required": [ - "id", - "sentence" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^[a-z0-9][a-z0-9-]*$" - }, - "sentence": { - "type": "string", - "pattern": "\\S" - }, - "axes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - }, - "description": "the axis values the obligation concerns, where it is not the whole claim" - }, - "inapplicable": { - "type": "array", - "minItems": 1, - "description": "where the obligation does not apply: a row holding every axis of a declaration at one of its values runs no check of the obligation (Row.Check records it inapplicable with the cite), a pair matched by a declaration is not wanted by the obligation, and a pair no obligation wants is declared inapplicable, never put in a generated row and left out of the gate's count as an exclusion is. `Axes.Build` refuses an axis or value the claim does not list, a malformed cite, and a not-promised id the claim lacks", - "items": { - "type": "object", - "required": [ - "axes", - "cite" - ], - "properties": { - "axes": { - "type": "object", - "additionalProperties": { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - }, - "description": "axis to the values where the obligation does not apply; every axis must hold at one of its values" - }, - "cite": { - "type": "string", - "pattern": "^(not-promised|docs|fact|record):", - "description": "why: not-promised:, docs:, fact:KB-NNN or record:NNNN, in the forms the harness's Cite accepts" - } - }, - "additionalProperties": false - } - } - }, - "additionalProperties": false - } - }, - "not-promised": { - "type": "array", - "minItems": 1, - "description": "what the claim does not promise, one entry per intended difference: the sentence of the document or record that makes it intended, quoted verbatim from `source` (checked as a narrowing is), and the axis values it concerns; a note key of outcome expected-refusal, a narrowing or an applicability condition cites an entry by its id (decision 104)", - "items": { - "type": "object", - "required": [ - "id", - "source", - "sentence" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^[a-z0-9][a-z0-9-]*$" - }, - "source": { - "type": "string", - "description": "file#heading of the document or record that states it" - }, - "sentence": { - "type": "string", - "pattern": "\\S" - }, - "axes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - }, - "description": "the axis values or shapes the difference concerns" - } - }, - "additionalProperties": false - } - }, - "exclude": { - "type": "array", - "description": "pairs no row can hold, each group with the reason why; `prober universe` prints the reasons, since nothing checks them mechanically", - "items": { - "type": "object", - "required": [ - "reason", - "pairs" - ], - "properties": { - "reason": { - "type": "string", - "pattern": "\\S", - "description": "one sentence saying why the pairs cannot exist or are not promised, citing a docs sentence, a record or a KB fact where one applies" - }, - "pairs": { - "type": "array", - "minItems": 1, - "items": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[^=]+=.*$" - }, - "minItems": 2, - "maxItems": 2 - } - } - }, - "additionalProperties": false - } - } - }, - "additionalProperties": false - } -} diff --git a/tools/Prober/Schemas/dismissed-line.schema.json b/tools/Prober/Schemas/dismissed-line.schema.json deleted file mode 100644 index 1556681b..00000000 --- a/tools/Prober/Schemas/dismissed-line.schema.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/dismissed-line.schema.json", - "title": "Dismissed finding (one line)", - "description": "Tracked (corpus/dismissed.jsonl): a finding the maintainers dismissed.", - "type": "object", - "required": [ - "id", - "reason" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "id": { - "type": "string" - }, - "reason": { - "type": "string" - }, - "date": { - "type": "string" - } - } -} diff --git a/tools/Prober/Schemas/evidence.schema.json b/tools/Prober/Schemas/evidence.schema.json deleted file mode 100644 index 7d86b9db..00000000 --- a/tools/Prober/Schemas/evidence.schema.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/evidence.schema.json", - "title": "Evidence", - "description": "State (branches//evidence/.json): what one replay of a probe did. Only checks that ended as a pass, in rows expected and executed, earn credit, for the settings that applied (the row's, the check's laid over them), while the identity holds. A row without checks is one check of the obligation `claim` with the row's category.", - "type": "object", - "required": [ - "identity", - "variants", - "rows" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "enum": [ - 1, - 2 - ], - "description": "The schema version: 2 records each row's checks. A file without it is version 1, whose rows have no checks." - }, - "probe": { - "type": "string" - }, - "identity": { - "type": "string" - }, - "commit": { - "type": "string" - }, - "result": { - "enum": [ - "pass", - "fail" - ] - }, - "date": { - "type": "string" - }, - "variants": { - "type": "array", - "items": { - "type": "object", - "required": [ - "expected", - "executed" - ], - "properties": { - "env": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally." - }, - "expected": { - "type": "array", - "items": { - "type": "integer" - } - }, - "executed": { - "type": "array", - "items": { - "type": "integer" - } - } - } - } - }, - "rows": { - "type": "object", - "additionalProperties": { - "type": "object", - "required": [ - "category", - "applied" - ], - "properties": { - "category": { - "enum": [ - "pass", - "violation", - "expected-refusal", - "inapplicable", - "harness-error", - "inconclusive", - "known-finding" - ], - "description": "The highest of the row's own outcome and its checks'." - }, - "applied": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally: the axes the row read outside any check, which every check of it ran under." - }, - "reasons": { - "type": "array", - "items": { - "type": "string" - } - }, - "findings": { - "type": "array", - "items": { - "type": "string" - }, - "description": "The open findings the row stepped around (Row.Skip in the harness); the row ends as known-finding." - }, - "checks": { - "type": "array", - "description": "Version 2: one entry per check the row ran (Row.Check in the harness), in the order they ended. Absent for a row that ran none.", - "items": { - "type": "object", - "required": [ - "obligation", - "category", - "applied" - ], - "properties": { - "obligation": { - "type": "string", - "description": "An id of the claim's obligations, or `claim` for a claim without them." - }, - "baseline": { - "type": [ - "string", - "null" - ], - "description": "What the check compared against: twin, framework, round-trip, model, refusal, cost, fact:KB-NNN or docs:file#anchor. A pass always has one." - }, - "category": { - "enum": [ - "pass", - "violation", - "expected-refusal", - "inapplicable", - "harness-error", - "inconclusive", - "known-finding" - ] - }, - "applied": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "The axes this check read, at the value that applied, and none another check read." - }, - "reasons": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Six at most, as the row's." - }, - "notes": { - "type": "string", - "description": "How the check was compared, and the citations of what did not apply or was refused, separated by ;." - } - }, - "additionalProperties": false - } - } - } - } - } - } -} diff --git a/tools/Prober/Schemas/finding-line.schema.json b/tools/Prober/Schemas/finding-line.schema.json deleted file mode 100644 index 317c24f6..00000000 --- a/tools/Prober/Schemas/finding-line.schema.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/finding-line.schema.json", - "title": "Finding event (one line)", - "description": "State (findings.jsonl): open, fixed or withdrawn. The last line per id wins; a fixed line counts once its commit is in HEAD's history.", - "type": "object", - "required": [ - "id", - "status" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "id": { - "type": "string" - }, - "claim": { - "type": [ - "string", - "null" - ] - }, - "status": { - "enum": [ - "open", - "fixed", - "withdrawn", - "dismissed" - ] - }, - "commit": { - "type": "string" - }, - "probe": { - "type": "string" - }, - "reason": { - "type": "string" - } - } -} diff --git a/tools/Prober/Schemas/footprint-line.schema.json b/tools/Prober/Schemas/footprint-line.schema.json deleted file mode 100644 index f5e41f2e..00000000 --- a/tools/Prober/Schemas/footprint-line.schema.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/footprint-line.schema.json", - "title": "Footprint (one line)", - "description": "State (footprints.jsonl): the source files a run of a probe executed, the compile-time paths and the toolchain, each with its id. The last line per probe wins.", - "type": "object", - "required": [ - "probe", - "footprint" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "probe": { - "type": "string" - }, - "commit": { - "type": "string" - }, - "footprint": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally." - }, - "compileTime": { - "type": "object", - "additionalProperties": { - "type": [ - "string", - "null" - ] - } - }, - "watched": { - "type": "object", - "additionalProperties": { - "type": [ - "string", - "null" - ] - }, - "description": "The paths the probe's registry entry watches, each with its object id at the commit the run built (null where it does not exist). A footprint line without one of the entry's watched paths is not current." - }, - "toolchain": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally." - }, - "date": { - "type": "string" - } - } -} diff --git a/tools/Prober/Schemas/ledger-line.schema.json b/tools/Prober/Schemas/ledger-line.schema.json deleted file mode 100644 index 188d2a8f..00000000 --- a/tools/Prober/Schemas/ledger-line.schema.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/ledger-line.schema.json", - "title": "Ledger line (legacy, one line)", - "description": "State (ledger.jsonl): what a round recorded per pair. Informational: it earns no credit; only evidence does.", - "type": "object", - "required": [ - "claim", - "pair", - "commit", - "result" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "claim": { - "type": "string" - }, - "pair": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[^=]+=.*$" - }, - "minItems": 2, - "maxItems": 2 - }, - "commit": { - "type": "string" - }, - "result": { - "type": "string" - }, - "probe": { - "type": "string" - }, - "date": { - "type": "string" - } - } -} diff --git a/tools/Prober/Schemas/lock.schema.json b/tools/Prober/Schemas/lock.schema.json deleted file mode 100644 index 5e9e290d..00000000 --- a/tools/Prober/Schemas/lock.schema.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/lock.schema.json", - "title": "Round lock", - "description": "State (branches//round.lock): one round at a time per branch. Created exclusively; alive while its heartbeat is recent.", - "type": "object", - "required": [ - "holder", - "mode", - "since", - "heartbeat" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "holder": { - "type": "string" - }, - "mode": { - "enum": [ - "replay", - "explore", - "full" - ] - }, - "owner": { - "type": "object", - "properties": { - "pid": { - "type": [ - "integer", - "null" - ] - }, - "host": { - "type": "string" - } - } - }, - "since": { - "type": "number" - }, - "heartbeat": { - "type": "number" - }, - "pending_replay": { - "type": "boolean" - } - } -} diff --git a/tools/Prober/Schemas/registry.schema.json b/tools/Prober/Schemas/registry.schema.json deleted file mode 100644 index 3be5eb0a..00000000 --- a/tools/Prober/Schemas/registry.schema.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/registry.schema.json", - "title": "Probe registry", - "description": "Tracked (corpus/registry.json): every probe, the claim it covers, how to select it, and the process variants it runs in.", - "type": "object", - "required": [ - "probes" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "probes": { - "type": "object", - "additionalProperties": { - "type": "object", - "required": [ - "claim", - "filter" - ], - "properties": { - "claim": { - "type": "string" - }, - "filter": { - "type": "string" - }, - "variants": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally." - }, - "description": "one process per environment map" - }, - "retired": { - "type": "boolean" - }, - "watched": { - "type": "array", - "items": { - "type": "string", - "minLength": 1 - }, - "description": "Paths, files or directories relative to the repository root, that the probe's result depends on and its footprint cannot see: a variant catalogue under test/ compiled into the probes, a build input a child process reads. The replay records each with its object id in the probe's footprint line; a change to one stales the footprint (Ledger.FootprintCurrent, FootprintChangedSince), and the release gate counts a change to one as touching the probe's claim. Part of the probe's identity, as the whole entry but its seeds is." - }, - "seeds": { - "type": "array", - "description": "One seeded defect per obligation of the probe's claim that this probe checks (decision 104): each as `seed` below, naming the obligation it breaks. A probe may carry `seed` and `seeds` both. Empty in the entry `prober new` stages, until the writer registers each with `prober register --obligation O`, which replaces a seed naming O; `seeds` and Seeds.Problems refuse a probe with none. Not part of the probe's identity.", - "items": { - "type": "object", - "required": [ - "obligation", - "defect" - ], - "anyOf": [ - { - "required": [ - "patch" - ] - }, - { - "required": [ - "env" - ] - } - ], - "properties": { - "obligation": { - "type": "string", - "description": "The id of the claim's obligation this seed breaks (claims.json `obligations[].id`, or `claim` for a claim without the field)." - }, - "patch": { - "type": "string" - }, - "env": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "defect": { - "type": "string", - "minLength": 1 - } - }, - "additionalProperties": false - } - }, - "seed": { - "type": "object", - "required": [ - "defect" - ], - "anyOf": [ - { - "required": [ - "patch" - ] - }, - { - "required": [ - "env" - ] - } - ], - "properties": { - "patch": { - "type": "string", - "description": "A unified diff against the product files (the replay's \"include\"), relative to the corpus directory: seeds/.patch." - }, - "env": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Environment variables set for the seeded build and every variant's run." - }, - "defect": { - "type": "string", - "minLength": 1, - "description": "What the seed breaks, in one sentence." - }, - "obligation": { - "type": "string", - "description": "The id of the claim's obligation this seed breaks (decision 104); absent, the seed proves the probe and counts for the claim's one implicit obligation only where the claim lists none." - } - }, - "additionalProperties": false, - "description": "The product defect `prober seeds` applies in a scratch worktree to prove the probe can fail (decision 100). Not part of the probe's identity." - } - }, - "additionalProperties": false - } - } - } -} diff --git a/tools/Prober/Schemas/round.schema.json b/tools/Prober/Schemas/round.schema.json deleted file mode 100644 index dda984fe..00000000 --- a/tools/Prober/Schemas/round.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/round.schema.json", - "title": "Round caps", - "description": "State (branches//round.json): the caps `rows` enforces for the round that holds the lock.", - "type": "object", - "required": [ - "holder", - "deadline", - "claims" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "holder": { - "type": "string" - }, - "started": { - "type": "number" - }, - "deadline": { - "type": "number" - }, - "max_claims": { - "type": [ - "integer", - "null" - ] - }, - "claims": { - "type": "array", - "items": { - "type": "string" - } - } - } -} diff --git a/tools/Prober/Schemas/rows.schema.json b/tools/Prober/Schemas/rows.schema.json deleted file mode 100644 index 290f9a7b..00000000 --- a/tools/Prober/Schemas/rows.schema.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/rows.schema.json", - "title": "Rows", - "description": "Tracked (corpus/rows/.json.gz, gzipped; rows/.json in the staging): the rows one probe runs, a pairwise covering array over its claim's axes. One file per registered probe, written whole by `prober rows --probe P`, never appended; no two rows of a file have the same axis map (ProbeRowsTests).", - "type": "object", - "required": [ - "claim", - "rows" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "claim": { - "type": "string", - "description": "The id of the probe's claim in claims.json; the file is named for the probe, so the claim is kept inside." - }, - "rows": { - "type": "array", - "items": { - "type": "object", - "required": [ - "row" - ], - "properties": { - "row": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally." - }, - "pairs": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[^=]+=.*$" - }, - "minItems": 2, - "maxItems": 2 - } - } - } - } - } - } -} diff --git a/tools/Prober/Schemas/run-line.schema.json b/tools/Prober/Schemas/run-line.schema.json deleted file mode 100644 index 5aca7f82..00000000 --- a/tools/Prober/Schemas/run-line.schema.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/run-line.schema.json", - "title": "Run (one line)", - "description": "State (runs.jsonl): one replay result of one probe, with the identity it ran under.", - "type": "object", - "required": [ - "probe", - "result", - "commit" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "probe": { - "type": "string" - }, - "result": { - "enum": [ - "pass", - "fail" - ] - }, - "commit": { - "type": "string" - }, - "date": { - "type": "string" - }, - "seconds": { - "type": [ - "number", - "null" - ] - }, - "identity": { - "type": "string" - } - } -} diff --git a/tools/Prober/Schemas/seeds-run.schema.json b/tools/Prober/Schemas/seeds-run.schema.json deleted file mode 100644 index 824b9919..00000000 --- a/tools/Prober/Schemas/seeds-run.schema.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/seeds-run.schema.json", - "title": "Seeds run", - "description": "State (seeds-last.json): the last `prober seeds` run on the branch, one outcome per seed it ran (a probe without one has a single outcome, `no seed`), the probes it skipped and why, and per probe the run that last caught every one of its seeds, which decides what the next run without --all skips (design/adr/0107). Never evidence: a seeded run proves the probe, not the product.", - "type": "object", - "required": [ - "branch", - "commit", - "seeds" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "branch": { - "type": "string" - }, - "commit": { - "type": "string" - }, - "seconds": { - "type": "number" - }, - "all": { - "type": "boolean", - "description": "Whether the run was `--all`, every probe whatever its record says, as a release runs it. Absent in a file written before footprint selection." - }, - "probes": { - "type": "object", - "description": "Per probe, the run that last caught every seed it owes; a probe with a seed missed, or that never ran, has no entry, so it runs next time. Carried forward for the probes a run skipped.", - "additionalProperties": { - "type": "object", - "required": [ - "identity", - "commit" - ], - "properties": { - "identity": { - "type": "string", - "description": "The seeds identity it was caught under: the probe's identity, its seeds and the content of their patches." - }, - "commit": { - "type": "string", - "description": "HEAD of the run that caught them; the product footprint and the patched files are compared with it." - }, - "seeds": { - "type": "integer", - "description": "How many seeds were caught." - } - }, - "additionalProperties": false - } - }, - "skipped": { - "type": "array", - "description": "The probes this run skipped, unchanged since every seed of theirs was caught, each with the reason printed.", - "items": { - "type": "object", - "required": [ - "probe", - "reason" - ], - "properties": { - "probe": { - "type": "string" - }, - "reason": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "seeds": { - "type": "array", - "items": { - "type": "object", - "required": [ - "probe", - "claim", - "result" - ], - "properties": { - "probe": { - "type": "string" - }, - "claim": { - "type": "string" - }, - "obligation": { - "type": [ - "string", - "null" - ], - "description": "The claim's obligation the seed breaks (decision 104), or null for a seed that names none." - }, - "seed": { - "type": "string", - "description": "The patch and the environment toggle applied, or (none)." - }, - "result": { - "enum": [ - "caught", - "missed", - "no seed", - "does not apply", - "build failed" - ] - }, - "violations": { - "type": "integer", - "description": "Rows the seed made violations that the unseeded probe does not have." - }, - "rows": { - "type": "integer", - "description": "Rows that ran under the seed." - }, - "detail": { - "type": "string" - } - }, - "additionalProperties": false - }, - "description": "One outcome per seed this run ran; the probes it skipped have none." - } - }, - "additionalProperties": false -} diff --git a/tools/Prober/Schemas/universe.schema.json b/tools/Prober/Schemas/universe.schema.json deleted file mode 100644 index 776635f3..00000000 --- a/tools/Prober/Schemas/universe.schema.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/universe.schema.json", - "title": "Universe", - "description": "State (branches//universe.json): each claim's axes and values, derived from the claims, the axes file and the generated axes.", - "type": "object", - "required": [ - "claims" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "base": { - "type": "string" - }, - "commit": { - "type": "string" - }, - "generated_versions": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Axis name to value, both compared ordinally." - }, - "claims": { - "type": "array", - "items": { - "type": "object", - "required": [ - "id", - "axes" - ], - "properties": { - "id": { - "type": "string" - }, - "source": { - "type": "string" - }, - "surfaces": { - "type": "array", - "items": { - "type": "string" - } - }, - "watched": { - "type": "array", - "items": { - "type": "string" - } - }, - "axes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "exclude": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[^=]+=.*$" - }, - "minItems": 2, - "maxItems": 2 - } - }, - "obligations": { - "type": "array", - "description": "written only where an obligation of the claim declares where it does not apply: every obligation's id with its declarations, as claims.json holds them, so the covering generator, status and the gate know the pairs each wants", - "items": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string" - }, - "inapplicable": { - "type": "array", - "items": { - "type": "object", - "required": [ - "axes", - "cite" - ], - "properties": { - "axes": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "cite": { - "type": "string" - } - } - } - } - } - } - } - } - } - } - } -} diff --git a/tools/Prober/Schemas/waivers.schema.json b/tools/Prober/Schemas/waivers.schema.json deleted file mode 100644 index 1b0d99c1..00000000 --- a/tools/Prober/Schemas/waivers.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://codometis.typekit/probe/schemas/waivers.schema.json", - "title": "Waivers", - "description": "Tracked (corpus/waivers.json): a claim's gate obligation met without a probe. Counts only with a reason and a reviewer.", - "type": "array", - "items": { - "type": "object", - "required": [ - "claim", - "reason", - "reviewed_by" - ], - "properties": { - "schemaVersion": { - "type": "integer", - "const": 1, - "description": "The schema version. A file or line without it is version 1 (the Python baseline)." - }, - "claim": { - "type": "string" - }, - "reason": { - "type": "string", - "minLength": 1 - }, - "reviewed_by": { - "type": "string", - "minLength": 1 - }, - "date": { - "type": "string" - } - } - } -} diff --git a/tools/Prober/Seeds.cs b/tools/Prober/Seeds.cs deleted file mode 100644 index 92e5fe86..00000000 --- a/tools/Prober/Seeds.cs +++ /dev/null @@ -1,396 +0,0 @@ -using System.Diagnostics; -using System.Globalization; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// Proves that each probe can fail (decision 100). A probe's registry entry names a seeded product defect: -/// a patch against the product files (the replay's include, src here), an environment toggle, -/// or both, and a sentence saying what it breaks. This applies each seed in a scratch worktree of its own, -/// builds, replays that probe there, and counts the seed caught only where a check ends as a violation that the -/// unseeded probe does not have in the same row for the same obligation and that no harness error raised, and, for a -/// seed naming an obligation, only a check naming that obligation (a row without checks is one check, claim). -/// Nothing it runs is recorded as evidence: a seeded run proves the probe, -/// not the product. Never in the checkout and never in the replay's worktree; one build per seed, so it runs -/// locally, not in CI. A missed seed, a probe without one, a seed that no longer applies and a seeded build -/// that fails all fail the command. Without --all it runs only the probes whose seeds identity or product -/// footprint changed since the run that last caught every seed of the probe (design/adr/0107), and says why it skips -/// each of the others; the release runs --all. -/// -internal static class Seeds -{ - /// How one seed ended; is the claim's obligation it breaks, or null for a seed that proves the probe alone. - internal sealed record Outcome(string Probe, string Claim, string? Obligation, string Seed, string Result, int Violations, int Rows, string Detail); - - /// - /// Every seed of a registry entry, each with the obligation it names: the one `seed` (its `obligation`, if - /// any) and each of `seeds` (decision 104). An entry without either has none. - /// - internal static List<(string? Obligation, JsonObject Seed)> SeedsOf(JsonObject entry) - { - var result = new List<(string?, JsonObject)>(); - if (entry["seed"] is JsonObject one) result.Add((Files.Str(one["obligation"]) is { Length: > 0 } o ? o : null, one)); - foreach (var seed in (entry["seeds"] as JsonArray ?? []).OfType()) - result.Add((Files.Str(seed["obligation"]) is { Length: > 0 } o ? o : null, seed)); - return result; - } - - private static string Named(string probe, string? obligation) => obligation is null ? probe : $"{probe}/{obligation}"; - - public static int Run(Context ctx, Args a, IProbeAdapter? adapter = null) - { - var ledger = new Ledger(ctx, a.Get("branch")); - var config = ledger.AxesBlock()["replay"] as JsonObject ?? throw new Refusal("the axes file's block has no \"replay\" configuration"); - adapter ??= new DotNetAdapter(config); - var registry = ledger.Registry(); - var states = ledger.ProbeStates(includeRetired: false).Where(s => !s.Retired).ToList(); - if (a.Get("probe") is { } only) - { - states = [.. states.Where(s => s.Probe == only)]; - if (states.Count == 0) throw new Refusal($"no registered probe {only} that is not retired", 2); - } - var head = ledger.Head; - var home = Replay.Home(ctx, ledger); - var worktree = Path.Combine(home, "seeds"); - var include = Files.Strings(config["include"]).ToArray() is { Length: > 0 } inc ? inc : ["src"]; - // The probes whose every seed the last runs caught, each at the commit and the identity it was caught at; a probe - // named by --probe, and every probe under --all, runs whatever its record says. - var last = Files.ReadJson(ledger.P(LastFile)) as JsonObject; - var record = (last?["probes"] as JsonObject ?? []).Where(kv => kv.Value is JsonObject).ToDictionary(kv => kv.Key, kv => (JsonObject)kv.Value!.DeepClone(), StringComparer.Ordinal); - var identities = states.ToDictionary(s => s.Probe, s => SeedsIdentity(ledger, s.Probe), StringComparer.Ordinal); - var skipped = new List<(string Probe, string Why)>(); - if (!a.Flag("all") && a.Get("probe") is null) - { - var footprints = ledger.Footprints(); - var runs = new List(); - foreach (var s in states) - { - var why = Stale(ledger, s.Probe, registry[s.Probe], record.GetValueOrDefault(s.Probe), identities[s.Probe], footprints); - if (why.Run) runs.Add(s); - else skipped.Add((s.Probe, why.Reason)); - ctx.Out.WriteLine($" {(why.Run ? "runs" : "skips")} {s.Probe}: {why.Reason}"); - } - states = runs; - } - var seedsOf = states.ToDictionary(s => s.Probe, s => SeedsOf(registry[s.Probe]), StringComparer.Ordinal); - // A probe without a seed owes one per obligation its claim lists (decision 104), each an outcome of its own; - // under a claim without obligations, one. - var listed = ledger.Claims().ToDictionary(c => Files.Str(c["id"]), Claim.ObligationIds, StringComparer.Ordinal); - List<(string? Obligation, JsonNode? Seed)> Owed(Ledger.ProbeState s) => - seedsOf[s.Probe].Count > 0 ? [.. seedsOf[s.Probe].Select(x => (x.Obligation, (JsonNode?)x.Seed))] - : listed.GetValueOrDefault(s.Claim) is { } ids && ids is not [Claim.ImplicitObligation] ? [.. ids.Select(id => ((string?)id, (JsonNode?)null))] - : [(null, null)]; - ctx.Out.WriteLine($"prober seeds: {ledger.Branch} at {head[..7]}: {seedsOf.Values.Sum(x => x.Count)} seeds of {states.Count} probes, in {worktree}" + - (skipped.Count > 0 ? $"; {skipped.Count} probes skipped, unchanged since every seed of theirs was caught (--all runs them)" : "")); - if (a.Flag("dry-run")) - { - foreach (var s in states) - { - foreach (var (obligation, seed) in Owed(s)) ctx.Out.WriteLine($" {Named(s.Probe, obligation)}: {Describe(seed)}"); - } - return 0; - } - - var clock = Stopwatch.StartNew(); - var outcomes = new List(); - // Nothing to run: no worktree and no build, only the record carried forward. - if (states.Count > 0) - { - Directory.CreateDirectory(home); - if (!Directory.Exists(worktree)) - { - var added = Git.Run(ledger.Root, "worktree", "add", "--detach", worktree, head); - if (added.ExitCode != 0) throw new Refusal("could not add the scratch worktree: " + added.Stderr.Trim()); - } - var environment = ProbeRun.Environment(ctx, adapter, home); - var results = Directory.CreateTempSubdirectory("prober-seeds-").FullName; - try - { - // The baseline: the checks each probe already fails without a seed, by row and obligation. From the ledger - // where its evidence is current, else from an unseeded run here, so a seed is credited only with violations - // of its own. - var baseline = new Dictionary>(StringComparer.Ordinal); - var unseeded = new List(); - foreach (var s in states) - { - if (!s.Stale && Files.ReadJson(ledger.EvidencePath(s.Probe)) is JsonObject evidence) - baseline[s.Probe] = [.. (evidence["rows"] as JsonObject ?? []).Where(kv => kv.Value is JsonObject) - .SelectMany(kv => Ledger.ChecksOf((JsonObject)kv.Value!).Where(c => c.Category == "violation") - .Select(c => (int.Parse(kv.Key, CultureInfo.InvariantCulture), c.Obligation)))]; - else unseeded.Add(s); - } - ctx.Out.WriteLine($" baseline: {states.Count - unseeded.Count} from the ledger, {unseeded.Count} to run unseeded"); - if (unseeded.Count > 0) - { - Reset(worktree, head); - Replay.Overlay(ledger, config, worktree); - var build = Timed(() => adapter.Build(worktree, environment), out var seconds); - ctx.Out.WriteLine($" unseeded build: {Seconds(seconds)}, {FirstLine(build)}"); - if (build.ExitCode != 0) { ctx.Out.WriteLine(build.Stdout); throw new Refusal("the unseeded build failed; no seed can be judged"); } - foreach (var s in unseeded) - { - var rows = RunProbe(adapter, worktree, s, environment, null, results, "base"); - baseline[s.Probe] = Violating(rows); - ctx.Out.WriteLine($" {s.Probe}: {rows.Count} rows, {baseline[s.Probe].Select(x => x.Row).Distinct().Count()} violations unseeded"); - } - } - - foreach (var s in states) - { - // A seed missing is an outcome "no seed"; a probe with several runs each under its obligation. - foreach (var (obligation, seed) in Owed(s)) - { - var outcome = One(ledger, config, adapter, worktree, head, include, environment, results, s, obligation, seed, baseline[s.Probe]); - outcomes.Add(outcome); - ctx.Out.WriteLine($" {Named(s.Probe, obligation)} ({s.Claim}): {outcome.Result}{(outcome.Detail.Length > 0 ? ", " + outcome.Detail : "")}"); - } - } - } - finally - { - // The worktree is left at HEAD, every seed undone, for the next run to build incrementally. - Reset(worktree, head); - try { Directory.Delete(results, recursive: true); } catch (IOException) { } - } - } - - // A probe is recorded only where every seed it owes was caught, so a missed one runs again next time, whatever changed. - foreach (var s in states) - { - var own = outcomes.Where(o => o.Probe == s.Probe).ToList(); - if (own.Count > 0 && own.All(o => o.Result == "caught")) - record[s.Probe] = new JsonObject { ["identity"] = identities[s.Probe], ["commit"] = head, ["seeds"] = own.Count }; - else record.Remove(s.Probe); - } - foreach (var gone in record.Keys.Where(probe => !registry.ContainsKey(probe)).ToList()) record.Remove(gone); - - Files.WriteJson(ledger.P(LastFile), new JsonObject - { - ["schemaVersion"] = Files.SchemaVersion, ["branch"] = ledger.Branch, ["commit"] = head, - ["seconds"] = Math.Round(clock.Elapsed.TotalSeconds, 1), - ["all"] = a.Flag("all"), - ["probes"] = new JsonObject(record.OrderBy(kv => kv.Key, StringComparer.Ordinal).Select(kv => KeyValuePair.Create(kv.Key, (JsonNode?)kv.Value))), - ["skipped"] = new JsonArray([.. skipped.Select(x => (JsonNode)new JsonObject { ["probe"] = x.Probe, ["reason"] = x.Why })]), - ["seeds"] = new JsonArray([.. outcomes.Select(o => (JsonNode)new JsonObject - { - ["probe"] = o.Probe, ["claim"] = o.Claim, ["obligation"] = o.Obligation, ["seed"] = o.Seed, ["result"] = o.Result, - ["violations"] = o.Violations, ["rows"] = o.Rows, ["detail"] = o.Detail, - })]), - }); - var caught = outcomes.Count(o => o.Result == "caught"); - var counts = outcomes.GroupBy(o => o.Result, StringComparer.Ordinal).OrderBy(g => g.Key, StringComparer.Ordinal).Select(g => $"{g.Count()} {g.Key}"); - ctx.Out.WriteLine($"prober seeds: {string.Join(", ", counts)}, {Seconds(clock.Elapsed.TotalSeconds)} in all"); - return caught == outcomes.Count ? 0 : 1; - } - - public const string LastFile = "seeds-last.json"; - - /// - /// What a probe's seeded runs depend on besides the product: the probe's identity (: - /// its registry entry, the harness and probe sources, its rows, the axes file, the build environment, the tool), - /// its seeds, which that identity leaves out, and the content of each patch they apply. - /// - internal static string SeedsIdentity(Ledger ledger, string probe) - { - using var sha = System.Security.Cryptography.IncrementalHash.CreateHash(System.Security.Cryptography.HashAlgorithmName.SHA256); - void Add(string text) => sha.AppendData(System.Text.Encoding.UTF8.GetBytes(text + "\0")); - Add(ledger.Identity(probe)); - foreach (var (obligation, seed) in SeedsOf(ledger.Registry().GetValueOrDefault(probe) ?? [])) - { - Add(obligation ?? "-"); - Add(Files.Canonical(seed)); - var patch = Files.Str(seed["patch"]); - if (patch.Length > 0 && File.Exists(ledger.CorpusPath(patch))) sha.AppendData(File.ReadAllBytes(ledger.CorpusPath(patch))); - } - return Convert.ToHexStringLower(sha.GetHashAndReset())[..16]; - } - - /// - /// Whether a probe's seeds run without --all, and why: they run unless every seed was caught at a recorded - /// commit, under the seeds identity the probe has now, and neither the product footprint the last replay recorded for - /// it nor a file its seeds patch changed since that commit. A probe without a recorded footprint runs. - /// - internal static (bool Run, string Reason) Stale(Ledger ledger, string probe, JsonObject entry, JsonObject? caught, string identity, Dictionary footprints) - { - if (caught is null) return (true, "no run caught every seed of it yet"); - var commit = Files.Str(caught["commit"]); - var at = commit.Length >= 7 ? commit[..7] : commit; - if (Files.Str(caught["identity"]) != identity) return (true, $"its identity or its seeds changed since they were caught at {at}"); - if (!footprints.ContainsKey(probe)) return (true, "no product footprint recorded for it (a replay records one)"); - if (ledger.FootprintChangedSince(probe, commit, footprints)) return (true, $"its product footprint changed since {at}"); - var patched = SeedsOf(entry).Select(x => Files.Str(x.Seed["patch"])).Where(p => p.Length > 0 && File.Exists(ledger.CorpusPath(p))) - .SelectMany(p => Patched(File.ReadAllText(ledger.CorpusPath(p)))).Distinct(StringComparer.Ordinal).ToArray(); - if (patched.Length > 0 && Git.Run(ledger.Top, ["diff", "--quiet", commit, "HEAD", "--", .. patched]).ExitCode != 0) - return (true, $"a file its seeds patch changed since {at}"); - return (false, $"every seed caught at {at}, and neither its identity nor its product footprint changed since"); - } - - /// The files a patch changes, as its +++ b/ lines name them. - private static IEnumerable Patched(string patch) => - patch.Split('\n').Where(line => line.StartsWith("+++ b/", StringComparison.Ordinal)).Select(line => line["+++ b/".Length..].TrimEnd('\r')); - - /// Applies one probe's seed, builds, runs the probe, and undoes the seed. - private static Outcome One(Ledger ledger, JsonObject config, IProbeAdapter adapter, string worktree, string head, string[] include, - Dictionary environment, string results, Ledger.ProbeState s, string? obligation, JsonNode? seed, - HashSet<(int Row, string Obligation)> baseline) - { - Outcome End(string result, string detail, int violations = 0, int rows = 0) => new(s.Probe, s.Claim, obligation, Describe(seed), result, violations, rows, detail); - - Reset(worktree, head); - Replay.Overlay(ledger, config, worktree); - var (refused, detail, patch, env) = Validate(ledger, include, seed, worktree); - if (refused is not null) return End(refused, detail); - if (patch is not null) - { - var ran = Git.Run(worktree, "apply", "--whitespace=nowarn", patch); - if (ran.ExitCode != 0) return End("does not apply", FirstLine(ran.Stderr)); - } - try - { - var seeded = new Dictionary(environment, StringComparer.Ordinal); - foreach (var (k, v) in env ?? []) seeded[k] = Files.Str(v); - var build = Timed(() => adapter.Build(worktree, seeded), out var buildSeconds); - if (build.ExitCode != 0) return End("build failed", $"the seeded build: {FirstLine(build)}"); - var rows = RunProbe(adapter, worktree, s, environment, env, results, "seed"); - // A check that broke the harness says nothing about the claim, even where it also returned a failure; a - // seed naming an obligation is caught only by a check naming it (decision 104), a seed naming none by any. - var fresh = rows.SelectMany(kv => kv.Value.Checks.Select(c => (Row: kv.Key, Check: c))) - .Where(x => x.Check.CleanViolation && !baseline.Contains((x.Row, x.Check.Obligation))).OrderBy(x => x.Row).ToList(); - var own = fresh.Where(x => obligation is null || x.Check.Obligation == obligation).ToList(); - var caughtRows = own.Select(x => x.Row).Distinct().Count(); - var tally = string.Join(", ", rows.Values.GroupBy(r => r.Category, StringComparer.Ordinal).OrderBy(g => g.Key, StringComparer.Ordinal).Select(g => $"{g.Key} {g.Count()}")); - var broken = rows.Values.Count(r => r.HarnessError); - var harness = broken > 0 ? $"; {broken} ended in a harness error, which is no catch" : ""; - // Violations by checks of other obligations are no catch of this one; say whose they were, a row without checks being `claim`'s. - var others = fresh.Count > own.Count - ? $"; {fresh.Select(x => x.Row).Distinct().Count()} violate by a check naming {string.Join(", ", fresh.Select(x => x.Check.Obligation).Distinct().Order(StringComparer.Ordinal))}, not {obligation}" - : ""; - if (own.Count == 0) return End("missed", $"no row violates that did not already ({rows.Count} rows: {(tally.Length > 0 ? tally : "none ran")}{harness}{others}; build {Seconds(buildSeconds)})", 0, rows.Count); - var example = own[0]; - var named = example.Check.Obligation == Claim.ImplicitObligation && rows[example.Row].Checks.Count == 1 ? "" : " " + example.Check.Obligation; - return End("caught", $"{caughtRows} of {rows.Count} rows violate; e.g. #{example.Row}{named}: {Cut(example.Check.Reason)}", caughtRows, rows.Count); - } - finally - { - if (patch is not null) Git.Run(worktree, "apply", "-R", "--whitespace=nowarn", patch); - } - } - - /// - /// Why a seed cannot be applied in (a result and a detail), or a null result with - /// the patch's full path and the environment toggle to apply. A seed names its defect and a patch, an - /// environment toggle or both; a patch exists in the corpus, touches only the product files and applies. - /// - private static (string? Refused, string Detail, string? Patch, JsonObject? Env) Validate(Ledger ledger, string[] include, JsonNode? seed, string worktree) - { - if (seed is not JsonObject entry) return ("no seed", "its registry entry names none", null, null); - var patch = Files.Str(entry["patch"]); - var env = entry["env"] as JsonObject; - if (Files.Str(entry["defect"]).Length == 0 || (patch.Length == 0 && env is not { Count: > 0 })) - return ("no seed", "a seed names its defect and a patch or an environment toggle", null, null); - if (patch.Length == 0) return (null, "", null, env); - - var file = Path.GetFullPath(ledger.CorpusPath(patch)); - if (!File.Exists(file)) return ("does not apply", $"{patch} is not in the corpus", null, null); - var touched = Git.Run(worktree, "apply", "--numstat", file); - if (touched.ExitCode != 0) return ("does not apply", FirstLine(touched.Stderr), null, null); - var outside = touched.Stdout.Split('\n', StringSplitOptions.RemoveEmptyEntries).Select(line => line.Split('\t')[^1].Trim()) - .Where(path => !include.Any(p => path.StartsWith(p.TrimEnd('/') + "/", StringComparison.Ordinal))).ToList(); - if (outside.Count > 0) return ("does not apply", $"it patches {string.Join(", ", outside)}, outside the product files ({string.Join(", ", include)})", null, null); - var check = Git.Run(worktree, "apply", "--check", file); - return check.ExitCode != 0 ? ("does not apply", FirstLine(check.Stderr), null, null) : (null, "", file, env); - } - - /// - /// What `seeds` would refuse before building anything, against this checkout: a probe without a seed, or a - /// seed that does not apply. No build, so the tests run it on every build and a probe registered without a - /// seed, or a product change that leaves a seed behind, fails there and not only at the next local run. - /// - internal static List Problems(Ledger ledger) - { - var config = ledger.AxesBlock()["replay"] as JsonObject ?? []; - var include = Files.Strings(config["include"]).ToArray() is { Length: > 0 } inc ? inc : ["src"]; - var problems = new List(); - // The obligations each claim lists (or its one implicit obligation), and the seeds that name each. - var obligations = ledger.Claims().ToDictionary(c => Files.Str(c["id"]), Claim.ObligationIds, StringComparer.Ordinal); - var seeded = new Dictionary>(StringComparer.Ordinal); - foreach (var (probe, entry) in ledger.Registry()) - { - if (entry["retired"] is JsonValue retired && retired.TryGetValue(out var r) && r) continue; - var claim = Files.Str(entry["claim"]); - var seeds = SeedsOf(entry); - if (seeds.Count == 0) { problems.Add($"{probe}: no seed, its registry entry names none"); continue; } - foreach (var (obligation, seed) in seeds) - { - if (Validate(ledger, include, seed, ledger.Top) is { Refused: { } refused, Detail: var detail }) - problems.Add($"{Named(probe, obligation)}: {refused}, {detail}"); - var ids = obligations.GetValueOrDefault(claim) ?? [Claim.ImplicitObligation]; - // A seed naming no obligation proves the probe; it counts for the claim's one implicit obligation only. - var counts = obligation ?? (ids is [Claim.ImplicitObligation] ? Claim.ImplicitObligation : null); - if (counts is null) continue; - if (!ids.Contains(counts)) { problems.Add($"{Named(probe, obligation)}: names obligation {counts}, which claim {claim} does not list"); continue; } - (seeded.TryGetValue(claim, out var set) ? set : seeded[claim] = new(StringComparer.Ordinal)).Add(counts); - } - } - // Every listed obligation of a claim that has a probe is seeded by some probe of that claim (decision 104); - // the implicit obligation is covered by the rule above that every probe has a seed. - var claimed = ledger.Registry().Values.Select(e => Files.Str(e["claim"])).ToHashSet(StringComparer.Ordinal); - foreach (var (claim, ids) in obligations.OrderBy(kv => kv.Key, StringComparer.Ordinal)) - { - if (ids is [Claim.ImplicitObligation] || !claimed.Contains(claim)) continue; - foreach (var id in ids.Where(id => !(seeded.GetValueOrDefault(claim)?.Contains(id) ?? false))) - problems.Add($"{claim}: obligation {id} has no seed in any of its probes"); - } - return problems; - } - - /// The (row, obligation) of every check that ended as a violation, clean or not: what a seed's violations are measured against. - private static HashSet<(int Row, string Obligation)> Violating(Dictionary rows) => - [.. rows.SelectMany(kv => kv.Value.Checks.Where(c => c.Category == "violation").Select(c => (kv.Key, c.Obligation)))]; - - /// Runs one probe in every one of its variants and reads how each row ended. - private static Dictionary RunProbe(IProbeAdapter adapter, string worktree, Ledger.ProbeState s, Dictionary environment, - JsonObject? seedEnv, string results, string tag) - { - var rows = new Dictionary(); - var index = 0; - foreach (var variant in s.Variants.OfType()) - { - var name = $"{s.Probe}-{tag}-{index}"; - var (_, outcomes) = ProbeRun.Once(adapter, worktree, s.Filter, results, name, name + ".cobertura.xml", ProbeRun.Variant(environment, variant, seedEnv)); - foreach (var (idx, outcome) in outcomes) rows[idx] = outcome; - index++; - } - return rows; - } - - /// Puts the scratch worktree's tracked files back at HEAD; the copied corpus, untracked, stays. - private static void Reset(string worktree, string head) - { - if (Git.Run(worktree, "checkout", "-q", "--detach", head).ExitCode != 0 && Git.Run(worktree, "reset", "-q", "--hard", head).ExitCode != 0) - throw new Refusal($"could not move the scratch worktree {worktree} to {head[..7]}"); - Git.Run(worktree, "reset", "-q", "--hard", head); - } - - private static string Describe(JsonNode? seed) => - seed is JsonObject o - ? string.Join(" + ", new[] { Files.Str(o["patch"]), o["env"] is JsonObject env ? string.Join(",", env.Select(kv => $"{kv.Key}={Files.Str(kv.Value)}")) : "" }.Where(x => x.Length > 0)) - : "(none)"; - - private static Ran Timed(Func run, out double seconds) - { - var clock = Stopwatch.StartNew(); - var ran = run(); - seconds = clock.Elapsed.TotalSeconds; - return ran; - } - - private static string Seconds(double seconds) => seconds.ToString("F1", CultureInfo.InvariantCulture) + " s"; - - private static string Cut(string s) => string.Join(" ", s.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)) is var line && line.Length > 160 ? line[..160] + "..." : line; - - private static string FirstLine(Ran ran) => ProbeRun.FirstLine(ran); - - private static string FirstLine(string text) => text.Trim().Split('\n')[0].Trim(); -} diff --git a/tools/Prober/SourceLint.cs b/tools/Prober/SourceLint.cs deleted file mode 100644 index 6b34502b..00000000 --- a/tools/Prober/SourceLint.cs +++ /dev/null @@ -1,277 +0,0 @@ -using System.Text; -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; - -namespace Prober; - -/// -/// What `register` and `publish` refuse in the staged probe sources before anything is built (decision 103): -/// a Note whose first argument is not a key of the catalogue (NoteKeys.Name, a member the -/// corpus or the staging declares), and a two-argument Skip (the harness's, not LINQ's) whose first -/// argument is not a string literal naming a finding this ledger holds open. The compiler refuses a key -/// outside the catalogue too; this says so by file and line before a build, and holds the finding ids, -/// which stay strings. A check's Inapplicable and Refused cite their reason by a Cite -/// factory with a string literal, and what it names exists: a not-promised entry of the probe's claim (of any -/// claim, for a harness source no one probe owns), a file of the docs, a knowledge entry under design/knowledge/, -/// a record under design/adr/. It reads code with comments and string literals blanked out, so a call written in -/// either does not count. -/// -internal static partial class SourceLint -{ - /// The catalogue's members, as harness/Row.cs declares them. - [GeneratedRegex(@"public\s+static\s+readonly\s+NoteKeys\s+(\w+)\s*=")] - private static partial Regex CatalogueMember(); - - [GeneratedRegex(@"\.\s*(Note|Skip|Inapplicable|Refused)\s*\(")] - private static partial Regex Call(); - - [GeneratedRegex("^Cite\\s*\\.\\s*(NotPromised|Docs|Fact|Record)\\s*\\(\\s*\"([^\"\\\\]*)\"\\s*\\)$")] - private static partial Regex CiteFactory(); - - [GeneratedRegex(@"^NoteKeys\s*\.\s*(\w+)$")] - private static partial Regex CatalogueKey(); - - [GeneratedRegex("^\"([^\"\\\\]*)\"$")] - private static partial Regex PlainLiteral(); - - /// Refuses, naming each file and line, while a staged source breaks a rule; does nothing without a staging. - public static void Refuse(Ledger l, string command) - { - var problems = Problems(l); - if (problems.Count > 0) - throw new Refusal($"{command}: the staged sources make a note, a skip or a citation that is not written out (decision 103):\n " + string.Join("\n ", problems)); - } - - /// Every problem in the staged harness and probe sources, with the finding ids checked against this ledger. - public static List Problems(Ledger l) - { - var staged = Sources(l.StagingDir).ToList(); - if (staged.Count == 0) return []; - var catalogue = new HashSet(StringComparer.Ordinal); - foreach (var file in Sources(l.CorpusDir).Concat(staged)) - foreach (Match m in CatalogueMember().Matches(Mask(File.ReadAllText(file)))) catalogue.Add(m.Groups[1].Value); - var findings = l.Findings(); - // The not-promised ids of each claim, and the claim of each registered probe: a probe's source cites its own - // claim's entries, a harness source that no one probe owns any claim's. - var notPromised = l.Claims().ToDictionary(c => Files.Str(c["id"]), - c => (IReadOnlySet)(c["not-promised"] as JsonArray ?? []).OfType().Select(n => Files.Str(n["id"])).ToHashSet(StringComparer.Ordinal), StringComparer.Ordinal); - // A probe's source is named for it, or for the class its filter selects (*C1Probe). - var claimOf = new Dictionary(StringComparer.Ordinal); - foreach (var (name, entry) in l.Registry()) - { - claimOf[name] = Files.Str(entry["claim"]); - if (Files.Str(entry["filter"]).TrimStart('*') is { Length: > 0 } cls) claimOf.TryAdd(cls, Files.Str(entry["claim"])); - } - var problems = new List(); - foreach (var file in staged) - { - // Relative to the checkout where the state lives in it, else in full (PROBE_STATE_DIR elsewhere). - var path = Path.GetRelativePath(l.Top, file) is var rel && !rel.StartsWith("..", StringComparison.Ordinal) ? rel.Replace('\\', '/') : file; - var cites = new Citations(l.Top, claimOf.TryGetValue(Path.GetFileNameWithoutExtension(file), out var claim) ? claim : null, notPromised); - foreach (var (line, problem, finding) in Scan(File.ReadAllText(file), catalogue, cites.Problem)) - { - if (problem is not null) problems.Add($"{path}:{line}: {problem}"); - else if (finding is not null && Status(findings, finding) is { } status) - problems.Add($"{path}:{line}: Skip(\"{finding}\", ...) names {status}; a skip steps around an open finding only"); - } - } - return problems; - } - - private static string? Status(Dictionary findings, string id) => - !findings.TryGetValue(id, out var f) ? "no finding this ledger has" - : Files.Str(f["status"]) is var status && status != "open" ? $"finding {id}, which is {status}" - : null; - - private static IEnumerable Sources(string root) => - new[] { "harness", "probes" }.Select(sub => Path.Combine(root, sub)).Where(Directory.Exists) - .SelectMany(dir => Directory.EnumerateFiles(dir, "*.cs")).Order(StringComparer.Ordinal); - - /// - /// What a citation of one source may name, and why one does not: takes the factory and its - /// literal and says what is missing, or null. is the claim of the probe the source is, or - /// null for a source that no one probe owns, which may cite any claim's not-promised entry. - /// - internal sealed record Citations(string Top, string? Claim, IReadOnlyDictionary> NotPromised) - { - public string? Problem(string factory, string value) - { - switch (factory) - { - case "NotPromised" when Claim is not null: - return NotPromised.GetValueOrDefault(Claim)?.Contains(value) ?? false ? null : $"names no not-promised entry of its claim {Claim}"; - case "NotPromised": - return NotPromised.Values.Any(ids => ids.Contains(value)) ? null : "names no not-promised entry of any claim"; - case "Docs": - var file = value.Split('#')[0]; - return file.Length > 0 && !file.Contains("..", StringComparison.Ordinal) && File.Exists(Path.Combine(Top, file)) ? null : $"names no file {file} in the repository"; - case "Fact": - return Named(Path.Combine(Top, "design", "knowledge"), value) ? null : "names no entry under design/knowledge/"; - default: - return Named(Path.Combine(Top, "design", "adr"), value) ? null : "names no record under design/adr/"; - } - } - - /// A file of the directory named for the id: KB-031-...md, 0094-...md. - private static bool Named(string directory, string id) => - id.Length > 0 && Directory.Exists(directory) - && Directory.EnumerateFiles(directory, "*.md").Any(f => Path.GetFileName(f).StartsWith(id + "-", StringComparison.Ordinal) || Path.GetFileName(f) == id + ".md"); - } - - /// - /// Each Note, two-argument Skip, and Inapplicable or Refused with an argument, of one - /// source: its line, the rule it breaks (or null), and for a skip written out, the finding it names. - /// says what a citation's factory and literal fail to name; without it only the form is held. - /// - internal static IEnumerable<(int Line, string? Problem, string? Finding)> Scan(string source, IReadOnlySet catalogue, Func? cite = null) - { - var masked = Mask(source); - foreach (Match m in Call().Matches(masked)) - { - var open = m.Index + m.Length - 1; - var arguments = Arguments(masked, source, open); - if (arguments is null) continue; - var line = 1 + masked.AsSpan(0, m.Index).Count('\n'); - var first = arguments.Count > 0 ? arguments[0] : ""; - if (m.Groups[1].Value is "Inapplicable" or "Refused") - { - if (arguments.Count == 0) continue; // an entry's own Refused() of the harness, not a check's - var call = m.Groups[1].Value; - var factory = CiteFactory().Match(first); - if (!factory.Success) yield return (line, $"{call}({Shown(first)}, ...) does not cite by a Cite factory with a string literal", null); - else if (cite?.Invoke(factory.Groups[1].Value, factory.Groups[2].Value) is { } missing) - yield return (line, $"{call}({Shown(first)}, ...) {missing}", null); - } - else if (m.Groups[1].Value == "Note") - { - var key = CatalogueKey().Match(first); - if (!key.Success) yield return (line, $"Note({Shown(first)}, ...) does not name a key of NoteKeys", null); - else if (!catalogue.Contains(key.Groups[1].Value)) yield return (line, $"Note({Shown(first)}, ...) names no key of NoteKeys", null); - } - else if (arguments.Count == 2) - { - var id = PlainLiteral().Match(first); - yield return id.Success ? (line, null, id.Groups[1].Value) : (line, $"Skip({Shown(first)}, ...) does not name its finding as a string literal", null); - } - } - } - - private static string Shown(string argument) => Regex.Replace(argument, @"\s+", " ") is var s && s.Length > 60 ? s[..60] + "..." : s; - - /// The top-level arguments of the call whose parenthesis opens at , from the original text; null if it never closes. - private static List? Arguments(string masked, string source, int open) - { - var arguments = new List(); - var depth = 0; var start = open + 1; - for (var i = open + 1; i < masked.Length; i++) - { - switch (masked[i]) - { - case '(' or '[' or '{': depth++; break; - case ')' or ']' or '}' when depth > 0: depth--; break; - case ',' when depth == 0: arguments.Add(source[start..i].Trim()); start = i + 1; break; - case ')': - var last = source[start..i].Trim(); - if (last.Length > 0 || arguments.Count > 0) arguments.Add(last); - return arguments; - } - } - return null; - } - - /// - /// The source with every comment and the content of every string and character literal blanked out (line - /// breaks kept, so lines still count), and the code of an interpolation hole kept as code. - /// - internal static string Mask(string s) - { - var m = new StringBuilder(s); - Code(s, m, 0, hole: false); - return m.ToString(); - } - - private static void Blank(StringBuilder m, int from, int to) - { - for (var i = from; i < to && i < m.Length; i++) if (m[i] != '\n') m[i] = ' '; - } - - /// Scans code from ; in a hole, returns the index after its closing brace. - private static int Code(string s, StringBuilder m, int i, bool hole) - { - var depth = 0; - while (i < s.Length) - { - var c = s[i]; - if (c == '/' && i + 1 < s.Length && s[i + 1] == '/') - { - var end = s.IndexOf('\n', i); end = end < 0 ? s.Length : end; - Blank(m, i, end); i = end; - } - else if (c == '/' && i + 1 < s.Length && s[i + 1] == '*') - { - var end = s.IndexOf("*/", i + 2, StringComparison.Ordinal); end = end < 0 ? s.Length : end + 2; - Blank(m, i, end); i = end; - } - else if (c == '\'') - { - var j = i + 1; - while (j < s.Length && s[j] != '\'' && s[j] != '\n') j += s[j] == '\\' ? 2 : 1; - Blank(m, i + 1, j); i = j + 1; - } - else if (c is '"' or '$' or '@' && StringStart(s, i) is { } literal) i = String(s, m, i, literal); - else if (hole && c == '{') { depth++; i++; } - else if (hole && c == '}') { if (depth-- == 0) return i + 1; i++; } - else i++; - } - return i; - } - - private sealed record Literal(int Dollars, bool Verbatim, int Quotes, int QuoteAt); - - /// The literal that starts at : its $ count, @, and run of quotes. - private static Literal? StringStart(string s, int i) - { - if (i > 0 && (char.IsLetterOrDigit(s[i - 1]) || s[i - 1] == '_') && s[i] != '"') return null; - var j = i; var dollars = 0; var verbatim = false; - while (j < s.Length && (s[j] == '$' || s[j] == '@')) { if (s[j] == '$') dollars++; else verbatim = true; j++; } - if (j >= s.Length || s[j] != '"') return null; - var quotes = 0; - while (j + quotes < s.Length && s[j + quotes] == '"') quotes++; - return new Literal(dollars, verbatim, quotes >= 3 ? quotes : 1, j); - } - - /// Blanks one literal's content, keeping its holes as code; returns the index after it. - private static int String(string s, StringBuilder m, int i, Literal literal) - { - var j = literal.QuoteAt + literal.Quotes; - if (literal.Quotes >= 3) - { - // A raw literal ends at a run of as many quotes as it opened with. Holes in it hold no note or skip - // (both return nothing), so it is blanked whole. - var close = new string('"', literal.Quotes); - var end = s.IndexOf(close, j, StringComparison.Ordinal); end = end < 0 ? s.Length : end; - Blank(m, j, end); - return end + literal.Quotes; - } - var from = j; - while (j < s.Length) - { - var c = s[j]; - if (literal.Verbatim && c == '"' && j + 1 < s.Length && s[j + 1] == '"') { j += 2; continue; } - if (!literal.Verbatim && c == '\\') { j += 2; continue; } - if (c == '"') { Blank(m, from, j); return j + 1; } - if (literal.Dollars > 0 && c == '{') - { - if (j + 1 < s.Length && s[j + 1] == '{') { j += 2; continue; } - Blank(m, from, j + 1); - j = Code(s, m, j + 1, hole: true); - from = j - 1; - continue; - } - if (!literal.Verbatim && c == '\n') break; - j++; - } - Blank(m, from, j); - return j; - } -} diff --git a/tools/Prober/TryProbe.cs b/tools/Prober/TryProbe.cs deleted file mode 100644 index ba6e36cc..00000000 --- a/tools/Prober/TryProbe.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System.Diagnostics; -using System.Globalization; -using System.Text.Json.Nodes; - -namespace Prober; - -/// -/// try: the writer's loop for one probe. It moves the replay's worktree to HEAD, overlays the corpus and -/// the branch's staging there as the replay does, builds once through the adapter (not with --no-build), -/// and runs the one probe in each of its registry variants; --rows keeps the rows given, run through the -/// harness's PROBE_ROWS one stretch of consecutive rows at a time, within the rows each variant's -/// PROBE_ONLY selects. It prints each run's first line (the verdict's) and how each row ended, from the -/// jsonl the harness writes. It records nothing, no evidence, footprint or run, so nothing under the state -/// directory changes, and takes no round lock, but it holds the replay's worktree () -/// while it runs: a try and a replay of the same checkout never build in it at once, and a try refuses while a -/// replay holds it. Its exit code is the probe's: the first run's that failed, else 0; 1 when the build fails. -/// -internal static class TryProbe -{ - public static int Run(Context ctx, Args a, IProbeAdapter? adapter = null) - { - var ledger = new Ledger(ctx, a.Get("branch")); - var config = ledger.AxesBlock()["replay"] as JsonObject ?? throw new Refusal("the axes file's block has no \"replay\" configuration"); - adapter ??= new DotNetAdapter(config); - var probe = a.Need("probe"); - if (!ledger.Registry().TryGetValue(probe, out var entry)) - throw new Refusal($"no probe {probe} in the registry, tracked or staged; `prober new` stages one", 2); - var claim = Files.Str(entry["claim"]); - var filter = Files.Str(entry["filter"]); - - // What each variant runs: the rows its PROBE_ONLY selects, those of --rows among them, in stretches. - var probeRows = ledger.RowsOf(probe); - var asked = Indices(a.Get("rows"), probeRows.Count); - var plan = new List<(JsonObject Variant, List Rows, List Stretches)>(); - foreach (var variant in Ledger.VariantsOf(entry).OfType()) - { - var only = Files.Str(variant["PROBE_ONLY"]); - var selected = Enumerable.Range(0, probeRows.Count).Where(i => Replay.Selected(Files.StringMap(probeRows[i]?["row"] ?? probeRows[i]), only)).ToList(); - if (asked is null) { plan.Add((variant, selected, [null])); continue; } - var rows = selected.Where(asked.Contains).ToList(); - if (rows.Count > 0) plan.Add((variant, rows, Stretches(rows))); - } - if (asked is not null && asked.Except(plan.SelectMany(p => p.Rows)).ToList() is { Count: > 0 } unrun) - throw new Refusal($"no variant of {probe} runs row(s) {string.Join(", ", unrun)}: each variant's PROBE_ONLY leaves them out", 2); - - var home = Replay.Home(ctx, ledger); - var worktree = Path.Combine(home, "wt"); - var noBuild = a.Flag("no-build"); - if (noBuild && !Directory.Exists(worktree)) throw new Refusal($"--no-build: the replay worktree {worktree} does not exist yet, so nothing is built; run without it", 2); - // The worktree is the replay's: held for the whole try, so neither moves it or builds in it under the other. - using var held = Replay.HoldWorktree(home) - ?? throw new Refusal($"a replay in this checkout is using {worktree}; run `prober try` when it ends"); - var head = ledger.Head; - var warmth = ProbeRun.Ready(ledger, worktree, head); - Replay.Overlay(ledger, config, worktree); - var environment = ProbeRun.Environment(ctx, adapter, home); - ctx.Out.WriteLine($"prober try: {probe} ({claim}) at {head[..7]} in {worktree}; nothing is recorded"); - if (!noBuild) - { - var clock = Stopwatch.StartNew(); - var build = adapter.Build(worktree, environment); - ctx.Out.WriteLine($" build ({warmth}): {Seconds(clock.Elapsed.TotalSeconds)}, {ProbeRun.FirstLine(build)}"); - if (build.ExitCode != 0) { ctx.Out.WriteLine(build.Stdout); return 1; } - } - - // The full logs of each run, kept until the next try; the results and the rows' jsonl are thrown away. - var logs = Path.Combine(home, "try-logs"); - try { if (Directory.Exists(logs)) Directory.Delete(logs, recursive: true); } catch (IOException) { } - var results = Directory.CreateTempSubdirectory("prober-try-").FullName; - var exit = 0; - var tally = new SortedDictionary(StringComparer.Ordinal); - try - { - var index = 0; - foreach (var (variant, rows, stretches) in plan) - { - var label = variant.Count > 0 ? " [" + string.Join(", ", variant.Select(kv => $"{kv.Key}={Files.Str(kv.Value)}")) + "]" : ""; - foreach (var stretch in stretches) - { - var name = $"{probe}-try-{index++}"; - var env = ProbeRun.Variant(environment, variant); - if (stretch is not null) env["PROBE_ROWS"] = stretch; - env["PROBE_LOG_DIR"] = Path.Combine(logs, name); - var clock = Stopwatch.StartNew(); - var (ran, outcomes) = ProbeRun.Once(adapter, worktree, filter, results, name, "", env); - ctx.Out.WriteLine($" {probe}{label}{(stretch is null ? "" : $" rows {stretch}")}: {ProbeRun.FirstLine(ran)} (exit {ran.ExitCode}, {Seconds(clock.Elapsed.TotalSeconds)})"); - foreach (var i in rows.Where(i => stretch is null || Within(i, stretch))) - { - var outcome = outcomes.GetValueOrDefault(i); - var category = outcome?.Category ?? "did not run"; - tally[category] = tally.GetValueOrDefault(category) + 1; - ctx.Out.WriteLine($" #{i} {category}{(outcome is { Category: not "pass", Reason.Length: > 0 } ? ": " + Cut(Unprefixed(outcome.Reason, category)) : "")}"); - } - if (ran.ExitCode != 0 && Directory.Exists(env["PROBE_LOG_DIR"])) ctx.Out.WriteLine($" log: {env["PROBE_LOG_DIR"]}"); - if (ran.ExitCode != 0 && exit == 0) exit = ran.ExitCode; - } - } - } - finally - { - try { Directory.Delete(results, recursive: true); } catch (IOException) { } - } - ctx.Out.WriteLine($"prober try: {probe}: {(tally.Count == 0 ? "no rows" : string.Join(", ", tally.Select(kv => $"{kv.Key} {kv.Value}")))}; exit {exit}"); - return exit; - } - - /// The row indices of --rows (i,j,..., a-b for a stretch), or null for every row; refuses one the claim does not have. - internal static SortedSet? Indices(string? given, int count) - { - if (given is null) return null; - var result = new SortedSet(); - foreach (var part in given.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)) - { - var bounds = part.Split('-'); - if (bounds.Length > 2 || !bounds.All(x => int.TryParse(x, NumberStyles.None, CultureInfo.InvariantCulture, out _))) - throw new Refusal($"--rows takes row indices, i,j,... or a-b: not {part}", 2); - var lo = int.Parse(bounds[0], CultureInfo.InvariantCulture); var hi = int.Parse(bounds[^1], CultureInfo.InvariantCulture); - for (var i = lo; i <= hi; i++) result.Add(i); - } - if (result.Count == 0) throw new Refusal("--rows takes row indices, i,j,... or a-b", 2); - if (result.Max >= count) throw new Refusal($"--rows {result.Max}: the claim has {count} row(s), 0 to {count - 1}", 2); - return result; - } - - /// The consecutive stretches of sorted rows, as the harness's PROBE_ROWS spells one: lo-hi. - internal static List Stretches(List rows) - { - var result = new List(); - for (var i = 0; i < rows.Count;) - { - var j = i; - while (j + 1 < rows.Count && rows[j + 1] == rows[j] + 1) j++; - result.Add(string.Create(CultureInfo.InvariantCulture, $"{rows[i]}-{rows[j]}")); - i = j + 1; - } - return result; - } - - private static bool Within(int row, string stretch) - { - var bounds = stretch.Split('-'); - return row >= int.Parse(bounds[0], CultureInfo.InvariantCulture) && row <= int.Parse(bounds[1], CultureInfo.InvariantCulture); - } - - /// A reason without the category the harness puts in front of it (violation:...), which the line already names. - private static string Unprefixed(string reason, string category) => reason.StartsWith(category + ":", StringComparison.Ordinal) ? reason[(category.Length + 1)..] : reason; - - private static string Seconds(double seconds) => seconds.ToString("F1", CultureInfo.InvariantCulture) + " s"; - - private static string Cut(string s) => string.Join(" ", s.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries)) is var line && line.Length > 160 ? line[..160] + "..." : line; -} diff --git a/tools/probe/corpus/claims.json b/tools/probe/corpus/claims.json deleted file mode 100644 index 301b96a8..00000000 --- a/tools/probe/corpus/claims.json +++ /dev/null @@ -1,16178 +0,0 @@ -[ - { - "id": "C01-decimal-spelling", - "source": "docs/json.md#decimals-in-one-spelling", - "surfaces": [ - "json" - ], - "axes": { - "converter": [ - "number", - "string" - ], - "input": [ - "7.80", - "7.8000", - "0.00", - "100", - "1E+2", - "max28digits", - "1e-28" - ] - }, - "narrow": { - "shape.wrapped": "Register either one once, and it covers every decimal: nullable ones, dictionary keys, and every value object over a decimal, since its JSON is the underlying type's.", - "input.json": "Both read a number, or a string holding one, and keep the scale they read." - }, - "obligations": [ - { - "id": "smallest-scale", - "sentence": "Two converters write the smallest scale instead:" - }, - { - "id": "number-is-a-number", - "sentence": "**`DecimalNumberJsonConverter`** writes it as a number.", - "axes": { - "converter": [ - "number" - ] - } - }, - { - "id": "string-is-a-string", - "sentence": "**`DecimalStringJsonConverter`** writes it as a string.", - "axes": { - "converter": [ - "string" - ] - } - }, - { - "id": "reads-a-number-or-a-string", - "sentence": "Both read a number, or a string holding one, and keep the scale they read." - }, - { - "id": "keeps-the-scale-it-reads", - "sentence": "Both read a number, or a string holding one, and keep the scale they read." - }, - { - "id": "covers-every-decimal", - "sentence": "Register either one once, and it covers every decimal: nullable ones, dictionary keys, and every value object over a decimal, since its JSON is the underlying type's." - } - ], - "exclude": [ - { - "reason": "A closed set wraps nothing, so it holds no decimal for a decimal converter to write (docs/json.md#decimals-in-one-spelling covers decimals, nullable ones, dictionary keys and value objects over a decimal).", - "pairs": [ - [ - "converter=number", - "shape.kind=closed-set" - ], - [ - "converter=string", - "shape.kind=closed-set" - ], - [ - "input=0.00", - "shape.kind=closed-set" - ], - [ - "input=100", - "shape.kind=closed-set" - ], - [ - "input=1E+2", - "shape.kind=closed-set" - ], - [ - "input=1e-28", - "shape.kind=closed-set" - ], - [ - "input=7.80", - "shape.kind=closed-set" - ], - [ - "input=7.8000", - "shape.kind=closed-set" - ], - [ - "input=max28digits", - "shape.kind=closed-set" - ], - [ - "json.AllowDuplicateProperties=default", - "shape.kind=closed-set" - ], - [ - "json.AllowDuplicateProperties=false", - "shape.kind=closed-set" - ], - [ - "json.AllowOutOfOrderMetadataProperties=default", - "shape.kind=closed-set" - ], - [ - "json.AllowOutOfOrderMetadataProperties=true", - "shape.kind=closed-set" - ], - [ - "json.AllowTrailingCommas=default", - "shape.kind=closed-set" - ], - [ - "json.AllowTrailingCommas=true", - "shape.kind=closed-set" - ], - [ - "json.Converters=JsonStringEnumConverter", - "shape.kind=closed-set" - ], - [ - "json.Converters=StoredJsonConverterFactory", - "shape.kind=closed-set" - ], - [ - "json.Converters=default", - "shape.kind=closed-set" - ], - [ - "json.Converters=own-for-value-object", - "shape.kind=closed-set" - ], - [ - "json.Converters=own-for-wrapped", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenReading", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenWriting", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenWritingDefault", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenWritingNull", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=default", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=CamelCase", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=KebabCaseUpper", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=SnakeCaseLower", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=default", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=own-upper-case", - "shape.kind=closed-set" - ], - [ - "json.Encoder=UnsafeRelaxedJsonEscaping", - "shape.kind=closed-set" - ], - [ - "json.Encoder=default", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyFields=default", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyFields=true", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyProperties=default", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyProperties=true", - "shape.kind=closed-set" - ], - [ - "json.IncludeFields=default", - "shape.kind=closed-set" - ], - [ - "json.IncludeFields=true", - "shape.kind=closed-set" - ], - [ - "json.MaxDepth=3", - "shape.kind=closed-set" - ], - [ - "json.MaxDepth=default", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=AllowNamedFloatingPointLiterals", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=AllowReadingFromString", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=WriteAsString", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=default", - "shape.kind=closed-set" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "shape.kind=closed-set" - ], - [ - "json.PreferredObjectCreationHandling=default", - "shape.kind=closed-set" - ], - [ - "json.PropertyNameCaseInsensitive=default", - "shape.kind=closed-set" - ], - [ - "json.PropertyNameCaseInsensitive=true", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=CamelCase", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=KebabCaseLower", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=KebabCaseUpper", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=SnakeCaseLower", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=SnakeCaseUpper", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=default", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=own-upper-case", - "shape.kind=closed-set" - ], - [ - "json.ReadCommentHandling=Skip", - "shape.kind=closed-set" - ], - [ - "json.ReadCommentHandling=default", - "shape.kind=closed-set" - ], - [ - "json.ReferenceHandler=IgnoreCycles", - "shape.kind=closed-set" - ], - [ - "json.ReferenceHandler=Preserve", - "shape.kind=closed-set" - ], - [ - "json.ReferenceHandler=default", - "shape.kind=closed-set" - ], - [ - "json.RespectNullableAnnotations=default", - "shape.kind=closed-set" - ], - [ - "json.RespectNullableAnnotations=true", - "shape.kind=closed-set" - ], - [ - "json.RespectRequiredConstructorParameters=default", - "shape.kind=closed-set" - ], - [ - "json.RespectRequiredConstructorParameters=true", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolver=default", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolver=default-with-renaming-modifier", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolver=source-generated-context", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolverChain=context-then-default", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolverChain=default", - "shape.kind=closed-set" - ], - [ - "json.UnknownTypeHandling=JsonNode", - "shape.kind=closed-set" - ], - [ - "json.UnknownTypeHandling=default", - "shape.kind=closed-set" - ], - [ - "json.UnmappedMemberHandling=Disallow", - "shape.kind=closed-set" - ], - [ - "json.UnmappedMemberHandling=default", - "shape.kind=closed-set" - ], - [ - "shape.containing=class", - "shape.kind=closed-set" - ], - [ - "shape.containing=generic-type", - "shape.kind=closed-set" - ], - [ - "shape.containing=record-class", - "shape.kind=closed-set" - ], - [ - "shape.containing=record-struct", - "shape.kind=closed-set" - ], - [ - "shape.containing=struct", - "shape.kind=closed-set" - ], - [ - "shape.kind=closed-set", - "shape.position=array-element" - ], - [ - "shape.kind=closed-set", - "shape.position=dictionary-key" - ], - [ - "shape.kind=closed-set", - "shape.position=dictionary-value" - ], - [ - "shape.kind=closed-set", - "shape.position=field" - ], - [ - "shape.kind=closed-set", - "shape.position=immutable-array-element" - ], - [ - "shape.kind=closed-set", - "shape.position=in-patch" - ], - [ - "shape.kind=closed-set", - "shape.position=list-element" - ], - [ - "shape.kind=closed-set", - "shape.position=nullable-property" - ], - [ - "shape.kind=closed-set", - "shape.position=polymorphic-derived-property" - ], - [ - "shape.kind=closed-set", - "shape.position=property" - ], - [ - "shape.kind=closed-set", - "shape.position=read-only-list-element" - ], - [ - "shape.kind=closed-set", - "shape.position=record-ctor-parameter" - ], - [ - "shape.kind=closed-set", - "shape.position=required-init" - ], - [ - "shape.kind=closed-set", - "shape.position=root" - ] - ] - }, - { - "reason": "A value at the root is not held by a containing type, so shape.containing has nothing to apply to.", - "pairs": [ - [ - "shape.containing=class", - "shape.position=root" - ], - [ - "shape.containing=generic-type", - "shape.position=root" - ], - [ - "shape.containing=record-class", - "shape.position=root" - ], - [ - "shape.containing=record-struct", - "shape.position=root" - ], - [ - "shape.containing=struct", - "shape.position=root" - ] - ] - }, - { - "reason": "System.Text.Json serializes a field only under IncludeFields (or [JsonInclude]), so without it the member is in no document and no converter runs in either direction, for the plain type alike.", - "pairs": [ - [ - "json.IncludeFields=default", - "shape.position=field" - ] - ] - }, - { - "reason": "System.Text.Json refuses JsonObjectCreationHandling.Populate together with a reference handler (InvalidOperationException when the options are used; harness/JsonRow.cs runs such a row without Populate), so no row can set both.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ] - ] - } - ] - }, - { - "id": "C02-optional-text", - "source": "docs/text.md#required-and-optional", - "surfaces": [ - "text" - ], - "axes": { - "entry": [ - "AsOptionalText", - "AsOptionalIdentifier", - "AsText", - "AsIdentifier" - ], - "input": [ - "null", - "empty", - "spaces", - "tab-newline", - "word", - "word+ZWSP", - "nbsp-only", - "ZWSP-only" - ] - }, - "narrow": { - "shape.kind": "`AsOptionalText()` and `AsOptionalIdentifier()` return a `Result, TextFault>`", - "shape.wrapped": "`AsOptionalText()` and `AsOptionalIdentifier()` return a `Result, TextFault>`", - "text.entry": "`AsOptionalText()` and `AsOptionalIdentifier()` return a `Result, TextFault>`" - }, - "obligations": [ - { - "id": "required-blank-is-an-error", - "sentence": "For a required field, `Blank` is an error.", - "axes": { - "entry": [ - "AsText", - "AsIdentifier" - ], - "input": [ - "null", - "empty", - "spaces", - "tab-newline", - "nbsp-only" - ] - } - }, - { - "id": "optional-blank-is-no-value", - "sentence": "For an optional one, a blank means \"no value\", and `AsOptionalText()` and `AsOptionalIdentifier()` return a `Result, TextFault>`.", - "axes": { - "entry": [ - "AsOptionalText", - "AsOptionalIdentifier" - ], - "input": [ - "null", - "empty", - "spaces", - "tab-newline", - "nbsp-only" - ] - } - }, - { - "id": "hidden-is-an-error-in-both", - "sentence": "`Hidden` is an error in both cases.", - "axes": { - "input": [ - "word+ZWSP", - "ZWSP-only" - ] - } - }, - { - "id": "null-is-blank", - "sentence": "A null string is `Blank`.", - "axes": { - "input": [ - "null" - ] - } - } - ], - "not-promised": [ - { - "id": "as-text-refused-in-globalization-invariant-mode", - "source": "docs/text.md#globalization-invariant-mode", - "sentence": "So `AsText()` throws `PlatformNotSupportedException` there, on its first call, whatever the string.", - "axes": { - "text.culture": [ - "globalization-invariant" - ], - "entry": [ - "AsText", - "AsOptionalText" - ] - } - } - ], - "exclude": [ - { - "reason": "Not promised (as-text-refused-in-globalization-invariant-mode): `AsText()` throws `PlatformNotSupportedException` in globalization-invariant mode (docs/text.md#globalization-invariant-mode), and `AsOptionalText()`, which calls it, throws with it, so C02OptionalTextProbe checks that refusal without credit and runs the row on the identifier counterpart; no row holds the pair.", - "pairs": [ - [ - "entry=AsText", - "text.culture=globalization-invariant" - ], - [ - "entry=AsOptionalText", - "text.culture=globalization-invariant" - ] - ] - } - ] - }, - { - "id": "C03-composed-faults", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", - "surfaces": [ - "http" - ], - "axes": { - "arity": [ - "2", - "3" - ], - "error": [ - "first-set", - "last-set", - "with-detail", - "with-rule" - ] - }, - "obligations": [ - { - "id": "each-error-own-set", - "sentence": "Each error is answered as its own set maps it." - }, - { - "id": "detail-and-rule-intact", - "sentence": "`Fault` (from CodoMetis.TypeKit) holds one error of either set, with its detail and rule intact.", - "axes": { - "error": [ - "with-detail", - "with-rule" - ] - } - }, - { - "id": "statuses-ascending", - "sentence": "So its operation lists the statuses of both sets, in ascending order, with the problem types of both where they share a status." - }, - { - "id": "shared-status-types", - "sentence": "So its operation lists the statuses of both sets, in ascending order, with the problem types of both where they share a status." - }, - { - "id": "unmapped-set-stops-start", - "sentence": "The host doesn't start while either set is unmapped." - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C04-without-faults", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#leaving-out-what-a-route-cannot-answer", - "surfaces": [ - "http" - ], - "axes": { - "scope": [ - "endpoint", - "group", - "controller" - ], - "combined": [ - "alone", - "with-WithFaultStatus-on-group" - ] - }, - "obligations": [ - { - "id": "doc-omits-left-out", - "sentence": "The operation then lists no status and no problem type for a member left out." - }, - { - "id": "reporting-left-out-throws", - "sentence": "Reporting a member left out anyway throws an `InvalidOperationException` naming the endpoint and the member, rather than answering with a status the document doesn't list." - }, - { - "id": "narrows-wider-status", - "sentence": "If a group gives `NotFound` a status and one endpoint inside leaves `NotFound` out, that endpoint drops it, and the group's other endpoints keep the status.", - "axes": { - "scope": [ - "endpoint", - "controller" - ], - "combined": [ - "with-WithFaultStatus-on-group" - ] - } - }, - { - "id": "left-out-everywhere-stops-start", - "sentence": "**These stop the host from starting**, as for a status: a value or a name no member has, a status that every endpoint it's set on leaves out (on the endpoint itself, or on a group whose endpoints all leave the member out), and a group or a controller none of whose endpoints answers with the type.", - "axes": { - "scope": [ - "group" - ], - "combined": [ - "with-WithFaultStatus-on-group" - ] - } - } - ], - "not-promised": [ - { - "id": "controller-scope-is-mvc", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#leaving-out-what-a-route-cannot-answer", - "sentence": "**In MVC**, an action or a controller says it with `[WithoutFaults(nameof(AccountFault.NotFound))]`.", - "axes": { - "scope": [ - "controller" - ], - "http.host": [ - "minimal", - "route-group" - ] - } - } - ], - "exclude": [ - { - "reason": "A minimal-API host has no controller to leave a member out on: the controller scope is MVC's (not-promised controller-scope-is-mvc).", - "pairs": [ - [ - "scope=controller", - "http.host=minimal" - ], - [ - "scope=controller", - "http.host=route-group" - ] - ] - }, - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C05-with-rule", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused", - "surfaces": [ - "http" - ], - "axes": { - "ruletype": [ - "enum", - "closed-set", - "nested-enum", - "flags-combination", - "undefined-cast" - ], - "qualified": [ - "bare", - "QualifiedFaultNames" - ] - }, - "obligations": [ - { - "id": "rule-qualified", - "sentence": "The problem carries it as `rule`, qualified with its type's name, so two types' `Blank` can be told apart:", - "axes": { - "ruletype": [ - "enum", - "closed-set" - ] - } - }, - { - "id": "nested-chain", - "sentence": "A rule of a nested type is named after its nesting chain, whatever `QualifiedFaultNames` says.", - "axes": { - "ruletype": [ - "nested-enum" - ] - } - }, - { - "id": "stays-the-errors", - "sentence": "The status, the mapping and the document stay the error's.", - "axes": { - "ruletype": [ - "enum", - "closed-set", - "nested-enum" - ] - } - }, - { - "id": "unnamed-value-throws", - "sentence": "A value no member names, such as a combination of flags or a cast number, throws where it's given.", - "axes": { - "ruletype": [ - "flags-combination", - "undefined-cast" - ] - } - }, - { - "id": "no-namespace", - "sentence": "**The name carries no namespace**, which would publish your application's structure to every client.", - "axes": { - "ruletype": [ - "enum", - "closed-set", - "nested-enum" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C06-fault-kinds", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#a-closed-set-as-the-fault-type", - "surfaces": [ - "http" - ], - "axes": { - "kind": [ - "PreconditionFailed", - "Malformed", - "Invalid", - "Unavailable" - ] - }, - "obligations": [ - { - "id": "kind-gives-status", - "sentence": "The kind gives the status:" - }, - { - "id": "description-as-detail", - "sentence": "The description becomes the problem's `detail`, so a client can show it." - }, - { - "id": "no-description-no-detail", - "sentence": "A member without one has no `detail`." - }, - { - "id": "member-must-have-kind", - "sentence": "**A member must have a kind.** A member whose kind is `default`, which is no kind, fails this call." - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C07-fault-responses-blanket", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#every-fault-set-at-once", - "surfaces": [ - "http" - ], - "axes": { - "mapping": [ - "by-kind", - "own-IFault-mapping" - ], - "set": [ - "fault-set", - "own-mapped-set", - "enum-unmapped", - "member-without-kind", - "mapping-throws", - "status-not-error" - ] - }, - "obligations": [ - { - "id": "by-kind", - "sentence": "every fault set an endpoint answers with, by its kind", - "axes": { - "mapping": [ - "by-kind" - ] - } - }, - { - "id": "own-mapping", - "sentence": "The mapping can be your own. It reads each member's kind and description through `IFault`:", - "axes": { - "mapping": [ - "own-IFault-mapping" - ] - } - }, - { - "id": "own-set-keeps-mapping", - "sentence": "A set mapped on its own keeps its mapping.", - "axes": { - "set": [ - "own-mapped-set" - ] - } - }, - { - "id": "enum-needs-own-mapping", - "sentence": "Neither has a kind, and the host doesn't start while an endpoint answers with one that's unmapped.", - "axes": { - "set": [ - "enum-unmapped" - ] - } - }, - { - "id": "member-without-kind-stops-start", - "sentence": "A member with no kind stops the start, and so does one the mapping throws for or gives a status that isn't an error.", - "axes": { - "set": [ - "member-without-kind" - ] - } - }, - { - "id": "mapping-refusal-stops-start", - "sentence": "A member with no kind stops the start, and so does one the mapping throws for or gives a status that isn't an error.", - "axes": { - "set": [ - "mapping-throws", - "status-not-error" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C08-same-name-warning", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types", - "surfaces": [ - "http" - ], - "axes": { - "naming": [ - "bare", - "qualified" - ], - "arity": [ - "2", - "3" - ], - "leave-out": [ - "none", - "WithoutFaults-one" - ] - }, - "obligations": [ - { - "id": "bare-names-warn", - "sentence": "With bare names, the default, that's `AccountFault.NotFound` beside an `EditFault.NotFound`.", - "axes": { - "naming": [ - "bare" - ] - } - }, - { - "id": "qualified-chain-warns", - "sentence": "With qualified names, it's two sets with one nesting chain in two namespaces, since the name carries no namespace.", - "axes": { - "naming": [ - "qualified" - ] - } - }, - { - "id": "warning-names-both", - "sentence": "A client reads the two errors as one, so the host logs a warning at startup naming both.", - "axes": { - "leave-out": [ - "none" - ] - } - }, - { - "id": "qualified-names-fix", - "sentence": "Fix it with `QualifiedFaultNames`, a rename, or by leaving one out of the route", - "axes": { - "naming": [ - "qualified" - ] - } - }, - { - "id": "leave-one-out-fixes", - "sentence": "Fix it with `QualifiedFaultNames`, a rename, or by leaving one out of the route", - "axes": { - "leave-out": [ - "WithoutFaults-one" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C09-base-record-equality", - "source": "CHANGELOG.md#2.1.0-fixed", - "surfaces": [ - "generation" - ], - "axes": { - "base-equality": [ - "none", - "override-Equals", - "override-GetHashCode", - "explicit-IEquatable" - ], - "collection": [ - "HashSet", - "Dictionary-key", - "Distinct" - ] - }, - "narrow": { - "shape.position": "Over a base record, a value object's equality is its wrapped value's, in a collection of the base too, whatever equality the base declares.", - "shape.containing": "Over a base record, a value object's equality is its wrapped value's, in a collection of the base too, whatever equality the base declares." - }, - "obligations": [ - { - "id": "equal-by-the-wrapped-value", - "sentence": "Over a base record, a value object's equality is its wrapped value's" - }, - { - "id": "in-a-collection-of-the-base", - "sentence": "in a collection of the base too, whatever equality the base declares." - } - ], - "exclude": [ - { - "reason": "A record struct or a closed set has no base record: C# gives a struct no base type, and a closed set is a sealed class that is never a record (CMTK1020).", - "pairs": [ - [ - "base-equality=explicit-IEquatable", - "shape.kind=closed-set" - ], - [ - "base-equality=explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "base-equality=explicit-IEquatable", - "shape.kind=validated-struct" - ], - [ - "base-equality=none", - "shape.kind=closed-set" - ], - [ - "base-equality=none", - "shape.kind=record-struct" - ], - [ - "base-equality=none", - "shape.kind=validated-struct" - ], - [ - "base-equality=override-Equals", - "shape.kind=closed-set" - ], - [ - "base-equality=override-Equals", - "shape.kind=record-struct" - ], - [ - "base-equality=override-Equals", - "shape.kind=validated-struct" - ], - [ - "base-equality=override-GetHashCode", - "shape.kind=closed-set" - ], - [ - "base-equality=override-GetHashCode", - "shape.kind=record-struct" - ], - [ - "base-equality=override-GetHashCode", - "shape.kind=validated-struct" - ], - [ - "collection=Dictionary-key", - "shape.kind=closed-set" - ], - [ - "collection=Dictionary-key", - "shape.kind=record-struct" - ], - [ - "collection=Dictionary-key", - "shape.kind=validated-struct" - ], - [ - "collection=Distinct", - "shape.kind=closed-set" - ], - [ - "collection=Distinct", - "shape.kind=record-struct" - ], - [ - "collection=Distinct", - "shape.kind=validated-struct" - ], - [ - "collection=HashSet", - "shape.kind=closed-set" - ], - [ - "collection=HashSet", - "shape.kind=record-struct" - ], - [ - "collection=HashSet", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=none", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=none", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=none", - "shape.kind=validated-struct" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=closed-set", - "shape.site=in-generic-type" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-in-class" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=closed-set", - "shape.site=top-level" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=record-struct", - "shape.site=nested-in-class" - ], - [ - "shape.kind=record-struct", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=record-struct", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=record-struct", - "shape.site=top-level" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=Guid" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=Uri" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=bool" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=byte" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=char" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=decimal" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=double" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=enum" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=int" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=long" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=string" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=ulong" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-struct", - "shape.site=nested-in-class" - ], - [ - "shape.kind=validated-struct", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=validated-struct", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=validated-struct", - "shape.site=top-level" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=Guid" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=Uri" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=bool" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=byte" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=char" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=decimal" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=double" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=enum" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=int" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=long" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=string" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=ulong" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ] - ] - }, - { - "reason": "A value object nested in a generic type fails the build with CMTK1005 (Generators README, Build errors), so it has no generated equality or parsing to check.", - "pairs": [ - [ - "base-equality=explicit-IEquatable", - "shape.site=in-generic-type" - ], - [ - "base-equality=none", - "shape.site=in-generic-type" - ], - [ - "base-equality=override-Equals", - "shape.site=in-generic-type" - ], - [ - "base-equality=override-GetHashCode", - "shape.site=in-generic-type" - ], - [ - "collection=Dictionary-key", - "shape.site=in-generic-type" - ], - [ - "collection=Distinct", - "shape.site=in-generic-type" - ], - [ - "collection=HashSet", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-1", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-2", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-3", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=none", - "shape.site=in-generic-type" - ], - [ - "shape.kind=sealed-record-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-class", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=in-generic-type" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTime" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Guid" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeSpan" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Uri" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=bool" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=byte" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=char" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=decimal" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=double" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=flags-enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=int" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=long" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=own-record-class" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=string" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=in-generic-type" - ] - ] - }, - { - "reason": "The claim is about a value object over a base record; with no base record it states nothing.", - "pairs": [ - [ - "base-equality=explicit-IEquatable", - "shape.inheritance=none" - ], - [ - "base-equality=none", - "shape.inheritance=none" - ], - [ - "base-equality=override-Equals", - "shape.inheritance=none" - ], - [ - "base-equality=override-GetHashCode", - "shape.inheritance=none" - ], - [ - "collection=Dictionary-key", - "shape.inheritance=none" - ], - [ - "collection=Distinct", - "shape.inheritance=none" - ], - [ - "collection=HashSet", - "shape.inheritance=none" - ], - [ - "shape.inheritance=none", - "shape.kind=sealed-record-class" - ], - [ - "shape.inheritance=none", - "shape.kind=validated-class" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=none", - "shape.site=nested-in-class" - ], - [ - "shape.inheritance=none", - "shape.site=nested-in-struct" - ], - [ - "shape.inheritance=none", - "shape.site=nested-two-levels" - ], - [ - "shape.inheritance=none", - "shape.site=top-level" - ], - [ - "shape.inheritance=none", - "shape.wrapped=DateOnly" - ], - [ - "shape.inheritance=none", - "shape.wrapped=DateTime" - ], - [ - "shape.inheritance=none", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.inheritance=none", - "shape.wrapped=Guid" - ], - [ - "shape.inheritance=none", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.inheritance=none", - "shape.wrapped=TimeOnly" - ], - [ - "shape.inheritance=none", - "shape.wrapped=TimeSpan" - ], - [ - "shape.inheritance=none", - "shape.wrapped=Uri" - ], - [ - "shape.inheritance=none", - "shape.wrapped=bool" - ], - [ - "shape.inheritance=none", - "shape.wrapped=byte" - ], - [ - "shape.inheritance=none", - "shape.wrapped=char" - ], - [ - "shape.inheritance=none", - "shape.wrapped=decimal" - ], - [ - "shape.inheritance=none", - "shape.wrapped=double" - ], - [ - "shape.inheritance=none", - "shape.wrapped=enum" - ], - [ - "shape.inheritance=none", - "shape.wrapped=flags-enum" - ], - [ - "shape.inheritance=none", - "shape.wrapped=int" - ], - [ - "shape.inheritance=none", - "shape.wrapped=long" - ], - [ - "shape.inheritance=none", - "shape.wrapped=own-record-class" - ], - [ - "shape.inheritance=none", - "shape.wrapped=string" - ], - [ - "shape.inheritance=none", - "shape.wrapped=ulong" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ] - ] - }, - { - "reason": "A declaration of a refused kind fails the build (CMTK1005, CMTK1006), so it is generated into nothing; .claude/probe-axes.md: shape.refused-kind is taken only where the refusal is the claim.", - "pairs": [ - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "base-equality=none", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-equality=none", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-equality=none", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-equality=none", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "collection=Distinct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "collection=Distinct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "collection=Distinct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "collection=Distinct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "collection=HashSet", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "collection=HashSet", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "collection=HashSet", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "collection=HashSet", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=ulong" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-equality=explicit-IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "base-equality=none", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-equality=none", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-equality=none", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-equality=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-equality=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-equality=override-Equals", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-equality=override-GetHashCode", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "collection=Dictionary-key", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "collection=Distinct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "collection=Distinct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "collection=Distinct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "collection=Distinct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "collection=Distinct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "collection=HashSet", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "collection=HashSet", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "collection=HashSet", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "collection=HashSet", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "collection=HashSet", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=ulong" - ] - ] - } - ] - }, - { - "id": "C10-preserve-guard", - "source": "src/CodoMetis.TypeKit.Generators/README.md#json", - "surfaces": [ - "json" - ], - "axes": { - "handler": [ - "Preserve", - "IgnoreCycles", - "none" - ] - }, - "obligations": [ - { - "id": "refused-where-references-could-be-written", - "sentence": "**Preserved references** (`ReferenceHandler.Preserve`) throw a `NotSupportedException` where the serializer could write `$id` or `$ref` inside the underlying value.", - "axes": { - "handler": [ - "Preserve" - ], - "shape.wrapped": [ - "own-record-class" - ] - } - }, - { - "id": "value-converters-unaffected", - "sentence": "These are unaffected: a value the serializer writes with a value converter (a number, a string, a `Guid`, a `Uri`)", - "axes": { - "handler": [ - "Preserve" - ] - } - }, - { - "id": "own-converters-unaffected", - "sentence": "anything a converter of your own writes, on the options or on one property", - "axes": { - "json.Converters": [ - "own-for-wrapped", - "own-for-value-object" - ] - } - }, - { - "id": "ignore-cycles-unaffected", - "sentence": "a struct of such values, and `ReferenceHandler.IgnoreCycles`.", - "axes": { - "handler": [ - "IgnoreCycles" - ] - } - } - ], - "exclude": [ - { - "reason": "handler is this claim's name for JsonSerializerOptions.ReferenceHandler (Preserve, IgnoreCycles, none = default), the same setting as json.ReferenceHandler; one setting cannot hold two values in one row.", - "pairs": [ - [ - "handler=IgnoreCycles", - "json.ReferenceHandler=Preserve" - ], - [ - "handler=IgnoreCycles", - "json.ReferenceHandler=default" - ], - [ - "handler=Preserve", - "json.ReferenceHandler=IgnoreCycles" - ], - [ - "handler=Preserve", - "json.ReferenceHandler=default" - ], - [ - "handler=none", - "json.ReferenceHandler=IgnoreCycles" - ], - [ - "handler=none", - "json.ReferenceHandler=Preserve" - ] - ] - }, - { - "reason": "A closed set wraps nothing (Generators README#closed-sets: a sealed class whose instances are its members), so it has no shape.wrapped.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "A value at the root is not held by a containing type, so shape.containing has nothing to apply to.", - "pairs": [ - [ - "shape.containing=class", - "shape.position=root" - ], - [ - "shape.containing=generic-type", - "shape.position=root" - ], - [ - "shape.containing=record-class", - "shape.position=root" - ], - [ - "shape.containing=record-struct", - "shape.position=root" - ], - [ - "shape.containing=struct", - "shape.position=root" - ] - ] - }, - { - "reason": "System.Text.Json refuses JsonObjectCreationHandling.Populate together with a reference handler (InvalidOperationException when the options are used; harness/JsonRow.cs runs such a row without Populate), so no row can set both.", - "pairs": [ - [ - "handler=IgnoreCycles", - "json.PreferredObjectCreationHandling=Populate" - ], - [ - "handler=Preserve", - "json.PreferredObjectCreationHandling=Populate" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ] - ] - } - ] - }, - { - "id": "C11-parse-shapes-build", - "source": "CHANGELOG.md#2.1.0-fixed", - "surfaces": [ - "text", - "generation" - ], - "axes": { - "parse-shape": [ - "implicit-result", - "ref-text", - "abstract-string-ctor", - "ordinary" - ] - }, - "narrow": { - "shape.position": "A wrapped type's `Parse` whose result can't be assigned to it, or that takes its text by `ref`, or an abstract class's string constructor, no longer breaks the build; the value object has no parsing.", - "shape.containing": "A wrapped type's `Parse` whose result can't be assigned to it, or that takes its text by `ref`, or an abstract class's string constructor, no longer breaks the build; the value object has no parsing." - }, - "obligations": [ - { - "id": "implicit-result", - "sentence": "A wrapped type's `Parse` whose result can't be assigned to it", - "axes": { - "parse-shape": [ - "implicit-result" - ] - } - }, - { - "id": "ref-text", - "sentence": "or that takes its text by `ref`", - "axes": { - "parse-shape": [ - "ref-text" - ] - } - }, - { - "id": "abstract-string-constructor", - "sentence": "or an abstract class's string constructor, no longer breaks the build; the value object has no parsing.", - "axes": { - "parse-shape": [ - "abstract-string-ctor" - ] - } - }, - { - "id": "parsing-where-it-can-be-parsed", - "sentence": "`IParsable`/`ISpanParsable`/`IUtf8SpanParsable`, formatting in the invariant culture", - "axes": { - "parse-shape": [ - "ordinary" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.wrapped": [ - "Uri", - "enum", - "flags-enum", - "NodaTime.Instant" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "not-promised:no-span-parsing-without-the-underlying-types" - } - ] - } - ], - "not-promised": [ - { - "id": "no-span-parsing-without-the-underlying-types", - "source": "src/CodoMetis.TypeKit.Generators/README.md#what-is-generated", - "sentence": "A `Uri`, an enum and a NodaTime type have neither.", - "axes": { - "shape.wrapped": [ - "Uri", - "enum", - "flags-enum", - "NodaTime.Instant" - ], - "text.entry": [ - "ISpanParsable" - ] - } - } - ], - "exclude": [ - { - "reason": "A closed set wraps no type, so it has no wrapped type's Parse to take for its parser.", - "pairs": [ - [ - "parse-shape=abstract-string-ctor", - "shape.kind=closed-set" - ], - [ - "parse-shape=implicit-result", - "shape.kind=closed-set" - ], - [ - "parse-shape=ordinary", - "shape.kind=closed-set" - ], - [ - "parse-shape=ref-text", - "shape.kind=closed-set" - ], - [ - "process.converter-lookup=none", - "shape.kind=closed-set" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=none", - "shape.kind=closed-set" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=closed-set", - "shape.site=in-generic-type" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-in-class" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=closed-set", - "shape.site=top-level" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ], - [ - "shape.kind=closed-set", - "text.culture=ar-SA" - ], - [ - "shape.kind=closed-set", - "text.culture=de-DE" - ], - [ - "shape.kind=closed-set", - "text.culture=globalization-invariant" - ], - [ - "shape.kind=closed-set", - "text.culture=invariant" - ], - [ - "shape.kind=closed-set", - "text.culture=tr-TR" - ], - [ - "shape.kind=closed-set", - "text.entry=IParsable" - ], - [ - "shape.kind=closed-set", - "text.entry=ISpanParsable" - ], - [ - "shape.kind=closed-set", - "text.entry=Parse" - ], - [ - "shape.kind=closed-set", - "text.entry=ToString-format" - ], - [ - "shape.kind=closed-set", - "text.entry=TryFormat-short-span" - ], - [ - "shape.kind=closed-set", - "text.entry=TryFrom" - ], - [ - "shape.kind=closed-set", - "text.entry=TryParse" - ], - [ - "shape.kind=closed-set", - "text.entry=type-converter" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=equality-operator (CMTK1011)" - ] - ] - }, - { - "reason": "A value object nested in a generic type fails the build with CMTK1005 (Generators README, Build errors), so it has no generated equality or parsing to check.", - "pairs": [ - [ - "parse-shape=abstract-string-ctor", - "shape.site=in-generic-type" - ], - [ - "parse-shape=implicit-result", - "shape.site=in-generic-type" - ], - [ - "parse-shape=ordinary", - "shape.site=in-generic-type" - ], - [ - "parse-shape=ref-text", - "shape.site=in-generic-type" - ], - [ - "process.converter-lookup=none", - "shape.site=in-generic-type" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-1", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-2", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-3", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=none", - "shape.site=in-generic-type" - ], - [ - "shape.kind=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=sealed-record-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-struct", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=in-generic-type" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTime" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Guid" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeSpan" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Uri" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=bool" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=byte" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=char" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=decimal" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=double" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=flags-enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=int" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=long" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=own-record-class" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=string" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=ulong" - ], - [ - "shape.site=in-generic-type", - "text.culture=ar-SA" - ], - [ - "shape.site=in-generic-type", - "text.culture=de-DE" - ], - [ - "shape.site=in-generic-type", - "text.culture=globalization-invariant" - ], - [ - "shape.site=in-generic-type", - "text.culture=invariant" - ], - [ - "shape.site=in-generic-type", - "text.culture=tr-TR" - ], - [ - "shape.site=in-generic-type", - "text.entry=IParsable" - ], - [ - "shape.site=in-generic-type", - "text.entry=ISpanParsable" - ], - [ - "shape.site=in-generic-type", - "text.entry=Parse" - ], - [ - "shape.site=in-generic-type", - "text.entry=ToString-format" - ], - [ - "shape.site=in-generic-type", - "text.entry=TryFormat-short-span" - ], - [ - "shape.site=in-generic-type", - "text.entry=TryFrom" - ], - [ - "shape.site=in-generic-type", - "text.entry=TryParse" - ], - [ - "shape.site=in-generic-type", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=in-generic-type" - ] - ] - }, - { - "reason": "A record struct has no base type, so it cannot derive from a base record or inherit a base's explicit IEquatable.", - "pairs": [ - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ] - ] - }, - { - "reason": "The parse shape is the wrapped type itself, a class of its own; a value object over one of the catalogue's wrapped types is the ordinary shape.", - "pairs": [ - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=DateOnly" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=DateTime" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=DateTimeOffset" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=Guid" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=NodaTime.Instant" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=TimeOnly" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=TimeSpan" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=Uri" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=bool" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=byte" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=char" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=decimal" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=double" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=enum" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=flags-enum" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=int" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=long" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=own-record-class" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=string" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.wrapped=ulong" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=DateOnly" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=DateTime" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=DateTimeOffset" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=Guid" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=NodaTime.Instant" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=TimeOnly" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=TimeSpan" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=Uri" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=bool" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=byte" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=char" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=decimal" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=double" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=enum" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=flags-enum" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=int" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=long" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=own-record-class" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=string" - ], - [ - "parse-shape=implicit-result", - "shape.wrapped=ulong" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=DateOnly" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=DateTime" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=DateTimeOffset" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=Guid" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=NodaTime.Instant" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=TimeOnly" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=TimeSpan" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=Uri" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=bool" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=byte" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=char" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=decimal" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=double" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=enum" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=flags-enum" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=int" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=long" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=own-record-class" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=string" - ], - [ - "parse-shape=ref-text", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "A declaration of a refused kind fails the build (CMTK1005, CMTK1006), so it is generated into nothing; .claude/probe-axes.md: shape.refused-kind is taken only where the refusal is the claim.", - "pairs": [ - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "text.entry=type-converter" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "parse-shape=abstract-string-ctor", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "parse-shape=implicit-result", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "parse-shape=ordinary", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "parse-shape=ref-text", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "process.converter-lookup=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.culture=ar-SA" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.culture=de-DE" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.culture=globalization-invariant" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.culture=invariant" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.culture=tr-TR" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=IParsable" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=ISpanParsable" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=Parse" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=ToString-format" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=TryFormat-short-span" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=TryFrom" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=TryParse" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "text.entry=type-converter" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "text.entry=type-converter" - ] - ] - }, - { - "reason": "A `Uri`, an enum and a NodaTime type have neither (Generators README, What is generated: no ISpanParsable or IUtf8SpanParsable where the underlying type has none, not-promised no-span-parsing-without-the-underlying-types), so parsing-where-it-can-be-parsed is inapplicable there and no check that reads shape.wrapped can credit them.", - "pairs": [ - [ - "shape.wrapped=NodaTime.Instant", - "text.entry=ISpanParsable" - ], - [ - "shape.wrapped=Uri", - "text.entry=ISpanParsable" - ], - [ - "shape.wrapped=enum", - "text.entry=ISpanParsable" - ], - [ - "shape.wrapped=flags-enum", - "text.entry=ISpanParsable" - ] - ] - } - ] - }, - { - "id": "C12-described-converter", - "source": "docs/json.md#describing-what-a-converter-writes", - "surfaces": [ - "http" - ], - "axes": { - "source": [ - "IDescribedJsonConverter", - "JsonSchemaDescriptions", - "decimal-converter" - ], - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController-visible" - ] - }, - "obligations": [ - { - "id": "own-converter-describes-itself", - "sentence": "**Your own converter** implements `IDescribedJsonConverter` and describes itself, as both decimal converters do.", - "axes": { - "source": [ - "IDescribedJsonConverter", - "decimal-converter" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "source": [ - "IDescribedJsonConverter", - "JsonSchemaDescriptions" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "options-describe", - "sentence": "**A converter someone else wrote**, or the serializer's own enum converter, is described in the options by `JsonSchemaDescriptions`.", - "axes": { - "source": [ - "JsonSchemaDescriptions" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "source": [ - "IDescribedJsonConverter", - "JsonSchemaDescriptions" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "every-position", - "sentence": "With CodoMetis.TypeKit.AspNetCore, `AddTypeKit()` writes the same descriptions into the OpenAPI document, in every position, a list's elements and a dictionary's values included.", - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "source": [ - "IDescribedJsonConverter", - "JsonSchemaDescriptions" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "parameter-keeps-aspnet", - "sentence": "So it keeps the description ASP.NET gives the type without your converters", - "axes": { - "source": [ - "decimal-converter" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "source": [ - "IDescribedJsonConverter", - "JsonSchemaDescriptions" - ] - }, - "cite": "record:0099" - } - ] - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C13-patch-required", - "source": "docs/merge-patches.md#required-constructor-parameters", - "surfaces": [ - "http" - ], - "axes": { - "declared": [ - "init", - "ctor-parameter" - ], - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController-visible" - ] - }, - "obligations": [ - { - "id": "doc-required-where-rejected", - "sentence": "So the document never calls a field optional when the endpoint rejects a request without it.", - "axes": { - "declared": [ - "ctor-parameter" - ], - "json.RespectRequiredConstructorParameters": [ - "true" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "doc-optional-where-absent", - "sentence": "`AddTypeKit()` leaves a patch out of `required` where the serializer lets it be absent, and keeps it there where the options reject a body without it.", - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "absent-is-default", - "sentence": "a property the request leaves out keeps its default, which is `Absent`." - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C14-declared-problem", - "source": "CHANGELOG.md#2.1.0-fixed", - "surfaces": [ - "http" - ], - "axes": { - "declared": [ - "ProducesProblem", - "ProducesResponseType", - "none" - ], - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController-visible" - ] - }, - "obligations": [ - { - "id": "declared-describes-fault", - "sentence": "OpenAPI: a problem response an endpoint declares itself (`ProducesProblem`, `[ProducesResponseType]`) describes `fault`, and names its problem types.", - "axes": { - "declared": [ - "ProducesProblem", - "ProducesResponseType" - ] - } - }, - { - "id": "declared-names-types", - "sentence": "OpenAPI: a problem response an endpoint declares itself (`ProducesProblem`, `[ProducesResponseType]`) describes `fault`, and names its problem types.", - "axes": { - "declared": [ - "ProducesProblem", - "ProducesResponseType" - ] - } - }, - { - "id": "ascending-with-declared", - "sentence": "OpenAPI: an operation with fault responses lists every status ascending, the ones its endpoint declares itself among them", - "axes": { - "declared": [ - "ProducesProblem", - "ProducesResponseType" - ] - } - }, - { - "id": "application-json-declared", - "sentence": "OpenAPI: a problem response an endpoint declares as `application/json`, such as `Produces(404)` or `[ProducesResponseType(404)]`, describes `fault` and `rule` and names its problem types, and keeps its media type", - "axes": { - "declared": [ - "ProducesResponseType" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C15-mvc-fault-status-doc", - "source": "CHANGELOG.md#2.1.0-fixed", - "surfaces": [ - "http" - ], - "axes": { - "setter": [ - "MapControllers().WithFaultStatus", - "action-attribute", - "controller-attribute" - ], - "kind": [ - "status-only", - "WithoutFaults" - ], - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController-visible" - ] - }, - "obligations": [ - { - "id": "builder-reaches-doc", - "sentence": "OpenAPI: a `WithFaultStatus` on the builder `MapControllers()` returns reaches the document, as it reached the response." - }, - { - "id": "without-faults-leaves-doc", - "sentence": "**`WithoutFaults`** and `[WithoutFaults]`: a route leaves out of its document the members it never answers with, and reporting one throws" - }, - { - "id": "status-per-scope", - "sentence": "`WithFaultStatus`/`[FaultStatus]` per endpoint, group or controller" - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C16-options-agreement", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", - "surfaces": [ - "http" - ], - "axes": { - "difference": [ - "converter-only-http", - "naming-policy", - "number-handling" - ], - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController-visible" - ] - }, - "obligations": [ - { - "id": "differing-refused", - "sentence": "Otherwise building the document fails rather than describe JSON the controllers don't write.", - "axes": { - "difference": [ - "converter-only-http" - ], - "http.host": [ - "mvc", - "both", - "controller-without-ApiController-visible" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "error-names-type-and-descriptions", - "sentence": "The error names the type and what each set of options says of it, also for a type held only inside a patch.", - "axes": { - "difference": [ - "converter-only-http" - ], - "http.host": [ - "mvc", - "both", - "controller-without-ApiController-visible" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "patch-held-refused", - "sentence": "The error names the type and what each set of options says of it, also for a type held only inside a patch.", - "axes": { - "difference": [ - "converter-only-http" - ], - "http.host": [ - "mvc", - "both", - "controller-without-ApiController-visible" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "same-converters-build", - "sentence": "A host with controllers registers the same converters and descriptions on both, in the same order.", - "axes": { - "difference": [ - "naming-policy", - "number-handling" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "minimal-host-not-compared", - "sentence": "A host with controllers registers the same converters and descriptions on both, in the same order.", - "axes": { - "difference": [ - "converter-only-http" - ], - "http.host": [ - "minimal", - "route-group" - ] - }, - "inapplicable": [ - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - } - ] - } - ], - "not-promised": [ - { - "id": "only-converters-and-descriptions-compared", - "source": "design/adr/0071-converters-say-what-they-write.md#0071-json-converters-say-what-they-write-decimals-get-one-spelling", - "sentence": "Where the host has a controller, building the document fails when the two option sets do not carry the same described converters and description sets, by type, naming each that differs; a host of minimal APIs alone is never compared.", - "axes": { - "difference": [ - "naming-policy", - "number-handling" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "C17-cmtk0014", - "source": "src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0014", - "surfaces": [ - "analyzers" - ], - "axes": { - "value": [ - "(FaultKind)9", - "default", - "valid" - ], - "site": [ - "attribute-argument", - "cast", - "default-literal" - ] - }, - "obligations": [ - { - "id": "a-cast-naming-no-member", - "sentence": "A `FaultKind` or a `ConstructorAccessibility` that names no member: a cast", - "axes": { - "value": [ - "(FaultKind)9" - ] - } - }, - { - "id": "default-and-zero", - "sentence": "`default(FaultKind)`, a zero", - "axes": { - "value": [ - "default" - ] - } - }, - { - "id": "constructor-accessibility-too", - "sentence": "[RequireParameterlessConstructor((ConstructorAccessibility)7)] // CMTK0014: no member, read as public", - "axes": { - "site": [ - "attribute-argument" - ], - "value": [ - "(FaultKind)9" - ] - } - }, - { - "id": "reported-where-written", - "sentence": "Both are reported where the value is written:", - "axes": { - "value": [ - "(FaultKind)9", - "default" - ] - } - }, - { - "id": "a-member-is-silent", - "sentence": "public static readonly ImportFault Duplicate = new(FaultKind.Conflict);", - "axes": { - "value": [ - "valid" - ] - } - } - ], - "exclude": [ - { - "reason": "A default literal is the value 0, so it cannot spell (FaultKind)9 or a member: FaultKind's members start at 1.", - "pairs": [ - [ - "site=default-literal", - "value=(FaultKind)9" - ], - [ - "site=default-literal", - "value=valid" - ] - ] - }, - { - "reason": "A record struct has no base type, so it cannot derive from a base record or inherit a base's explicit IEquatable.", - "pairs": [ - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ] - ] - }, - { - "reason": "A closed set wraps no type, so a closed set over a wrapped type cannot be declared.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "Declared as .claude/probe-axes.md says (as C22's harness, BuildRefusals.cs, declares it), a closed set named as one of its generated members leaves their writing to the generators, so in this compilation without them it does not implement IClosedSet's members: the compiler's own CS0535, and no row can hold it beside the analyzer's places.", - "pairs": [ - [ - "shape.containing=class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=field", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=root", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=attribute-argument" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=cast" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=default-literal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "value=(FaultKind)9" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "value=default" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "value=valid" - ] - ] - }, - { - "reason": "A value object with a hand-written operator == and != between two of the type is C#'s own CS0111 without the generators (Generators README, Build errors: CMTK1011, 'which C# also reports as CS0111'), since a record already declares both, so this compilation without the generators cannot hold it.", - "pairs": [ - [ - "shape.containing=class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=field", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=root", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=attribute-argument" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=cast" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=default-literal" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "value=(FaultKind)9" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "value=default" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "value=valid" - ] - ] - } - ] - }, - { - "id": "C18-cmtk1023", - "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", - "surfaces": [ - "generation" - ], - "axes": { - "base-member": [ - "Equals", - "GetHashCode", - "IEquatable" - ] - }, - "obligations": [ - { - "id": "names-each-base-member", - "sentence": "So a hand-written `Equals(TBase)`, `GetHashCode()` or `IEquatable.Equals` on a base record isn't used, and a warning names it (CMTK1023)." - }, - { - "id": "a-warning-and-generated", - "sentence": "A warning, and the value object is generated." - }, - { - "id": "generated-equality-never-calls-the-base", - "sentence": "Over a base record, the generated `Equals(TSelf)` and `GetHashCode()` compare the underlying value alone, and never call the base's." - } - ], - "exclude": [ - { - "reason": "A record struct or a closed set has no base record: C# gives a struct no base type, and a closed set is a sealed class that is never a record (CMTK1020). CMTK1023 is about a base record's equality.", - "pairs": [ - [ - "base-member=Equals", - "shape.kind=closed-set" - ], - [ - "base-member=Equals", - "shape.kind=record-struct" - ], - [ - "base-member=Equals", - "shape.kind=validated-struct" - ], - [ - "base-member=GetHashCode", - "shape.kind=closed-set" - ], - [ - "base-member=GetHashCode", - "shape.kind=record-struct" - ], - [ - "base-member=GetHashCode", - "shape.kind=validated-struct" - ], - [ - "base-member=IEquatable", - "shape.kind=closed-set" - ], - [ - "base-member=IEquatable", - "shape.kind=record-struct" - ], - [ - "base-member=IEquatable", - "shape.kind=validated-struct" - ], - [ - "shape.containing=class", - "shape.kind=closed-set" - ], - [ - "shape.containing=class", - "shape.kind=record-struct" - ], - [ - "shape.containing=class", - "shape.kind=validated-struct" - ], - [ - "shape.containing=generic-type", - "shape.kind=closed-set" - ], - [ - "shape.containing=generic-type", - "shape.kind=record-struct" - ], - [ - "shape.containing=generic-type", - "shape.kind=validated-struct" - ], - [ - "shape.containing=record-class", - "shape.kind=closed-set" - ], - [ - "shape.containing=record-class", - "shape.kind=record-struct" - ], - [ - "shape.containing=record-class", - "shape.kind=validated-struct" - ], - [ - "shape.containing=record-struct", - "shape.kind=closed-set" - ], - [ - "shape.containing=record-struct", - "shape.kind=record-struct" - ], - [ - "shape.containing=record-struct", - "shape.kind=validated-struct" - ], - [ - "shape.containing=struct", - "shape.kind=closed-set" - ], - [ - "shape.containing=struct", - "shape.kind=record-struct" - ], - [ - "shape.containing=struct", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=none", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=none", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=none", - "shape.kind=validated-struct" - ], - [ - "shape.kind=closed-set", - "shape.position=array-element" - ], - [ - "shape.kind=closed-set", - "shape.position=dictionary-key" - ], - [ - "shape.kind=closed-set", - "shape.position=dictionary-value" - ], - [ - "shape.kind=closed-set", - "shape.position=field" - ], - [ - "shape.kind=closed-set", - "shape.position=immutable-array-element" - ], - [ - "shape.kind=closed-set", - "shape.position=in-patch" - ], - [ - "shape.kind=closed-set", - "shape.position=list-element" - ], - [ - "shape.kind=closed-set", - "shape.position=nullable-property" - ], - [ - "shape.kind=closed-set", - "shape.position=polymorphic-derived-property" - ], - [ - "shape.kind=closed-set", - "shape.position=property" - ], - [ - "shape.kind=closed-set", - "shape.position=read-only-list-element" - ], - [ - "shape.kind=closed-set", - "shape.position=record-ctor-parameter" - ], - [ - "shape.kind=closed-set", - "shape.position=required-init" - ], - [ - "shape.kind=closed-set", - "shape.position=root" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=closed-set", - "shape.site=in-generic-type" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-in-class" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=closed-set", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=closed-set", - "shape.site=top-level" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ], - [ - "shape.kind=record-struct", - "shape.position=array-element" - ], - [ - "shape.kind=record-struct", - "shape.position=dictionary-key" - ], - [ - "shape.kind=record-struct", - "shape.position=dictionary-value" - ], - [ - "shape.kind=record-struct", - "shape.position=field" - ], - [ - "shape.kind=record-struct", - "shape.position=immutable-array-element" - ], - [ - "shape.kind=record-struct", - "shape.position=in-patch" - ], - [ - "shape.kind=record-struct", - "shape.position=list-element" - ], - [ - "shape.kind=record-struct", - "shape.position=nullable-property" - ], - [ - "shape.kind=record-struct", - "shape.position=polymorphic-derived-property" - ], - [ - "shape.kind=record-struct", - "shape.position=property" - ], - [ - "shape.kind=record-struct", - "shape.position=read-only-list-element" - ], - [ - "shape.kind=record-struct", - "shape.position=record-ctor-parameter" - ], - [ - "shape.kind=record-struct", - "shape.position=required-init" - ], - [ - "shape.kind=record-struct", - "shape.position=root" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=record-struct", - "shape.site=nested-in-class" - ], - [ - "shape.kind=record-struct", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=record-struct", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=record-struct", - "shape.site=top-level" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=Guid" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=Uri" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=bool" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=byte" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=char" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=decimal" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=double" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=enum" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=int" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=long" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=string" - ], - [ - "shape.kind=record-struct", - "shape.wrapped=ulong" - ], - [ - "shape.kind=validated-struct", - "shape.position=array-element" - ], - [ - "shape.kind=validated-struct", - "shape.position=dictionary-key" - ], - [ - "shape.kind=validated-struct", - "shape.position=dictionary-value" - ], - [ - "shape.kind=validated-struct", - "shape.position=field" - ], - [ - "shape.kind=validated-struct", - "shape.position=immutable-array-element" - ], - [ - "shape.kind=validated-struct", - "shape.position=in-patch" - ], - [ - "shape.kind=validated-struct", - "shape.position=list-element" - ], - [ - "shape.kind=validated-struct", - "shape.position=nullable-property" - ], - [ - "shape.kind=validated-struct", - "shape.position=polymorphic-derived-property" - ], - [ - "shape.kind=validated-struct", - "shape.position=property" - ], - [ - "shape.kind=validated-struct", - "shape.position=read-only-list-element" - ], - [ - "shape.kind=validated-struct", - "shape.position=record-ctor-parameter" - ], - [ - "shape.kind=validated-struct", - "shape.position=required-init" - ], - [ - "shape.kind=validated-struct", - "shape.position=root" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-struct", - "shape.site=nested-in-class" - ], - [ - "shape.kind=validated-struct", - "shape.site=nested-in-struct" - ], - [ - "shape.kind=validated-struct", - "shape.site=nested-two-levels" - ], - [ - "shape.kind=validated-struct", - "shape.site=top-level" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=Guid" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=Uri" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=bool" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=byte" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=char" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=decimal" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=double" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=enum" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=int" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=long" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=string" - ], - [ - "shape.kind=validated-struct", - "shape.wrapped=ulong" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ] - ] - }, - { - "reason": "A value object nested in a generic type fails the build with CMTK1005 (Generators README, Build errors), so it has no generated equality or parsing to check.", - "pairs": [ - [ - "base-member=Equals", - "shape.site=in-generic-type" - ], - [ - "base-member=GetHashCode", - "shape.site=in-generic-type" - ], - [ - "base-member=IEquatable", - "shape.site=in-generic-type" - ], - [ - "shape.containing=class", - "shape.site=in-generic-type" - ], - [ - "shape.containing=generic-type", - "shape.site=in-generic-type" - ], - [ - "shape.containing=record-class", - "shape.site=in-generic-type" - ], - [ - "shape.containing=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.containing=struct", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-1", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-2", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-3", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=none", - "shape.site=in-generic-type" - ], - [ - "shape.kind=sealed-record-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-class", - "shape.site=in-generic-type" - ], - [ - "shape.position=array-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=dictionary-key", - "shape.site=in-generic-type" - ], - [ - "shape.position=dictionary-value", - "shape.site=in-generic-type" - ], - [ - "shape.position=field", - "shape.site=in-generic-type" - ], - [ - "shape.position=immutable-array-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=in-patch", - "shape.site=in-generic-type" - ], - [ - "shape.position=list-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=nullable-property", - "shape.site=in-generic-type" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.site=in-generic-type" - ], - [ - "shape.position=property", - "shape.site=in-generic-type" - ], - [ - "shape.position=read-only-list-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=record-ctor-parameter", - "shape.site=in-generic-type" - ], - [ - "shape.position=required-init", - "shape.site=in-generic-type" - ], - [ - "shape.position=root", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=in-generic-type" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTime" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Guid" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeSpan" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Uri" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=bool" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=byte" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=char" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=decimal" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=double" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=flags-enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=int" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=long" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=own-record-class" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=string" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=in-generic-type" - ] - ] - }, - { - "reason": "Without a base record there is no base to declare Equals, GetHashCode or IEquatable on.", - "pairs": [ - [ - "base-member=Equals", - "shape.inheritance=none" - ], - [ - "base-member=GetHashCode", - "shape.inheritance=none" - ], - [ - "base-member=IEquatable", - "shape.inheritance=none" - ], - [ - "shape.containing=class", - "shape.inheritance=none" - ], - [ - "shape.containing=generic-type", - "shape.inheritance=none" - ], - [ - "shape.containing=record-class", - "shape.inheritance=none" - ], - [ - "shape.containing=record-struct", - "shape.inheritance=none" - ], - [ - "shape.containing=struct", - "shape.inheritance=none" - ], - [ - "shape.inheritance=none", - "shape.kind=sealed-record-class" - ], - [ - "shape.inheritance=none", - "shape.kind=validated-class" - ], - [ - "shape.inheritance=none", - "shape.position=array-element" - ], - [ - "shape.inheritance=none", - "shape.position=dictionary-key" - ], - [ - "shape.inheritance=none", - "shape.position=dictionary-value" - ], - [ - "shape.inheritance=none", - "shape.position=field" - ], - [ - "shape.inheritance=none", - "shape.position=immutable-array-element" - ], - [ - "shape.inheritance=none", - "shape.position=in-patch" - ], - [ - "shape.inheritance=none", - "shape.position=list-element" - ], - [ - "shape.inheritance=none", - "shape.position=nullable-property" - ], - [ - "shape.inheritance=none", - "shape.position=polymorphic-derived-property" - ], - [ - "shape.inheritance=none", - "shape.position=property" - ], - [ - "shape.inheritance=none", - "shape.position=read-only-list-element" - ], - [ - "shape.inheritance=none", - "shape.position=record-ctor-parameter" - ], - [ - "shape.inheritance=none", - "shape.position=required-init" - ], - [ - "shape.inheritance=none", - "shape.position=root" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=none", - "shape.site=nested-in-class" - ], - [ - "shape.inheritance=none", - "shape.site=nested-in-struct" - ], - [ - "shape.inheritance=none", - "shape.site=nested-two-levels" - ], - [ - "shape.inheritance=none", - "shape.site=top-level" - ], - [ - "shape.inheritance=none", - "shape.wrapped=DateOnly" - ], - [ - "shape.inheritance=none", - "shape.wrapped=DateTime" - ], - [ - "shape.inheritance=none", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.inheritance=none", - "shape.wrapped=Guid" - ], - [ - "shape.inheritance=none", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.inheritance=none", - "shape.wrapped=TimeOnly" - ], - [ - "shape.inheritance=none", - "shape.wrapped=TimeSpan" - ], - [ - "shape.inheritance=none", - "shape.wrapped=Uri" - ], - [ - "shape.inheritance=none", - "shape.wrapped=bool" - ], - [ - "shape.inheritance=none", - "shape.wrapped=byte" - ], - [ - "shape.inheritance=none", - "shape.wrapped=char" - ], - [ - "shape.inheritance=none", - "shape.wrapped=decimal" - ], - [ - "shape.inheritance=none", - "shape.wrapped=double" - ], - [ - "shape.inheritance=none", - "shape.wrapped=enum" - ], - [ - "shape.inheritance=none", - "shape.wrapped=flags-enum" - ], - [ - "shape.inheritance=none", - "shape.wrapped=int" - ], - [ - "shape.inheritance=none", - "shape.wrapped=long" - ], - [ - "shape.inheritance=none", - "shape.wrapped=own-record-class" - ], - [ - "shape.inheritance=none", - "shape.wrapped=string" - ], - [ - "shape.inheritance=none", - "shape.wrapped=ulong" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ] - ] - }, - { - "reason": "CMTK1023 is 'A warning, and the value object is generated' (Generators README, Build errors); a refused declaration is not generated. A declaration of a refused kind fails the build (CMTK1005, CMTK1006), so it is generated into nothing; .claude/probe-axes.md: shape.refused-kind is taken only where the refusal is the claim.", - "pairs": [ - [ - "base-member=Equals", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-member=Equals", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-member=Equals", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-member=Equals", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.containing=class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.containing=class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.containing=class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.containing=class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=field", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=field", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=field", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=field", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=property", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=property", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=property", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=property", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.position=root", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.position=root", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.position=root", - "shape.refused-kind=over-value-object (CMTK1005)" - ], - [ - "shape.position=root", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.wrapped=ulong" - ], - [ - "base-member=Equals", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-member=Equals", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-member=Equals", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-member=Equals", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-member=Equals", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-member=GetHashCode", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "base-member=IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.containing=class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.containing=class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.containing=class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=field", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=field", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=field", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=field", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=field", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=property", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=property", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=property", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=root", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.position=root", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.position=root", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.position=root", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=root", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=ulong" - ] - ] - } - ] - }, - { - "id": "C19-cmtk0010-kinds", - "source": "docs/type-constraints.md#the-kind-of-a-type-argument", - "surfaces": [ - "analyzers" - ], - "axes": { - "attribute": [ - "Interface", - "Unsealed", - "ValueObject", - "ClosedSet", - "FlagsEnum", - "ReadOnlyStruct", - "Distinct", - "Unrelated" - ], - "site": [ - "call", - "foreach", - "await", - "Deconstruct", - "collection-expression" - ] - }, - "obligations": [ - { - "id": "interface-and-unsealed", - "sentence": "**`[Interface]` and `[Unsealed]`** are what a proxy needs: a contract to implement, or a class to derive from.", - "axes": { - "attribute": [ - "Interface", - "Unsealed" - ] - } - }, - { - "id": "value-object-and-closed-set", - "sentence": "**`[ValueObject]` and `[ClosedSet]`** accept their marker interface with any type argument.", - "axes": { - "attribute": [ - "ValueObject", - "ClosedSet" - ] - } - }, - { - "id": "flags-enum-and-read-only-struct", - "sentence": "**`[FlagsEnum]` and `[ReadOnlyStruct]`** narrow what `where T : Enum` and `where T : struct` admit.", - "axes": { - "attribute": [ - "FlagsEnum", - "ReadOnlyStruct" - ] - } - }, - { - "id": "a-pair-once-at-the-later-argument", - "sentence": "A breach is reported once, at the later argument.", - "axes": { - "attribute": [ - "Distinct", - "Unrelated" - ] - } - }, - { - "id": "methods-the-compiler-calls", - "sentence": "**Methods the compiler calls for you:** a `foreach`'s `GetEnumerator`, an `await`'s `GetAwaiter`, a `Deconstruct` (in `var (a, b) = x`, a `foreach`, or a pattern like `x is (1, 2)`), and a collection expression's `Add` or builder method.", - "axes": { - "site": [ - "foreach", - "await", - "Deconstruct", - "collection-expression" - ] - } - } - ], - "exclude": [ - { - "reason": "A record struct has no base type, so it cannot derive from a base record or inherit a base's explicit IEquatable.", - "pairs": [ - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ] - ] - }, - { - "reason": "A closed set wraps no type, so a closed set over a wrapped type cannot be declared.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "Declared as .claude/probe-axes.md says (as C22's harness, BuildRefusals.cs, declares it), a closed set named as one of its generated members leaves their writing to the generators, so in this compilation without them it does not implement IClosedSet's members: the compiler's own CS0535, and no row can hold it beside the analyzer's places.", - "pairs": [ - [ - "attribute=ClosedSet", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=Distinct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=FlagsEnum", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=Interface", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=ReadOnlyStruct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=Unrelated", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=Unsealed", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "attribute=ValueObject", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=field", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=property", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.position=root", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=Deconstruct" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=await" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=call" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=collection-expression" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "site=foreach" - ] - ] - }, - { - "reason": "A value object with a hand-written operator == and != between two of the type is C#'s own CS0111 without the generators (Generators README, Build errors: CMTK1011, 'which C# also reports as CS0111'), since a record already declares both, so this compilation without the generators cannot hold it.", - "pairs": [ - [ - "attribute=ClosedSet", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=Distinct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=FlagsEnum", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=Interface", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=ReadOnlyStruct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=Unrelated", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=Unsealed", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "attribute=ValueObject", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=generic-type", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.containing=struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.inheritance=none", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=array-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=dictionary-key", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=dictionary-value", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=field", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=immutable-array-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=in-patch", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=list-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=nullable-property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=property", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=read-only-list-element", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=record-ctor-parameter", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=required-init", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.position=root", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-in-struct" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=nested-two-levels" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=top-level" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=Deconstruct" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=await" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=call" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=collection-expression" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "site=foreach" - ] - ] - } - ] - }, - { - "id": "C20-testing-shouldhold", - "source": "src/CodoMetis.TypeKit.Testing/README.md", - "surfaces": [ - "option-result" - ], - "axes": { - "arity": [ - "2", - "3" - ], - "set": [ - "first", - "last" - ], - "wrong-reason": [ - "no", - "yes" - ] - }, - "obligations": [ - { - "id": "fails-unless-it-holds-that-reason", - "sentence": "`ShouldHold(reason)` fails unless the fault holds that reason, whichever of its types the reason belongs to." - }, - { - "id": "whichever-of-its-types", - "sentence": "whichever of its types the reason belongs to", - "axes": { - "set": [ - "first", - "last" - ], - "arity": [ - "2", - "3" - ] - } - }, - { - "id": "hands-back-detail-and-rule", - "sentence": "It hands back the `Fault` with its detail and rule intact.", - "axes": { - "wrong-reason": [ - "no" - ] - } - }, - { - "id": "uninitialized-fails", - "sentence": "**An uninitialized result fails every assertion.**", - "axes": { - "or.operation": [ - "default-instance" - ] - } - }, - { - "id": "a-failure-says-the-outcome", - "sentence": "**A failure says what the outcome was**", - "axes": { - "wrong-reason": [ - "yes" - ] - } - } - ], - "exclude": [ - { - "reason": "Result.Catch turns an exception into a Result, never an Option (src/CodoMetis.TypeKit/ResultExtensions.cs), so no row can catch into an Option.", - "pairs": [ - [ - "or.operation=Result.Catch", - "or.shape=Option" - ] - ] - }, - { - "reason": "Result has no Select or SelectMany, so no query expression produces one, and FirstOrNone returns an Option, never a Result (src/CodoMetis.TypeKit/ResultExtensions.cs and OptionExtensions.cs).", - "pairs": [ - [ - "or.operation=FirstOrNone", - "or.shape=Result-E" - ], - [ - "or.operation=query-syntax", - "or.shape=Result-E" - ] - ] - } - ] - }, - { - "id": "C21-openapi-schema-parity", - "source": "README.md#what-you-get", - "surfaces": [ - "http", - "json" - ], - "axes": { - "http.host": [ - "minimal", - "mvc", - "both", - "route-group", - "controller-without-ApiController-visible" - ] - }, - "obligations": [ - { - "id": "the-underlying-types-schema", - "sentence": "The JSON, the database column and the OpenAPI schema are the same as the underlying type's.", - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "not-promised:own-converter-for-the-value-object" - }, - { - "axes": { - "json.Converters": [ - "own-for-wrapped" - ] - }, - "cite": "not-promised:own-converter-for-the-wrapped-type" - }, - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.NumberHandling": [ - "WriteAsString" - ], - "shape.wrapped": [ - "char" - ] - }, - "cite": "fact:KB-042" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "shape.wrapped": [ - "own-record-class" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "nullable-admits-null-as-the-wrapped-does", - "sentence": "Its OpenAPI schema is the one ASP.NET Core publishes for the underlying type.", - "axes": { - "http.nullability": [ - "nullable" - ] - }, - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "not-promised:own-converter-for-the-value-object" - }, - { - "axes": { - "json.Converters": [ - "own-for-wrapped" - ] - }, - "cite": "not-promised:own-converter-for-the-wrapped-type" - }, - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.NumberHandling": [ - "WriteAsString" - ], - "shape.wrapped": [ - "char" - ] - }, - "cite": "fact:KB-042" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "shape.wrapped": [ - "own-record-class" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "container-elements", - "sentence": "Its OpenAPI schema is the one ASP.NET Core publishes for the underlying type.", - "axes": { - "shape.position": [ - "list-element", - "array-element", - "immutable-array-element", - "read-only-list-element", - "dictionary-value" - ] - }, - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "not-promised:own-converter-for-the-value-object" - }, - { - "axes": { - "json.Converters": [ - "own-for-wrapped" - ] - }, - "cite": "not-promised:own-converter-for-the-wrapped-type" - }, - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.NumberHandling": [ - "WriteAsString" - ], - "shape.wrapped": [ - "char" - ] - }, - "cite": "fact:KB-042" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "shape.wrapped": [ - "own-record-class" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "dictionary-key", - "sentence": "Its OpenAPI schema is the one ASP.NET Core publishes for the underlying type.", - "axes": { - "shape.position": [ - "dictionary-key" - ] - }, - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "not-promised:own-converter-for-the-value-object" - }, - { - "axes": { - "json.Converters": [ - "own-for-wrapped" - ] - }, - "cite": "not-promised:own-converter-for-the-wrapped-type" - }, - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.NumberHandling": [ - "WriteAsString" - ], - "shape.wrapped": [ - "char" - ] - }, - "cite": "fact:KB-042" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "shape.wrapped": [ - "own-record-class" - ] - }, - "cite": "record:0099" - } - ] - }, - { - "id": "every-document-version", - "sentence": "Its OpenAPI schema is the one ASP.NET Core publishes for the underlying type.", - "axes": { - "openapi.OpenApiVersion": [ - "OpenApi2_0", - "OpenApi3_0" - ] - }, - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "not-promised:own-converter-for-the-value-object" - }, - { - "axes": { - "json.Converters": [ - "own-for-wrapped" - ] - }, - "cite": "not-promised:own-converter-for-the-wrapped-type" - }, - { - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ] - }, - "cite": "record:0099" - }, - { - "axes": { - "json.NumberHandling": [ - "WriteAsString" - ], - "shape.wrapped": [ - "char" - ] - }, - "cite": "fact:KB-042" - }, - { - "axes": { - "json.MaxDepth": [ - "3" - ], - "shape.wrapped": [ - "own-record-class" - ] - }, - "cite": "record:0099" - } - ] - } - ], - "not-promised": [ - { - "id": "a-closed-set-is-a-string-enum", - "source": "README.md#what-you-get", - "sentence": "One line per member gives you parsing by name, JSON as the name, an OpenAPI string enum and a text column.", - "axes": { - "shape.kind": [ - "closed-set" - ] - } - }, - { - "id": "own-converter-for-the-value-object", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", - "sentence": "That converter then writes it instead of the generated one, so it's described as that converter says (see \"A described type\" below).", - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - } - }, - { - "id": "own-converter-for-the-wrapped-type", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", - "sentence": "ASP.NET can't see through a JSON converter you write yourself. It writes the type as `{}`, or with only the `format` its CLR type maps to. It also drops a list's `items` and a dictionary's `additionalProperties` of that type.", - "axes": { - "json.Converters": [ - "own-for-wrapped" - ] - } - }, - { - "id": "a-class-value-object-admits-null", - "source": "design/adr/0036-nullable-value-object-admits-null-openapi.md#0036-a-nullable-value-object-admits-null-in-the-openapi-document-wherever-it-appears", - "sentence": "A nullable value object admits null in the OpenAPI document wherever it appears", - "axes": { - "shape.kind": [ - "sealed-record-class", - "validated-class" - ] - } - }, - { - "id": "a-nullable-value-object-admits-null", - "source": "design/adr/0036-nullable-value-object-admits-null-openapi.md#0036-a-nullable-value-object-admits-null-in-the-openapi-document-wherever-it-appears", - "sentence": "A nullable value object admits null in the OpenAPI document wherever it appears", - "axes": { - "http.nullability": [ - "nullable" - ] - } - }, - { - "id": "openapi-2-nullable-component-loses-its-type", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", - "sentence": "So under 2.0 a nullable value-object property loses its type, where the underlying type's nullable property keeps it.", - "axes": { - "openapi.OpenApiVersion": [ - "OpenApi2_0" - ], - "openapi.CreateSchemaReferenceId": [ - "default", - "own-prefixing" - ] - } - }, - { - "id": "enum-component-is-its-first-use", - "source": "design/knowledge/KB-027-an-enum-component-is-its-first-use.md#kb-027-the-component-aspnet-makes-for-an-enum-written-by-name-is-the-schema-of-the-first-use-it-meets", - "sentence": "So whether a parameter of the wrapped `E?` admits null in a document with components depends on the endpoints and their order, not on the parameter.", - "axes": { - "json.Converters": [ - "JsonStringEnumConverter" - ], - "http.nullability": [ - "nullable" - ], - "shape.wrapped": [ - "enum" - ] - } - }, - { - "id": "openapi-2-nullable-body-keeps-only-its-null", - "source": "design/knowledge/KB-001-openapi-2-nullable-body-drops-pattern.md#kb-001-under-openapi-20-aspnet-writes-a-nullable-request-body-as-allof-x-nullable-true-and-drops-its-pattern", - "sentence": "A minimal API writes it the same, and a nullable enum body, which has no `format`, keeps nothing but the null:", - "axes": { - "openapi.OpenApiVersion": [ - "OpenApi2_0" - ], - "http.binding": [ - "body" - ], - "http.nullability": [ - "nullable" - ], - "shape.kind": [ - "sealed-record-class", - "validated-class" - ] - } - }, - { - "id": "enum-component-lists-the-null-of-its-first-use", - "source": "design/knowledge/KB-027-an-enum-component-is-its-first-use.md#kb-027-the-component-aspnet-makes-for-an-enum-written-by-name-is-the-schema-of-the-first-use-it-meets", - "sentence": "What the component says is whatever schema ASP.NET built for the first use it met: met first as a nullable parameter, the component lists null among its values, for its non-nullable uses too; met first as itself, it does not, for its nullable uses too.", - "axes": { - "json.Converters": [ - "JsonStringEnumConverter" - ], - "shape.wrapped": [ - "enum" - ] - } - }, - { - "id": "openapi-2-nullable-element-loses-its-type", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", - "sentence": "A nullable element of a list or a dictionary loses its type the same way, since it's the component or null too.", - "axes": { - "openapi.OpenApiVersion": [ - "OpenApi2_0" - ], - "openapi.CreateSchemaReferenceId": [ - "default", - "own-prefixing" - ], - "shape.position": [ - "list-element", - "array-element", - "immutable-array-element", - "read-only-list-element", - "dictionary-value" - ] - } - }, - { - "id": "a-librarys-converter-for-the-wrapped-type", - "source": "src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says", - "sentence": "The same goes for a converter a library registers for its own type, such as NodaTime's for `Instant`.", - "axes": { - "shape.wrapped": [ - "NodaTime.Instant" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - }, - { - "reason": "Not promised (a-closed-set-is-a-string-enum): a closed set wraps nothing and is described as the string enum of its names, so it has no underlying type's schema to equal.", - "pairs": [ - [ - "http.binding=route", - "shape.kind=closed-set" - ], - [ - "http.binding=query", - "shape.kind=closed-set" - ], - [ - "http.binding=header", - "shape.kind=closed-set" - ], - [ - "http.binding=body", - "shape.kind=closed-set" - ], - [ - "http.binding=form", - "shape.kind=closed-set" - ], - [ - "http.binding=as-parameters", - "shape.kind=closed-set" - ], - [ - "http.host=minimal", - "shape.kind=closed-set" - ], - [ - "http.host=mvc", - "shape.kind=closed-set" - ], - [ - "http.host=both", - "shape.kind=closed-set" - ], - [ - "http.host=route-group", - "shape.kind=closed-set" - ], - [ - "http.host=controller-without-ApiController-visible", - "shape.kind=closed-set" - ], - [ - "http.nullability=as-declared", - "shape.kind=closed-set" - ], - [ - "http.nullability=nullable", - "shape.kind=closed-set" - ], - [ - "http.response=result-to-http-result", - "shape.kind=closed-set" - ], - [ - "http.response=composed-fault", - "shape.kind=closed-set" - ], - [ - "http.response=two-faults-same-name", - "shape.kind=closed-set" - ], - [ - "http.response=group-with-fault-status", - "shape.kind=closed-set" - ], - [ - "http.response=endpoint-without-faults", - "shape.kind=closed-set" - ], - [ - "http.response=declared-produces-problem", - "shape.kind=closed-set" - ], - [ - "input.json=valid", - "shape.kind=closed-set" - ], - [ - "input.json=refused-by-create", - "shape.kind=closed-set" - ], - [ - "input.json=wrong-token", - "shape.kind=closed-set" - ], - [ - "input.json=null", - "shape.kind=closed-set" - ], - [ - "input.json=empty-string", - "shape.kind=closed-set" - ], - [ - "input.json=at-type-limit", - "shape.kind=closed-set" - ], - [ - "input.json=quoted-number", - "shape.kind=closed-set" - ], - [ - "input.json=escape-sequence", - "shape.kind=closed-set" - ], - [ - "input.json=duplicate-property", - "shape.kind=closed-set" - ], - [ - "input.json=metadata-property", - "shape.kind=closed-set" - ], - [ - "json.AllowDuplicateProperties=default", - "shape.kind=closed-set" - ], - [ - "json.AllowDuplicateProperties=false", - "shape.kind=closed-set" - ], - [ - "json.AllowOutOfOrderMetadataProperties=default", - "shape.kind=closed-set" - ], - [ - "json.AllowOutOfOrderMetadataProperties=true", - "shape.kind=closed-set" - ], - [ - "json.AllowTrailingCommas=default", - "shape.kind=closed-set" - ], - [ - "json.AllowTrailingCommas=true", - "shape.kind=closed-set" - ], - [ - "json.Converters=default", - "shape.kind=closed-set" - ], - [ - "json.Converters=JsonStringEnumConverter", - "shape.kind=closed-set" - ], - [ - "json.Converters=StoredJsonConverterFactory", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=default", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenWritingDefault", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenWritingNull", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenWriting", - "shape.kind=closed-set" - ], - [ - "json.DefaultIgnoreCondition=WhenReading", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=default", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=CamelCase", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=SnakeCaseLower", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=KebabCaseUpper", - "shape.kind=closed-set" - ], - [ - "json.DictionaryKeyPolicy=own-upper-case", - "shape.kind=closed-set" - ], - [ - "json.Encoder=default", - "shape.kind=closed-set" - ], - [ - "json.Encoder=UnsafeRelaxedJsonEscaping", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyFields=default", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyFields=true", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyProperties=default", - "shape.kind=closed-set" - ], - [ - "json.IgnoreReadOnlyProperties=true", - "shape.kind=closed-set" - ], - [ - "json.IncludeFields=default", - "shape.kind=closed-set" - ], - [ - "json.IncludeFields=true", - "shape.kind=closed-set" - ], - [ - "json.MaxDepth=default", - "shape.kind=closed-set" - ], - [ - "json.MaxDepth=3", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=default", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=AllowReadingFromString", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=WriteAsString", - "shape.kind=closed-set" - ], - [ - "json.NumberHandling=AllowNamedFloatingPointLiterals", - "shape.kind=closed-set" - ], - [ - "json.PreferredObjectCreationHandling=default", - "shape.kind=closed-set" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "shape.kind=closed-set" - ], - [ - "json.PropertyNameCaseInsensitive=default", - "shape.kind=closed-set" - ], - [ - "json.PropertyNameCaseInsensitive=true", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=default", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=CamelCase", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=SnakeCaseLower", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=SnakeCaseUpper", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=KebabCaseLower", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=KebabCaseUpper", - "shape.kind=closed-set" - ], - [ - "json.PropertyNamingPolicy=own-upper-case", - "shape.kind=closed-set" - ], - [ - "json.ReadCommentHandling=default", - "shape.kind=closed-set" - ], - [ - "json.ReadCommentHandling=Skip", - "shape.kind=closed-set" - ], - [ - "json.ReferenceHandler=default", - "shape.kind=closed-set" - ], - [ - "json.ReferenceHandler=Preserve", - "shape.kind=closed-set" - ], - [ - "json.ReferenceHandler=IgnoreCycles", - "shape.kind=closed-set" - ], - [ - "json.RespectNullableAnnotations=default", - "shape.kind=closed-set" - ], - [ - "json.RespectNullableAnnotations=true", - "shape.kind=closed-set" - ], - [ - "json.RespectRequiredConstructorParameters=default", - "shape.kind=closed-set" - ], - [ - "json.RespectRequiredConstructorParameters=true", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolver=default", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolver=source-generated-context", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolver=default-with-renaming-modifier", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolverChain=default", - "shape.kind=closed-set" - ], - [ - "json.TypeInfoResolverChain=context-then-default", - "shape.kind=closed-set" - ], - [ - "json.UnknownTypeHandling=default", - "shape.kind=closed-set" - ], - [ - "json.UnknownTypeHandling=JsonNode", - "shape.kind=closed-set" - ], - [ - "json.UnmappedMemberHandling=default", - "shape.kind=closed-set" - ], - [ - "json.UnmappedMemberHandling=Disallow", - "shape.kind=closed-set" - ], - [ - "mvc.AllowEmptyInputInBodyModelBinding=default", - "shape.kind=closed-set" - ], - [ - "mvc.AllowEmptyInputInBodyModelBinding=true", - "shape.kind=closed-set" - ], - [ - "mvc.Conventions=default", - "shape.kind=closed-set" - ], - [ - "mvc.Conventions=own-route-prefix", - "shape.kind=closed-set" - ], - [ - "mvc.InputFormatters=default", - "shape.kind=closed-set" - ], - [ - "mvc.InputFormatters=xml-added", - "shape.kind=closed-set" - ], - [ - "mvc.MaxModelBindingCollectionSize=default", - "shape.kind=closed-set" - ], - [ - "mvc.MaxModelBindingCollectionSize=2", - "shape.kind=closed-set" - ], - [ - "mvc.MaxModelValidationErrors=default", - "shape.kind=closed-set" - ], - [ - "mvc.MaxModelValidationErrors=1", - "shape.kind=closed-set" - ], - [ - "mvc.MaxValidationDepth=default", - "shape.kind=closed-set" - ], - [ - "mvc.MaxValidationDepth=1", - "shape.kind=closed-set" - ], - [ - "mvc.ModelBinderProviders=default", - "shape.kind=closed-set" - ], - [ - "mvc.ModelBinderProviders=own-provider-first", - "shape.kind=closed-set" - ], - [ - "mvc.OutputFormatters=default", - "shape.kind=closed-set" - ], - [ - "mvc.OutputFormatters=xml-added", - "shape.kind=closed-set" - ], - [ - "mvc.RespectBrowserAcceptHeader=default", - "shape.kind=closed-set" - ], - [ - "mvc.RespectBrowserAcceptHeader=true", - "shape.kind=closed-set" - ], - [ - "mvc.ReturnHttpNotAcceptable=default", - "shape.kind=closed-set" - ], - [ - "mvc.ReturnHttpNotAcceptable=true", - "shape.kind=closed-set" - ], - [ - "mvc.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes=default", - "shape.kind=closed-set" - ], - [ - "mvc.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes=true", - "shape.kind=closed-set" - ], - [ - "mvc.ValidateComplexTypesIfChildValidationFails=default", - "shape.kind=closed-set" - ], - [ - "mvc.ValidateComplexTypesIfChildValidationFails=true", - "shape.kind=closed-set" - ], - [ - "openapi.CreateSchemaReferenceId=default", - "shape.kind=closed-set" - ], - [ - "openapi.CreateSchemaReferenceId=own-prefixing", - "shape.kind=closed-set" - ], - [ - "openapi.CreateSchemaReferenceId=null-inlines-all", - "shape.kind=closed-set" - ], - [ - "openapi.OpenApiVersion=default", - "shape.kind=closed-set" - ], - [ - "openapi.OpenApiVersion=OpenApi2_0", - "shape.kind=closed-set" - ], - [ - "openapi.OpenApiVersion=OpenApi3_0", - "shape.kind=closed-set" - ], - [ - "openapi.transformers=default", - "shape.kind=closed-set" - ], - [ - "openapi.transformers=own-schema-transformer", - "shape.kind=closed-set" - ], - [ - "openapi.transformers=own-operation-transformer", - "shape.kind=closed-set" - ], - [ - "openapi.transformers=own-document-transformer", - "shape.kind=closed-set" - ], - [ - "process.converter-lookup=none", - "shape.kind=closed-set" - ], - [ - "process.converter-lookup=wrapped-type-converter-looked-up-first", - "shape.kind=closed-set" - ], - [ - "shape.containing=class", - "shape.kind=closed-set" - ], - [ - "shape.containing=record-class", - "shape.kind=closed-set" - ], - [ - "shape.containing=struct", - "shape.kind=closed-set" - ], - [ - "shape.containing=record-struct", - "shape.kind=closed-set" - ], - [ - "shape.containing=generic-type", - "shape.kind=closed-set" - ], - [ - "shape.kind=closed-set", - "shape.position=root" - ], - [ - "shape.kind=closed-set", - "shape.position=property" - ], - [ - "shape.kind=closed-set", - "shape.position=nullable-property" - ], - [ - "shape.kind=closed-set", - "shape.position=field" - ], - [ - "shape.kind=closed-set", - "shape.position=list-element" - ], - [ - "shape.kind=closed-set", - "shape.position=array-element" - ], - [ - "shape.kind=closed-set", - "shape.position=immutable-array-element" - ], - [ - "shape.kind=closed-set", - "shape.position=read-only-list-element" - ], - [ - "shape.kind=closed-set", - "shape.position=dictionary-key" - ], - [ - "shape.kind=closed-set", - "shape.position=dictionary-value" - ], - [ - "shape.kind=closed-set", - "shape.position=record-ctor-parameter" - ], - [ - "shape.kind=closed-set", - "shape.position=required-init" - ], - [ - "shape.kind=closed-set", - "shape.position=in-patch" - ], - [ - "shape.kind=closed-set", - "shape.position=polymorphic-derived-property" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ] - ] - } - ] - }, - { - "id": "E01-column-parity", - "source": "docs/ef-core.md#the-model", - "surfaces": [ - "ef" - ], - "axes": { - "ef.mapping": [ - "property", - "nullable", - "key", - "owned", - "complex" - ], - "ef.facet": [ - "none", - "HasMaxLength", - "HavePrecision", - "HasColumnType" - ], - "shape.wrapped": [ - "string", - "Guid", - "int", - "long", - "byte", - "ulong", - "decimal", - "double", - "bool", - "char", - "DateTime", - "DateTimeOffset", - "DateOnly", - "TimeOnly", - "TimeSpan", - "enum", - "flags-enum", - "Uri" - ], - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ] - }, - "narrow": { - "ef.query": "Every property maps as a column of the underlying type, nullable where the property is." - }, - "obligations": [ - { - "id": "column-type", - "sentence": "Every property maps as a column of the underlying type, nullable where the property is.", - "axes": { - "ef.mapping": [ - "property", - "key", - "owned", - "complex" - ] - } - }, - { - "id": "nullable", - "sentence": "nullable where the property is", - "axes": { - "ef.mapping": [ - "nullable" - ] - } - }, - { - "id": "facet-kept", - "sentence": "A facet you configure on it is kept: a precision, a length, a column type.", - "axes": { - "ef.facet": [ - "HasMaxLength", - "HavePrecision", - "HasColumnType" - ] - } - } - ], - "not-promised": [ - { - "id": "char-key-not-generated", - "source": "docs/ef-core.md#keys", - "sentence": "A key over `char` is always yours to assign", - "axes": { - "ef.mapping": [ - "key" - ], - "shape.wrapped": [ - "char" - ] - } - }, - { - "id": "guid-key-not-generated", - "source": "docs/ef-core.md#keys", - "sentence": "A key over a `Guid` is yours to assign", - "axes": { - "ef.mapping": [ - "key" - ], - "shape.wrapped": [ - "Guid" - ] - } - } - ] - }, - { - "id": "E02-value-translates-to-column", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "surfaces": [ - "ef" - ], - "axes": { - "ef.query": [ - "where-equals", - "where-value-compare", - "order-by", - "contains", - "select", - "group-by" - ], - "ef.accessor": [ - "Value", - "GetValue", - "ValueOrNull" - ], - "shape.wrapped": [ - "string", - "Guid", - "int", - "long", - "byte", - "ulong", - "decimal", - "double", - "bool", - "char", - "DateTime", - "DateTimeOffset", - "DateOnly", - "TimeOnly", - "TimeSpan", - "enum", - "flags-enum", - "Uri" - ], - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ] - }, - "narrow": { - "ef.mapping": "`.Value`, `GetValue()` and `ValueOrNull()` translate to the column itself." - }, - "obligations": [ - { - "id": "value", - "sentence": "`.Value`, `GetValue()` and `ValueOrNull()` translate to the column itself.", - "axes": { - "ef.accessor": [ - "Value" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.wrapped": [ - "DateTimeOffset", - "TimeSpan", - "ulong" - ], - "ef.query": [ - "where-value-compare", - "order-by" - ] - }, - "cite": "fact:KB-039" - } - ] - }, - { - "id": "get-value", - "sentence": "db.Orders.Where(o => o.Total.GetValue() > 100m);", - "axes": { - "ef.accessor": [ - "GetValue" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.wrapped": [ - "DateTimeOffset", - "TimeSpan", - "ulong" - ], - "ef.query": [ - "where-value-compare", - "order-by" - ] - }, - "cite": "fact:KB-039" - } - ] - }, - { - "id": "value-or-null", - "sentence": "Use `ValueOrNull()` for an optional value object, where `.Value` would first unwrap the `Nullable`.", - "axes": { - "ef.accessor": [ - "ValueOrNull" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.wrapped": [ - "DateTimeOffset", - "TimeSpan", - "ulong" - ], - "ef.query": [ - "where-value-compare", - "order-by" - ] - }, - "cite": "fact:KB-039" - } - ] - }, - { - "id": "column-not-cast", - "sentence": "A table's column is re-typed, not cast, so an index on it still serves the query.", - "inapplicable": [ - { - "axes": { - "shape.wrapped": [ - "DateTimeOffset", - "TimeSpan", - "ulong" - ], - "ef.query": [ - "where-value-compare", - "order-by" - ] - }, - "cite": "fact:KB-039" - } - ] - } - ], - "not-promised": [ - { - "id": "null-passes-no-comparison", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "sentence": "A null passes no `<`, `<=`, `>` or `>=` in the database.", - "axes": { - "ef.accessor": [ - "ValueOrNull" - ], - "ef.query": [ - "where-value-compare" - ] - } - }, - { - "id": "collation-orders", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "sentence": "Ordering in SQL follows the database's collation", - "axes": { - "ef.query": [ - "order-by" - ], - "shape.wrapped": [ - "string" - ] - } - } - ], - "exclude": [ - { - "reason": "C# defines no `>=` for a `string`, a `bool` or a `Uri`, so no query compares their `.Value` with it; E02ValueTranslatesProbe writes where-equals in its place there, so no row holds the pair.", - "pairs": [ - [ - "ef.query=where-value-compare", - "shape.wrapped=string" - ], - [ - "ef.query=where-value-compare", - "shape.wrapped=bool" - ], - [ - "ef.query=where-value-compare", - "shape.wrapped=Uri" - ] - ] - } - ] - }, - { - "id": "E03-column-round-trip", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#what-maps", - "surfaces": [ - "ef" - ], - "axes": { - "ef.mapping": [ - "property", - "nullable", - "key", - "owned", - "complex" - ], - "shape.wrapped": [ - "string", - "Guid", - "int", - "long", - "byte", - "ulong", - "decimal", - "double", - "bool", - "char", - "DateTime", - "DateTimeOffset", - "DateOnly", - "TimeOnly", - "TimeSpan", - "enum", - "flags-enum", - "Uri" - ], - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ] - }, - "narrow": { - "ef.query": "Keys, foreign keys, nullable properties, primitive collections and query parameters all map as plain columns of the underlying type." - }, - "obligations": [ - { - "id": "stored-as-underlying", - "sentence": "Every value object is stored in a plain column of its underlying type", - "axes": { - "ef.mapping": [ - "property", - "owned", - "complex" - ] - } - }, - { - "id": "keys", - "sentence": "Keys, foreign keys, nullable properties, primitive collections and query parameters all map as plain columns of the underlying type.", - "axes": { - "ef.mapping": [ - "key" - ] - } - }, - { - "id": "nullable-properties", - "sentence": "Keys, foreign keys, nullable properties, primitive collections and query parameters all map as plain columns of the underlying type.", - "axes": { - "ef.mapping": [ - "nullable" - ] - } - } - ] - }, - { - "id": "E04-integer-key-generated", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "surfaces": [ - "ef" - ], - "axes": { - "shape.wrapped": [ - "int", - "long", - "byte", - "ulong", - "char", - "Guid", - "string" - ], - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "ef.key-config": [ - "default", - "ValueGeneratedOnAdd", - "ValueGeneratedNever" - ] - }, - "narrow": { - "ef.query": "A single-column key over an integer is generated on add, like a key of that integer type.", - "ef.mapping": "A single-column key over an integer is generated on add, like a key of that integer type.", - "shape.site": "A single-column key over an integer is generated on add, like a key of that integer type." - }, - "obligations": [ - { - "id": "generated-on-add", - "sentence": "A single-column key over an integer is generated on add, like a key of that integer type.", - "axes": { - "shape.wrapped": [ - "int", - "long", - "ulong" - ] - } - }, - { - "id": "byte-not-generated", - "sentence": "That's EF's own list: `int`, `long`, `short`, `sbyte`, `uint`, `ulong` and `ushort`, and not `byte`.", - "axes": { - "shape.wrapped": [ - "byte" - ] - } - }, - { - "id": "char-key-yours", - "sentence": "A key over `char` is yours to assign.", - "axes": { - "shape.wrapped": [ - "char" - ], - "ef.key-config": [ - "default" - ] - } - }, - { - "id": "guid-key-yours", - "sentence": "A key over a `Guid` is yours to assign", - "axes": { - "shape.wrapped": [ - "Guid" - ], - "ef.key-config": [ - "default" - ] - } - }, - { - "id": "not-on-efs-list", - "sentence": "That's EF's own list: `int`, `long`, `short`, `sbyte`, `uint`, `ulong` and `ushort`, and not `byte`.", - "axes": { - "shape.wrapped": [ - "string" - ], - "ef.key-config": [ - "default" - ] - } - }, - { - "id": "own-configuration-wins", - "sentence": "A configuration you write yourself always wins over these defaults.", - "axes": { - "shape.wrapped": [ - "char", - "Guid", - "string" - ], - "ef.key-config": [ - "ValueGeneratedOnAdd", - "ValueGeneratedNever" - ] - } - } - ], - "not-promised": [ - { - "id": "meaningful-char-key-unchecked", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "sentence": "TypeKit stops that invented value, but it doesn't check that you set a meaningful one.", - "axes": { - "shape.wrapped": [ - "char" - ], - "ef.key-config": [ - "default" - ] - } - }, - { - "id": "ulong-key-on-a-decimal-column", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "sentence": "A default key over `ulong` throws at `Add` where the column is a `decimal`", - "axes": { - "shape.wrapped": [ - "ulong" - ], - "provider": [ - "SQL Server", - "PostgreSQL" - ] - } - } - ] - }, - { - "id": "E05-own-compareto-rejected", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "surfaces": [ - "ef" - ], - "axes": { - "ef.op": [ - "lt", - "gt", - "le", - "ge", - "CompareTo", - "OrderBy", - "OrderByDescending", - "ThenBy", - "Order", - "Min", - "Max", - "equals", - "HasQueryFilter", - "named-query-filter", - "value-order" - ], - "ef.vo": [ - "int-struct", - "string-struct", - "decimal-struct", - "DateTime-struct", - "int-class", - "string-class" - ] - }, - "narrow": { - "ef.query": "Your own `CompareTo(TSelf)` can't run in the database.", - "ef.mapping": "Your own `CompareTo(TSelf)` can't run in the database.", - "shape.kind": "Your own `CompareTo(TSelf)` can't run in the database.", - "shape.wrapped": "Your own `CompareTo(TSelf)` can't run in the database.", - "shape.site": "Your own `CompareTo(TSelf)` can't run in the database." - }, - "obligations": [ - { - "id": "comparison", - "sentence": "a comparison (`<`, `>`, `<=`, `>=`, `CompareTo`);", - "axes": { - "ef.op": [ - "lt", - "gt", - "le", - "ge", - "CompareTo" - ] - } - }, - { - "id": "ordering", - "sentence": "an ordering (`OrderBy`, `ThenBy`, their descending forms, `Order`);", - "axes": { - "ef.op": [ - "OrderBy", - "OrderByDescending", - "ThenBy", - "Order" - ] - } - }, - { - "id": "min-max", - "sentence": "`Min` or `Max`.", - "axes": { - "ef.op": [ - "Min", - "Max" - ] - } - }, - { - "id": "equality-allowed", - "sentence": "Equality isn't ordering, and stays allowed.", - "axes": { - "ef.op": [ - "equals" - ] - } - }, - { - "id": "value-order-allowed", - "sentence": "Compare or order by `.Value` where the underlying value's order is what you mean", - "axes": { - "ef.op": [ - "value-order" - ] - } - }, - { - "id": "query-filter", - "sentence": "A query filter (`HasQueryFilter`, named or not) that does the same fails when the model is built, naming the entity type, since it applies to every query of that type.", - "axes": { - "ef.op": [ - "HasQueryFilter", - "named-query-filter" - ] - } - } - ], - "not-promised": [ - { - "id": "collation-orders", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "sentence": "Ordering in SQL follows the database's collation", - "axes": { - "ef.op": [ - "value-order" - ], - "ef.vo": [ - "string-struct", - "string-class" - ] - } - } - ] - }, - { - "id": "E06-own-converter-no-value", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "surfaces": [ - "ef" - ], - "axes": { - "ef.converter": [ - "HasConversion-lambda", - "converter-type", - "ConfigureConventions" - ], - "ef.op": [ - "value-access", - "vo-equality" - ], - "shape.wrapped": [ - "string", - "int", - "Guid", - "decimal" - ] - }, - "narrow": { - "ef.query": "A property your application converts itself", - "ef.mapping": "A property your application converts itself", - "shape.kind": "A property your application converts itself", - "shape.site": "A property your application converts itself" - }, - "obligations": [ - { - "id": "value-not-translated", - "sentence": "So a filter, a sort, a grouping or an aggregate that reads `.Value` there fails with EF's \"could not be translated\", rather than comparing against what the column really holds.", - "axes": { - "ef.op": [ - "value-access" - ] - } - }, - { - "id": "value-object-comparison", - "sentence": "Comparing the value object itself (`o.Code == code`) goes through that converter and still works.", - "axes": { - "ef.op": [ - "vo-equality" - ] - } - } - ] - }, - { - "id": "E07-closed-set-stored-as-name", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#closed-sets", - "surfaces": [ - "ef" - ], - "axes": { - "ef.site": [ - "table", - "primitive-collection", - "json-column" - ], - "ef.event": [ - "round-trip", - "unknown-name-on-read", - "non-member-on-write" - ] - }, - "narrow": { - "ef.query": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", - "ef.mapping": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", - "shape.kind": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", - "shape.wrapped": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", - "shape.site": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself." - }, - "obligations": [ - { - "id": "stored-as-name", - "sentence": "A closed set (`IClosedSet`) is stored as a text column of the member's name, and read back as the member itself.", - "axes": { - "ef.event": [ - "round-trip" - ] - } - }, - { - "id": "in-collections-and-json", - "sentence": "That holds in a table, in a primitive collection of names (`text[]` on PostgreSQL, a JSON array elsewhere) and in a JSON column alike, with nothing registered per set.", - "axes": { - "ef.site": [ - "primitive-collection", - "json-column" - ], - "ef.event": [ - "round-trip" - ] - } - }, - { - "id": "unknown-name-throws", - "sentence": "A name the set no longer has throws when it's read, rather than reading as null.", - "axes": { - "ef.event": [ - "unknown-name-on-read" - ] - } - }, - { - "id": "non-member-throws", - "sentence": "An instance that isn't a member throws when it's written.", - "axes": { - "ef.event": [ - "non-member-on-write" - ] - } - } - ] - }, - { - "id": "E08-option-result-not-columns", - "source": "docs/ef-core.md#option-and-result", - "surfaces": [ - "ef" - ], - "axes": { - "ef.type": [ - "Option-int", - "Option-VO", - "Result-int-E", - "Result-VO-E", - "Result-E" - ], - "ef.position": [ - "property", - "key", - "collection", - "owned-property" - ], - "shape.wrapped": [ - "string", - "int", - "Guid" - ] - }, - "narrow": { - "ef.query": "EF can't map an `Option` or a `Result` property, and building the model fails with an error that says so.", - "ef.mapping": "EF can't map an `Option` or a `Result` property, and building the model fails with an error that says so.", - "shape.kind": "EF can't map an `Option` or a `Result` property, and building the model fails with an error that says so.", - "shape.site": "EF can't map an `Option` or a `Result` property, and building the model fails with an error that says so." - }, - "obligations": [ - { - "id": "model-fails", - "sentence": "EF can't map an `Option` or a `Result` property" - }, - { - "id": "error-says-so", - "sentence": "building the model fails with an error that says so" - } - ] - }, - { - "id": "E09-or-none-in-database", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", - "surfaces": [ - "ef" - ], - "axes": { - "ef.operator": [ - "FirstOrNoneAsync", - "FirstOrNone", - "SingleOrNoneAsync", - "SingleOrNone", - "ElementAtOrNone", - "FirstOrError" - ], - "ef.data": [ - "empty", - "one-match", - "many-match" - ], - "ef.condition": [ - "lambda", - "expression-variable" - ], - "shape.wrapped": [ - "int", - "Guid", - "string" - ] - }, - "narrow": { - "ef.query": "These ask the database for one row and let it run the condition:", - "ef.mapping": "These ask the database for one row and let it run the condition:", - "shape.kind": "These ask the database for one row and let it run the condition:", - "shape.site": "These ask the database for one row and let it run the condition:" - }, - "obligations": [ - { - "id": "first-reads-one-row", - "sentence": "read one row: `WHERE ... LIMIT @p`.", - "axes": { - "ef.operator": [ - "FirstOrNoneAsync", - "FirstOrNone", - "FirstOrError" - ] - } - }, - { - "id": "single-asks-for-two", - "sentence": "ask for two rows, and throw for more than one.", - "axes": { - "ef.operator": [ - "SingleOrNoneAsync", - "SingleOrNone" - ] - } - }, - { - "id": "element-at-skips", - "sentence": "skips to its row: `OFFSET @p`.", - "axes": { - "ef.operator": [ - "ElementAtOrNone" - ] - } - } - ], - "not-promised": [ - { - "id": "func-condition-runs-in-memory", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", - "sentence": "Then every row is read and the condition runs in memory, without a warning.", - "axes": { - "ef.condition": [ - "func-variable", - "method-group" - ] - } - }, - { - "id": "last-on-a-query-does-not-compile", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", - "sentence": "`LastOrNone` and `LastOrError` on a query don't compile.", - "axes": { - "ef.operator": [ - "LastOrNone", - "LastOrError" - ] - } - }, - { - "id": "not-precompiled-under-native-aot", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#an-option-for-nothing-found", - "sentence": "Under Native AOT these throw \"Query wasn't precompiled\"", - "axes": { - "process": [ - "native-aot" - ] - } - } - ] - }, - { - "id": "E10-read-back-skips-validation", - "source": "docs/ef-core.md#reading-back-without-validation", - "surfaces": [ - "ef" - ], - "axes": { - "ef.mapping": [ - "property", - "key", - "nullable", - "owned", - "complex" - ], - "shape.wrapped": [ - "string", - "int", - "Guid", - "decimal", - "DateTime", - "Uri" - ], - "shape.kind": [ - "validated-struct", - "validated-class" - ] - }, - "narrow": { - "ef.query": "EF reads a column back without validation, through the value object's `Materialize` rather than `Create`.", - "shape.site": "EF reads a column back without validation, through the value object's `Materialize` rather than `Create`." - }, - "obligations": [ - { - "id": "reads-without-create", - "sentence": "EF reads a column back without validation, through the value object's `Materialize` rather than `Create`." - }, - { - "id": "revalidate-finds", - "sentence": "`Revalidate()` finds the rows that today's rules reject, as above." - } - ] - }, - { - "id": "E11-usetypekit-order", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#setup", - "surfaces": [ - "ef" - ], - "axes": { - "ef.order": [ - "before-provider", - "after-provider" - ], - "ef.mapping": [ - "property", - "key", - "integer-key", - "nullable", - "owned", - "complex", - "closed-set" - ] - }, - "narrow": { - "ef.query": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`", - "shape.kind": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`", - "shape.site": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`", - "shape.wrapped": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`" - }, - "obligations": [ - { - "id": "order-does-not-matter", - "sentence": "it doesn't matter whether you call it before or after `UseNpgsql` or `UseSqlite`" - } - ], - "not-promised": [ - { - "id": "in-memory-provider-maps-nothing", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#setup", - "sentence": "EF's in-memory provider has no relational type mapping, so nothing is mapped there.", - "axes": { - "ef.provider": [ - "InMemory" - ] - } - } - ] - }, - { - "id": "E12-convention-by-vo-type", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#model-wide-conventions-follow-the-propertys-type", - "surfaces": [ - "ef" - ], - "axes": { - "ef.convention": [ - "HaveMaxLength", - "HavePrecision", - "HaveColumnType" - ], - "ef.convention-type": [ - "value-object", - "underlying" - ], - "shape.wrapped": [ - "string", - "decimal", - "Uri", - "int" - ] - }, - "narrow": { - "ef.query": "Configure the value object instead:", - "ef.mapping": "Configure the value object instead:", - "shape.site": "Configure the value object instead:", - "shape.kind": "Configure the value object instead:" - }, - "obligations": [ - { - "id": "value-object-type-reaches", - "sentence": "Configure the value object instead: `configurationBuilder.Properties().HavePrecision(18, 2)`.", - "axes": { - "ef.convention-type": [ - "value-object" - ] - } - }, - { - "id": "underlying-type-does-not-reach", - "sentence": "So `configurationBuilder.Properties().HavePrecision(18, 2)` reaches `decimal` properties, and not an `Amount` that wraps one.", - "axes": { - "ef.convention-type": [ - "underlying" - ] - } - } - ], - "not-promised": [ - { - "id": "underlying-type-convention", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#model-wide-conventions-follow-the-propertys-type", - "sentence": "EF applies `ConfigureConventions` by CLR type.", - "axes": { - "ef.convention-type": [ - "underlying" - ] - } - } - ] - }, - { - "id": "E13-primitive-collections", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "surfaces": [ - "ef" - ], - "axes": { - "ef.query": [ - "contains", - "any-value-equals" - ], - "shape.wrapped": [ - "string", - "int", - "Guid", - "long", - "decimal" - ] - }, - "narrow": { - "ef.mapping": "db.Orders.Where(o => o.Tags.Contains(tag));", - "shape.site": "db.Orders.Where(o => o.Tags.Contains(tag));", - "shape.kind": "db.Orders.Where(o => o.Tags.Contains(tag));" - }, - "obligations": [ - { - "id": "contains", - "sentence": "db.Orders.Where(o => o.Tags.Contains(tag));", - "axes": { - "ef.query": [ - "contains" - ] - } - }, - { - "id": "element-value", - "sentence": "db.Orders.Where(o => o.Tags.Any(t => t.Value == \"x\"));", - "axes": { - "ef.query": [ - "any-value-equals" - ] - } - } - ], - "not-promised": [ - { - "id": "element-converted-may-cast", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries", - "sentence": "These are converted instead, which works everywhere and may add a cast:", - "axes": { - "ef.query": [ - "any-value-equals" - ] - } - } - ] - }, - { - "id": "E14-inheritance-key-generation", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "surfaces": [ - "ef" - ], - "axes": { - "ef.inheritance": [ - "TPH", - "TPT", - "TPC" - ], - "shape.wrapped": [ - "int", - "long", - "Guid" - ] - }, - "narrow": { - "ef.query": "The root of an inheritance hierarchy follows the same rules under TPH and TPT.", - "ef.mapping": "The root of an inheritance hierarchy follows the same rules under TPH and TPT.", - "shape.site": "The root of an inheritance hierarchy follows the same rules under TPH and TPT.", - "shape.kind": "The root of an inheritance hierarchy follows the same rules under TPH and TPT." - }, - "obligations": [ - { - "id": "tph-tpt-root", - "sentence": "The root of an inheritance hierarchy follows the same rules under TPH and TPT.", - "axes": { - "ef.inheritance": [ - "TPH", - "TPT" - ] - } - }, - { - "id": "tpc-assign-on-sqlite", - "sentence": "SQLite has no such sequence, so there you assign it.", - "axes": { - "ef.inheritance": [ - "TPC" - ] - } - } - ], - "not-promised": [ - { - "id": "guid-key-not-generated", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "sentence": "A key over a `Guid` is yours to assign", - "axes": { - "shape.wrapped": [ - "Guid" - ] - } - } - ] - }, - { - "id": "E15-composite-key", - "source": "docs/ef-core.md#keys", - "surfaces": [ - "ef" - ], - "axes": { - "shape.wrapped": [ - "int", - "Guid", - "string", - "long" - ], - "ef.key-position": [ - "first", - "second" - ] - }, - "narrow": { - "ef.query": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives.", - "ef.mapping": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives.", - "shape.site": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives.", - "shape.kind": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives." - }, - "obligations": [ - { - "id": "as-for-primitives", - "sentence": "A composite key of value objects is `HasKey(x => new { x.Order, x.Line })`, as for primitives." - } - ] - }, - { - "id": "E16-own-configuration-wins", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "surfaces": [ - "ef" - ], - "axes": { - "ef.config": [ - "ValueGeneratedNever", - "ValueGeneratedOnAdd", - "HasConversion", - "HasColumnType", - "IsRequired-false" - ], - "shape.wrapped": [ - "int", - "long", - "char", - "Guid", - "string" - ] - }, - "narrow": { - "ef.query": "A configuration you write yourself always wins over these defaults.", - "ef.mapping": "A configuration you write yourself always wins over these defaults.", - "shape.site": "A configuration you write yourself always wins over these defaults.", - "shape.kind": "A configuration you write yourself always wins over these defaults." - }, - "obligations": [ - { - "id": "never", - "sentence": "A configuration you write yourself always wins over these defaults.", - "axes": { - "ef.config": [ - "ValueGeneratedNever" - ] - } - }, - { - "id": "on-add", - "sentence": "A configuration you write yourself always wins over these defaults.", - "axes": { - "ef.config": [ - "ValueGeneratedOnAdd" - ] - } - }, - { - "id": "column-type", - "sentence": "A facet you configure on the property, such as a maximum length or a column type, is kept.", - "axes": { - "ef.config": [ - "HasColumnType" - ] - } - }, - { - "id": "conversion", - "sentence": "A configuration you write yourself always wins over these defaults.", - "axes": { - "ef.config": [ - "HasConversion" - ] - } - }, - { - "id": "optional", - "sentence": "A configuration you write yourself always wins over these defaults.", - "axes": { - "ef.config": [ - "IsRequired-false" - ] - } - } - ], - "not-promised": [ - { - "id": "char-key-not-generated", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "sentence": "A key over `char` is yours to assign.", - "axes": { - "ef.config": [ - "HasColumnType", - "HasConversion" - ], - "shape.wrapped": [ - "char" - ] - } - }, - { - "id": "guid-key-not-generated", - "source": "src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#keys", - "sentence": "A key over a `Guid` is yours to assign", - "axes": { - "ef.config": [ - "HasColumnType", - "HasConversion" - ], - "shape.wrapped": [ - "Guid" - ] - } - } - ] - }, - { - "id": "L01-json-bytes", - "source": "README.md#what-typekit-guarantees", - "surfaces": [ - "json" - ], - "obligations": [ - { - "id": "the-underlying-types-json", - "sentence": "Its JSON is the underlying type's under your options", - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "byte" - ], - "shape.position": [ - "array-element" - ] - }, - "cite": "not-promised:a-byte-array-is-base64" - } - ] - }, - { - "id": "as-a-dictionary-key-too", - "sentence": "Its JSON is the underlying type's under your options", - "axes": { - "shape.position": [ - "dictionary-key" - ] - }, - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-value-object" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says" - }, - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "shape.position": [ - "dictionary-key" - ], - "json.DictionaryKeyPolicy": [ - "CamelCase", - "SnakeCaseLower", - "KebabCaseUpper", - "own-upper-case" - ] - }, - "cite": "not-promised:a-closed-set-key-is-its-name" - } - ] - }, - { - "id": "read-as-the-underlying-type-reads", - "sentence": "**Swapping a primitive for a value object keeps the JSON, the column and the schema.**", - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "byte" - ], - "shape.position": [ - "array-element" - ] - }, - "cite": "not-promised:a-byte-array-is-base64" - }, - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "shape.position": [ - "dictionary-key" - ], - "json.DictionaryKeyPolicy": [ - "CamelCase", - "SnakeCaseLower", - "KebabCaseUpper", - "own-upper-case" - ] - }, - "cite": "not-promised:a-closed-set-key-is-its-name" - } - ] - } - ], - "not-promised": [ - { - "id": "a-datetime-is-written-as-utc", - "source": "README.md#what-typekit-guarantees", - "sentence": "Its JSON is the underlying type's under your options, with two exceptions: a `DateTime` is written as UTC", - "axes": { - "shape.wrapped": [ - "DateTime" - ] - } - }, - { - "id": "number-handling-on-the-containing-type", - "source": "README.md#what-typekit-guarantees", - "sentence": "and no converter sees number handling set by an attribute on the containing type" - }, - { - "id": "a-struct-refuses-a-json-null", - "source": "README.md#what-typekit-guarantees", - "sentence": "What changes is what the value object rejects, a JSON `null` for a struct value object included.", - "axes": { - "input.json": [ - "null" - ], - "shape.kind": [ - "record-struct", - "validated-struct" - ] - } - }, - { - "id": "a-validated-value-object-refuses-what-create-refuses", - "source": "README.md#what-typekit-guarantees", - "sentence": "What changes is what the value object rejects", - "axes": { - "input.json": [ - "refused-by-create" - ], - "shape.kind": [ - "validated-struct", - "validated-class" - ] - } - }, - { - "id": "an-enum-under-a-source-generated-context", - "source": "README.md#what-typekit-guarantees", - "sentence": "And under a source-generated context, a value object over an enum needs its enum listed", - "axes": { - "json.TypeInfoResolver": [ - "source-generated-context" - ], - "shape.wrapped": [ - "enum", - "flags-enum" - ] - } - }, - { - "id": "preserved-references-over-a-walked-class", - "source": "src/CodoMetis.TypeKit.Generators/README.md#json", - "sentence": "**Preserved references** (`ReferenceHandler.Preserve`) throw a `NotSupportedException` where the serializer could write `$id` or `$ref` inside the underlying value.", - "axes": { - "json.ReferenceHandler": [ - "Preserve" - ], - "shape.wrapped": [ - "own-record-class" - ] - } - }, - { - "id": "a-closed-set-key-is-its-name", - "source": "docs/closed-sets.md#send-it-as-json", - "sentence": "No naming policy renames it, because a renamed name wouldn't read back.", - "axes": { - "shape.kind": [ - "closed-set" - ], - "shape.position": [ - "dictionary-key" - ] - } - }, - { - "id": "a-byte-array-is-base64", - "source": "docs/json.md#the-wrapped-types-json", - "sentence": "An array of value objects over `byte` is a JSON array of numbers.", - "axes": { - "shape.wrapped": [ - "byte" - ], - "shape.position": [ - "array-element" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "L02-no-quote", - "source": "README.md#what-typekit-guarantees", - "surfaces": [ - "json", - "text", - "logging" - ], - "obligations": [ - { - "id": "parsing-never-repeats", - "sentence": "**Rejections never repeat the input.**", - "axes": { - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "Uri", - "enum", - "flags-enum", - "NodaTime.Instant" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#closed-sets" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "own-record-class" - ], - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "text.entry": [ - "TryFrom", - "ToString-format", - "TryFormat-short-span" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#when-text-is-rejected" - } - ] - }, - { - "id": "json-never-repeats", - "sentence": "A JSON or parsing rejection names the value object and the rule, or the underlying type it could not read.", - "inapplicable": [ - { - "axes": { - "json.Converters": [ - "own-for-wrapped", - "own-for-value-object" - ] - }, - "cite": "not-promised:the-applications-own-converter" - } - ] - }, - { - "id": "no-inner-that-quotes", - "sentence": "It carries no inner exception that quotes the text.", - "axes": { - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "Uri", - "enum", - "flags-enum", - "NodaTime.Instant" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#closed-sets" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "own-record-class" - ], - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "text.entry": [ - "TryFrom", - "ToString-format", - "TryFormat-short-span" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#when-text-is-rejected" - } - ] - } - ], - "not-promised": [ - { - "id": "a-rejected-dictionary-key-in-the-path", - "source": "README.md#what-typekit-guarantees", - "sentence": "One exception comes from System.Text.Json: a rejected dictionary key is in the `JsonException`'s `Path`, and so in MVC's 400", - "axes": { - "shape.position": [ - "dictionary-key" - ] - } - }, - { - "id": "the-applications-own-converter", - "source": "README.md#what-typekit-guarantees", - "sentence": "So a secret doesn't end up in a message or a log through this package, as long as your fault type doesn't carry it.", - "axes": { - "json.Converters": [ - "own-for-wrapped", - "own-for-value-object" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - }, - { - "reason": "System.Text.Json writes no dictionary key of a record class but through a converter of the application's (NotSupportedException for the wrapped type alike, L01's rows), where the JSON half is not promised (not-promised the-applications-own-converter), and a value object over a record class has no parsing (Generators README#what-is-generated), so no check of the claim can read the pair.", - "pairs": [ - [ - "shape.position=dictionary-key", - "shape.wrapped=own-record-class" - ] - ] - } - ] - }, - { - "id": "L03-one-rule", - "source": "README.md#what-typekit-guarantees", - "surfaces": [ - "text", - "json" - ], - "narrow": { - "input.json": "The generated `TryFrom`, `FromKnownGood`, JSON converter, parsing and type converter all run it, and each reports the fault you return from `Create`" - }, - "obligations": [ - { - "id": "tryfrom-runs-create", - "sentence": "The generated `TryFrom`, `FromKnownGood`, JSON converter, parsing and type converter all run it", - "axes": { - "text.entry": [ - "TryFrom" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "text.entry": [ - "TryFrom" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#closed-sets" - } - ] - }, - { - "id": "parsing-runs-create", - "sentence": "The generated `TryFrom`, `FromKnownGood`, JSON converter, parsing and type converter all run it", - "axes": { - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "Uri", - "enum", - "flags-enum", - "NodaTime.Instant" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#closed-sets" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "own-record-class" - ], - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - } - ] - }, - { - "id": "json-runs-create", - "sentence": "The generated `TryFrom`, `FromKnownGood`, JSON converter, parsing and type converter all run it" - }, - { - "id": "refusals-name-the-fault", - "sentence": "the `JsonException`, the `FormatException` and the `FromKnownGood` exception all name your `EmailFault.NoAt`" - } - ], - "not-promised": [ - { - "id": "stored-json-skips-validation", - "source": "README.md#what-typekit-guarantees", - "sentence": "`StoredJsonConverterFactory` reads JSON the application stored itself.", - "axes": { - "json.Converters": [ - "StoredJsonConverterFactory" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "L04-round-trip", - "source": "src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting", - "surfaces": [ - "text", - "json" - ], - "obligations": [ - { - "id": "invariant-whatever-the-culture", - "sentence": "A null `IFormatProvider` means the invariant culture in every generated `Parse`, `TryParse`, `ToString` and `TryFormat`, so the text doesn't depend on the culture the process runs in." - }, - { - "id": "the-type-converter-writes-the-same", - "sentence": "`ToString()` is the underlying type's own default text under the invariant culture, and the type converter and `$\"{x}\"` write the same.", - "axes": { - "text.entry": [ - "ToString-format", - "TryFormat-short-span", - "type-converter" - ] - }, - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "text.entry": [ - "ToString-format", - "TryFormat-short-span" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#closed-sets" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "own-record-class" - ], - "text.entry": [ - "type-converter" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - } - ] - }, - { - "id": "text-reads-back", - "sentence": "That text reads back as the same value wherever the underlying type's own does", - "inapplicable": [ - { - "axes": { - "shape.kind": [ - "closed-set" - ], - "text.entry": [ - "TryFrom", - "ISpanParsable", - "ToString-format", - "TryFormat-short-span" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#closed-sets" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "own-record-class" - ], - "text.entry": [ - "Parse", - "TryParse", - "IParsable", - "ISpanParsable", - "type-converter", - "ToString-format", - "TryFormat-short-span" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "Uri", - "enum", - "flags-enum", - "NodaTime.Instant" - ], - "text.entry": [ - "ISpanParsable" - ] - }, - "cite": "docs:src/CodoMetis.TypeKit.Generators/README.md#what-is-generated" - }, - { - "axes": { - "shape.kind": [ - "record-struct", - "sealed-record-class", - "validated-struct", - "validated-class" - ], - "shape.wrapped": [ - "TimeOnly", - "DateTime", - "DateTimeOffset" - ], - "text.entry": [ - "type-converter" - ] - }, - "cite": "not-promised:dates-and-times-lose-detail-as-text" - } - ] - }, - { - "id": "json-refusal-is-a-json-exception", - "sentence": "Input it can't read throws a `JsonException` naming the value object and the underlying type" - } - ], - "not-promised": [ - { - "id": "dates-and-times-lose-detail-as-text", - "source": "src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting", - "sentence": "**`TimeOnly`, `DateTime` and `DateTimeOffset` lose detail as text.**", - "axes": { - "shape.wrapped": [ - "TimeOnly", - "DateTime", - "DateTimeOffset" - ] - } - } - ], - "exclude": [ - { - "reason": "System.Text.Json refuses PreferredObjectCreationHandling.Populate together with a ReferenceHandler on the options object; JsonRow substitutes the default, so the pair never applies.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ] - ] - } - ] - }, - { - "id": "L05-equality", - "source": "src/CodoMetis.TypeKit.Generators/README.md#equality", - "surfaces": [ - "generation" - ], - "narrow": { - "shape.refused-kind": "A declaration that can't be generated fails the build, so no type is left half-generated." - }, - "obligations": [ - { - "id": "equality-is-the-underlying-values", - "sentence": "Equality is the underlying value's, like the ordering, the JSON and the column." - }, - { - "id": "ordering-follows-the-underlying-type", - "sentence": "`CompareTo` and the operators follow the underlying type's ordering, ordinal for a string." - }, - { - "id": "through-every-base", - "sentence": "The value object implements each base's `IEquatable` again (`IReimplementedEquatable`), so a collection of the base compares it the way the value object does.", - "axes": { - "shape.inheritance": [ - "base-depth-1", - "base-depth-2", - "base-depth-3", - "base-explicit-IEquatable" - ] - } - } - ], - "exclude": [ - { - "reason": "A struct cannot derive from a base type (C# structs inherit only from ValueType), so it has no base record.", - "pairs": [ - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ] - ] - }, - { - "reason": "A closed set wraps nothing (Generators README#closed-sets: a sealed class whose instances are its members), so it has no shape.wrapped.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "A value object or closed set nested in a generic type fails the build (CMTK1005, CMTK1018; Generators README#build-errors), so no such type exists to compare.", - "pairs": [ - [ - "shape.containing=class", - "shape.site=in-generic-type" - ], - [ - "shape.containing=generic-type", - "shape.site=in-generic-type" - ], - [ - "shape.containing=record-class", - "shape.site=in-generic-type" - ], - [ - "shape.containing=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.containing=struct", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-1", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-2", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-3", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=none", - "shape.site=in-generic-type" - ], - [ - "shape.kind=closed-set", - "shape.site=in-generic-type" - ], - [ - "shape.kind=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=sealed-record-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-struct", - "shape.site=in-generic-type" - ], - [ - "shape.position=array-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=dictionary-key", - "shape.site=in-generic-type" - ], - [ - "shape.position=dictionary-value", - "shape.site=in-generic-type" - ], - [ - "shape.position=field", - "shape.site=in-generic-type" - ], - [ - "shape.position=immutable-array-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=in-patch", - "shape.site=in-generic-type" - ], - [ - "shape.position=list-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=nullable-property", - "shape.site=in-generic-type" - ], - [ - "shape.position=polymorphic-derived-property", - "shape.site=in-generic-type" - ], - [ - "shape.position=property", - "shape.site=in-generic-type" - ], - [ - "shape.position=read-only-list-element", - "shape.site=in-generic-type" - ], - [ - "shape.position=record-ctor-parameter", - "shape.site=in-generic-type" - ], - [ - "shape.position=required-init", - "shape.site=in-generic-type" - ], - [ - "shape.position=root", - "shape.site=in-generic-type" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTime" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Guid" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeSpan" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Uri" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=bool" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=byte" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=char" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=decimal" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=double" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=flags-enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=int" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=long" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=own-record-class" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=string" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "A value at the root is not held by a containing type, so shape.containing has nothing to apply to.", - "pairs": [ - [ - "shape.containing=class", - "shape.position=root" - ], - [ - "shape.containing=generic-type", - "shape.position=root" - ], - [ - "shape.containing=record-class", - "shape.position=root" - ], - [ - "shape.containing=record-struct", - "shape.position=root" - ], - [ - "shape.containing=struct", - "shape.position=root" - ] - ] - } - ] - }, - { - "id": "L06-off-the-wire", - "source": "README.md#what-typekit-guarantees", - "surfaces": [ - "json", - "option-result" - ], - "obligations": [ - { - "id": "never-written", - "sentence": "System.Text.Json throws `NotSupportedException` for either, in both directions, instead of writing `{}` that reads back as `None`." - }, - { - "id": "never-read", - "sentence": "System.Text.Json throws `NotSupportedException` for either, in both directions, instead of writing `{}` that reads back as `None`." - } - ], - "not-promised": [ - { - "id": "a-source-generated-context-refuses-a-nullable", - "source": "src/CodoMetis.TypeKit/README.md#not-wire-types", - "sentence": "**A source-generated context can't describe an `Option?` or `Result<...>?` property.**", - "axes": { - "json.TypeInfoResolver": [ - "source-generated-context" - ], - "shape.position": [ - "nullable-property" - ] - } - }, - { - "id": "a-missing-property-reaches-no-converter", - "source": "src/CodoMetis.TypeKit/README.md#not-wire-types", - "sentence": "**A missing property reaches no converter.**" - } - ], - "exclude": [ - { - "reason": "A closed set wraps nothing (Generators README#closed-sets: a sealed class whose instances are its members), so it has no shape.wrapped.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "A value at the root is not held by a containing type, so shape.containing has nothing to apply to.", - "pairs": [ - [ - "shape.containing=class", - "shape.position=root" - ], - [ - "shape.containing=generic-type", - "shape.position=root" - ], - [ - "shape.containing=record-class", - "shape.position=root" - ], - [ - "shape.containing=record-struct", - "shape.position=root" - ], - [ - "shape.containing=struct", - "shape.position=root" - ] - ] - }, - { - "reason": "Result has no Select or SelectMany, so no query expression produces one, and FirstOrNone returns an Option, never a Result (src/CodoMetis.TypeKit/ResultExtensions.cs and OptionExtensions.cs).", - "pairs": [ - [ - "or.operation=FirstOrNone", - "or.shape=Result-E" - ], - [ - "or.operation=query-syntax", - "or.shape=Result-E" - ] - ] - }, - { - "reason": "System.Text.Json serializes a field only under IncludeFields (or [JsonInclude]), so without it the member is in no document and no converter runs in either direction, for the plain type alike.", - "pairs": [ - [ - "json.IncludeFields=default", - "shape.position=field" - ] - ] - }, - { - "reason": "System.Text.Json refuses JsonObjectCreationHandling.Populate together with a reference handler (InvalidOperationException when the options are used; harness/JsonRow.cs runs such a row without Populate), so no row can set both.", - "pairs": [ - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=IgnoreCycles" - ], - [ - "json.PreferredObjectCreationHandling=Populate", - "json.ReferenceHandler=Preserve" - ] - ] - } - ] - }, - { - "id": "C22-generator-refusals", - "source": "src/CodoMetis.TypeKit.Generators/README.md#build-errors", - "surfaces": [ - "generation", - "analyzers" - ], - "axes": { - "build-host": [ - "sdk-build" - ] - }, - "narrow": { - "shape.position": "A declaration that can't be generated fails the build, so no type is left half-generated.", - "shape.containing": "A declaration that can't be generated fails the build, so no type is left half-generated." - }, - "obligations": [ - { - "id": "no-type-half-generated", - "sentence": "A declaration that can't be generated fails the build, so no type is left half-generated." - }, - { - "id": "every-error-links-the-table", - "sentence": "Every error ends with a link to this table." - }, - { - "id": "unsealed-record-class", - "sentence": "A record class not declared `sealed`.", - "axes": { - "shape.refused-kind": [ - "unsealed-record-class (CMTK1006)" - ] - } - }, - { - "id": "over-value-object", - "sentence": "or a value object (itself included). Wrap what the other value object wraps instead.", - "axes": { - "shape.refused-kind": [ - "over-value-object (CMTK1005)" - ] - } - }, - { - "id": "generic-wrapped", - "sentence": "A generic underlying type, a tuple included, fails the build (CMTK1005).", - "axes": { - "shape.refused-kind": [ - "generic-wrapped (CMTK1005)" - ] - } - }, - { - "id": "abstract", - "sentence": "An abstract type with a value-object marker. It would get no member, and a value held as it, of a type derived from it, would have no `Value` and be written as `{}`.", - "axes": { - "shape.refused-kind": [ - "abstract (CMTK1005)" - ] - } - }, - { - "id": "over-object", - "sentence": "or wrapping `object`, `System.Enum`, an array, a pointer, a nullable type, a generic type (a tuple included) or a value object (itself included).", - "axes": { - "shape.refused-kind": [ - "over-object (CMTK1005)" - ] - } - }, - { - "id": "over-system-enum", - "sentence": "or wrapping `object`, `System.Enum`, an array, a pointer, a nullable type, a generic type (a tuple included) or a value object (itself included).", - "axes": { - "shape.refused-kind": [ - "over-System.Enum (CMTK1005)" - ] - } - }, - { - "id": "named-as-generated-member", - "sentence": "named `Value` or as another member the generators add (`From`, `TryFrom`, `FromKnownGood`, `Revalidate`, `Parse`, `TryParse`, `TryFormat`, `MinValue`, `MaxValue`, `CompareTo`)", - "axes": { - "shape.refused-kind": [ - "named-as-generated-member (CMTK1005)" - ] - } - }, - { - "id": "closed-set-named-as-generated-member", - "sentence": "a set itself named as one of them (a member can't have the name of its type)", - "axes": { - "shape.refused-kind": [ - "closed-set-named-as-generated-member (CMTK1021)" - ] - } - }, - { - "id": "equality-operator", - "sentence": "So a hand-written `Equals(TSelf)`, `GetHashCode()`, `IEquatable.Equals`, or `operator ==` or `!=` between two of the type, fails the build (CMTK1011).", - "axes": { - "shape.refused-kind": [ - "equality-operator (CMTK1011)" - ] - } - } - ], - "exclude": [ - { - "reason": "A declaration nested in a generic type is refused for that alone (Generators README, Build errors: CMTK1005, \"Generic or nested in a generic type\"; the axes file's refused list), so it cannot show which refusal of its own the generators report.", - "pairs": [ - [ - "build-host=sdk-build", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-1", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-2", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-depth-3", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=explicit-interface-member", - "shape.site=in-generic-type" - ], - [ - "shape.inheritance=none", - "shape.site=in-generic-type" - ], - [ - "shape.kind=closed-set", - "shape.site=in-generic-type" - ], - [ - "shape.kind=record-struct", - "shape.site=in-generic-type" - ], - [ - "shape.kind=sealed-record-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-class", - "shape.site=in-generic-type" - ], - [ - "shape.kind=validated-struct", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=abstract (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=equality-operator (CMTK1011)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=generic-wrapped (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=named-as-generated-member (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=over-value-object (CMTK1005)", - "shape.site=in-generic-type" - ], - [ - "shape.refused-kind=unsealed-record-class (CMTK1006)", - "shape.site=in-generic-type" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTime" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Guid" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeOnly" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=TimeSpan" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=Uri" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=bool" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=byte" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=char" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=decimal" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=double" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=flags-enum" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=int" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=long" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=own-record-class" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=string" - ], - [ - "shape.site=in-generic-type", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "C# seals every struct and refuses an abstract one, so a record struct can be neither an unsealed nor an abstract record class; a closed set is never a record (CMTK1020), and an unsealed or abstract one is CMTK1014, a refusal of its own.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=record-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=abstract (CMTK1005)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=unsealed-record-class (CMTK1006)" - ] - ] - }, - { - "reason": "A closed set wraps no type and has no equality of the underlying value to write by hand (Generators README, Closed sets), so it cannot be declared over a type or with a value object's equality; its own name clash is closed-set-named-as-generated-member (CMTK1021).", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.refused-kind=equality-operator (CMTK1011)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=generic-wrapped (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=named-as-generated-member (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-System.Enum (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-object (CMTK1005)" - ], - [ - "shape.kind=closed-set", - "shape.refused-kind=over-value-object (CMTK1005)" - ] - ] - }, - { - "reason": "CMTK1021 is a closed set's refusal; a value object named as a generated member is named-as-generated-member (CMTK1005).", - "pairs": [ - [ - "shape.kind=record-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=sealed-record-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-class", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.kind=validated-struct", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ] - ] - }, - { - "reason": "The refused kind fixes what is wrapped: object, System.Enum; and a closed set wraps no type (Generators README, Closed sets), so shape.wrapped has nothing to apply to.", - "pairs": [ - [ - "shape.kind=closed-set", - "shape.wrapped=DateOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTime" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Guid" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeOnly" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=TimeSpan" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=Uri" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=bool" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=byte" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=char" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=decimal" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=double" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=flags-enum" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=int" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=long" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=own-record-class" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=string" - ], - [ - "shape.kind=closed-set", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-System.Enum (CMTK1005)", - "shape.wrapped=ulong" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTime" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=DateTimeOffset" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Guid" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=NodaTime.Instant" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeOnly" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=TimeSpan" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=Uri" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=bool" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=byte" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=char" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=decimal" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=double" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=flags-enum" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=int" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=long" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=own-record-class" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=string" - ], - [ - "shape.refused-kind=over-object (CMTK1005)", - "shape.wrapped=ulong" - ] - ] - }, - { - "reason": "A record struct has no base type, and a closed set is a sealed class that is never a record (CMTK1020), so neither derives from the base records of shape.inheritance; an explicit member of another interface they implement themselves.", - "pairs": [ - [ - "shape.inheritance=base-depth-1", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-1", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-2", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-depth-3", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=closed-set" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=record-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.kind=validated-struct" - ], - [ - "shape.inheritance=base-explicit-IEquatable", - "shape.refused-kind=closed-set-named-as-generated-member (CMTK1021)" - ] - ] - } - ] - } -] diff --git a/tools/probe/corpus/dismissed.jsonl b/tools/probe/corpus/dismissed.jsonl deleted file mode 100644 index 4327b389..00000000 --- a/tools/probe/corpus/dismissed.jsonl +++ /dev/null @@ -1 +0,0 @@ -{"id": "G1", "reason": "Not a TypeKit bug: the MVC [FromBody] T v of a class is nullable, so ASP.NET makes the body optional, and its OpenAPI 2.0 writer turns any nullable body into allOf:[{x-nullable:true}] without pattern; a plain int? without TypeKit gets the same bytes. The harness compared a nullable class value object with a non-nullable int (fix-f2-g1-openapi, measured at 1ee02fc).", "date": "2026-10-15"} diff --git a/tools/probe/corpus/harness/BaseProbe.cs b/tools/probe/corpus/harness/BaseProbe.cs deleted file mode 100644 index 13b5e370..00000000 --- a/tools/probe/corpus/harness/BaseProbe.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Calibration of the shared HTTP host (not a claim): runs the baseline's wire half over its own rows of claim C07 to find harness mistakes -// before the claims use it. The schema half is claim C21's (C21OpenapiSchemaParityProbe). Each comparison is a check of its own (HttpBaseline.Run), -// of the implicit obligation claim: C07 promises nothing of the wire, and its seed names no obligation. -using Probes.Shapes; -namespace Probes; -public sealed class BaseProbe -{ - public static TheoryData Data() => Rows.Data("BaseProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run("BASE", idx, async r => await HttpBaseline.Run(r, Registry.Of(r), schema: false), probe); -} diff --git a/tools/probe/corpus/harness/BuildConsumer.cs b/tools/probe/corpus/harness/BuildConsumer.cs deleted file mode 100644 index 15dddbc5..00000000 --- a/tools/probe/corpus/harness/BuildConsumer.cs +++ /dev/null @@ -1,125 +0,0 @@ -// A throwaway consumer of the generators, built once per probe run with every row's declarations in a file of its own, for what -// only a build can show: the generators' diagnostics (CMTK1xxx). It builds as test/CodoMetis.TypeKit.Generators.Tests' BuildOutcomeTests -// does: under artifacts/, against the projects this run already built (--no-dependencies), outside the repository's build settings. -using System.Diagnostics; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.PortableExecutable; -using System.Text.RegularExpressions; -namespace Probes.Build; - -public sealed record BuildDiagnostic(string File, string Severity, string Id, string Message); - -public sealed record ConsumerOutcome(int ExitCode, string Output, IReadOnlyList Diagnostics, IReadOnlyDictionary> Methods) -{ - /// The diagnostics reported in one of the consumer's files. - public IEnumerable In(string file) => Diagnostics.Where(d => Path.GetFileName(d.File) == file); -} - -public static partial class Consumer -{ - static readonly Dictionary>> Builds = new(); - - /// Builds the consumer of once per in this process. - public static Task Build(string key, Func> files) - { - lock (Builds) - { - if (!Builds.TryGetValue(key, out var build)) Builds[key] = build = new(() => Run(files())); - return build.Value; - } - } - - public static string RepositoryRoot() - { - for (var d = new DirectoryInfo(AppContext.BaseDirectory); d is not null; d = d.Parent) - if (File.Exists(Path.Combine(d.FullName, "CodoMetis.TypeKit.slnx"))) return d.FullName; - throw new InvalidOperationException($"no CodoMetis.TypeKit.slnx above {AppContext.BaseDirectory}"); - } - - static string Configuration => typeof(Consumer).Assembly.GetCustomAttribute()?.Configuration - ?? throw new InvalidOperationException("the probe assembly carries no AssemblyConfigurationAttribute"); - - static async Task Run(IReadOnlyDictionary files) - { - var root = RepositoryRoot(); - var dir = Path.Combine(root, "artifacts", $"probe-consumer-{Guid.NewGuid():N}"); - Directory.CreateDirectory(dir); - try - { - var src = Path.Combine(root, "src"); - await File.WriteAllTextAsync(Path.Combine(dir, "Consumer.csproj"), $""" - - - net10.0 - enable - disable - ProbeConsumer - - - - {typeof(NodaTime.Instant).Assembly.Location} - - - """); - await File.WriteAllTextAsync(Path.Combine(dir, "Directory.Build.props"), ""); - await File.WriteAllTextAsync(Path.Combine(dir, "Directory.Build.targets"), ""); - await File.WriteAllTextAsync(Path.Combine(dir, "Directory.Packages.props"), - "false"); - foreach (var (name, text) in files) await File.WriteAllTextAsync(Path.Combine(dir, name), text); - - var dotnet = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH") is { Length: > 0 } host ? host : "dotnet"; - var info = new ProcessStartInfo(dotnet, ["build", dir, "-c", Configuration, "--no-dependencies", "-p:RestoreRecursive=false", "-nodeReuse:false", "-clp:NoSummary", "-v:q", "-nologo"]) - { - RedirectStandardOutput = true, RedirectStandardError = true, WorkingDirectory = dir, - }; - // The run's code coverage instruments this process through its environment; the build is not the probe's code. - foreach (var k in info.Environment.Keys.ToList()) - if (k.StartsWith("CORECLR_", StringComparison.OrdinalIgnoreCase) || k.StartsWith("COR_", StringComparison.OrdinalIgnoreCase) - || k.Contains("CODECOVERAGE", StringComparison.OrdinalIgnoreCase) || k.StartsWith("MicrosoftInstrumentationEngine", StringComparison.OrdinalIgnoreCase) - || k.Equals("DOTNET_STARTUP_HOOKS", StringComparison.OrdinalIgnoreCase)) - info.Environment.Remove(k); - info.Environment["DOTNET_CLI_UI_LANGUAGE"] = "en"; - using var process = Process.Start(info)!; - var stdout = process.StandardOutput.ReadToEndAsync(); - var stderr = process.StandardError.ReadToEndAsync(); - using (var timeout = new CancellationTokenSource(TimeSpan.FromMinutes(10))) await process.WaitForExitAsync(timeout.Token); - var output = await stdout + await stderr; - var diagnostics = Line().Matches(output) - .Select(m => new BuildDiagnostic(m.Groups["file"].Value.Trim(), m.Groups["sev"].Value, m.Groups["id"].Value, m.Groups["msg"].Value.Trim())) - .Distinct().ToList(); - var dll = Path.Combine(dir, "bin", Configuration, "net10.0", "ProbeConsumer.dll"); - return new ConsumerOutcome(process.ExitCode, output, diagnostics, File.Exists(dll) ? Methods(dll) : new Dictionary>()); - } - finally - { - try { Directory.Delete(dir, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - } - - /// The methods each type of the built assembly declares, by the type's metadata name (nesting with '+'), read without loading it. - static Dictionary> Methods(string dll) - { - using var stream = File.OpenRead(dll); - using var pe = new PEReader(stream); - var md = pe.GetMetadataReader(); - string Name(TypeDefinition t) - { - var name = md.GetString(t.Name); - var outer = t.GetDeclaringType(); - if (!outer.IsNil) return Name(md.GetTypeDefinition(outer)) + "+" + name; - var ns = md.GetString(t.Namespace); - return ns.Length == 0 ? name : ns + "." + name; - } - var result = new Dictionary>(); - foreach (var h in md.TypeDefinitions) - { - var t = md.GetTypeDefinition(h); - result[Name(t)] = [.. t.GetMethods().Select(m => md.GetString(md.GetMethodDefinition(m).Name))]; - } - return result; - } - - [GeneratedRegex(@"^(?[^\r\n(]+)\((?\d+),(?\d+)\): (?warning|error) (?[A-Z]+\d+): (?.*?)(?: \[[^\]\r\n]*\])?\r?$", RegexOptions.Multiline)] - private static partial Regex Line(); -} diff --git a/tools/probe/corpus/harness/BuildDecls.cs b/tools/probe/corpus/harness/BuildDecls.cs deleted file mode 100644 index 7efdb659..00000000 --- a/tools/probe/corpus/harness/BuildDecls.cs +++ /dev/null @@ -1,91 +0,0 @@ -// The hand half of C09Shapes.g.cs and C11Shapes.g.cs (generated from the rows, one value object per row): the tables' rows, and the -// wrapped types of C11's parse shapes. -namespace Probes.Build; - -/// One C09 row as declared: the effective settings, the value object, its bases from the direct one up, and its factory. -public sealed record C09Case(int Index, string Key, string Kind, string Site, string Inheritance, Type Vo, Type[] Bases, Func Make, (string Axis, string Value)[] Substituted); - -/// -/// One C11 row as declared: the effective settings, the value object and the type it wraps, and for a parse shape its control: a value -/// object of the same kind, site and inheritance over the nearest type that does parse. -/// -public sealed record C11Case(int Index, string Key, string Kind, string Site, string Inheritance, Type Vo, Type Wrapped, Type? Control, Type? ControlWrapped, (string Axis, string Value)[] Substituted); - -public static class Decls -{ - /// - /// The row's settings as the generator keyed them; a table generated from other rows is a harness error, not a pass. Read from - /// the cached copy of the row, so the run's own row marks no axis read. - /// - public static string Key(string probe, int index) => - string.Join(";", Probes.Shapes.Rows.Get(probe, index).All.OrderBy(kv => kv.Key, StringComparer.Ordinal).Select(kv => $"{kv.Key}={kv.Value}")); -} - -// C11's parse shapes, each the whole wrapped type (CHANGELOG 2.1.0, Fixed): "A wrapped type's `Parse` whose result can't be assigned -// to it, or that takes its text by `ref`, or an abstract class's string constructor". - -/// implicit-result: a static Parse whose result, an int, cannot be assigned to the type. -public sealed class C11ParsesToInt -{ - public static int Parse(string text) => text.Length; - public override string ToString() => "parses-to-int"; -} - -/// ref-text: a static Parse that takes its text by ref. -public sealed class C11ParsesByRef -{ - public static C11ParsesByRef Parse(ref string text) { text = ""; return new(); } - public override string ToString() => "parses-by-ref"; -} - -/// ref-text: a string constructor that takes its text by ref. -public sealed class C11ConstructedByRef -{ - public C11ConstructedByRef(ref string text) => text = ""; - private C11ConstructedByRef() { } - public static C11ConstructedByRef Sample() => new(); - public override string ToString() => "constructed-by-ref"; -} - -/// abstract-string-ctor: an abstract class with a public string constructor, which only a derived class can call. -public abstract class C11AbstractText -{ - public C11AbstractText(string text) => Text = text; - public string Text { get; } - public override string ToString() => Text; -} - -public sealed class C11ConcreteText(string text) : C11AbstractText(text); - -// The controls, each the nearest type that can be parsed (Generators README, "What you can wrap": "Parsing where it can be parsed"): -// a Parse whose result converts to the type by a user-defined implicit operator, so it can be assigned; a Parse taking its text by in, -// which a call passes as it is; a sealed class's public string constructor. - -/// Control of implicit-result: Parse gives a type that converts to this one implicitly. -public sealed class C11ParsedShape -{ - public string Text { get; init; } = ""; - public static C11ParsedCircle Parse(string text) => new() { Text = text }; - public override string ToString() => Text; -} - -public sealed class C11ParsedCircle -{ - public string Text { get; init; } = ""; - public static implicit operator C11ParsedShape(C11ParsedCircle circle) => new() { Text = circle.Text }; -} - -/// Control of ref-text: Parse takes its text by in. -public sealed class C11ParsesFromIn -{ - public string Text { get; private init; } = ""; - public static C11ParsesFromIn Parse(in string text) => new() { Text = text }; - public override string ToString() => Text; -} - -/// Control of abstract-string-ctor: a sealed class with a public string constructor. -public sealed class C11ConstructedConcrete(string text) -{ - public string Text { get; } = text; - public override string ToString() => Text; -} diff --git a/tools/probe/corpus/harness/BuildRefusals.cs b/tools/probe/corpus/harness/BuildRefusals.cs deleted file mode 100644 index be3d79da..00000000 --- a/tools/probe/corpus/harness/BuildRefusals.cs +++ /dev/null @@ -1,280 +0,0 @@ -// The declarations the generators refuse (shape.refused-kind), written as C# per row, and the consumer build that shows what the -// generators did with them (C22). The build is BuildConsumer.cs's (a throwaway consumer under artifacts/, against the projects this run -// already built, outside the repository's build settings) with Metalama's transformed files kept, since a refused declaration fails the -// build and leaves no assembly to read: the transformed source is where a member the generators added to a refused type would show. -using System.Diagnostics; -using System.Reflection; -using System.Text.RegularExpressions; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace Probes.Build; - -/// A consumer build: its exit code, its output, its diagnostics, and Metalama's transformed source of each file. -public sealed record RefusalOutcome(int ExitCode, string Output, IReadOnlyList Diagnostics, IReadOnlyDictionary Transformed) -{ - /// The diagnostics reported in one of the consumer's files. - public IEnumerable In(string file) => Diagnostics.Where(d => Path.GetFileName(d.File) == file); -} - -/// -/// One refusal of the Generators README's "Build errors" table, as a row declares it: the id the table gives it, the obligation of C22 -/// that states it, the consumer it is built in, and the compiler errors that may stand beside it in its own file. -/// -/// -/// A compiler error in a consumer hid every LAMA0611 of the other files (e4b751c), so the declarations whose refusal comes with a -/// compiler error of its own are built apart: a refused closed set leaves its interface's members unimplemented (CS0535, as -/// BuildOutcomeTests allows it), and a hand-written equality operator of a record is also C#'s CS0111 (the README says so). -/// -public sealed record Refusal(string Kind, string Id, string Obligation, string Group, IReadOnlyList Companions); - -/// One row's declarations: the refused type, as the diagnostics name it, and a control the generators must generate. -public sealed record RefusedDeclaration(int Index, Refusal Refusal, string Name, string Display, string Control, string File, string Source); - -public static partial class Refusals -{ - /// The refusals C22 declares, by their shape.refused-kind value; any other value is the harness's mistake, never a pass. - public static readonly IReadOnlyDictionary Table = new Refusal[] - { - new("unsealed-record-class (CMTK1006)", "CMTK1006", "unsealed-record-class", "value-objects", []), - new("over-value-object (CMTK1005)", "CMTK1005", "over-value-object", "value-objects", []), - new("generic-wrapped (CMTK1005)", "CMTK1005", "generic-wrapped", "value-objects", []), - // The label keeps the id it had when C09's and C11's rows were generated; an abstract value object is CMTK1022 since 1ef30be. - new("abstract (CMTK1005)", "CMTK1022", "abstract", "value-objects", []), - new("over-object (CMTK1005)", "CMTK1005", "over-object", "value-objects", []), - new("over-System.Enum (CMTK1005)", "CMTK1005", "over-system-enum", "value-objects", []), - new("named-as-generated-member (CMTK1005)", "CMTK1005", "named-as-generated-member", "value-objects", []), - new("closed-set-named-as-generated-member (CMTK1021)", "CMTK1021", "closed-set-named-as-generated-member", "closed-sets", ["CS0535"]), - new("equality-operator (CMTK1011)", "CMTK1011", "equality-operator", "operators", ["CS0111"]), - }.ToDictionary(r => r.Kind); - - /// - /// The value-object names CMTK1005 refuses (the README's list), and the closed-set names CMTK1021 refuses; a row takes one by its - /// index. C17's and C19's probes name their named-as-generated-member declaration from the same list. - /// - public static readonly string[] ValueObjectNames = ["Value", "From", "TryFrom", "FromKnownGood", "Revalidate", "Parse", "TryParse", "TryFormat", "MinValue", "MaxValue", "CompareTo"]; - static readonly string[] ClosedSetNames = ["Name", "QualifiedName", "All", "Match", "Parse", "TryParse"]; - - /// The link every generator error ends with (Generators README, Build errors: "Every error ends with a link to this table"). - public const string TableLink = "https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/main/src/CodoMetis.TypeKit.Generators/README.md#build-errors"; - - static readonly string[] Structs = ["record-struct", "validated-struct"]; - - /// - /// The row's declarations. Reads shape.refused-kind, shape.kind, shape.site, shape.inheritance and build-host, and shape.wrapped where - /// the refused kind wraps it. A refused kind the table does not hold, a combination the claim excludes, and a refusal the README's - /// Build errors table no longer lists are harness errors: the row would show nothing about a refusal the README states. - /// - public static RefusedDeclaration Declare(Probes.Shapes.Row r) - { - if (r["build-host"] != "sdk-build") throw new InvalidOperationException("build-host " + r["build-host"] + " has no build here"); - var kindValue = r["shape.refused-kind"]; - if (!Table.TryGetValue(kindValue, out var refusal)) throw new InvalidOperationException($"shape.refused-kind '{kindValue}' is no refusal this harness declares"); - if (!ReadmeLists(refusal.Id)) throw new InvalidOperationException($"the Generators README's Build errors table has no row for {refusal.Id}"); - var kind = r["shape.kind"]; var site = r["shape.site"]; var inheritance = r["shape.inheritance"]; - var n = r.Index; var id = n.ToString(); - var closedSet = kind == "closed-set"; - if (closedSet != (refusal.Group == "closed-sets")) throw new InvalidOperationException($"{kindValue} cannot be declared as a {kind} (excluded in claims.json)"); - if (Structs.Contains(kind) && refusal.Obligation is "unsealed-record-class" or "abstract") throw new InvalidOperationException($"a {kind} cannot be {refusal.Obligation} (excluded in claims.json)"); - if ((Structs.Contains(kind) || closedSet) && inheritance is not ("none" or "explicit-interface-member")) throw new InvalidOperationException($"a {kind} has no base record for {inheritance} (excluded in claims.json)"); - if (site == "in-generic-type") throw new InvalidOperationException("in-generic-type is a refusal of its own (excluded in claims.json)"); - - var name = refusal.Obligation switch - { - "named-as-generated-member" => ValueObjectNames[n % ValueObjectNames.Length], - "closed-set-named-as-generated-member" => ClosedSetNames[n % ClosedSetNames.Length], - _ => $"V{id}", - }; - var control = closedSet ? $"S{id}" : $"K{id}"; - var body = new System.Text.StringBuilder(); - body.AppendLine($"public enum VF{id} {{ No }}"); - var explicitMember = inheritance == "explicit-interface-member"; - if (explicitMember) body.AppendLine($"public interface IMark{id} {{ int Mark(); }}"); - - // The bases, from the topmost down: plain abstract records, the direct one with an explicit IEquatable of its own or an explicit - // member of another interface where shape.inheritance says so. A struct or a closed set implements that interface itself. - var depth = inheritance switch { "base-depth-2" => 2, "base-depth-3" => 3, "none" => 0, _ => 1 }; - if (closedSet || Structs.Contains(kind)) depth = 0; - for (var d = depth; d >= 1; d--) - { - var b = $"B{id}_{d}"; - var parents = new List(); - if (d < depth) parents.Add($"B{id}_{d + 1}"); - var members = ""; - if (d == 1 && inheritance == "base-explicit-IEquatable") { parents.Add($"IEquatable<{b}>"); members = $"bool IEquatable<{b}>.Equals({b}? other) => ReferenceEquals(this, other);"; } - if (d == 1 && explicitMember) { parents.Add($"IMark{id}"); members = $"int IMark{id}.Mark() => 0;"; } - body.AppendLine($"public abstract record {b}{(parents.Count > 0 ? " : " + string.Join(", ", parents) : "")} {{ {members} }}"); - } - var baseList = depth > 0 ? $"B{id}_1, " : ""; - var ownMark = explicitMember && depth == 0; - var markList = ownMark ? $", IMark{id}" : ""; - var markMember = ownMark ? $" int IMark{id}.Mark() => 0;" : ""; - - if (closedSet) - { - body.AppendLine($"public sealed partial class {name} : IClosedSet<{name}>{markList} {{ public static readonly {name} A{id} = new();{markMember} }}"); - body.AppendLine($"public sealed partial class {control} : IClosedSet<{control}>{markList} {{ public static readonly {control} A{id} = new();{markMember} }}"); - } - else - { - var w = refusal.Obligation is "over-object" or "over-system-enum" ? null : Src.Wrapped(r["shape.wrapped"], id); - var wrapped = refusal.Obligation switch - { - "over-value-object" => $"I{id}", - "generic-wrapped" => $"List<{w}>", - "over-object" => "object", - "over-system-enum" => "System.Enum", - _ => w!, - }; - if (refusal.Obligation == "over-value-object") body.AppendLine($"public readonly partial record struct I{id} : IValue<{w}>;"); - var modifier = refusal.Obligation switch { "unsealed-record-class" => "", "abstract" => "abstract ", _ => "sealed " }; - var operators = refusal.Obligation == "equality-operator"; - body.AppendLine(ValueObject(kind, name, modifier, baseList, wrapped, id, markList, markMember, operators)); - body.AppendLine(ValueObject(kind, control, "sealed ", baseList, w ?? "int", id, markList, markMember, operators: false)); - } - - var source = Src.Usings + $"namespace C22R{id};\n" + Src.WrappedDeclarations(id) + Src.AtSite(site, id, body.ToString()) + "\n"; - return new(n, refusal, name, Nesting(site, id) + name, control, $"R{id}.cs", source); - } - - static string ValueObject(string kind, string name, string modifier, string baseList, string wrapped, string id, string markList, string markMember, bool operators) - { - var validated = kind.StartsWith("validated", StringComparison.Ordinal); - var marker = validated ? $"IValidatedValue<{name}, {wrapped}, VF{id}>" : $"IValue<{wrapped}>"; - var head = Structs.Contains(kind) - ? $"public readonly partial record struct {name} : {marker}{markList}" - : $"public {modifier}partial record {name} : {baseList}{marker}{markList}"; - var members = new List(); - if (validated) members.Add($"public static Result<{name}, VF{id}> Create({wrapped} value) => Result.Error(VF{id}.No);"); - if (operators) - { - var t = Structs.Contains(kind) ? name : name + "?"; - members.Add($"public static bool operator ==({t} left, {t} right) => true;"); - members.Add($"public static bool operator !=({t} left, {t} right) => false;"); - } - if (markMember.Length > 0) members.Add(markMember.Trim()); - return members.Count == 0 ? head + ";" : $"{head}\n{{\n {string.Join("\n ", members)}\n}}"; - } - - /// shape.site's nesting as a diagnostic names a type: its containing types, dotted. - static string Nesting(string site, string id) => site switch - { - "top-level" => "", "nested-in-class" or "nested-in-struct" => $"O{id}.", "nested-two-levels" => $"O{id}.P{id}.", - _ => throw new ArgumentException("shape.site " + site), - }; - - static readonly Lazy Readme = new(() => File.ReadAllText(Path.Combine(Consumer.RepositoryRoot(), "src", "CodoMetis.TypeKit.Generators", "README.md"))); - - /// Whether the README's Build errors table has a row for . - public static bool ReadmeLists(string id) => - Readme.Value.IndexOf("\n## Build errors", StringComparison.Ordinal) is var at and >= 0 - && Readme.Value.IndexOf($"\n| {id} |", at, StringComparison.Ordinal) >= 0; - - /// Whether the README still has the heading the table link points at. - public static bool ReadmeHasBuildErrorsHeading() => Readme.Value.Split('\n').Any(l => l.TrimEnd('\r') == "## Build errors"); - - /// - /// How the generators left a type in Metalama's transformed source: null where its declaration is as it was written (no base - /// type and no member added, and no {Name}Extensions companion), else what they added. Throws where the type is not there. - /// - public static string? Added(RefusalOutcome build, RefusedDeclaration d, string name) - { - if (!build.Transformed.TryGetValue(d.File, out var transformed)) throw new InvalidOperationException($"Metalama wrote no transformed {d.File}"); - var written = One(CSharpSyntaxTree.ParseText(d.Source).GetRoot(), name, "the row's source"); - var woven = One(CSharpSyntaxTree.ParseText(transformed).GetRoot(), name, "the transformed " + d.File); - var added = new List(); - var bw = written.BaseList?.Types.Count ?? 0; var bt = woven.BaseList?.Types.Count ?? 0; - if (bt != bw) added.Add($"{bt - bw} base type(s)"); - if (woven.Members.Count != written.Members.Count) added.Add($"{woven.Members.Count - written.Members.Count} member(s)"); - var companion = name + "Extensions"; - foreach (var (file, text) in build.Transformed) - if (text.Contains($"namespace C22R{d.Index}", StringComparison.Ordinal) && text.Contains(companion, StringComparison.Ordinal) - && CSharpSyntaxTree.ParseText(text).GetRoot().DescendantNodes().OfType().Any(c => c.Identifier.Text == companion)) - added.Add($"the companion {companion} ({file})"); - return added.Count == 0 ? null : string.Join(", ", added); - } - - static TypeDeclarationSyntax One(Microsoft.CodeAnalysis.SyntaxNode root, string name, string where) - { - var found = root.DescendantNodes().OfType().Where(t => t.Identifier.Text == name).ToList(); - return found.Count == 1 ? found[0] : throw new InvalidOperationException($"{found.Count} declarations of {name} in {where}"); - } - - static readonly Dictionary>> Builds = new(); - - /// Builds the consumer of once per in this process. - public static Task Build(string key, Func> files) - { - lock (Builds) - { - if (!Builds.TryGetValue(key, out var build)) Builds[key] = build = new(() => Run(files())); - return build.Value; - } - } - - static string Configuration => typeof(Refusals).Assembly.GetCustomAttribute()?.Configuration - ?? throw new InvalidOperationException("the probe assembly carries no AssemblyConfigurationAttribute"); - - static async Task Run(IReadOnlyDictionary files) - { - var root = Consumer.RepositoryRoot(); - var dir = Path.Combine(root, "artifacts", $"probe-refusals-{Guid.NewGuid():N}"); - Directory.CreateDirectory(dir); - try - { - var src = Path.Combine(root, "src"); - await File.WriteAllTextAsync(Path.Combine(dir, "Consumer.csproj"), $""" - - - net10.0 - enable - disable - ProbeRefusals - true - - - - {typeof(NodaTime.Instant).Assembly.Location} - - - """); - await File.WriteAllTextAsync(Path.Combine(dir, "Directory.Build.props"), ""); - await File.WriteAllTextAsync(Path.Combine(dir, "Directory.Build.targets"), ""); - await File.WriteAllTextAsync(Path.Combine(dir, "Directory.Packages.props"), - "false"); - foreach (var (name, text) in files) await File.WriteAllTextAsync(Path.Combine(dir, name), text); - - var dotnet = Environment.GetEnvironmentVariable("DOTNET_HOST_PATH") is { Length: > 0 } host ? host : "dotnet"; - var info = new ProcessStartInfo(dotnet, ["build", dir, "-c", Configuration, "--no-dependencies", "-p:RestoreRecursive=false", "-nodeReuse:false", "-clp:NoSummary", "-v:q", "-nologo"]) - { - RedirectStandardOutput = true, RedirectStandardError = true, WorkingDirectory = dir, - }; - // The run's code coverage instruments this process through its environment; the build is not the probe's code. - foreach (var k in info.Environment.Keys.ToList()) - if (k.StartsWith("CORECLR_", StringComparison.OrdinalIgnoreCase) || k.StartsWith("COR_", StringComparison.OrdinalIgnoreCase) - || k.Contains("CODECOVERAGE", StringComparison.OrdinalIgnoreCase) || k.StartsWith("MicrosoftInstrumentationEngine", StringComparison.OrdinalIgnoreCase) - || k.Equals("DOTNET_STARTUP_HOOKS", StringComparison.OrdinalIgnoreCase)) - info.Environment.Remove(k); - info.Environment["DOTNET_CLI_UI_LANGUAGE"] = "en"; - using var process = Process.Start(info)!; - var stdout = process.StandardOutput.ReadToEndAsync(); - var stderr = process.StandardError.ReadToEndAsync(); - using (var timeout = new CancellationTokenSource(TimeSpan.FromMinutes(10))) await process.WaitForExitAsync(timeout.Token); - var output = await stdout + await stderr; - var diagnostics = Line().Matches(output) - .Select(m => new BuildDiagnostic(m.Groups["file"].Value.Trim(), m.Groups["sev"].Value, m.Groups["id"].Value, m.Groups["msg"].Value.Trim())) - .Distinct().ToList(); - var woven = Path.Combine(dir, "obj", Configuration, "net10.0", "metalama"); - var transformed = Directory.Exists(woven) - ? Directory.GetFiles(woven, "*.cs").ToDictionary(f => Path.GetFileName(f), f => File.ReadAllText(f)) - : new Dictionary(); - return new RefusalOutcome(process.ExitCode, output, diagnostics, transformed); - } - finally - { - try { Directory.Delete(dir, recursive: true); } catch (IOException) { } catch (UnauthorizedAccessException) { } - } - } - - [GeneratedRegex(@"^(?[^\r\n(]+)\((?\d+),(?\d+)\): (?warning|error) (?[A-Z]+\d+): (?.*?)(?: \[[^\]\r\n]*\])?\r?$", RegexOptions.Multiline)] - private static partial Regex Line(); -} diff --git a/tools/probe/corpus/harness/BuildRoslyn.cs b/tools/probe/corpus/harness/BuildRoslyn.cs deleted file mode 100644 index 2f3584d1..00000000 --- a/tools/probe/corpus/harness/BuildRoslyn.cs +++ /dev/null @@ -1,167 +0,0 @@ -// The analyzer probes' compiler (C17 CMTK0014, C19 CMTK0010): a CSharpCompilation over the real CodoMetis.TypeKit and the -// running framework, with the CMTK analyzer that reports the claim's id attached, as test/CodoMetis.TypeKit.Analyzers.Tests -// runs it. Sources carry markup {|#label:...|}; a marked span is where the probe expects (or forbids) a report. -using System.Collections.Immutable; -using System.Reflection; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Text; -namespace Probes.Build; - -/// One marked span of a source file, by its label. -public sealed record Mark(string Label, string File, TextSpan Span, string Text); - -/// A source file whose markup was taken out, with the spans it marked. -public sealed record Marked(string File, string Text, IReadOnlyList Marks) -{ - /// Strips {|#label:…|} (not nested) and records each span in the stripped text. - public static Marked Parse(string file, string source) - { - var sb = new System.Text.StringBuilder(); var marks = new List(); var i = 0; - while (i < source.Length) - { - var open = source.IndexOf("{|#", i, StringComparison.Ordinal); - if (open < 0) { sb.Append(source, i, source.Length - i); break; } - sb.Append(source, i, open - i); - var colon = source.IndexOf(':', open); - var label = source[(open + 3)..colon]; - var close = source.IndexOf("|}", colon, StringComparison.Ordinal); - if (close < 0) throw new InvalidOperationException($"unclosed markup {label} in {file}"); - var inner = source[(colon + 1)..close]; - if (inner.Contains("{|", StringComparison.Ordinal)) throw new InvalidOperationException($"nested markup in {label} of {file}"); - marks.Add(new Mark(label, file, new TextSpan(sb.Length, inner.Length), inner)); - sb.Append(inner); - i = close + 2; - } - return new Marked(file, sb.ToString(), marks); - } -} - -/// What one compilation reported: compiler errors, the analyzer's diagnostics, analyzer failures. -public sealed record Analysis(IReadOnlyList Errors, IReadOnlyList Reported, IReadOnlyList AnalyzerFailures, IReadOnlyList Files) -{ - public IEnumerable Marks => Files.SelectMany(f => f.Marks); - public static string Where(Diagnostic d) => $"{d.Location.SourceTree?.FilePath}:{d.Location.SourceSpan} '{d.Location.SourceTree?.GetText().ToString(d.Location.SourceSpan)}'"; - public string ErrorText() => string.Join("; ", Errors.Take(5).Select(e => $"{e.Id} {Where(e)}: {e.GetMessage()}")); -} - -public static class Rz -{ - static readonly Lazy> Refs = new(() => - { - // The running shared framework (implementation assemblies, as the probe's own process binds), plus the real base package and NodaTime. - var framework = Path.GetDirectoryName(typeof(object).Assembly.Location)!; - var tpa = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")!).Split(Path.PathSeparator) - .Where(p => Path.GetDirectoryName(p) == framework && Path.GetFileName(p) is var n && (n.StartsWith("System.") || n.StartsWith("Microsoft.") || n is "mscorlib.dll" or "netstandard.dll")); - return [.. tpa.Concat([typeof(CodoMetis.TypeKit.Option<>).Assembly.Location, typeof(NodaTime.Instant).Assembly.Location]) - .Distinct().Select(p => (MetadataReference)MetadataReference.CreateFromFile(p))]; - }); - - /// The CMTK analyzers that report , found by the id they declare, never by type name. - public static ImmutableArray AnalyzersFor(string id) => - [ - .. typeof(CodoMetis.TypeKit.Analyzers.TypeArgumentConstraintAnalyzer).Assembly.GetTypes() - .Where(t => !t.IsAbstract && typeof(DiagnosticAnalyzer).IsAssignableFrom(t) && t.GetCustomAttribute() is not null) - .Select(t => (DiagnosticAnalyzer)Activator.CreateInstance(t)!) - .Where(a => a.SupportedDiagnostics.Any(d => d.Id == id)), - ]; - - public static async Task Analyze(string id, IEnumerable<(string File, string Source)> sources) - { - var files = sources.Select(s => Marked.Parse(s.File, s.Source)).ToList(); - var parse = new CSharpParseOptions(LanguageVersion.Latest); - var trees = files.Select(f => CSharpSyntaxTree.ParseText(f.Text, parse, path: f.File)).ToList(); - var compilation = CSharpCompilation.Create("ProbeBuild" + Guid.NewGuid().ToString("N"), trees, Refs.Value, - new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, nullableContextOptions: NullableContextOptions.Enable)); - var analyzers = AnalyzersFor(id); - if (analyzers.Length == 0) throw new InvalidOperationException($"no CMTK analyzer declares {id}"); - var failures = new List(); - var options = new CompilationWithAnalyzersOptions(new AnalyzerOptions([]), (ex, analyzer, diagnostic) => { lock (failures) failures.Add(diagnostic); }, - concurrentAnalysis: false, logAnalyzerExecutionTime: false); - var with = compilation.WithAnalyzers(analyzers, options); - var analyzerDiagnostics = await with.GetAnalyzerDiagnosticsAsync(CancellationToken.None); - var errors = compilation.GetDiagnostics().Where(d => d.Severity == DiagnosticSeverity.Error).ToList(); - failures.AddRange(analyzerDiagnostics.Where(d => d.Id == "AD0001")); - return new Analysis(errors, [.. analyzerDiagnostics.Where(d => d.Id == id)], failures, files); - } - - /// - /// Compares the reports with the marks: every mark in reported exactly once at its span, nothing - /// reported anywhere else. Null when they agree, else what differs. - /// - public static string? Agree(Analysis a, IReadOnlySet expected, Func? message = null) => - Agree(a, expected, _ => true, outside: true, message); - - /// - /// The same over the marks selects, one check's share of a compilation: each of them in - /// reported exactly once at its span, the others silent, and with , nothing - /// reported outside every mark. A report at a mark the check does not judge is another check's. - /// - public static string? Agree(Analysis a, IReadOnlySet expected, Func judged, bool outside, Func? message = null) - { - var marks = a.Marks.ToList(); - foreach (var label in expected) if (!marks.Any(m => m.Label == label)) throw new InvalidOperationException($"no mark {label}"); - var problems = new List(); - foreach (var m in marks.Where(judged)) - { - var at = At(a, m); - if (expected.Contains(m.Label)) - { - if (at.Count != 1) problems.Add($"{m.Label} '{m.Text}': reported {at.Count} times, expected once"); - else if (message?.Invoke(at[0], m) is { } bad) problems.Add($"{m.Label} '{m.Text}': {bad}"); - } - else if (at.Count != 0) problems.Add($"{m.Label} '{m.Text}': reported, expected silent ({at[0].GetMessage()})"); - } - if (outside) problems.AddRange(Outside(a).Select(d => $"reported outside every mark at {Analysis.Where(d)}: {d.GetMessage()}")); - return problems.Count == 0 ? null : string.Join("; ", problems); - } - - /// The reports exactly at a mark's span. - public static List At(Analysis a, Mark m) => - [.. a.Reported.Where(d => d.Location.SourceTree?.FilePath == m.File && d.Location.SourceSpan == m.Span)]; - - /// The reports whose span holds a mark's: at it, or at the syntax around it. - public static List Around(Analysis a, Mark m) => - [.. a.Reported.Where(d => d.Location.SourceTree?.FilePath == m.File && d.Location.SourceSpan.Contains(m.Span))]; - - /// The reports whose span holds no mark. - public static List Outside(Analysis a) => - [.. a.Reported.Where(d => !a.Marks.Any(m => d.Location.SourceTree?.FilePath == m.File && d.Location.SourceSpan.Contains(m.Span)))]; - - /// - /// Whether a value is reported, wherever around it: each mark names that is in - /// has exactly one report at or around it, the others none. Where the report sits is 's question, so a - /// report moved to the syntax around its value still counts here. Null when they agree, else what differs. - /// - public static string? Reported(Analysis a, IEnumerable judged, IReadOnlySet expected, Func? message = null) - { - var problems = new List(); - foreach (var label in judged) - { - var m = a.Marks.SingleOrDefault(x => x.Label == label) ?? throw new InvalidOperationException($"no mark {label}"); - var around = Around(a, m); - if (expected.Contains(label)) - { - if (around.Count != 1) problems.Add($"{m.Label} '{m.Text}': reported {around.Count} times, expected once"); - else if (message?.Invoke(around[0], m) is { } bad) problems.Add($"{m.Label} '{m.Text}': {bad}"); - } - else if (around.Count != 0) problems.Add($"{m.Label} '{m.Text}': reported, expected silent ({around[0].GetMessage()})"); - } - return problems.Count == 0 ? null : string.Join("; ", problems); - } - - /// - /// Where the reports sit: every report at or around a mark in is at the mark's own span, the value as - /// written, and none is outside every mark. Null when so, else what differs. - /// - public static string? WhereWritten(Analysis a, IReadOnlySet expected) - { - var problems = new List(); - foreach (var m in a.Marks.Where(m => expected.Contains(m.Label))) - foreach (var d in Around(a, m).Where(d => d.Location.SourceSpan != m.Span)) - problems.Add($"{m.Label} '{m.Text}': reported at {Analysis.Where(d)}, not at the value"); - problems.AddRange(Outside(a).Select(d => $"reported outside every mark at {Analysis.Where(d)}: {d.GetMessage()}")); - return problems.Count == 0 ? null : string.Join("; ", problems); - } -} diff --git a/tools/probe/corpus/harness/BuildSource.cs b/tools/probe/corpus/harness/BuildSource.cs deleted file mode 100644 index bc37edfc..00000000 --- a/tools/probe/corpus/harness/BuildSource.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Source text for the build family's probes (C17, C18, C19): a row's shape.* axes written as C#, for a compilation the probe -// makes itself (an analyzer run, or the consumer build of C18). Each piece names its types after a suffix, so the pieces of -// several rows can sit in one compilation. -namespace Probes.Build; - -public static class Src -{ - public const string Usings = - """ - #nullable enable - using System; - using System.Collections.Generic; - using System.Collections.Immutable; - using System.Threading.Tasks; - using CodoMetis.TypeKit; - using CodoMetis.TypeKit.ClosedSets; - using CodoMetis.TypeKit.ValueObjects; - - """; - - /// shape.site: declared at the top level, nested in a class or a struct, two levels down, or in a generic type. - public static string AtSite(string site, string id, string inner) => site switch - { - "top-level" => inner, - "nested-in-class" => $"public static partial class O{id}\n{{\n{inner}\n}}", - "nested-in-struct" => $"public partial struct O{id}\n{{\n{inner}\n}}", - "nested-two-levels" => $"public static partial class O{id}\n{{\npublic sealed partial class P{id}\n{{\n{inner}\n}}\n}}", - "in-generic-type" => $"public static partial class O{id}\n{{\n{inner}\n}}", - _ => throw new ArgumentException("shape.site " + site), - }; - - /// shape.wrapped as a type name; enum, flags-enum and own-record-class are declared by . - public static string Wrapped(string wrapped, string id) => wrapped switch - { - "string" or "int" or "long" or "byte" or "ulong" or "decimal" or "double" or "bool" or "char" => wrapped, - "Guid" or "DateTime" or "DateTimeOffset" or "DateOnly" or "TimeOnly" or "TimeSpan" or "Uri" => "System." + wrapped, - "enum" => $"WEnum{id}", "flags-enum" => $"WFlags{id}", "NodaTime.Instant" => "global::NodaTime.Instant", "own-record-class" => $"WRec{id}", - _ => throw new ArgumentException("shape.wrapped " + wrapped), - }; - - public static string WrappedDeclarations(string id) => - $"public enum WEnum{id} {{ A, B }}\n[Flags] public enum WFlags{id} {{ None = 0, P = 1, Q = 2 }}\npublic sealed record WRec{id} {{ public int N {{ get; init; }} }}\n"; - - public static bool IsStructKind(string kind) => kind is "record-struct" or "validated-struct"; - - /// The type head of shape.containing, and the type as written from inside it (generic-type is closed over int outside). - public static string ContainerHead(string containing, string name, string primary = "") => containing switch - { - "class" => $"public sealed partial class {name}{primary}", - "record-class" => $"public sealed partial record {name}{primary}", - "struct" => $"public partial struct {name}{primary}", - "record-struct" => $"public partial record struct {name}{primary}", - "generic-type" => $"public sealed partial class {name}{primary}", - _ => throw new ArgumentException("shape.containing " + containing), - }; - - public static string ContainerSelf(string containing, string name) => containing == "generic-type" ? $"{name}" : name; -} diff --git a/tools/probe/corpus/harness/C09Shapes.g.cs b/tools/probe/corpus/harness/C09Shapes.g.cs deleted file mode 100644 index 2a365946..00000000 --- a/tools/probe/corpus/harness/C09Shapes.g.cs +++ /dev/null @@ -1,1031 +0,0 @@ -// by tools/probe/generators/decls.cs from rows/C09BaseRecordEqualityProbe.json.gz: one value object per row. Do not edit; regenerate with the rows. -#nullable enable -// CMTK1023: the bases' own equality is the point (C09) or beside it (C11); CS8851: a base's Equals without GetHashCode, on purpose. -#pragma warning disable CMTK1023, CS8851, CS1591 -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -namespace Probes.Build.C09; - -// row 0 -public static partial class O0 -{ -public sealed partial class P0 -{ -public abstract record B0_1 : System.IEquatable { bool System.IEquatable.Equals(B0_1? other) => ReferenceEquals(this, other); } -public sealed partial record V0 : B0_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PRec value) => new V0(value); -} -} -} - -// row 1 -public static partial class O1 -{ -public sealed partial class P1 -{ -public abstract record B1_3 { public virtual bool Equals(B1_3? other) => ReferenceEquals(this, other); } -public abstract record B1_2 : B1_3 { } -public abstract record B1_1 : B1_2 { } -public sealed partial record V1 : B1_1, IValue; -} -} - -// row 2 -public partial struct O2 -{ -public abstract record B2_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V2 : B2_1, IValidatedValue -{ - public static Result Create(long value) => new V2(value); -} -} - -// row 3 -public abstract record B3_1 { } -public sealed partial record V3 : B3_1, IValue; - -// row 4 -public interface IMark4 { int Mark(); } -public abstract record B4_1 : IMark4 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); int IMark4.Mark() => 1; } -public sealed partial record V4 : B4_1, IValidatedValue -{ - public static Result Create(string value) => new V4(value); -} - -// row 5 -public static partial class O5 -{ -public interface IMark5 { int Mark(); } -public abstract record B5_1 : System.IEquatable, IMark5 { bool System.IEquatable.Equals(B5_1? other) => ReferenceEquals(this, other); int IMark5.Mark() => 1; } -public sealed partial record V5 : B5_1, IValue; -} - -// row 6 -public static partial class O6 -{ -public abstract record B6_2 { } -public abstract record B6_1 : B6_2 { } -public sealed partial record V6 : B6_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V6(value); -} -} - -// row 7 -public partial struct O7 -{ -public abstract record B7_2 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B7_1 : B7_2 { } -public sealed partial record V7 : B7_1, IValue; -} - -// row 8 -public partial struct O8 -{ -public abstract record B8_1 : System.IEquatable { bool System.IEquatable.Equals(B8_1? other) => ReferenceEquals(this, other); } -public sealed partial record V8 : B8_1, IValue; -} - -// row 9 -public static partial class O9 -{ -public sealed partial class P9 -{ -public interface IMark9 { int Mark(); } -public abstract record B9_1 : IMark9 { int IMark9.Mark() => 1; } -public sealed partial record V9 : B9_1, IValue; -} -} - -// row 10 -public abstract record B10_2 { public virtual bool Equals(B10_2? other) => ReferenceEquals(this, other); } -public abstract record B10_1 : B10_2 { } -public sealed partial record V10 : B10_1, IValidatedValue -{ - public static Result Create(global::System.DateOnly value) => new V10(value); -} - -// row 11 -public static partial class O11 -{ -public abstract record B11_1 { public virtual bool Equals(B11_1? other) => ReferenceEquals(this, other); } -public sealed partial record V11 : B11_1, IValidatedValue -{ - public static Result Create(global::System.Guid value) => new V11(value); -} -} - -// row 12 -public partial struct O12 -{ -public abstract record B12_2 : System.IEquatable { bool System.IEquatable.Equals(B12_2? other) => ReferenceEquals(this, other); } -public abstract record B12_1 : B12_2 { } -public sealed partial record V12 : B12_1, IValidatedValue -{ - public static Result Create(ulong value) => new V12(value); -} -} - -// row 13 -public partial struct O13 -{ -public abstract record B13_3 { public virtual bool Equals(B13_3? other) => ReferenceEquals(this, other); } -public abstract record B13_2 : B13_3 { } -public abstract record B13_1 : B13_2 { } -public sealed partial record V13 : B13_1, IValidatedValue -{ - public static Result Create(decimal value) => new V13(value); -} -} - -// row 14 -public static partial class O14 -{ -public abstract record B14_3 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B14_2 : B14_3 { } -public abstract record B14_1 : B14_2 { } -public sealed partial record V14 : B14_1, IValue; -} - -// row 15 -public partial struct O15 -{ -public interface IMark15 { int Mark(); } -public abstract record B15_1 : IMark15 { public virtual bool Equals(B15_1? other) => ReferenceEquals(this, other); int IMark15.Mark() => 1; } -public sealed partial record V15 : B15_1, IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V15(value); -} -} - -// row 16 -public abstract record B16_3 : System.IEquatable { bool System.IEquatable.Equals(B16_3? other) => ReferenceEquals(this, other); } -public abstract record B16_2 : B16_3 { } -public abstract record B16_1 : B16_2 { } -public sealed partial record V16 : B16_1, IValue; - -// row 17 -public static partial class O17 -{ -public abstract record B17_1 : System.IEquatable { public virtual bool Equals(B17_1? other) => ReferenceEquals(this, other); bool System.IEquatable.Equals(B17_1? other) => ReferenceEquals(this, other); } -public sealed partial record V17 : B17_1, IValue; -} - -// row 18 -public static partial class O18 -{ -public sealed partial class P18 -{ -public abstract record B18_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V18 : B18_1, IValue; -} -} - -// row 19 -public abstract record B19_1 : System.IEquatable { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); bool System.IEquatable.Equals(B19_1? other) => ReferenceEquals(this, other); } -public sealed partial record V19 : B19_1, IValidatedValue -{ - public static Result Create(char value) => new V19(value); -} - -// row 20 -public abstract record B20_3 { } -public abstract record B20_2 : B20_3 { } -public abstract record B20_1 : B20_2 { } -public sealed partial record V20 : B20_1, IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V20(value); -} - -// row 21 -public static partial class O21 -{ -public abstract record B21_2 : System.IEquatable { bool System.IEquatable.Equals(B21_2? other) => ReferenceEquals(this, other); } -public abstract record B21_1 : B21_2 { } -public sealed partial record V21 : B21_1, IValue; -} - -// row 22 -public static partial class O22 -{ -public sealed partial class P22 -{ -public abstract record B22_2 { } -public abstract record B22_1 : B22_2 { } -public sealed partial record V22 : B22_1, IValue; -} -} - -// row 23 -public abstract record B23_1 : System.IEquatable { bool System.IEquatable.Equals(B23_1? other) => ReferenceEquals(this, other); } -public sealed partial record V23 : B23_1, IValidatedValue -{ - public static Result Create(global::System.TimeOnly value) => new V23(value); -} - -// row 24 -public static partial class O24 -{ -public sealed partial class P24 -{ -public abstract record B24_1 { } -public sealed partial record V24 : B24_1, IValidatedValue -{ - public static Result Create(global::System.Uri value) => new V24(value); -} -} -} - -// row 25 -public static partial class O25 -{ -public abstract record B25_1 { } -public sealed partial record V25 : B25_1, IValidatedValue -{ - public static Result Create(bool value) => new V25(value); -} -} - -// row 26 -public static partial class O26 -{ -public sealed partial class P26 -{ -public abstract record B26_3 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B26_2 : B26_3 { } -public abstract record B26_1 : B26_2 { } -public sealed partial record V26 : B26_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V26(value); -} -} -} - -// row 27 -public abstract record B27_2 { } -public abstract record B27_1 : B27_2 { } -public sealed partial record V27 : B27_1, IValue; - -// row 28 -public partial struct O28 -{ -public abstract record B28_1 { } -public sealed partial record V28 : B28_1, IValue; -} - -// row 29 -public partial struct O29 -{ -public interface IMark29 { int Mark(); } -public abstract record B29_1 : System.IEquatable, IMark29 { bool System.IEquatable.Equals(B29_1? other) => ReferenceEquals(this, other); int IMark29.Mark() => 1; } -public sealed partial record V29 : B29_1, IValue; -} - -// row 30 -public abstract record B30_2 : System.IEquatable { bool System.IEquatable.Equals(B30_2? other) => ReferenceEquals(this, other); } -public abstract record B30_1 : B30_2 { } -public sealed partial record V30 : B30_1, IValue; - -// row 31 -public static partial class O31 -{ -public sealed partial class P31 -{ -public abstract record B31_3 { } -public abstract record B31_2 : B31_3 { } -public abstract record B31_1 : B31_2 { } -public sealed partial record V31 : B31_1, IValue; -} -} - -// row 32 -public partial struct O32 -{ -public abstract record B32_1 : System.IEquatable { bool System.IEquatable.Equals(B32_1? other) => ReferenceEquals(this, other); } -public sealed partial record V32 : B32_1, IValidatedValue -{ - public static Result Create(double value) => new V32(value); -} -} - -// row 33 -public static partial class O33 -{ -public sealed partial class P33 -{ -public abstract record B33_1 : System.IEquatable { public virtual bool Equals(B33_1? other) => ReferenceEquals(this, other); bool System.IEquatable.Equals(B33_1? other) => ReferenceEquals(this, other); } -public sealed partial record V33 : B33_1, IValue; -} -} - -// row 34 -public partial struct O34 -{ -public abstract record B34_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V34 : B34_1, IValidatedValue -{ - public static Result Create(global::System.DateTimeOffset value) => new V34(value); -} -} - -// row 35 -public abstract record B35_3 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B35_2 : B35_3 { } -public abstract record B35_1 : B35_2 { } -public sealed partial record V35 : B35_1, IValue; - -// row 36 -public static partial class O36 -{ -public abstract record B36_3 { } -public abstract record B36_2 : B36_3 { } -public abstract record B36_1 : B36_2 { } -public sealed partial record V36 : B36_1, IValue; -} - -// row 37 -public static partial class O37 -{ -public abstract record B37_1 : System.IEquatable { bool System.IEquatable.Equals(B37_1? other) => ReferenceEquals(this, other); } -public sealed partial record V37 : B37_1, IValue; -} - -// row 38 -public partial struct O38 -{ -public abstract record B38_2 : System.IEquatable { bool System.IEquatable.Equals(B38_2? other) => ReferenceEquals(this, other); } -public abstract record B38_1 : B38_2 { } -public sealed partial record V38 : B38_1, IValue; -} - -// row 39 -public abstract record B39_2 { public virtual bool Equals(B39_2? other) => ReferenceEquals(this, other); } -public abstract record B39_1 : B39_2 { } -public sealed partial record V39 : B39_1, IValidatedValue -{ - public static Result Create(byte value) => new V39(value); -} - -// row 40 -public partial struct O40 -{ -public abstract record B40_3 { public virtual bool Equals(B40_3? other) => ReferenceEquals(this, other); } -public abstract record B40_2 : B40_3 { } -public abstract record B40_1 : B40_2 { } -public sealed partial record V40 : B40_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V40(value); -} -} - -// row 41 -public abstract record B41_3 { } -public abstract record B41_2 : B41_3 { } -public abstract record B41_1 : B41_2 { } -public sealed partial record V41 : B41_1, IValidatedValue -{ - public static Result Create(global::System.TimeSpan value) => new V41(value); -} - -// row 42 -public partial struct O42 -{ -public interface IMark42 { int Mark(); } -public abstract record B42_1 : IMark42 { public virtual bool Equals(B42_1? other) => ReferenceEquals(this, other); int IMark42.Mark() => 1; } -public sealed partial record V42 : B42_1, IValue; -} - -// row 43 -public partial struct O43 -{ -public abstract record B43_1 { public virtual bool Equals(B43_1? other) => ReferenceEquals(this, other); } -public sealed partial record V43 : B43_1, IValue; -} - -// row 44 -public partial struct O44 -{ -public abstract record B44_1 : System.IEquatable { public virtual bool Equals(B44_1? other) => ReferenceEquals(this, other); bool System.IEquatable.Equals(B44_1? other) => ReferenceEquals(this, other); } -public sealed partial record V44 : B44_1, IValue; -} - -// row 45 -public static partial class O45 -{ -public abstract record B45_1 { } -public sealed partial record V45 : B45_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V45(value); -} -} - -// row 46 -public static partial class O46 -{ -public interface IMark46 { int Mark(); } -public abstract record B46_1 : System.IEquatable, IMark46 { bool System.IEquatable.Equals(B46_1? other) => ReferenceEquals(this, other); int IMark46.Mark() => 1; } -public sealed partial record V46 : B46_1, IValidatedValue -{ - public static Result Create(long value) => new V46(value); -} -} - -// row 47 -public abstract record B47_3 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B47_2 : B47_3 { } -public abstract record B47_1 : B47_2 { } -public sealed partial record V47 : B47_1, IValue; - -// row 48 -public partial struct O48 -{ -public abstract record B48_3 { } -public abstract record B48_2 : B48_3 { } -public abstract record B48_1 : B48_2 { } -public sealed partial record V48 : B48_1, IValue; -} - -// row 49 -public interface IMark49 { int Mark(); } -public abstract record B49_1 : IMark49 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); int IMark49.Mark() => 1; } -public sealed partial record V49 : B49_1, IValue; - -// row 50 -public static partial class O50 -{ -public sealed partial class P50 -{ -public abstract record B50_3 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B50_2 : B50_3 { } -public abstract record B50_1 : B50_2 { } -public sealed partial record V50 : B50_1, IValue; -} -} - -// row 51 -public abstract record B51_1 : System.IEquatable { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); bool System.IEquatable.Equals(B51_1? other) => ReferenceEquals(this, other); } -public sealed partial record V51 : B51_1, IValidatedValue -{ - public static Result Create(bool value) => new V51(value); -} - -// row 52 -public abstract record B52_2 { } -public abstract record B52_1 : B52_2 { } -public sealed partial record V52 : B52_1, IValue; - -// row 53 -public partial struct O53 -{ -public interface IMark53 { int Mark(); } -public abstract record B53_1 : IMark53 { int IMark53.Mark() => 1; } -public sealed partial record V53 : B53_1, IValue; -} - -// row 54 -public partial struct O54 -{ -public abstract record B54_1 : System.IEquatable { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); bool System.IEquatable.Equals(B54_1? other) => ReferenceEquals(this, other); } -public sealed partial record V54 : B54_1, IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V54(value); -} -} - -// row 55 -public partial struct O55 -{ -public abstract record B55_3 : System.IEquatable { bool System.IEquatable.Equals(B55_3? other) => ReferenceEquals(this, other); } -public abstract record B55_2 : B55_3 { } -public abstract record B55_1 : B55_2 { } -public sealed partial record V55 : B55_1, IValue; -} - -// row 56 -public interface IMark56 { int Mark(); } -public abstract record B56_1 : IMark56 { int IMark56.Mark() => 1; } -public sealed partial record V56 : B56_1, IValidatedValue -{ - public static Result Create(decimal value) => new V56(value); -} - -// row 57 -public static partial class O57 -{ -public abstract record B57_1 { public virtual bool Equals(B57_1? other) => ReferenceEquals(this, other); } -public sealed partial record V57 : B57_1, IValidatedValue -{ - public static Result Create(double value) => new V57(value); -} -} - -// row 58 -public interface IMark58 { int Mark(); } -public abstract record B58_1 : IMark58 { public virtual bool Equals(B58_1? other) => ReferenceEquals(this, other); int IMark58.Mark() => 1; } -public sealed partial record V58 : B58_1, IValidatedValue -{ - public static Result Create(global::System.TimeOnly value) => new V58(value); -} - -// row 59 -public partial struct O59 -{ -public abstract record B59_1 : System.IEquatable { bool System.IEquatable.Equals(B59_1? other) => ReferenceEquals(this, other); } -public sealed partial record V59 : B59_1, IValue; -} - -// row 60 -public abstract record B60_1 : System.IEquatable { public virtual bool Equals(B60_1? other) => ReferenceEquals(this, other); bool System.IEquatable.Equals(B60_1? other) => ReferenceEquals(this, other); } -public sealed partial record V60 : B60_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V60(value); -} - -// row 61 -public abstract record B61_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V61 : B61_1, IValue; - -// row 62 -public static partial class O62 -{ -public abstract record B62_2 { public virtual bool Equals(B62_2? other) => ReferenceEquals(this, other); } -public abstract record B62_1 : B62_2 { } -public sealed partial record V62 : B62_1, IValue; -} - -// row 63 -public static partial class O63 -{ -public sealed partial class P63 -{ -public abstract record B63_1 : System.IEquatable { public virtual bool Equals(B63_1? other) => ReferenceEquals(this, other); bool System.IEquatable.Equals(B63_1? other) => ReferenceEquals(this, other); } -public sealed partial record V63 : B63_1, IValidatedValue -{ - public static Result Create(long value) => new V63(value); -} -} -} - -// row 64 -public static partial class O64 -{ -public sealed partial class P64 -{ -public abstract record B64_1 : System.IEquatable { bool System.IEquatable.Equals(B64_1? other) => ReferenceEquals(this, other); } -public sealed partial record V64 : B64_1, IValidatedValue -{ - public static Result Create(int value) => new V64(value); -} -} -} - -// row 65 -public static partial class O65 -{ -public abstract record B65_1 : System.IEquatable { bool System.IEquatable.Equals(B65_1? other) => ReferenceEquals(this, other); } -public sealed partial record V65 : B65_1, IValue; -} - -// row 66 -public static partial class O66 -{ -public sealed partial class P66 -{ -public abstract record B66_1 : System.IEquatable { bool System.IEquatable.Equals(B66_1? other) => ReferenceEquals(this, other); } -public sealed partial record V66 : B66_1, IValidatedValue -{ - public static Result Create(global::System.TimeSpan value) => new V66(value); -} -} -} - -// row 67 -public static partial class O67 -{ -public sealed partial class P67 -{ -public abstract record B67_1 { public virtual bool Equals(B67_1? other) => ReferenceEquals(this, other); } -public sealed partial record V67 : B67_1, IValue; -} -} - -// row 68 -public static partial class O68 -{ -public abstract record B68_1 { public virtual bool Equals(B68_1? other) => ReferenceEquals(this, other); } -public sealed partial record V68 : B68_1, IValidatedValue -{ - public static Result Create(ulong value) => new V68(value); -} -} - -// row 69 -public static partial class O69 -{ -public sealed partial class P69 -{ -public abstract record B69_2 { public virtual bool Equals(B69_2? other) => ReferenceEquals(this, other); } -public abstract record B69_1 : B69_2 { } -public sealed partial record V69 : B69_1, IValue; -} -} - -// row 70 -public abstract record B70_2 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B70_1 : B70_2 { } -public sealed partial record V70 : B70_1, IValidatedValue -{ - public static Result Create(global::System.Uri value) => new V70(value); -} - -// row 71 -public interface IMark71 { int Mark(); } -public abstract record B71_1 : System.IEquatable, IMark71 { bool System.IEquatable.Equals(B71_1? other) => ReferenceEquals(this, other); int IMark71.Mark() => 1; } -public sealed partial record V71 : B71_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V71(value); -} - -// row 72 -public static partial class O72 -{ -public abstract record B72_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V72 : B72_1, IValue; -} - -// row 73 -public static partial class O73 -{ -public sealed partial class P73 -{ -public abstract record B73_1 : System.IEquatable { bool System.IEquatable.Equals(B73_1? other) => ReferenceEquals(this, other); } -public sealed partial record V73 : B73_1, IValue; -} -} - -// row 74 -public static partial class O74 -{ -public sealed partial class P74 -{ -public abstract record B74_2 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B74_1 : B74_2 { } -public sealed partial record V74 : B74_1, IValidatedValue -{ - public static Result Create(double value) => new V74(value); -} -} -} - -// row 75 -public static partial class O75 -{ -public abstract record B75_1 : System.IEquatable { bool System.IEquatable.Equals(B75_1? other) => ReferenceEquals(this, other); } -public sealed partial record V75 : B75_1, IValue; -} - -// row 76 -public static partial class O76 -{ -public interface IMark76 { int Mark(); } -public abstract record B76_1 : System.IEquatable, IMark76 { bool System.IEquatable.Equals(B76_1? other) => ReferenceEquals(this, other); int IMark76.Mark() => 1; } -public sealed partial record V76 : B76_1, IValidatedValue -{ - public static Result Create(global::System.DateTimeOffset value) => new V76(value); -} -} - -// row 77 -public static partial class O77 -{ -public sealed partial class P77 -{ -public abstract record B77_2 : System.IEquatable { bool System.IEquatable.Equals(B77_2? other) => ReferenceEquals(this, other); } -public abstract record B77_1 : B77_2 { } -public sealed partial record V77 : B77_1, IValidatedValue -{ - public static Result Create(char value) => new V77(value); -} -} -} - -// row 78 -public static partial class O78 -{ -public sealed partial class P78 -{ -public abstract record B78_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V78 : B78_1, IValue; -} -} - -// row 79 -public static partial class O79 -{ -public abstract record B79_2 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B79_1 : B79_2 { } -public sealed partial record V79 : B79_1, IValue; -} - -// row 80 -public static partial class O80 -{ -public sealed partial class P80 -{ -public abstract record B80_3 { public virtual bool Equals(B80_3? other) => ReferenceEquals(this, other); } -public abstract record B80_2 : B80_3 { } -public abstract record B80_1 : B80_2 { } -public sealed partial record V80 : B80_1, IValidatedValue -{ - public static Result Create(global::System.TimeOnly value) => new V80(value); -} -} -} - -// row 81 -public static partial class O81 -{ -public interface IMark81 { int Mark(); } -public abstract record B81_1 : System.IEquatable, IMark81 { bool System.IEquatable.Equals(B81_1? other) => ReferenceEquals(this, other); int IMark81.Mark() => 1; } -public sealed partial record V81 : B81_1, IValue; -} - -// row 82 -public static partial class O82 -{ -public interface IMark82 { int Mark(); } -public abstract record B82_1 : IMark82 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); int IMark82.Mark() => 1; } -public sealed partial record V82 : B82_1, IValue; -} - -// row 83 -public abstract record B83_1 : System.IEquatable { bool System.IEquatable.Equals(B83_1? other) => ReferenceEquals(this, other); } -public sealed partial record V83 : B83_1, IValue; - -// row 84 -public abstract record B84_1 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public sealed partial record V84 : B84_1, IValidatedValue -{ - public static Result Create(char value) => new V84(value); -} - -// row 85 -public static partial class O85 -{ -public interface IMark85 { int Mark(); } -public abstract record B85_1 : System.IEquatable, IMark85 { bool System.IEquatable.Equals(B85_1? other) => ReferenceEquals(this, other); int IMark85.Mark() => 1; } -public sealed partial record V85 : B85_1, IValue; -} - -// row 86 -public partial struct O86 -{ -public abstract record B86_2 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); } -public abstract record B86_1 : B86_2 { } -public sealed partial record V86 : B86_1, IValue; -} - -// row 87 -public partial struct O87 -{ -public abstract record B87_1 : System.IEquatable { bool System.IEquatable.Equals(B87_1? other) => ReferenceEquals(this, other); } -public sealed partial record V87 : B87_1, IValidatedValue -{ - public static Result Create(global::System.DateTimeOffset value) => new V87(value); -} -} - -// row 88 -public static partial class O88 -{ -public abstract record B88_2 : System.IEquatable { bool System.IEquatable.Equals(B88_2? other) => ReferenceEquals(this, other); } -public abstract record B88_1 : B88_2 { } -public sealed partial record V88 : B88_1, IValidatedValue -{ - public static Result Create(global::System.Guid value) => new V88(value); -} -} - -// row 89 -public static partial class O89 -{ -public abstract record B89_1 : System.IEquatable { bool System.IEquatable.Equals(B89_1? other) => ReferenceEquals(this, other); } -public sealed partial record V89 : B89_1, IValue; -} - -// row 90 -public abstract record B90_3 : System.IEquatable { bool System.IEquatable.Equals(B90_3? other) => ReferenceEquals(this, other); } -public abstract record B90_2 : B90_3 { } -public abstract record B90_1 : B90_2 { } -public sealed partial record V90 : B90_1, IValidatedValue -{ - public static Result Create(long value) => new V90(value); -} - -// row 91 -public static partial class O91 -{ -public sealed partial class P91 -{ -public abstract record B91_2 : System.IEquatable { bool System.IEquatable.Equals(B91_2? other) => ReferenceEquals(this, other); } -public abstract record B91_1 : B91_2 { } -public sealed partial record V91 : B91_1, IValue; -} -} - -// row 92 -public abstract record B92_3 : System.IEquatable { bool System.IEquatable.Equals(B92_3? other) => ReferenceEquals(this, other); } -public abstract record B92_2 : B92_3 { } -public abstract record B92_1 : B92_2 { } -public sealed partial record V92 : B92_1, IValidatedValue -{ - public static Result Create(bool value) => new V92(value); -} - -// row 93 -public abstract record B93_1 : System.IEquatable { bool System.IEquatable.Equals(B93_1? other) => ReferenceEquals(this, other); } -public sealed partial record V93 : B93_1, IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V93(value); -} - -// row 94 -public static partial class O94 -{ -public sealed partial class P94 -{ -public interface IMark94 { int Mark(); } -public abstract record B94_1 : System.IEquatable, IMark94 { bool System.IEquatable.Equals(B94_1? other) => ReferenceEquals(this, other); int IMark94.Mark() => 1; } -public sealed partial record V94 : B94_1, IValue; -} -} - -// row 95 -public static partial class O95 -{ -public abstract record B95_1 : System.IEquatable { bool System.IEquatable.Equals(B95_1? other) => ReferenceEquals(this, other); } -public sealed partial record V95 : B95_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V95(value); -} -} - -// row 96 -public partial struct O96 -{ -public interface IMark96 { int Mark(); } -public abstract record B96_1 : IMark96 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); int IMark96.Mark() => 1; } -public sealed partial record V96 : B96_1, IValue; -} - -// row 97 -public static partial class O97 -{ -public sealed partial class P97 -{ -public abstract record B97_3 { } -public abstract record B97_2 : B97_3 { } -public abstract record B97_1 : B97_2 { } -public sealed partial record V97 : B97_1, IValue; -} -} - -// row 98 -public static partial class O98 -{ -public interface IMark98 { int Mark(); } -public abstract record B98_1 : System.IEquatable, IMark98 { bool System.IEquatable.Equals(B98_1? other) => ReferenceEquals(this, other); int IMark98.Mark() => 1; } -public sealed partial record V98 : B98_1, IValue; -} - -// row 99 -public static partial class O99 -{ -public interface IMark99 { int Mark(); } -public abstract record B99_1 : IMark99 { public override int GetHashCode() => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(this); int IMark99.Mark() => 1; } -public sealed partial record V99 : B99_1, IValidatedValue -{ - public static Result Create(double value) => new V99(value); -} -} - -// row 100 -public static partial class O100 -{ -public abstract record B100_3 : System.IEquatable { bool System.IEquatable.Equals(B100_3? other) => ReferenceEquals(this, other); } -public abstract record B100_2 : B100_3 { } -public abstract record B100_1 : B100_2 { } -public sealed partial record V100 : B100_1, IValidatedValue -{ - public static Result Create(global::System.Uri value) => new V100(value); -} -} - -public static partial class C09Table -{ - public static readonly C09Case[] Cases = - [ - new(0, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=own-record-class", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O0.P0.V0), [typeof(O0.P0.B0_1)], x => O0.P0.V0.FromKnownGood((global::Probes.Shapes.PRec)x), []), - new(1, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTimeOffset", "sealed-record-class", "nested-two-levels", "base-depth-3", typeof(O1.P1.V1), [typeof(O1.P1.B1_1), typeof(O1.P1.B1_2), typeof(O1.P1.B1_3)], x => O1.P1.V1.From((global::System.DateTimeOffset)x), []), - new(2, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=long", "validated-class", "nested-in-struct", "base-depth-1", typeof(O2.V2), [typeof(O2.B2_1)], x => O2.V2.FromKnownGood((long)x), []), - new(3, "base-equality=none;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=DateOnly", "sealed-record-class", "top-level", "base-depth-1", typeof(V3), [typeof(B3_1)], x => V3.From((global::System.DateOnly)x), []), - new(4, "base-equality=override-GetHashCode;collection=Distinct;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=string", "validated-class", "top-level", "explicit-interface-member", typeof(V4), [typeof(B4_1)], x => V4.FromKnownGood((string)x), []), - new(5, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=Uri", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O5.V5), [typeof(O5.B5_1)], x => O5.V5.From((global::System.Uri)x), []), - new(6, "base-equality=none;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=flags-enum", "validated-class", "nested-in-class", "base-depth-2", typeof(O6.V6), [typeof(O6.B6_1), typeof(O6.B6_2)], x => O6.V6.FromKnownGood((global::Probes.Shapes.PFlags)x), []), - new(7, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=TimeSpan", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O7.V7), [typeof(O7.B7_1), typeof(O7.B7_2)], x => O7.V7.From((global::System.TimeSpan)x), []), - new(8, "base-equality=none;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=TimeOnly", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O8.V8), [typeof(O8.B8_1)], x => O8.V8.From((global::System.TimeOnly)x), []), - new(9, "base-equality=none;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=byte", "sealed-record-class", "nested-two-levels", "explicit-interface-member", typeof(O9.P9.V9), [typeof(O9.P9.B9_1)], x => O9.P9.V9.From((byte)x), []), - new(10, "base-equality=override-Equals;collection=Dictionary-key;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=DateOnly", "validated-class", "top-level", "base-depth-2", typeof(V10), [typeof(B10_1), typeof(B10_2)], x => V10.FromKnownGood((global::System.DateOnly)x), []), - new(11, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=Guid", "validated-class", "nested-in-class", "base-depth-1", typeof(O11.V11), [typeof(O11.B11_1)], x => O11.V11.FromKnownGood((global::System.Guid)x), []), - new(12, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=ulong", "validated-class", "nested-in-struct", "base-depth-2", typeof(O12.V12), [typeof(O12.B12_1), typeof(O12.B12_2)], x => O12.V12.FromKnownGood((ulong)x), []), - new(13, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=decimal", "validated-class", "nested-in-struct", "base-depth-3", typeof(O13.V13), [typeof(O13.B13_1), typeof(O13.B13_2), typeof(O13.B13_3)], x => O13.V13.FromKnownGood((decimal)x), []), - new(14, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=int", "sealed-record-class", "nested-in-class", "base-depth-3", typeof(O14.V14), [typeof(O14.B14_1), typeof(O14.B14_2), typeof(O14.B14_3)], x => O14.V14.From((int)x), [("shape.kind", "sealed-record-class")]), - new(15, "base-equality=override-Equals;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=NodaTime.Instant", "validated-class", "nested-in-struct", "explicit-interface-member", typeof(O15.V15), [typeof(O15.B15_1)], x => O15.V15.FromKnownGood((global::NodaTime.Instant)x), []), - new(16, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=double", "sealed-record-class", "top-level", "base-depth-3", typeof(V16), [typeof(B16_1), typeof(B16_2), typeof(B16_3)], x => V16.From((double)x), []), - new(17, "base-equality=override-Equals;collection=Dictionary-key;shape.inheritance=base-explicit-IEquatable;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeSpan", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O17.V17), [typeof(O17.B17_1)], x => O17.V17.From((global::System.TimeSpan)x), [("shape.kind", "sealed-record-class")]), - new(18, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=flags-enum", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O18.P18.V18), [typeof(O18.P18.B18_1)], x => O18.P18.V18.From((global::Probes.Shapes.PFlags)x), []), - new(19, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=char", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V19), [typeof(B19_1)], x => V19.FromKnownGood((char)x), []), - new(20, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=DateTime", "validated-class", "top-level", "base-depth-3", typeof(V20), [typeof(B20_1), typeof(B20_2), typeof(B20_3)], x => V20.FromKnownGood((global::System.DateTime)x), []), - new(21, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateTime", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O21.V21), [typeof(O21.B21_1), typeof(O21.B21_2)], x => O21.V21.From((global::System.DateTime)x), []), - new(22, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=NodaTime.Instant", "sealed-record-class", "nested-two-levels", "base-depth-2", typeof(O22.P22.V22), [typeof(O22.P22.B22_1), typeof(O22.P22.B22_2)], x => O22.P22.V22.From((global::NodaTime.Instant)x), []), - new(23, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=TimeOnly", "validated-class", "top-level", "base-depth-1", typeof(V23), [typeof(B23_1)], x => V23.FromKnownGood((global::System.TimeOnly)x), []), - new(24, "base-equality=none;collection=Distinct;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Uri", "validated-class", "nested-two-levels", "base-depth-1", typeof(O24.P24.V24), [typeof(O24.P24.B24_1)], x => O24.P24.V24.FromKnownGood((global::System.Uri)x), []), - new(25, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=bool", "validated-class", "nested-in-class", "base-depth-1", typeof(O25.V25), [typeof(O25.B25_1)], x => O25.V25.FromKnownGood((bool)x), []), - new(26, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=enum", "validated-class", "nested-two-levels", "base-depth-3", typeof(O26.P26.V26), [typeof(O26.P26.B26_1), typeof(O26.P26.B26_2), typeof(O26.P26.B26_3)], x => O26.P26.V26.FromKnownGood((global::Probes.Shapes.PEnum)x), []), - new(27, "base-equality=none;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=long", "sealed-record-class", "top-level", "base-depth-2", typeof(V27), [typeof(B27_1), typeof(B27_2)], x => V27.From((long)x), []), - new(28, "base-equality=none;collection=Distinct;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=own-record-class", "sealed-record-class", "nested-in-struct", "base-depth-1", typeof(O28.V28), [typeof(O28.B28_1)], x => O28.V28.From((global::Probes.Shapes.PRec)x), []), - new(29, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=bool", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O29.V29), [typeof(O29.B29_1)], x => O29.V29.From((bool)x), []), - new(30, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=int", "sealed-record-class", "top-level", "base-depth-2", typeof(V30), [typeof(B30_1), typeof(B30_2)], x => V30.From((int)x), []), - new(31, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=ulong", "sealed-record-class", "nested-two-levels", "base-depth-3", typeof(O31.P31.V31), [typeof(O31.P31.B31_1), typeof(O31.P31.B31_2), typeof(O31.P31.B31_3)], x => O31.P31.V31.From((ulong)x), []), - new(32, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=double", "validated-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O32.V32), [typeof(O32.B32_1)], x => O32.V32.FromKnownGood((double)x), []), - new(33, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=string", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O33.P33.V33), [typeof(O33.P33.B33_1)], x => O33.P33.V33.From((string)x), []), - new(34, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=DateTimeOffset", "validated-class", "nested-in-struct", "base-depth-1", typeof(O34.V34), [typeof(O34.B34_1)], x => O34.V34.FromKnownGood((global::System.DateTimeOffset)x), []), - new(35, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=Guid", "sealed-record-class", "top-level", "base-depth-3", typeof(V35), [typeof(B35_1), typeof(B35_2), typeof(B35_3)], x => V35.From((global::System.Guid)x), []), - new(36, "base-equality=none;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=char", "sealed-record-class", "nested-in-class", "base-depth-3", typeof(O36.V36), [typeof(O36.B36_1), typeof(O36.B36_2), typeof(O36.B36_3)], x => O36.V36.From((char)x), []), - new(37, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=decimal", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O37.V37), [typeof(O37.B37_1)], x => O37.V37.From((decimal)x), []), - new(38, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=enum", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O38.V38), [typeof(O38.B38_1), typeof(O38.B38_2)], x => O38.V38.From((global::Probes.Shapes.PEnum)x), []), - new(39, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=byte", "validated-class", "top-level", "base-depth-2", typeof(V39), [typeof(B39_1), typeof(B39_2)], x => V39.FromKnownGood((byte)x), []), - new(40, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=flags-enum", "validated-class", "nested-in-struct", "base-depth-3", typeof(O40.V40), [typeof(O40.B40_1), typeof(O40.B40_2), typeof(O40.B40_3)], x => O40.V40.FromKnownGood((global::Probes.Shapes.PFlags)x), []), - new(41, "base-equality=none;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=TimeSpan", "validated-class", "top-level", "base-depth-3", typeof(V41), [typeof(B41_1), typeof(B41_2), typeof(B41_3)], x => V41.FromKnownGood((global::System.TimeSpan)x), []), - new(42, "base-equality=override-Equals;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=char", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O42.V42), [typeof(O42.B42_1)], x => O42.V42.From((char)x), []), - new(43, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=int", "sealed-record-class", "nested-in-struct", "base-depth-1", typeof(O43.V43), [typeof(O43.B43_1)], x => O43.V43.From((int)x), []), - new(44, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Uri", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O44.V44), [typeof(O44.B44_1)], x => O44.V44.From((global::System.Uri)x), []), - new(45, "base-equality=none;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=enum", "validated-class", "nested-in-class", "base-depth-1", typeof(O45.V45), [typeof(O45.B45_1)], x => O45.V45.FromKnownGood((global::Probes.Shapes.PEnum)x), []), - new(46, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=long", "validated-class", "nested-in-class", "explicit-interface-member", typeof(O46.V46), [typeof(O46.B46_1)], x => O46.V46.FromKnownGood((long)x), []), - new(47, "base-equality=override-GetHashCode;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=NodaTime.Instant", "sealed-record-class", "top-level", "base-depth-3", typeof(V47), [typeof(B47_1), typeof(B47_2), typeof(B47_3)], x => V47.From((global::NodaTime.Instant)x), []), - new(48, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=string", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O48.V48), [typeof(O48.B48_1), typeof(O48.B48_2), typeof(O48.B48_3)], x => O48.V48.From((string)x), []), - new(49, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=own-record-class", "sealed-record-class", "top-level", "explicit-interface-member", typeof(V49), [typeof(B49_1)], x => V49.From((global::Probes.Shapes.PRec)x), [("shape.kind", "sealed-record-class")]), - new(50, "base-equality=override-GetHashCode;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateOnly", "sealed-record-class", "nested-two-levels", "base-depth-3", typeof(O50.P50.V50), [typeof(O50.P50.B50_1), typeof(O50.P50.B50_2), typeof(O50.P50.B50_3)], x => O50.P50.V50.From((global::System.DateOnly)x), []), - new(51, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=bool", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V51), [typeof(B51_1)], x => V51.FromKnownGood((bool)x), []), - new(52, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=DateTimeOffset", "sealed-record-class", "top-level", "base-depth-2", typeof(V52), [typeof(B52_1), typeof(B52_2)], x => V52.From((global::System.DateTimeOffset)x), []), - new(53, "base-equality=none;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Guid", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O53.V53), [typeof(O53.B53_1)], x => O53.V53.From((global::System.Guid)x), []), - new(54, "base-equality=override-GetHashCode;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=DateTime", "validated-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O54.V54), [typeof(O54.B54_1)], x => O54.V54.FromKnownGood((global::System.DateTime)x), []), - new(55, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=byte", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O55.V55), [typeof(O55.B55_1), typeof(O55.B55_2), typeof(O55.B55_3)], x => O55.V55.From((byte)x), []), - new(56, "base-equality=none;collection=Distinct;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=decimal", "validated-class", "top-level", "explicit-interface-member", typeof(V56), [typeof(B56_1)], x => V56.FromKnownGood((decimal)x), [("shape.kind", "validated-class")]), - new(57, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=double", "validated-class", "nested-in-class", "base-depth-1", typeof(O57.V57), [typeof(O57.B57_1)], x => O57.V57.FromKnownGood((double)x), []), - new(58, "base-equality=override-Equals;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=TimeOnly", "validated-class", "top-level", "explicit-interface-member", typeof(V58), [typeof(B58_1)], x => V58.FromKnownGood((global::System.TimeOnly)x), [("shape.kind", "validated-class")]), - new(59, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateOnly", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O59.V59), [typeof(O59.B59_1)], x => O59.V59.From((global::System.DateOnly)x), [("shape.kind", "sealed-record-class")]), - new(60, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=enum", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V60), [typeof(B60_1)], x => V60.FromKnownGood((global::Probes.Shapes.PEnum)x), []), - new(61, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=ulong", "sealed-record-class", "top-level", "base-depth-1", typeof(V61), [typeof(B61_1)], x => V61.From((ulong)x), []), - new(62, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=closed-set;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=own-record-class", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O62.V62), [typeof(O62.B62_1), typeof(O62.B62_2)], x => O62.V62.From((global::Probes.Shapes.PRec)x), [("shape.kind", "sealed-record-class")]), - new(63, "base-equality=override-Equals;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=long", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O63.P63.V63), [typeof(O63.P63.B63_1)], x => O63.P63.V63.FromKnownGood((long)x), []), - new(64, "base-equality=none;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=int", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O64.P64.V64), [typeof(O64.P64.B64_1)], x => O64.P64.V64.FromKnownGood((int)x), []), - new(65, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=string", "sealed-record-class", "nested-in-class", "base-depth-1", typeof(O65.V65), [typeof(O65.B65_1)], x => O65.V65.From((string)x), []), - new(66, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=TimeSpan", "validated-class", "nested-two-levels", "base-depth-1", typeof(O66.P66.V66), [typeof(O66.P66.B66_1)], x => O66.P66.V66.FromKnownGood((global::System.TimeSpan)x), []), - new(67, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTime", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O67.P67.V67), [typeof(O67.P67.B67_1)], x => O67.P67.V67.From((global::System.DateTime)x), []), - new(68, "base-equality=override-Equals;collection=Dictionary-key;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=ulong", "validated-class", "nested-in-class", "base-depth-1", typeof(O68.V68), [typeof(O68.B68_1)], x => O68.V68.FromKnownGood((ulong)x), [("shape.kind", "validated-class")]), - new(69, "base-equality=override-Equals;collection=Dictionary-key;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=bool", "sealed-record-class", "nested-two-levels", "base-depth-2", typeof(O69.P69.V69), [typeof(O69.P69.B69_1), typeof(O69.P69.B69_2)], x => O69.P69.V69.From((bool)x), []), - new(70, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=Uri", "validated-class", "top-level", "base-depth-2", typeof(V70), [typeof(B70_1), typeof(B70_2)], x => V70.FromKnownGood((global::System.Uri)x), []), - new(71, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=flags-enum", "validated-class", "top-level", "explicit-interface-member", typeof(V71), [typeof(B71_1)], x => V71.FromKnownGood((global::Probes.Shapes.PFlags)x), []), - new(72, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=byte", "sealed-record-class", "nested-in-class", "base-depth-1", typeof(O72.V72), [typeof(O72.B72_1)], x => O72.V72.From((byte)x), []), - new(73, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Guid", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O73.P73.V73), [typeof(O73.P73.B73_1)], x => O73.P73.V73.From((global::System.Guid)x), []), - new(74, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=double", "validated-class", "nested-two-levels", "base-depth-2", typeof(O74.P74.V74), [typeof(O74.P74.B74_1), typeof(O74.P74.B74_2)], x => O74.P74.V74.FromKnownGood((double)x), []), - new(75, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=NodaTime.Instant", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O75.V75), [typeof(O75.B75_1)], x => O75.V75.From((global::NodaTime.Instant)x), []), - new(76, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateTimeOffset", "validated-class", "nested-in-class", "explicit-interface-member", typeof(O76.V76), [typeof(O76.B76_1)], x => O76.V76.FromKnownGood((global::System.DateTimeOffset)x), []), - new(77, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=char", "validated-class", "nested-two-levels", "base-depth-2", typeof(O77.P77.V77), [typeof(O77.P77.B77_1), typeof(O77.P77.B77_2)], x => O77.P77.V77.FromKnownGood((char)x), []), - new(78, "base-equality=override-GetHashCode;collection=HashSet;shape.inheritance=base-depth-1;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=decimal", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O78.P78.V78), [typeof(O78.P78.B78_1)], x => O78.P78.V78.From((decimal)x), [("shape.kind", "sealed-record-class")]), - new(79, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeOnly", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O79.V79), [typeof(O79.B79_1), typeof(O79.B79_2)], x => O79.V79.From((global::System.TimeOnly)x), []), - new(80, "base-equality=override-Equals;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=TimeOnly", "validated-class", "nested-two-levels", "base-depth-3", typeof(O80.P80.V80), [typeof(O80.P80.B80_1), typeof(O80.P80.B80_2), typeof(O80.P80.B80_3)], x => O80.P80.V80.FromKnownGood((global::System.TimeOnly)x), []), - new(81, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=ulong", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O81.V81), [typeof(O81.B81_1)], x => O81.V81.From((ulong)x), []), - new(82, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateOnly", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O82.V82), [typeof(O82.B82_1)], x => O82.V82.From((global::System.DateOnly)x), []), - new(83, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=ulong", "sealed-record-class", "top-level", "base-explicit-IEquatable", typeof(V83), [typeof(B83_1)], x => V83.From((ulong)x), []), - new(84, "base-equality=override-GetHashCode;collection=Distinct;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=char", "validated-class", "top-level", "base-depth-1", typeof(V84), [typeof(B84_1)], x => V84.FromKnownGood((char)x), []), - new(85, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeSpan", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O85.V85), [typeof(O85.B85_1)], x => O85.V85.From((global::System.TimeSpan)x), []), - new(86, "base-equality=override-GetHashCode;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=decimal", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O86.V86), [typeof(O86.B86_1), typeof(O86.B86_2)], x => O86.V86.From((decimal)x), []), - new(87, "base-equality=none;collection=HashSet;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTimeOffset", "validated-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O87.V87), [typeof(O87.B87_1)], x => O87.V87.FromKnownGood((global::System.DateTimeOffset)x), []), - new(88, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=Guid", "validated-class", "nested-in-class", "base-depth-2", typeof(O88.V88), [typeof(O88.B88_1), typeof(O88.B88_2)], x => O88.V88.FromKnownGood((global::System.Guid)x), []), - new(89, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=in-generic-type;shape.wrapped=byte", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O89.V89), [typeof(O89.B89_1)], x => O89.V89.From((byte)x), [("shape.site", "nested-in-class")]), - new(90, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=long", "validated-class", "top-level", "base-depth-3", typeof(V90), [typeof(B90_1), typeof(B90_2), typeof(B90_3)], x => V90.FromKnownGood((long)x), []), - new(91, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=string", "sealed-record-class", "nested-two-levels", "base-depth-2", typeof(O91.P91.V91), [typeof(O91.P91.B91_1), typeof(O91.P91.B91_2)], x => O91.P91.V91.From((string)x), []), - new(92, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=bool", "validated-class", "top-level", "base-depth-3", typeof(V92), [typeof(B92_1), typeof(B92_2), typeof(B92_3)], x => V92.FromKnownGood((bool)x), [("shape.kind", "validated-class")]), - new(93, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=NodaTime.Instant", "validated-class", "top-level", "base-depth-1", typeof(V93), [typeof(B93_1)], x => V93.FromKnownGood((global::NodaTime.Instant)x), []), - new(94, "base-equality=explicit-IEquatable;collection=Distinct;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=int", "sealed-record-class", "nested-two-levels", "explicit-interface-member", typeof(O94.P94.V94), [typeof(O94.P94.B94_1)], x => O94.P94.V94.From((int)x), []), - new(95, "base-equality=none;collection=Distinct;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=flags-enum", "validated-class", "nested-in-class", "base-explicit-IEquatable", typeof(O95.V95), [typeof(O95.B95_1)], x => O95.V95.FromKnownGood((global::Probes.Shapes.PFlags)x), []), - new(96, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=enum", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O96.V96), [typeof(O96.B96_1)], x => O96.V96.From((global::Probes.Shapes.PEnum)x), []), - new(97, "base-equality=none;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=own-record-class", "sealed-record-class", "nested-two-levels", "base-depth-3", typeof(O97.P97.V97), [typeof(O97.P97.B97_1), typeof(O97.P97.B97_2), typeof(O97.P97.B97_3)], x => O97.P97.V97.From((global::Probes.Shapes.PRec)x), []), - new(98, "base-equality=explicit-IEquatable;collection=HashSet;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=DateTime", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O98.V98), [typeof(O98.B98_1)], x => O98.V98.From((global::System.DateTime)x), []), - new(99, "base-equality=override-GetHashCode;collection=Dictionary-key;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=in-generic-type;shape.wrapped=double", "validated-class", "nested-in-class", "explicit-interface-member", typeof(O99.V99), [typeof(O99.B99_1)], x => O99.V99.FromKnownGood((double)x), [("shape.site", "nested-in-class")]), - new(100, "base-equality=explicit-IEquatable;collection=Dictionary-key;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=in-generic-type;shape.wrapped=Uri", "validated-class", "nested-in-class", "base-depth-3", typeof(O100.V100), [typeof(O100.B100_1), typeof(O100.B100_2), typeof(O100.B100_3)], x => O100.V100.FromKnownGood((global::System.Uri)x), [("shape.site", "nested-in-class")]), - ]; -} diff --git a/tools/probe/corpus/harness/C11Shapes.g.cs b/tools/probe/corpus/harness/C11Shapes.g.cs deleted file mode 100644 index 992834fa..00000000 --- a/tools/probe/corpus/harness/C11Shapes.g.cs +++ /dev/null @@ -1,2596 +0,0 @@ -// by tools/probe/generators/decls.cs from rows/C11ParseShapesBuildProbe.json.gz: one value object per row. Do not edit; regenerate with the rows. -#nullable enable -// CMTK1023: the bases' own equality is the point (C09) or beside it (C11); CS8851: a base's Equals without GetHashCode, on purpose. -#pragma warning disable CMTK1023, CS8851, CS1591 -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -namespace Probes.Build.C11; - -// row 0 -public static partial class O0 -{ -public interface IMark0 { int Mark(); } -public sealed partial record V0 : IValue, IMark0 { int IMark0.Mark() => 1; } -} - -// row 1 -public sealed partial record V1 : IValidatedValue -{ - public static Result Create(global::System.TimeSpan value) => new V1(value); -} - -// row 2 -public partial struct O2 -{ -public abstract record B2_2 { } -public abstract record B2_1 : B2_2 { } -public sealed partial record V2 : B2_1, IValue { } -public abstract record BC2_2 { } -public abstract record BC2_1 : BC2_2 { } -public sealed partial record VC2 : BC2_1, IValue { } -} - -// row 3 -public static partial class O3 -{ -public sealed partial class P3 -{ -public readonly partial record struct V3 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V3(value); -} -public readonly partial record struct VC3 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC3(value); -} -} -} - -// row 4 -public interface IMark4 { int Mark(); } -public readonly partial record struct V4 : IValue, IMark4 { int IMark4.Mark() => 1; } -public readonly partial record struct VC4 : IValue, IMark4 { int IMark4.Mark() => 1; } - -// row 5 -public partial struct O5 -{ -public abstract record B5_1 { } -public sealed partial record V5 : B5_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V5(value); -} -public abstract record BC5_1 { } -public sealed partial record VC5 : BC5_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC5(value); -} -} - -// row 6 -public static partial class O6 -{ -public readonly partial record struct V6 : IValue { } -public readonly partial record struct VC6 : IValue { } -} - -// row 7 -public static partial class O7 -{ -public sealed partial class P7 -{ -public abstract record B7_1 { } -public sealed partial record V7 : B7_1, IValue { } -public abstract record BC7_1 { } -public sealed partial record VC7 : BC7_1, IValue { } -} -} - -// row 8 -public static partial class O8 -{ -public sealed partial class P8 -{ -public abstract record B8_1 : System.IEquatable { bool System.IEquatable.Equals(B8_1? other) => ReferenceEquals(this, other); } -public sealed partial record V8 : B8_1, IValue { } -} -} - -// row 9 -public partial struct O9 -{ -public abstract record B9_3 { } -public abstract record B9_2 : B9_3 { } -public abstract record B9_1 : B9_2 { } -public sealed partial record V9 : B9_1, IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V9(value); -} -} - -// row 10 -public abstract record B10_1 : System.IEquatable { bool System.IEquatable.Equals(B10_1? other) => ReferenceEquals(this, other); } -public sealed partial record V10 : B10_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V10(value); -} -public abstract record BC10_1 : System.IEquatable { bool System.IEquatable.Equals(BC10_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC10 : BC10_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC10(value); -} - -// row 11 -public static partial class O11 -{ -public interface IMark11 { int Mark(); } -public readonly partial record struct V11 : IValidatedValue, IMark11 -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V11(value); int IMark11.Mark() => 1; -} -public readonly partial record struct VC11 : IValidatedValue, IMark11 -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC11(value); int IMark11.Mark() => 1; -} -} - -// row 12 -public abstract record B12_2 { } -public abstract record B12_1 : B12_2 { } -public sealed partial record V12 : B12_1, IValue { } - -// row 13 -public static partial class O13 -{ -public abstract record B13_3 { } -public abstract record B13_2 : B13_3 { } -public abstract record B13_1 : B13_2 { } -public sealed partial record V13 : B13_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V13(value); -} -public abstract record BC13_3 { } -public abstract record BC13_2 : BC13_3 { } -public abstract record BC13_1 : BC13_2 { } -public sealed partial record VC13 : BC13_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC13(value); -} -} - -// row 14 -public partial struct O14 -{ -public readonly partial record struct V14 : IValidatedValue -{ - public static Result Create(global::System.DateOnly value) => new V14(value); -} -} - -// row 15 -public partial struct O15 -{ -public readonly partial record struct V15 : IValue { } -public readonly partial record struct VC15 : IValue { } -} - -// row 16 -public static partial class O16 -{ -public sealed partial class P16 -{ -public interface IMark16 { int Mark(); } -public readonly partial record struct V16 : IValue, IMark16 { int IMark16.Mark() => 1; } -public readonly partial record struct VC16 : IValue, IMark16 { int IMark16.Mark() => 1; } -} -} - -// row 17 -public readonly partial record struct V17 : IValue { } - -// row 18 -public static partial class O18 -{ -public sealed partial class P18 -{ -public abstract record B18_2 { } -public abstract record B18_1 : B18_2 { } -public sealed partial record V18 : B18_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V18(value); -} -public abstract record BC18_2 { } -public abstract record BC18_1 : BC18_2 { } -public sealed partial record VC18 : BC18_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC18(value); -} -} -} - -// row 19 -public static partial class O19 -{ -public abstract record B19_1 : System.IEquatable { bool System.IEquatable.Equals(B19_1? other) => ReferenceEquals(this, other); } -public sealed partial record V19 : B19_1, IValue { } -public abstract record BC19_1 : System.IEquatable { bool System.IEquatable.Equals(BC19_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC19 : BC19_1, IValue { } -} - -// row 20 -public partial struct O20 -{ -public interface IMark20 { int Mark(); } -public readonly partial record struct V20 : IValidatedValue, IMark20 -{ - public static Result Create(global::Probes.Build.C11ParsesByRef value) => new V20(value); int IMark20.Mark() => 1; -} -public readonly partial record struct VC20 : IValidatedValue, IMark20 -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC20(value); int IMark20.Mark() => 1; -} -} - -// row 21 -public static partial class O21 -{ -public readonly partial record struct V21 : IValidatedValue -{ - public static Result Create(global::System.DateTimeOffset value) => new V21(value); -} -} - -// row 22 -public static partial class O22 -{ -public sealed partial class P22 -{ -public interface IMark22 { int Mark(); } -public readonly partial record struct V22 : IValue, IMark22 { int IMark22.Mark() => 1; } -public readonly partial record struct VC22 : IValue, IMark22 { int IMark22.Mark() => 1; } -} -} - -// row 23 -public static partial class O23 -{ -public sealed partial class P23 -{ -public abstract record B23_3 { } -public abstract record B23_2 : B23_3 { } -public abstract record B23_1 : B23_2 { } -public sealed partial record V23 : B23_1, IValue { } -} -} - -// row 24 -public static partial class O24 -{ -public readonly partial record struct V24 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V24(value); -} -public readonly partial record struct VC24 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC24(value); -} -} - -// row 25 -public interface IMark25 { int Mark(); } -public readonly partial record struct V25 : IValidatedValue, IMark25 -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V25(value); int IMark25.Mark() => 1; -} -public readonly partial record struct VC25 : IValidatedValue, IMark25 -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC25(value); int IMark25.Mark() => 1; -} - -// row 26 -public partial struct O26 -{ -public abstract record B26_1 : System.IEquatable { bool System.IEquatable.Equals(B26_1? other) => ReferenceEquals(this, other); } -public sealed partial record V26 : B26_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesByRef value) => new V26(value); -} -public abstract record BC26_1 : System.IEquatable { bool System.IEquatable.Equals(BC26_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC26 : BC26_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC26(value); -} -} - -// row 27 -public static partial class O27 -{ -public readonly partial record struct V27 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V27(value); -} -public readonly partial record struct VC27 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC27(value); -} -} - -// row 28 -public readonly partial record struct V28 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesByRef value) => new V28(value); -} -public readonly partial record struct VC28 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC28(value); -} - -// row 29 -public partial struct O29 -{ -public interface IMark29 { int Mark(); } -public sealed partial record V29 : IValidatedValue, IMark29 -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V29(value); int IMark29.Mark() => 1; -} -public sealed partial record VC29 : IValidatedValue, IMark29 -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC29(value); int IMark29.Mark() => 1; -} -} - -// row 30 -public abstract record B30_2 { } -public abstract record B30_1 : B30_2 { } -public sealed partial record V30 : B30_1, IValue { } -public abstract record BC30_2 { } -public abstract record BC30_1 : BC30_2 { } -public sealed partial record VC30 : BC30_1, IValue { } - -// row 31 -public static partial class O31 -{ -public readonly partial record struct V31 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V31(value); -} -public readonly partial record struct VC31 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC31(value); -} -} - -// row 32 -public partial struct O32 -{ -public sealed partial record V32 : IValue { } -public sealed partial record VC32 : IValue { } -} - -// row 33 -public static partial class O33 -{ -public abstract record B33_1 { } -public sealed partial record V33 : B33_1, IValidatedValue -{ - public static Result Create(long value) => new V33(value); -} -} - -// row 34 -public abstract record B34_3 { } -public abstract record B34_2 : B34_3 { } -public abstract record B34_1 : B34_2 { } -public sealed partial record V34 : B34_1, IValue { } -public abstract record BC34_3 { } -public abstract record BC34_2 : BC34_3 { } -public abstract record BC34_1 : BC34_2 { } -public sealed partial record VC34 : BC34_1, IValue { } - -// row 35 -public abstract record B35_2 { } -public abstract record B35_1 : B35_2 { } -public sealed partial record V35 : B35_1, IValue { } - -// row 36 -public partial struct O36 -{ -public abstract record B36_2 { } -public abstract record B36_1 : B36_2 { } -public sealed partial record V36 : B36_1, IValue { } -public abstract record BC36_2 { } -public abstract record BC36_1 : BC36_2 { } -public sealed partial record VC36 : BC36_1, IValue { } -} - -// row 37 -public static partial class O37 -{ -public sealed partial class P37 -{ -public sealed partial record V37 : IValue { } -} -} - -// row 38 -public partial struct O38 -{ -public abstract record B38_2 { } -public abstract record B38_1 : B38_2 { } -public sealed partial record V38 : B38_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesByRef value) => new V38(value); -} -public abstract record BC38_2 { } -public abstract record BC38_1 : BC38_2 { } -public sealed partial record VC38 : BC38_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC38(value); -} -} - -// row 39 -public partial struct O39 -{ -public abstract record B39_3 { } -public abstract record B39_2 : B39_3 { } -public abstract record B39_1 : B39_2 { } -public sealed partial record V39 : B39_1, IValue { } -} - -// row 40 -public partial struct O40 -{ -public readonly partial record struct V40 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V40(value); -} -public readonly partial record struct VC40 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC40(value); -} -} - -// row 41 -public partial struct O41 -{ -public abstract record B41_1 : System.IEquatable { bool System.IEquatable.Equals(B41_1? other) => ReferenceEquals(this, other); } -public sealed partial record V41 : B41_1, IValue { } -} - -// row 42 -public static partial class O42 -{ -public sealed partial class P42 -{ -public abstract record B42_1 : System.IEquatable { bool System.IEquatable.Equals(B42_1? other) => ReferenceEquals(this, other); } -public sealed partial record V42 : B42_1, IValue { } -} -} - -// row 43 -public partial struct O43 -{ -public readonly partial record struct V43 : IValue { } -public readonly partial record struct VC43 : IValue { } -} - -// row 44 -public static partial class O44 -{ -public sealed partial class P44 -{ -public readonly partial record struct V44 : IValue { } -public readonly partial record struct VC44 : IValue { } -} -} - -// row 45 -public readonly partial record struct V45 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V45(value); -} -public readonly partial record struct VC45 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC45(value); -} - -// row 46 -public static partial class O46 -{ -public readonly partial record struct V46 : IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V46(value); -} -} - -// row 47 -public static partial class O47 -{ -public readonly partial record struct V47 : IValidatedValue -{ - public static Result Create(int value) => new V47(value); -} -} - -// row 48 -public static partial class O48 -{ -public readonly partial record struct V48 : IValue { } -public readonly partial record struct VC48 : IValue { } -} - -// row 49 -public static partial class O49 -{ -public abstract record B49_1 : System.IEquatable { bool System.IEquatable.Equals(B49_1? other) => ReferenceEquals(this, other); } -public sealed partial record V49 : B49_1, IValidatedValue -{ - public static Result Create(bool value) => new V49(value); -} -} - -// row 50 -public abstract record B50_1 : System.IEquatable { bool System.IEquatable.Equals(B50_1? other) => ReferenceEquals(this, other); } -public sealed partial record V50 : B50_1, IValue { } -public abstract record BC50_1 : System.IEquatable { bool System.IEquatable.Equals(BC50_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC50 : BC50_1, IValue { } - -// row 51 -public static partial class O51 -{ -public abstract record B51_3 { } -public abstract record B51_2 : B51_3 { } -public abstract record B51_1 : B51_2 { } -public sealed partial record V51 : B51_1, IValidatedValue -{ - public static Result Create(global::System.DateOnly value) => new V51(value); -} -} - -// row 52 -public partial struct O52 -{ -public sealed partial record V52 : IValue { } -} - -// row 53 -public static partial class O53 -{ -public sealed partial class P53 -{ -public abstract record B53_3 { } -public abstract record B53_2 : B53_3 { } -public abstract record B53_1 : B53_2 { } -public sealed partial record V53 : B53_1, IValidatedValue -{ - public static Result Create(string value) => new V53(value); -} -} -} - -// row 54 -public static partial class O54 -{ -public sealed partial class P54 -{ -public abstract record B54_3 { } -public abstract record B54_2 : B54_3 { } -public abstract record B54_1 : B54_2 { } -public sealed partial record V54 : B54_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V54(value); -} -public abstract record BC54_3 { } -public abstract record BC54_2 : BC54_3 { } -public abstract record BC54_1 : BC54_2 { } -public sealed partial record VC54 : BC54_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC54(value); -} -} -} - -// row 55 -public static partial class O55 -{ -public sealed partial class P55 -{ -public abstract record B55_1 { } -public sealed partial record V55 : B55_1, IValue { } -} -} - -// row 56 -public static partial class O56 -{ -public sealed partial class P56 -{ -public abstract record B56_1 { } -public sealed partial record V56 : B56_1, IValidatedValue -{ - public static Result Create(decimal value) => new V56(value); -} -} -} - -// row 57 -public abstract record B57_1 { } -public sealed partial record V57 : B57_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V57(value); -} - -// row 58 -public readonly partial record struct V58 : IValue { } - -// row 59 -public static partial class O59 -{ -public sealed partial class P59 -{ -public abstract record B59_3 { } -public abstract record B59_2 : B59_3 { } -public abstract record B59_1 : B59_2 { } -public sealed partial record V59 : B59_1, IValidatedValue -{ - public static Result Create(double value) => new V59(value); -} -} -} - -// row 60 -public static partial class O60 -{ -public interface IMark60 { int Mark(); } -public sealed partial record V60 : IValue, IMark60 { int IMark60.Mark() => 1; } -} - -// row 61 -public partial struct O61 -{ -public abstract record B61_1 { } -public sealed partial record V61 : B61_1, IValue { } -public abstract record BC61_1 { } -public sealed partial record VC61 : BC61_1, IValue { } -} - -// row 62 -public static partial class O62 -{ -public sealed partial class P62 -{ -public readonly partial record struct V62 : IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V62(value); -} -} -} - -// row 63 -public interface IMark63 { int Mark(); } -public readonly partial record struct V63 : IValue, IMark63 { int IMark63.Mark() => 1; } - -// row 64 -public static partial class O64 -{ -public readonly partial record struct V64 : IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V64(value); -} -} - -// row 65 -public abstract record B65_2 { } -public abstract record B65_1 : B65_2 { } -public sealed partial record V65 : B65_1, IValidatedValue -{ - public static Result Create(global::System.Guid value) => new V65(value); -} - -// row 66 -public abstract record B66_1 : System.IEquatable { bool System.IEquatable.Equals(B66_1? other) => ReferenceEquals(this, other); } -public sealed partial record V66 : B66_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PRec value) => new V66(value); -} - -// row 67 -public static partial class O67 -{ -public sealed partial class P67 -{ -public readonly partial record struct V67 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V67(value); -} -public readonly partial record struct VC67 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC67(value); -} -} -} - -// row 68 -public static partial class O68 -{ -public sealed partial class P68 -{ -public readonly partial record struct V68 : IValue { } -} -} - -// row 69 -public partial struct O69 -{ -public interface IMark69 { int Mark(); } -public readonly partial record struct V69 : IValidatedValue, IMark69 -{ - public static Result Create(long value) => new V69(value); int IMark69.Mark() => 1; -} -} - -// row 70 -public static partial class O70 -{ -public sealed partial class P70 -{ -public interface IMark70 { int Mark(); } -public readonly partial record struct V70 : IValue, IMark70 { int IMark70.Mark() => 1; } -} -} - -// row 71 -public static partial class O71 -{ -public sealed partial class P71 -{ -public readonly partial record struct V71 : IValue { } -} -} - -// row 72 -public partial struct O72 -{ -public readonly partial record struct V72 : IValue { } -} - -// row 73 -public static partial class O73 -{ -public interface IMark73 { int Mark(); } -public readonly partial record struct V73 : IValidatedValue, IMark73 -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V73(value); int IMark73.Mark() => 1; -} -public readonly partial record struct VC73 : IValidatedValue, IMark73 -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC73(value); int IMark73.Mark() => 1; -} -} - -// row 74 -public static partial class O74 -{ -public readonly partial record struct V74 : IValue { } -} - -// row 75 -public partial struct O75 -{ -public abstract record B75_1 { } -public sealed partial record V75 : B75_1, IValidatedValue -{ - public static Result Create(int value) => new V75(value); -} -} - -// row 76 -public static partial class O76 -{ -public interface IMark76 { int Mark(); } -public sealed partial record V76 : IValue, IMark76 { int IMark76.Mark() => 1; } -} - -// row 77 -public readonly partial record struct V77 : IValue { } -public readonly partial record struct VC77 : IValue { } - -// row 78 -public static partial class O78 -{ -public sealed partial class P78 -{ -public readonly partial record struct V78 : IValue { } -public readonly partial record struct VC78 : IValue { } -} -} - -// row 79 -public abstract record B79_1 : System.IEquatable { bool System.IEquatable.Equals(B79_1? other) => ReferenceEquals(this, other); } -public sealed partial record V79 : B79_1, IValue { } -public abstract record BC79_1 : System.IEquatable { bool System.IEquatable.Equals(BC79_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC79 : BC79_1, IValue { } - -// row 80 -public static partial class O80 -{ -public readonly partial record struct V80 : IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V80(value); -} -} - -// row 81 -public static partial class O81 -{ -public abstract record B81_1 : System.IEquatable { bool System.IEquatable.Equals(B81_1? other) => ReferenceEquals(this, other); } -public sealed partial record V81 : B81_1, IValue { } -public abstract record BC81_1 : System.IEquatable { bool System.IEquatable.Equals(BC81_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC81 : BC81_1, IValue { } -} - -// row 82 -public static partial class O82 -{ -public sealed partial class P82 -{ -public interface IMark82 { int Mark(); } -public readonly partial record struct V82 : IValue, IMark82 { int IMark82.Mark() => 1; } -} -} - -// row 83 -public abstract record B83_2 { } -public abstract record B83_1 : B83_2 { } -public sealed partial record V83 : B83_1, IValidatedValue -{ - public static Result Create(string value) => new V83(value); -} - -// row 84 -public static partial class O84 -{ -public abstract record B84_2 { } -public abstract record B84_1 : B84_2 { } -public sealed partial record V84 : B84_1, IValidatedValue -{ - public static Result Create(long value) => new V84(value); -} -} - -// row 85 -public partial struct O85 -{ -public abstract record B85_1 : System.IEquatable { bool System.IEquatable.Equals(B85_1? other) => ReferenceEquals(this, other); } -public sealed partial record V85 : B85_1, IValue { } -} - -// row 86 -public static partial class O86 -{ -public sealed partial class P86 -{ -public abstract record B86_2 { } -public abstract record B86_1 : B86_2 { } -public sealed partial record V86 : B86_1, IValue { } -public abstract record BC86_2 { } -public abstract record BC86_1 : BC86_2 { } -public sealed partial record VC86 : BC86_1, IValue { } -} -} - -// row 87 -public static partial class O87 -{ -public sealed partial class P87 -{ -public sealed partial record V87 : IValue { } -} -} - -// row 88 -public sealed partial record V88 : IValue { } -public sealed partial record VC88 : IValue { } - -// row 89 -public abstract record B89_2 { } -public abstract record B89_1 : B89_2 { } -public sealed partial record V89 : B89_1, IValidatedValue -{ - public static Result Create(ulong value) => new V89(value); -} - -// row 90 -public readonly partial record struct V90 : IValue { } - -// row 91 -public static partial class O91 -{ -public sealed partial class P91 -{ -public abstract record B91_1 { } -public sealed partial record V91 : B91_1, IValue { } -public abstract record BC91_1 { } -public sealed partial record VC91 : BC91_1, IValue { } -} -} - -// row 92 -public static partial class O92 -{ -public abstract record B92_2 { } -public abstract record B92_1 : B92_2 { } -public sealed partial record V92 : B92_1, IValidatedValue -{ - public static Result Create(global::System.TimeSpan value) => new V92(value); -} -} - -// row 93 -public abstract record B93_3 { } -public abstract record B93_2 : B93_3 { } -public abstract record B93_1 : B93_2 { } -public sealed partial record V93 : B93_1, IValue { } - -// row 94 -public partial struct O94 -{ -public abstract record B94_2 { } -public abstract record B94_1 : B94_2 { } -public sealed partial record V94 : B94_1, IValue { } -} - -// row 95 -public abstract record B95_3 { } -public abstract record B95_2 : B95_3 { } -public abstract record B95_1 : B95_2 { } -public sealed partial record V95 : B95_1, IValidatedValue -{ - public static Result Create(char value) => new V95(value); -} - -// row 96 -public partial struct O96 -{ -public abstract record B96_3 { } -public abstract record B96_2 : B96_3 { } -public abstract record B96_1 : B96_2 { } -public sealed partial record V96 : B96_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PRec value) => new V96(value); -} -} - -// row 97 -public abstract record B97_1 { } -public sealed partial record V97 : B97_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V97(value); -} - -// row 98 -public abstract record B98_2 { } -public abstract record B98_1 : B98_2 { } -public sealed partial record V98 : B98_1, IValue { } - -// row 99 -public interface IMark99 { int Mark(); } -public readonly partial record struct V99 : IValidatedValue, IMark99 -{ - public static Result Create(string value) => new V99(value); int IMark99.Mark() => 1; -} - -// row 100 -public abstract record B100_1 { } -public sealed partial record V100 : B100_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V100(value); -} -public abstract record BC100_1 { } -public sealed partial record VC100 : BC100_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC100(value); -} - -// row 101 -public static partial class O101 -{ -public interface IMark101 { int Mark(); } -public readonly partial record struct V101 : IValidatedValue, IMark101 -{ - public static Result Create(global::System.DateOnly value) => new V101(value); int IMark101.Mark() => 1; -} -} - -// row 102 -public static partial class O102 -{ -public sealed partial class P102 -{ -public interface IMark102 { int Mark(); } -public sealed partial record V102 : IValue, IMark102 { int IMark102.Mark() => 1; } -} -} - -// row 103 -public readonly partial record struct V103 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V103(value); -} -public readonly partial record struct VC103 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC103(value); -} - -// row 104 -public static partial class O104 -{ -public sealed partial class P104 -{ -public readonly partial record struct V104 : IValue { } -} -} - -// row 105 -public interface IMark105 { int Mark(); } -public readonly partial record struct V105 : IValue, IMark105 { int IMark105.Mark() => 1; } - -// row 106 -public static partial class O106 -{ -public sealed partial class P106 -{ -public abstract record B106_1 : System.IEquatable { bool System.IEquatable.Equals(B106_1? other) => ReferenceEquals(this, other); } -public sealed partial record V106 : B106_1, IValue { } -public abstract record BC106_1 : System.IEquatable { bool System.IEquatable.Equals(BC106_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC106 : BC106_1, IValue { } -} -} - -// row 107 -public static partial class O107 -{ -public sealed partial class P107 -{ -public readonly partial record struct V107 : IValue { } -public readonly partial record struct VC107 : IValue { } -} -} - -// row 108 -public static partial class O108 -{ -public sealed partial class P108 -{ -public readonly partial record struct V108 : IValidatedValue -{ - public static Result Create(bool value) => new V108(value); -} -} -} - -// row 109 -public static partial class O109 -{ -public abstract record B109_2 { } -public abstract record B109_1 : B109_2 { } -public sealed partial record V109 : B109_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V109(value); -} -public abstract record BC109_2 { } -public abstract record BC109_1 : BC109_2 { } -public sealed partial record VC109 : BC109_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC109(value); -} -} - -// row 110 -public static partial class O110 -{ -public sealed partial class P110 -{ -public abstract record B110_1 : System.IEquatable { bool System.IEquatable.Equals(B110_1? other) => ReferenceEquals(this, other); } -public sealed partial record V110 : B110_1, IValue { } -} -} - -// row 111 -public static partial class O111 -{ -public readonly partial record struct V111 : IValue { } -public readonly partial record struct VC111 : IValue { } -} - -// row 112 -public partial struct O112 -{ -public interface IMark112 { int Mark(); } -public readonly partial record struct V112 : IValidatedValue, IMark112 -{ - public static Result Create(int value) => new V112(value); int IMark112.Mark() => 1; -} -} - -// row 113 -public partial struct O113 -{ -public abstract record B113_3 { } -public abstract record B113_2 : B113_3 { } -public abstract record B113_1 : B113_2 { } -public sealed partial record V113 : B113_1, IValue { } -} - -// row 114 -public partial struct O114 -{ -public abstract record B114_2 { } -public abstract record B114_1 : B114_2 { } -public sealed partial record V114 : B114_1, IValidatedValue -{ - public static Result Create(double value) => new V114(value); -} -} - -// row 115 -public static partial class O115 -{ -public readonly partial record struct V115 : IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V115(value); -} -} - -// row 116 -public static partial class O116 -{ -public abstract record B116_2 { } -public abstract record B116_1 : B116_2 { } -public sealed partial record V116 : B116_1, IValue { } -} - -// row 117 -public static partial class O117 -{ -public abstract record B117_1 { } -public sealed partial record V117 : B117_1, IValue { } -public abstract record BC117_1 { } -public sealed partial record VC117 : BC117_1, IValue { } -} - -// row 118 -public partial struct O118 -{ -public abstract record B118_1 : System.IEquatable { bool System.IEquatable.Equals(B118_1? other) => ReferenceEquals(this, other); } -public sealed partial record V118 : B118_1, IValue { } -} - -// row 119 -public static partial class O119 -{ -public sealed partial class P119 -{ -public abstract record B119_1 { } -public sealed partial record V119 : B119_1, IValue { } -} -} - -// row 120 -public partial struct O120 -{ -public abstract record B120_2 { } -public abstract record B120_1 : B120_2 { } -public sealed partial record V120 : B120_1, IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V120(value); -} -} - -// row 121 -public abstract record B121_3 { } -public abstract record B121_2 : B121_3 { } -public abstract record B121_1 : B121_2 { } -public sealed partial record V121 : B121_1, IValue { } -public abstract record BC121_3 { } -public abstract record BC121_2 : BC121_3 { } -public abstract record BC121_1 : BC121_2 { } -public sealed partial record VC121 : BC121_1, IValue { } - -// row 122 -public static partial class O122 -{ -public readonly partial record struct V122 : IValue { } -} - -// row 123 -public partial struct O123 -{ -public interface IMark123 { int Mark(); } -public sealed partial record V123 : IValue, IMark123 { int IMark123.Mark() => 1; } -public sealed partial record VC123 : IValue, IMark123 { int IMark123.Mark() => 1; } -} - -// row 124 -public partial struct O124 -{ -public readonly partial record struct V124 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesByRef value) => new V124(value); -} -public readonly partial record struct VC124 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC124(value); -} -} - -// row 125 -public static partial class O125 -{ -public interface IMark125 { int Mark(); } -public readonly partial record struct V125 : IValidatedValue, IMark125 -{ - public static Result Create(global::System.Uri value) => new V125(value); int IMark125.Mark() => 1; -} -} - -// row 126 -public static partial class O126 -{ -public sealed partial class P126 -{ -public abstract record B126_1 : System.IEquatable { bool System.IEquatable.Equals(B126_1? other) => ReferenceEquals(this, other); } -public sealed partial record V126 : B126_1, IValidatedValue -{ - public static Result Create(decimal value) => new V126(value); -} -} -} - -// row 127 -public static partial class O127 -{ -public abstract record B127_1 : System.IEquatable { bool System.IEquatable.Equals(B127_1? other) => ReferenceEquals(this, other); } -public sealed partial record V127 : B127_1, IValue { } -} - -// row 128 -public static partial class O128 -{ -public abstract record B128_1 : System.IEquatable { bool System.IEquatable.Equals(B128_1? other) => ReferenceEquals(this, other); } -public sealed partial record V128 : B128_1, IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V128(value); -} -} - -// row 129 -public readonly partial record struct V129 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V129(value); -} -public readonly partial record struct VC129 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC129(value); -} - -// row 130 -public static partial class O130 -{ -public interface IMark130 { int Mark(); } -public readonly partial record struct V130 : IValue, IMark130 { int IMark130.Mark() => 1; } -} - -// row 131 -public partial struct O131 -{ -public interface IMark131 { int Mark(); } -public readonly partial record struct V131 : IValue, IMark131 { int IMark131.Mark() => 1; } -} - -// row 132 -public interface IMark132 { int Mark(); } -public readonly partial record struct V132 : IValidatedValue, IMark132 -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V132(value); int IMark132.Mark() => 1; -} -public readonly partial record struct VC132 : IValidatedValue, IMark132 -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC132(value); int IMark132.Mark() => 1; -} - -// row 133 -public static partial class O133 -{ -public abstract record B133_2 { } -public abstract record B133_1 : B133_2 { } -public sealed partial record V133 : B133_1, IValue { } -} - -// row 134 -public abstract record B134_2 { } -public abstract record B134_1 : B134_2 { } -public sealed partial record V134 : B134_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesByRef value) => new V134(value); -} -public abstract record BC134_2 { } -public abstract record BC134_1 : BC134_2 { } -public sealed partial record VC134 : BC134_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC134(value); -} - -// row 135 -public partial struct O135 -{ -public abstract record B135_3 { } -public abstract record B135_2 : B135_3 { } -public abstract record B135_1 : B135_2 { } -public sealed partial record V135 : B135_1, IValue { } -} - -// row 136 -public partial struct O136 -{ -public interface IMark136 { int Mark(); } -public readonly partial record struct V136 : IValue, IMark136 { int IMark136.Mark() => 1; } -} - -// row 137 -public static partial class O137 -{ -public abstract record B137_1 { } -public sealed partial record V137 : B137_1, IValue { } -public abstract record BC137_1 { } -public sealed partial record VC137 : BC137_1, IValue { } -} - -// row 138 -public static partial class O138 -{ -public readonly partial record struct V138 : IValue { } -public readonly partial record struct VC138 : IValue { } -} - -// row 139 -public static partial class O139 -{ -public sealed partial class P139 -{ -public abstract record B139_1 : System.IEquatable { bool System.IEquatable.Equals(B139_1? other) => ReferenceEquals(this, other); } -public sealed partial record V139 : B139_1, IValue { } -} -} - -// row 140 -public static partial class O140 -{ -public abstract record B140_2 { } -public abstract record B140_1 : B140_2 { } -public sealed partial record V140 : B140_1, IValue { } -} - -// row 141 -public static partial class O141 -{ -public interface IMark141 { int Mark(); } -public readonly partial record struct V141 : IValue, IMark141 { int IMark141.Mark() => 1; } -public readonly partial record struct VC141 : IValue, IMark141 { int IMark141.Mark() => 1; } -} - -// row 142 -public static partial class O142 -{ -public readonly partial record struct V142 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V142(value); -} -public readonly partial record struct VC142 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC142(value); -} -} - -// row 143 -public sealed partial record V143 : IValue { } -public sealed partial record VC143 : IValue { } - -// row 144 -public static partial class O144 -{ -public sealed partial class P144 -{ -public interface IMark144 { int Mark(); } -public readonly partial record struct V144 : IValue, IMark144 { int IMark144.Mark() => 1; } -public readonly partial record struct VC144 : IValue, IMark144 { int IMark144.Mark() => 1; } -} -} - -// row 145 -public static partial class O145 -{ -public sealed partial class P145 -{ -public readonly partial record struct V145 : IValidatedValue -{ - public static Result Create(ulong value) => new V145(value); -} -} -} - -// row 146 -public static partial class O146 -{ -public readonly partial record struct V146 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V146(value); -} -public readonly partial record struct VC146 : IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC146(value); -} -} - -// row 147 -public static partial class O147 -{ -public sealed partial class P147 -{ -public interface IMark147 { int Mark(); } -public readonly partial record struct V147 : IValidatedValue, IMark147 -{ - public static Result Create(global::Probes.Build.C11AbstractText value) => new V147(value); int IMark147.Mark() => 1; -} -public readonly partial record struct VC147 : IValidatedValue, IMark147 -{ - public static Result Create(global::Probes.Build.C11ConstructedConcrete value) => new VC147(value); int IMark147.Mark() => 1; -} -} -} - -// row 148 -public static partial class O148 -{ -public sealed partial record V148 : IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V148(value); -} -} - -// row 149 -public partial struct O149 -{ -public interface IMark149 { int Mark(); } -public sealed partial record V149 : IValue, IMark149 { int IMark149.Mark() => 1; } -public sealed partial record VC149 : IValue, IMark149 { int IMark149.Mark() => 1; } -} - -// row 150 -public static partial class O150 -{ -public sealed partial class P150 -{ -public abstract record B150_3 { } -public abstract record B150_2 : B150_3 { } -public abstract record B150_1 : B150_2 { } -public sealed partial record V150 : B150_1, IValidatedValue -{ - public static Result Create(decimal value) => new V150(value); -} -} -} - -// row 151 -public static partial class O151 -{ -public sealed partial record V151 : IValidatedValue -{ - public static Result Create(ulong value) => new V151(value); -} -} - -// row 152 -public static partial class O152 -{ -public interface IMark152 { int Mark(); } -public sealed partial record V152 : IValue, IMark152 { int IMark152.Mark() => 1; } -public sealed partial record VC152 : IValue, IMark152 { int IMark152.Mark() => 1; } -} - -// row 153 -public static partial class O153 -{ -public sealed partial record V153 : IValue { } -public sealed partial record VC153 : IValue { } -} - -// row 154 -public static partial class O154 -{ -public sealed partial class P154 -{ -public abstract record B154_1 : System.IEquatable { bool System.IEquatable.Equals(B154_1? other) => ReferenceEquals(this, other); } -public sealed partial record V154 : B154_1, IValue { } -public abstract record BC154_1 : System.IEquatable { bool System.IEquatable.Equals(BC154_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC154 : BC154_1, IValue { } -} -} - -// row 155 -public sealed partial record V155 : IValue { } -public sealed partial record VC155 : IValue { } - -// row 156 -public interface IMark156 { int Mark(); } -public readonly partial record struct V156 : IValidatedValue, IMark156 -{ - public static Result Create(global::System.DateTimeOffset value) => new V156(value); int IMark156.Mark() => 1; -} - -// row 157 -public static partial class O157 -{ -public sealed partial class P157 -{ -public abstract record B157_1 : System.IEquatable { bool System.IEquatable.Equals(B157_1? other) => ReferenceEquals(this, other); } -public sealed partial record V157 : B157_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesToInt value) => new V157(value); -} -public abstract record BC157_1 : System.IEquatable { bool System.IEquatable.Equals(BC157_1? other) => ReferenceEquals(this, other); } -public sealed partial record VC157 : BC157_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsedShape value) => new VC157(value); -} -} -} - -// row 158 -public static partial class O158 -{ -public sealed partial class P158 -{ -public abstract record B158_3 { } -public abstract record B158_2 : B158_3 { } -public abstract record B158_1 : B158_2 { } -public sealed partial record V158 : B158_1, IValidatedValue -{ - public static Result Create(string value) => new V158(value); -} -} -} - -// row 159 -public static partial class O159 -{ -public sealed partial class P159 -{ -public abstract record B159_2 { } -public abstract record B159_1 : B159_2 { } -public sealed partial record V159 : B159_1, IValue { } -} -} - -// row 160 -public partial struct O160 -{ -public interface IMark160 { int Mark(); } -public sealed partial record V160 : IValue, IMark160 { int IMark160.Mark() => 1; } -} - -// row 161 -public static partial class O161 -{ -public readonly partial record struct V161 : IValue { } -} - -// row 162 -public partial struct O162 -{ -public abstract record B162_3 { } -public abstract record B162_2 : B162_3 { } -public abstract record B162_1 : B162_2 { } -public sealed partial record V162 : B162_1, IValue { } -} - -// row 163 -public partial struct O163 -{ -public abstract record B163_1 : System.IEquatable { bool System.IEquatable.Equals(B163_1? other) => ReferenceEquals(this, other); } -public sealed partial record V163 : B163_1, IValue { } -} - -// row 164 -public partial struct O164 -{ -public interface IMark164 { int Mark(); } -public readonly partial record struct V164 : IValidatedValue, IMark164 -{ - public static Result Create(byte value) => new V164(value); int IMark164.Mark() => 1; -} -} - -// row 165 -public abstract record B165_1 : System.IEquatable { bool System.IEquatable.Equals(B165_1? other) => ReferenceEquals(this, other); } -public sealed partial record V165 : B165_1, IValue { } - -// row 166 -public static partial class O166 -{ -public readonly partial record struct V166 : IValue { } -} - -// row 167 -public static partial class O167 -{ -public readonly partial record struct V167 : IValue { } -} - -// row 168 -public static partial class O168 -{ -public readonly partial record struct V168 : IValue { } -} - -// row 169 -public partial struct O169 -{ -public interface IMark169 { int Mark(); } -public readonly partial record struct V169 : IValue, IMark169 { int IMark169.Mark() => 1; } -} - -// row 170 -public static partial class O170 -{ -public sealed partial class P170 -{ -public readonly partial record struct V170 : IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PRec value) => new V170(value); -} -} -} - -// row 171 -public static partial class O171 -{ -public sealed partial record V171 : IValidatedValue -{ - public static Result Create(byte value) => new V171(value); -} -} - -// row 172 -public static partial class O172 -{ -public sealed partial class P172 -{ -public abstract record B172_2 { } -public abstract record B172_1 : B172_2 { } -public sealed partial record V172 : B172_1, IValue { } -} -} - -// row 173 -public abstract record B173_3 { } -public abstract record B173_2 : B173_3 { } -public abstract record B173_1 : B173_2 { } -public sealed partial record V173 : B173_1, IValidatedValue -{ - public static Result Create(global::System.TimeOnly value) => new V173(value); -} - -// row 174 -public static partial class O174 -{ -public abstract record B174_3 { } -public abstract record B174_2 : B174_3 { } -public abstract record B174_1 : B174_2 { } -public sealed partial record V174 : B174_1, IValidatedValue -{ - public static Result Create(global::System.Uri value) => new V174(value); -} -} - -// row 175 -public partial struct O175 -{ -public readonly partial record struct V175 : IValidatedValue -{ - public static Result Create(double value) => new V175(value); -} -} - -// row 176 -public partial struct O176 -{ -public abstract record B176_1 : System.IEquatable { bool System.IEquatable.Equals(B176_1? other) => ReferenceEquals(this, other); } -public sealed partial record V176 : B176_1, IValue { } -} - -// row 177 -public static partial class O177 -{ -public abstract record B177_3 { } -public abstract record B177_2 : B177_3 { } -public abstract record B177_1 : B177_2 { } -public sealed partial record V177 : B177_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ConstructedByRef value) => new V177(value); -} -public abstract record BC177_3 { } -public abstract record BC177_2 : BC177_3 { } -public abstract record BC177_1 : BC177_2 { } -public sealed partial record VC177 : BC177_1, IValidatedValue -{ - public static Result Create(global::Probes.Build.C11ParsesFromIn value) => new VC177(value); -} -} - -// row 178 -public partial struct O178 -{ -public interface IMark178 { int Mark(); } -public readonly partial record struct V178 : IValidatedValue, IMark178 -{ - public static Result Create(global::System.Guid value) => new V178(value); int IMark178.Mark() => 1; -} -} - -// row 179 -public static partial class O179 -{ -public readonly partial record struct V179 : IValidatedValue -{ - public static Result Create(global::System.TimeOnly value) => new V179(value); -} -} - -// row 180 -public static partial class O180 -{ -public sealed partial class P180 -{ -public interface IMark180 { int Mark(); } -public readonly partial record struct V180 : IValue, IMark180 { int IMark180.Mark() => 1; } -} -} - -// row 181 -public interface IMark181 { int Mark(); } -public readonly partial record struct V181 : IValidatedValue, IMark181 -{ - public static Result Create(global::System.TimeSpan value) => new V181(value); int IMark181.Mark() => 1; -} - -// row 182 -public static partial class O182 -{ -public readonly partial record struct V182 : IValidatedValue -{ - public static Result Create(decimal value) => new V182(value); -} -} - -// row 183 -public partial struct O183 -{ -public abstract record B183_3 { } -public abstract record B183_2 : B183_3 { } -public abstract record B183_1 : B183_2 { } -public sealed partial record V183 : B183_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PFlags value) => new V183(value); -} -} - -// row 184 -public abstract record B184_1 { } -public sealed partial record V184 : B184_1, IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V184(value); -} - -// row 185 -public static partial class O185 -{ -public sealed partial class P185 -{ -public readonly partial record struct V185 : IValue { } -} -} - -// row 186 -public abstract record B186_3 { } -public abstract record B186_2 : B186_3 { } -public abstract record B186_1 : B186_2 { } -public sealed partial record V186 : B186_1, IValue { } - -// row 187 -public static partial class O187 -{ -public abstract record B187_1 { } -public sealed partial record V187 : B187_1, IValidatedValue -{ - public static Result Create(global::System.DateOnly value) => new V187(value); -} -} - -// row 188 -public static partial class O188 -{ -public sealed partial class P188 -{ -public interface IMark188 { int Mark(); } -public readonly partial record struct V188 : IValue, IMark188 { int IMark188.Mark() => 1; } -} -} - -// row 189 -public static partial class O189 -{ -public sealed partial class P189 -{ -public interface IMark189 { int Mark(); } -public sealed partial record V189 : IValidatedValue, IMark189 -{ - public static Result Create(global::NodaTime.Instant value) => new V189(value); int IMark189.Mark() => 1; -} -} -} - -// row 190 -public partial struct O190 -{ -public abstract record B190_3 { } -public abstract record B190_2 : B190_3 { } -public abstract record B190_1 : B190_2 { } -public sealed partial record V190 : B190_1, IValue { } -} - -// row 191 -public static partial class O191 -{ -public sealed partial class P191 -{ -public interface IMark191 { int Mark(); } -public sealed partial record V191 : IValue, IMark191 { int IMark191.Mark() => 1; } -} -} - -// row 192 -public abstract record B192_1 : System.IEquatable { bool System.IEquatable.Equals(B192_1? other) => ReferenceEquals(this, other); } -public sealed partial record V192 : B192_1, IValidatedValue -{ - public static Result Create(ulong value) => new V192(value); -} - -// row 193 -public abstract record B193_2 { } -public abstract record B193_1 : B193_2 { } -public sealed partial record V193 : B193_1, IValue { } - -// row 194 -public static partial class O194 -{ -public abstract record B194_2 { } -public abstract record B194_1 : B194_2 { } -public sealed partial record V194 : B194_1, IValidatedValue -{ - public static Result Create(byte value) => new V194(value); -} -} - -// row 195 -public interface IMark195 { int Mark(); } -public sealed partial record V195 : IValue, IMark195 { int IMark195.Mark() => 1; } - -// row 196 -public abstract record B196_1 : System.IEquatable { bool System.IEquatable.Equals(B196_1? other) => ReferenceEquals(this, other); } -public sealed partial record V196 : B196_1, IValidatedValue -{ - public static Result Create(double value) => new V196(value); -} - -// row 197 -public static partial class O197 -{ -public abstract record B197_2 { } -public abstract record B197_1 : B197_2 { } -public sealed partial record V197 : B197_1, IValue { } -} - -// row 198 -public partial struct O198 -{ -public readonly partial record struct V198 : IValidatedValue -{ - public static Result Create(byte value) => new V198(value); -} -} - -// row 199 -public static partial class O199 -{ -public sealed partial class P199 -{ -public interface IMark199 { int Mark(); } -public readonly partial record struct V199 : IValidatedValue, IMark199 -{ - public static Result Create(char value) => new V199(value); int IMark199.Mark() => 1; -} -} -} - -// row 200 -public partial struct O200 -{ -public abstract record B200_1 : System.IEquatable { bool System.IEquatable.Equals(B200_1? other) => ReferenceEquals(this, other); } -public sealed partial record V200 : B200_1, IValue { } -} - -// row 201 -public partial struct O201 -{ -public abstract record B201_3 { } -public abstract record B201_2 : B201_3 { } -public abstract record B201_1 : B201_2 { } -public sealed partial record V201 : B201_1, IValue { } -} - -// row 202 -public partial struct O202 -{ -public abstract record B202_2 { } -public abstract record B202_1 : B202_2 { } -public sealed partial record V202 : B202_1, IValue { } -} - -// row 203 -public static partial class O203 -{ -public sealed partial class P203 -{ -public abstract record B203_1 { } -public sealed partial record V203 : B203_1, IValue { } -} -} - -// row 204 -public partial struct O204 -{ -public abstract record B204_1 { } -public sealed partial record V204 : B204_1, IValidatedValue -{ - public static Result Create(global::System.TimeOnly value) => new V204(value); -} -} - -// row 205 -public partial struct O205 -{ -public abstract record B205_1 { } -public sealed partial record V205 : B205_1, IValue { } -} - -// row 206 -public static partial class O206 -{ -public sealed partial class P206 -{ -public abstract record B206_1 { } -public sealed partial record V206 : B206_1, IValidatedValue -{ - public static Result Create(global::System.Uri value) => new V206(value); -} -} -} - -// row 207 -public abstract record B207_1 { } -public sealed partial record V207 : B207_1, IValue { } - -// row 208 -public abstract record B208_2 { } -public abstract record B208_1 : B208_2 { } -public sealed partial record V208 : B208_1, IValidatedValue -{ - public static Result Create(long value) => new V208(value); -} - -// row 209 -public static partial class O209 -{ -public sealed partial class P209 -{ -public interface IMark209 { int Mark(); } -public sealed partial record V209 : IValidatedValue, IMark209 -{ - public static Result Create(ulong value) => new V209(value); int IMark209.Mark() => 1; -} -} -} - -// row 210 -public static partial class O210 -{ -public abstract record B210_1 { } -public sealed partial record V210 : B210_1, IValidatedValue -{ - public static Result Create(bool value) => new V210(value); -} -} - -// row 211 -public abstract record B211_1 : System.IEquatable { bool System.IEquatable.Equals(B211_1? other) => ReferenceEquals(this, other); } -public sealed partial record V211 : B211_1, IValidatedValue -{ - public static Result Create(global::System.TimeSpan value) => new V211(value); -} - -// row 212 -public static partial class O212 -{ -public abstract record B212_3 { } -public abstract record B212_2 : B212_3 { } -public abstract record B212_1 : B212_2 { } -public sealed partial record V212 : B212_1, IValidatedValue -{ - public static Result Create(int value) => new V212(value); -} -} - -// row 213 -public static partial class O213 -{ -public abstract record B213_1 : System.IEquatable { bool System.IEquatable.Equals(B213_1? other) => ReferenceEquals(this, other); } -public sealed partial record V213 : B213_1, IValue { } -} - -// row 214 -public abstract record B214_1 { } -public sealed partial record V214 : B214_1, IValidatedValue -{ - public static Result Create(decimal value) => new V214(value); -} - -// row 215 -public static partial class O215 -{ -public sealed partial class P215 -{ -public abstract record B215_1 : System.IEquatable { bool System.IEquatable.Equals(B215_1? other) => ReferenceEquals(this, other); } -public sealed partial record V215 : B215_1, IValidatedValue -{ - public static Result Create(byte value) => new V215(value); -} -} -} - -// row 216 -public static partial class O216 -{ -public sealed partial class P216 -{ -public abstract record B216_1 { } -public sealed partial record V216 : B216_1, IValidatedValue -{ - public static Result Create(global::Probes.Shapes.PRec value) => new V216(value); -} -} -} - -// row 217 -public partial struct O217 -{ -public readonly partial record struct V217 : IValidatedValue -{ - public static Result Create(int value) => new V217(value); -} -} - -// row 218 -public static partial class O218 -{ -public abstract record B218_1 : System.IEquatable { bool System.IEquatable.Equals(B218_1? other) => ReferenceEquals(this, other); } -public sealed partial record V218 : B218_1, IValue { } -} - -// row 219 -public static partial class O219 -{ -public sealed partial class P219 -{ -public abstract record B219_2 { } -public abstract record B219_1 : B219_2 { } -public sealed partial record V219 : B219_1, IValidatedValue -{ - public static Result Create(global::System.Guid value) => new V219(value); -} -} -} - -// row 220 -public static partial class O220 -{ -public sealed partial class P220 -{ -public abstract record B220_1 { } -public sealed partial record V220 : B220_1, IValue { } -} -} - -// row 221 -public partial struct O221 -{ -public sealed partial record V221 : IValue { } -} - -// row 222 -public partial struct O222 -{ -public abstract record B222_1 { } -public sealed partial record V222 : B222_1, IValue { } -} - -// row 223 -public sealed partial record V223 : IValue { } - -// row 224 -public partial struct O224 -{ -public abstract record B224_1 { } -public sealed partial record V224 : B224_1, IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V224(value); -} -} - -// row 225 -public static partial class O225 -{ -public sealed partial class P225 -{ -public readonly partial record struct V225 : IValue { } -} -} - -// row 226 -public static partial class O226 -{ -public sealed partial class P226 -{ -public readonly partial record struct V226 : IValidatedValue -{ - public static Result Create(global::System.DateTimeOffset value) => new V226(value); -} -} -} - -// row 227 -public static partial class O227 -{ -public abstract record B227_3 { } -public abstract record B227_2 : B227_3 { } -public abstract record B227_1 : B227_2 { } -public sealed partial record V227 : B227_1, IValue { } -} - -// row 228 -public static partial class O228 -{ -public readonly partial record struct V228 : IValidatedValue -{ - public static Result Create(global::System.TimeSpan value) => new V228(value); -} -} - -// row 229 -public static partial class O229 -{ -public sealed partial class P229 -{ -public abstract record B229_1 : System.IEquatable { bool System.IEquatable.Equals(B229_1? other) => ReferenceEquals(this, other); } -public sealed partial record V229 : B229_1, IValidatedValue -{ - public static Result Create(global::System.DateTime value) => new V229(value); -} -} -} - -// row 230 -public partial struct O230 -{ -public abstract record B230_1 : System.IEquatable { bool System.IEquatable.Equals(B230_1? other) => ReferenceEquals(this, other); } -public sealed partial record V230 : B230_1, IValidatedValue -{ - public static Result Create(double value) => new V230(value); -} -} - -// row 231 -public static partial class O231 -{ -public interface IMark231 { int Mark(); } -public readonly partial record struct V231 : IValidatedValue, IMark231 -{ - public static Result Create(global::System.Uri value) => new V231(value); int IMark231.Mark() => 1; -} -} - -// row 232 -public partial struct O232 -{ -public interface IMark232 { int Mark(); } -public readonly partial record struct V232 : IValue, IMark232 { int IMark232.Mark() => 1; } -} - -// row 233 -public static partial class O233 -{ -public sealed partial class P233 -{ -public readonly partial record struct V233 : IValue { } -} -} - -// row 234 -public readonly partial record struct V234 : IValue { } - -// row 235 -public abstract record B235_3 { } -public abstract record B235_2 : B235_3 { } -public abstract record B235_1 : B235_2 { } -public sealed partial record V235 : B235_1, IValidatedValue -{ - public static Result Create(global::System.DateTimeOffset value) => new V235(value); -} - -// row 236 -public abstract record B236_3 { } -public abstract record B236_2 : B236_3 { } -public abstract record B236_1 : B236_2 { } -public sealed partial record V236 : B236_1, IValidatedValue -{ - public static Result Create(bool value) => new V236(value); -} - -// row 237 -public static partial class O237 -{ -public abstract record B237_2 { } -public abstract record B237_1 : B237_2 { } -public sealed partial record V237 : B237_1, IValue { } -} - -// row 238 -public static partial class O238 -{ -public sealed partial class P238 -{ -public abstract record B238_1 { } -public sealed partial record V238 : B238_1, IValue { } -} -} - -// row 239 -public abstract record B239_1 { } -public sealed partial record V239 : B239_1, IValue { } - -// row 240 -public abstract record B240_1 { } -public sealed partial record V240 : B240_1, IValue { } - -// row 241 -public static partial class O241 -{ -public sealed partial class P241 -{ -public interface IMark241 { int Mark(); } -public sealed partial record V241 : IValidatedValue, IMark241 -{ - public static Result Create(global::Probes.Shapes.PEnum value) => new V241(value); int IMark241.Mark() => 1; -} -} -} - -// row 242 -public partial struct O242 -{ -public abstract record B242_3 { } -public abstract record B242_2 : B242_3 { } -public abstract record B242_1 : B242_2 { } -public sealed partial record V242 : B242_1, IValue { } -} - -// row 243 -public readonly partial record struct V243 : IValue { } - -// row 244 -public static partial class O244 -{ -public sealed partial class P244 -{ -public readonly partial record struct V244 : IValidatedValue -{ - public static Result Create(global::NodaTime.Instant value) => new V244(value); -} -} -} - -// row 245 -public partial struct O245 -{ -public interface IMark245 { int Mark(); } -public readonly partial record struct V245 : IValue, IMark245 { int IMark245.Mark() => 1; } -} - -// row 246 -public static partial class O246 -{ -public sealed partial class P246 -{ -public abstract record B246_3 { } -public abstract record B246_2 : B246_3 { } -public abstract record B246_1 : B246_2 { } -public sealed partial record V246 : B246_1, IValidatedValue -{ - public static Result Create(global::System.Uri value) => new V246(value); -} -} -} - -public static partial class C11Table -{ - public static readonly C11Case[] Cases = - [ - new(0, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=double;text.culture=invariant;text.entry=TryFrom", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O0.V0), typeof(double), null, null, []), - new(1, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=TimeSpan;text.culture=de-DE;text.entry=ISpanParsable", "validated-class", "top-level", "none", typeof(V1), typeof(global::System.TimeSpan), null, null, []), - new(2, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=decimal;text.culture=tr-TR;text.entry=TryFormat-short-span", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O2.V2), typeof(global::Probes.Build.C11ParsesToInt), typeof(O2.VC2), typeof(global::Probes.Build.C11ParsedShape), []), - new(3, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=TimeOnly;text.culture=tr-TR;text.entry=Parse", "validated-struct", "nested-two-levels", "none", typeof(O3.P3.V3), typeof(global::Probes.Build.C11AbstractText), typeof(O3.P3.VC3), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(4, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=decimal;text.culture=ar-SA;text.entry=ToString-format", "record-struct", "top-level", "explicit-interface-member", typeof(V4), typeof(global::Probes.Build.C11ParsesByRef), typeof(VC4), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(5, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=char;text.culture=globalization-invariant;text.entry=IParsable", "validated-class", "nested-in-struct", "base-depth-1", typeof(O5.V5), typeof(global::Probes.Build.C11AbstractText), typeof(O5.VC5), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(6, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=string;text.culture=globalization-invariant;text.entry=TryParse", "record-struct", "nested-in-class", "none", typeof(O6.V6), typeof(global::Probes.Build.C11ParsesToInt), typeof(O6.VC6), typeof(global::Probes.Build.C11ParsedShape), []), - new(7, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=NodaTime.Instant;text.culture=invariant;text.entry=type-converter", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O7.P7.V7), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O7.P7.VC7), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(8, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=long;text.culture=ar-SA;text.entry=IParsable", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O8.P8.V8), typeof(long), null, null, []), - new(9, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=NodaTime.Instant;text.culture=de-DE;text.entry=TryParse", "validated-class", "nested-in-struct", "base-depth-3", typeof(O9.V9), typeof(global::NodaTime.Instant), null, null, []), - new(10, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=ulong;text.culture=invariant;text.entry=TryFormat-short-span", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V10), typeof(global::Probes.Build.C11ParsesToInt), typeof(VC10), typeof(global::Probes.Build.C11ParsedShape), []), - new(11, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=Guid;text.culture=de-DE;text.entry=Parse", "validated-struct", "nested-in-class", "explicit-interface-member", typeof(O11.V11), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O11.VC11), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(12, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=bool;text.culture=globalization-invariant;text.entry=type-converter", "sealed-record-class", "top-level", "base-depth-2", typeof(V12), typeof(bool), null, null, []), - new(13, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateTime;text.culture=tr-TR;text.entry=ToString-format", "validated-class", "nested-in-class", "base-depth-3", typeof(O13.V13), typeof(global::Probes.Build.C11AbstractText), typeof(O13.VC13), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(14, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateOnly;text.culture=ar-SA;text.entry=ISpanParsable", "validated-struct", "nested-in-struct", "none", typeof(O14.V14), typeof(global::System.DateOnly), null, null, [("shape.inheritance", "none")]), - new(15, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=int;text.culture=invariant;text.entry=TryFrom", "record-struct", "nested-in-struct", "none", typeof(O15.V15), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O15.VC15), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(16, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=enum;text.culture=globalization-invariant;text.entry=TryFormat-short-span", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O16.P16.V16), typeof(global::Probes.Build.C11AbstractText), typeof(O16.P16.VC16), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(17, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=Uri;text.culture=tr-TR;text.entry=Parse", "record-struct", "top-level", "none", typeof(V17), typeof(global::System.Uri), null, null, [("shape.inheritance", "none")]), - new(18, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=TimeOnly;text.culture=ar-SA;text.entry=TryFrom", "validated-class", "nested-two-levels", "base-depth-2", typeof(O18.P18.V18), typeof(global::Probes.Build.C11ParsesToInt), typeof(O18.P18.VC18), typeof(global::Probes.Build.C11ParsedShape), []), - new(19, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=string;text.culture=de-DE;text.entry=ISpanParsable", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O19.V19), typeof(global::Probes.Build.C11AbstractText), typeof(O19.VC19), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(20, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=TimeSpan;text.culture=tr-TR;text.entry=IParsable", "validated-struct", "nested-in-struct", "explicit-interface-member", typeof(O20.V20), typeof(global::Probes.Build.C11ParsesByRef), typeof(O20.VC20), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(21, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=DateTimeOffset;text.culture=ar-SA;text.entry=TryFormat-short-span", "validated-struct", "nested-in-class", "none", typeof(O21.V21), typeof(global::System.DateTimeOffset), null, null, []), - new(22, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=ulong;text.culture=de-DE;text.entry=ISpanParsable", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O22.P22.V22), typeof(global::Probes.Build.C11ParsesToInt), typeof(O22.P22.VC22), typeof(global::Probes.Build.C11ParsedShape), []), - new(23, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=byte;text.culture=invariant;text.entry=ToString-format", "sealed-record-class", "nested-two-levels", "base-depth-3", typeof(O23.P23.V23), typeof(byte), null, null, []), - new(24, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=own-record-class;text.culture=de-DE;text.entry=ToString-format", "validated-struct", "nested-in-class", "none", typeof(O24.V24), typeof(global::Probes.Build.C11ParsesToInt), typeof(O24.VC24), typeof(global::Probes.Build.C11ParsedShape), [("shape.inheritance", "none")]), - new(25, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=char;text.culture=ar-SA;text.entry=TryParse", "validated-struct", "top-level", "explicit-interface-member", typeof(V25), typeof(global::Probes.Build.C11AbstractText), typeof(VC25), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(26, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=byte;text.culture=globalization-invariant;text.entry=Parse", "validated-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O26.V26), typeof(global::Probes.Build.C11ParsesByRef), typeof(O26.VC26), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(27, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=ulong;text.culture=ar-SA;text.entry=type-converter", "validated-struct", "nested-in-class", "none", typeof(O27.V27), typeof(global::Probes.Build.C11ParsesToInt), typeof(O27.VC27), typeof(global::Probes.Build.C11ParsedShape), [("shape.inheritance", "none")]), - new(28, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=TimeOnly;text.culture=globalization-invariant;text.entry=TryFrom", "validated-struct", "top-level", "none", typeof(V28), typeof(global::Probes.Build.C11ParsesByRef), typeof(VC28), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.inheritance", "none")]), - new(29, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=flags-enum;text.culture=de-DE;text.entry=type-converter", "validated-class", "nested-in-struct", "explicit-interface-member", typeof(O29.V29), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O29.VC29), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(30, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=DateOnly;text.culture=invariant;text.entry=TryParse", "sealed-record-class", "top-level", "base-depth-2", typeof(V30), typeof(global::Probes.Build.C11ParsesByRef), typeof(VC30), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(31, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=decimal;text.culture=invariant;text.entry=IParsable", "validated-struct", "nested-in-class", "none", typeof(O31.V31), typeof(global::Probes.Build.C11ParsesToInt), typeof(O31.VC31), typeof(global::Probes.Build.C11ParsedShape), []), - new(32, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Guid;text.culture=globalization-invariant;text.entry=ToString-format", "sealed-record-class", "nested-in-struct", "none", typeof(O32.V32), typeof(global::Probes.Build.C11AbstractText), typeof(O32.VC32), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(33, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=long;text.culture=de-DE;text.entry=TryFrom", "validated-class", "nested-in-class", "base-depth-1", typeof(O33.V33), typeof(long), null, null, []), - new(34, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=flags-enum;text.culture=globalization-invariant;text.entry=Parse", "sealed-record-class", "top-level", "base-depth-3", typeof(V34), typeof(global::Probes.Build.C11ParsesToInt), typeof(VC34), typeof(global::Probes.Build.C11ParsedShape), []), - new(35, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=int;text.culture=globalization-invariant;text.entry=IParsable", "sealed-record-class", "top-level", "base-depth-2", typeof(V35), typeof(int), null, null, []), - new(36, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTime;text.culture=invariant;text.entry=Parse", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O36.V36), typeof(global::Probes.Build.C11AbstractText), typeof(O36.VC36), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(37, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=char;text.culture=tr-TR;text.entry=type-converter", "sealed-record-class", "nested-two-levels", "none", typeof(O37.P37.V37), typeof(char), null, null, []), - new(38, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=DateTimeOffset;text.culture=globalization-invariant;text.entry=ISpanParsable", "validated-class", "nested-in-struct", "base-depth-2", typeof(O38.V38), typeof(global::Probes.Build.C11ParsesByRef), typeof(O38.VC38), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(39, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=enum;text.culture=ar-SA;text.entry=Parse", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O39.V39), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(40, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Uri;text.culture=invariant;text.entry=ISpanParsable", "validated-struct", "nested-in-struct", "none", typeof(O40.V40), typeof(global::Probes.Build.C11ParsesToInt), typeof(O40.VC40), typeof(global::Probes.Build.C11ParsedShape), [("shape.inheritance", "none")]), - new(41, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=own-record-class;text.culture=tr-TR;text.entry=ISpanParsable", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O41.V41), typeof(global::Probes.Shapes.PRec), null, null, []), - new(42, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Guid;text.culture=tr-TR;text.entry=TryParse", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O42.P42.V42), typeof(global::System.Guid), null, null, []), - new(43, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=bool;text.culture=de-DE;text.entry=IParsable", "record-struct", "nested-in-struct", "none", typeof(O43.V43), typeof(global::Probes.Build.C11AbstractText), typeof(O43.VC43), typeof(global::Probes.Build.C11ConstructedConcrete), [("shape.inheritance", "none")]), - new(44, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=TimeOnly;text.culture=de-DE;text.entry=TryFormat-short-span", "record-struct", "nested-two-levels", "none", typeof(O44.P44.V44), typeof(global::Probes.Build.C11ParsesByRef), typeof(O44.P44.VC44), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.inheritance", "none")]), - new(45, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=double;text.culture=ar-SA;text.entry=TryFormat-short-span", "validated-struct", "top-level", "none", typeof(V45), typeof(global::Probes.Build.C11ConstructedByRef), typeof(VC45), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(46, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=flags-enum;text.culture=invariant;text.entry=ToString-format", "validated-struct", "nested-in-class", "none", typeof(O46.V46), typeof(global::Probes.Shapes.PFlags), null, null, [("shape.inheritance", "none")]), - new(47, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=int;text.culture=de-DE;text.entry=type-converter", "validated-struct", "nested-in-class", "none", typeof(O47.V47), typeof(int), null, null, [("shape.inheritance", "none")]), - new(48, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=in-generic-type;shape.wrapped=Guid;text.culture=invariant;text.entry=type-converter", "record-struct", "nested-in-class", "none", typeof(O48.V48), typeof(global::Probes.Build.C11AbstractText), typeof(O48.VC48), typeof(global::Probes.Build.C11ConstructedConcrete), [("shape.site", "nested-in-class"), ("shape.inheritance", "none")]), - new(49, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=bool;text.culture=tr-TR;text.entry=TryFrom", "validated-class", "nested-in-class", "base-explicit-IEquatable", typeof(O49.V49), typeof(bool), null, null, []), - new(50, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=DateTimeOffset;text.culture=invariant;text.entry=type-converter", "sealed-record-class", "top-level", "base-explicit-IEquatable", typeof(V50), typeof(global::Probes.Build.C11ParsesByRef), typeof(VC50), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(51, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateOnly;text.culture=globalization-invariant;text.entry=IParsable", "validated-class", "nested-in-class", "base-depth-3", typeof(O51.V51), typeof(global::System.DateOnly), null, null, []), - new(52, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=ulong;text.culture=tr-TR;text.entry=TryFrom", "sealed-record-class", "nested-in-struct", "none", typeof(O52.V52), typeof(ulong), null, null, []), - new(53, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=string;text.culture=invariant;text.entry=TryFormat-short-span", "validated-class", "nested-two-levels", "base-depth-3", typeof(O53.P53.V53), typeof(string), null, null, []), - new(54, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Uri;text.culture=ar-SA;text.entry=TryFrom", "validated-class", "nested-two-levels", "base-depth-3", typeof(O54.P54.V54), typeof(global::Probes.Build.C11AbstractText), typeof(O54.P54.VC54), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(55, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=TimeSpan;text.culture=ar-SA;text.entry=TryParse", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O55.P55.V55), typeof(global::System.TimeSpan), null, null, []), - new(56, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=decimal;text.culture=globalization-invariant;text.entry=TryParse", "validated-class", "nested-two-levels", "base-depth-1", typeof(O56.P56.V56), typeof(decimal), null, null, []), - new(57, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=enum;text.culture=de-DE;text.entry=ToString-format", "validated-class", "top-level", "base-depth-1", typeof(V57), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(58, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=byte;text.culture=tr-TR;text.entry=TryParse", "record-struct", "top-level", "none", typeof(V58), typeof(byte), null, null, []), - new(59, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=double;text.culture=tr-TR;text.entry=TryParse", "validated-class", "nested-two-levels", "base-depth-3", typeof(O59.P59.V59), typeof(double), null, null, []), - new(60, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeOnly;text.culture=invariant;text.entry=ToString-format", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O60.V60), typeof(global::System.TimeOnly), null, null, []), - new(61, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=string;text.culture=tr-TR;text.entry=Parse", "sealed-record-class", "nested-in-struct", "base-depth-1", typeof(O61.V61), typeof(global::Probes.Build.C11ParsesToInt), typeof(O61.VC61), typeof(global::Probes.Build.C11ParsedShape), []), - new(62, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTime;text.culture=ar-SA;text.entry=ISpanParsable", "validated-struct", "nested-two-levels", "none", typeof(O62.P62.V62), typeof(global::System.DateTime), null, null, []), - new(63, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=NodaTime.Instant;text.culture=tr-TR;text.entry=TryFrom", "record-struct", "top-level", "explicit-interface-member", typeof(V63), typeof(global::NodaTime.Instant), null, null, []), - new(64, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=enum;text.culture=tr-TR;text.entry=type-converter", "validated-struct", "nested-in-class", "none", typeof(O64.V64), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(65, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=Guid;text.culture=ar-SA;text.entry=TryFormat-short-span", "validated-class", "top-level", "base-depth-2", typeof(V65), typeof(global::System.Guid), null, null, []), - new(66, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=own-record-class;text.culture=ar-SA;text.entry=IParsable", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V66), typeof(global::Probes.Shapes.PRec), null, null, []), - new(67, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=bool;text.culture=ar-SA;text.entry=ISpanParsable", "validated-struct", "nested-two-levels", "none", typeof(O67.P67.V67), typeof(global::Probes.Build.C11AbstractText), typeof(O67.P67.VC67), typeof(global::Probes.Build.C11ConstructedConcrete), [("shape.inheritance", "none")]), - new(68, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=DateOnly;text.culture=tr-TR;text.entry=ToString-format", "record-struct", "nested-two-levels", "none", typeof(O68.P68.V68), typeof(global::System.DateOnly), null, null, [("shape.inheritance", "none")]), - new(69, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=long;text.culture=invariant;text.entry=TryParse", "validated-struct", "nested-in-struct", "explicit-interface-member", typeof(O69.V69), typeof(long), null, null, []), - new(70, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTimeOffset;text.culture=tr-TR;text.entry=Parse", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O70.P70.V70), typeof(global::System.DateTimeOffset), null, null, []), - new(71, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=flags-enum;text.culture=ar-SA;text.entry=TryFormat-short-span", "record-struct", "nested-two-levels", "none", typeof(O71.P71.V71), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(72, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=double;text.culture=globalization-invariant;text.entry=ToString-format", "record-struct", "nested-in-struct", "none", typeof(O72.V72), typeof(double), null, null, [("shape.inheritance", "none")]), - new(73, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=byte;text.culture=de-DE;text.entry=ISpanParsable", "validated-struct", "nested-in-class", "explicit-interface-member", typeof(O73.V73), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O73.VC73), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(74, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=char;text.culture=de-DE;text.entry=TryFormat-short-span", "record-struct", "nested-in-class", "none", typeof(O74.V74), typeof(char), null, null, []), - new(75, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=int;text.culture=ar-SA;text.entry=TryFormat-short-span", "validated-class", "nested-in-struct", "base-depth-1", typeof(O75.V75), typeof(int), null, null, []), - new(76, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=Uri;text.culture=de-DE;text.entry=TryParse", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O76.V76), typeof(global::System.Uri), null, null, []), - new(77, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=long;text.culture=globalization-invariant;text.entry=ToString-format", "record-struct", "top-level", "none", typeof(V77), typeof(global::Probes.Build.C11AbstractText), typeof(VC77), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(78, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=own-record-class;text.culture=invariant;text.entry=TryParse", "record-struct", "nested-two-levels", "none", typeof(O78.P78.V78), typeof(global::Probes.Build.C11ParsesToInt), typeof(O78.P78.VC78), typeof(global::Probes.Build.C11ParsedShape), []), - new(79, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=DateTime;text.culture=globalization-invariant;text.entry=TryFrom", "sealed-record-class", "top-level", "base-explicit-IEquatable", typeof(V79), typeof(global::Probes.Build.C11ParsesToInt), typeof(VC79), typeof(global::Probes.Build.C11ParsedShape), []), - new(80, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=NodaTime.Instant;text.culture=globalization-invariant;text.entry=IParsable", "validated-struct", "nested-in-class", "none", typeof(O80.V80), typeof(global::NodaTime.Instant), null, null, [("shape.inheritance", "none")]), - new(81, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=closed-set;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeSpan;text.culture=ar-SA;text.entry=Parse", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O81.V81), typeof(global::Probes.Build.C11AbstractText), typeof(O81.VC81), typeof(global::Probes.Build.C11ConstructedConcrete), [("shape.kind", "sealed-record-class")]), - new(82, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTime;text.culture=de-DE;text.entry=IParsable", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O82.P82.V82), typeof(global::System.DateTime), null, null, []), - new(83, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=string;text.culture=ar-SA;text.entry=ToString-format", "validated-class", "top-level", "base-depth-2", typeof(V83), typeof(string), null, null, []), - new(84, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=long;text.culture=tr-TR;text.entry=ISpanParsable", "validated-class", "nested-in-class", "base-depth-2", typeof(O84.V84), typeof(long), null, null, []), - new(85, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=TimeOnly;text.culture=invariant;text.entry=type-converter", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O85.V85), typeof(global::System.TimeOnly), null, null, []), - new(86, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=byte;text.culture=ar-SA;text.entry=TryFrom", "sealed-record-class", "nested-two-levels", "base-depth-2", typeof(O86.P86.V86), typeof(global::Probes.Build.C11ParsesToInt), typeof(O86.P86.VC86), typeof(global::Probes.Build.C11ParsedShape), []), - new(87, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=int;text.culture=tr-TR;text.entry=ToString-format", "sealed-record-class", "nested-two-levels", "none", typeof(O87.P87.V87), typeof(int), null, null, []), - new(88, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=DateOnly;text.culture=de-DE;text.entry=type-converter", "sealed-record-class", "top-level", "none", typeof(V88), typeof(global::Probes.Build.C11AbstractText), typeof(VC88), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(89, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=ulong;text.culture=globalization-invariant;text.entry=TryParse", "validated-class", "top-level", "base-depth-2", typeof(V89), typeof(ulong), null, null, []), - new(90, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=NodaTime.Instant;text.culture=ar-SA;text.entry=TryFormat-short-span", "record-struct", "top-level", "none", typeof(V90), typeof(global::NodaTime.Instant), null, null, []), - new(91, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTimeOffset;text.culture=de-DE;text.entry=ToString-format", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O91.P91.V91), typeof(global::Probes.Build.C11ParsesToInt), typeof(O91.P91.VC91), typeof(global::Probes.Build.C11ParsedShape), [("shape.kind", "sealed-record-class")]), - new(92, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=in-generic-type;shape.wrapped=TimeSpan;text.culture=invariant;text.entry=type-converter", "validated-class", "nested-in-class", "base-depth-2", typeof(O92.V92), typeof(global::System.TimeSpan), null, null, [("shape.site", "nested-in-class")]), - new(93, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=decimal;text.culture=de-DE;text.entry=ISpanParsable", "sealed-record-class", "top-level", "base-depth-3", typeof(V93), typeof(decimal), null, null, []), - new(94, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Uri;text.culture=globalization-invariant;text.entry=IParsable", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O94.V94), typeof(global::System.Uri), null, null, []), - new(95, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=char;text.culture=invariant;text.entry=TryFrom", "validated-class", "top-level", "base-depth-3", typeof(V95), typeof(char), null, null, []), - new(96, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=own-record-class;text.culture=globalization-invariant;text.entry=type-converter", "validated-class", "nested-in-struct", "base-depth-3", typeof(O96.V96), typeof(global::Probes.Shapes.PRec), null, null, []), - new(97, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=flags-enum;text.culture=tr-TR;text.entry=TryFrom", "validated-class", "top-level", "base-depth-1", typeof(V97), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(98, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=enum;text.culture=invariant;text.entry=TryParse", "sealed-record-class", "top-level", "base-depth-2", typeof(V98), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(99, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=string;text.culture=invariant;text.entry=TryFrom", "validated-struct", "top-level", "explicit-interface-member", typeof(V99), typeof(string), null, null, []), - new(100, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=double;text.culture=de-DE;text.entry=ISpanParsable", "validated-class", "top-level", "base-depth-1", typeof(V100), typeof(global::Probes.Build.C11ParsesToInt), typeof(VC100), typeof(global::Probes.Build.C11ParsedShape), []), - new(101, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=in-generic-type;shape.wrapped=DateOnly;text.culture=tr-TR;text.entry=Parse", "validated-struct", "nested-in-class", "explicit-interface-member", typeof(O101.V101), typeof(global::System.DateOnly), null, null, [("shape.site", "nested-in-class")]), - new(102, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=bool;text.culture=invariant;text.entry=TryParse", "sealed-record-class", "nested-two-levels", "explicit-interface-member", typeof(O102.P102.V102), typeof(bool), null, null, []), - new(103, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=bool;text.culture=ar-SA;text.entry=ToString-format", "validated-struct", "top-level", "none", typeof(V103), typeof(global::Probes.Build.C11ParsesToInt), typeof(VC103), typeof(global::Probes.Build.C11ParsedShape), [("shape.inheritance", "none")]), - new(104, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=TimeSpan;text.culture=globalization-invariant;text.entry=TryFormat-short-span", "record-struct", "nested-two-levels", "none", typeof(O104.P104.V104), typeof(global::System.TimeSpan), null, null, []), - new(105, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=own-record-class;text.culture=de-DE;text.entry=TryFormat-short-span", "record-struct", "top-level", "explicit-interface-member", typeof(V105), typeof(global::Probes.Shapes.PRec), null, null, []), - new(106, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=enum;text.culture=globalization-invariant;text.entry=ISpanParsable", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O106.P106.V106), typeof(global::Probes.Build.C11ParsesToInt), typeof(O106.P106.VC106), typeof(global::Probes.Build.C11ParsedShape), []), - new(107, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Uri;text.culture=tr-TR;text.entry=ToString-format", "record-struct", "nested-two-levels", "none", typeof(O107.P107.V107), typeof(global::Probes.Build.C11ParsesToInt), typeof(O107.P107.VC107), typeof(global::Probes.Build.C11ParsedShape), []), - new(108, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=bool;text.culture=tr-TR;text.entry=TryFormat-short-span", "validated-struct", "nested-two-levels", "none", typeof(O108.P108.V108), typeof(bool), null, null, []), - new(109, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=flags-enum;text.culture=ar-SA;text.entry=ISpanParsable", "validated-class", "nested-in-class", "base-depth-2", typeof(O109.V109), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O109.VC109), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(110, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Uri;text.culture=ar-SA;text.entry=type-converter", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O110.P110.V110), typeof(global::System.Uri), null, null, []), - new(111, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=int;text.culture=de-DE;text.entry=ISpanParsable", "record-struct", "nested-in-class", "none", typeof(O111.V111), typeof(global::Probes.Build.C11ParsesToInt), typeof(O111.VC111), typeof(global::Probes.Build.C11ParsedShape), [("shape.inheritance", "none")]), - new(112, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=int;text.culture=ar-SA;text.entry=TryParse", "validated-struct", "nested-in-struct", "explicit-interface-member", typeof(O112.V112), typeof(int), null, null, []), - new(113, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=ulong;text.culture=globalization-invariant;text.entry=Parse", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O113.V113), typeof(ulong), null, null, []), - new(114, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=double;text.culture=de-DE;text.entry=IParsable", "validated-class", "nested-in-struct", "base-depth-2", typeof(O114.V114), typeof(double), null, null, []), - new(115, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateTime;text.culture=tr-TR;text.entry=TryParse", "validated-struct", "nested-in-class", "none", typeof(O115.V115), typeof(global::System.DateTime), null, null, [("shape.inheritance", "none")]), - new(116, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=closed-set;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=in-generic-type;shape.wrapped=char;text.culture=globalization-invariant;text.entry=ISpanParsable", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O116.V116), typeof(char), null, null, [("shape.kind", "sealed-record-class"), ("shape.site", "nested-in-class")]), - new(117, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=byte;text.culture=tr-TR;text.entry=TryFormat-short-span", "sealed-record-class", "nested-in-class", "base-depth-1", typeof(O117.V117), typeof(global::Probes.Build.C11ParsesToInt), typeof(O117.VC117), typeof(global::Probes.Build.C11ParsedShape), []), - new(118, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=char;text.culture=ar-SA;text.entry=Parse", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O118.V118), typeof(char), null, null, []), - new(119, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Guid;text.culture=tr-TR;text.entry=IParsable", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O119.P119.V119), typeof(global::System.Guid), null, null, []), - new(120, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=NodaTime.Instant;text.culture=invariant;text.entry=ToString-format", "validated-class", "nested-in-struct", "base-depth-2", typeof(O120.V120), typeof(global::NodaTime.Instant), null, null, []), - new(121, "parse-shape=abstract-string-ctor;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=closed-set;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=TimeSpan;text.culture=invariant;text.entry=TryFrom", "sealed-record-class", "top-level", "base-depth-3", typeof(V121), typeof(global::Probes.Build.C11AbstractText), typeof(VC121), typeof(global::Probes.Build.C11ConstructedConcrete), [("shape.kind", "sealed-record-class")]), - new(122, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=in-generic-type;shape.wrapped=long;text.culture=globalization-invariant;text.entry=type-converter", "record-struct", "nested-in-class", "none", typeof(O122.V122), typeof(long), null, null, [("shape.site", "nested-in-class"), ("shape.inheritance", "none")]), - new(123, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateOnly;text.culture=de-DE;text.entry=TryFrom", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O123.V123), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O123.VC123), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.kind", "sealed-record-class")]), - new(124, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTimeOffset;text.culture=tr-TR;text.entry=TryFrom", "validated-struct", "nested-in-struct", "none", typeof(O124.V124), typeof(global::Probes.Build.C11ParsesByRef), typeof(O124.VC124), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.inheritance", "none")]), - new(125, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=Uri;text.culture=tr-TR;text.entry=TryFormat-short-span", "validated-struct", "nested-in-class", "explicit-interface-member", typeof(O125.V125), typeof(global::System.Uri), null, null, []), - new(126, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=decimal;text.culture=de-DE;text.entry=Parse", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O126.P126.V126), typeof(decimal), null, null, []), - new(127, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=closed-set;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=NodaTime.Instant;text.culture=ar-SA;text.entry=Parse", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O127.V127), typeof(global::NodaTime.Instant), null, null, [("shape.kind", "sealed-record-class")]), - new(128, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=DateTime;text.culture=de-DE;text.entry=type-converter", "validated-class", "nested-in-class", "base-explicit-IEquatable", typeof(O128.V128), typeof(global::System.DateTime), null, null, []), - new(129, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=own-record-class;text.culture=ar-SA;text.entry=TryFrom", "validated-struct", "top-level", "none", typeof(V129), typeof(global::Probes.Build.C11ConstructedByRef), typeof(VC129), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.inheritance", "none")]), - new(130, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=char;text.culture=globalization-invariant;text.entry=ToString-format", "record-struct", "nested-in-class", "explicit-interface-member", typeof(O130.V130), typeof(char), null, null, []), - new(131, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=long;text.culture=globalization-invariant;text.entry=TryFormat-short-span", "record-struct", "nested-in-struct", "explicit-interface-member", typeof(O131.V131), typeof(long), null, null, []), - new(132, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=double;text.culture=invariant;text.entry=Parse", "validated-struct", "top-level", "explicit-interface-member", typeof(V132), typeof(global::Probes.Build.C11AbstractText), typeof(VC132), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(133, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=own-record-class;text.culture=de-DE;text.entry=Parse", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O133.V133), typeof(global::Probes.Shapes.PRec), null, null, []), - new(134, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=NodaTime.Instant;text.culture=invariant;text.entry=ISpanParsable", "validated-class", "top-level", "base-depth-2", typeof(V134), typeof(global::Probes.Build.C11ParsesByRef), typeof(VC134), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(135, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=TimeSpan;text.culture=globalization-invariant;text.entry=ToString-format", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O135.V135), typeof(global::System.TimeSpan), null, null, [("shape.kind", "sealed-record-class")]), - new(136, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=TimeOnly;text.culture=de-DE;text.entry=TryParse", "record-struct", "nested-in-struct", "explicit-interface-member", typeof(O136.V136), typeof(global::System.TimeOnly), null, null, []), - new(137, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=byte;text.culture=ar-SA;text.entry=IParsable", "sealed-record-class", "nested-in-class", "base-depth-1", typeof(O137.V137), typeof(global::Probes.Build.C11ParsesToInt), typeof(O137.VC137), typeof(global::Probes.Build.C11ParsedShape), []), - new(138, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeOnly;text.culture=invariant;text.entry=ISpanParsable", "record-struct", "nested-in-class", "none", typeof(O138.V138), typeof(global::Probes.Build.C11AbstractText), typeof(O138.VC138), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(139, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=flags-enum;text.culture=de-DE;text.entry=TryParse", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O139.P139.V139), typeof(global::Probes.Shapes.PFlags), null, null, [("shape.kind", "sealed-record-class")]), - new(140, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=bool;text.culture=globalization-invariant;text.entry=Parse", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O140.V140), typeof(bool), null, null, []), - new(141, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=in-generic-type;shape.wrapped=DateTimeOffset;text.culture=de-DE;text.entry=IParsable", "record-struct", "nested-in-class", "explicit-interface-member", typeof(O141.V141), typeof(global::Probes.Build.C11AbstractText), typeof(O141.VC141), typeof(global::Probes.Build.C11ConstructedConcrete), [("shape.site", "nested-in-class")]), - new(142, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=in-generic-type;shape.wrapped=TimeOnly;text.culture=invariant;text.entry=IParsable", "validated-struct", "nested-in-class", "none", typeof(O142.V142), typeof(global::Probes.Build.C11ParsesToInt), typeof(O142.VC142), typeof(global::Probes.Build.C11ParsedShape), [("shape.site", "nested-in-class")]), - new(143, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=none;shape.kind=closed-set;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=byte;text.culture=tr-TR;text.entry=type-converter", "sealed-record-class", "top-level", "none", typeof(V143), typeof(global::Probes.Build.C11ConstructedByRef), typeof(VC143), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.kind", "sealed-record-class")]), - new(144, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=enum;text.culture=de-DE;text.entry=TryFrom", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O144.P144.V144), typeof(global::Probes.Build.C11AbstractText), typeof(O144.P144.VC144), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(145, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=ulong;text.culture=de-DE;text.entry=ToString-format", "validated-struct", "nested-two-levels", "none", typeof(O145.P145.V145), typeof(ulong), null, null, []), - new(146, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=int;text.culture=de-DE;text.entry=Parse", "validated-struct", "nested-in-class", "none", typeof(O146.V146), typeof(global::Probes.Build.C11ParsesToInt), typeof(O146.VC146), typeof(global::Probes.Build.C11ParsedShape), []), - new(147, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=Guid;text.culture=ar-SA;text.entry=ISpanParsable", "validated-struct", "nested-two-levels", "explicit-interface-member", typeof(O147.P147.V147), typeof(global::Probes.Build.C11AbstractText), typeof(O147.P147.VC147), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(148, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=in-generic-type;shape.wrapped=enum;text.culture=globalization-invariant;text.entry=IParsable", "validated-class", "nested-in-class", "none", typeof(O148.V148), typeof(global::Probes.Shapes.PEnum), null, null, [("shape.site", "nested-in-class")]), - new(149, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTime;text.culture=invariant;text.entry=TryFormat-short-span", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O149.V149), typeof(global::Probes.Build.C11ParsesToInt), typeof(O149.VC149), typeof(global::Probes.Build.C11ParsedShape), []), - new(150, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=decimal;text.culture=de-DE;text.entry=TryFrom", "validated-class", "nested-two-levels", "base-depth-3", typeof(O150.P150.V150), typeof(decimal), null, null, []), - new(151, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=ulong;text.culture=invariant;text.entry=IParsable", "validated-class", "nested-in-class", "none", typeof(O151.V151), typeof(ulong), null, null, []), - new(152, "parse-shape=abstract-string-ctor;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=double;text.culture=ar-SA;text.entry=type-converter", "sealed-record-class", "nested-in-class", "explicit-interface-member", typeof(O152.V152), typeof(global::Probes.Build.C11AbstractText), typeof(O152.VC152), typeof(global::Probes.Build.C11ConstructedConcrete), []), - new(153, "parse-shape=implicit-result;process.converter-lookup=none;shape.inheritance=none;shape.kind=closed-set;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=in-generic-type;shape.wrapped=Guid;text.culture=ar-SA;text.entry=TryFrom", "sealed-record-class", "nested-in-class", "none", typeof(O153.V153), typeof(global::Probes.Build.C11ParsesToInt), typeof(O153.VC153), typeof(global::Probes.Build.C11ParsedShape), [("shape.kind", "sealed-record-class"), ("shape.site", "nested-in-class")]), - new(154, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=long;text.culture=invariant;text.entry=Parse", "sealed-record-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O154.P154.V154), typeof(global::Probes.Build.C11ParsesToInt), typeof(O154.P154.VC154), typeof(global::Probes.Build.C11ParsedShape), []), - new(155, "parse-shape=ref-text;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=closed-set;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=string;text.culture=globalization-invariant;text.entry=type-converter", "sealed-record-class", "top-level", "none", typeof(V155), typeof(global::Probes.Build.C11ConstructedByRef), typeof(VC155), typeof(global::Probes.Build.C11ParsesFromIn), [("shape.kind", "sealed-record-class")]), - new(156, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=DateTimeOffset;text.culture=de-DE;text.entry=TryParse", "validated-struct", "top-level", "explicit-interface-member", typeof(V156), typeof(global::System.DateTimeOffset), null, null, []), - new(157, "parse-shape=implicit-result;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateOnly;text.culture=globalization-invariant;text.entry=TryFormat-short-span", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O157.P157.V157), typeof(global::Probes.Build.C11ParsesToInt), typeof(O157.P157.VC157), typeof(global::Probes.Build.C11ParsedShape), []), - new(158, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=string;text.culture=invariant;text.entry=IParsable", "validated-class", "nested-two-levels", "base-depth-3", typeof(O158.P158.V158), typeof(string), null, null, []), - new(159, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=flags-enum;text.culture=globalization-invariant;text.entry=IParsable", "sealed-record-class", "nested-two-levels", "base-depth-2", typeof(O159.P159.V159), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(160, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=decimal;text.culture=invariant;text.entry=type-converter", "sealed-record-class", "nested-in-struct", "explicit-interface-member", typeof(O160.V160), typeof(decimal), null, null, []), - new(161, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=Guid;text.culture=invariant;text.entry=type-converter", "record-struct", "nested-in-class", "none", typeof(O161.V161), typeof(global::System.Guid), null, null, []), - new(162, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTime;text.culture=invariant;text.entry=TryFormat-short-span", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O162.V162), typeof(global::System.DateTime), null, null, []), - new(163, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTimeOffset;text.culture=invariant;text.entry=ToString-format", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O163.V163), typeof(global::System.DateTimeOffset), null, null, []), - new(164, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=byte;text.culture=ar-SA;text.entry=IParsable", "validated-struct", "nested-in-struct", "explicit-interface-member", typeof(O164.V164), typeof(byte), null, null, []), - new(165, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=DateOnly;text.culture=de-DE;text.entry=ToString-format", "sealed-record-class", "top-level", "base-explicit-IEquatable", typeof(V165), typeof(global::System.DateOnly), null, null, []), - new(166, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=decimal;text.culture=ar-SA;text.entry=ToString-format", "record-struct", "nested-in-class", "none", typeof(O166.V166), typeof(decimal), null, null, []), - new(167, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=string;text.culture=de-DE;text.entry=Parse", "record-struct", "nested-in-class", "none", typeof(O167.V167), typeof(string), null, null, []), - new(168, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=ulong;text.culture=ar-SA;text.entry=TryFormat-short-span", "record-struct", "nested-in-class", "none", typeof(O168.V168), typeof(ulong), null, null, [("shape.inheritance", "none")]), - new(169, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=bool;text.culture=de-DE;text.entry=ISpanParsable", "record-struct", "nested-in-struct", "explicit-interface-member", typeof(O169.V169), typeof(bool), null, null, []), - new(170, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=own-record-class;text.culture=invariant;text.entry=ToString-format", "validated-struct", "nested-two-levels", "none", typeof(O170.P170.V170), typeof(global::Probes.Shapes.PRec), null, null, []), - new(171, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=byte;text.culture=globalization-invariant;text.entry=ISpanParsable", "validated-class", "nested-in-class", "none", typeof(O171.V171), typeof(byte), null, null, []), - new(172, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=TimeOnly;text.culture=ar-SA;text.entry=Parse", "sealed-record-class", "nested-two-levels", "base-depth-2", typeof(O172.P172.V172), typeof(global::System.TimeOnly), null, null, []), - new(173, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=TimeOnly;text.culture=tr-TR;text.entry=TryFormat-short-span", "validated-class", "top-level", "base-depth-3", typeof(V173), typeof(global::System.TimeOnly), null, null, []), - new(174, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=Uri;text.culture=invariant;text.entry=ISpanParsable", "validated-class", "nested-in-class", "base-depth-3", typeof(O174.V174), typeof(global::System.Uri), null, null, []), - new(175, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=double;text.culture=ar-SA;text.entry=ISpanParsable", "validated-struct", "nested-in-struct", "none", typeof(O175.V175), typeof(double), null, null, [("shape.inheritance", "none")]), - new(176, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=string;text.culture=tr-TR;text.entry=ToString-format", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O176.V176), typeof(string), null, null, []), - new(177, "parse-shape=ref-text;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateTimeOffset;text.culture=globalization-invariant;text.entry=TryFrom", "validated-class", "nested-in-class", "base-depth-3", typeof(O177.V177), typeof(global::Probes.Build.C11ConstructedByRef), typeof(O177.VC177), typeof(global::Probes.Build.C11ParsesFromIn), []), - new(178, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=Guid;text.culture=tr-TR;text.entry=ToString-format", "validated-struct", "nested-in-struct", "explicit-interface-member", typeof(O178.V178), typeof(global::System.Guid), null, null, []), - new(179, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeOnly;text.culture=globalization-invariant;text.entry=TryFrom", "validated-struct", "nested-in-class", "none", typeof(O179.V179), typeof(global::System.TimeOnly), null, null, []), - new(180, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=enum;text.culture=globalization-invariant;text.entry=ISpanParsable", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O180.P180.V180), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(181, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=TimeSpan;text.culture=tr-TR;text.entry=IParsable", "validated-struct", "top-level", "explicit-interface-member", typeof(V181), typeof(global::System.TimeSpan), null, null, []), - new(182, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=decimal;text.culture=tr-TR;text.entry=TryFormat-short-span", "validated-struct", "nested-in-class", "none", typeof(O182.V182), typeof(decimal), null, null, [("shape.inheritance", "none")]), - new(183, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=flags-enum;text.culture=invariant;text.entry=ISpanParsable", "validated-class", "nested-in-struct", "base-depth-3", typeof(O183.V183), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(184, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=DateTime;text.culture=globalization-invariant;text.entry=type-converter", "validated-class", "top-level", "base-depth-1", typeof(V184), typeof(global::System.DateTime), null, null, []), - new(185, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=bool;text.culture=ar-SA;text.entry=IParsable", "record-struct", "nested-two-levels", "none", typeof(O185.P185.V185), typeof(bool), null, null, [("shape.inheritance", "none")]), - new(186, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=long;text.culture=globalization-invariant;text.entry=ToString-format", "sealed-record-class", "top-level", "base-depth-3", typeof(V186), typeof(long), null, null, []), - new(187, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=in-generic-type;shape.wrapped=DateOnly;text.culture=invariant;text.entry=TryFrom", "validated-class", "nested-in-class", "base-depth-1", typeof(O187.V187), typeof(global::System.DateOnly), null, null, [("shape.site", "nested-in-class")]), - new(188, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=int;text.culture=invariant;text.entry=Parse", "record-struct", "nested-two-levels", "explicit-interface-member", typeof(O188.P188.V188), typeof(int), null, null, []), - new(189, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=NodaTime.Instant;text.culture=invariant;text.entry=ISpanParsable", "validated-class", "nested-two-levels", "explicit-interface-member", typeof(O189.P189.V189), typeof(global::NodaTime.Instant), null, null, []), - new(190, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Guid;text.culture=de-DE;text.entry=TryFrom", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O190.V190), typeof(global::System.Guid), null, null, []), - new(191, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=string;text.culture=globalization-invariant;text.entry=TryParse", "sealed-record-class", "nested-two-levels", "explicit-interface-member", typeof(O191.P191.V191), typeof(string), null, null, []), - new(192, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=ulong;text.culture=globalization-invariant;text.entry=type-converter", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V192), typeof(ulong), null, null, []), - new(193, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=DateOnly;text.culture=globalization-invariant;text.entry=TryParse", "sealed-record-class", "top-level", "base-depth-2", typeof(V193), typeof(global::System.DateOnly), null, null, []), - new(194, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=byte;text.culture=de-DE;text.entry=TryFrom", "validated-class", "nested-in-class", "base-depth-2", typeof(O194.V194), typeof(byte), null, null, []), - new(195, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=flags-enum;text.culture=globalization-invariant;text.entry=Parse", "sealed-record-class", "top-level", "explicit-interface-member", typeof(V195), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(196, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=double;text.culture=ar-SA;text.entry=type-converter", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V196), typeof(double), null, null, []), - new(197, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=DateTime;text.culture=invariant;text.entry=TryFrom", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O197.V197), typeof(global::System.DateTime), null, null, []), - new(198, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=byte;text.culture=invariant;text.entry=type-converter", "validated-struct", "nested-in-struct", "none", typeof(O198.V198), typeof(byte), null, null, [("shape.inheritance", "none")]), - new(199, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=char;text.culture=invariant;text.entry=IParsable", "validated-struct", "nested-two-levels", "explicit-interface-member", typeof(O199.P199.V199), typeof(char), null, null, []), - new(200, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=enum;text.culture=ar-SA;text.entry=TryFormat-short-span", "sealed-record-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O200.V200), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(201, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Guid;text.culture=globalization-invariant;text.entry=ISpanParsable", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O201.V201), typeof(global::System.Guid), null, null, []), - new(202, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTimeOffset;text.culture=de-DE;text.entry=IParsable", "sealed-record-class", "nested-in-struct", "base-depth-2", typeof(O202.V202), typeof(global::System.DateTimeOffset), null, null, []), - new(203, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=char;text.culture=invariant;text.entry=TryParse", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O203.P203.V203), typeof(char), null, null, []), - new(204, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=TimeOnly;text.culture=invariant;text.entry=ISpanParsable", "validated-class", "nested-in-struct", "base-depth-1", typeof(O204.V204), typeof(global::System.TimeOnly), null, null, []), - new(205, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=string;text.culture=tr-TR;text.entry=ISpanParsable", "sealed-record-class", "nested-in-struct", "base-depth-1", typeof(O205.V205), typeof(string), null, null, []), - new(206, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Uri;text.culture=tr-TR;text.entry=TryFrom", "validated-class", "nested-two-levels", "base-depth-1", typeof(O206.P206.V206), typeof(global::System.Uri), null, null, []), - new(207, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=DateTimeOffset;text.culture=ar-SA;text.entry=ISpanParsable", "sealed-record-class", "top-level", "base-depth-1", typeof(V207), typeof(global::System.DateTimeOffset), null, null, []), - new(208, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=long;text.culture=ar-SA;text.entry=Parse", "validated-class", "top-level", "base-depth-2", typeof(V208), typeof(long), null, null, []), - new(209, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=ulong;text.culture=de-DE;text.entry=ISpanParsable", "validated-class", "nested-two-levels", "explicit-interface-member", typeof(O209.P209.V209), typeof(ulong), null, null, []), - new(210, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=bool;text.culture=invariant;text.entry=ToString-format", "validated-class", "nested-in-class", "base-depth-1", typeof(O210.V210), typeof(bool), null, null, []), - new(211, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=top-level;shape.wrapped=TimeSpan;text.culture=tr-TR;text.entry=Parse", "validated-class", "top-level", "base-explicit-IEquatable", typeof(V211), typeof(global::System.TimeSpan), null, null, []), - new(212, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=int;text.culture=globalization-invariant;text.entry=TryFrom", "validated-class", "nested-in-class", "base-depth-3", typeof(O212.V212), typeof(int), null, null, []), - new(213, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=in-generic-type;shape.wrapped=int;text.culture=invariant;text.entry=ToString-format", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O213.V213), typeof(int), null, null, [("shape.site", "nested-in-class")]), - new(214, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=top-level;shape.wrapped=decimal;text.culture=tr-TR;text.entry=IParsable", "validated-class", "top-level", "base-depth-1", typeof(V214), typeof(decimal), null, null, []), - new(215, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=byte;text.culture=de-DE;text.entry=TryFormat-short-span", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O215.P215.V215), typeof(byte), null, null, []), - new(216, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=own-record-class;text.culture=ar-SA;text.entry=TryParse", "validated-class", "nested-two-levels", "base-depth-1", typeof(O216.P216.V216), typeof(global::Probes.Shapes.PRec), null, null, []), - new(217, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=int;text.culture=invariant;text.entry=ISpanParsable", "validated-struct", "nested-in-struct", "none", typeof(O217.V217), typeof(int), null, null, []), - new(218, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=in-generic-type;shape.wrapped=string;text.culture=globalization-invariant;text.entry=type-converter", "sealed-record-class", "nested-in-class", "base-explicit-IEquatable", typeof(O218.V218), typeof(string), null, null, [("shape.site", "nested-in-class")]), - new(219, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=Guid;text.culture=invariant;text.entry=Parse", "validated-class", "nested-two-levels", "base-depth-2", typeof(O219.P219.V219), typeof(global::System.Guid), null, null, []), - new(220, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-two-levels;shape.wrapped=flags-enum;text.culture=globalization-invariant;text.entry=type-converter", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O220.P220.V220), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(221, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=byte;text.culture=invariant;text.entry=Parse", "sealed-record-class", "nested-in-struct", "none", typeof(O221.V221), typeof(byte), null, null, []), - new(222, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=DateTime;text.culture=tr-TR;text.entry=Parse", "sealed-record-class", "nested-in-struct", "base-depth-1", typeof(O222.V222), typeof(global::System.DateTime), null, null, []), - new(223, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=none;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=own-record-class;text.culture=tr-TR;text.entry=TryFrom", "sealed-record-class", "top-level", "none", typeof(V223), typeof(global::Probes.Shapes.PRec), null, null, []), - new(224, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-struct;shape.wrapped=NodaTime.Instant;text.culture=tr-TR;text.entry=type-converter", "validated-class", "nested-in-struct", "base-depth-1", typeof(O224.V224), typeof(global::NodaTime.Instant), null, null, []), - new(225, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-2;shape.kind=record-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateOnly;text.culture=de-DE;text.entry=type-converter", "record-struct", "nested-two-levels", "none", typeof(O225.P225.V225), typeof(global::System.DateOnly), null, null, [("shape.inheritance", "none")]), - new(226, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-two-levels;shape.wrapped=DateTimeOffset;text.culture=invariant;text.entry=type-converter", "validated-struct", "nested-two-levels", "none", typeof(O226.P226.V226), typeof(global::System.DateTimeOffset), null, null, [("shape.inheritance", "none")]), - new(227, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeOnly;text.culture=ar-SA;text.entry=IParsable", "sealed-record-class", "nested-in-class", "base-depth-3", typeof(O227.V227), typeof(global::System.TimeOnly), null, null, []), - new(228, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-struct;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-class;shape.wrapped=TimeSpan;text.culture=globalization-invariant;text.entry=TryFrom", "validated-struct", "nested-in-class", "none", typeof(O228.V228), typeof(global::System.TimeSpan), null, null, [("shape.inheritance", "none")]), - new(229, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=DateTime;text.culture=tr-TR;text.entry=ToString-format", "validated-class", "nested-two-levels", "base-explicit-IEquatable", typeof(O229.P229.V229), typeof(global::System.DateTime), null, null, []), - new(230, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-explicit-IEquatable;shape.kind=validated-class;shape.refused-kind=generic-wrapped (CMTK1005);shape.site=nested-in-struct;shape.wrapped=double;text.culture=globalization-invariant;text.entry=TryFormat-short-span", "validated-class", "nested-in-struct", "base-explicit-IEquatable", typeof(O230.V230), typeof(double), null, null, []), - new(231, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-struct;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-class;shape.wrapped=Uri;text.culture=ar-SA;text.entry=ToString-format", "validated-struct", "nested-in-class", "explicit-interface-member", typeof(O231.V231), typeof(global::System.Uri), null, null, []), - new(232, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=over-value-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=double;text.culture=ar-SA;text.entry=Parse", "record-struct", "nested-in-struct", "explicit-interface-member", typeof(O232.V232), typeof(double), null, null, []), - new(233, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-two-levels;shape.wrapped=DateOnly;text.culture=tr-TR;text.entry=TryFormat-short-span", "record-struct", "nested-two-levels", "none", typeof(O233.P233.V233), typeof(global::System.DateOnly), null, null, [("shape.inheritance", "none")]), - new(234, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=record-struct;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=enum;text.culture=invariant;text.entry=TryFrom", "record-struct", "top-level", "none", typeof(V234), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(235, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=top-level;shape.wrapped=DateTimeOffset;text.culture=globalization-invariant;text.entry=TryFrom", "validated-class", "top-level", "base-depth-3", typeof(V235), typeof(global::System.DateTimeOffset), null, null, []), - new(236, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=bool;text.culture=de-DE;text.entry=Parse", "validated-class", "top-level", "base-depth-3", typeof(V236), typeof(bool), null, null, []), - new(237, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-2;shape.kind=sealed-record-class;shape.refused-kind=unsealed-record-class (CMTK1006);shape.site=nested-in-class;shape.wrapped=decimal;text.culture=tr-TR;text.entry=TryFormat-short-span", "sealed-record-class", "nested-in-class", "base-depth-2", typeof(O237.V237), typeof(decimal), null, null, []), - new(238, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=ulong;text.culture=de-DE;text.entry=TryFormat-short-span", "sealed-record-class", "nested-two-levels", "base-depth-1", typeof(O238.P238.V238), typeof(ulong), null, null, []), - new(239, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=double;text.culture=de-DE;text.entry=IParsable", "sealed-record-class", "top-level", "base-depth-1", typeof(V239), typeof(double), null, null, []), - new(240, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-1;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=top-level;shape.wrapped=byte;text.culture=ar-SA;text.entry=TryFrom", "sealed-record-class", "top-level", "base-depth-1", typeof(V240), typeof(byte), null, null, []), - new(241, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=validated-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-two-levels;shape.wrapped=enum;text.culture=de-DE;text.entry=IParsable", "validated-class", "nested-two-levels", "explicit-interface-member", typeof(O241.P241.V241), typeof(global::Probes.Shapes.PEnum), null, null, []), - new(242, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=sealed-record-class;shape.refused-kind=abstract (CMTK1005);shape.site=nested-in-struct;shape.wrapped=flags-enum;text.culture=ar-SA;text.entry=TryFrom", "sealed-record-class", "nested-in-struct", "base-depth-3", typeof(O242.V242), typeof(global::Probes.Shapes.PFlags), null, null, []), - new(243, "parse-shape=ordinary;process.converter-lookup=wrapped-type-converter-looked-up-first;shape.inheritance=base-depth-3;shape.kind=record-struct;shape.refused-kind=closed-set-named-as-generated-member (CMTK1021);shape.site=top-level;shape.wrapped=Uri;text.culture=ar-SA;text.entry=IParsable", "record-struct", "top-level", "none", typeof(V243), typeof(global::System.Uri), null, null, [("shape.inheritance", "none")]), - new(244, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=none;shape.kind=validated-struct;shape.refused-kind=equality-operator (CMTK1011);shape.site=nested-two-levels;shape.wrapped=NodaTime.Instant;text.culture=ar-SA;text.entry=TryFormat-short-span", "validated-struct", "nested-two-levels", "none", typeof(O244.P244.V244), typeof(global::NodaTime.Instant), null, null, []), - new(245, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=explicit-interface-member;shape.kind=record-struct;shape.refused-kind=over-object (CMTK1005);shape.site=nested-in-struct;shape.wrapped=Uri;text.culture=invariant;text.entry=TryFormat-short-span", "record-struct", "nested-in-struct", "explicit-interface-member", typeof(O245.V245), typeof(global::System.Uri), null, null, []), - new(246, "parse-shape=ordinary;process.converter-lookup=none;shape.inheritance=base-depth-3;shape.kind=validated-class;shape.refused-kind=over-System.Enum (CMTK1005);shape.site=nested-two-levels;shape.wrapped=Uri;text.culture=ar-SA;text.entry=TryParse", "validated-class", "nested-two-levels", "base-depth-3", typeof(O246.P246.V246), typeof(global::System.Uri), null, null, []), - ]; -} diff --git a/tools/probe/corpus/harness/Cmp.cs b/tools/probe/corpus/harness/Cmp.cs deleted file mode 100644 index a435030b..00000000 --- a/tools/probe/corpus/harness/Cmp.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Composed-fault errors for C03/C05 (harness). e: 1 first set, 2 last set, 3 last set with detail, 4/5/6 first set with a rule (enum / closed set / nested enum). -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ClosedSets; -using CodoMetis.TypeKit.AspNetCore; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -namespace Probes; - -public sealed partial class KFault : IFaultSet -{ - public static readonly KFault Clash = new(FaultKind.Conflict, null); - public static readonly KFault Lost = new(FaultKind.NotFound, null); - private KFault(FaultKind kind, string? description) { Kind = kind; Description = description; } - public FaultKind Kind { get; } - public string? Description { get; } -} - -public static class Cmp -{ - public const string Detail = "It is at version 3, not 2."; - static Fault Rule(int e) => e switch - { - 4 => Fault.Of(HFault.Clash).WithRule(PRule.A), - 5 => Fault.Of(HFault.Clash).WithRule(RuleSet.X), - 6 => Fault.Of(HFault.Clash).WithRule(Holder.NestedRule.N), - _ => throw new ArgumentOutOfRangeException(nameof(e)), - }; - public static Result> Two(int e) => e switch - { - 1 => Fault.Of(HFault.Missing), - 2 => Fault.Of(GFault.Raced), - 3 => Fault.Of(Fault.Of(GFault.Old, Detail)), - >= 4 and <= 6 => Fault.Of(Rule(e)), - _ => Result>.Success(), - }; - public static Result> TwoK(int e) => e switch - { - 1 => Fault.Of(HFault.Missing), - 2 => Fault.Of(KFault.Clash), - 3 => Fault.Of(Fault.Of(KFault.Lost, Detail)), - >= 4 and <= 6 => Fault.Of(Rule(e)), - _ => Result>.Success(), - }; - public static Result> Three(int e) => e switch - { - 1 => Fault.Of(HFault.Missing), - 2 => Fault.Of(SFault.First), - 3 => Fault.Of(Fault.Of(SFault.Second, Detail)), - >= 4 and <= 6 => Fault.Of(Rule(e)), - _ => Result>.Success(), - }; - public static Result> ThreeK(int e) => e switch - { - 1 => Fault.Of(HFault.Missing), - 2 => Fault.Of(SFault.First), - 3 => Fault.Of(Fault.Of(SFault.Second, Detail)), - >= 4 and <= 6 => Fault.Of(Rule(e)), - _ => Result>.Success(), - }; - - // ---- expectations - /// (fault type name, member name, status) of the error e answers, by arity and variant; variant group moves HFault.Clash to 422. - public static (string Type, string Member, int Status) Expect(int arity, string variant, int e) - { - var k = variant == "dup"; - int clash = variant == "group" ? 422 : 409; - return e switch - { - 1 => ("HFault", "Missing", 404), - 2 => arity == 2 ? (k ? ("KFault", "Clash", 409) : ("GFault", "Raced", 409)) : ("SFault", "First", 409), - 3 => arity == 2 ? (k ? ("KFault", "Lost", 404) : ("GFault", "Old", 412)) : ("SFault", "Second", 410), - _ => ("HFault", "Clash", clash), - }; - } - /// The statuses >= 400 the operation lists: those of every member of every answered type, minus the left-out ones, plus the declared 429. - public static SortedSet DocStatuses(int arity, string variant) - { - var s = new SortedSet(); - var h = new (string, int)[] { ("Missing", 404), ("Clash", variant == "group" ? 422 : 409), ("Bad", 422), ("Denied", 403), ("Down", 503), ("Stale", 412), ("Garbled", 400) }; - foreach (var (m, st) in h) if (!(variant == "wo" && m == "Bad")) s.Add(st); - if (variant == "dup") { s.Add(409); s.Add(404); } else { s.Add(404); s.Add(409); s.Add(412); } - if (arity == 3) { s.Add(409); s.Add(410); } - if (variant == "declared") s.Add(429); - return s; - } - - static readonly Dictionary Kinds = new(StringComparer.Ordinal) - { - ["HFault.Missing"] = "NotFound", ["HFault.Clash"] = "Conflict", ["HFault.Bad"] = "Invalid", ["HFault.Denied"] = "Forbidden", - ["HFault.Down"] = "Unavailable", ["HFault.Stale"] = "PreconditionFailed", ["HFault.Garbled"] = "Malformed", - ["GFault.Gone"] = "NotFound", ["GFault.Raced"] = "Conflict", ["GFault.Old"] = "PreconditionFailed", - ["KFault.Clash"] = "Conflict", ["KFault.Lost"] = "NotFound", - }; - /// The kind of a fault-set member, or null for a member of the enum SFault, which has none. - public static string? KindOf(string type, string member) => Kinds.GetValueOrDefault(type + "." + member); - /// The problem types the operation's response for names: every member answered with it, of every set. - public static HashSet TypesAt(int arity, string variant, int status) - { - var members = new List<(string Type, string Member, int Status)> - { - ("HFault", "Missing", 404), ("HFault", "Clash", variant == "group" ? 422 : 409), ("HFault", "Denied", 403), ("HFault", "Down", 503), - ("HFault", "Stale", 412), ("HFault", "Garbled", 400), - }; - if (variant != "wo") members.Add(("HFault", "Bad", 422)); - if (variant == "dup") members.AddRange([("KFault", "Clash", 409), ("KFault", "Lost", 404)]); - else members.AddRange([("GFault", "Gone", 404), ("GFault", "Raced", 409), ("GFault", "Old", 412)]); - // arity 3 adds SFault, an enum mapped to 409 and 410 with no type - return [.. members.Where(m => m.Status == status).Select(m => ComposedClaims.TypeOf(m.Type, KindOf(m.Type, m.Member)!))]; - } - - public static RouteHandlerBuilder Decorate(RouteHandlerBuilder rb, string variant) => variant switch - { - "wo" => rb.WithoutFaults(HFault.Bad), - "group" => rb.WithFaultStatus(HFault.Clash, 422), - "declared" => rb.ProducesProblem(429), - _ => rb, - }; - public static void MapMinimal(IEndpointRouteBuilder b) - { - foreach (var v in new[] { "plain", "wo", "group", "declared", "dup" }) - { - var k = v == "dup"; - Decorate(k ? b.MapGet($"/m/2/{v}", (int e) => TwoK(e).ToHttpResult()) : b.MapGet($"/m/2/{v}", (int e) => Two(e).ToHttpResult()), v); - Decorate(k ? b.MapGet($"/m/3/{v}", (int e) => ThreeK(e).ToHttpResult()) : b.MapGet($"/m/3/{v}", (int e) => Three(e).ToHttpResult()), v); - } - } -} diff --git a/tools/probe/corpus/harness/ComposedProbes.cs b/tools/probe/corpus/harness/ComposedProbes.cs deleted file mode 100644 index 56532242..00000000 --- a/tools/probe/corpus/harness/ComposedProbes.cs +++ /dev/null @@ -1,228 +0,0 @@ -// Claims C03-composed-faults (AspNetCore README#faults-of-several-types) and C05-with-rule (README#the-rule-that-refused). -// C03: a Fault is "answered as its own set maps it" (status, `fault`, problem type, detail, rule intact); "its operation lists the -// statuses of both sets, in ascending order, with the problem types of both where they share a status"; "the host doesn't start while either -// set is unmapped". The host maps every fault set with a problem type of its set and kind (TypeOf), so two sets sharing a status name two types. -// C05: WithRule(member) is written as `rule`, "qualified with its type's name", a nested type after its nesting chain "whatever QualifiedFaultNames -// says"; "The status, the mapping and the document stay the error's"; a value no member names "throws where it's given"; the document describes `rule`. -// Oracle: claim (README text) + differential wire/document. Expected: see Cmp.Expect / Cmp.DocStatuses. Each obligation is a check of its -// own (ComposedChecks.C03, C05), every check on one host. -using System.Text.Json.Nodes; -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.AspNetCore; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Probes.Faults; -using Probes.Shapes; -namespace Probes; - -public static class ComposedClaims -{ - /// The application's own string converter (json.Converters=own-for-wrapped) wraps every string it writes: take it off again. - static string? Un(Row r, string? s) => r.Is("json.Converters", "own-for-wrapped") && s is not null && s.StartsWith("own:") ? s[4..].Trim('"') : s; - static string Cut(string? s) => s is null ? "(null)" : s.Length > 200 ? s[..200] + "..." : s; - public static string Variant(Row r) => r["http.response"] switch - { - "endpoint-without-faults" => "wo", "group-with-fault-status" => "group", "declared-produces-problem" => "declared", "two-faults-same-name" => "dup", _ => "plain", - }; - static HostCfg Cfg(Row r) => new() - { - FaultControllers = true, Controllers = Hx.Plain(r) ? [typeof(RulePlainController)] : [typeof(RuleApiController)], - Minimal = Cmp.MapMinimal, Qualified = r.Is("qualified", "QualifiedFaultNames"), - Mapping = "own-per-set-type", - Services = s => s.AddFaultResponses(f => FaultResponse.For(f.Kind).WithType(new Uri(TypeOf(f.GetType().Name, f.Kind.ToString())))), - }; - - /// The problem type the host maps a fault-set member to: its set's and its kind's, so two sets sharing a status name two types. - public static string TypeOf(string set, string kind) => $"https://p.example/{set}/{kind}"; - - /// The problem's rule, an aspect of its own beside 's. - public const string Rule = "rule"; - - /// - /// The wire and the document of one endpoint family under the row, one check (Row.Check) per obligation names an - /// aspect for ('s and ), against ; every check runs on the one host, with - /// the answers fetched once. e: the error code of Cmp. - /// - public static async Task WireAndDoc(Row r, Entry en, int arity, int e, string rule, Func of, Baseline against) - { - var variant = Variant(r); - var obligations = Aspect.Answer.Append(Rule).Concat(Aspect.Doc).SelectMany(of).Distinct().ToList(); - WebApplication? app = null; Exception? down = null; - try { app = await Hx.Start(r, en, Cfg(r)); } - catch (Exception ex) when (ex is not Sides.InputsNotEquivalent) { down = ex; } - await using var _ = app; - string? failed = null; - if (down is not null) - { - foreach (var o in obligations) { var f = r.Check(o, against, _ => "host did not start: " + down.GetType().Name + ": " + Cut(down.Message)); failed ??= f; } - return failed; - } - var qualified = r.Is("qualified", "QualifiedFaultNames"); - var sides = new List(); - if (Hx.HasMinimal(r)) sides.Add(Hx.M(r, $"/m/{arity}/{variant}")); - if (Hx.HasMvc(r)) sides.Add(Hx.C(r, $"/c/{arity}/{variant}")); - JsonNode? doc = null; Exception? docFailed = null; - try { doc = await Hx.Doc(app!); } - catch (Exception ex) { docFailed = ex; } - var wires = new Dictionary(); - foreach (var path in sides) wires[path] = await Hx.Get(app!, $"{path}?e={e}"); - var (type, member, status) = Cmp.Expect(arity, variant, e); - - foreach (var o in obligations) - { - var f = await r.Check(o, against, async c => - { - bool want(string aspect) => of(aspect).Contains(o); - if (Aspect.Answer.Any(want) || want(Rule)) - foreach (var path in sides) - { - var w = wires[path]; - if (w.Thrown is not null) return $"{path} e={e}: request threw {w.Thrown}"; - if (want(Aspect.Status) && (int)w.Status != status) return $"{path} e={e}: status {(int)w.Status}, expected {status}: {Cut(w.Body)}"; - JsonNode? body; try { body = JsonNode.Parse(w.Body); } catch { return $"{path} e={e}: body is not JSON: {Cut(w.Body)}"; } - var fault = Un(r, body?["fault"]?.GetValue()); - var wantFault = qualified ? $"{type}.{member}" : member; - if (want(Aspect.Fault) && fault != wantFault) return $"{path} e={e}: fault {fault}, expected {wantFault}"; - if (want(Aspect.Detail) && e == 3 && Un(r, body?["detail"]?.GetValue()) != Cmp.Detail) return $"{path} e={e}: detail {body?["detail"]}, expected the occurrence's"; - var gotRule = Un(r, body?["rule"]?.GetValue()); - if (want(Rule) && gotRule != (rule == "" ? null : rule)) return $"{path} e={e}: rule {gotRule ?? "(none)"}, expected {(rule == "" ? "(none)" : rule)}"; - // an enum (SFault) is mapped to a status alone, and ASP.NET writes its own default type there - if (want(Aspect.Type) && Cmp.KindOf(type, member) is { } kind && Un(r, body?["type"]?.GetValue()) is var gotType && gotType != TypeOf(type, kind)) - return $"{path} e={e}: type {gotType ?? "(none)"}, expected {TypeOf(type, kind)}"; - if (want(Aspect.Status) && int.Parse(body?["status"]?.ToString() is { } st ? Un(r, st)!.Trim('"') : "0") != status) return $"{path} e={e}: problem status field {body?["status"]}"; - } - if (!Aspect.Doc.Any(want)) return null; - // the document: one ASP.NET alone refuses the same way has nothing to check (noted there) - if (docFailed is not null) - return await Hx.DocRefusedByAspNetAlone(r, en, Cfg(r), docFailed, (Aspect.Answer.Any(want) || want(Rule)) && sides.Count > 0) is { } alone - ? alone + " @ " + string.Join(" < ", (docFailed.StackTrace ?? "").Split('\n').Take(4).Select(x => x.Trim().Split('(')[0])) - : null; - foreach (var path in sides) - { - var ops = doc!["paths"]?[path]?["get"]; - if (ops is null && !Hx.InDocument(r) && path.Contains("/c/")) { c.Note(NoteKeys.DocControllerNotInApiExplorer); continue; } - if (ops is null) return $"document has no GET {path}"; - var keys = ops["responses"]!.AsObject().Select(kv => kv.Key).Where(k => int.TryParse(k, out var n) && n >= 400).Select(int.Parse).ToList(); - var listed = Cmp.DocStatuses(arity, variant); - // A status the endpoint declares itself (the 429) takes its place among the sets' statuses (fixed in 8d1ebd8). - if ((want(Aspect.DocListed) || want(Aspect.DocOrder)) && !keys.SequenceEqual(listed)) return $"{path}: document lists {string.Join(",", keys)}, expected {string.Join(",", listed)} (ascending)"; - foreach (var k in keys) - { - if (variant == "declared" && k == 429) continue; // a declared problem is ASP.NET's, not an answered fault - var txt = Hx.Deep(doc!, ops["responses"]![k.ToString()])?.ToJsonString() ?? ""; - if (want(Aspect.DocDescribes) && !txt.Contains("\"fault\"")) return $"{path} {k}: response schema does not describe fault: {Cut(txt)}"; - if (want(Aspect.DocDescribes) && !txt.Contains("\"rule\"")) return $"{path} {k}: response schema does not describe rule: {Cut(txt)}"; - var desc = ops["responses"]![k.ToString()]?["description"]?.GetValue() ?? ""; - const string Lead = "Problem types: "; - var at = desc.IndexOf(Lead, StringComparison.Ordinal); - var types = at < 0 ? [] : desc[(at + Lead.Length)..].Split(", ").ToHashSet(); - var wantTypes = Cmp.TypesAt(arity, variant, k); - if (want(Aspect.DocTypes) && !types.SetEquals(wantTypes)) - return $"{path} {k}: description \"{desc}\" names problem types {{{string.Join(", ", types)}}}, expected {{{string.Join(", ", wantTypes)}}}"; - } - } - return null; - }); - failed ??= f; - } - return failed; - } - - /// "The host doesn't start while either set is unmapped." - public static async Task UnmappedDoesNotStart(Row r, Entry en, int arity, int e) - { - var cfg = Cfg(r); cfg.MapBlanketMapping = false; - var unmapped = e == 1 ? "HFault" : arity == 2 ? "GFault" : "GFault"; - var variant = Variant(r); - if (variant == "dup") unmapped = e == 1 ? "HFault" : "KFault"; - cfg.Services = s => - { - if (unmapped != "HFault") s.AddFaultResponses(); - if (unmapped != "GFault" && variant != "dup") s.AddFaultResponses(); - if (unmapped != "KFault" && variant == "dup") s.AddFaultResponses(); - if (arity == 3) s.AddFaultResponses(f => f switch { SFault.First => 409, _ => 410 }); - }; - WebApplication? app = null; - try { app = await Hx.Start(r, en, cfg); } - catch (Exception ex) when (ex is not Sides.InputsNotEquivalent) - { - return ex.ToString().Contains(unmapped) ? null : $"host refused to start but not naming {unmapped}: {ex.GetType().Name}: {Cut(ex.Message)}"; - } - await using var _ = app; - return $"host started with {unmapped} unmapped (arity {arity}, variant {variant}); answered only at request time?"; - } -} - -public static class ComposedChecks -{ - static void Process(Row r, Entry en) { if (r.Is("process.converter-lookup", "wrapped-type-converter-looked-up-first")) _ = System.ComponentModel.TypeDescriptor.GetConverter(Make.Held(en.Plain)); } - /// - /// C03, a check per obligation: each-error-own-set (status, fault, problem type, and the rule where the error names none), - /// detail-and-rule-intact (error with-detail or with-rule: the detail and the rule), statuses-ascending (the statuses each operation - /// lists, in order, and their problem schemas), shared-status-types (the problem types each status's description names), and - /// unmapped-set-stops-start (a host with one set unmapped, against the refusal) in every row. - /// - public static async Task C03(Row r) - { - var en = Registry.Of(r); Process(r, en); - var arity = int.Parse(r["arity"]); - var e = r["error"] switch { "first-set" => 1, "last-set" => 2, "with-detail" => 3, _ => 4 }; - var intact = r["error"] is "with-detail" or "with-rule"; - string[] Of(string aspect) => aspect switch - { - Aspect.Detail or ComposedClaims.Rule when intact => ["detail-and-rule-intact"], - Aspect.DocListed or Aspect.DocOrder or Aspect.DocDescribes => ["statuses-ascending"], - Aspect.DocTypes => ["shared-status-types"], - _ => ["each-error-own-set"], - }; - var answered = await ComposedClaims.WireAndDoc(r, en, arity, e, e == 4 ? "PRule.A" : "", Of, - Baseline.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#faults-of-several-types")); - var unmapped = await r.Check("unmapped-set-stops-start", Baseline.Refusal, _ => ComposedClaims.UnmappedDoesNotStart(r, en, arity, e)); - return answered ?? unmapped; - } - /// - /// C05, a check per obligation: unnamed-value-throws (ruletype flags-combination or undefined-cast, against the refusal); - /// rule-qualified (enum, closed-set) or nested-chain (nested-enum), and no-namespace, for the rule on the wire; stays-the-errors for - /// the status, fault, problem type and the document, and in the rows of an unnamed value for the error answered without a rule. - /// - public static async Task C05(Row r) - { - var en = Registry.Of(r); Process(r, en); - var ruletype = r["ruletype"]; - // a value no member names throws where it is given (never a rule on the wire) - var thrown = ruletype switch - { - "flags-combination" => r.Check("unnamed-value-throws", Baseline.Refusal, c => - { - try { _ = Fault.Of(HFault.Clash).WithRule((FRule)3); return "WithRule(flags combination) did not throw"; } catch (ArgumentException) { return null; } - }), - "undefined-cast" => r.Check("unnamed-value-throws", Baseline.Refusal, c => - { - try { _ = Fault.Of(HFault.Clash).WithRule((PRule)9); return "WithRule(undefined cast) did not throw"; } catch (ArgumentException) { return null; } - }), - _ => null, - }; - var (e, rule) = ruletype switch { "enum" => (4, "PRule.A"), "closed-set" => (5, "RuleSet.X"), "nested-enum" => (6, "Holder.NestedRule.N"), _ => (1, "") }; - var named = ruletype switch { "enum" or "closed-set" => "rule-qualified", "nested-enum" => "nested-chain", _ => null }; - string[] Of(string aspect) => aspect == ComposedClaims.Rule && named is not null ? [named, "no-namespace"] : ["stays-the-errors"]; - var answered = await ComposedClaims.WireAndDoc(r, en, 3, e, rule, Of, Baseline.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#the-rule-that-refused")); - return thrown ?? answered; - } -} -public static class ComposedShrinkInit -{ - [System.Runtime.CompilerServices.ModuleInitializer] - public static void Init() { ShrinkChecks.All["C03"] = ComposedChecks.C03; ShrinkChecks.All["C05"] = ComposedChecks.C05; } -} -public sealed class C03ComposedProbe -{ - public static TheoryData Data() => Rows.Data("C03ComposedProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run("C03", idx, ComposedChecks.C03, probe); -} -public sealed class C05RuleProbe -{ - public static TheoryData Data() => Rows.Data("C05RuleProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run("C05", idx, ComposedChecks.C05, probe); -} diff --git a/tools/probe/corpus/harness/Containers.g.cs b/tools/probe/corpus/harness/Containers.g.cs deleted file mode 100644 index d79627ed..00000000 --- a/tools/probe/corpus/harness/Containers.g.cs +++ /dev/null @@ -1,25 +0,0 @@ -// by tools/probe/generators/containers.cs -#nullable disable -#pragma warning disable CS8618, CS1591, CS0649 -using System.Text.Json.Serialization; -namespace Probes.Shapes; -public class Cn_class_P { public M P { get; set; } } -public class Cn_class_F { public M F; } -public class Cn_class_C { public M P { get; } [JsonConstructor] public Cn_class_C(M p) { P = p; } } -public class Cn_class_R { public required M P { get; init; } } -public record class Cn_record_class_P { public M P { get; set; } } -public record class Cn_record_class_F { public M F; } -public record class Cn_record_class_C(M P); -public record class Cn_record_class_R { public required M P { get; init; } } -public struct Cn_struct_P { public M P { get; set; } } -public struct Cn_struct_F { public M F; } -public struct Cn_struct_C { public M P { get; } [JsonConstructor] public Cn_struct_C(M p) { P = p; } } -public struct Cn_struct_R { public required M P { get; init; } } -public record struct Cn_record_struct_P { public M P { get; set; } } -public record struct Cn_record_struct_F { public M F; } -public record struct Cn_record_struct_C { public M P { get; } [JsonConstructor] public Cn_record_struct_C(M p) { P = p; } } -public record struct Cn_record_struct_R { public required M P { get; init; } } -public class Cn_generic_type_P { public M P { get; set; } } -public class Cn_generic_type_F { public M F; } -public class Cn_generic_type_C { public M P { get; } [JsonConstructor] public Cn_generic_type_C(M p) { P = p; } } -public class Cn_generic_type_R { public required M P { get; init; } } diff --git a/tools/probe/corpus/harness/DecimalSpelling.cs b/tools/probe/corpus/harness/DecimalSpelling.cs deleted file mode 100644 index 11a7c617..00000000 --- a/tools/probe/corpus/harness/DecimalSpelling.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Claim C01-decimal-spelling (docs/json.md#decimals-in-one-spelling): DecimalNumberJsonConverter writes the smallest scale as a -// number, DecimalStringJsonConverter as a string; "Register either one once, and it covers every decimal: nullable ones, dictionary -// keys, and every value object over a decimal, since its JSON is the underlying type's." "Both read a number, or a string holding one, -// and keep the scale they read." -// Oracle: claim (the minimal spelling, computed here independently of the product) plus differential (the value object's document is the -// plain decimal's under the same options), with the options' own leaving-out shown by a baseline without the converter in the same row. -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; -using CodoMetis.TypeKit; -using Probes.Shapes; -namespace Probes.Json; - -public static class DecimalSpelling -{ - static readonly CultureInfo Inv = CultureInfo.InvariantCulture; - const char Bs = (char)92; - - /// The input axis as decimal text: max28digits is 7.8 at scale 28, the largest scale a decimal has. - public static string Text(string input) => input == "max28digits" ? "7.8000000000000000000000000000" : input; - - /// The minimal spelling, worked out without the product: invariant digits, trailing fractional zeros dropped, a zero written 0. - public static string Canonical(decimal d) - { - if (d == 0m) return "0"; - var s = d.ToString(Inv); - return s.Contains('.') ? s.TrimEnd('0').TrimEnd('.') : s; - } - - static bool IsDecimal(JTok t, decimal d) => t.Type switch - { - JsonTokenType.Number => decimal.TryParse(t.Raw, NumberStyles.Float, Inv, out var x) && x == d, - JsonTokenType.String or JsonTokenType.PropertyName => t.Text is { Length: > 0 } s && s.Trim() == s && decimal.TryParse(s, NumberStyles.Float, Inv, out var y) && y == d, - _ => false, - }; - - /// The decimals a read value holds, as the serializer writes them by default: with the scale they hold. - static List Held(object? v, Type declared, decimal d) - { - if (v is null) return []; - var json = JsonSerializer.Serialize(v, declared, Jx.Plain); - return Jx.Tokens(json).Where(t => IsDecimal(t, d)).Select(t => decimal.Parse(t.Type == JsonTokenType.Number ? t.Raw : t.Text!, NumberStyles.Float, Inv)).ToList(); - } - static bool Same(decimal a, decimal b) => decimal.GetBits(a).SequenceEqual(decimal.GetBits(b)); - static string Show(List l) => string.Join(",", l.Select(x => x.ToString(Inv))); - - /// What one form of the document read as: the decimal's and the value object's refusals and the decimals each holds. - sealed record Form(string Name, string Json, Exception? Ep, Exception? Ev, List Cp, List Cv, bool BothRefused); - - /// - /// C01's checks, one per obligation, over one write and one read of the row's shape: the converter's spelling of each value - /// (smallest-scale; number-is-a-number or string-is-a-string, by the row's converter) against the docs' minimal spelling worked out - /// here; every decimal of the document, a key's included, and the value object's document against the plain decimal's - /// (covers-every-decimal, the twin); each form of the input read (reads-a-number-or-a-string) with the scale it carries - /// (keeps-the-scale-it-reads). The options' own leaving-out is shown by a baseline without the converter in the same row: a - /// direction it leaves out has nothing to check. Every check runs; returns the first failure. - /// - public static string? Check(Row r) - { - var kind = r["shape.kind"]; - if (kind == "closed-set") { r.Outcome("harness-error", "C01 excludes closed-set: a closed set holds no decimal"); return null; } - var e = Registry.Get(kind, "decimal"); - var text = Text(r["input"]); - var d = decimal.Parse(text, NumberStyles.Float, Inv); - var canon = Canonical(d); - var number = r["converter"] == "number"; - JsonConverter conv = number ? new DecimalNumberJsonConverter() : new DecimalStringJsonConverter(); - var position = r["shape.position"]; - var containing = position == "root" ? "class" : r["shape.containing"]; - var (hp, hv) = Sides.Twins(position, containing, e, d, Make.Vo(e, d)); - var o = JCtx.Apply(r, e, hp.Declared, hv.Declared); - var ob = new JsonSerializerOptions(o); // the baseline: the same options, the serializer's own decimal - foreach (var c in ob.Converters.Where(c => c.CanConvert(typeof(decimal))).ToList()) ob.Converters.Remove(c); - o.Converters.Insert(0, conv); // registered first: an application converter for decimals (own-for-wrapped) comes after it - var ownVo = r.Is("json.Converters", "own-for-value-object"); - var docs = Baseline.Docs("docs/json.md#decimals-in-one-spelling"); - const string Smallest = "smallest-scale", Covers = "covers-every-decimal", Reads = "reads-a-number-or-a-string", Keeps = "keeps-the-scale-it-reads"; - var kindOf = number ? "number-is-a-number" : "string-is-a-string"; - - // Writing: one spelling, the smallest scale, as a number or a string; the value object's document is the decimal's. - var (jp, xp) = Jx.Ser(hp, o); var (jv, xv) = Jx.Ser(hv, o); var (jb, xb) = Jx.Ser(hp, ob); - if (xb is not null && xp is not null && (xv is not null || ownVo) && xp.GetType() == xb.GetType()) - { - // the options refuse the shape for the serializer's own decimal too: nothing is written or read to compare. Where the value - // object is refused alike, at the same stage with the same exception type, the decimal without TypeKit's converter is side (1) - // of the three-sided differential (Sides), and each check is the framework's refusal; otherwise none can tell. - var one = new Sides.Answer("write", null, xb); var three = new Sides.Answer("write", null, xv); - if (Sides.Alike(one, three)) - { - var framework = Sides.Measured(one, "the serializer's own decimal, without TypeKit's converter"); - foreach (var o2 in new[] { Smallest, kindOf, Covers, Reads, Keeps }) r.Check(o2, framework.Baseline, c => Sides.Refuses(c, framework, three)); - return null; - } - var why = "the options refuse the shape for the serializer's own decimal too: " + Jx.Ex(xb); - string? None(Check c) => c.Inconclusive(why); - foreach (var ob2 in new[] { Smallest, kindOf }) r.Check(ob2, docs, None); - r.Check(Covers, Baseline.Twin, None); r.Check(Reads, docs, None); r.Check(Keeps, docs, None); - return null; - } - var tp = xp is null ? Jx.Tokens(jp!).Where(t => IsDecimal(t, d)).ToList() : []; - var tb = xb is null ? Jx.Tokens(jb!).Where(t => IsDecimal(t, d)).ToList() : null; - var writeLeftOut = tb is { Count: 0 } && xp is null && tp.Count == 0; - string? WriteLeftOut(Check c) { c.Note(NoteKeys.JsonMemberLeftOutByOptions, "write: " + Jx.Cut(jb)); return c.Inconclusive("write: the options leave the member out, for the serializer's own decimal too: " + Jx.Cut(jb)); } - var want = number ? JsonTokenType.Number : JsonTokenType.String; - var f1 = r.Check(Smallest, docs, c => - { - if (xp is not null) return $"write: the decimal with {conv.GetType().Name} threw {Jx.Ex(xp)}; without it the serializer wrote {Jx.Cut(jb)}"; - if (tb is { Count: 0 } && tp.Count != 0) return $"write: the options leave the member out without the converter ({Jx.Cut(jb)}) but it wrote {Jx.Cut(jp)}"; - if (writeLeftOut) return WriteLeftOut(c); - if (tp.Count == 0) return $"write: no decimal in {Jx.Cut(jp)}; the serializer alone wrote {Jx.Cut(jb)}"; - foreach (var t in tp.Where(t => t.Type != JsonTokenType.PropertyName)) - if (t.Raw != canon) return $"write: {t.Type} {t.Raw}, expected the smallest scale {canon}, in {Jx.Cut(jp)}"; - c.Note(NoteKeys.Compared, $"write {text} -> {canon}"); - return null; - }); - var f2 = r.Check(kindOf, docs, c => - { - if (xp is not null) return c.Inconclusive("write: the decimal with the converter threw, judged by smallest-scale"); - if (writeLeftOut) return WriteLeftOut(c); - var values = tp.Where(t => t.Type != JsonTokenType.PropertyName).ToList(); - if (values.Count == 0) return c.Inconclusive($"write: no decimal value in {Jx.Cut(jp)}, only keys, which are names"); - foreach (var t in values) - if (t.Type != want) return $"write: {t.Type} {t.Raw}, expected the {want} {canon}, in {Jx.Cut(jp)}"; - c.Note(NoteKeys.Compared, $"write as a {want}"); - return null; - }); - - // Reading: a number, a string holding one, and an escaped string all read, the scale they carry kept, on both sides alike. - var full = Jx.Full(o); - var (jf, xf) = Jx.Ser(hp, full); - if (xf is not null) { r.Outcome("harness-error", "the document with every member written threw " + Jx.Ex(xf)); return f1 ?? f2; } - var at = Jx.Tokens(jf!).Where(t => IsDecimal(t, d)).ToList(); - string? readNothing = null; - var forms = new List
(); - var leftOut = false; - if (at.Count == 0) - { - // Nothing to read either: the options leave the member out of every document (a field without IncludeFields). - var (jfb, _) = Jx.Ser(hp, Jx.Full(ob)); - if (jfb is null || Jx.Tokens(jfb).Any(t => IsDecimal(t, d))) { r.Outcome("harness-error", "no decimal in the document with every member written: " + jf); return f1 ?? f2; } - readNothing = "read: the options leave the member out of every document, for the serializer's own decimal too: " + Jx.Cut(jf); - } - else - { - var key = at.Any(t => t.Type == JsonTokenType.PropertyName); - var texts = new List<(string Name, string Json)>(); - if (!key) texts.Add(("number", Jx.Rewrite(jf!, at, _ => text))); - texts.Add(("string", Jx.Rewrite(jf!, at, _ => "\"" + text + "\""))); - texts.Add(("escaped string", Jx.Rewrite(jf!, at, _ => "\"" + Bs + "u00" + ((int)text[0]).ToString("x2") + text[1..] + "\""))); - // The baseline reads the first form with the serializer's own decimal: it shows whether these options read the member at all. - var (vb, eb) = Jx.De(texts[0].Json, hp.Declared, ob); - leftOut = eb is null && Held(vb, hp.Declared, d).Count == 0; - foreach (var (name, json) in texts) - { - var (vp, ep) = Jx.De(json, hp.Declared, o); - var (vv, ev) = ownVo ? (null, null) : Jx.De(json, hv.Declared, o); - var both = ep is not null && eb is not null && (ownVo || ev is not null) && ep.GetType() == eb.GetType(); - var cp = ep is null ? Held(vp, hp.Declared, d) : []; var cv = ownVo ? cp : ev is null ? Held(vv, hv.Declared, d) : []; - forms.Add(new(name, json, ep, ev, cp, cv, both)); - } - if (leftOut && forms.All(f => f.Ep is null && f.Ev is null && f.Cp.Count == 0 && f.Cv.Count == 0)) - readNothing = "read: the options read no member, for the serializer's own decimal too"; - } - string? ReadLeftOut(Check c) { c.Note(NoteKeys.JsonMemberLeftOutByOptions, "read"); return c.Inconclusive(readNothing!); } - // The forms both sides refuse alike under these options (the serializer's own decimal too) have nothing to compare. - var compared = forms.Where(f => !f.BothRefused).ToList(); - string? AllRefused(Check c) - { - foreach (var f in forms.Where(f => f.BothRefused)) c.Log.AppendLine($"read {f.Name}: both refuse: {Jx.Ex(f.Ep!)}"); - return c.Inconclusive("read: every form is refused for the serializer's own decimal too: " + Jx.Ex(forms[0].Ep!)); - } - var f4 = r.Check(Reads, docs, c => - { - if (readNothing is not null) return ReadLeftOut(c); - foreach (var f in forms) - { - if (f.BothRefused) continue; - if (f.Ep is not null) return $"read {f.Name}: the decimal with {conv.GetType().Name} threw {Jx.Ex(f.Ep)}\n text={Jx.Cut(f.Json)}"; - if (leftOut) { if (f.Cp.Count != 0) return $"read {f.Name}: the options read no member for the serializer's own decimal, yet it read {Show(f.Cp)}"; continue; } - if (f.Cp.Count == 0) return $"read {f.Name}: the decimal read nothing\n text={Jx.Cut(f.Json)}"; - } - if (compared.Count == 0) return AllRefused(c); - c.Note(NoteKeys.Compared, "read " + string.Join(", ", compared.Select(f => f.Name))); - return null; - }); - var f5 = r.Check(Keeps, docs, c => - { - if (readNothing is not null) return ReadLeftOut(c); - if (compared.Count == 0) return AllRefused(c); - var kept = 0; - foreach (var f in compared) - { - if (f.Cp.Count == 0) continue; // read nothing, or refused: reads-a-number-or-a-string judges it - if (f.Cp.Any(x => !Same(x, d))) return $"read {f.Name}: read {Show(f.Cp)}, expected {d.ToString(Inv)} with its scale\n text={Jx.Cut(f.Json)}"; - kept++; - } - if (kept == 0) return c.Inconclusive("read: no form read a decimal to hold its scale to"); - c.Note(NoteKeys.Compared, $"read with the scale of {text}"); - return null; - }); - var f3 = r.Check(Covers, ownVo ? Baseline.RoundTrip : Baseline.Twin, c => - { - if (xv is not null && !ownVo) return $"write: the value object threw {Jx.Ex(xv)} where the decimal wrote {Jx.Cut(jp)}"; - if (xp is not null) return c.Inconclusive("write: the decimal with the converter threw, judged by smallest-scale"); - if (tb is not null && tb.Count != 0 && tp.Count != tb.Count) return $"write: {tp.Count} decimals in {Jx.Cut(jp)}, {tb.Count} in {Jx.Cut(jb)}"; - foreach (var t in tp.Where(t => t.Type == JsonTokenType.PropertyName)) - if (t.Raw != canon) return $"write: key {t.Raw}, expected {canon}, in {Jx.Cut(jp)}"; - if (ownVo) - { - // "Your own converter wins" (AspNetCore README#what-the-document-says): the application's converter writes the value object, - // so the decimal's document is none of its; its own document reads back under the same options - c.Note(NoteKeys.OwnVo); - var (_, xr) = Jx.De(jv!, hv.Declared, o); - if (xr is not null) return "own converter for the value object: its document does not read back: " + Jx.Ex(xr); - return null; - } - if (jv != jp) return $"write: the value object wrote {Jx.Cut(jv)}, the decimal {Jx.Cut(jp)}"; - foreach (var f in compared) - { - if (f.Ep is not null) continue; // the decimal refused it: reads-a-number-or-a-string judges it - if (f.Ev is not null) return $"read {f.Name}: the value object threw {Jx.Ex(f.Ev)} where the decimal read it\n text={Jx.Cut(f.Json)}"; - if (f.Cp.Count != f.Cv.Count || f.Cp.Zip(f.Cv).Any(z => !Same(z.First, z.Second))) return $"read {f.Name}: the value object read {Show(f.Cv)}, the decimal {Show(f.Cp)}\n text={Jx.Cut(f.Json)}"; - } - if (writeLeftOut && (readNothing is not null || compared.Count == 0)) return WriteLeftOut(c); - c.Note(NoteKeys.Compared, $"{(number ? "number" : "string")} {text} -> {canon}, the value object's document the decimal's"); - return null; - }); - return f1 ?? f2 ?? f3 ?? f4 ?? f5; - } -} diff --git a/tools/probe/corpus/harness/EfExtra.cs b/tools/probe/corpus/harness/EfExtra.cs deleted file mode 100644 index 26ef7def..00000000 --- a/tools/probe/corpus/harness/EfExtra.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Entity shapes and helpers for the EF claims E07, E13, E14, E15 (reuse EfHarness.cs: EfDb, EfModel, Q, EfRegistry, KeyRegistry). -#nullable enable -using System.Linq.Expressions; -using System.Reflection; -using Microsoft.EntityFrameworkCore; -using Probes.Shapes; -namespace Probes.Ef; - -public class EntL where T : notnull { public int Id { get; set; } public List Items { get; set; } = []; } -public class EntComp where TA : notnull where TB : notnull { public TA A { get; set; } = default!; public TB B { get; set; } = default!; public string Tag { get; set; } = ""; } -public abstract class RootE where T : notnull { public T Id { get; set; } = default!; public string Name { get; set; } = ""; } -public class LeafA : RootE where T : notnull { public int X { get; set; } } -public class LeafB : RootE where T : notnull { public int Y { get; set; } } - -public static class EfX -{ - /// The i-th distinct plain value of a wrapped type. - public static object Sample(string wrapped, int i) => wrapped switch - { - "string" => "val-" + (char)('a' + i), - "int" => 10 + i, - "long" => 4_000_000_000L + i, - "Guid" => new Guid(i + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), - "decimal" => 1.5m + i, - _ => throw new ArgumentException(wrapped), - }; - public static EfEntry Top(string kind, string wrapped) => EfRegistry.All.FirstOrDefault(x => x.Kind == kind && x.Wrapped == wrapped && x.Site == "top-level") - ?? EfRegistry.All.First(x => (x.Kind is "record-struct" or "sealed-record-class") && x.Wrapped == wrapped && x.Site == "top-level"); - public static readonly string[] Kinds = ["record-struct", "sealed-record-class", "validated-class", "validated-struct"]; - public static object New(Type t) => Activator.CreateInstance(t)!; - public static void Set(object o, string prop, object? v) => o.GetType().GetProperty(prop)!.SetValue(o, v); - public static object? Get(object o, string prop) => o.GetType().GetProperty(prop)!.GetValue(o); - public static string Plainify(object? k) - { - if (k is not null && k.GetType().Namespace == "Probes.Ef") k = k.GetType().GetProperty("Value")!.GetValue(k); - return Convert.ToString(k, System.Globalization.CultureInfo.InvariantCulture) ?? "null"; - } - public static IEnumerable Enumerate(IQueryable q) { foreach (var o in q) yield return o!; } - public static async Task RawScalar(EfDb db, string sql) - { - await using var cmd = db.Connection.CreateCommand(); cmd.CommandText = sql; - return Convert.ToString(await cmd.ExecuteScalarAsync(), System.Globalization.CultureInfo.InvariantCulture); - } - public static async Task Raw(EfDb db, string sql) - { - await using var cmd = db.Connection.CreateCommand(); cmd.CommandText = sql; await cmd.ExecuteNonQueryAsync(); - } -} diff --git a/tools/probe/corpus/harness/EfExtra2.cs b/tools/probe/corpus/harness/EfExtra2.cs deleted file mode 100644 index 2cffd4cf..00000000 --- a/tools/probe/corpus/harness/EfExtra2.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Shared by the EF claims E06, E11, E12, E16 (after EfHarness.cs / EfExtra.cs): a context with ConventionS and the order of UseTypeKit, -// and an application-owned converter ("C:" + the plain value as text) for any type. -#nullable enable -using System.Globalization; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Probes.Shapes; -namespace Probes.Ef; - -public sealed class DynCtx2(DbContextOptions options, Action configure, Action? conventions) : DbContext(options) -{ - protected override void OnModelCreating(ModelBuilder modelBuilder) => configure(modelBuilder); - protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) => conventions?.Invoke(configurationBuilder); -} - -public sealed class EfDb2 : IAsyncDisposable -{ - public SqliteConnection Connection { get; } - public DynCtx2 Context { get; } - // order: "none" (no UseTypeKit), "before-provider" or "after-provider". - public EfDb2(Action configure, string order, Action? conventions = null) - { - Connection = new SqliteConnection("Data Source=:memory:"); - Connection.Open(); - var b = new DbContextOptionsBuilder(); - if (order == "before-provider") b.UseTypeKit(); - b.UseSqlite(Connection); - if (order == "after-provider") b.UseTypeKit(); - b.ReplaceService(); - Context = new DynCtx2(b.Options, configure, conventions); - } - public async ValueTask DisposeAsync() { await Context.DisposeAsync(); await Connection.DisposeAsync(); } -} - -/// An application-owned conversion of T to text: "C:" + the plain value. T is the value object or its wrapped type. -public static class OwnConv -{ - public static Func ToF = _ => throw new InvalidOperationException("OwnConv not set up"); - public static Func FromF = _ => throw new InvalidOperationException("OwnConv not set up"); - public static string To(T v) => ToF(v); - public static T From(string s) => FromF(s); - public static void Setup(string wrapped, Func make, Func plain) - { - ToF = v => "C:" + Fmt(plain(v!)); - FromF = s => (T)make(Parse(wrapped, s[2..])); - } - public static string Fmt(object p) => Convert.ToString(p, CultureInfo.InvariantCulture)!; - public static object Parse(string wrapped, string s) => wrapped switch - { - "string" => s, "int" => int.Parse(s, CultureInfo.InvariantCulture), "long" => long.Parse(s, CultureInfo.InvariantCulture), - "Guid" => Guid.Parse(s), "decimal" => decimal.Parse(s, CultureInfo.InvariantCulture), "char" => s[0], - _ => throw new ArgumentException(wrapped), - }; -} - -public sealed class OwnConverter() : ValueConverter(v => OwnConv.To(v), s => OwnConv.From(s)); - -public static class OwnConvs -{ - /// Sets OwnConv up for the value object (voSide) or for its wrapped type, returns the converter type. - public static Type Setup(EfEntry e, bool vo) - { - if (vo) - { - typeof(OwnConv<>).MakeGenericType(e.Vo).GetMethod("Setup")!.Invoke(null, [e.Wrapped, (Func)e.MakeVo, (Func)(v => v.GetType().GetProperty("Value")!.GetValue(v)!)]); - return typeof(OwnConverter<>).MakeGenericType(e.Vo); - } - typeof(OwnConv<>).MakeGenericType(e.Plain).GetMethod("Setup")!.Invoke(null, [e.Wrapped, (Func)(p => p), (Func)(p => p)]); - return typeof(OwnConverter<>).MakeGenericType(e.Plain); - } -} - -public static class EfX2 -{ - public static async Task RawScalar(SqliteConnection c, string sql) - { - await using var cmd = c.CreateCommand(); cmd.CommandText = sql; - return Convert.ToString(await cmd.ExecuteScalarAsync(), CultureInfo.InvariantCulture); - } -} diff --git a/tools/probe/corpus/harness/EfHarness.cs b/tools/probe/corpus/harness/EfHarness.cs deleted file mode 100644 index c6de75a1..00000000 --- a/tools/probe/corpus/harness/EfHarness.cs +++ /dev/null @@ -1,191 +0,0 @@ -// Shared EF row-applying code for the EF satellite claims (surface ef): the entity shapes, a DbContext built from a -// configuration delegate, the model descriptor and the query helpers. Written once; later EF claims reuse it. -#nullable enable -using System.Linq.Expressions; -using System.Reflection; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Probes.Shapes; -namespace Probes.Ef; - -public sealed record EfEntry(string Kind, string Wrapped, string Site, Type Vo, Type Plain, Func Valid) -{ - /// The value object around a plain value, by its public seams: From, else FromKnownGood. - public object MakeVo(object plain) - { - var from = Vo.GetMethod("From", BindingFlags.Public | BindingFlags.Static, [Plain]); - if (from is not null) return from.Invoke(null, [plain])!; - var known = Vo.GetMethod("FromKnownGood", BindingFlags.Public | BindingFlags.Static, [Plain, typeof(string)]); - return known is null ? throw new InvalidOperationException($"{Vo} has neither From nor FromKnownGood") : known.Invoke(null, [plain, null])!; - } - - /// The generated companion extension GetValue / ValueOrNull of this value object (a static class in its namespace; the first parameter is the value object, or its Nullable for ValueOrNull). - public MethodInfo? Companion(string name) - { - var first = name == "ValueOrNull" && Vo.IsValueType ? typeof(Nullable<>).MakeGenericType(Vo) : Vo; - return Vo.Assembly.GetTypes().Where(t => t.IsAbstract && t.IsSealed && t.Namespace == Vo.Namespace) - .SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.Static)) - .FirstOrDefault(m => m.Name == name && m.GetParameters() is [var p] && p.ParameterType == first); - } -} - -public static partial class EfRegistry -{ - public static readonly List All = Build(); - static List Build() { var e = new List(); Fill(e); return e; } - static partial void Fill(List e); - public static EfEntry Of(Row r) { var k = r["shape.kind"]; var w = r["shape.wrapped"]; var s = r["shape.site"]; return All.First(x => x.Kind == k && x.Wrapped == w && x.Site == s); } -} - -public class EntP where T : notnull { public int Id { get; set; } public T P { get; set; } = default!; } -public class EntNC where T : class { public int Id { get; set; } public T? P { get; set; } } -public class EntK where T : notnull { public T Id { get; set; } = default!; public string Tag { get; set; } = ""; } -public class Own where T : notnull { public T P { get; set; } = default!; } -public class EntO where T : notnull { public int Id { get; set; } public Own O { get; set; } = new(); } -public class EntC where T : notnull { public int Id { get; set; } public Own C { get; set; } = new(); } -public sealed class Box { public T Value = default!; } - -public sealed class UniqueModelKey : Microsoft.EntityFrameworkCore.Infrastructure.IModelCacheKeyFactory -{ - public object Create(DbContext context, bool designTime) => new object(); -} - -public sealed class DynCtx(DbContextOptions options, Action configure) : DbContext(options) -{ - protected override void OnModelCreating(ModelBuilder modelBuilder) => configure(modelBuilder); -} - -public sealed class EfDb : IAsyncDisposable -{ - public SqliteConnection Connection { get; } - public DynCtx Context { get; } - public EfDb(Action configure, bool typeKit, Action? extra = null) - { - Connection = new SqliteConnection("Data Source=:memory:"); - Connection.Open(); - var b = new DbContextOptionsBuilder().UseSqlite(Connection).ReplaceService(); - if (typeKit) b.UseTypeKit(); - extra?.Invoke(b); - Context = new DynCtx(b.Options, configure); - } - public async ValueTask DisposeAsync() { await Context.DisposeAsync(); await Connection.DisposeAsync(); } -} - -public static class EfModel -{ - public static Type Entity(string mapping, Type t) => mapping switch - { - "property" => typeof(EntP<>).MakeGenericType(t), - "nullable" => t.IsValueType ? typeof(EntP<>).MakeGenericType(typeof(Nullable<>).MakeGenericType(t)) : typeof(EntNC<>).MakeGenericType(t), - "key" => typeof(EntK<>).MakeGenericType(t), - "owned" => typeof(EntO<>).MakeGenericType(t), - "complex" => typeof(EntC<>).MakeGenericType(t), - _ => throw new ArgumentException("mapping " + mapping), - }; - - public static readonly Dictionary ColumnTypes = new() - { - ["string"] = "VARCHAR(40)", ["Uri"] = "VARCHAR(40)", ["Guid"] = "UNIQUEIDENTIFIER", ["int"] = "BIGINT", ["long"] = "BIGINT", ["byte"] = "TINYINT", - ["ulong"] = "BIGINT", ["decimal"] = "NUMERIC(10,2)", ["double"] = "FLOAT", ["bool"] = "BIT", ["char"] = "CHAR(1)", ["DateTime"] = "DATETIME", - ["DateTimeOffset"] = "DATETIMEOFFSET", ["DateOnly"] = "DATE", ["TimeOnly"] = "TIME", ["TimeSpan"] = "TIME", ["enum"] = "SMALLINT", ["flags-enum"] = "SMALLINT", - }; - - /// Maps the entity of a mapping in table "t", applying a facet to the column property (and UseAutoincrement to an integer key when asked). - public static Action Configure(string mapping, Type entity, Action? facet, bool autoincrement) => mb => - { - var eb = mb.Entity(entity); - eb.ToTable("t"); - var t = entity.GetGenericArguments()[0]; - switch (mapping) - { - case "property" or "nullable": eb.HasKey("Id"); if (facet is not null) facet(eb.Property("P").Metadata); break; - case "key": - eb.HasKey("Id"); - var pb = eb.Property("Id"); - facet?.Invoke(pb.Metadata); - if (autoincrement) Microsoft.EntityFrameworkCore.SqlitePropertyBuilderExtensions.UseAutoincrement(pb); - break; - case "owned": - eb.HasKey("Id"); - eb.OwnsOne(typeof(Own<>).MakeGenericType(t), "O", ob => { if (facet is not null) facet(ob.Property("P").Metadata); }); - break; - case "complex": - eb.HasKey("Id"); - eb.ComplexProperty("C", cb => { if (facet is not null) facet(cb.Property("P").Metadata); }); - break; - } - }; - - /// What the model says about every mapped column: store type, nullability, facets, key and generation. - public static string Describe(DbContext db) - { - var model = db.GetService().Model; - var lines = new List(); - string Line(string table, string prefix, IProperty p) - { - string col = "?"; try { col = ((IReadOnlyProperty)p).GetColumnType() ?? "?"; } catch { try { col = Microsoft.EntityFrameworkCore.RelationalPropertyExtensions.GetRelationalTypeMapping(p).StoreType; } catch { col = "?"; } } - string nul; try { nul = p.IsColumnNullable().ToString(); } catch { nul = p.IsNullable.ToString(); } - return $"{table}.{prefix}{p.Name}: type={col} nullable={nul} max={p.GetMaxLength()} prec={p.GetPrecision()} scale={p.GetScale()} unicode={p.IsUnicode()} pk={p.IsPrimaryKey()} gen={p.ValueGenerated}"; - } - foreach (var et in model.GetEntityTypes()) - { - var table = et.GetTableName() ?? "(none)"; - foreach (var p in et.GetProperties()) lines.Add(Line(table, "", p)); - foreach (var cp in et.GetComplexProperties()) foreach (var p in cp.ComplexType.GetProperties()) lines.Add(Line(table, cp.Name + ".", p)); - } - lines.Sort(StringComparer.Ordinal); - return string.Join("\n", lines); - } - - public static string FirstDiff(string a, string b) - { - var x = a.Split('\n'); var y = b.Split('\n'); - for (var i = 0; i < Math.Max(x.Length, y.Length); i++) - if ((i < x.Length ? x[i] : "") != (i < y.Length ? y[i] : "")) return $"VO: {(i < x.Length ? x[i] : "")} | plain: {(i < y.Length ? y[i] : "")}"; - return ""; - } -} - -/// -/// How a check of a two-sided EF row ends where a side threw: the value object's context under UseTypeKit() and the -/// wrapped twin's under plain EF ran the same step, named by what. Neither threw: false, compare on. The value object -/// alone: its violation. Both, with exceptions of one type: nothing to compare, inconclusive, since no fact or sentence says why -/// the framework refuses it. Both, otherwise: a violation, since the value object did not fail as its twin does. The twin alone: -/// inconclusive, no twin to compare with. -/// -public static class EfSides -{ - public static bool Threw(Check c, Exception? vo, Exception? plain, string what, out string? failure) - { - failure = null; - if (vo is null && plain is null) return false; - if (vo is not null && plain is not null) - failure = vo.GetType() == plain.GetType() - ? c.Inconclusive($"both sides refuse {what} alike: {vo.GetType().Name}: {Short(vo.Message)}") - : $"{what}: the value object's side threw {vo.GetType().Name}: {Short(vo.Message)}; the wrapped type's {plain.GetType().Name}: {Short(plain.Message)}"; - else if (plain is not null) failure = c.Inconclusive($"the wrapped type's side refuses {what}, so there is no twin to compare with: {plain.GetType().Name}: {Short(plain.Message)}"); - else failure = $"{what} with the value object threw {vo!.GetType().Name}: {Short(vo.Message)}; the wrapped type's did not"; - return true; - } - - static string Short(string s) { s = s.Split('\n')[0]; return s.Length > 300 ? s[..300] : s; } -} - -public static class Q -{ - public static IQueryable Call(string name, Type[] typeArgs, IQueryable src, params Expression[] args) - { - static bool OneParamLambda(ParameterInfo p) => - p.ParameterType.IsGenericType && p.ParameterType.GetGenericTypeDefinition() == typeof(Expression<>) && p.ParameterType.GetGenericArguments()[0].GetGenericArguments().Length == 2; - var m = typeof(Queryable).GetMethods().First(x => x.Name == name && x.IsGenericMethodDefinition && x.GetGenericArguments().Length == typeArgs.Length - && x.GetParameters().Length == args.Length + 1 && x.GetParameters().Skip(1).All(OneParamLambda)); - return (IQueryable)m.MakeGenericMethod(typeArgs).Invoke(null, [src, .. args.Select(a => (object)a)])!; - } - public static IQueryable SetOf(DbContext db, Type entity) => - (IQueryable)typeof(DbContext).GetMethods().First(m => m.Name == "Set" && m.GetParameters().Length == 0).MakeGenericMethod(entity).Invoke(db, null)!; - public static object NewBox(Type t, object? value) { var b = Activator.CreateInstance(typeof(Box<>).MakeGenericType(t))!; typeof(Box<>).MakeGenericType(t).GetField("Value")!.SetValue(b, value); return b; } - public static string Sql(IQueryable q) => q.ToQueryString(); -} diff --git a/tools/probe/corpus/harness/EfShapes.g.cs b/tools/probe/corpus/harness/EfShapes.g.cs deleted file mode 100644 index 95fa592f..00000000 --- a/tools/probe/corpus/harness/EfShapes.g.cs +++ /dev/null @@ -1,962 +0,0 @@ -// by tools/probe/generators/ef.cs catalogue; the EF probes' shape catalogue (shape.kind x shape.wrapped x shape.site). Do not edit. -#nullable enable -#pragma warning disable CMTK0014, CS8618, CS1591, CMTK0005, CMTK1000, CMTK0003, CMTK0006, CA1000 -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -using Probes.Shapes; -namespace Probes.Ef; -public struct S_E_record_struct_DateOnly -{ -public readonly partial record struct V : IValue; -} -public static class C2_E_record_struct_DateOnly -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_DateOnly : IValue; -public static class C_E_record_struct_DateTime -{ -public readonly partial record struct V : IValue; -} -public static class C2_E_record_struct_DateTime -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_DateTime : IValue; -public readonly partial record struct E_record_struct_DateTimeOffset : IValue; -public static class C_E_record_struct_Guid -{ -public readonly partial record struct V : IValue; -} -public static class C2_E_record_struct_Guid -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_Guid : IValue; -public static class C2_E_record_struct_TimeOnly -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public static class C_E_record_struct_TimeSpan -{ -public readonly partial record struct V : IValue; -} -public struct S_E_record_struct_TimeSpan -{ -public readonly partial record struct V : IValue; -} -public static class C_E_record_struct_Uri -{ -public readonly partial record struct V : IValue; -} -public static class C2_E_record_struct_Uri -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_Uri : IValue; -public struct S_E_record_struct_bool -{ -public readonly partial record struct V : IValue; -} -public readonly partial record struct E_record_struct_bool : IValue; -public static class C2_E_record_struct_byte -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_byte : IValue; -public static class C_E_record_struct_char -{ -public readonly partial record struct V : IValue; -} -public struct S_E_record_struct_char -{ -public readonly partial record struct V : IValue; -} -public readonly partial record struct E_record_struct_char : IValue; -public struct S_E_record_struct_decimal -{ -public readonly partial record struct V : IValue; -} -public static class C2_E_record_struct_decimal -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_decimal : IValue; -public struct S_E_record_struct_double -{ -public readonly partial record struct V : IValue; -} -public static class C2_E_record_struct_enum -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_enum : IValue; -public static class C2_E_record_struct_flags_enum -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_flags_enum : IValue; -public static class C2_E_record_struct_int -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_int : IValue; -public static class C2_E_record_struct_long -{ - public static class Inner - { -public readonly partial record struct V : IValue; - } -} -public readonly partial record struct E_record_struct_long : IValue; -public static class C_E_record_struct_string -{ -public readonly partial record struct V : IValue; -} -public struct S_E_record_struct_ulong -{ -public readonly partial record struct V : IValue; -} -public struct S_E_sealed_record_class_DateOnly -{ -public sealed partial record class V : IValue; -} -public static class C2_E_sealed_record_class_DateOnly -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public struct S_E_sealed_record_class_DateTime -{ -public sealed partial record class V : IValue; -} -public static class C2_E_sealed_record_class_DateTime -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public static class C_E_sealed_record_class_DateTimeOffset -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_DateTimeOffset -{ -public sealed partial record class V : IValue; -} -public static class C2_E_sealed_record_class_DateTimeOffset -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public static class C2_E_sealed_record_class_Guid -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public static class C_E_sealed_record_class_TimeOnly -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_TimeOnly -{ -public sealed partial record class V : IValue; -} -public static class C2_E_sealed_record_class_TimeOnly -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public sealed partial record class E_sealed_record_class_TimeSpan : IValue; -public static class C_E_sealed_record_class_Uri -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_Uri -{ -public sealed partial record class V : IValue; -} -public static class C2_E_sealed_record_class_Uri -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public static class C2_E_sealed_record_class_bool -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public static class C_E_sealed_record_class_byte -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_byte -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_char -{ -public sealed partial record class V : IValue; -} -public sealed partial record class E_sealed_record_class_char : IValue; -public static class C_E_sealed_record_class_decimal -{ -public sealed partial record class V : IValue; -} -public static class C2_E_sealed_record_class_decimal -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public static class C2_E_sealed_record_class_double -{ - public static class Inner - { -public sealed partial record class V : IValue; - } -} -public sealed partial record class E_sealed_record_class_double : IValue; -public sealed partial record class E_sealed_record_class_enum : IValue; -public static class C_E_sealed_record_class_flags_enum -{ -public sealed partial record class V : IValue; -} -public sealed partial record class E_sealed_record_class_flags_enum : IValue; -public static class C_E_sealed_record_class_int -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_int -{ -public sealed partial record class V : IValue; -} -public static class C_E_sealed_record_class_long -{ -public sealed partial record class V : IValue; -} -public static class C_E_sealed_record_class_string -{ -public sealed partial record class V : IValue; -} -public struct S_E_sealed_record_class_string -{ -public sealed partial record class V : IValue; -} -public sealed partial record class E_sealed_record_class_string : IValue; -public static class C_E_sealed_record_class_ulong -{ -public sealed partial record class V : IValue; -} -public struct S_E_validated_class_DateOnly -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(DateOnly value) => - EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_class_DateTimeOffset -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(DateTimeOffset value) => - EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C_E_validated_class_Guid -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_class_Guid -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public sealed partial record class E_validated_class_Guid : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new E_validated_class_Guid(value); -} -public static class C_E_validated_class_TimeOnly -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(TimeOnly value) => - EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public sealed partial record class E_validated_class_TimeOnly : IValidatedValue -{ - public static Result Create(TimeOnly value) => - EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new E_validated_class_TimeOnly(value); -} -public static class C2_E_validated_class_TimeSpan -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(TimeSpan value) => - EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public struct S_E_validated_class_Uri -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(Uri value) => - EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C_E_validated_class_bool -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(bool value) => - EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_class_bool -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(bool value) => - EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public sealed partial record class E_validated_class_bool : IValidatedValue -{ - public static Result Create(bool value) => - EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new E_validated_class_bool(value); -} -public static class C_E_validated_class_byte -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(byte value) => - EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public sealed partial record class E_validated_class_byte : IValidatedValue -{ - public static Result Create(byte value) => - EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new E_validated_class_byte(value); -} -public static class C_E_validated_class_char -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(char value) => - EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_class_char -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(char value) => - EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public static class C_E_validated_class_double -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(double value) => - EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_class_double -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(double value) => - EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public struct S_E_validated_class_enum -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(PEnum value) => - EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_class_enum -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(PEnum value) => - EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public static class C_E_validated_class_flags_enum -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(PFlags value) => - EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_class_flags_enum -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(PFlags value) => - EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_class_flags_enum -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(PFlags value) => - EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public static class C2_E_validated_class_int -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(int value) => - EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public sealed partial record class E_validated_class_int : IValidatedValue -{ - public static Result Create(int value) => - EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new E_validated_class_int(value); -} -public struct S_E_validated_class_long -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(long value) => - EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_class_long -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(long value) => - EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public struct S_E_validated_class_string -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(string value) => - EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_class_string -{ - public static class Inner - { -public sealed partial record class V : IValidatedValue -{ - public static Result Create(string value) => - EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public struct S_E_validated_class_ulong -{ -public sealed partial record class V : IValidatedValue -{ - public static Result Create(ulong value) => - EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public sealed partial record class E_validated_class_ulong : IValidatedValue -{ - public static Result Create(ulong value) => - EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new E_validated_class_ulong(value); -} -public static class C_E_validated_struct_DateOnly -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(DateOnly value) => - EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public readonly partial record struct E_validated_struct_DateOnly : IValidatedValue -{ - public static Result Create(DateOnly value) => - EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new E_validated_struct_DateOnly(value); -} -public static class C_E_validated_struct_DateTime -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(DateTime value) => - EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_DateTime -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(DateTime value) => - EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C_E_validated_struct_DateTimeOffset -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(DateTimeOffset value) => - EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_struct_DateTimeOffset -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(DateTimeOffset value) => - EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public static class C_E_validated_struct_Guid -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_Guid -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_TimeOnly -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(TimeOnly value) => - EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public readonly partial record struct E_validated_struct_TimeOnly : IValidatedValue -{ - public static Result Create(TimeOnly value) => - EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new E_validated_struct_TimeOnly(value); -} -public static class C_E_validated_struct_TimeSpan -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(TimeSpan value) => - EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public readonly partial record struct E_validated_struct_Uri : IValidatedValue -{ - public static Result Create(Uri value) => - EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new E_validated_struct_Uri(value); -} -public static class C_E_validated_struct_bool -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(bool value) => - EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_bool -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(bool value) => - EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_struct_bool -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(bool value) => - EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public struct S_E_validated_struct_byte -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(byte value) => - EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_struct_byte -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(byte value) => - EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public static class C2_E_validated_struct_char -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(char value) => - EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public readonly partial record struct E_validated_struct_char : IValidatedValue -{ - public static Result Create(char value) => - EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new E_validated_struct_char(value); -} -public static class C_E_validated_struct_decimal -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(decimal value) => - EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_decimal -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(decimal value) => - EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_struct_decimal -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(decimal value) => - EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public readonly partial record struct E_validated_struct_decimal : IValidatedValue -{ - public static Result Create(decimal value) => - EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new E_validated_struct_decimal(value); -} -public static class C_E_validated_struct_double -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(double value) => - EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public readonly partial record struct E_validated_struct_double : IValidatedValue -{ - public static Result Create(double value) => - EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new E_validated_struct_double(value); -} -public static class C_E_validated_struct_enum -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(PEnum value) => - EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_flags_enum -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(PFlags value) => - EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C_E_validated_struct_int -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(int value) => - EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public struct S_E_validated_struct_int -{ -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(int value) => - EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); -} -} -public static class C2_E_validated_struct_long -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(long value) => - EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public readonly partial record struct E_validated_struct_long : IValidatedValue -{ - public static Result Create(long value) => - EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new E_validated_struct_long(value); -} -public static class C2_E_validated_struct_string -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(string value) => - EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public readonly partial record struct E_validated_struct_string : IValidatedValue -{ - public static Result Create(string value) => - EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new E_validated_struct_string(value); -} -public static class C2_E_validated_struct_ulong -{ - public static class Inner - { -public readonly partial record struct V : IValidatedValue -{ - public static Result Create(ulong value) => - EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); -} - } -} -public static partial class EfRegistry -{ - static partial void Fill(List e) - { - e.Add(new EfEntry("record-struct", "DateOnly", "nested-in-struct", typeof(S_E_record_struct_DateOnly.V), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("record-struct", "DateOnly", "nested-two-levels", typeof(C2_E_record_struct_DateOnly.Inner.V), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("record-struct", "DateOnly", "top-level", typeof(E_record_struct_DateOnly), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("record-struct", "DateTime", "nested-in-class", typeof(C_E_record_struct_DateTime.V), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("record-struct", "DateTime", "nested-two-levels", typeof(C2_E_record_struct_DateTime.Inner.V), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("record-struct", "DateTime", "top-level", typeof(E_record_struct_DateTime), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("record-struct", "DateTimeOffset", "top-level", typeof(E_record_struct_DateTimeOffset), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("record-struct", "Guid", "nested-in-class", typeof(C_E_record_struct_Guid.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("record-struct", "Guid", "nested-two-levels", typeof(C2_E_record_struct_Guid.Inner.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("record-struct", "Guid", "top-level", typeof(E_record_struct_Guid), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("record-struct", "TimeOnly", "nested-two-levels", typeof(C2_E_record_struct_TimeOnly.Inner.V), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("record-struct", "TimeSpan", "nested-in-class", typeof(C_E_record_struct_TimeSpan.V), typeof(TimeSpan), () => TimeSpan.FromMinutes(90))); - e.Add(new EfEntry("record-struct", "TimeSpan", "nested-in-struct", typeof(S_E_record_struct_TimeSpan.V), typeof(TimeSpan), () => TimeSpan.FromMinutes(90))); - e.Add(new EfEntry("record-struct", "Uri", "nested-in-class", typeof(C_E_record_struct_Uri.V), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("record-struct", "Uri", "nested-two-levels", typeof(C2_E_record_struct_Uri.Inner.V), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("record-struct", "Uri", "top-level", typeof(E_record_struct_Uri), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("record-struct", "bool", "nested-in-struct", typeof(S_E_record_struct_bool.V), typeof(bool), () => true)); - e.Add(new EfEntry("record-struct", "bool", "top-level", typeof(E_record_struct_bool), typeof(bool), () => true)); - e.Add(new EfEntry("record-struct", "byte", "nested-two-levels", typeof(C2_E_record_struct_byte.Inner.V), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("record-struct", "byte", "top-level", typeof(E_record_struct_byte), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("record-struct", "char", "nested-in-class", typeof(C_E_record_struct_char.V), typeof(char), () => 'a')); - e.Add(new EfEntry("record-struct", "char", "nested-in-struct", typeof(S_E_record_struct_char.V), typeof(char), () => 'a')); - e.Add(new EfEntry("record-struct", "char", "top-level", typeof(E_record_struct_char), typeof(char), () => 'a')); - e.Add(new EfEntry("record-struct", "decimal", "nested-in-struct", typeof(S_E_record_struct_decimal.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("record-struct", "decimal", "nested-two-levels", typeof(C2_E_record_struct_decimal.Inner.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("record-struct", "decimal", "top-level", typeof(E_record_struct_decimal), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("record-struct", "double", "nested-in-struct", typeof(S_E_record_struct_double.V), typeof(double), () => 1.5)); - e.Add(new EfEntry("record-struct", "enum", "nested-two-levels", typeof(C2_E_record_struct_enum.Inner.V), typeof(PEnum), () => PEnum.B)); - e.Add(new EfEntry("record-struct", "enum", "top-level", typeof(E_record_struct_enum), typeof(PEnum), () => PEnum.B)); - e.Add(new EfEntry("record-struct", "flags-enum", "nested-two-levels", typeof(C2_E_record_struct_flags_enum.Inner.V), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("record-struct", "flags-enum", "top-level", typeof(E_record_struct_flags_enum), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("record-struct", "int", "nested-two-levels", typeof(C2_E_record_struct_int.Inner.V), typeof(int), () => 42)); - e.Add(new EfEntry("record-struct", "int", "top-level", typeof(E_record_struct_int), typeof(int), () => 42)); - e.Add(new EfEntry("record-struct", "long", "nested-two-levels", typeof(C2_E_record_struct_long.Inner.V), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("record-struct", "long", "top-level", typeof(E_record_struct_long), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("record-struct", "string", "nested-in-class", typeof(C_E_record_struct_string.V), typeof(string), () => "alpha")); - e.Add(new EfEntry("record-struct", "ulong", "nested-in-struct", typeof(S_E_record_struct_ulong.V), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("sealed-record-class", "DateOnly", "nested-in-struct", typeof(S_E_sealed_record_class_DateOnly.V), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("sealed-record-class", "DateOnly", "nested-two-levels", typeof(C2_E_sealed_record_class_DateOnly.Inner.V), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("sealed-record-class", "DateTime", "nested-in-struct", typeof(S_E_sealed_record_class_DateTime.V), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("sealed-record-class", "DateTime", "nested-two-levels", typeof(C2_E_sealed_record_class_DateTime.Inner.V), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("sealed-record-class", "DateTimeOffset", "nested-in-class", typeof(C_E_sealed_record_class_DateTimeOffset.V), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("sealed-record-class", "DateTimeOffset", "nested-in-struct", typeof(S_E_sealed_record_class_DateTimeOffset.V), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("sealed-record-class", "DateTimeOffset", "nested-two-levels", typeof(C2_E_sealed_record_class_DateTimeOffset.Inner.V), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("sealed-record-class", "Guid", "nested-two-levels", typeof(C2_E_sealed_record_class_Guid.Inner.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("sealed-record-class", "TimeOnly", "nested-in-class", typeof(C_E_sealed_record_class_TimeOnly.V), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("sealed-record-class", "TimeOnly", "nested-in-struct", typeof(S_E_sealed_record_class_TimeOnly.V), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("sealed-record-class", "TimeOnly", "nested-two-levels", typeof(C2_E_sealed_record_class_TimeOnly.Inner.V), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("sealed-record-class", "TimeSpan", "top-level", typeof(E_sealed_record_class_TimeSpan), typeof(TimeSpan), () => TimeSpan.FromMinutes(90))); - e.Add(new EfEntry("sealed-record-class", "Uri", "nested-in-class", typeof(C_E_sealed_record_class_Uri.V), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("sealed-record-class", "Uri", "nested-in-struct", typeof(S_E_sealed_record_class_Uri.V), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("sealed-record-class", "Uri", "nested-two-levels", typeof(C2_E_sealed_record_class_Uri.Inner.V), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("sealed-record-class", "bool", "nested-two-levels", typeof(C2_E_sealed_record_class_bool.Inner.V), typeof(bool), () => true)); - e.Add(new EfEntry("sealed-record-class", "byte", "nested-in-class", typeof(C_E_sealed_record_class_byte.V), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("sealed-record-class", "byte", "nested-in-struct", typeof(S_E_sealed_record_class_byte.V), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("sealed-record-class", "char", "nested-in-struct", typeof(S_E_sealed_record_class_char.V), typeof(char), () => 'a')); - e.Add(new EfEntry("sealed-record-class", "char", "top-level", typeof(E_sealed_record_class_char), typeof(char), () => 'a')); - e.Add(new EfEntry("sealed-record-class", "decimal", "nested-in-class", typeof(C_E_sealed_record_class_decimal.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("sealed-record-class", "decimal", "nested-two-levels", typeof(C2_E_sealed_record_class_decimal.Inner.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("sealed-record-class", "double", "nested-two-levels", typeof(C2_E_sealed_record_class_double.Inner.V), typeof(double), () => 1.5)); - e.Add(new EfEntry("sealed-record-class", "double", "top-level", typeof(E_sealed_record_class_double), typeof(double), () => 1.5)); - e.Add(new EfEntry("sealed-record-class", "enum", "top-level", typeof(E_sealed_record_class_enum), typeof(PEnum), () => PEnum.B)); - e.Add(new EfEntry("sealed-record-class", "flags-enum", "nested-in-class", typeof(C_E_sealed_record_class_flags_enum.V), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("sealed-record-class", "flags-enum", "top-level", typeof(E_sealed_record_class_flags_enum), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("sealed-record-class", "int", "nested-in-class", typeof(C_E_sealed_record_class_int.V), typeof(int), () => 42)); - e.Add(new EfEntry("sealed-record-class", "int", "nested-in-struct", typeof(S_E_sealed_record_class_int.V), typeof(int), () => 42)); - e.Add(new EfEntry("sealed-record-class", "long", "nested-in-class", typeof(C_E_sealed_record_class_long.V), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("sealed-record-class", "string", "nested-in-class", typeof(C_E_sealed_record_class_string.V), typeof(string), () => "alpha")); - e.Add(new EfEntry("sealed-record-class", "string", "nested-in-struct", typeof(S_E_sealed_record_class_string.V), typeof(string), () => "alpha")); - e.Add(new EfEntry("sealed-record-class", "string", "top-level", typeof(E_sealed_record_class_string), typeof(string), () => "alpha")); - e.Add(new EfEntry("sealed-record-class", "ulong", "nested-in-class", typeof(C_E_sealed_record_class_ulong.V), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("validated-class", "DateOnly", "nested-in-struct", typeof(S_E_validated_class_DateOnly.V), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("validated-class", "DateTimeOffset", "nested-in-struct", typeof(S_E_validated_class_DateTimeOffset.V), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("validated-class", "Guid", "nested-in-class", typeof(C_E_validated_class_Guid.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-class", "Guid", "nested-in-struct", typeof(S_E_validated_class_Guid.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-class", "Guid", "top-level", typeof(E_validated_class_Guid), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-class", "TimeOnly", "nested-in-class", typeof(C_E_validated_class_TimeOnly.V), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("validated-class", "TimeOnly", "top-level", typeof(E_validated_class_TimeOnly), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("validated-class", "TimeSpan", "nested-two-levels", typeof(C2_E_validated_class_TimeSpan.Inner.V), typeof(TimeSpan), () => TimeSpan.FromMinutes(90))); - e.Add(new EfEntry("validated-class", "Uri", "nested-in-struct", typeof(S_E_validated_class_Uri.V), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("validated-class", "bool", "nested-in-class", typeof(C_E_validated_class_bool.V), typeof(bool), () => true)); - e.Add(new EfEntry("validated-class", "bool", "nested-in-struct", typeof(S_E_validated_class_bool.V), typeof(bool), () => true)); - e.Add(new EfEntry("validated-class", "bool", "top-level", typeof(E_validated_class_bool), typeof(bool), () => true)); - e.Add(new EfEntry("validated-class", "byte", "nested-in-class", typeof(C_E_validated_class_byte.V), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("validated-class", "byte", "top-level", typeof(E_validated_class_byte), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("validated-class", "char", "nested-in-class", typeof(C_E_validated_class_char.V), typeof(char), () => 'a')); - e.Add(new EfEntry("validated-class", "char", "nested-two-levels", typeof(C2_E_validated_class_char.Inner.V), typeof(char), () => 'a')); - e.Add(new EfEntry("validated-class", "double", "nested-in-class", typeof(C_E_validated_class_double.V), typeof(double), () => 1.5)); - e.Add(new EfEntry("validated-class", "double", "nested-two-levels", typeof(C2_E_validated_class_double.Inner.V), typeof(double), () => 1.5)); - e.Add(new EfEntry("validated-class", "enum", "nested-in-struct", typeof(S_E_validated_class_enum.V), typeof(PEnum), () => PEnum.B)); - e.Add(new EfEntry("validated-class", "enum", "nested-two-levels", typeof(C2_E_validated_class_enum.Inner.V), typeof(PEnum), () => PEnum.B)); - e.Add(new EfEntry("validated-class", "flags-enum", "nested-in-class", typeof(C_E_validated_class_flags_enum.V), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("validated-class", "flags-enum", "nested-in-struct", typeof(S_E_validated_class_flags_enum.V), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("validated-class", "flags-enum", "nested-two-levels", typeof(C2_E_validated_class_flags_enum.Inner.V), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("validated-class", "int", "nested-two-levels", typeof(C2_E_validated_class_int.Inner.V), typeof(int), () => 42)); - e.Add(new EfEntry("validated-class", "int", "top-level", typeof(E_validated_class_int), typeof(int), () => 42)); - e.Add(new EfEntry("validated-class", "long", "nested-in-struct", typeof(S_E_validated_class_long.V), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("validated-class", "long", "nested-two-levels", typeof(C2_E_validated_class_long.Inner.V), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("validated-class", "string", "nested-in-struct", typeof(S_E_validated_class_string.V), typeof(string), () => "alpha")); - e.Add(new EfEntry("validated-class", "string", "nested-two-levels", typeof(C2_E_validated_class_string.Inner.V), typeof(string), () => "alpha")); - e.Add(new EfEntry("validated-class", "ulong", "nested-in-struct", typeof(S_E_validated_class_ulong.V), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("validated-class", "ulong", "top-level", typeof(E_validated_class_ulong), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("validated-struct", "DateOnly", "nested-in-class", typeof(C_E_validated_struct_DateOnly.V), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("validated-struct", "DateOnly", "top-level", typeof(E_validated_struct_DateOnly), typeof(DateOnly), () => new DateOnly(2026,10,15))); - e.Add(new EfEntry("validated-struct", "DateTime", "nested-in-class", typeof(C_E_validated_struct_DateTime.V), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("validated-struct", "DateTime", "nested-in-struct", typeof(S_E_validated_struct_DateTime.V), typeof(DateTime), () => new DateTime(2026,10,15,8,30,0,DateTimeKind.Utc))); - e.Add(new EfEntry("validated-struct", "DateTimeOffset", "nested-in-class", typeof(C_E_validated_struct_DateTimeOffset.V), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("validated-struct", "DateTimeOffset", "nested-two-levels", typeof(C2_E_validated_struct_DateTimeOffset.Inner.V), typeof(DateTimeOffset), () => new DateTimeOffset(2026,10,15,8,30,0,TimeSpan.Zero))); - e.Add(new EfEntry("validated-struct", "Guid", "nested-in-class", typeof(C_E_validated_struct_Guid.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-struct", "Guid", "nested-in-struct", typeof(S_E_validated_struct_Guid.V), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-struct", "TimeOnly", "nested-in-struct", typeof(S_E_validated_struct_TimeOnly.V), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("validated-struct", "TimeOnly", "top-level", typeof(E_validated_struct_TimeOnly), typeof(TimeOnly), () => new TimeOnly(8,30,15))); - e.Add(new EfEntry("validated-struct", "TimeSpan", "nested-in-class", typeof(C_E_validated_struct_TimeSpan.V), typeof(TimeSpan), () => TimeSpan.FromMinutes(90))); - e.Add(new EfEntry("validated-struct", "Uri", "top-level", typeof(E_validated_struct_Uri), typeof(Uri), () => new Uri("https://example.com/a"))); - e.Add(new EfEntry("validated-struct", "bool", "nested-in-class", typeof(C_E_validated_struct_bool.V), typeof(bool), () => true)); - e.Add(new EfEntry("validated-struct", "bool", "nested-in-struct", typeof(S_E_validated_struct_bool.V), typeof(bool), () => true)); - e.Add(new EfEntry("validated-struct", "bool", "nested-two-levels", typeof(C2_E_validated_struct_bool.Inner.V), typeof(bool), () => true)); - e.Add(new EfEntry("validated-struct", "byte", "nested-in-struct", typeof(S_E_validated_struct_byte.V), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("validated-struct", "byte", "nested-two-levels", typeof(C2_E_validated_struct_byte.Inner.V), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("validated-struct", "char", "nested-two-levels", typeof(C2_E_validated_struct_char.Inner.V), typeof(char), () => 'a')); - e.Add(new EfEntry("validated-struct", "char", "top-level", typeof(E_validated_struct_char), typeof(char), () => 'a')); - e.Add(new EfEntry("validated-struct", "decimal", "nested-in-class", typeof(C_E_validated_struct_decimal.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("validated-struct", "decimal", "nested-in-struct", typeof(S_E_validated_struct_decimal.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("validated-struct", "decimal", "nested-two-levels", typeof(C2_E_validated_struct_decimal.Inner.V), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("validated-struct", "decimal", "top-level", typeof(E_validated_struct_decimal), typeof(decimal), () => 7.80m)); - e.Add(new EfEntry("validated-struct", "double", "nested-in-class", typeof(C_E_validated_struct_double.V), typeof(double), () => 1.5)); - e.Add(new EfEntry("validated-struct", "double", "top-level", typeof(E_validated_struct_double), typeof(double), () => 1.5)); - e.Add(new EfEntry("validated-struct", "enum", "nested-in-class", typeof(C_E_validated_struct_enum.V), typeof(PEnum), () => PEnum.B)); - e.Add(new EfEntry("validated-struct", "flags-enum", "nested-in-struct", typeof(S_E_validated_struct_flags_enum.V), typeof(PFlags), () => PFlags.P | PFlags.Q)); - e.Add(new EfEntry("validated-struct", "int", "nested-in-class", typeof(C_E_validated_struct_int.V), typeof(int), () => 42)); - e.Add(new EfEntry("validated-struct", "int", "nested-in-struct", typeof(S_E_validated_struct_int.V), typeof(int), () => 42)); - e.Add(new EfEntry("validated-struct", "long", "nested-two-levels", typeof(C2_E_validated_struct_long.Inner.V), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("validated-struct", "long", "top-level", typeof(E_validated_struct_long), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("validated-struct", "string", "nested-two-levels", typeof(C2_E_validated_struct_string.Inner.V), typeof(string), () => "alpha")); - e.Add(new EfEntry("validated-struct", "string", "top-level", typeof(E_validated_struct_string), typeof(string), () => "alpha")); - e.Add(new EfEntry("validated-struct", "ulong", "nested-two-levels", typeof(C2_E_validated_struct_ulong.Inner.V), typeof(ulong), () => 4200000000UL)); - } -} diff --git a/tools/probe/corpus/harness/EfShapes3.cs b/tools/probe/corpus/harness/EfShapes3.cs deleted file mode 100644 index b4b846b7..00000000 --- a/tools/probe/corpus/harness/EfShapes3.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Lookup of the top-level shapes of EfShapes3.g.cs as EfEntry (so MakeVo/Companion work): the complete kind x wrapped grid. -#nullable enable -namespace Probes.Ef3; -public static class E3 -{ - public static Probes.Ef.EfEntry Find(string kind, string wrapped) - { - var (vo, plain) = Reg3.All[(kind, wrapped)]; - var src = Probes.Ef.EfRegistry.All.Where(x => x.Wrapped == wrapped && x.Kind == (kind.StartsWith("validated") ? "validated-struct" : "record-struct")).FirstOrDefault() - ?? Probes.Ef.EfRegistry.All.First(x => x.Wrapped == wrapped); - return new Probes.Ef.EfEntry(kind, wrapped, "top-level", vo, plain, src.Valid); - } -} -public static class E4 -{ - /// The shape at a site; in-generic-type (CMTK1005, refused at build) runs at top-level and says so. - public static Probes.Ef.EfEntry At(Probes.Shapes.Row r, string kind, string wrapped, string site) - { - if (site == "in-generic-type") { r.Substituted("shape.site", "top-level", "CMTK1005: a value object nested in a generic type does not build"); site = "top-level"; } - if (site == "top-level") return E3.Find(kind, wrapped); - var (vo, plain) = Probes.Ef4.Reg4.All[(kind, wrapped, site)]; - var src = Probes.Ef.EfRegistry.All.Where(x => x.Wrapped == wrapped && x.Kind == (kind.StartsWith("validated") ? "validated-struct" : "record-struct")).FirstOrDefault() - ?? Probes.Ef.EfRegistry.All.First(x => x.Wrapped == wrapped); - return new Probes.Ef.EfEntry(kind, wrapped, site, vo, plain, src.Valid); - } -} diff --git a/tools/probe/corpus/harness/EfShapes3.g.cs b/tools/probe/corpus/harness/EfShapes3.g.cs deleted file mode 100644 index ef335f76..00000000 --- a/tools/probe/corpus/harness/EfShapes3.g.cs +++ /dev/null @@ -1,155 +0,0 @@ -// by tools/probe/generators/ef.cs top-level: top-level shapes for every (kind, wrapped) the E03/E09/E10 probes need. Do not edit. -#nullable enable -#pragma warning disable CMTK0014, CS8618, CS1591, CMTK0005, CMTK1000, CMTK0003, CMTK0006, CA1000 -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -using Probes.Shapes; -namespace Probes.Ef3; -public readonly partial record struct X_rs_DateOnly : IValue; -public sealed partial record class X_rc_DateOnly : IValue; -public readonly partial record struct X_vs_DateOnly : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vs_DateOnly(value); } -public sealed partial record class X_vc_DateOnly : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vc_DateOnly(value); } -public readonly partial record struct X_rs_DateTime : IValue; -public sealed partial record class X_rc_DateTime : IValue; -public readonly partial record struct X_vs_DateTime : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vs_DateTime(value); } -public sealed partial record class X_vc_DateTime : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vc_DateTime(value); } -public readonly partial record struct X_rs_DateTimeOffset : IValue; -public sealed partial record class X_rc_DateTimeOffset : IValue; -public readonly partial record struct X_vs_DateTimeOffset : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vs_DateTimeOffset(value); } -public sealed partial record class X_vc_DateTimeOffset : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vc_DateTimeOffset(value); } -public readonly partial record struct X_rs_Guid : IValue; -public sealed partial record class X_rc_Guid : IValue; -public readonly partial record struct X_vs_Guid : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new X_vs_Guid(value); } -public sealed partial record class X_vc_Guid : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new X_vc_Guid(value); } -public readonly partial record struct X_rs_TimeOnly : IValue; -public sealed partial record class X_rc_TimeOnly : IValue; -public readonly partial record struct X_vs_TimeOnly : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vs_TimeOnly(value); } -public sealed partial record class X_vc_TimeOnly : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vc_TimeOnly(value); } -public readonly partial record struct X_rs_TimeSpan : IValue; -public sealed partial record class X_rc_TimeSpan : IValue; -public readonly partial record struct X_vs_TimeSpan : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vs_TimeSpan(value); } -public sealed partial record class X_vc_TimeSpan : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new X_vc_TimeSpan(value); } -public readonly partial record struct X_rs_Uri : IValue; -public sealed partial record class X_rc_Uri : IValue; -public readonly partial record struct X_vs_Uri : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new X_vs_Uri(value); } -public sealed partial record class X_vc_Uri : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new X_vc_Uri(value); } -public readonly partial record struct X_rs_bool : IValue; -public sealed partial record class X_rc_bool : IValue; -public readonly partial record struct X_vs_bool : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new X_vs_bool(value); } -public sealed partial record class X_vc_bool : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new X_vc_bool(value); } -public readonly partial record struct X_rs_byte : IValue; -public sealed partial record class X_rc_byte : IValue; -public readonly partial record struct X_vs_byte : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new X_vs_byte(value); } -public sealed partial record class X_vc_byte : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new X_vc_byte(value); } -public readonly partial record struct X_rs_char : IValue; -public sealed partial record class X_rc_char : IValue; -public readonly partial record struct X_vs_char : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new X_vs_char(value); } -public sealed partial record class X_vc_char : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new X_vc_char(value); } -public readonly partial record struct X_rs_decimal : IValue; -public sealed partial record class X_rc_decimal : IValue; -public readonly partial record struct X_vs_decimal : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new X_vs_decimal(value); } -public sealed partial record class X_vc_decimal : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new X_vc_decimal(value); } -public readonly partial record struct X_rs_double : IValue; -public sealed partial record class X_rc_double : IValue; -public readonly partial record struct X_vs_double : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new X_vs_double(value); } -public sealed partial record class X_vc_double : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new X_vc_double(value); } -public readonly partial record struct X_rs_enum : IValue; -public sealed partial record class X_rc_enum : IValue; -public readonly partial record struct X_vs_enum : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new X_vs_enum(value); } -public sealed partial record class X_vc_enum : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new X_vc_enum(value); } -public readonly partial record struct X_rs_flags_enum : IValue; -public sealed partial record class X_rc_flags_enum : IValue; -public readonly partial record struct X_vs_flags_enum : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new X_vs_flags_enum(value); } -public sealed partial record class X_vc_flags_enum : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new X_vc_flags_enum(value); } -public readonly partial record struct X_rs_int : IValue; -public sealed partial record class X_rc_int : IValue; -public readonly partial record struct X_vs_int : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new X_vs_int(value); } -public sealed partial record class X_vc_int : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new X_vc_int(value); } -public readonly partial record struct X_rs_long : IValue; -public sealed partial record class X_rc_long : IValue; -public readonly partial record struct X_vs_long : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new X_vs_long(value); } -public sealed partial record class X_vc_long : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new X_vc_long(value); } -public readonly partial record struct X_rs_string : IValue; -public sealed partial record class X_rc_string : IValue; -public readonly partial record struct X_vs_string : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new X_vs_string(value); } -public sealed partial record class X_vc_string : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new X_vc_string(value); } -public readonly partial record struct X_rs_ulong : IValue; -public sealed partial record class X_rc_ulong : IValue; -public readonly partial record struct X_vs_ulong : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new X_vs_ulong(value); } -public sealed partial record class X_vc_ulong : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new X_vc_ulong(value); } -public static class Reg3 { - public static readonly Dictionary<(string Kind, string Wrapped), (Type Vo, Type Plain)> All = new() { - [("record-struct", "DateOnly")] = (typeof(X_rs_DateOnly), typeof(DateOnly)), - [("sealed-record-class", "DateOnly")] = (typeof(X_rc_DateOnly), typeof(DateOnly)), - [("validated-struct", "DateOnly")] = (typeof(X_vs_DateOnly), typeof(DateOnly)), - [("validated-class", "DateOnly")] = (typeof(X_vc_DateOnly), typeof(DateOnly)), - [("record-struct", "DateTime")] = (typeof(X_rs_DateTime), typeof(DateTime)), - [("sealed-record-class", "DateTime")] = (typeof(X_rc_DateTime), typeof(DateTime)), - [("validated-struct", "DateTime")] = (typeof(X_vs_DateTime), typeof(DateTime)), - [("validated-class", "DateTime")] = (typeof(X_vc_DateTime), typeof(DateTime)), - [("record-struct", "DateTimeOffset")] = (typeof(X_rs_DateTimeOffset), typeof(DateTimeOffset)), - [("sealed-record-class", "DateTimeOffset")] = (typeof(X_rc_DateTimeOffset), typeof(DateTimeOffset)), - [("validated-struct", "DateTimeOffset")] = (typeof(X_vs_DateTimeOffset), typeof(DateTimeOffset)), - [("validated-class", "DateTimeOffset")] = (typeof(X_vc_DateTimeOffset), typeof(DateTimeOffset)), - [("record-struct", "Guid")] = (typeof(X_rs_Guid), typeof(Guid)), - [("sealed-record-class", "Guid")] = (typeof(X_rc_Guid), typeof(Guid)), - [("validated-struct", "Guid")] = (typeof(X_vs_Guid), typeof(Guid)), - [("validated-class", "Guid")] = (typeof(X_vc_Guid), typeof(Guid)), - [("record-struct", "TimeOnly")] = (typeof(X_rs_TimeOnly), typeof(TimeOnly)), - [("sealed-record-class", "TimeOnly")] = (typeof(X_rc_TimeOnly), typeof(TimeOnly)), - [("validated-struct", "TimeOnly")] = (typeof(X_vs_TimeOnly), typeof(TimeOnly)), - [("validated-class", "TimeOnly")] = (typeof(X_vc_TimeOnly), typeof(TimeOnly)), - [("record-struct", "TimeSpan")] = (typeof(X_rs_TimeSpan), typeof(TimeSpan)), - [("sealed-record-class", "TimeSpan")] = (typeof(X_rc_TimeSpan), typeof(TimeSpan)), - [("validated-struct", "TimeSpan")] = (typeof(X_vs_TimeSpan), typeof(TimeSpan)), - [("validated-class", "TimeSpan")] = (typeof(X_vc_TimeSpan), typeof(TimeSpan)), - [("record-struct", "Uri")] = (typeof(X_rs_Uri), typeof(Uri)), - [("sealed-record-class", "Uri")] = (typeof(X_rc_Uri), typeof(Uri)), - [("validated-struct", "Uri")] = (typeof(X_vs_Uri), typeof(Uri)), - [("validated-class", "Uri")] = (typeof(X_vc_Uri), typeof(Uri)), - [("record-struct", "bool")] = (typeof(X_rs_bool), typeof(bool)), - [("sealed-record-class", "bool")] = (typeof(X_rc_bool), typeof(bool)), - [("validated-struct", "bool")] = (typeof(X_vs_bool), typeof(bool)), - [("validated-class", "bool")] = (typeof(X_vc_bool), typeof(bool)), - [("record-struct", "byte")] = (typeof(X_rs_byte), typeof(byte)), - [("sealed-record-class", "byte")] = (typeof(X_rc_byte), typeof(byte)), - [("validated-struct", "byte")] = (typeof(X_vs_byte), typeof(byte)), - [("validated-class", "byte")] = (typeof(X_vc_byte), typeof(byte)), - [("record-struct", "char")] = (typeof(X_rs_char), typeof(char)), - [("sealed-record-class", "char")] = (typeof(X_rc_char), typeof(char)), - [("validated-struct", "char")] = (typeof(X_vs_char), typeof(char)), - [("validated-class", "char")] = (typeof(X_vc_char), typeof(char)), - [("record-struct", "decimal")] = (typeof(X_rs_decimal), typeof(decimal)), - [("sealed-record-class", "decimal")] = (typeof(X_rc_decimal), typeof(decimal)), - [("validated-struct", "decimal")] = (typeof(X_vs_decimal), typeof(decimal)), - [("validated-class", "decimal")] = (typeof(X_vc_decimal), typeof(decimal)), - [("record-struct", "double")] = (typeof(X_rs_double), typeof(double)), - [("sealed-record-class", "double")] = (typeof(X_rc_double), typeof(double)), - [("validated-struct", "double")] = (typeof(X_vs_double), typeof(double)), - [("validated-class", "double")] = (typeof(X_vc_double), typeof(double)), - [("record-struct", "enum")] = (typeof(X_rs_enum), typeof(PEnum)), - [("sealed-record-class", "enum")] = (typeof(X_rc_enum), typeof(PEnum)), - [("validated-struct", "enum")] = (typeof(X_vs_enum), typeof(PEnum)), - [("validated-class", "enum")] = (typeof(X_vc_enum), typeof(PEnum)), - [("record-struct", "flags-enum")] = (typeof(X_rs_flags_enum), typeof(PFlags)), - [("sealed-record-class", "flags-enum")] = (typeof(X_rc_flags_enum), typeof(PFlags)), - [("validated-struct", "flags-enum")] = (typeof(X_vs_flags_enum), typeof(PFlags)), - [("validated-class", "flags-enum")] = (typeof(X_vc_flags_enum), typeof(PFlags)), - [("record-struct", "int")] = (typeof(X_rs_int), typeof(int)), - [("sealed-record-class", "int")] = (typeof(X_rc_int), typeof(int)), - [("validated-struct", "int")] = (typeof(X_vs_int), typeof(int)), - [("validated-class", "int")] = (typeof(X_vc_int), typeof(int)), - [("record-struct", "long")] = (typeof(X_rs_long), typeof(long)), - [("sealed-record-class", "long")] = (typeof(X_rc_long), typeof(long)), - [("validated-struct", "long")] = (typeof(X_vs_long), typeof(long)), - [("validated-class", "long")] = (typeof(X_vc_long), typeof(long)), - [("record-struct", "string")] = (typeof(X_rs_string), typeof(string)), - [("sealed-record-class", "string")] = (typeof(X_rc_string), typeof(string)), - [("validated-struct", "string")] = (typeof(X_vs_string), typeof(string)), - [("validated-class", "string")] = (typeof(X_vc_string), typeof(string)), - [("record-struct", "ulong")] = (typeof(X_rs_ulong), typeof(ulong)), - [("sealed-record-class", "ulong")] = (typeof(X_rc_ulong), typeof(ulong)), - [("validated-struct", "ulong")] = (typeof(X_vs_ulong), typeof(ulong)), - [("validated-class", "ulong")] = (typeof(X_vc_ulong), typeof(ulong)), - }; -} diff --git a/tools/probe/corpus/harness/EfShapes4.g.cs b/tools/probe/corpus/harness/EfShapes4.g.cs deleted file mode 100644 index 27234211..00000000 --- a/tools/probe/corpus/harness/EfShapes4.g.cs +++ /dev/null @@ -1,443 +0,0 @@ -// by tools/probe/generators/ef.cs nested: nested-site shapes (nested-in-class, nested-in-struct, nested-two-levels) for every kind x wrapped. Do not edit. -#nullable enable -#pragma warning disable CMTK0014, CS8618, CS1591, CMTK0005, CMTK1000, CMTK0003, CMTK0006, CA1000 -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -using Probes.Shapes; -namespace Probes.Ef4; -public static class NC_rs_DateOnly { public readonly partial record struct V : IValue; } -public struct NS_rs_DateOnly { public readonly partial record struct V : IValue; } -public static class N2_rs_DateOnly { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_DateOnly { public sealed partial record class V : IValue; } -public struct NS_rc_DateOnly { public sealed partial record class V : IValue; } -public static class N2_rc_DateOnly { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_DateOnly { public readonly partial record struct V : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_DateOnly { public readonly partial record struct V : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_DateOnly { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_DateOnly { public sealed partial record class V : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_DateOnly { public sealed partial record class V : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_DateOnly { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(DateOnly value) => EqualityComparer.Default.Equals(value, DateOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_DateTime { public readonly partial record struct V : IValue; } -public struct NS_rs_DateTime { public readonly partial record struct V : IValue; } -public static class N2_rs_DateTime { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_DateTime { public sealed partial record class V : IValue; } -public struct NS_rc_DateTime { public sealed partial record class V : IValue; } -public static class N2_rc_DateTime { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_DateTime { public readonly partial record struct V : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_DateTime { public readonly partial record struct V : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_DateTime { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_DateTime { public sealed partial record class V : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_DateTime { public sealed partial record class V : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_DateTime { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(DateTime value) => EqualityComparer.Default.Equals(value, DateTime.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_DateTimeOffset { public readonly partial record struct V : IValue; } -public struct NS_rs_DateTimeOffset { public readonly partial record struct V : IValue; } -public static class N2_rs_DateTimeOffset { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_DateTimeOffset { public sealed partial record class V : IValue; } -public struct NS_rc_DateTimeOffset { public sealed partial record class V : IValue; } -public static class N2_rc_DateTimeOffset { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_DateTimeOffset { public readonly partial record struct V : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_DateTimeOffset { public readonly partial record struct V : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_DateTimeOffset { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_DateTimeOffset { public sealed partial record class V : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_DateTimeOffset { public sealed partial record class V : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_DateTimeOffset { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(DateTimeOffset value) => EqualityComparer.Default.Equals(value, DateTimeOffset.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_Guid { public readonly partial record struct V : IValue; } -public struct NS_rs_Guid { public readonly partial record struct V : IValue; } -public static class N2_rs_Guid { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_Guid { public sealed partial record class V : IValue; } -public struct NS_rc_Guid { public sealed partial record class V : IValue; } -public static class N2_rc_Guid { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_Guid { public readonly partial record struct V : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_Guid { public readonly partial record struct V : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_Guid { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_Guid { public sealed partial record class V : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_Guid { public sealed partial record class V : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_Guid { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(Guid value) => EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_TimeOnly { public readonly partial record struct V : IValue; } -public struct NS_rs_TimeOnly { public readonly partial record struct V : IValue; } -public static class N2_rs_TimeOnly { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_TimeOnly { public sealed partial record class V : IValue; } -public struct NS_rc_TimeOnly { public sealed partial record class V : IValue; } -public static class N2_rc_TimeOnly { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_TimeOnly { public readonly partial record struct V : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_TimeOnly { public readonly partial record struct V : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_TimeOnly { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_TimeOnly { public sealed partial record class V : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_TimeOnly { public sealed partial record class V : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_TimeOnly { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(TimeOnly value) => EqualityComparer.Default.Equals(value, TimeOnly.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_TimeSpan { public readonly partial record struct V : IValue; } -public struct NS_rs_TimeSpan { public readonly partial record struct V : IValue; } -public static class N2_rs_TimeSpan { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_TimeSpan { public sealed partial record class V : IValue; } -public struct NS_rc_TimeSpan { public sealed partial record class V : IValue; } -public static class N2_rc_TimeSpan { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_TimeSpan { public readonly partial record struct V : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_TimeSpan { public readonly partial record struct V : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_TimeSpan { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_TimeSpan { public sealed partial record class V : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_TimeSpan { public sealed partial record class V : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_TimeSpan { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(TimeSpan value) => EqualityComparer.Default.Equals(value, TimeSpan.MinValue) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_Uri { public readonly partial record struct V : IValue; } -public struct NS_rs_Uri { public readonly partial record struct V : IValue; } -public static class N2_rs_Uri { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_Uri { public sealed partial record class V : IValue; } -public struct NS_rc_Uri { public sealed partial record class V : IValue; } -public static class N2_rc_Uri { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_Uri { public readonly partial record struct V : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_Uri { public readonly partial record struct V : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_Uri { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_Uri { public sealed partial record class V : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_Uri { public sealed partial record class V : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_Uri { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(Uri value) => EqualityComparer.Default.Equals(value, new Uri("https://example.com/refused")) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_bool { public readonly partial record struct V : IValue; } -public struct NS_rs_bool { public readonly partial record struct V : IValue; } -public static class N2_rs_bool { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_bool { public sealed partial record class V : IValue; } -public struct NS_rc_bool { public sealed partial record class V : IValue; } -public static class N2_rc_bool { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_bool { public readonly partial record struct V : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_bool { public readonly partial record struct V : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_bool { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_bool { public sealed partial record class V : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_bool { public sealed partial record class V : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_bool { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(bool value) => EqualityComparer.Default.Equals(value, false) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_byte { public readonly partial record struct V : IValue; } -public struct NS_rs_byte { public readonly partial record struct V : IValue; } -public static class N2_rs_byte { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_byte { public sealed partial record class V : IValue; } -public struct NS_rc_byte { public sealed partial record class V : IValue; } -public static class N2_rc_byte { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_byte { public readonly partial record struct V : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_byte { public readonly partial record struct V : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_byte { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_byte { public sealed partial record class V : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_byte { public sealed partial record class V : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_byte { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(byte value) => EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_char { public readonly partial record struct V : IValue; } -public struct NS_rs_char { public readonly partial record struct V : IValue; } -public static class N2_rs_char { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_char { public sealed partial record class V : IValue; } -public struct NS_rc_char { public sealed partial record class V : IValue; } -public static class N2_rc_char { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_char { public readonly partial record struct V : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_char { public readonly partial record struct V : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_char { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_char { public sealed partial record class V : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_char { public sealed partial record class V : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_char { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(char value) => EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_decimal { public readonly partial record struct V : IValue; } -public struct NS_rs_decimal { public readonly partial record struct V : IValue; } -public static class N2_rs_decimal { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_decimal { public sealed partial record class V : IValue; } -public struct NS_rc_decimal { public sealed partial record class V : IValue; } -public static class N2_rc_decimal { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_decimal { public readonly partial record struct V : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_decimal { public readonly partial record struct V : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_decimal { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_decimal { public sealed partial record class V : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_decimal { public sealed partial record class V : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_decimal { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(decimal value) => EqualityComparer.Default.Equals(value, -1m) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_double { public readonly partial record struct V : IValue; } -public struct NS_rs_double { public readonly partial record struct V : IValue; } -public static class N2_rs_double { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_double { public sealed partial record class V : IValue; } -public struct NS_rc_double { public sealed partial record class V : IValue; } -public static class N2_rc_double { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_double { public readonly partial record struct V : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_double { public readonly partial record struct V : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_double { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_double { public sealed partial record class V : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_double { public sealed partial record class V : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_double { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(double value) => EqualityComparer.Default.Equals(value, -1.0) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_enum { public readonly partial record struct V : IValue; } -public struct NS_rs_enum { public readonly partial record struct V : IValue; } -public static class N2_rs_enum { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_enum { public sealed partial record class V : IValue; } -public struct NS_rc_enum { public sealed partial record class V : IValue; } -public static class N2_rc_enum { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_enum { public readonly partial record struct V : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_enum { public readonly partial record struct V : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_enum { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_enum { public sealed partial record class V : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_enum { public sealed partial record class V : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_enum { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(PEnum value) => EqualityComparer.Default.Equals(value, (PEnum)99) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_flags_enum { public readonly partial record struct V : IValue; } -public struct NS_rs_flags_enum { public readonly partial record struct V : IValue; } -public static class N2_rs_flags_enum { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_flags_enum { public sealed partial record class V : IValue; } -public struct NS_rc_flags_enum { public sealed partial record class V : IValue; } -public static class N2_rc_flags_enum { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_flags_enum { public readonly partial record struct V : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_flags_enum { public readonly partial record struct V : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_flags_enum { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_flags_enum { public sealed partial record class V : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_flags_enum { public sealed partial record class V : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_flags_enum { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(PFlags value) => EqualityComparer.Default.Equals(value, (PFlags)0) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_int { public readonly partial record struct V : IValue; } -public struct NS_rs_int { public readonly partial record struct V : IValue; } -public static class N2_rs_int { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_int { public sealed partial record class V : IValue; } -public struct NS_rc_int { public sealed partial record class V : IValue; } -public static class N2_rc_int { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_int { public readonly partial record struct V : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_int { public readonly partial record struct V : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_int { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_int { public sealed partial record class V : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_int { public sealed partial record class V : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_int { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(int value) => EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_long { public readonly partial record struct V : IValue; } -public struct NS_rs_long { public readonly partial record struct V : IValue; } -public static class N2_rs_long { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_long { public sealed partial record class V : IValue; } -public struct NS_rc_long { public sealed partial record class V : IValue; } -public static class N2_rc_long { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_long { public readonly partial record struct V : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_long { public readonly partial record struct V : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_long { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_long { public sealed partial record class V : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_long { public sealed partial record class V : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_long { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(long value) => EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_string { public readonly partial record struct V : IValue; } -public struct NS_rs_string { public readonly partial record struct V : IValue; } -public static class N2_rs_string { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_string { public sealed partial record class V : IValue; } -public struct NS_rc_string { public sealed partial record class V : IValue; } -public static class N2_rc_string { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_string { public readonly partial record struct V : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_string { public readonly partial record struct V : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_string { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_string { public sealed partial record class V : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_string { public sealed partial record class V : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_string { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(string value) => EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_rs_ulong { public readonly partial record struct V : IValue; } -public struct NS_rs_ulong { public readonly partial record struct V : IValue; } -public static class N2_rs_ulong { public static class Inner { public readonly partial record struct V : IValue; } } -public static class NC_rc_ulong { public sealed partial record class V : IValue; } -public struct NS_rc_ulong { public sealed partial record class V : IValue; } -public static class N2_rc_ulong { public static class Inner { public sealed partial record class V : IValue; } } -public static class NC_vs_ulong { public readonly partial record struct V : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vs_ulong { public readonly partial record struct V : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vs_ulong { public static class Inner { public readonly partial record struct V : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class NC_vc_ulong { public sealed partial record class V : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public struct NS_vc_ulong { public sealed partial record class V : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); } } -public static class N2_vc_ulong { public static class Inner { public sealed partial record class V : IValidatedValue { public static Result Create(ulong value) => EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new V(value); } } } -public static class Reg4 { - public static readonly Dictionary<(string Kind, string Wrapped, string Site), (Type Vo, Type Plain)> All = new() { - [("record-struct", "DateOnly", "nested-in-class")] = (typeof(NC_rs_DateOnly.V), typeof(DateOnly)), - [("record-struct", "DateOnly", "nested-in-struct")] = (typeof(NS_rs_DateOnly.V), typeof(DateOnly)), - [("record-struct", "DateOnly", "nested-two-levels")] = (typeof(N2_rs_DateOnly.Inner.V), typeof(DateOnly)), - [("sealed-record-class", "DateOnly", "nested-in-class")] = (typeof(NC_rc_DateOnly.V), typeof(DateOnly)), - [("sealed-record-class", "DateOnly", "nested-in-struct")] = (typeof(NS_rc_DateOnly.V), typeof(DateOnly)), - [("sealed-record-class", "DateOnly", "nested-two-levels")] = (typeof(N2_rc_DateOnly.Inner.V), typeof(DateOnly)), - [("validated-struct", "DateOnly", "nested-in-class")] = (typeof(NC_vs_DateOnly.V), typeof(DateOnly)), - [("validated-struct", "DateOnly", "nested-in-struct")] = (typeof(NS_vs_DateOnly.V), typeof(DateOnly)), - [("validated-struct", "DateOnly", "nested-two-levels")] = (typeof(N2_vs_DateOnly.Inner.V), typeof(DateOnly)), - [("validated-class", "DateOnly", "nested-in-class")] = (typeof(NC_vc_DateOnly.V), typeof(DateOnly)), - [("validated-class", "DateOnly", "nested-in-struct")] = (typeof(NS_vc_DateOnly.V), typeof(DateOnly)), - [("validated-class", "DateOnly", "nested-two-levels")] = (typeof(N2_vc_DateOnly.Inner.V), typeof(DateOnly)), - [("record-struct", "DateTime", "nested-in-class")] = (typeof(NC_rs_DateTime.V), typeof(DateTime)), - [("record-struct", "DateTime", "nested-in-struct")] = (typeof(NS_rs_DateTime.V), typeof(DateTime)), - [("record-struct", "DateTime", "nested-two-levels")] = (typeof(N2_rs_DateTime.Inner.V), typeof(DateTime)), - [("sealed-record-class", "DateTime", "nested-in-class")] = (typeof(NC_rc_DateTime.V), typeof(DateTime)), - [("sealed-record-class", "DateTime", "nested-in-struct")] = (typeof(NS_rc_DateTime.V), typeof(DateTime)), - [("sealed-record-class", "DateTime", "nested-two-levels")] = (typeof(N2_rc_DateTime.Inner.V), typeof(DateTime)), - [("validated-struct", "DateTime", "nested-in-class")] = (typeof(NC_vs_DateTime.V), typeof(DateTime)), - [("validated-struct", "DateTime", "nested-in-struct")] = (typeof(NS_vs_DateTime.V), typeof(DateTime)), - [("validated-struct", "DateTime", "nested-two-levels")] = (typeof(N2_vs_DateTime.Inner.V), typeof(DateTime)), - [("validated-class", "DateTime", "nested-in-class")] = (typeof(NC_vc_DateTime.V), typeof(DateTime)), - [("validated-class", "DateTime", "nested-in-struct")] = (typeof(NS_vc_DateTime.V), typeof(DateTime)), - [("validated-class", "DateTime", "nested-two-levels")] = (typeof(N2_vc_DateTime.Inner.V), typeof(DateTime)), - [("record-struct", "DateTimeOffset", "nested-in-class")] = (typeof(NC_rs_DateTimeOffset.V), typeof(DateTimeOffset)), - [("record-struct", "DateTimeOffset", "nested-in-struct")] = (typeof(NS_rs_DateTimeOffset.V), typeof(DateTimeOffset)), - [("record-struct", "DateTimeOffset", "nested-two-levels")] = (typeof(N2_rs_DateTimeOffset.Inner.V), typeof(DateTimeOffset)), - [("sealed-record-class", "DateTimeOffset", "nested-in-class")] = (typeof(NC_rc_DateTimeOffset.V), typeof(DateTimeOffset)), - [("sealed-record-class", "DateTimeOffset", "nested-in-struct")] = (typeof(NS_rc_DateTimeOffset.V), typeof(DateTimeOffset)), - [("sealed-record-class", "DateTimeOffset", "nested-two-levels")] = (typeof(N2_rc_DateTimeOffset.Inner.V), typeof(DateTimeOffset)), - [("validated-struct", "DateTimeOffset", "nested-in-class")] = (typeof(NC_vs_DateTimeOffset.V), typeof(DateTimeOffset)), - [("validated-struct", "DateTimeOffset", "nested-in-struct")] = (typeof(NS_vs_DateTimeOffset.V), typeof(DateTimeOffset)), - [("validated-struct", "DateTimeOffset", "nested-two-levels")] = (typeof(N2_vs_DateTimeOffset.Inner.V), typeof(DateTimeOffset)), - [("validated-class", "DateTimeOffset", "nested-in-class")] = (typeof(NC_vc_DateTimeOffset.V), typeof(DateTimeOffset)), - [("validated-class", "DateTimeOffset", "nested-in-struct")] = (typeof(NS_vc_DateTimeOffset.V), typeof(DateTimeOffset)), - [("validated-class", "DateTimeOffset", "nested-two-levels")] = (typeof(N2_vc_DateTimeOffset.Inner.V), typeof(DateTimeOffset)), - [("record-struct", "Guid", "nested-in-class")] = (typeof(NC_rs_Guid.V), typeof(Guid)), - [("record-struct", "Guid", "nested-in-struct")] = (typeof(NS_rs_Guid.V), typeof(Guid)), - [("record-struct", "Guid", "nested-two-levels")] = (typeof(N2_rs_Guid.Inner.V), typeof(Guid)), - [("sealed-record-class", "Guid", "nested-in-class")] = (typeof(NC_rc_Guid.V), typeof(Guid)), - [("sealed-record-class", "Guid", "nested-in-struct")] = (typeof(NS_rc_Guid.V), typeof(Guid)), - [("sealed-record-class", "Guid", "nested-two-levels")] = (typeof(N2_rc_Guid.Inner.V), typeof(Guid)), - [("validated-struct", "Guid", "nested-in-class")] = (typeof(NC_vs_Guid.V), typeof(Guid)), - [("validated-struct", "Guid", "nested-in-struct")] = (typeof(NS_vs_Guid.V), typeof(Guid)), - [("validated-struct", "Guid", "nested-two-levels")] = (typeof(N2_vs_Guid.Inner.V), typeof(Guid)), - [("validated-class", "Guid", "nested-in-class")] = (typeof(NC_vc_Guid.V), typeof(Guid)), - [("validated-class", "Guid", "nested-in-struct")] = (typeof(NS_vc_Guid.V), typeof(Guid)), - [("validated-class", "Guid", "nested-two-levels")] = (typeof(N2_vc_Guid.Inner.V), typeof(Guid)), - [("record-struct", "TimeOnly", "nested-in-class")] = (typeof(NC_rs_TimeOnly.V), typeof(TimeOnly)), - [("record-struct", "TimeOnly", "nested-in-struct")] = (typeof(NS_rs_TimeOnly.V), typeof(TimeOnly)), - [("record-struct", "TimeOnly", "nested-two-levels")] = (typeof(N2_rs_TimeOnly.Inner.V), typeof(TimeOnly)), - [("sealed-record-class", "TimeOnly", "nested-in-class")] = (typeof(NC_rc_TimeOnly.V), typeof(TimeOnly)), - [("sealed-record-class", "TimeOnly", "nested-in-struct")] = (typeof(NS_rc_TimeOnly.V), typeof(TimeOnly)), - [("sealed-record-class", "TimeOnly", "nested-two-levels")] = (typeof(N2_rc_TimeOnly.Inner.V), typeof(TimeOnly)), - [("validated-struct", "TimeOnly", "nested-in-class")] = (typeof(NC_vs_TimeOnly.V), typeof(TimeOnly)), - [("validated-struct", "TimeOnly", "nested-in-struct")] = (typeof(NS_vs_TimeOnly.V), typeof(TimeOnly)), - [("validated-struct", "TimeOnly", "nested-two-levels")] = (typeof(N2_vs_TimeOnly.Inner.V), typeof(TimeOnly)), - [("validated-class", "TimeOnly", "nested-in-class")] = (typeof(NC_vc_TimeOnly.V), typeof(TimeOnly)), - [("validated-class", "TimeOnly", "nested-in-struct")] = (typeof(NS_vc_TimeOnly.V), typeof(TimeOnly)), - [("validated-class", "TimeOnly", "nested-two-levels")] = (typeof(N2_vc_TimeOnly.Inner.V), typeof(TimeOnly)), - [("record-struct", "TimeSpan", "nested-in-class")] = (typeof(NC_rs_TimeSpan.V), typeof(TimeSpan)), - [("record-struct", "TimeSpan", "nested-in-struct")] = (typeof(NS_rs_TimeSpan.V), typeof(TimeSpan)), - [("record-struct", "TimeSpan", "nested-two-levels")] = (typeof(N2_rs_TimeSpan.Inner.V), typeof(TimeSpan)), - [("sealed-record-class", "TimeSpan", "nested-in-class")] = (typeof(NC_rc_TimeSpan.V), typeof(TimeSpan)), - [("sealed-record-class", "TimeSpan", "nested-in-struct")] = (typeof(NS_rc_TimeSpan.V), typeof(TimeSpan)), - [("sealed-record-class", "TimeSpan", "nested-two-levels")] = (typeof(N2_rc_TimeSpan.Inner.V), typeof(TimeSpan)), - [("validated-struct", "TimeSpan", "nested-in-class")] = (typeof(NC_vs_TimeSpan.V), typeof(TimeSpan)), - [("validated-struct", "TimeSpan", "nested-in-struct")] = (typeof(NS_vs_TimeSpan.V), typeof(TimeSpan)), - [("validated-struct", "TimeSpan", "nested-two-levels")] = (typeof(N2_vs_TimeSpan.Inner.V), typeof(TimeSpan)), - [("validated-class", "TimeSpan", "nested-in-class")] = (typeof(NC_vc_TimeSpan.V), typeof(TimeSpan)), - [("validated-class", "TimeSpan", "nested-in-struct")] = (typeof(NS_vc_TimeSpan.V), typeof(TimeSpan)), - [("validated-class", "TimeSpan", "nested-two-levels")] = (typeof(N2_vc_TimeSpan.Inner.V), typeof(TimeSpan)), - [("record-struct", "Uri", "nested-in-class")] = (typeof(NC_rs_Uri.V), typeof(Uri)), - [("record-struct", "Uri", "nested-in-struct")] = (typeof(NS_rs_Uri.V), typeof(Uri)), - [("record-struct", "Uri", "nested-two-levels")] = (typeof(N2_rs_Uri.Inner.V), typeof(Uri)), - [("sealed-record-class", "Uri", "nested-in-class")] = (typeof(NC_rc_Uri.V), typeof(Uri)), - [("sealed-record-class", "Uri", "nested-in-struct")] = (typeof(NS_rc_Uri.V), typeof(Uri)), - [("sealed-record-class", "Uri", "nested-two-levels")] = (typeof(N2_rc_Uri.Inner.V), typeof(Uri)), - [("validated-struct", "Uri", "nested-in-class")] = (typeof(NC_vs_Uri.V), typeof(Uri)), - [("validated-struct", "Uri", "nested-in-struct")] = (typeof(NS_vs_Uri.V), typeof(Uri)), - [("validated-struct", "Uri", "nested-two-levels")] = (typeof(N2_vs_Uri.Inner.V), typeof(Uri)), - [("validated-class", "Uri", "nested-in-class")] = (typeof(NC_vc_Uri.V), typeof(Uri)), - [("validated-class", "Uri", "nested-in-struct")] = (typeof(NS_vc_Uri.V), typeof(Uri)), - [("validated-class", "Uri", "nested-two-levels")] = (typeof(N2_vc_Uri.Inner.V), typeof(Uri)), - [("record-struct", "bool", "nested-in-class")] = (typeof(NC_rs_bool.V), typeof(bool)), - [("record-struct", "bool", "nested-in-struct")] = (typeof(NS_rs_bool.V), typeof(bool)), - [("record-struct", "bool", "nested-two-levels")] = (typeof(N2_rs_bool.Inner.V), typeof(bool)), - [("sealed-record-class", "bool", "nested-in-class")] = (typeof(NC_rc_bool.V), typeof(bool)), - [("sealed-record-class", "bool", "nested-in-struct")] = (typeof(NS_rc_bool.V), typeof(bool)), - [("sealed-record-class", "bool", "nested-two-levels")] = (typeof(N2_rc_bool.Inner.V), typeof(bool)), - [("validated-struct", "bool", "nested-in-class")] = (typeof(NC_vs_bool.V), typeof(bool)), - [("validated-struct", "bool", "nested-in-struct")] = (typeof(NS_vs_bool.V), typeof(bool)), - [("validated-struct", "bool", "nested-two-levels")] = (typeof(N2_vs_bool.Inner.V), typeof(bool)), - [("validated-class", "bool", "nested-in-class")] = (typeof(NC_vc_bool.V), typeof(bool)), - [("validated-class", "bool", "nested-in-struct")] = (typeof(NS_vc_bool.V), typeof(bool)), - [("validated-class", "bool", "nested-two-levels")] = (typeof(N2_vc_bool.Inner.V), typeof(bool)), - [("record-struct", "byte", "nested-in-class")] = (typeof(NC_rs_byte.V), typeof(byte)), - [("record-struct", "byte", "nested-in-struct")] = (typeof(NS_rs_byte.V), typeof(byte)), - [("record-struct", "byte", "nested-two-levels")] = (typeof(N2_rs_byte.Inner.V), typeof(byte)), - [("sealed-record-class", "byte", "nested-in-class")] = (typeof(NC_rc_byte.V), typeof(byte)), - [("sealed-record-class", "byte", "nested-in-struct")] = (typeof(NS_rc_byte.V), typeof(byte)), - [("sealed-record-class", "byte", "nested-two-levels")] = (typeof(N2_rc_byte.Inner.V), typeof(byte)), - [("validated-struct", "byte", "nested-in-class")] = (typeof(NC_vs_byte.V), typeof(byte)), - [("validated-struct", "byte", "nested-in-struct")] = (typeof(NS_vs_byte.V), typeof(byte)), - [("validated-struct", "byte", "nested-two-levels")] = (typeof(N2_vs_byte.Inner.V), typeof(byte)), - [("validated-class", "byte", "nested-in-class")] = (typeof(NC_vc_byte.V), typeof(byte)), - [("validated-class", "byte", "nested-in-struct")] = (typeof(NS_vc_byte.V), typeof(byte)), - [("validated-class", "byte", "nested-two-levels")] = (typeof(N2_vc_byte.Inner.V), typeof(byte)), - [("record-struct", "char", "nested-in-class")] = (typeof(NC_rs_char.V), typeof(char)), - [("record-struct", "char", "nested-in-struct")] = (typeof(NS_rs_char.V), typeof(char)), - [("record-struct", "char", "nested-two-levels")] = (typeof(N2_rs_char.Inner.V), typeof(char)), - [("sealed-record-class", "char", "nested-in-class")] = (typeof(NC_rc_char.V), typeof(char)), - [("sealed-record-class", "char", "nested-in-struct")] = (typeof(NS_rc_char.V), typeof(char)), - [("sealed-record-class", "char", "nested-two-levels")] = (typeof(N2_rc_char.Inner.V), typeof(char)), - [("validated-struct", "char", "nested-in-class")] = (typeof(NC_vs_char.V), typeof(char)), - [("validated-struct", "char", "nested-in-struct")] = (typeof(NS_vs_char.V), typeof(char)), - [("validated-struct", "char", "nested-two-levels")] = (typeof(N2_vs_char.Inner.V), typeof(char)), - [("validated-class", "char", "nested-in-class")] = (typeof(NC_vc_char.V), typeof(char)), - [("validated-class", "char", "nested-in-struct")] = (typeof(NS_vc_char.V), typeof(char)), - [("validated-class", "char", "nested-two-levels")] = (typeof(N2_vc_char.Inner.V), typeof(char)), - [("record-struct", "decimal", "nested-in-class")] = (typeof(NC_rs_decimal.V), typeof(decimal)), - [("record-struct", "decimal", "nested-in-struct")] = (typeof(NS_rs_decimal.V), typeof(decimal)), - [("record-struct", "decimal", "nested-two-levels")] = (typeof(N2_rs_decimal.Inner.V), typeof(decimal)), - [("sealed-record-class", "decimal", "nested-in-class")] = (typeof(NC_rc_decimal.V), typeof(decimal)), - [("sealed-record-class", "decimal", "nested-in-struct")] = (typeof(NS_rc_decimal.V), typeof(decimal)), - [("sealed-record-class", "decimal", "nested-two-levels")] = (typeof(N2_rc_decimal.Inner.V), typeof(decimal)), - [("validated-struct", "decimal", "nested-in-class")] = (typeof(NC_vs_decimal.V), typeof(decimal)), - [("validated-struct", "decimal", "nested-in-struct")] = (typeof(NS_vs_decimal.V), typeof(decimal)), - [("validated-struct", "decimal", "nested-two-levels")] = (typeof(N2_vs_decimal.Inner.V), typeof(decimal)), - [("validated-class", "decimal", "nested-in-class")] = (typeof(NC_vc_decimal.V), typeof(decimal)), - [("validated-class", "decimal", "nested-in-struct")] = (typeof(NS_vc_decimal.V), typeof(decimal)), - [("validated-class", "decimal", "nested-two-levels")] = (typeof(N2_vc_decimal.Inner.V), typeof(decimal)), - [("record-struct", "double", "nested-in-class")] = (typeof(NC_rs_double.V), typeof(double)), - [("record-struct", "double", "nested-in-struct")] = (typeof(NS_rs_double.V), typeof(double)), - [("record-struct", "double", "nested-two-levels")] = (typeof(N2_rs_double.Inner.V), typeof(double)), - [("sealed-record-class", "double", "nested-in-class")] = (typeof(NC_rc_double.V), typeof(double)), - [("sealed-record-class", "double", "nested-in-struct")] = (typeof(NS_rc_double.V), typeof(double)), - [("sealed-record-class", "double", "nested-two-levels")] = (typeof(N2_rc_double.Inner.V), typeof(double)), - [("validated-struct", "double", "nested-in-class")] = (typeof(NC_vs_double.V), typeof(double)), - [("validated-struct", "double", "nested-in-struct")] = (typeof(NS_vs_double.V), typeof(double)), - [("validated-struct", "double", "nested-two-levels")] = (typeof(N2_vs_double.Inner.V), typeof(double)), - [("validated-class", "double", "nested-in-class")] = (typeof(NC_vc_double.V), typeof(double)), - [("validated-class", "double", "nested-in-struct")] = (typeof(NS_vc_double.V), typeof(double)), - [("validated-class", "double", "nested-two-levels")] = (typeof(N2_vc_double.Inner.V), typeof(double)), - [("record-struct", "enum", "nested-in-class")] = (typeof(NC_rs_enum.V), typeof(PEnum)), - [("record-struct", "enum", "nested-in-struct")] = (typeof(NS_rs_enum.V), typeof(PEnum)), - [("record-struct", "enum", "nested-two-levels")] = (typeof(N2_rs_enum.Inner.V), typeof(PEnum)), - [("sealed-record-class", "enum", "nested-in-class")] = (typeof(NC_rc_enum.V), typeof(PEnum)), - [("sealed-record-class", "enum", "nested-in-struct")] = (typeof(NS_rc_enum.V), typeof(PEnum)), - [("sealed-record-class", "enum", "nested-two-levels")] = (typeof(N2_rc_enum.Inner.V), typeof(PEnum)), - [("validated-struct", "enum", "nested-in-class")] = (typeof(NC_vs_enum.V), typeof(PEnum)), - [("validated-struct", "enum", "nested-in-struct")] = (typeof(NS_vs_enum.V), typeof(PEnum)), - [("validated-struct", "enum", "nested-two-levels")] = (typeof(N2_vs_enum.Inner.V), typeof(PEnum)), - [("validated-class", "enum", "nested-in-class")] = (typeof(NC_vc_enum.V), typeof(PEnum)), - [("validated-class", "enum", "nested-in-struct")] = (typeof(NS_vc_enum.V), typeof(PEnum)), - [("validated-class", "enum", "nested-two-levels")] = (typeof(N2_vc_enum.Inner.V), typeof(PEnum)), - [("record-struct", "flags-enum", "nested-in-class")] = (typeof(NC_rs_flags_enum.V), typeof(PFlags)), - [("record-struct", "flags-enum", "nested-in-struct")] = (typeof(NS_rs_flags_enum.V), typeof(PFlags)), - [("record-struct", "flags-enum", "nested-two-levels")] = (typeof(N2_rs_flags_enum.Inner.V), typeof(PFlags)), - [("sealed-record-class", "flags-enum", "nested-in-class")] = (typeof(NC_rc_flags_enum.V), typeof(PFlags)), - [("sealed-record-class", "flags-enum", "nested-in-struct")] = (typeof(NS_rc_flags_enum.V), typeof(PFlags)), - [("sealed-record-class", "flags-enum", "nested-two-levels")] = (typeof(N2_rc_flags_enum.Inner.V), typeof(PFlags)), - [("validated-struct", "flags-enum", "nested-in-class")] = (typeof(NC_vs_flags_enum.V), typeof(PFlags)), - [("validated-struct", "flags-enum", "nested-in-struct")] = (typeof(NS_vs_flags_enum.V), typeof(PFlags)), - [("validated-struct", "flags-enum", "nested-two-levels")] = (typeof(N2_vs_flags_enum.Inner.V), typeof(PFlags)), - [("validated-class", "flags-enum", "nested-in-class")] = (typeof(NC_vc_flags_enum.V), typeof(PFlags)), - [("validated-class", "flags-enum", "nested-in-struct")] = (typeof(NS_vc_flags_enum.V), typeof(PFlags)), - [("validated-class", "flags-enum", "nested-two-levels")] = (typeof(N2_vc_flags_enum.Inner.V), typeof(PFlags)), - [("record-struct", "int", "nested-in-class")] = (typeof(NC_rs_int.V), typeof(int)), - [("record-struct", "int", "nested-in-struct")] = (typeof(NS_rs_int.V), typeof(int)), - [("record-struct", "int", "nested-two-levels")] = (typeof(N2_rs_int.Inner.V), typeof(int)), - [("sealed-record-class", "int", "nested-in-class")] = (typeof(NC_rc_int.V), typeof(int)), - [("sealed-record-class", "int", "nested-in-struct")] = (typeof(NS_rc_int.V), typeof(int)), - [("sealed-record-class", "int", "nested-two-levels")] = (typeof(N2_rc_int.Inner.V), typeof(int)), - [("validated-struct", "int", "nested-in-class")] = (typeof(NC_vs_int.V), typeof(int)), - [("validated-struct", "int", "nested-in-struct")] = (typeof(NS_vs_int.V), typeof(int)), - [("validated-struct", "int", "nested-two-levels")] = (typeof(N2_vs_int.Inner.V), typeof(int)), - [("validated-class", "int", "nested-in-class")] = (typeof(NC_vc_int.V), typeof(int)), - [("validated-class", "int", "nested-in-struct")] = (typeof(NS_vc_int.V), typeof(int)), - [("validated-class", "int", "nested-two-levels")] = (typeof(N2_vc_int.Inner.V), typeof(int)), - [("record-struct", "long", "nested-in-class")] = (typeof(NC_rs_long.V), typeof(long)), - [("record-struct", "long", "nested-in-struct")] = (typeof(NS_rs_long.V), typeof(long)), - [("record-struct", "long", "nested-two-levels")] = (typeof(N2_rs_long.Inner.V), typeof(long)), - [("sealed-record-class", "long", "nested-in-class")] = (typeof(NC_rc_long.V), typeof(long)), - [("sealed-record-class", "long", "nested-in-struct")] = (typeof(NS_rc_long.V), typeof(long)), - [("sealed-record-class", "long", "nested-two-levels")] = (typeof(N2_rc_long.Inner.V), typeof(long)), - [("validated-struct", "long", "nested-in-class")] = (typeof(NC_vs_long.V), typeof(long)), - [("validated-struct", "long", "nested-in-struct")] = (typeof(NS_vs_long.V), typeof(long)), - [("validated-struct", "long", "nested-two-levels")] = (typeof(N2_vs_long.Inner.V), typeof(long)), - [("validated-class", "long", "nested-in-class")] = (typeof(NC_vc_long.V), typeof(long)), - [("validated-class", "long", "nested-in-struct")] = (typeof(NS_vc_long.V), typeof(long)), - [("validated-class", "long", "nested-two-levels")] = (typeof(N2_vc_long.Inner.V), typeof(long)), - [("record-struct", "string", "nested-in-class")] = (typeof(NC_rs_string.V), typeof(string)), - [("record-struct", "string", "nested-in-struct")] = (typeof(NS_rs_string.V), typeof(string)), - [("record-struct", "string", "nested-two-levels")] = (typeof(N2_rs_string.Inner.V), typeof(string)), - [("sealed-record-class", "string", "nested-in-class")] = (typeof(NC_rc_string.V), typeof(string)), - [("sealed-record-class", "string", "nested-in-struct")] = (typeof(NS_rc_string.V), typeof(string)), - [("sealed-record-class", "string", "nested-two-levels")] = (typeof(N2_rc_string.Inner.V), typeof(string)), - [("validated-struct", "string", "nested-in-class")] = (typeof(NC_vs_string.V), typeof(string)), - [("validated-struct", "string", "nested-in-struct")] = (typeof(NS_vs_string.V), typeof(string)), - [("validated-struct", "string", "nested-two-levels")] = (typeof(N2_vs_string.Inner.V), typeof(string)), - [("validated-class", "string", "nested-in-class")] = (typeof(NC_vc_string.V), typeof(string)), - [("validated-class", "string", "nested-in-struct")] = (typeof(NS_vc_string.V), typeof(string)), - [("validated-class", "string", "nested-two-levels")] = (typeof(N2_vc_string.Inner.V), typeof(string)), - [("record-struct", "ulong", "nested-in-class")] = (typeof(NC_rs_ulong.V), typeof(ulong)), - [("record-struct", "ulong", "nested-in-struct")] = (typeof(NS_rs_ulong.V), typeof(ulong)), - [("record-struct", "ulong", "nested-two-levels")] = (typeof(N2_rs_ulong.Inner.V), typeof(ulong)), - [("sealed-record-class", "ulong", "nested-in-class")] = (typeof(NC_rc_ulong.V), typeof(ulong)), - [("sealed-record-class", "ulong", "nested-in-struct")] = (typeof(NS_rc_ulong.V), typeof(ulong)), - [("sealed-record-class", "ulong", "nested-two-levels")] = (typeof(N2_rc_ulong.Inner.V), typeof(ulong)), - [("validated-struct", "ulong", "nested-in-class")] = (typeof(NC_vs_ulong.V), typeof(ulong)), - [("validated-struct", "ulong", "nested-in-struct")] = (typeof(NS_vs_ulong.V), typeof(ulong)), - [("validated-struct", "ulong", "nested-two-levels")] = (typeof(N2_vs_ulong.Inner.V), typeof(ulong)), - [("validated-class", "ulong", "nested-in-class")] = (typeof(NC_vc_ulong.V), typeof(ulong)), - [("validated-class", "ulong", "nested-in-struct")] = (typeof(NS_vc_ulong.V), typeof(ulong)), - [("validated-class", "ulong", "nested-two-levels")] = (typeof(N2_vc_ulong.Inner.V), typeof(ulong)), - }; -} diff --git a/tools/probe/corpus/harness/Equality.cs b/tools/probe/corpus/harness/Equality.cs deleted file mode 100644 index 7cabd460..00000000 --- a/tools/probe/corpus/harness/Equality.cs +++ /dev/null @@ -1,211 +0,0 @@ -// Claim L05-equality (README.md#what-typekit-guarantees; Generators README "Equality", "Comparison"; oracle "Equality (metamorphic)" in -// .claude/probe-axes.md): equal value objects have equal hash codes, CompareTo is zero exactly when Equals is true, and both agree with the -// wrapped type's (ordinal for a string), through every base in the inheritance chain, and wherever the value object is held. A closed set's -// members are singletons, so its equality is reference equality (docs/closed-sets.md). -// Oracle: metamorphic. Two value objects over values the wrapped type calls equal in different forms (7.8m and 7.80m, 0.0 and -0.0, one -// instant at two offsets, two string instances), and one over a value it calls unequal and orders after. -using System.Collections; -using System.Reflection; -using Probes.Shapes; -namespace Probes.Json; - -public sealed record L05Entry(string Kind, string Wrapped, string Inheritance, string Site, Type Type, Func A1, Func A2, Func B); - -public abstract record L05PolyBase; -public sealed record L05PolyDerived : L05PolyBase { public T Value { get; set; } = default!; } - -public static partial class L05Registry -{ - static readonly List All = []; - static L05Registry() => Fill(); - static partial void Fill(); - static void Add(string kind, string wrapped, string inheritance, string site, Type type, Func a1, Func a2, Func b) => - All.Add(new(kind, wrapped, inheritance, site, type, a1, a2, b)); - public static L05Entry? Get(string kind, string wrapped, string inheritance, string site) => - All.FirstOrDefault(x => x.Kind == kind && x.Wrapped == wrapped && x.Inheritance == inheritance && x.Site == site); -} - -public static class Equality -{ - static IEqualityComparer Comparer(Type t) => (IEqualityComparer)typeof(EqualityComparer<>).MakeGenericType(t).GetProperty("Default")!.GetValue(null)!; - static int Sign(int x) => Math.Sign(x); - - static object Make(Type v, Type w, object value) - { - var m = v.GetMethods(BindingFlags.Public | BindingFlags.Static) - .First(x => x.Name is "From" or "FromKnownGood" && x.GetParameters() is [var p, ..] && p.ParameterType == w); - var args = m.GetParameters().Select((p, i) => i == 0 ? value : Type.Missing).ToArray(); - return m.Invoke(null, BindingFlags.OptionalParamBinding | BindingFlags.Default, null, args, null)!; - } - - static object? Op(Type t, string name, object a, object b) => - t.GetMethod(name, BindingFlags.Public | BindingFlags.Static, [t, t]) is { } m ? m.Invoke(null, [a, b]) : null; - - public static string? Check(Row r) - { - var kind = r["shape.kind"]; var inh = r["shape.inheritance"]; var site = r["shape.site"]; - var closed = kind == "closed-set"; - // claims.json excludes the pairs no type can have; a row the covering array made with one anyway runs the nearest shape that exists - if (site == "in-generic-type") { r.Substituted("shape.site", "top-level", "CMTK1005/CMTK1018: nothing nests in a generic type"); site = "top-level"; } - if (kind is "record-struct" or "validated-struct" && inh.StartsWith("base-")) { r.Substituted("shape.inheritance", "none", "a struct has no base type"); inh = "none"; } - var wrapped = closed ? "-" : r["shape.wrapped"]; - var en = L05Registry.Get(kind, wrapped, inh, site); - if (en is null) { r.Outcome("harness-error", $"no L05 shape for {kind}/{wrapped}/{inh}/{site}: run harness/gen_json_family.py"); return null; } - var v = en.Type; - object x1, x2, y; bool eq12; - Type? w = null; object? a1 = null, b = null; - if (closed) - { - x1 = en.A1(); x2 = en.A2(); y = en.B(); - if (!ReferenceEquals(x1, x2)) return "closed set: the member found in All is not the member itself"; - eq12 = true; - } - else - { - w = v.GetProperty("Value")!.PropertyType; - a1 = en.A1(); var a2 = en.A2(); b = en.B(); - var cw = Comparer(w); - if (!cw.Equals(a1, a2) || cw.Equals(a1, b)) { r.Outcome("harness-error", $"samples of {wrapped}: {a1} and {a2} must be equal, {b} not"); return null; } - eq12 = true; - x1 = Make(v, w, a1); x2 = Make(v, w, a2); y = Make(v, w, b); - if (!cw.Equals(v.GetProperty("Value")!.GetValue(x1), a1)) return $"Value of {v.Name} is not the value it was made from"; - } - // each failure goes to the obligation it breaks: the value object's own equality and wherever it is held, its ordering, its bases - List eqF = [], ordF = [], baseF = []; - var fails = eqF; - void Expect(bool got, bool want, string what) { if (got != want) fails.Add($"{what}: {got}, expected {want}"); } - - // the value object's own equality - Expect(x1.Equals(x2), eq12, "Equals(object) of equal values"); - Expect(x1.Equals(y), false, "Equals(object) of unequal values"); - Expect(x1.Equals(null), false, "Equals(null)"); - Expect(Comparer(v).Equals(x1, x2), eq12, "EqualityComparer of equal values"); - Expect(Comparer(v).Equals(x1, y), false, "EqualityComparer of unequal values"); - if (x1!.GetHashCode() != x2!.GetHashCode()) fails.Add($"equal values hash apart: {x1.GetHashCode()} and {x2.GetHashCode()}"); - if (Comparer(v).GetHashCode(x1) != Comparer(v).GetHashCode(x2)) fails.Add("EqualityComparer hashes equal values apart"); - if (Op(v, "op_Equality", x1, x2) is { } e12) Expect((bool)e12, eq12, "== of equal values"); else if (!closed) fails.Add("no operator =="); - if (Op(v, "op_Equality", x1, y) is { } e1b) Expect((bool)e1b, false, "== of unequal values"); - if (Op(v, "op_Inequality", x1, x2) is { } n12) Expect((bool)n12, !eq12, "!= of equal values"); - - // ordering: generated where the wrapped type is comparable, ordinal for a string, zero exactly when equal - fails = ordF; - var icv = typeof(IComparable<>).MakeGenericType(v); - if (!closed) - { - var comparableW = typeof(IComparable<>).MakeGenericType(w!).IsAssignableFrom(w) || typeof(IComparable).IsAssignableFrom(w); // an enum is IComparable only - if (icv.IsAssignableFrom(v) != comparableW) fails.Add($"IComparable<{v.Name}> is {(icv.IsAssignableFrom(v) ? "" : "not ")}implemented, the wrapped {w!.Name} is {(comparableW ? "" : "not ")}comparable"); - } - if (icv.IsAssignableFrom(v)) - { - var cmp = icv.GetMethod("CompareTo")!; - var c12 = (int)cmp.Invoke(x1, [x2])!; var c1b = (int)cmp.Invoke(x1, [y])!; var cb1 = (int)cmp.Invoke(y, [x1])!; - Expect(c12 == 0, eq12, "CompareTo of equal values is zero"); - if (c1b == 0) fails.Add("CompareTo of unequal values is zero"); - if (Sign(c1b) != -Sign(cb1)) fails.Add($"CompareTo is not antisymmetric: {c1b} and {cb1}"); - if (!closed) - { - var want = w == typeof(string) ? string.CompareOrdinal((string)a1!, (string)b!) : ((IComparer)typeof(Comparer<>).MakeGenericType(w!).GetProperty("Default")!.GetValue(null)!).Compare(a1, b); - if (Sign(c1b) != Sign(want)) fails.Add($"CompareTo orders {c1b}, the wrapped type {want}"); - } - if (x1 is IComparable nc) { if (Sign(nc.CompareTo(y)) != Sign(c1b) || nc.CompareTo(x2) != 0 == eq12) fails.Add("CompareTo(object) disagrees with CompareTo(TSelf)"); } - if (Op(v, "op_LessThan", x1, y) is { } lt) Expect((bool)lt, c1b < 0, "<"); - if (Op(v, "op_GreaterThan", x1, y) is { } gt) Expect((bool)gt, c1b > 0, ">"); - if (Op(v, "op_LessThanOrEqual", x1, x2) is { } le) Expect((bool)le, true, "<= of equal values"); - if (Op(v, "op_GreaterThanOrEqual", x1, x2) is { } ge) Expect((bool)ge, true, ">= of equal values"); - if (Op(v, "op_LessThan", x1, x2) is { } lt2) Expect((bool)lt2, false, "< of equal values"); - } - - // through every base, and every IEquatable it implements - var bases = 0; - for (var t = v.BaseType; t is not null; t = t.BaseType) - { - // object and ValueType are every value object's, a base of none: held as one, it is its own equality - var own = t == typeof(object) || t == typeof(ValueType); - if (!own) bases++; - fails = own ? eqF : baseF; - var c = Comparer(t); - Expect(c.Equals(x1, x2), eq12, $"EqualityComparer<{t.Name}> of equal values"); - Expect(c.Equals(x1, y), false, $"EqualityComparer<{t.Name}> of unequal values"); - if (c.GetHashCode(x1) != c.GetHashCode(x2)) fails.Add($"EqualityComparer<{t.Name}> hashes equal values apart"); - if (Op(t, "op_Equality", x1, x2) is { } be) Expect((bool)be, eq12, $"{t.Name}'s == of equal values"); - var set = (IEnumerable)Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(t))!; - var add = set.GetType().GetMethod("Add")!; add.Invoke(set, [x1]); add.Invoke(set, [x2]); add.Invoke(set, [y]); - var count = set.Cast().Count(); - if (count != 2) fails.Add($"HashSet<{t.Name}> of two equal values and one other holds {count}"); - } - foreach (var i in v.GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEquatable<>))) - { - fails = i.GetGenericArguments()[0] == v ? eqF : baseF; // IEquatable is its own equality, IEquatable a base's - var m = i.GetMethod("Equals")!; - Expect((bool)m.Invoke(x1, [x2])!, eq12, $"{Jx.Name(i)}.Equals of equal values"); - Expect((bool)m.Invoke(x1, [y])!, false, $"{Jx.Name(i)}.Equals of unequal values"); - } - - // wherever it is held - fails = eqF; - var position = r["shape.position"]; - var containing = position == "root" ? "class" : r["shape.containing"]; - var e = new Entry(kind, wrapped, v, v, () => x1, () => null, typeof(L05PolyBase), typeof(L05PolyDerived<>).MakeGenericType(v), typeof(L05PolyBase), typeof(L05PolyDerived<>).MakeGenericType(v)); - var h1 = Pos.Build(position, containing, e, true, x1); var h2 = Pos.Build(position, containing, e, true, x2); var h3 = Pos.Build(position, containing, e, true, y); - object? Member(Held h) => position == "root" ? h.Value : h.Declared.GetProperty("P") is { } p ? p.GetValue(h.Value) : h.Declared.GetField("F")!.GetValue(h.Value); - switch (position) - { - case "root": break; - case "list-element" or "array-element" or "immutable-array-element" or "read-only-list-element": - { - var l = (IList)Member(h1)!; - Expect(l.Contains(x2), eq12, $"{Jx.Name(l.GetType())}.Contains of an equal value"); - Expect(l.Contains(y), false, $"{Jx.Name(l.GetType())}.Contains of an unequal value"); - if (l.IndexOf(x2) != 0) fails.Add("IndexOf of an equal value is " + l.IndexOf(x2)); - break; - } - case "dictionary-key": - { - var d = (IDictionary)Member(h1)!; - Expect(d.Contains(x2), eq12, "dictionary lookup by an equal key"); - Expect(d.Contains(y), false, "dictionary lookup by an unequal key"); - break; - } - case "dictionary-value": - { - var d = Member(h1)!; var cv = d.GetType().GetMethod("ContainsValue")!; - Expect((bool)cv.Invoke(d, [x2])!, eq12, "ContainsValue of an equal value"); - Expect((bool)cv.Invoke(d, [y])!, false, "ContainsValue of an unequal value"); - break; - } - default: - { - // a container with value equality compares through the member; one with reference equality is compared by its member - var byValue = containing is "record-class" or "record-struct" or "struct"; - var (p1, p2, p3) = byValue ? (h1.Value, h2.Value, h3.Value) : (Member(h1), Member(h2), Member(h3)); - var what = byValue ? Jx.Name(h1.Declared) : $"the {position} of {Jx.Name(h1.Declared)}"; - Expect(Equals(p1, p2), eq12, what + " holding equal values"); - Expect(Equals(p1, p3), false, what + " holding unequal values"); - if (p1 is not null && p2 is not null && p1.GetHashCode() != p2.GetHashCode()) fails.Add(what + " holding equal values hashes them apart"); - break; - } - } - string What(List f) => $"{Jx.Name(v)} ({kind}, {wrapped}, {inh}, {site}, {position} in {containing}): " + string.Join("; ", f); - var f1 = r.Check("equality-is-the-underlying-values", Baseline.Twin, c => - { - if (eqF.Count > 0) return What(eqF); - c.Note(NoteKeys.Compared, $"{v.Name} {position}: equality, against EqualityComparer<{(w is null ? v.Name : w.Name)}>"); - return null; - }); - var f2 = r.Check("ordering-follows-the-underlying-type", Baseline.Twin, c => - { - if (ordF.Count > 0) return What(ordF); - c.Note(NoteKeys.Compared, $"{v.Name}: ordering{(icv.IsAssignableFrom(v) ? "" : ", none generated where the wrapped type has none")}"); - return null; - }); - // a value object with a base record: each base compares it as it does (the chain is shape.inheritance's) - var f3 = bases == 0 ? null : r.Check("through-every-base", Baseline.Twin, c => - { - _ = c["shape.inheritance"]; - if (baseF.Count > 0) return What(baseF); - c.Note(NoteKeys.Compared, $"{v.Name}: {bases} base type(s)"); - return null; - }); - return f1 ?? f2 ?? f3; - } -} diff --git a/tools/probe/corpus/harness/FaultClaim.cs b/tools/probe/corpus/harness/FaultClaim.cs deleted file mode 100644 index 03018dd1..00000000 --- a/tools/probe/corpus/harness/FaultClaim.cs +++ /dev/null @@ -1,412 +0,0 @@ -// The shared runner of the fault claims C04-without-faults, C06-fault-kinds, C14-declared-problem and C15-mvc-fault-status-doc -// (AspNetCore README "A closed set as the fault type", "A status per endpoint", "Leaving out what a route cannot answer"; CHANGELOG 2.1.0 Fixed). -// A claim is a Spec: its minimal endpoints as a tree of groups, the MVC controllers of FxCtl (FaultClaimControllers.g.cs), what -// MapControllers()'s builder adds, and the errors each endpoint reports. Each declaration is listed where it is made, so an endpoint's -// declarations come in ASP.NET's metadata order: outer group, inner group, endpoint; or controller, action, then MapControllers()'s builder. -// The oracle is the README's rules applied to those declarations, never the product's own reading of them: -// - a member is answered with the last status its endpoint's metadata sets for it, else the mapped one ("When several statuses name one -// member, the last in ASP.NET's metadata order wins"); the mapping is by kind (README table), or its own with a problem type per kind; -// - a member left out anywhere in that metadata is listed nowhere in the operation, and reporting it throws an InvalidOperationException -// naming the endpoint and the member ("Leave out only what the route can't report"); -// - the operation lists every status of every remaining member of every answered type, the endpoint's own declared ones among them, all its -// responses ascending; each fault status's problem schema describes fault and rule, and its description names exactly the problem types -// of the members answered with it ("names its problem types", CHANGELOG 2.1.0); -// - a status that every endpoint of its scope leaves out stops the host, naming the member and the status. -// Each comparison is about one Aspect, and a claim's Spec.Of names the obligations it is checked for: the row runs one check (Row.Check) per -// obligation it reaches, against the README's rules (Spec.Against) or, for a refusal, the documented one (Spec.Refusals), every check on the -// one host and the answers fetched once. -// http.response picks what every endpoint of the row answers (one fault type, a composed fault, two types writing one name) and what the -// outermost scope adds (a status for another member, a member left out, a problem the endpoint declares itself). -using System.Text.Json.Nodes; -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.AspNetCore; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.DependencyInjection; -using Probes.Shapes; -namespace Probes.Faults; - -/// One declaration about one member: a status (WithFaultStatus, [FaultStatus]) or, with status 0, the member left out. -public sealed record Decl(string Type, string Member, int Status) -{ - public bool Out => Status == 0; - public bool Names(Mem m) => Type == m.Type && Member == m.Name; - public override string ToString() => Out ? $"WithoutFaults({Type}.{Member})" : $"WithFaultStatus({Type}.{Member}, {Status})"; -} -/// An MVC action of FxCtl: its route (before the result-type segment), what it declares, the problem statuses it declares itself. -public sealed record Act(string Route, Decl[] Decls, int[] Declared); -/// An MVC controller of FxCtl: the [ApiController] and the plain copy, what the class declares, its actions. -public sealed record Ctl(Type Api, Type Plain, Decl[] Decls, Act[] Actions); -public static partial class FxCtl -{ - public static readonly Dictionary All = Build(); - static Dictionary Build() { var d = new Dictionary(StringComparer.Ordinal); Fill(d); return d; } - static partial void Fill(Dictionary d); -} - -/// A minimal endpoint, relative to its group; How: "pp" = ProducesProblem(each Declared), "prt" = [ProducesResponseType<ProblemDetails>(404)]. -public sealed record MEp(string Route, Decl[] Decls, int[]? Declared = null, string? How = null); -/// A route group: its prefix (never empty), what it declares, its inner groups and endpoints. -public sealed record MGrp(string Prefix, Decl[] Decls, MGrp[] Groups, MEp[] Eps); - -/// A member of a fault type the endpoints answer with, its kind and the status its kind maps to (README table). -public sealed record Mem(string Type, string Name, string Kind, int Status) { public string Q => Type + "." + Name; } - -public static class FxErr -{ - public static readonly Mem[] H = - [ - new("HFault", "Missing", "NotFound", 404), new("HFault", "Clash", "Conflict", 409), new("HFault", "Bad", "Invalid", 422), - new("HFault", "Denied", "Forbidden", 403), new("HFault", "Down", "Unavailable", 503), new("HFault", "Stale", "PreconditionFailed", 412), - new("HFault", "Garbled", "Malformed", 400), - ]; - static readonly Mem[] G = [new("GFault", "Gone", "NotFound", 404), new("GFault", "Raced", "Conflict", 409), new("GFault", "Old", "PreconditionFailed", 412)]; - static readonly Mem[] K = [new("KFault", "Clash", "Conflict", 409), new("KFault", "Lost", "NotFound", 404)]; - /// Every member of every type an endpoint answering answers with. - public static Mem[] Answered(string t) => t == "two" ? [.. H, .. G] : t == "dup" ? [.. H, .. K] : H; - /// e: 1-based index into H; 0 is a success. - static HFault Of(int e) => (HFault)typeof(HFault).GetField(H[e - 1].Name)!.GetValue(null)!; - public static Result> One(int e) { if (e == 0) return Result>.Success(); return Fault.Of(Of(e)); } - public static Result> Two(int e) => e == 0 ? Result>.Success() : Fault.Of(Of(e)); - public static Result> Dup(int e) => e == 0 ? Result>.Success() : Fault.Of(Of(e)); - public static int E(string member) => Array.FindIndex(H, m => m.Name == member) + 1; -} - -/// One endpoint as the oracle sees it: its URL in this host, the result it answers, its declarations in metadata order. -public sealed record Ep(bool Mvc, string Url, string T, Decl[] Decls, int[] Declared, Func Map) -{ - public bool LeftOut(Mem m) => Decls.Any(d => d.Out && d.Names(m)); - public int StatusOf(Mem m) => Decls.LastOrDefault(d => !d.Out && d.Names(m))?.Status ?? Map(m).Status; - public SortedSet FaultStatuses() => new(FxErr.Answered(T).Where(m => !LeftOut(m)).Select(StatusOf)); - public SortedSet DocStatuses() { var s = FaultStatuses(); foreach (var d in Declared) s.Add(d); return s; } - public HashSet TypesAt(int status) => - [.. FxErr.Answered(T).Where(m => !LeftOut(m) && StatusOf(m) == status).Select(m => Map(m).Type).OfType()]; -} - -/// What one comparison of is about; a claim's names the obligations each is checked for. -public static class Aspect -{ - /// The host starts, or refuses to as the README says. - public const string Start = "start"; - /// Reporting a member left out throws, naming the endpoint and the member. - public const string LeftOut = "left-out"; - /// A member's status, on the wire and in the problem's status field. - public const string Status = "status"; - /// The problem's fault, its type and its detail. - public const string Fault = "fault", Type = "type", Detail = "detail"; - /// The operation's statuses (which), their order, the problem schema's fault and rule, and the problem types its description names. - public const string DocListed = "doc-listed", DocOrder = "doc-order", DocDescribes = "doc-describes", DocTypes = "doc-types"; - public static readonly string[] Answer = [Status, Fault, Type, Detail]; - public static readonly string[] Doc = [DocListed, DocOrder, DocDescribes, DocTypes]; -} - -/// What one claim's row asks: see the header. -public sealed class Spec -{ - /// The obligations a comparison of an aspect is checked for, given the member it is about (none for the start and the document). - public Func Of = (_, _) => ["claim"]; - /// What the README's rules are compared as: the sentence of the claim's source. - public Baseline Against = Baseline.Model; - /// The obligations whose check holds a refusal by its type and what it names. - public string[] Refusals = []; - public MGrp? Minimal; // under the outer group /m, where the host has minimal APIs - public string[] Controllers = []; // FxCtl keys, where it has MVC - public Decl[] Builder = []; // added to MapControllers()'s builder, after the response's own - public int[] Errors = []; // the HFault members each endpoint reports (FxErr.E) - public bool Typed = true; // the host's mapping gives a problem type per kind; else AddFaultResponses() by kind - public string[]? Refused; // the host must not start, with an InvalidOperationException naming each of these - public Func? RefusedAs; // or: the host must not start, and this judges the exception (null: as expected) - public Func? Map; // how the host maps each member; default by kind, with a type per kind where Typed - public string? Mapping; // HostCfg.Mapping in place of Typed's - public Action? Services; - public Action? Extra; // more minimal endpoints, at the root - public Type[] ExtraControllers = []; -} - -/// What http.response makes every endpoint of the row answer, and what the outermost scope adds. -public sealed record Resp(string T, Decl[] Outer, int[] Declared) -{ - public static Resp Of(Row r) => r["http.response"] switch - { - "composed-fault" => new("two", [], []), - "two-faults-same-name" => new("dup", [], []), - "group-with-fault-status" => new("one", [new("HFault", "Clash", 422)], []), - "endpoint-without-faults" => new("one", [new("HFault", "Missing", 0)], []), - "declared-produces-problem" => new("decl", [], [429]), - _ => new("one", [], []), - }; -} - -/// The baseline's problem response in MVC (see FaultClaim.DocRefusedByAspNetAlone). -[ApiController] -internal sealed class FxProblemBaseline : ControllerBase -{ - [HttpGet("baseline-problem/c"), ProducesResponseType(404, "application/problem+json")] public IActionResult Get() => NoContent(); -} - -public static class FaultClaim -{ - public static string TypeOf(string kind) => "https://p.example/" + kind; - static string? Un(Row r, string? s) => r.Is("json.Converters", "own-for-wrapped") && s is not null && s.StartsWith("own:") ? s[4..].Trim('"') : s; - static string Cut(string? s) => s is null ? "(null)" : s.Length > 300 ? s[..300] + "..." : s; - static void Process(Row r, Entry en) { if (r.Is("process.converter-lookup", "wrapped-type-converter-looked-up-first")) _ = System.ComponentModel.TypeDescriptor.GetConverter(Make.Held(en.Plain)); } - - static T Member(string name) => (T)typeof(T).GetField(name)!.GetValue(null)!; - static TB Apply(TB b, Decl d) where TB : IEndpointConventionBuilder => (d.Type, d.Out) switch - { - ("HFault", true) => b.WithoutFaults(Member(d.Member)), - ("HFault", false) => b.WithFaultStatus(Member(d.Member), d.Status), - ("GFault", true) => b.WithoutFaults(Member(d.Member)), - ("GFault", false) => b.WithFaultStatus(Member(d.Member), d.Status), - ("KFault", true) => b.WithoutFaults(Member(d.Member)), - _ => b.WithFaultStatus(Member(d.Member), d.Status), - }; - - static RouteHandlerBuilder MapT(IEndpointRouteBuilder g, string path, string t, string? how) => (t, how) switch - { - ("two", "prt") => g.MapGet(path, [ProducesResponseType(404)] (int e) => FxErr.Two(e).ToHttpResult()), - ("dup", "prt") => g.MapGet(path, [ProducesResponseType(404)] (int e) => FxErr.Dup(e).ToHttpResult()), - (_, "prt") => g.MapGet(path, [ProducesResponseType(404)] (int e) => FxErr.One(e).ToHttpResult()), - ("two", _) => g.MapGet(path, (int e) => FxErr.Two(e).ToHttpResult()), - ("dup", _) => g.MapGet(path, (int e) => FxErr.Dup(e).ToHttpResult()), - _ => g.MapGet(path, (int e) => FxErr.One(e).ToHttpResult()), - }; - - /// Walks a minimal tree: maps it where is given, and lists its endpoints with their declarations in metadata order. - static void Walk(IEndpointRouteBuilder? b, MGrp g, Decl[] above, string prefix, Resp resp, List<(string Path, Decl[] Decls, int[] Declared)> eps) - { - RouteGroupBuilder? grp = null; - if (b is not null) { grp = b.MapGroup(g.Prefix); foreach (var d in g.Decls) Apply(grp, d); } - Decl[] decls = [.. above, .. g.Decls]; - var pre = prefix + g.Prefix; - foreach (var sub in g.Groups) Walk(grp, sub, decls, pre, resp, eps); - foreach (var ep in g.Eps) - { - var path = "/" + ep.Route + "/" + resp.T; - if (grp is not null) - { - var rb = MapT(grp, path, resp.T, ep.How); - foreach (var d in ep.Decls) Apply(rb, d); - if (ep.How == "pp") foreach (var s in ep.Declared ?? []) rb.ProducesProblem(s); - if (resp.T == "decl") rb.ProducesProblem(429); - } - eps.Add((pre + path, [.. decls, .. ep.Decls], [.. ep.Declared ?? [], .. resp.Declared])); - } - } - - static (List Eps, HostCfg Cfg) Plan(Row r, Spec s, Resp resp) - { - var eps = new List(); - var map = s.Map ?? (m => (m.Status, s.Typed ? TypeOf(m.Kind) : (string?)null)); - MGrp? root = s.Minimal is null ? null : new MGrp("/m", resp.Outer, [s.Minimal], []); - if (root is not null && Hx.HasMinimal(r)) - { - var found = new List<(string Path, Decl[] Decls, int[] Declared)>(); - Walk(null, root, [], "", resp, found); - eps.AddRange(found.Select(x => new Ep(false, Hx.M(r, x.Path), resp.T, x.Decls, x.Declared, map))); - } - var controllers = new List(); - Decl[] builder = [.. resp.Outer, .. s.Builder]; - if (Hx.HasMvc(r)) - foreach (var key in s.Controllers) - { - var c = FxCtl.All[key]; - controllers.Add(Hx.Plain(r) ? c.Plain : c.Api); - foreach (var a in c.Actions) - eps.Add(new Ep(true, Hx.C(r, "/c/" + a.Route + "/" + resp.T), resp.T, [.. c.Decls, .. a.Decls, .. builder], [.. a.Declared, .. resp.Declared], map)); - } - if (Hx.HasMvc(r)) controllers.AddRange(s.ExtraControllers); - var cfg = new HostCfg - { - FaultControllers = true, Controllers = [.. controllers], - Mapping = s.Mapping ?? (s.Typed ? "own-IFault-mapping" : "per-set"), - Services = sv => { if (s.Mapping is null && !s.Typed) sv.AddFaultResponses(); s.Services?.Invoke(sv); }, - Minimal = b => { if (root is not null) Walk(b, root, [], "", resp, []); s.Extra?.Invoke(b); }, - ControllerBuilder = cb => { foreach (var d in builder) Apply(cb, d); return cb; }, - }; - return (eps, cfg); - } - - public static async Task Run(Row r, Spec s) - { - var en = Registry.Of(r); Process(r, en); - var resp = Resp.Of(r); - var (eps, cfg) = Plan(r, s, resp); - if (eps.Count == 0) return "harness: the row maps no endpoint of the claim (an excluded pair?)"; - WebApplication? app = null; Exception? down = null; - try { app = await Hx.Start(r, en, cfg); } - catch (Exception ex) when (ex is not Sides.InputsNotEquivalent) { down = ex; } - await using var _ = app; - Baseline Against(string o) => s.Refusals.Contains(o) ? Baseline.Refusal : s.Against; - string? failed = null; - - // A host the README says must not start: that is the row's one comparison. - if (s.Refused is not null || s.RefusedAs is not null) - { - foreach (var o in s.Of(Aspect.Start, null)) - { - var f = r.Check(o, Against(o), _ => down is null - ? (s.RefusedAs is not null ? "host started, though the README says this set stops the start" - : $"host started, though a status every endpoint of its scope leaves out must stop it ({string.Join(", ", s.Refused!)})") - : StartRefused(s, down)); - failed ??= f; - } - return failed; - } - - var members = s.Errors.Select(e => FxErr.H[e - 1]).ToList(); - var obligations = Aspect.Answer.Append(Aspect.LeftOut).SelectMany(a => members.SelectMany(m => s.Of(a, m))) - .Concat(Aspect.Doc.SelectMany(a => s.Of(a, null))).Distinct().ToList(); - if (down is not null) - { - foreach (var o in obligations) { var f = r.Check(o, Against(o), _ => "host did not start: " + down.GetType().Name + ": " + Cut(down.Message)); failed ??= f; } - return failed; - } - - var display = app!.Services.GetRequiredService().Endpoints.OfType() - .GroupBy(e => "/" + (e.RoutePattern.RawText ?? "").TrimStart('/'), StringComparer.OrdinalIgnoreCase) - .ToDictionary(g => g.Key, g => g.First().DisplayName ?? "", StringComparer.OrdinalIgnoreCase); - JsonNode? doc = null; Exception? docFailed = null; - try { doc = await Hx.Doc(app); } - catch (Exception ex) { docFailed = ex; } - var wires = new Dictionary<(string Url, int E), Hx.Wire>(); - foreach (var ep in eps) - foreach (var e in s.Errors) - wires[(ep.Url, e)] = await Hx.Get(app, $"{ep.Url}?e={e}"); - - foreach (var o in obligations) - { - var f = await r.Check(o, Against(o), async c => - { - var wire = false; // whether the check compared an answer on the wire before the document - bool want(string aspect, Mem? m) - { - var wanted = s.Of(aspect, m).Contains(o); - if (wanted && !Aspect.Doc.Contains(aspect)) wire = true; - return wanted; - } - foreach (var ep in eps) - foreach (var e in s.Errors) - if (Wire(r, ep, FxErr.H[e - 1], wires[(ep.Url, e)], display, want) is { } fail) return fail; - if (!Aspect.Doc.Any(a => want(a, null))) return null; - // A document ASP.NET alone refuses too has nothing to check (noted there); any other failure is returned. - if (docFailed is not null) return await DocRefusedByAspNetAlone(c, r, en, cfg, docFailed, wire); - foreach (var ep in eps) - if (DocOf(r, doc!, ep, want) is { } fail) return fail; - return null; - }); - failed ??= f; - } - return failed; - } - - /// The host refused to start: as the README says, with an InvalidOperationException naming each of , or as judges. - static string? StartRefused(Spec s, Exception ex) - { - if (s.RefusedAs is { } judge) return judge(ex); - var names = s.Refused!; - var ioe = ex as InvalidOperationException ?? ex.InnerException as InvalidOperationException; - if (ioe is null) return $"host refused to start, but with {ex.GetType().Name}, not InvalidOperationException: {Cut(ex.Message)}"; - foreach (var name in names) - if (!ioe.Message.Contains(name, StringComparison.Ordinal)) return $"host refused to start, but not naming {name}: {Cut(ioe.Message)}"; - return null; - } - - /// - /// Hx.DocRefusedByAspNetAlone, with a baseline that has a problem response: the same host without AddTypeKit(), plus one endpoint (and one - /// action, where the host has MVC) declaring ProducesProblem(404). AddTypeKit() adds its problem responses "as ProducesProblem would" - /// (README "A Result as a response"), so ASP.NET alone writing a document of the same host without any problem response says nothing about - /// them: under json.MaxDepth=3 System.Text.Json refuses the problem schema of ASP.NET's own ProducesProblem too (decision 99). - /// - static async Task DocRefusedByAspNetAlone(Check c, Row r, Entry en, HostCfg cfg, Exception withTypeKit, bool comparedBefore) - { - static string Say(Exception x) => x.GetType().Name + ": " + Cut(x.Message); - var alone = cfg.Copy(); alone.TypeKitOpenApi = false; - alone.Controllers = [.. cfg.Controllers ?? [], typeof(FxProblemBaseline)]; - alone.Minimal = b => { cfg.Minimal?.Invoke(b); b.MapGet("/baseline-problem", () => Results.NoContent()).ProducesProblem(404); }; - try - { - await using var app = await Hx.Start(r, en, alone); - await Hx.Doc(app); - } - // the same refusal by type and stage, never by its words (Hx.DocAlike) - catch (Exception ex) when (Hx.DocAlike(ex, withTypeKit)) - { - Hx.DocRefused(r, ex, comparedBefore); - return null; - } - catch (Exception ex) when (r.Is("json.MaxDepth", "3") && Depth(ex) && Depth(withTypeKit)) - { - // Both refuse the problem schema under MaxDepth=3, by System.Text.Json's own depth checks, but on different paths (TypeKit's - // transformer through the schema exporter, ProducesProblem through the document writer): a refusal of STJ's own, nothing to check - // (decision 99: under MaxDepth=3 System.Text.Json refuses the OpenAPI document of a problem response for plain ASP.NET too). - return c.Refused(Cite.Record("0099"), $"{Say(withTypeKit)} / {Say(ex)}"); - } - catch (Exception ex) { return $"document: AddTypeKit() fails ({Say(withTypeKit)}), ASP.NET alone with a ProducesProblem fails otherwise ({Say(ex)})"; } - return $"document: AddTypeKit() fails ({Say(withTypeKit)}), ASP.NET alone with a ProducesProblem writes it"; - } - - static bool Depth(Exception x) => x is InvalidOperationException or System.Text.Json.JsonException; - - /// One endpoint's answer to reporting , judged on the aspects names. - static string? Wire(Row r, Ep ep, Mem m, Hx.Wire w, Dictionary display, Func want) - { - var at = $"{ep.Url} reporting {m.Q}"; - if (ep.LeftOut(m)) - { - if (!want(Aspect.LeftOut, m)) return null; - if (w.Thrown is null) return $"{at}: left out of its document, but answered {(int)w.Status}: {Cut(w.Body)}"; - if (!w.Thrown.StartsWith(nameof(InvalidOperationException) + ":", StringComparison.Ordinal)) return $"{at}: left out, threw {Cut(w.Thrown)}, expected an InvalidOperationException"; - if (!display.TryGetValue(ep.Url, out var name) || name.Length == 0) return $"harness: no endpoint named at {ep.Url}"; - if (!w.Thrown.Contains(name, StringComparison.Ordinal) || !w.Thrown.Contains(m.Q, StringComparison.Ordinal)) - return $"{at}: the refusal does not name the endpoint ({name}) and the member ({m.Q}): {Cut(w.Thrown)}"; - return null; - } - if (!Aspect.Answer.Any(a => want(a, m))) return null; - if (w.Thrown is not null) return $"{at}: request threw {Cut(w.Thrown)}"; - var status = ep.StatusOf(m); - if (want(Aspect.Status, m) && (int)w.Status != status) return $"{at}: status {(int)w.Status}, expected {status}: {Cut(w.Body)}"; - JsonNode? body; try { body = JsonNode.Parse(w.Body); } catch { return $"{at}: body is not JSON: {Cut(w.Body)}"; } - var fault = Un(r, body?["fault"]?.GetValue()); - if (want(Aspect.Fault, m) && fault != m.Name) return $"{at}: fault {fault ?? "(none)"}, expected {m.Name}"; - if (want(Aspect.Status, m) && int.Parse(body?["status"]?.ToString() is { } st ? Un(r, st)!.Trim('"') : "0") != status) return $"{at}: problem status field {body?["status"]}, expected {status}"; - if (want(Aspect.Type, m) && ep.Map(m).Type is { } type && Un(r, body?["type"]?.GetValue()) != type) return $"{at}: type {body?["type"]}, expected {type}"; - var detail = Un(r, body?["detail"]?.GetValue()); - var wantDetail = m.Q == "HFault.Missing" ? "Missing." : null; - if (want(Aspect.Detail, m) && detail != wantDetail) return $"{at}: detail {detail ?? "(none)"}, expected {wantDetail ?? "none (the member has no description)"}"; - return null; - } - - /// One endpoint's operation in the document, judged on the aspects names. - static string? DocOf(Row r, JsonNode doc, Ep ep, Func want) - { - var op = doc["paths"]?[ep.Url]?["get"]; - if (op is null && ep.Mvc && !Hx.InDocument(r)) { r.Note(NoteKeys.DocControllerNotInApiExplorer); return null; } - if (op is null) return $"document has no GET {ep.Url}"; - var responses = op["responses"]?.AsObject(); - if (responses is null) return $"{ep.Url}: operation has no responses"; - var nums = responses.Select(kv => kv.Key).Where(k => int.TryParse(k, out _)).Select(int.Parse).ToList(); - if (want(Aspect.DocOrder, null) && !nums.SequenceEqual(nums.Order())) return $"{ep.Url}: responses {string.Join(",", responses.Select(kv => kv.Key))} are not in ascending order"; - var got = nums.Where(n => n >= 400).ToList(); - var listed = ep.DocStatuses(); - // which statuses are listed, as a set: their order is DocOrder's, above - if (want(Aspect.DocListed, null) && !got.Order().SequenceEqual(listed)) return $"{ep.Url}: document lists {string.Join(",", got)}, expected {string.Join(",", listed)} ({string.Join(" ", ep.Decls)})"; - foreach (var status in ep.FaultStatuses()) - { - var resp = responses[status.ToString()]; - var txt = Hx.Deep(doc, resp)?.ToJsonString() ?? ""; - if (want(Aspect.DocDescribes, null) && !txt.Contains("\"fault\"")) return $"{ep.Url} {status}: response schema does not describe fault: {Cut(txt)}"; - if (want(Aspect.DocDescribes, null) && !txt.Contains("\"rule\"")) return $"{ep.Url} {status}: response schema does not describe rule: {Cut(txt)}"; - var desc = resp?["description"]?.GetValue() ?? ""; - const string Lead = "Problem types: "; - var i = desc.IndexOf(Lead, StringComparison.Ordinal); - var types = i < 0 ? [] : desc[(i + Lead.Length)..].Split(", ").ToHashSet(); - var wantTypes = ep.TypesAt(status); - if (want(Aspect.DocTypes, null) && !types.SetEquals(wantTypes)) - return $"{ep.Url} {status}: description \"{desc}\" names problem types {{{string.Join(", ", types)}}}, expected {{{string.Join(", ", wantTypes)}}}"; - } - return null; - } -} diff --git a/tools/probe/corpus/harness/FaultClaimControllers.g.cs b/tools/probe/corpus/harness/FaultClaimControllers.g.cs deleted file mode 100644 index afec71e4..00000000 --- a/tools/probe/corpus/harness/FaultClaimControllers.g.cs +++ /dev/null @@ -1,206 +0,0 @@ -// Generated by tools/probe/generators/faults.cs (the fault claims' MVC controllers, C04 C06 C14 C15): do not edit by hand. -// Every action answers FxErr's errors; its route ends in the result type it answers (one, two, dup) or decl (one, with a -// [ProducesResponseType(429)] of its own). The table FxCtl.All restates what each class and action declares, -// in ASP.NET's metadata order (controller, then action), as the input FaultClaim computes the expected response and document from. -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.AspNetCore; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.HttpResults; -using Microsoft.AspNetCore.Mvc; -namespace Probes.Faults; - -internal abstract class FxC04EpBase : ControllerBase -{ - [HttpGet("c/fx/ep/wo/one"), WithoutFaults("Down")] public Results> FxEpWoOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ep/wo/two"), WithoutFaults("Down")] public Results, FaultProblem> FxEpWoTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/ep/wo/dup"), WithoutFaults("Down")] public Results, FaultProblem> FxEpWoDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/ep/wo/decl"), WithoutFaults("Down"), ProducesResponseType(429)] public Results> FxEpWoDecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ep/keep/one")] public Results> FxEpKeepOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ep/keep/two")] public Results, FaultProblem> FxEpKeepTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/ep/keep/dup")] public Results, FaultProblem> FxEpKeepDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/ep/keep/decl"), ProducesResponseType(429)] public Results> FxEpKeepDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC04EpApi : FxC04EpBase { } -internal sealed class FxC04EpPlain : FxC04EpBase { } -[ApiController, FaultStatus("Down", 507)] internal sealed class FxC04EpSApi : FxC04EpBase { } -[FaultStatus("Down", 507)] internal sealed class FxC04EpSPlain : FxC04EpBase { } - -internal abstract class FxC04CtWoBase : ControllerBase -{ - [HttpGet("c/fx/ct/wo/a/one")] public Results> FxCtWoAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/a/two")] public Results, FaultProblem> FxCtWoATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/a/dup")] public Results, FaultProblem> FxCtWoADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/a/decl"), ProducesResponseType(429)] public Results> FxCtWoADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/b/one")] public Results> FxCtWoBOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/b/two")] public Results, FaultProblem> FxCtWoBTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/b/dup")] public Results, FaultProblem> FxCtWoBDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/ct/wo/b/decl"), ProducesResponseType(429)] public Results> FxCtWoBDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController, WithoutFaults("Down")] internal sealed class FxC04CtWoApi : FxC04CtWoBase { } -[WithoutFaults("Down")] internal sealed class FxC04CtWoPlain : FxC04CtWoBase { } - -internal abstract class FxC04CtKeepBase : ControllerBase -{ - [HttpGet("c/fx/ct/keep/one")] public Results> FxCtKeepOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/ct/keep/two")] public Results, FaultProblem> FxCtKeepTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/ct/keep/dup")] public Results, FaultProblem> FxCtKeepDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/ct/keep/decl"), ProducesResponseType(429)] public Results> FxCtKeepDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC04CtKeepApi : FxC04CtKeepBase { } -internal sealed class FxC04CtKeepPlain : FxC04CtKeepBase { } - -internal abstract class FxC04GrBase : ControllerBase -{ - [HttpGet("c/fx/gr/a/one")] public Results> FxGrAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/gr/a/two")] public Results, FaultProblem> FxGrATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/gr/a/dup")] public Results, FaultProblem> FxGrADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/gr/a/decl"), ProducesResponseType(429)] public Results> FxGrADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/gr/b/one")] public Results> FxGrBOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/fx/gr/b/two")] public Results, FaultProblem> FxGrBTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/fx/gr/b/dup")] public Results, FaultProblem> FxGrBDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/fx/gr/b/decl"), ProducesResponseType(429)] public Results> FxGrBDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC04GrApi : FxC04GrBase { } -internal sealed class FxC04GrPlain : FxC04GrBase { } - -internal abstract class FxC06KBase : ControllerBase -{ - [HttpGet("c/k/one")] public Results> KOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/k/two")] public Results, FaultProblem> KTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/k/dup")] public Results, FaultProblem> KDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/k/decl"), ProducesResponseType(429)] public Results> KDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC06KApi : FxC06KBase { } -internal sealed class FxC06KPlain : FxC06KBase { } - -internal abstract class FxC14PpBase : ControllerBase -{ - [HttpGet("c/d/pp/one"), ProducesResponseType(404, "application/problem+json")] public Results> DPpOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/d/pp/two"), ProducesResponseType(404, "application/problem+json")] public Results, FaultProblem> DPpTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/d/pp/dup"), ProducesResponseType(404, "application/problem+json")] public Results, FaultProblem> DPpDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/d/pp/decl"), ProducesResponseType(404, "application/problem+json"), ProducesResponseType(429)] public Results> DPpDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC14PpApi : FxC14PpBase { } -internal sealed class FxC14PpPlain : FxC14PpBase { } - -internal abstract class FxC14PrtBase : ControllerBase -{ - [HttpGet("c/d/prt/one"), ProducesResponseType(404)] public Results> DPrtOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/d/prt/two"), ProducesResponseType(404)] public Results, FaultProblem> DPrtTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/d/prt/dup"), ProducesResponseType(404)] public Results, FaultProblem> DPrtDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/d/prt/decl"), ProducesResponseType(404), ProducesResponseType(429)] public Results> DPrtDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC14PrtApi : FxC14PrtBase { } -internal sealed class FxC14PrtPlain : FxC14PrtBase { } - -internal abstract class FxC14NoneBase : ControllerBase -{ - [HttpGet("c/d/none/one")] public Results> DNoneOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/d/none/two")] public Results, FaultProblem> DNoneTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/d/none/dup")] public Results, FaultProblem> DNoneDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/d/none/decl"), ProducesResponseType(429)] public Results> DNoneDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC14NoneApi : FxC14NoneBase { } -internal sealed class FxC14NonePlain : FxC14NoneBase { } - -internal abstract class FxC15MBase : ControllerBase -{ - [HttpGet("c/s/a/one")] public Results> SAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/a/two")] public Results, FaultProblem> SATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/a/dup")] public Results, FaultProblem> SADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/a/decl"), ProducesResponseType(429)] public Results> SADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/p/one"), FaultStatus("Denied", 452)] public Results> SPOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/p/two"), FaultStatus("Denied", 452)] public Results, FaultProblem> SPTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/p/dup"), FaultStatus("Denied", 452)] public Results, FaultProblem> SPDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/p/decl"), FaultStatus("Denied", 452), ProducesResponseType(429)] public Results> SPDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC15MApi : FxC15MBase { } -internal sealed class FxC15MPlain : FxC15MBase { } - -internal abstract class FxC15ASBase : ControllerBase -{ - [HttpGet("c/s/a/one"), FaultStatus("Denied", 451)] public Results> SAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/a/two"), FaultStatus("Denied", 451)] public Results, FaultProblem> SATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/a/dup"), FaultStatus("Denied", 451)] public Results, FaultProblem> SADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/a/decl"), FaultStatus("Denied", 451), ProducesResponseType(429)] public Results> SADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/k/one")] public Results> SKOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/k/two")] public Results, FaultProblem> SKTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/k/dup")] public Results, FaultProblem> SKDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/k/decl"), ProducesResponseType(429)] public Results> SKDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC15ASApi : FxC15ASBase { } -internal sealed class FxC15ASPlain : FxC15ASBase { } - -internal abstract class FxC15AWBase : ControllerBase -{ - [HttpGet("c/s/a/one"), WithoutFaults("Down")] public Results> SAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/a/two"), WithoutFaults("Down")] public Results, FaultProblem> SATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/a/dup"), WithoutFaults("Down")] public Results, FaultProblem> SADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/a/decl"), WithoutFaults("Down"), ProducesResponseType(429)] public Results> SADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/k/one")] public Results> SKOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/k/two")] public Results, FaultProblem> SKTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/k/dup")] public Results, FaultProblem> SKDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/k/decl"), ProducesResponseType(429)] public Results> SKDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC15AWApi : FxC15AWBase { } -internal sealed class FxC15AWPlain : FxC15AWBase { } - -internal abstract class FxC15CSBase : ControllerBase -{ - [HttpGet("c/s/a/one")] public Results> SAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/a/two")] public Results, FaultProblem> SATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/a/dup")] public Results, FaultProblem> SADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/a/decl"), ProducesResponseType(429)] public Results> SADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/p/one"), FaultStatus("Denied", 452)] public Results> SPOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/p/two"), FaultStatus("Denied", 452)] public Results, FaultProblem> SPTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/p/dup"), FaultStatus("Denied", 452)] public Results, FaultProblem> SPDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/p/decl"), FaultStatus("Denied", 452), ProducesResponseType(429)] public Results> SPDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController, FaultStatus("Denied", 451)] internal sealed class FxC15CSApi : FxC15CSBase { } -[FaultStatus("Denied", 451)] internal sealed class FxC15CSPlain : FxC15CSBase { } - -internal abstract class FxC15CWBase : ControllerBase -{ - [HttpGet("c/s/a/one")] public Results> SAOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/a/two")] public Results, FaultProblem> SATwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/a/dup")] public Results, FaultProblem> SADup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/a/decl"), ProducesResponseType(429)] public Results> SADecl(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/p/one"), FaultStatus("Denied", 452)] public Results> SPOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/p/two"), FaultStatus("Denied", 452)] public Results, FaultProblem> SPTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/p/dup"), FaultStatus("Denied", 452)] public Results, FaultProblem> SPDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/p/decl"), FaultStatus("Denied", 452), ProducesResponseType(429)] public Results> SPDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController, WithoutFaults("Down")] internal sealed class FxC15CWApi : FxC15CWBase { } -[WithoutFaults("Down")] internal sealed class FxC15CWPlain : FxC15CWBase { } - -internal abstract class FxC15KBase : ControllerBase -{ - [HttpGet("c/s/k/one")] public Results> SKOne(int e) => FxErr.One(e).ToHttpResult(); - [HttpGet("c/s/k/two")] public Results, FaultProblem> SKTwo(int e) => FxErr.Two(e).ToHttpResult(); - [HttpGet("c/s/k/dup")] public Results, FaultProblem> SKDup(int e) => FxErr.Dup(e).ToHttpResult(); - [HttpGet("c/s/k/decl"), ProducesResponseType(429)] public Results> SKDecl(int e) => FxErr.One(e).ToHttpResult(); -} -[ApiController] internal sealed class FxC15KApi : FxC15KBase { } -internal sealed class FxC15KPlain : FxC15KBase { } - -public static partial class FxCtl -{ - static partial void Fill(Dictionary d) - { - d["C04Ep"] = new(typeof(FxC04EpApi), typeof(FxC04EpPlain), [], [new("fx/ep/wo", [new("HFault", "Down", 0)], []), new("fx/ep/keep", [], [])]); - d["C04EpS"] = new(typeof(FxC04EpSApi), typeof(FxC04EpSPlain), [new("HFault", "Down", 507)], [new("fx/ep/wo", [new("HFault", "Down", 0)], []), new("fx/ep/keep", [], [])]); - d["C04CtWo"] = new(typeof(FxC04CtWoApi), typeof(FxC04CtWoPlain), [new("HFault", "Down", 0)], [new("fx/ct/wo/a", [], []), new("fx/ct/wo/b", [], [])]); - d["C04CtKeep"] = new(typeof(FxC04CtKeepApi), typeof(FxC04CtKeepPlain), [], [new("fx/ct/keep", [], [])]); - d["C04Gr"] = new(typeof(FxC04GrApi), typeof(FxC04GrPlain), [], [new("fx/gr/a", [], []), new("fx/gr/b", [], [])]); - d["C06K"] = new(typeof(FxC06KApi), typeof(FxC06KPlain), [], [new("k", [], [])]); - d["C14Pp"] = new(typeof(FxC14PpApi), typeof(FxC14PpPlain), [], [new("d/pp", [], [404])]); - d["C14Prt"] = new(typeof(FxC14PrtApi), typeof(FxC14PrtPlain), [], [new("d/prt", [], [404])]); - d["C14None"] = new(typeof(FxC14NoneApi), typeof(FxC14NonePlain), [], [new("d/none", [], [])]); - d["C15M"] = new(typeof(FxC15MApi), typeof(FxC15MPlain), [], [new("s/a", [], []), new("s/p", [new("HFault", "Denied", 452)], [])]); - d["C15AS"] = new(typeof(FxC15ASApi), typeof(FxC15ASPlain), [], [new("s/a", [new("HFault", "Denied", 451)], []), new("s/k", [], [])]); - d["C15AW"] = new(typeof(FxC15AWApi), typeof(FxC15AWPlain), [], [new("s/a", [new("HFault", "Down", 0)], []), new("s/k", [], [])]); - d["C15CS"] = new(typeof(FxC15CSApi), typeof(FxC15CSPlain), [new("HFault", "Denied", 451)], [new("s/a", [], []), new("s/p", [new("HFault", "Denied", 452)], [])]); - d["C15CW"] = new(typeof(FxC15CWApi), typeof(FxC15CWPlain), [new("HFault", "Down", 0)], [new("s/a", [], []), new("s/p", [new("HFault", "Denied", 452)], [])]); - d["C15K"] = new(typeof(FxC15KApi), typeof(FxC15KPlain), [], [new("s/k", [], [])]); - } -} diff --git a/tools/probe/corpus/harness/FaultClaimSets.cs b/tools/probe/corpus/harness/FaultClaimSets.cs deleted file mode 100644 index 30111c23..00000000 --- a/tools/probe/corpus/harness/FaultClaimSets.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Fault types for C07-fault-responses-blanket (AspNetCore README#every-fault-set-at-once), each answered by one endpoint of its own beside the -// claim's: an enum (which no mapping for every set covers), a fault set with a member of no kind, and two fault sets the host's mapping -// refuses (one it throws for, one it gives a status that is no error). -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.AspNetCore; -using CodoMetis.TypeKit.ClosedSets; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.HttpResults; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; -namespace Probes.Faults; - -public enum FxEnum { Lost, Taken } -public sealed partial class FxNoKind : IFaultSet -{ - public static readonly FxNoKind Fine = new(FaultKind.NotFound, null); -#pragma warning disable CMTK0014 // a member of no kind, on purpose: the claim is that it stops the start - public static readonly FxNoKind Blank = new(default, null); -#pragma warning restore CMTK0014 - private FxNoKind(FaultKind kind, string? description) { Kind = kind; Description = description; } - public FaultKind Kind { get; } - public string? Description { get; } -} -public sealed partial class FxThrows : IFaultSet -{ - public static readonly FxThrows Odd = new(FaultKind.Conflict, null); - private FxThrows(FaultKind kind, string? description) { Kind = kind; Description = description; } - public FaultKind Kind { get; } - public string? Description { get; } -} -public sealed partial class FxStatus : IFaultSet -{ - public static readonly FxStatus Moved = new(FaultKind.NotFound, null); - private FxStatus(FaultKind kind, string? description) { Kind = kind; Description = description; } - public FaultKind Kind { get; } - public string? Description { get; } -} -/// What the application's mapping throws (set=mapping-throws). -public sealed class FxMappingRefused() : Exception("the mapping refuses FxThrows"); - -public static class FxSets -{ - public static Result> Enum(int e) { if (e == 0) return Result>.Success(); return Fault.Of(FxEnum.Lost); } - public static Result> NoKind(int e) { if (e == 0) return Result>.Success(); return Fault.Of(FxNoKind.Fine); } - public static Result> Throws(int e) { if (e == 0) return Result>.Success(); return Fault.Of(FxThrows.Odd); } - public static Result> Status(int e) { if (e == 0) return Result>.Success(); return Fault.Of(FxStatus.Moved); } - - /// The minimal endpoint answering the row's set, at /c7x. - public static void Map(IEndpointRouteBuilder b, string set) - { - switch (set) - { - case "enum-unmapped": b.MapGet("/c7x", (int e) => Enum(e).ToHttpResult()); break; - case "member-without-kind": b.MapGet("/c7x", (int e) => NoKind(e).ToHttpResult()); break; - case "mapping-throws": b.MapGet("/c7x", (int e) => Throws(e).ToHttpResult()); break; - case "status-not-error": b.MapGet("/c7x", (int e) => Status(e).ToHttpResult()); break; - } - } - /// The MVC controller answering the row's set. - public static Type[] Controllers(string set) => set switch - { - "enum-unmapped" => [typeof(FxC07Enum)], "member-without-kind" => [typeof(FxC07NoKind)], - "mapping-throws" => [typeof(FxC07Throws)], "status-not-error" => [typeof(FxC07Status)], _ => [], - }; -} -[ApiController] internal sealed class FxC07Enum : ControllerBase { [HttpGet("c/c7x/enum")] public Results> Get(int e) => FxSets.Enum(e).ToHttpResult(); } -[ApiController] internal sealed class FxC07NoKind : ControllerBase { [HttpGet("c/c7x/nokind")] public Results> Get(int e) => FxSets.NoKind(e).ToHttpResult(); } -[ApiController] internal sealed class FxC07Throws : ControllerBase { [HttpGet("c/c7x/throws")] public Results> Get(int e) => FxSets.Throws(e).ToHttpResult(); } -[ApiController] internal sealed class FxC07Status : ControllerBase { [HttpGet("c/c7x/status")] public Results> Get(int e) => FxSets.Status(e).ToHttpResult(); } diff --git a/tools/probe/corpus/harness/FaultControllers.cs b/tools/probe/corpus/harness/FaultControllers.cs deleted file mode 100644 index f93ff5dc..00000000 --- a/tools/probe/corpus/harness/FaultControllers.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Controllers answering with faults; the Plain* copies have no [ApiController] (http.host=controller-without-ApiController, and -// controller-without-ApiController-visible, where a convention puts them into the document). -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.AspNetCore; -using Microsoft.AspNetCore.Http.HttpResults; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -namespace Probes; - -[ApiController] -public sealed class MvcAController : ControllerBase -{ - [HttpGet("c/two")] public Results, FaultProblem> Two(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/wo"), WithoutFaults(nameof(HFault.Missing), nameof(HFault.Bad))] - public Results, FaultProblem> Wo(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/fs"), FaultStatus(nameof(HFault.Clash), 422)] - public Results, FaultProblem> Fs(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/three")] public Results, FaultProblem, FaultProblem> Three(int e) => Errors.Three(e).ToHttpResult(); - [HttpGet("c/declared404"), ProducesResponseType(404)] - public Results, FaultProblem> Declared404(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/declared"), ProducesResponseType(429)] - public Results, FaultProblem> Declared(int e) => Errors.Two(e).ToHttpResult(); -} -[ApiController, FaultStatus(nameof(HFault.Denied), 451), WithoutFaults(nameof(HFault.Down))] -public sealed class MvcBController : ControllerBase -{ - [HttpGet("d/two")] public Results, FaultProblem> Two(int e) => Errors.Two(e).ToHttpResult(); -} - - -public sealed class PlainAController : ControllerBase -{ - [HttpGet("c/two")] public Results, FaultProblem> Two(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/wo"), WithoutFaults(nameof(HFault.Missing), nameof(HFault.Bad))] - public Results, FaultProblem> Wo(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/fs"), FaultStatus(nameof(HFault.Clash), 422)] - public Results, FaultProblem> Fs(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/three")] public Results, FaultProblem, FaultProblem> Three(int e) => Errors.Three(e).ToHttpResult(); - [HttpGet("c/declared404"), ProducesResponseType(404)] - public Results, FaultProblem> Declared404(int e) => Errors.Two(e).ToHttpResult(); - [HttpGet("c/declared"), ProducesResponseType(429)] - public Results, FaultProblem> Declared(int e) => Errors.Two(e).ToHttpResult(); -} -[FaultStatus(nameof(HFault.Denied), 451), WithoutFaults(nameof(HFault.Down))] -public sealed class PlainBController : ControllerBase -{ - [HttpGet("d/two")] public Results, FaultProblem> Two(int e) => Errors.Two(e).ToHttpResult(); -} - diff --git a/tools/probe/corpus/harness/Faults.cs b/tools/probe/corpus/harness/Faults.cs deleted file mode 100644 index eac16d31..00000000 --- a/tools/probe/corpus/harness/Faults.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Fault types, error tables and shared logging for the HTTP probes (harness; see HttpHost.cs). -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -using CodoMetis.TypeKit.ClosedSets; -using Microsoft.AspNetCore.Mvc.ApplicationParts; -using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.Extensions.Logging; -using System.Reflection; -namespace Probes; - -public sealed partial class HFault : IFaultSet -{ - public static readonly HFault Missing = new(FaultKind.NotFound, "Missing."); - public static readonly HFault Clash = new(FaultKind.Conflict, null); - public static readonly HFault Bad = new(FaultKind.Invalid, null); - public static readonly HFault Denied = new(FaultKind.Forbidden, null); - public static readonly HFault Down = new(FaultKind.Unavailable, null); - public static readonly HFault Stale = new(FaultKind.PreconditionFailed, null); - public static readonly HFault Garbled = new(FaultKind.Malformed, null); - private HFault(FaultKind kind, string? description) { Kind = kind; Description = description; } - public FaultKind Kind { get; } - public string? Description { get; } -} -public sealed partial class GFault : IFaultSet -{ - public static readonly GFault Gone = new(FaultKind.NotFound, null); - public static readonly GFault Raced = new(FaultKind.Conflict, null); - public static readonly GFault Old = new(FaultKind.PreconditionFailed, null); - private GFault(FaultKind kind, string? description) { Kind = kind; Description = description; } - public FaultKind Kind { get; } - public string? Description { get; } -} -public enum SFault { First, Second } -public enum PRule { A, B } -[Flags] public enum FRule { P = 1, Q = 2 } -public static class Holder { public enum NestedRule { N } } -public sealed partial class RuleSet : IClosedSet { public static readonly RuleSet X = new(); public static readonly RuleSet Y = new(); } - -public static class Errors -{ - public static Result> Two(int e) => e switch - { - 0 => Result>.Success(), - 1 => Fault.Of(HFault.Missing), - 2 => Fault.Of(HFault.Clash), - 3 => Fault.Of(HFault.Bad), - 4 => Fault.Of(HFault.Denied), - 5 => Fault.Of(HFault.Down), - 6 => Fault.Of(HFault.Stale), - 7 => Fault.Of(HFault.Garbled), - 8 => Fault.Of(GFault.Gone), - 9 => Fault.Of(GFault.Raced), - 10 => Fault.Of(GFault.Old), - _ => throw new ArgumentOutOfRangeException(nameof(e)), - }; - public static Result> Three(int e) => e switch - { - 0 => Result>.Success(), - 1 => Fault.Of(HFault.Missing), - 8 => Fault.Of(GFault.Gone), - 11 => Fault.Of(SFault.First), - 12 => Fault.Of(Fault.Of(SFault.Second, "second detail").WithRule(PRule.B)), - 13 => Fault.Of(Fault.Of(HFault.Clash).WithRule(RuleSet.X)), - 14 => Fault.Of(Fault.Of(GFault.Raced).WithRule(Holder.NestedRule.N)), - _ => throw new ArgumentOutOfRangeException(nameof(e)), - }; - public static Result> One(int e) => e switch - { - 0 => Result>.Success(), - 1 => Fault.Of(HFault.Missing), - 2 => Fault.Of(HFault.Clash), - 4 => Fault.Of(HFault.Denied), - 5 => Fault.Of(HFault.Down), - _ => throw new ArgumentOutOfRangeException(nameof(e)), - }; - public static Result> OneG(int e) => e switch - { - 0 => Result>.Success(), - 8 => Fault.Of(GFault.Gone), - 9 => Fault.Of(GFault.Raced), - _ => throw new ArgumentOutOfRangeException(nameof(e)), - }; -} - -public sealed class ListedLogs : ILoggerProvider -{ - public List Lines { get; } = []; - public ILogger CreateLogger(string categoryName) => new L(this); - public void Dispose() { } - private sealed class L(ListedLogs o) : ILogger - { - public IDisposable? BeginScope(TState state) where TState : notnull => null; - public bool IsEnabled(LogLevel logLevel) => true; - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) => - o.Lines.Add($"{logLevel}: {formatter(state, exception)}"); - } -} - -public sealed class OnlyControllers(Type[] controllers) : IApplicationFeatureProvider -{ - public void PopulateFeature(IEnumerable parts, ControllerFeature feature) - { - foreach (var c in controllers) feature.Controllers.Add(c.GetTypeInfo()); - } -} - diff --git a/tools/probe/corpus/harness/HandOrdered.cs b/tools/probe/corpus/harness/HandOrdered.cs deleted file mode 100644 index c1c72cfb..00000000 --- a/tools/probe/corpus/harness/HandOrdered.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Value objects that declare their own CompareTo(TSelf) (a descending order), for the EF claims about hand-written ordering. -#nullable enable -#pragma warning disable CMTK0014, CS8618, CS1591, CMTK0005, CMTK1000, CMTK0003, CMTK0006 -using CodoMetis.TypeKit.ValueObjects; -namespace Probes.Ef; - -public readonly partial record struct HO_int_struct : IValue { public int CompareTo(HO_int_struct other) => other.Value.CompareTo(Value); } -public readonly partial record struct HO_string_struct : IValue { public int CompareTo(HO_string_struct other) => string.CompareOrdinal(other.Value, Value); } -public readonly partial record struct HO_decimal_struct : IValue { public int CompareTo(HO_decimal_struct other) => other.Value.CompareTo(Value); } -public readonly partial record struct HO_DateTime_struct : IValue { public int CompareTo(HO_DateTime_struct other) => other.Value.CompareTo(Value); } -public sealed partial record class HO_int_class : IValue { public int CompareTo(HO_int_class? other) => other is null ? 1 : other.Value.CompareTo(Value); } -public sealed partial record class HO_string_class : IValue { public int CompareTo(HO_string_class? other) => other is null ? 1 : string.CompareOrdinal(other.Value, Value); } - -public static class HandOrdered -{ - public sealed record Entry(string Name, Type Vo, Type Plain, object[] Values); - public static readonly Entry[] All = - [ - new("int-struct", typeof(HO_int_struct), typeof(int), [1, 2, 3]), - new("string-struct", typeof(HO_string_struct), typeof(string), ["a", "b", "c"]), - new("decimal-struct", typeof(HO_decimal_struct), typeof(decimal), [1.5m, 2.5m, 3.5m]), - new("DateTime-struct", typeof(HO_DateTime_struct), typeof(DateTime), [new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(2026, 1, 2, 0, 0, 0, DateTimeKind.Utc), new DateTime(2026, 1, 3, 0, 0, 0, DateTimeKind.Utc)]), - new("int-class", typeof(HO_int_class), typeof(int), [1, 2, 3]), - new("string-class", typeof(HO_string_class), typeof(string), ["a", "b", "c"]), - ]; - public static Entry Of(string name) => All.First(e => e.Name == name); - public static object Make(Entry e, object plain) => e.Vo.GetMethod("From", [e.Plain])!.Invoke(null, [plain])!; -} diff --git a/tools/probe/corpus/harness/HttpBaseline.cs b/tools/probe/corpus/harness/HttpBaseline.cs deleted file mode 100644 index 731f5d84..00000000 --- a/tools/probe/corpus/harness/HttpBaseline.cs +++ /dev/null @@ -1,800 +0,0 @@ -// The baseline every http claim shares: under the row's options, a payload with the value object behaves like the same payload with the wrapped -// type (response bytes, request reading, parameter binding, OpenAPI schema), in the hosting models the row's http.host names. -// Oracle: differential (JSON/wire/schema parity), each comparison a check (Row.Check); a difference a document makes intended ends its check -// as that citation (Cite), and one no document makes intended is compared. -using System.Net; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using System.Text.Json; -using System.Text.Json.Nodes; -using CodoMetis.TypeKit.Facts; -namespace Probes.Shapes; - -public static class HttpBaseline -{ - static string Cut(string? s) => s is null ? "(null)" : s.Length > 220 ? s[..220] + "..." : s; - - /// True only where the shape's Create refuses exactly the wrapped type's limit (the validated byte refuses 255): - /// anywhere else a refused limit is the value object's to explain. - static bool RefusesItsLimit(Entry e) - { - var refused = e.RefusedFn(); // the plain value the shape's Create refuses - if (refused is null) return false; - var t = Make.Held(e.Plain); - return new[] { "MaxValue", "MinValue" }.Any(f => t.GetField(f)?.GetValue(null) is { } limit && limit.Equals(refused)); - } - - /// - /// One wire comparison with the twin, inside its check : the wrapped type's answer (side (2)) and the - /// value object's (side (3)); side (1) refusing alike was decided before the check (). A difference a - /// document makes intended ends the check as that document's citation; BaseProbe calibrates the host on C07's rows, whose claim promises - /// nothing of the wire, so these cite the sentence itself, not a not-promised entry of C07. - /// - static string? Same(Check c, Row r, Entry e, string what, Hx.Wire p, Hx.Wire v, string input = "valid") - { - r.Log.AppendLine($"{what}: plain {(int)p.Status} {Cut(p.Body)} {p.Thrown} | vo {(int)v.Status} {Cut(v.Body)} {v.Thrown}"); - bool ok(Hx.Wire w) => (int)w.Status is >= 200 and < 300; - // both refused, and not as the twin without TypeKit refuses (Sides.Alike): evidence about refusing, and nothing to compare - if (!ok(p) && !ok(v)) return c.Inconclusive($"{what}: both refuse, not alike: wrapped {p.Side(what)}, value object {v.Side(what)}"); - // "Your own converter wins": the application's converter writes the value object instead of the generated one. - if (r.Is("json.Converters", "own-for-value-object") && ok(v)) return c.Inapplicable(Cite.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says"), what); - if (ok(p) && !ok(v)) - { - if (ReadRefusedAsDocumented(c, r, e, input, what)) return null; - // the same: the value object's array reads a JSON array of numbers, never the base64 string the twin's byte[] wrote and reads - if (ByteArray(r, e)) return c.Inapplicable(Cite.Docs("docs/json.md#the-wrapped-types-json"), what); - // A closed set travels as its member's name; the wrapped type under the application's converter is no reference. - if (e.Kind == "closed-set" && r.Is("json.Converters", "own-for-wrapped")) return c.Inapplicable(Cite.Docs("README.md#what-you-get"), what); - // The validated shapes' Create refuses the wrapped type's limit on purpose, so the limit input is a refusal. - if (e.Kind.StartsWith("validated") && input == "at-type-limit" && RefusesItsLimit(e)) return c.Refused(Cite.Docs("docs/json.md#when-a-value-is-rejected"), what); - return (e.Wrapped == "NodaTime.Instant" && what.StartsWith("mvc bind") ? "[F1] " : "") + $"{what}: wrapped answered {(int)p.Status} {Cut(p.Body)}, value object answered {(int)v.Status} {Cut(v.Body)} {v.Thrown}"; - } - if (!ok(p) && ok(v)) - { - // docs/json.md "Null and missing": a struct value object rejects a JSON null; a sealed partial record reads it as null, - // like any class, where the struct it wraps refuses it. - if (input == "null" && Make.AdmitsNull(e.Vo) && !Make.AdmitsNull(e.Plain)) return c.Refused(Cite.Docs("docs/json.md#null-and-missing"), what); - return $"{what}: value object answered {(int)v.Status} {Cut(v.Body)} where wrapped answered {(int)p.Status} {Cut(p.Body)} {p.Thrown}"; - } - if (p.Body != v.Body) - { - // A closed set travels as its member's name, never as the string or number standing in for it. - if (e.Kind == "closed-set") return c.Inapplicable(Cite.Docs("README.md#what-you-get"), what); - // docs/json.md "The wrapped type's JSON": an array of value objects over byte is a JSON array of numbers, where the twin, a byte[], - // is one base64 string (KB-038). - if (ByteArray(r, e)) return c.Inapplicable(Cite.Docs("docs/json.md#the-wrapped-types-json"), what); - return $"{what}: bodies differ: wrapped {Cut(p.Body)} vs value object {Cut(v.Body)}"; - } - c.Note(NoteKeys.Compared, what); - return null; - } - - /// - /// One check of the wire, three-sided (Sides): side (2) and side (3) answered on the host with - /// TypeKit; side (1) is asked of the host without it (), lazily, only where they disagree or refuse. Where (1) - /// refuses alike with (3), the check is the framework's refusal against Baseline.Framework; where (1) answers and the value object's - /// write was refused under a depth limit, side (1) is a converter's value there (KB-040, in process); otherwise - /// compares, once (2) is held to (1). - /// - static async Task Wire(Row r, Entry e, string obligation, Baseline against, string what, Hx.Wire p, Hx.Wire v, Func> one, Func> body) - { - var two = p.Side(what); var three = v.Side(what); - Sides.Answer? first = null; Sides.Side? framework = null; - if (two.Refused || three.Refused || p.Body != v.Body) - { - if (await one() is { } w) first = w.Side(what); - if (three.Refused && first is { Refused: true } && Sides.Alike(first, three)) framework = Sides.Measured(first, "the twin on a host without TypeKit"); - else if (three.Refused && v.Ex is { } thrown && first is { Refused: false } && (Sides.Why = null) is null - && Sides.WrittenByAConverter(r, e, Twin(r, e), Sides.WithoutTypeKit(JsonRow.Apply(r, e).Options!), new("write", null, thrown)) is { } converter - && Sides.Alike(converter.Answer, new("write", null, thrown))) - return Sides.Check(r, obligation, against, converter, new("write", null, thrown), null, null, _ => (string?)null); - } - var failed = await Sides.Check(r, obligation, against, framework, three, first, first is null ? null : two, body); - // the failure names side (1), for the triage of the row - return failed is null || first is null ? failed : failed + $" [side (1), the twin without TypeKit: {first}{(Sides.Why is { } why ? "; " + why : "")}]"; - } - - /// The wrapped twin's payload, as the echo writes it: the row's position and containing type around the wrapped value. - static Held Twin(Row r, Entry e) => Pos.Build(r["shape.position"], r.Get("shape.containing") ?? "class", e, false, e.Valid()); - - /// An array of value objects over byte, whose twin is a byte[] (KB-038). - static bool ByteArray(Row r, Entry e) => e.Wrapped == "byte" && r["shape.position"] == "array-element"; - - /// What MVC writes for a type's default: null for no content (a reference, or a Nullable), else its JSON under MVC's options. - static string? DefaultBody(WebApplication app, Type t) => - !t.IsValueType || Nullable.GetUnderlyingType(t) is not null ? null - : JsonSerializer.Serialize(Activator.CreateInstance(t), t, app.Services.GetRequiredService>().Value.JsonSerializerOptions); - - /// - /// Whether an answer is the type's default as MVC writes it: 204 for null, else 200 with its JSON, compared as JSON, since MVC's - /// formatter escapes with its own encoder where the options name none. - /// - static bool HoldsDefault(Hx.Wire w, string? body) - { - if (body is null) return w.Status == HttpStatusCode.NoContent; - if (w.Status != HttpStatusCode.OK) return false; - try { return JsonNode.DeepEquals(JsonNode.Parse(w.Body), JsonNode.Parse(body)); } - catch (JsonException) { return false; } - } - - /// A text the wrapped type does not read, for a twin that shows what MVC does with a binding failure; none where any text binds. - static string? Unreadable(Entry e) => e.Wrapped is "string" or "Uri" or "own-record-class" ? null : "abc"; - - /// - /// The value object refused a read the wrapped type answered, as a document says it does (the JSON family's documented differences, each - /// cited by its sentence; JsonParity.ReadMayDiffer listed them uncited): side (1) answered and (3) refused, which the citation makes - /// intended (Sides). The check ends as that refusal and true is returned. - /// - static bool ReadRefusedAsDocumented(Check c, Row r, Entry e, string input, string what) - { - if (r.Is("json.ReferenceHandler", "Preserve") && e.Wrapped == "own-record-class") { c.Refused(Cite.Docs("src/CodoMetis.TypeKit.Generators/README.md#json"), what); return true; } - if (e.Kind.StartsWith("validated") && input == "refused-by-create" && r.Get("json.Converters") != "StoredJsonConverterFactory") { c.Refused(Cite.Docs("docs/json.md#when-a-value-is-rejected"), what); return true; } - if (input == "null" && !Make.AdmitsNull(e.Vo)) { c.Refused(Cite.Docs("docs/json.md#null-and-missing"), what); return true; } - if (e.Kind == "closed-set" && input != "valid") { c.Refused(Cite.Docs("README.md#what-you-get"), what); return true; } - return false; - } - - /// Where two schemas first differ, and what each side has there: the comparison's 220 characters rarely reach it. - static string FirstDifference(JsonNode? p, JsonNode? v, string path) => - Difference(p, v, path) is var d ? $"{d.Path}: wrapped {Cut(d.P?.ToJsonString() ?? "(absent)")} | value object {Cut(d.V?.ToJsonString() ?? "(absent)")}" : ""; - - /// - /// Where two schemas first differ: the path as it is shown, the keys that lead there (a property's name, an element's index), each - /// side's node there (null where it is absent) and the node holding it, so a difference is told by its structure, never by its path's text. - /// - sealed record Diff(string Path, IReadOnlyList Keys, JsonNode? P, JsonNode? V, JsonNode? ParentP, JsonNode? ParentV); - - static Diff Difference(JsonNode? p, JsonNode? v, string path) => Difference(p, v, path, [], null, null); - - static Diff Difference(JsonNode? p, JsonNode? v, string path, List keys, JsonNode? parentP, JsonNode? parentV) - { - if (p is JsonObject po && v is JsonObject vo) - { - foreach (var k in po.Select(kv => kv.Key).Union(vo.Select(kv => kv.Key)).Order(StringComparer.Ordinal)) - if (!JsonNode.DeepEquals(po[k], vo[k])) return Difference(po[k], vo[k], path + "." + k, [.. keys, k], p, v); - } - else if (p is JsonArray pa && v is JsonArray va && pa.Count == va.Count) - { - for (var i = 0; i < pa.Count; i++) - if (!JsonNode.DeepEquals(pa[i], va[i])) return Difference(pa[i], va[i], $"{path}[{i}]", [.. keys, i.ToString(System.Globalization.CultureInfo.InvariantCulture)], p, v); - } - return new(path, keys, p, v, parentP, parentV); - } - - /// The node the keys of a lead to in another schema, or null where it has none. - static JsonNode? At(JsonNode? node, IEnumerable keys) - { - foreach (var k in keys) - node = node switch { JsonObject o => o[k], JsonArray a when int.TryParse(k, out var i) && i < a.Count => a[i], _ => null }; - return node; - } - - /// - /// Side (1) of a row's wire and schema comparisons: the same host started without TypeKit (HostCfg.WithoutTypeKit), once, on the first - /// comparison that asks for it; null where it does not start, which no comparison then excuses anything by. The twin's side (1) is a - /// host with the twin's endpoints alone (plain): ASP.NET alone describing the value object's types beside them names components - /// after them and writes the twin's own schemas otherwise. A host with both (both) answers for the value object's position. - /// - sealed class SideOne(Row r, Entry e, string only) : IAsyncDisposable - { - Task? started; - public string? Down { get; private set; } - public Task Host() => started ??= Start(); - async Task Start() - { - try { return await Hx.Start(r, e, new HostCfg { FaultControllers = false, MapBlanketMapping = false, WithoutTypeKit = true, PayloadOnly = only }); } - catch (Exception x) when (x is not Sides.InputsNotEquivalent) { Down = x.GetType().Name + ": " + Cut(x.Message); r.Log.AppendLine("side (1) host did not start: " + Down); return null; } - } - public async Task Ask(Func> ask) => await Host() is { } app ? await ask(app) : null; - public async ValueTask DisposeAsync() { if (started is not null && await started is { } app) await app.DisposeAsync(); } - } - - /// - /// BaseProbe's calibration of the shared host: every wire comparison a check of its own, named (BaseProbe - /// runs on rows of C07, which promises nothing of the wire, so its checks are the implicit claim). Per side: the echo against the - /// twin; the request read with the row's input.json, against the twin, or a closed set against its own response read back; the binding of - /// the row's http.binding with a valid value against the twin, and with a value Create refuses against the documented 400. Each is - /// three-sided (Sides): side (1), the twin on the same host without TypeKit, is asked where the twin and the value object disagree or - /// refuse. With , the schema parity too (C21's check). Every check runs; the first failure is returned. - /// - public static async Task Run(Row r, Entry e, bool schema = true, string obligation = "claim") - { - WebApplication app; - try { app = await Hx.Start(r, e, new HostCfg { FaultControllers = false, MapBlanketMapping = false }); } - catch (Exception ex) when (ex is not Sides.InputsNotEquivalent) { return "baseline host did not start: " + ex.GetType().Name + ": " + Cut(ex.Message); } - await using var _ = app; - await using var one = new SideOne(r, e, "plain"); - await using var alone = new SideOne(r, e, "both"); - var jopts = JsonRow.Apply(r, e).Options!; - var position = r["shape.position"]; - var plainSample = e.Valid(); - var input = r.Get("input.json") ?? "valid"; - var ownVo = r.Is("json.Converters", "own-for-value-object"); - var bind = r["http.binding"]; - string? failed = null; - var sides = new List<(string name, Func path, string echo, string inn, string bindPre)>(); - if (Hx.HasMinimal(r)) sides.Add(("minimal", p => Hx.M(r, p), "/echo/", "/in/", "/bind/")); - if (Hx.HasMvc(r)) sides.Add(("mvc", p => Hx.C(r, p), "/mvc/echo/", "/mvc/in/", "/mvc/bind/")); - foreach (var (name, path, echo, inn, bindPre) in sides) - { - // 1. response side - var ep = await Hx.Get(app, path(echo + "plain")); var ev = await Hx.Get(app, path(echo + "vo")); - var f1 = await Wire(r, e, obligation, Baseline.Twin, name + " echo", ep, ev, () => one.Ask(h => Hx.Get(h, path(echo + "plain"))), - c => Task.FromResult(Same(c, r, e, name + " echo", ep, ev))); - failed ??= f1; - // 2. request side, with the row's input.json, where the wrapped type's echo gave a body to change - if ((int)ep.Status == 200) - { - string? f2; - if (ownVo) - // "Your own converter wins": the application's converter reads the value object, so the twin's text is none of its; - // only that it reads its own response back is held, and the check earns nothing. - f2 = await r.Check(obligation, Baseline.RoundTrip, async c => - { - var ip = await Hx.Send(app, HttpMethod.Post, path(inn + "plain"), ep.Body); var iv = await Hx.Send(app, HttpMethod.Post, path(inn + "vo"), ev.Body); - if ((int)ev.Status == 200 && (int)iv.Status != 200 && (int)ip.Status == 200) return $"{name} in: the value object cannot read its own response ({(int)iv.Status}): {Cut(iv.Body)}"; - return c.Inapplicable(Cite.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says"), name + " in"); - }); - else if (e.Kind == "closed-set") - // A closed set travels as its member's name (README "What you get"): the string standing in for it is no twin, so the - // value object reads its own response back. - f2 = await r.Check(obligation, Baseline.RoundTrip, async c => - { - if ((int)ev.Status != 200) return c.Inconclusive($"{name} in: the value object's echo answered {(int)ev.Status}, no response of its own to read back"); - var ip = await Hx.Send(app, HttpMethod.Post, path(inn + "plain"), ep.Body); var iv = await Hx.Send(app, HttpMethod.Post, path(inn + "vo"), ev.Body); - r.Log.AppendLine($"{name} in(own response): plain {(int)ip.Status} {Cut(ip.Body)} {ip.Thrown} | vo {(int)iv.Status} {Cut(iv.Body)} {iv.Thrown}"); - // The wrapped type does not read its own response back under the row's options either: nothing to tell. - if ((int)iv.Status != 200 && (int)ip.Status != 200) return c.Inconclusive($"{name} in: neither side reads its own response back ({(int)ip.Status}, {(int)iv.Status})"); - if ((int)iv.Status != 200) return $"{name} in: the closed set cannot read its own response ({(int)iv.Status}), the wrapped type reads its own: {Cut(iv.Body)} {iv.Thrown}"; - c.Note(NoteKeys.Compared, name + " in: its own response read back"); - return null; - }); - else - { - var text = JsonParity.InputFor(input, e, jopts, ep.Body, position); - var ip = await Hx.Send(app, HttpMethod.Post, path(inn + "plain"), text); var iv = await Hx.Send(app, HttpMethod.Post, path(inn + "vo"), text); - var what = name + " in(" + input + ")"; - f2 = await Wire(r, e, obligation, Baseline.Twin, what, ip, iv, () => one.Ask(h => Hx.Send(h, HttpMethod.Post, path(inn + "plain"), text)), - c => Task.FromResult(Same(c, r, e, what, ip, iv, input))); - } - failed ??= f2; - } - // 3. binding, the row's http.binding - var unbindable = e.Wrapped == "own-record-class" && bind != "body" ? "a record class" - : e.Wrapped == "NodaTime.Instant" && name == "minimal" && bind != "body" ? "Instant in a minimal API" : null; - if (unbindable is not null) - { - // No sentence cites it: the wrapped type is not bound from text either, so neither side has an endpoint and there is no twin. - r.Check(obligation, Baseline.Twin, c => c.Inconclusive($"{name} bind {bind}: {unbindable} is not bound from text, the wrapped type neither")); - continue; - } - if (bind == "body" && ownVo) - { - // "Your own converter wins": the application's converter reads the body, not the twin's JSON. - r.Check(obligation, Baseline.Twin, c => c.Inapplicable(Cite.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says"), $"{name} bind body")); - continue; - } - var valid = Hx.BindText(e, plainSample); - var refused = e.Refused() is { } rf ? Hx.BindText(e, rf) : null; - async Task B(WebApplication host, string which, string txt, string w) - { - var enc = Uri.EscapeDataString(txt); - return bind switch - { - "route" => await Hx.Get(host, path(bindPre + "route/" + w + "/" + enc)), - "query" => await Hx.Get(host, path(bindPre + "query/" + w + "?v=" + enc)), - "as-parameters" => await Hx.Get(host, path(bindPre + "params/" + w + "?v=" + enc)), - "header" => await Hx.Send(host, HttpMethod.Get, path(bindPre + "header/" + w), header: ("v", txt)), - "form" => await Hx.Send(host, HttpMethod.Post, path(bindPre + "form/" + w), "v=" + enc, "application/x-www-form-urlencoded"), - _ => await Hx.Send(host, HttpMethod.Post, path(bindPre + "body/" + w), - which == "valid" ? JsonSerializer.Serialize(plainSample, e.Plain, jopts) : which == "refused" ? JsonSerializer.Serialize(e.Refused(), e.Plain, jopts) : JsonSerializer.Serialize(txt)), - }; - } - // Both sides are mapped for every binding they reach here: a 404 is the harness's routing, never a binding result. Counted as - // "plain unbindable", a plain route mapped under another name went unnoticed. - static string? Routed(string name, string bind, Hx.Wire bp, Hx.Wire bv) => - bp.Status == HttpStatusCode.NotFound || bv.Status == HttpStatusCode.NotFound - ? $"harness: {name} bind {bind} has no endpoint (plain {(int)bp.Status}, value object {(int)bv.Status})" : null; - // A text a route segment cannot carry as it is ('/', ':', '?', '#'): escaped, it arrives as other text ('%2F' stays), so the value - // bound is not the one sent. A limit of the harness, which no sentence cites: the check cannot tell. - bool Unsafe(string txt) => bind == "route" && (txt.Contains('/') || txt.Contains(':') || txt.Contains('?') || txt.Contains('#')); - string? Unplaceable(Check c, string txt) => c.Inconclusive($"{name} bind route: the text {txt} cannot be carried by a route segment as it is"); - string? f3; - if (Unsafe(valid)) f3 = r.Check(obligation, Baseline.Twin, c => Unplaceable(c, valid)); - else - { - var bp = await B(app, "valid", valid, "plain"); var bv = await B(app, "valid", valid, "vo"); - r.Log.AppendLine($"{name} bind {bind} valid text={valid}: plain {(int)bp.Status} {Cut(bp.Body)} {bp.Thrown} | vo {(int)bv.Status} {Cut(bv.Body)} {bv.Thrown}"); - f3 = Routed(name, bind, bp, bv) is { } unrouted - ? r.Check(obligation, Baseline.Twin, _ => unrouted) - : await Wire(r, e, obligation, Baseline.Twin, name + " bind " + bind, bp, bv, () => one.Ask(h => B(h, "valid", valid, "plain")), - c => Task.FromResult(Same(c, r, e, name + " bind " + bind, bp, bv))); - } - failed ??= f3; - if (refused is null) continue; - // README "Binding" (AspNetCore): a value Create rejects gets a 400, the one set of rules. - var against = Baseline.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#binding"); - if (Unsafe(refused)) { failed ??= r.Check(obligation, against, c => Unplaceable(c, refused)); continue; } - var rp = await B(app, "refused", refused, "plain"); var rv = await B(app, "refused", refused, "vo"); - r.Log.AppendLine($"{name} bind {bind} refused text={refused}: plain {(int)rp.Status} {Cut(rp.Body)} {rp.Thrown} | vo {(int)rv.Status} {Cut(rv.Body)} {rv.Thrown}"); - if (Routed(name, bind, rp, rv) is { } unrouted2) { failed ??= r.Check(obligation, against, _ => unrouted2); continue; } - // Side (1) of a refused binding: the twin on the host without TypeKit, refused a binding too, as MVC refuses a text the wrapped - // type cannot read. Where the value object's refusal could not be answered (a 500, which MVC's 400 under a source-generated - // context that does not list ValidationProblemDetails is, KB-041), the twin's refused binding is side (1): read from KB-041's - // fixture where it covers the row, else asked of the host without TypeKit. - Sides.Side? framework = null; - if (rv.Ex is { } refusal && Unreadable(e) is { } unreadable) - { - var settings = Sides.Settings(r, ("endpoint", name == "mvc" ? "mvc-api-controller" : "minimal"), ("binding", "fails")); - if (Sides.Covered(r, "KB-041", settings) is { Kind: FactAnswer.Exception } answer) - framework = new(new(name + " bind " + bind + " refused", null, Status: 500, FixtureRefusal: (string?)answer.Value["type"]), Baseline.Fact("KB-041"), $"KB-041 {answer.Id}: a binding MVC refuses, under a source-generated context"); - else if (await one.Ask(h => B(h, "unreadable", unreadable, "plain")) is { } twin) - framework = Sides.Measured(twin.Side(name + " bind " + bind + " refused"), $"the twin on a host without TypeKit, sent {unreadable}"); - } - var f4 = await Sides.Check(r, obligation, against, framework, rv.Side(name + " bind " + bind + " refused"), null, null, async c => - { - if ((int)rp.Status is not (>= 200 and < 300)) return c.Inconclusive($"{name} bind {bind}: the wrapped type refuses the value Create refuses too ({(int)rp.Status})"); - if (r.Is("json.ReferenceHandler", "Preserve") && e.Wrapped == "own-record-class") return c.Refused(Cite.Docs("src/CodoMetis.TypeKit.Generators/README.md#json"), "bind"); - // README "What TypeKit guarantees": StoredJsonConverterFactory reads JSON the application stored itself, without validation. - if (bind == "body" && r.Is("json.Converters", "StoredJsonConverterFactory")) return c.Inapplicable(Cite.Docs("README.md#what-typekit-guarantees"), "bind body"); - // KB-037: under MaxValidationDepth=1 MVC runs an action whose parameter it could not bind, with the parameter at its default. The - // value object must hold its default then, never the refused value; side (1), the twin sent a text it cannot read, shows the - // framework doing the same: read from KB-037's fixture where it covers the row, else asked of the host without TypeKit. - if (name == "mvc" && r.Is("mvc.MaxValidationDepth", "1") && (int)rv.Status is >= 200 and < 300) - { - if (DefaultBody(app, e.Vo) is var voDefault && !HoldsDefault(rv, voDefault)) - return $"{name} bind {bind}: validated value object bound the refused value (status {(int)rv.Status}) {Cut(rv.Body)}, not its default ({(voDefault is null ? "204" : "200 " + Cut(voDefault))})"; - if (Unreadable(e) is not { } text) - return c.Inapplicable(Cite.Fact("KB-037"), $"{name} bind {bind}: the value object holds its default; any text binds the wrapped type, so no twin shows it"); - Hx.Wire? bt; - if (Sides.Covered(r, "KB-037", Sides.Settings(r, ("text", text))) is { Kind: FactAnswer.Status } answer) - bt = new((HttpStatusCode)(int)answer.Value["status"]!, (string?)answer.Value["body"] ?? ""); - else bt = await one.Ask(h => B(h, "unreadable", text, "plain")); - if (bt is null) return c.Inconclusive($"{name} bind {bind}: the value object holds its default (KB-037); no host without TypeKit to show the wrapped type's ({one.Down})"); - r.Log.AppendLine($"{name} bind {bind} unreadable text={text}: plain {(int)bt.Status} {Cut(bt.Body)} {bt.Thrown}"); - if (HoldsDefault(bt, DefaultBody(app, e.Plain))) - return c.Inapplicable(Cite.Fact("KB-037"), $"{name} bind {bind}: both hold their default, the wrapped type for a text it cannot read"); - if ((int)bt.Status is >= 400 and < 500) - return $"{name} bind {bind}: the value object answered {(int)rv.Status} holding its default, where the wrapped type rejects a text it cannot read ({(int)bt.Status})"; - // KB-037's class from the query: the validator throws at the twin's property, and the value object, written by a - // converter of its own, is no class it walks - return c.Inconclusive($"{name} bind {bind}: the value object holds its default (KB-037); the wrapped type answered {(int)bt.Status} {Cut(bt.Body)} {bt.Thrown}"); - } - // a refused value must not bind (the one set of rules), except where the application skips validation on purpose - if ((int)rv.Status is >= 200 and < 300) return $"{name} bind {bind}: validated value object bound the refused value (status {(int)rv.Status}) {Cut(rv.Body)}"; - if ((int)rv.Status != 400) return $"{name} bind {bind}: refused value answered {(int)rv.Status}, expected 400: {Cut(rv.Body)} {rv.Thrown}"; - c.Note(NoteKeys.Compared, $"{name} bind {bind}: the refused value answered 400"); - return null; - }); - failed ??= f4; - } - // 4. schema parity - if (schema) { var f5 = await r.Check(obligation, Baseline.Twin, async c => await SchemaParity(app, one, alone, r, e, c)); failed ??= f5; } - return failed; - } - - /// - /// The schema parity alone, on the same host as : claim C21's check (C21OpenapiSchemaParityProbe), which BaseProbe leaves - /// out of its calibration, run once for each of the row's against the twin. C21 promises the schema ASP.NET - /// Core publishes for the underlying type, so side (1), the same host without TypeKit, is started on every row (Sides.Unconditional). - /// Every check runs; the first failure is returned. - /// - public static async Task Schema(Row r, Entry e, IEnumerable obligations) - { - WebApplication? app = null; string? down = null; - try { app = await Hx.Start(r, e, new HostCfg { FaultControllers = false, MapBlanketMapping = false }); } - catch (Exception ex) when (ex is not Sides.InputsNotEquivalent) { down = "schema host did not start: " + ex.GetType().Name + ": " + Cut(ex.Message); } - await using var _ = app; - await using var one = new SideOne(r, e, "plain"); - await using var alone = new SideOne(r, e, "both"); - var list = obligations.ToList(); - if (down is null && list.Any(o => Sides.Unconditional(r, o))) await one.Host(); - string? failed = null; - foreach (var obligation in list) - { - var f = await r.Check(obligation, Baseline.Twin, c => down is not null ? Task.FromResult(down) : SchemaParity(app!, one, alone, r, e, c)); - failed ??= f; - } - return failed; - } - - /// - /// Where either side is a null-or-reference (oneOf [null, component]), both sides there in one spelling: - /// the null as x-null beside the schema, wherever the side spelled it (type [null, X], nullable, - /// x-nullable, a null in an enum, or the null-or itself). A shared component cannot hold the null of one - /// position, so a nullable value object that is one is null around its reference, where ASP.NET writes the - /// wrapped type's null inside its inline schema (decision 36: "as a container's element (`oneOf: [null, - /// component]`, ASP.NET's own form)"; AspNetCore README: "A nullable element (`List<Quantity?>`, - /// `Dictionary<string, Quantity?>`) is the component or null, as a nullable property is."). Whether a side - /// admits null is kept; everywhere else, inlined schemas included, the comparison stays byte for byte (rows 170, - /// 196 and 215 of C21). Returns both sides without the marks put on resolved references. - /// - static (string, string, bool) NullAroundReferences(string sp, string sv) - { - var around = false; - static bool IsNull(JsonNode? a) => a is JsonObject ao && (ao["type"]?.ToJsonString() == "\"null\"" || ao["enum"]?.ToJsonString() == "[null]"); - static bool NullOrReference(JsonNode? n) => - n is JsonObject o && o["oneOf"] is JsonArray alts && alts.Count == 2 && alts.Any(IsNull) && alts.Any(a => a is JsonObject ao && ao.ContainsKey(Hx.ResolvedReference)); - static JsonNode? Unmark(JsonNode? n) => n switch - { - JsonObject o => new JsonObject(o.Where(kv => kv.Key != Hx.ResolvedReference).Select(kv => KeyValuePair.Create(kv.Key, Unmark(kv.Value)))), - JsonArray a => new JsonArray(a.Select(Unmark).ToArray()), - _ => n?.DeepClone(), - }; - static JsonNode? OneSpelling(JsonNode? n) - { - switch (n) - { - case JsonObject o when o["oneOf"] is JsonArray alts && alts.Count == 2 && alts.Any(IsNull) && alts.FirstOrDefault(a => !IsNull(a)) is JsonObject keep: - { - var c = (JsonObject)OneSpelling(keep)!; c["x-null"] = true; return Sorted(c); - } - case JsonObject o: - { - var c = new JsonObject(); - foreach (var (k, v) in o) - { - if (k == Hx.ResolvedReference) continue; - if (k is "nullable" or "x-nullable") { if (v?.GetValue() == true) c["x-null"] = true; continue; } - if (k == "allOf" && v is JsonArray aa && aa.Count == 1 && aa[0] is JsonObject a0 && a0.Count == 1 && a0.ContainsKey("x-nullable")) { c["x-null"] = true; continue; } - if (k == "type" && v is JsonArray ta && ta.Any(x => x?.GetValue() == "null")) - { - var f = ta.Where(x => x?.GetValue() != "null").ToList(); - c["type"] = f.Count == 1 ? f[0]!.DeepClone() : new JsonArray(f.Select(x => x!.DeepClone()).ToArray()); c["x-null"] = true; continue; - } - if (k == "type" && v?.ToJsonString() == "\"null\"") { c["x-null"] = true; continue; } - if (k == "enum" && v is JsonArray en && en.Any(x => x is null)) { c["enum"] = new JsonArray(en.Where(x => x is not null).Select(x => x!.DeepClone()).ToArray()); c["x-null"] = true; continue; } - if (k == "anyOf" && v is JsonArray any && any.Any(IsNull)) { c["anyOf"] = new JsonArray(any.Where(x => !IsNull(x)).Select(OneSpelling).ToArray()); c["x-null"] = true; continue; } - c[k] = OneSpelling(v); - } - return Sorted(c); - } - case JsonArray a: return new JsonArray(a.Select(OneSpelling).ToArray()); - default: return n?.DeepClone(); - } - } - static JsonObject Sorted(JsonObject o) => new(o.OrderBy(kv => kv.Key, StringComparer.Ordinal).Select(kv => KeyValuePair.Create(kv.Key, kv.Value?.DeepClone()))); - (JsonNode?, JsonNode?) Walk(JsonNode? p, JsonNode? v) - { - if (NullOrReference(p) || NullOrReference(v)) { around = true; return (OneSpelling(p), OneSpelling(v)); } - if (p is JsonObject po && v is JsonObject vo) - { - var cp = new JsonObject(); var cv = new JsonObject(); - foreach (var k in po.Select(kv => kv.Key).Union(vo.Select(kv => kv.Key)).Where(k => k != Hx.ResolvedReference).Order(StringComparer.Ordinal)) - { - if (!po.ContainsKey(k)) { cv[k] = Unmark(vo[k]); continue; } - if (!vo.ContainsKey(k)) { cp[k] = Unmark(po[k]); continue; } - var (a, b) = Walk(po[k], vo[k]); cp[k] = a; cv[k] = b; - } - return (cp, cv); - } - if (p is JsonArray pa && v is JsonArray va && pa.Count == va.Count) - { - var cp = new JsonArray(); var cv = new JsonArray(); - for (var i = 0; i < pa.Count; i++) { var (a, b) = Walk(pa[i], va[i]); cp.Add(a); cv.Add(b); } - return (cp, cv); - } - return (Unmark(p), Unmark(v)); - } - var (np, nv) = Walk(JsonNode.Parse(sp), JsonNode.Parse(sv)); - return (np?.ToJsonString() ?? "null", nv?.ToJsonString() ?? "null", around); - } - - /// - /// The component two operations of one document both refer to at the same place (a parameter's or the body's schema), where one - /// substitutes the value object for the twin: two types under one name, told by the references' structure. - /// - static string? SharedComponent(JsonNode twin, JsonNode valueObject) - { - static IEnumerable<(string, string)> References(JsonNode op) - { - if (op["parameters"] is JsonArray ps) - for (var i = 0; i < ps.Count; i++) - if (ps[i]?["schema"]?["$ref"]?.GetValue() is { } p) yield return ($"parameter {i}", p); - if (op["requestBody"]?["content"] is JsonObject content) - foreach (var (media, body) in content) - if (body?["schema"]?["$ref"]?.GetValue() is { } b) yield return ($"body {media}", b); - } - var twins = References(twin).ToDictionary(x => x.Item1, x => x.Item2); - return References(valueObject).FirstOrDefault(x => twins.TryGetValue(x.Item1, out var t) && t == x.Item2).Item2; - } - - /// A schema that is the OpenAPI 2.0 null flag and nothing else: {"allOf":[{"x-nullable":true}]}. - static bool OnlyTheNullFlag(JsonObject o) => - o.Count == 1 && o["allOf"] is JsonArray { Count: 1 } all && all[0] is JsonObject { Count: 1 } flag && flag["x-nullable"]?.GetValueKind() == JsonValueKind.True; - - /// - /// The OpenAPI 2.0 null flag with the wrapped type's format beside it and nothing else, {"format":"uri","allOf":[{"x-nullable":true}]}: - /// a nullable component's property, which TypeKit gives the wrapped type's format (KB-026). - /// - static bool TheNullFlagBeside(JsonObject o) => - o.ContainsKey("format") && o.Count == 2 && OnlyTheNullFlag(new JsonObject { ["allOf"] = o["allOf"]?.DeepClone() }); - - /// The keys of a difference up to the property it lies in (…, properties, P), or null where it lies in none. - static IReadOnlyList? PropertyAt(IReadOnlyList keys) - { - for (var i = keys.Count - 2; i >= 0; i--) - if (keys[i] == "properties") return [.. keys.Take(i + 2)]; - return null; - } - - /// - /// OpenAPI 2.0's nullable property of a component (KB-026): allOf: [{x-nullable: true}], without the reference and so without a - /// type, beside what TypeKit kept of the wrapped type (a format). - /// - static bool TheNullFlagWithoutItsReference(JsonObject o) => - o["allOf"] is JsonArray { Count: 1 } all && all[0] is JsonObject { Count: 1 } flag && flag["x-nullable"]?.GetValueKind() == JsonValueKind.True - && !o.ContainsKey("$ref") && !o.ContainsKey(Hx.ResolvedReference) && !o.ContainsKey("type"); - - /// - /// A body whose schema is its format and its null alone, {"schema": {"format": "int32", "allOf": [{"x-nullable": true}]}}, or its null - /// alone where the type has no format, anywhere in an operation: told by its structure (KB-001). - /// - static bool OnlyItsNull(JsonNode? n) => n switch - { - JsonObject o => o["schema"] is JsonObject schema && schema.All(kv => kv.Key is "allOf" or "format") - && schema["allOf"] is JsonArray { Count: 1 } all && all[0] is JsonObject { Count: 1 } flag - && flag["x-nullable"]?.GetValueKind() == JsonValueKind.True - || o.Any(kv => OnlyItsNull(kv.Value)), - JsonArray a => a.Any(OnlyItsNull), - _ => false, - }; - - /// - /// The value object's schema (3) against the wrapped twin's (2) at each endpoint pair, three-sided (Sides): the twin's schema is held to - /// the one ASP.NET publishes on the same host without TypeKit (1), where that host writes a document; and where the value object's schema - /// differs from the twin's, side (1)'s document at the same path tells whether ASP.NET alone writes that difference. - /// - static async Task SchemaParity(WebApplication app, SideOne one, SideOne alone, Row r, Entry e, Check c) - { - JsonNode doc; - try { doc = (await Hx.Doc(app))!; } - catch (Exception ex) - { - // The baseline is ASP.NET alone on the same host: a document it refuses too has no schema to compare (decision 99). - return await Hx.DocRefusedByAspNetAlone(r, e, new HostCfg { FaultControllers = false, MapBlanketMapping = false }, ex); - } - // docs/json.md "Describing what a converter writes": ASP.NET drops items/additionalProperties of a converter it cannot see into, the value - // object's schema is the underlying type's; and the application's converter for the value object describes it as that converter says. - // C21 declares both on every obligation (claims.json inapplicable), so Row.Check records them before this body runs and no row of - // C21 is generated with them; these lines hold for the schema half run under another claim (ShrinkProbe's baseline). - if (r.Is("json.Converters", "own-for-wrapped")) return c.Inapplicable(Cite.NotPromised("own-converter-for-the-wrapped-type")); - if (r.Is("json.Converters", "own-for-value-object")) return c.Inapplicable(Cite.NotPromised("own-converter-for-the-value-object")); - // side (1): the document ASP.NET writes for the twin's endpoints without TypeKit, where it writes one; and, asked only where the value - // object's schema differs from the twin's, the one it writes for both sides' endpoints, for the value object's position - async Task Document(SideOne host) - { - if (await host.Host() is not { } h) return null; - try { return await Hx.Doc(h); } - catch (Exception x) { r.Log.AppendLine("side (1) document refused: " + x.GetType().Name + ": " + Cut(x.Message)); return null; } - } - var doc1 = await Document(one); - JsonNode? Op(JsonNode d, string path, string method) => d["paths"]?[path]?[method]; - // only the schemas are compared (the claim is about the schema); whether a parameter or body is required follows the .NET type's nullability - JsonNode? Schemas(JsonNode? n) - { - switch (n) - { - case JsonArray a: { var c = new JsonArray(); foreach (var x in a) c.Add(Schemas(x)); return c; } - case JsonObject o: - { - var c = new JsonObject(); - foreach (var kv in o.OrderBy(k => k.Key, StringComparer.Ordinal)) - { - if (kv.Key == "required" && kv.Value is JsonValue) continue; // parameter / body / old-style flags - c[kv.Key] = Schemas(kv.Value); - } - return c; - } - default: return n?.DeepClone(); - } - } - string Sig(JsonNode d, JsonNode op) - { - var o = new JsonObject(); - o["parameters"] = Schemas(Hx.Deep(d, op["parameters"], mark: true)); - o["requestBody"] = Schemas(Hx.Deep(d, op["requestBody"], mark: true)); - o["ok"] = Schemas(Hx.Deep(d, op["responses"]?["200"], mark: true)); - return o.ToJsonString(); - } - // The media types of an operation's request body and 200 response, each named by where it is - static HashSet MediaTypes(JsonNode op) => - [ - .. (op["requestBody"]?["content"] as JsonObject ?? []).Select(kv => "requestBody:" + kv.Key), - .. (op["responses"]?["200"]?["content"] as JsonObject ?? []).Select(kv => "ok:" + kv.Key), - ]; - // A signature with only the request body's and the 200 response's media types given - static string UnderMediaTypes(string sig, IEnumerable media) - { - var keep = media.ToHashSet(); - var o = JsonNode.Parse(sig)!.AsObject(); - foreach (var (part, name) in new[] { ("requestBody", "requestBody"), ("ok", "ok") }) - if (o[part]?["content"] is JsonObject content) - foreach (var key in content.Select(kv => kv.Key).ToList()) - if (!keep.Contains(name + ":" + key)) content.Remove(key); - return o.ToJsonString(); - } - var checks = new List<(string, string)>(); - if (Hx.HasMinimal(r)) { checks.Add((Hx.M(r, "/schema/plain"), Hx.M(r, "/schema/vo"))); } - if (Hx.HasMvc(r)) - { - var bind = r["http.binding"] switch { "route" => "route", "query" => "query", "header" => "header", "form" => "form", "as-parameters" => "params", _ => "body" }; - var sfx = bind == "route" ? "/{v}" : ""; - checks.Add((Hx.C(r, $"/mvc/bind/{bind}/plain{sfx}"), Hx.C(r, $"/mvc/bind/{bind}/vo{sfx}"))); - } - if (Hx.HasMinimal(r)) - { - var bind = r["http.binding"] switch { "route" => "route", "query" => "query", "header" => "header", "form" => "form", "as-parameters" => "params", _ => "body" }; - // route: /bind/route/{which}/{v} - checks.Add((bind == "route" ? Hx.M(r, "/bind/route/plain/{v}") : Hx.M(r, $"/bind/{bind}/plain"), bind == "route" ? Hx.M(r, "/bind/route/vo/{v}") : Hx.M(r, $"/bind/{bind}/vo"))); - } - // The inputs of the two sides, apart from the type substituted: where each value is bound, under which - // name, and whether it is required. They must agree before the schemas are compared; otherwise the - // comparison measures the harness (G1: a nullable class value object against a required int). - string Inputs(JsonNode op) - { - var parts = new List(); - if (op["parameters"] is JsonArray ps) - foreach (var prm in ps) { var q = Hx.Deep(doc, prm); parts.Add($"{q?["in"]}:{q?["name"]}:required={q?["required"]?.ToJsonString() ?? "false"}"); } - if (Hx.Deep(doc, op["requestBody"]) is JsonObject rb) parts.Add($"body:required={rb["required"]?.ToJsonString() ?? "false"}"); - return string.Join(",", parts); - } - foreach (var (pp0, vp) in checks) - { - var method = pp0.Contains("/schema/") || pp0.Contains("/body/") || pp0.Contains("/form/") ? "post" : "get"; - // Like with like from the start: the twin is the wrapped type at the value object's nullability (shapes.cs), so a class - // value object over a struct faces the struct made nullable, at every endpoint (row 384 of C07: a record class over TimeOnly, - // optional, against TimeOnly?). - var pp = pp0; - var po = Op(doc, pp, method); var vo = Op(doc, vp, method); - if (po is null) - { - // Mapped for bodies only (a record class, Instant in a minimal API): neither side is there. - if (vo is not null) return $"harness: the value object's {method} {vp} is documented, its plain twin is not (missing {method} {pp})"; - c.Note(NoteKeys.SchemaNeitherSideDocumented, $"missing {method} {pp}"); continue; - } - if (vo is null) return $"missing {method} {vp}"; - // The twin's and the value object's shapes are two .NET types; one component name for both (an id the row's CreateSchemaReferenceId - // makes alike for both, such as an array of a generic type) holds one schema for the two, so the document cannot tell them apart. - if (SharedComponent(po, vo) is { } shared) - { c.Inconclusive($"{pp} vs {vp}: the twin's and the value object's shapes are one component, {shared}, in the document: nothing to compare"); continue; } - // (2) held to (1): the twin's schema is the one ASP.NET publishes on the same host without TypeKit, but where the twin itself - // holds one of TypeKit's types (a Patch), which no host without TypeKit describes - var po1 = doc1 is null ? null : Op(doc1, pp, method); - var twinHoldsTypeKit = pp.Contains("/schema/") && Sides.HoldsTypeKit(Twin(r, e).Declared); - if (po1 is not null && !twinHoldsTypeKit && Sig(doc1!, po1) is var s1 && Sig(doc, po) is var s2 && s1 != s2) - return $"schema of the wrapped type at {pp}: TypeKit changed the wrapped type's schema, at {FirstDifference(JsonNode.Parse(s1), JsonNode.Parse(s2), "$")} (without TypeKit, then with it)"; - if (Inputs(po) is var ip && Inputs(vo) is var iv && ip != iv) - { - // No twin of the wrapped type at the value object's nullability here (a struct value object over a class, which no plain - // type mirrors), or a wrapped record class, which ASP.NET binds by its properties where the value object is one value: the - // two sides are not alike, and no sentence cites it, so the check cannot tell. - if (Make.AdmitsNull(e.Vo) != Make.AdmitsNull(e.Plain)) - c.Inconclusive($"{pp} vs {vp}: no twin of {e.Plain.Name} at the value object's nullability, the inputs differ: wrapped [{ip}] vs value object [{iv}]"); - else if (e.Wrapped == "own-record-class") - c.Inconclusive($"{pp} vs {vp}: the wrapped record class is bound by its properties, the value object as one value, the inputs differ: wrapped [{ip}] vs value object [{iv}]"); - else r.Outcome("harness-error", $"inputs not equivalent for {pp} vs {vp}: wrapped [{ip}] vs value object [{iv}]"); - continue; - } - var sp = Sig(doc, po); var sv = Sig(doc, vo); - // MVC lists a body's and a response's media types by what its formatters can read and write of the .NET type, and the twin - // and the value object are two types (row 38 of C21: XmlSerializerInputFormatter reads a record class value object, not the - // Uri it wraps). Where the lists differ and side (1), ASP.NET alone with both sides' endpoints, lists each side's the same, - // the formatters decided it, not TypeKit: the schemas are compared under the media types both list. Otherwise as they are. - if (MediaTypes(po) is var mp && MediaTypes(vo) is var mv && !mp.SetEquals(mv) - && await Document(alone) is { } both0 && Op(both0, pp, method) is { } pAlone && Op(both0, vp, method) is { } vAlone - && MediaTypes(pAlone).SetEquals(mp) && MediaTypes(vAlone).SetEquals(mv)) - { - r.Log.AppendLine($"{pp} vs {vp}: media types the formatters list differ alike without TypeKit, compared under [{string.Join(", ", mp.Intersect(mv))}]"); - sp = UnderMediaTypes(sp, mp.Intersect(mv)); sv = UnderMediaTypes(sv, mp.Intersect(mv)); - } - if (NullAroundReferences(sp, sv) is var (np, nv, around)) { sp = np; sv = nv; if (around) c.Note(NoteKeys.SchemaNullAroundReferenceNormalised); } - if (sp != sv && Make.AdmitsNull(e.Vo) && Make.AdmitsNull(e.Plain) && e.Vo.IsValueType != e.Plain.IsValueType) - { - // Both sides nullable alike, one a class and the other a struct made nullable (a class value object and its nullable twin, or - // a nullable struct value object and a wrapped class); OpenAPI 3.x spells nullability two ways (oneOf [null, X] or type [null, X]). - sp = Hx.NoNull(JsonNode.Parse(sp))!.ToJsonString(); sv = Hx.NoNull(JsonNode.Parse(sv))!.ToJsonString(); - c.Note(NoteKeys.SchemaNullableSpellingsNormalised); - } - if (sp != sv && Make.AdmitsNull(e.Vo) != Make.AdmitsNull(e.Plain)) - { - // A struct value object over a class, whose twin is nullable by being a class where the value object is not (no plain - // type mirrors it); the markers go, the rest of the schema must agree. - sp = Hx.NoNull(JsonNode.Parse(sp))!.ToJsonString(); sv = Hx.NoNull(JsonNode.Parse(sv))!.ToJsonString(); - c.Note(NoteKeys.SchemaClassVoNullabilityNormalised); - } - if (sp != sv) - { - if (e.Kind == "closed-set") { c.Inapplicable(Cite.NotPromised("a-closed-set-is-a-string-enum"), "schema"); continue; } - // A form binds the wrapped record class by its properties and the value object otherwise, as the parameters above: the two - // sides' fields are not alike, and no sentence cites it, so the check cannot tell (row 62 of C21). - if (e.Wrapped == "own-record-class" && pp.Contains("/form/") && method == "post") - { c.Inconclusive($"{pp} vs {vp}: the wrapped record class is bound from a form by its properties, the value object otherwise: the fields differ"); continue; } - var d = Difference(JsonNode.Parse(sp), JsonNode.Parse(sv), "$"); - // Decision 36: a nullable value object admits null wherever it appears, where ASP.NET may write the twin's nullable type without - // it (the items of a list of double? under AllowNamedFloatingPointLiterals, row 216 of C21; the twin is held to side (1) above). - // Only that null differs: the value object admits it where the twin does not, and the schemas are otherwise the same. - if (Make.AdmitsNull(e.Vo) && d.Keys is [.., "x-null"] && d.P is null && d.V?.GetValueKind() == JsonValueKind.True - && JsonNode.DeepEquals(Hx.NoNull(JsonNode.Parse(sp)), Hx.NoNull(JsonNode.Parse(sv)))) - { c.Inapplicable(Cite.NotPromised("a-nullable-value-object-admits-null"), d.Path); continue; } - var openApi2 = r.Is("openapi.OpenApiVersion", "OpenApi2_0"); - // Side (1) at the same path: the twin's and the value object's operations in the document ASP.NET writes without TypeKit. - var twin1 = po1 is null ? null : JsonNode.Parse(Sig(doc1!, po1)); - var both1 = openApi2 && d.P is null && d.V is not null ? await Document(alone) : null; - var vo1 = both1 is null ? null : Op(both1, vp, method) is { } o1 ? JsonNode.Parse(Sig(both1, o1)) : null; - var vo3 = JsonNode.Parse(Sig(doc, vo)); - // KB-026: OpenAPI 2.0 writes a nullable property of any component as allOf [{x-nullable: true}], without the reference, and a - // value object keeps a component of its own (not-promised openapi-2-nullable-component-loses-its-type; row 38 of C21). Side (1) - // shows it: without TypeKit, ASP.NET writes the value object's position at the same path the same, where the twin has nothing. - if (openApi2 && d.P is null && d.V is not null && At(vo1, d.Keys) is { } same1 && JsonNode.DeepEquals(same1, At(vo3, d.Keys))) - { c.Inapplicable(Cite.NotPromised("openapi-2-nullable-component-loses-its-type"), d.Path); continue; } - // The same, where the spellings of the null were normalised above, which takes the null flag out of the value object's - // schema and leaves it without what the 2.0 writer dropped with the reference: its type, its pattern (rows 386, 178, 181 - // and 243 of C21: a nullable struct value object over Uri as a required-init property, and class value objects whose - // property admits null as a type parameter's or set through the constructor). Told by its structure: the value object's - // property is the null flag, alone or beside the wrapped type's format, and the twin's, which admits null, has that format. - if (openApi2 && PropertyAt(d.Keys) is { } property - && At(vo3, property) is JsonObject flagged3 && (TheNullFlagBeside(flagged3) || OnlyTheNullFlag(flagged3)) - && At(JsonNode.Parse(Sig(doc, po)), property) is JsonObject typed2 - && (typed2["x-nullable"]?.GetValueKind() == JsonValueKind.True - // or the twin is a component itself (a wrapped record class, row 444 of C21), whose reference ASP.NET's own rule - // leaves without the null the value object admits (decision 36: a-nullable-value-object-admits-null) - || typed2.ContainsKey(Hx.ResolvedReference) && Make.AdmitsNull(e.Vo)) - && JsonNode.DeepEquals(typed2["format"], flagged3["format"])) - { c.Inapplicable(Cite.NotPromised("openapi-2-nullable-component-loses-its-type"), d.Path); continue; } - // AspNetCore README "What the document says": a nullable element is the component or null, as a nullable property is, which - // OpenAPI 2.0 writes as allOf [{x-nullable: true}] without the reference (not-promised openapi-2-nullable-element-loses-its-type; - // row 358 of C21, a dictionary's value). ASP.NET alone drops a converter-backed element, so side (1) has nothing there; told by - // its structure, the value object's element is the null flag alone where the twin's admits null. - if (openApi2 && d.Keys is [.., "items" or "additionalProperties", "allOf"] && d.P is null - && At(vo3, d.Keys.SkipLast(1)) is JsonObject element3 && OnlyTheNullFlag(element3) - && At(JsonNode.Parse(Sig(doc, po)), d.Keys.SkipLast(1)) is JsonObject element2 && element2["x-nullable"]?.GetValueKind() == JsonValueKind.True) - { c.Inapplicable(Cite.NotPromised("openapi-2-nullable-element-loses-its-type"), d.Path); continue; } - // The same loss told by the row's axes, where side (1) cannot show it: a nullable value object that is a component is a - // nullable property wherever the serializer's contract says so (a get-only or a type parameter's property among them), where - // ASP.NET alone adds the null only for a settable annotated one. Its property is then the null flag without the reference, - // where the twin's keeps its type beside x-nullable. - if (openApi2 && Make.AdmitsNull(e.Vo) && !r.Is("openapi.CreateSchemaReferenceId", "null-inlines-all") && d.V is null - && At(vo3, d.Keys.SkipLast(1)) is JsonObject lost && TheNullFlagWithoutItsReference(lost) - && At(JsonNode.Parse(Sig(doc, po)), d.Keys.SkipLast(1)) is JsonObject kept && kept["x-nullable"]?.GetValueKind() == JsonValueKind.True) - { c.Inapplicable(Cite.NotPromised("openapi-2-nullable-component-loses-its-type"), d.Path); continue; } - // KB-001: OpenAPI 2.0 writes a nullable body of the wrapped value type as its format and allOf [{x-nullable: true}] alone (the - // null alone where it has no format, an enum), where a class value object's body in a minimal API is not nullable and keeps its - // schema (not-promised openapi-2-nullable-body-keeps-only-its-null; row 257, and rows 113 and 282 over TimeOnly and char). Side (1) - // shows it: without TypeKit, the twin's schema there is that format and that null alone. - // AspNetCore README "What the document says" (KB-026), seen from the twin: OpenAPI 2.0 writes a nullable property of any component, - // the twin's nullable enum among them, as allOf [{x-nullable: true}] without the reference, where the value object keeps its type. - // Side (1) shows it: without TypeKit, the twin's property there is that null alone. - if (openApi2 && d.P is null && d.V is not null && Make.AdmitsNull(e.Plain) && At(twin1, d.Keys.SkipLast(1)) is JsonObject t1 && OnlyTheNullFlag(t1)) - { c.Inapplicable(Cite.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says"), d.Path); continue; } - if (openApi2 && !e.Vo.IsValueType && Nullable.GetUnderlyingType(e.Plain) is not null && OnlyItsNull(twin1) && OnlyItsNull(JsonNode.Parse(Sig(doc, po)))) - { c.Inapplicable(Cite.NotPromised("openapi-2-nullable-body-keeps-only-its-null"), pp); continue; } - // KB-027: the component ASP.NET makes for an enum written by name is the schema of the first use it meets, so a wrapped E? - // parameter lists null through E's component where E was first met nullable; the value object's parameter is the enum's - // content without it wherever the enum is a component (not-promised enum-component-is-its-first-use; row 285 of C21). Side (1) - // shows it: without TypeKit, the twin's parameter lists the same null, through the same resolved component. - // The same component met first as a nullable use lists that null for a property too, the twin's non-nullable one included - // (not-promised enum-component-lists-the-null-of-its-first-use; row 196 of C21, a polymorphic derived type's property). - if (d.Keys is [.., "enum"] && d.P is JsonArray we && d.V is JsonArray ve && we.Count == ve.Count + 1 && we[^1] is null - && JsonNode.DeepEquals(new JsonArray(we.Take(ve.Count).Select(x => x?.DeepClone()).ToArray()), ve) - && At(JsonNode.Parse(Sig(doc, po)), d.Keys.SkipLast(1)) is JsonObject held && held.ContainsKey(Hx.ResolvedReference) - && At(twin1, d.Keys) is { } listed1 && JsonNode.DeepEquals(listed1, d.P)) - { - if (d.Keys is ["parameters", ..]) c.Inapplicable(Cite.NotPromised("enum-component-is-its-first-use"), vp); - else c.Inapplicable(Cite.NotPromised("enum-component-lists-the-null-of-its-first-use"), vp); - continue; - } - // AspNetCore README "A described type": ASP.NET cannot see through a converter it did not write, one a library registers for - // its own type among them, and drops a list's items and a dictionary's additionalProperties of that type, where the value - // object's element is put back (not-promised a-librarys-converter-for-the-wrapped-type; row 422 of C21, a list of Instant?). - // Side (1) shows it: without TypeKit, the twin's container has no element schema either. - if (e.Wrapped == "NodaTime.Instant" && d.Keys is [.., "items" or "additionalProperties"] && d.P is null && d.V is not null - && twin1 is not null && At(twin1, d.Keys.SkipLast(1)) is JsonObject container1 && !container1.ContainsKey(d.Keys[^1])) - { c.Inapplicable(Cite.NotPromised("a-librarys-converter-for-the-wrapped-type"), d.Path); continue; } - return $"schema differs for {pp} vs {vp} at {FirstDifference(JsonNode.Parse(sp), JsonNode.Parse(sv), "$")}:\n wrapped {Cut(sp)}\n value object {Cut(sv)}"; - } - } - return null; - } -} diff --git a/tools/probe/corpus/harness/HttpHost.cs b/tools/probe/corpus/harness/HttpHost.cs deleted file mode 100644 index 5f6d7186..00000000 --- a/tools/probe/corpus/harness/HttpHost.cs +++ /dev/null @@ -1,438 +0,0 @@ -// The shared HTTP host: applies a row's json.*, openapi.*, mvc.* and http.* axes and the shape axes, then runs the baseline checks -// (payload echo/in/binding parity, schema parity) that every http claim shares. Claim-specific scenarios plug in through HostCfg. -using System.Net; -using System.Net.Http.Headers; -using System.Reflection; -using System.Text; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Text.Json.Serialization; -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.AspNetCore; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Routing; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.ApplicationModels; -using Microsoft.AspNetCore.Mvc.ApplicationParts; -using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.AspNetCore.Mvc.ModelBinding; -using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; -using Microsoft.AspNetCore.Mvc.Routing; -using Microsoft.AspNetCore.Mvc.ActionConstraints; -using Microsoft.AspNetCore.OpenApi; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi; -using HttpJsonOptions = Microsoft.AspNetCore.Http.Json.JsonOptions; -using MvcJsonOptions = Microsoft.AspNetCore.Mvc.JsonOptions; -namespace Probes.Shapes; - -public sealed record Payload(Held Vo, Held Plain); - -public sealed class NullBinderProvider : IModelBinderProvider { public IModelBinder? GetBinder(ModelBinderProviderContext context) => null; } -public sealed class PrefixConvention(string prefix) : IApplicationModelConvention -{ - public void Apply(ApplicationModel application) - { - foreach (var c in application.Controllers) - foreach (var s in c.Selectors.Concat(c.Actions.SelectMany(a => a.Selectors))) - if (s.AttributeRouteModel is { } m && !(m.Template?.StartsWith('/') ?? false)) - s.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(new AttributeRouteModel(new RouteAttribute(prefix)), m); - } -} - -/// -/// http.host=controller-without-ApiController-visible: what ASP.NET documents as the switch beside [ApiController] and -/// [ApiExplorerSettings], a convention that sets ApiExplorer.IsVisible, so the document checks reach those controllers. -/// -public sealed class VisibleToApiExplorer : IApplicationModelConvention -{ - public void Apply(ApplicationModel application) - { - foreach (var c in application.Controllers) c.ApiExplorer.IsVisible = true; - } -} - -/// Closed generic controllers: one over the value object, one over the wrapped type; routes are set by BindConvention. -[ApiController] -public sealed class MvcBind : ControllerBase -{ - public sealed class Q { public T V { get; set; } = default!; } - [ProducesResponseType(200), Route("_")] - public IActionResult RouteA([FromRoute(Name = "v")] T v) => new ObjectResult(v) { DeclaredType = typeof(T) }; - [ProducesResponseType(200), Route("_")] - public IActionResult QueryA([FromQuery(Name = "v")] T v) => new ObjectResult(v) { DeclaredType = typeof(T) }; - [ProducesResponseType(200), Route("_")] - public IActionResult HeaderA([FromHeader(Name = "v")] T v) => new ObjectResult(v) { DeclaredType = typeof(T) }; - [ProducesResponseType(200), Route("_")] - public IActionResult BodyA([FromBody] T v) => new ObjectResult(v) { DeclaredType = typeof(T) }; - [ProducesResponseType(200), Route("_")] - public IActionResult FormA([FromForm(Name = "v")] T v) => new ObjectResult(v) { DeclaredType = typeof(T) }; - [ProducesResponseType(200), Route("_")] - public IActionResult ParamsA([FromQuery] Q q) => new ObjectResult(q.V) { DeclaredType = typeof(T) }; -} -public sealed class BindConvention(Type vo, Type plain, string prefix) : IControllerModelConvention -{ - public void Apply(ControllerModel c) - { - if (!c.ControllerType.IsGenericType || c.ControllerType.GetGenericTypeDefinition() != typeof(MvcBind<>)) return; - var arg = c.ControllerType.GenericTypeArguments[0]; - // By the entry's own types: the plain side is the twin, at the value object's nullability. - var which = arg == vo ? "vo" : arg == plain ? "plain" : throw new InvalidOperationException($"MvcBind<{arg.Name}> is neither side's"); - foreach (var a in c.Actions) - { - var (kind, post) = a.ActionName switch { "RouteA" => ("route", false), "QueryA" => ("query", false), "HeaderA" => ("header", false), "BodyA" => ("body", true), "FormA" => ("form", true), _ => ("params", false) }; - a.Selectors.Clear(); - a.Selectors.Add(new SelectorModel - { - AttributeRouteModel = new AttributeRouteModel(new RouteAttribute($"{prefix}mvc/bind/{kind}/{which}" + (kind == "route" ? "/{v}" : ""))), - ActionConstraints = { new Microsoft.AspNetCore.Mvc.ActionConstraints.HttpMethodActionConstraint([post ? "POST" : "GET"]) }, - EndpointMetadata = { new Microsoft.AspNetCore.Routing.HttpMethodMetadata([post ? "POST" : "GET"]) }, - }); - } - } -} -[ApiController] -public sealed class MvcPayloadController(Payload payload) : ControllerBase -{ - [HttpGet("mvc/echo/{which}")] - public IActionResult Echo(string which) { var h = which == "vo" ? payload.Vo : payload.Plain; return new ObjectResult(h.Value) { DeclaredType = h.Declared }; } - - [HttpPost("mvc/in/{which}")] - public async Task In(string which) - { - var h = which == "vo" ? payload.Vo : payload.Plain; - var f = HttpContext.RequestServices.GetRequiredService>().Value.InputFormatters.OfType().First(); - var meta = HttpContext.RequestServices.GetRequiredService().GetMetadataForType(h.Declared); - var factory = HttpContext.RequestServices.GetRequiredService(); - var ctx = new InputFormatterContext(HttpContext, "model", ModelState, meta, factory.CreateReader); - var result = await f.ReadAsync(ctx); - if (result.HasError) return StatusCode(400); - return new ObjectResult(result.Model) { DeclaredType = h.Declared }; - } -} - -public sealed class HostCfg -{ - public Action? Minimal; - public Func? ControllerBuilder; - public Action? Services; - public string Mapping = "by-kind"; - public bool Qualified; - public ListedLogs? Logs; - public Type[]? Controllers; // null: the fault controllers of the host - public bool FaultControllers = true; - public bool Payload = true; // payload echo / in / binding / schema endpoints - public string PayloadOnly = "both"; // "both", "vo" or "plain": the endpoints of one side only, minimal and MVC (side (1)'s twin alone, a document refusal isolated) - public bool MapBlanketMapping = true; - public bool TypeKitOpenApi = true; // false: the document as ASP.NET alone writes it, the baseline of a refused one - /// - /// The three-sided differential's side (1) (Sides): no AddTypeKit(), none of TypeKit's JSON converters on either set of options, and no - /// fault responses; the wrapped twin's endpoints answer as ASP.NET and System.Text.Json have them without TypeKit. - /// - public bool WithoutTypeKit; - public HostCfg Copy() => (HostCfg)MemberwiseClone(); -} - -public static class Hx -{ - public static bool HasMinimal(Row r) => r["http.host"] is "minimal" or "both" or "route-group"; - public static bool HasMvc(Row r) => r["http.host"] is "mvc" or "both" or "controller-without-ApiController" or "controller-without-ApiController-visible"; - /// The fault controllers have no [ApiController]: MVC infers no [FromBody] and answers no automatic 400. - public static bool Plain(Row r) => r["http.host"] is "controller-without-ApiController" or "controller-without-ApiController-visible"; - /// A controller without [ApiController] is in the document only when something makes it visible to the API explorer. - public static bool InDocument(Row r) => r["http.host"] != "controller-without-ApiController"; - /// Path of a minimal endpoint (route-group hosts map everything under /rg). - public static string M(Row r, string path) => (r["http.host"] == "route-group" ? "/rg" : "") + path; - /// Path of a controller endpoint (own-route-prefix convention puts /px before relative routes). - public static string C(Row r, string path) => (r.Is("mvc.Conventions", "own-route-prefix") ? "/px" : "") + path; - - public static Type[] FaultControllers(Row r) => - Plain(r) ? [typeof(PlainAController), typeof(PlainBController)] : [typeof(MvcAController), typeof(MvcBController)]; - - static void ApplyMvc(MvcOptions o, Row r) - { - foreach (var kv in r.All.Where(kv => kv.Key.StartsWith("mvc.") && kv.Value != "default")) - { - var n = kv.Key[4..]; - switch (n) - { - case "InputFormatters": o.InputFormatters.Add(new XmlSerializerInputFormatter(o)); continue; - case "OutputFormatters": o.OutputFormatters.Add(new XmlSerializerOutputFormatter()); continue; - case "ModelBinderProviders": o.ModelBinderProviders.Insert(0, new NullBinderProvider()); continue; - case "Conventions": o.Conventions.Add(new PrefixConvention("px")); continue; - } - var p = typeof(MvcOptions).GetProperty(n) ?? throw new ArgumentException("no mvc option " + n); - var t = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType; - object v = t == typeof(bool) ? bool.Parse(kv.Value) : t == typeof(int) ? int.Parse(kv.Value) : t.IsEnum ? Enum.Parse(t, kv.Value) : throw new ArgumentException($"no hand value for mvc.{n}"); - p.SetValue(o, v); - } - } - - static void ApplyOpenApi(OpenApiOptions o, Row r) - { - var v = r.Get("openapi.OpenApiVersion"); - if (v is not (null or "default")) o.OpenApiVersion = Enum.Parse(v); - switch (r.Get("openapi.CreateSchemaReferenceId")) - { - case "own-prefixing": o.CreateSchemaReferenceId = ti => OpenApiOptions.CreateDefaultSchemaReferenceId(ti) is { } id ? "X" + id : null; break; - case "null-inlines-all": o.CreateSchemaReferenceId = _ => null; break; - } - switch (r.Get("openapi.transformers")) - { - case "own-schema-transformer": o.AddSchemaTransformer((s, c, ct) => Task.CompletedTask); break; - case "own-operation-transformer": o.AddOperationTransformer((op, c, ct) => Task.CompletedTask); break; - case "own-document-transformer": o.AddDocumentTransformer((d, c, ct) => Task.CompletedTask); break; - } - } - - public static async Task Start(Row r, Entry e, HostCfg c) - { - var builder = WebApplication.CreateBuilder(new WebApplicationOptions { EnvironmentName = Environments.Production }); - builder.WebHost.UseTestServer(); - builder.Logging.ClearProviders(); - if (c.Logs is not null) builder.Logging.AddProvider(c.Logs); - var plain = e.Valid(); var vo = Make.Vo(e, plain); - var (twin, held) = Sides.Twins(r["shape.position"], r.Get("shape.containing") ?? "class", e, plain, vo); - var payload = new Payload(held, twin); - builder.Services.AddSingleton(payload); - builder.Services.ConfigureHttpJsonOptions(o => { JsonRow.Apply(r, e, o.SerializerOptions); if (c.WithoutTypeKit) Sides.DropTypeKit(o.SerializerOptions); }); - builder.Services.AddOpenApi(x => { ApplyOpenApi(x, r); if (c.TypeKitOpenApi && !c.WithoutTypeKit) x.AddTypeKit(); }); - if (!c.WithoutTypeKit) builder.Services.Configure(x => x.QualifiedFaultNames = c.Qualified); - c.Services?.Invoke(builder.Services); - if (c.MapBlanketMapping && !c.WithoutTypeKit) - { - builder.Services.AddFaultResponses(f => f switch { SFault.First => 409, SFault.Second => 410, _ => throw new ArgumentOutOfRangeException(nameof(f)) }); - if (c.Mapping == "by-kind") builder.Services.AddFaultResponses(); - else if (c.Mapping == "own-IFault-mapping") builder.Services.AddFaultResponses(f => FaultResponse.For(f.Kind).WithType(new Uri($"https://p.example/{f.Kind}"))); - else if (c.Mapping == "per-set") { builder.Services.AddFaultResponses(); builder.Services.AddFaultResponses(); } - } - var mvc = HasMvc(r); - if (mvc) - { - var controllers = new List(); - if (c.FaultControllers) controllers.AddRange(c.Controllers ?? FaultControllers(r)); - if (c.Payload) - { - controllers.Add(typeof(MvcPayloadController)); - if (c.PayloadOnly != "plain") controllers.Add(typeof(MvcBind<>).MakeGenericType(e.Vo)); - if (c.PayloadOnly != "vo") controllers.Add(typeof(MvcBind<>).MakeGenericType(e.Plain)); - } - var pfx = ""; - builder.Services.AddControllers(o => - { - o.Conventions.Add(new BindConvention(e.Vo, e.Plain, pfx)); // before the prefix convention, so that it prefixes these routes too - if (r["http.host"] == "controller-without-ApiController-visible") o.Conventions.Add(new VisibleToApiExplorer()); - ApplyMvc(o, r); - }) - .AddJsonOptions(o => { JsonRow.Apply(r, e, o.JsonSerializerOptions); if (c.WithoutTypeKit) Sides.DropTypeKit(o.JsonSerializerOptions); }) - .ConfigureApplicationPartManager(p => { p.ApplicationParts.Clear(); p.FeatureProviders.Add(new OnlyControllers([.. controllers])); }); - } - var app = builder.Build(); - app.MapOpenApi(); - if (HasMinimal(r)) - { - IEndpointRouteBuilder root = r["http.host"] == "route-group" ? app.MapGroup("/rg") : app; - c.Minimal?.Invoke(root); - if (c.Payload) MapPayload(root, payload, r, e, c.PayloadOnly); - } - if (mvc) { var cb = app.MapControllers(); c.ControllerBuilder?.Invoke(cb); } - try { await app.StartAsync(); } catch { await app.DisposeAsync(); throw; } - return app; - } - - // ---- minimal payload endpoints - static void MapPayload(IEndpointRouteBuilder b, Payload p, Row r, Entry e, string only) - { - foreach (var which in new[] { "vo", "plain" }) - { - if (only != "both" && only != which) continue; - var h = which == "vo" ? p.Vo : p.Plain; - b.MapGet($"/echo/{which}", async (HttpContext ctx) => { await ctx.Response.WriteAsJsonAsync(h.Value, h.Declared, options: null, contentType: null, ctx.RequestAborted); }); - b.MapPost($"/in/{which}", async (HttpContext ctx) => - { - object? v; - try { v = await ctx.Request.ReadFromJsonAsync(h.Declared, ctx.RequestAborted); } - catch (JsonException) { ctx.Response.StatusCode = 400; return; } - catch (BadHttpRequestException) { ctx.Response.StatusCode = 400; return; } - await ctx.Response.WriteAsJsonAsync(v, h.Declared, options: null, contentType: null, ctx.RequestAborted); - }); - typeof(Hx).GetMethod(nameof(MapBind), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(which == "vo" ? e.Vo : e.Plain) - .Invoke(null, [b, which, e.Wrapped is "own-record-class" or "NodaTime.Instant"]); - typeof(Hx).GetMethod(nameof(MapSchema), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(h.Declared).Invoke(null, [b, which]); - } - } - - sealed record AsP([FromQuery(Name = "v")] T V); - static void MapBind(IEndpointRouteBuilder b, string which, bool bodyOnly) - { - static IResult Out(HttpContext ctx, T v) => Results.Json(v, ctx.RequestServices.GetRequiredService>().Value.SerializerOptions, null, null); - b.MapPost($"/bind/body/{which}", (HttpContext ctx, [FromBody] T v) => Out(ctx, v)); - if (bodyOnly) return; // a record class cannot be bound from a route, query, header or form (the wrapped type neither) - b.MapGet($"/bind/route/{which}/{{v}}", (HttpContext ctx, T v) => Out(ctx, v)); - b.MapGet($"/bind/query/{which}", (HttpContext ctx, [FromQuery(Name = "v")] T v) => Out(ctx, v)); - b.MapGet($"/bind/header/{which}", (HttpContext ctx, [FromHeader(Name = "v")] T v) => Out(ctx, v)); - b.MapPost($"/bind/form/{which}", (HttpContext ctx, [FromForm(Name = "v")] T v) => Out(ctx, v)).DisableAntiforgery(); - b.MapGet($"/bind/params/{which}", (HttpContext ctx, [AsParameters] AsP p) => Out(ctx, p.V)); - } - static void MapSchema(IEndpointRouteBuilder b, string which) => - b.MapPost($"/schema/{which}", ([FromBody] T body) => Results.Ok(body)); - - // ---- client side - /// An answer on the wire: its status and body, or the exception the server threw (, a 500), named in . - public sealed record Wire(HttpStatusCode Status, string Body, string? Thrown = null, Exception? Ex = null) - { - /// The answer as the three-sided differential compares it (Sides): the status, the body, and the exception's type and stage. - public Sides.Answer Side(string operation) => new(operation, Ex is null ? Body : null, Ex, (int)Status); - } - public static async Task Send(WebApplication app, HttpMethod m, string path, string? body = null, string? contentType = null, (string, string)? header = null) - { - var req = new HttpRequestMessage(m, path); - req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - if (body is not null) req.Content = new StringContent(body, Encoding.UTF8, contentType ?? "application/json"); - if (header is { } h) req.Headers.TryAddWithoutValidation(h.Item1, h.Item2); - try - { - var resp = await app.GetTestClient().SendAsync(req); - return new(resp.StatusCode, await resp.Content.ReadAsStringAsync()); - } - catch (Exception ex) { return new(HttpStatusCode.InternalServerError, "", ex.GetType().Name + ": " + ex.Message, ex); } - } - public static Task Get(WebApplication app, string path) => Send(app, HttpMethod.Get, path); - public static async Task Doc(WebApplication app) => JsonNode.Parse(await app.GetTestClient().GetStringAsync("/openapi/v1.json")); - - /// - /// The document failed with AddTypeKit(). The same host without it is side (1) of the three (Sides): where ASP.NET alone refuses the - /// document alike, by exception type and stage and never by message (), the document part has nothing to check - /// (); where it writes the document, or refuses it otherwise, the failure is returned (F2 hid behind a baseline - /// that kept AddTypeKit() on both sides). says whether the check compared an answer before the document. - /// - public static async Task DocRefusedByAspNetAlone(Row r, Entry e, HostCfg c, Exception withTypeKit, bool comparedBefore = false) - { - static string Say(Exception x) => x.GetType().Name + ": " + (x.Message.Length > 200 ? x.Message[..200] + "..." : x.Message); - var alone = c.Copy(); alone.TypeKitOpenApi = false; - try - { - await using var app = await Start(r, e, alone); - await Doc(app); - } - catch (Exception ex) when (DocAlike(ex, withTypeKit)) - { - DocRefused(r, ex, comparedBefore); - return null; - } - catch (Exception ex) { return $"document: AddTypeKit() fails ({Say(withTypeKit)}), ASP.NET alone fails otherwise ({Say(ex)})"; } - return $"document: AddTypeKit() fails ({Say(withTypeKit)}), ASP.NET alone writes it"; - } - - /// - /// ASP.NET alone (side (1)) and AddTypeKit() (side (3)) refuse the document alike: the same exception type at the same stage (a - /// JsonException's Path), as compares two refusals. No message is compared: the two documents differ in length - /// by what AddTypeKit() wrote, so one refusal is at another line and byte of each (rows 31 and 140 of C21), and a refusal's words decide - /// no row (decision 99, WS2's three-sided differential). - /// - public static bool DocAlike(Exception one, Exception three) => - Sides.Alike(new Sides.Answer("document", null, one), new Sides.Answer("document", null, three)); - - /// - /// The document refused alike by ASP.NET alone: its part has nothing to check. A check that compared nothing before it is the framework's - /// refusal, an expected refusal that earns nothing (framework-refuses); one that compared an answer on the wire first is judged by that - /// answer (doc:refused-by-aspnet-alone, a pass: decision 99's "judged by its other checks"). - /// - public static void DocRefused(Row r, Exception one, bool comparedBefore) - { - if (comparedBefore) r.Note(NoteKeys.DocRefusedByAspnetAlone, one.GetType().Name); - else r.Note(NoteKeys.FrameworkRefuses, $"document refused by ASP.NET alone too ({one.GetType().Name}), side (1) measured on the same host without AddTypeKit()"); - } - - public static string BindText(Entry e, object plain) => e.Wrapped switch - { - "DateTime" => ((DateTime)plain).ToString("O"), "DateTimeOffset" => ((DateTimeOffset)plain).ToString("O"), - "DateOnly" => ((DateOnly)plain).ToString("yyyy-MM-dd"), "TimeOnly" => ((TimeOnly)plain).ToString("HH:mm:ss"), - "TimeSpan" => ((TimeSpan)plain).ToString("c"), "bool" => (bool)plain ? "true" : "false", "enum" or "flags-enum" => ((Enum)plain).ToString(), - _ => Convert.ToString(plain, System.Globalization.CultureInfo.InvariantCulture)! - }; - - // ---- schema comparison - /// Drops nullability markers (a class value object over a value type is nullable by being a class; not the value object's doing). - public static JsonNode? NoNull(JsonNode? n) - { - switch (n) - { - case JsonObject o: - static bool IsNull(JsonNode? a) => a is JsonObject ao && (ao["type"]?.ToJsonString() == "\"null\"" || ao["enum"]?.ToJsonString() == "[null]"); - if (o["oneOf"] is JsonArray alts && alts.Count == 2 && alts.Any(IsNull) && alts.FirstOrDefault(a => !IsNull(a)) is { } keep) - return NoNull(keep.DeepClone()); - var c = new JsonObject(); - foreach (var kv in o) - { - if (kv.Key is "nullable" or "x-nullable" or "x-null" or "required") continue; - if (kv.Key == "type" && kv.Value is JsonArray ta) { var f = ta.Where(x => x?.GetValue() != "null").ToList(); c["type"] = f.Count == 1 ? f[0]!.DeepClone() : new JsonArray(f.Select(x => x!.DeepClone()).ToArray()); continue; } - if (kv.Key == "allOf" && kv.Value is JsonArray aa && aa.Count == 1 && aa[0] is JsonObject a0 && a0.Count == 1 && a0.ContainsKey("x-nullable")) continue; - // OpenAPI 3.0 writes a type of several with null as anyOf [{type: integer}, {type: string}, {enum: [null]}] (row 260 of C21) - if (kv.Key == "anyOf" && kv.Value is JsonArray any && any.Any(IsNull)) { c["anyOf"] = new JsonArray(any.Where(x => !IsNull(x)).Select(NoNull).ToArray()); continue; } - if (kv.Key == "enum" && kv.Value is JsonArray en && en.Any(x => x is null)) { c["enum"] = new JsonArray(en.Where(x => x is not null).Select(x => x!.DeepClone()).ToArray()); continue; } - c[kv.Key] = NoNull(kv.Value); - } - return c; - case JsonArray a: var ca = new JsonArray(); foreach (var x in a) ca.Add(NoNull(x)); return ca; - default: return n?.DeepClone(); - } - } - - /// The key puts on a schema it resolved from a reference, when asked to mark them. - public const string ResolvedReference = "x-probe-resolved-reference"; - - public static JsonNode? Deep(JsonNode doc, JsonNode? n, HashSet? seen = null, bool mark = false) - { - seen ??= []; - switch (n) - { - case JsonObject o: - if (o["$ref"] is { } rf) - { - var key = rf.GetValue(); - if (!seen.Add(key)) return JsonValue.Create(""); - var target = doc; foreach (var seg in key.TrimStart('#', '/').Split('/')) target = target?[seg]; - var res = Deep(doc, target, seen, mark); seen.Remove(key); - if (mark && res is JsonObject resolved) resolved[ResolvedReference] = true; - return res; - } - var c = new JsonObject(); - foreach (var kv in o.OrderBy(k => k.Key, StringComparer.Ordinal)) - if (kv.Key is not ("title" or "description" or "example" or "examples")) - c[kv.Key] = kv.Key == "discriminator" ? Discriminator(o, kv.Value) : Deep(doc, kv.Value, seen, mark); - return c; - case JsonArray a: var ca = new JsonArray(); foreach (var x in a) ca.Add(Deep(doc, x, seen, mark)); return ca; - default: return n?.DeepClone(); - } - } - - /// - /// A discriminator's mapping names a component per value, and a component's name is made of the type's, which - /// differs between the two sides by construction (row 347 of C07: PB<TimeSpan> against - /// PB<V>). Each value names instead the branch of the same schema's anyOf or oneOf it maps to, whose - /// content compares; a target that is no branch stays as it is, and so still differs. - /// - static JsonNode? Discriminator(JsonObject schema, JsonNode? discriminator) - { - if (discriminator is not JsonObject d || d["mapping"] is not JsonObject mapping) return discriminator?.DeepClone(); - var branches = (schema["anyOf"] ?? schema["oneOf"]) as JsonArray; - var c = (JsonObject)d.DeepClone(); - var named = new JsonObject(); - foreach (var (value, target) in mapping.OrderBy(m => m.Key, StringComparer.Ordinal)) - { - var index = -1; - for (var i = 0; target is JsonValue && i < (branches?.Count ?? 0); i++) - if (branches![i]?["$ref"]?.GetValue() == target.GetValue()) { index = i; break; } - named[value] = index >= 0 ? $"branch {index}" : target?.DeepClone(); - } - c["mapping"] = named; - return c; - } -} diff --git a/tools/probe/corpus/harness/JsonFamily.cs b/tools/probe/corpus/harness/JsonFamily.cs deleted file mode 100644 index 8a1ef837..00000000 --- a/tools/probe/corpus/harness/JsonFamily.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Shared code of the JSON family's claim checks (C01 decimal spelling, C10 Preserve guard, L06 off the wire): -// serializing a held shape, reading its tokens, rewriting one token, and reading what a document holds back. -using System.Text; -using System.Text.Json; -using Probes.Shapes; -namespace Probes.Json; - -/// One token of a JSON document: its kind, its raw text (a string's without quotes), its value as text, and its byte span. -public sealed record JTok(JsonTokenType Type, string Raw, string? Text, int Start, int End); - -public static class Jx -{ - public static (string? Json, Exception? Ex) Ser(Held h, JsonSerializerOptions o) - { try { return (JsonSerializer.Serialize(h.Value, h.Declared, o), null); } catch (Exception ex) { return (null, ex); } } - - public static (object? Value, Exception? Ex) De(string text, Type declared, JsonSerializerOptions o) - { try { return (JsonSerializer.Deserialize(text, declared, o), null); } catch (Exception ex) { return (null, ex); } } - - /// Every token of a document, with the byte span it takes (a string's and a property name's quotes included). - public static List Tokens(string json) - { - var bytes = Encoding.UTF8.GetBytes(json); - var rd = new Utf8JsonReader(bytes, new JsonReaderOptions { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip }); - var list = new List(); - while (rd.Read()) - { - var start = (int)rd.TokenStartIndex; - switch (rd.TokenType) - { - case JsonTokenType.Number: - list.Add(new(rd.TokenType, Encoding.UTF8.GetString(rd.ValueSpan), Encoding.UTF8.GetString(rd.ValueSpan), start, start + rd.ValueSpan.Length)); break; - case JsonTokenType.String or JsonTokenType.PropertyName: - list.Add(new(rd.TokenType, Encoding.UTF8.GetString(rd.ValueSpan), rd.GetString(), start, start + rd.ValueSpan.Length + 2)); break; - default: - list.Add(new(rd.TokenType, "", null, start, start)); break; - } - } - return list; - } - - /// The document with the tokens replaced by (raw JSON text). - public static string Rewrite(string json, IEnumerable at, Func with) - { - var bytes = Encoding.UTF8.GetBytes(json); - var sb = new StringBuilder(); var pos = 0; - foreach (var t in at.OrderBy(t => t.Start)) - { - sb.Append(Encoding.UTF8.GetString(bytes, pos, t.Start - pos)); sb.Append(with(t)); pos = t.End; - } - sb.Append(Encoding.UTF8.GetString(bytes, pos, bytes.Length - pos)); - return sb.ToString(); - } - - /// Options that write what a value holds as the serializer writes it by default (a decimal with its scale, every field). - public static readonly JsonSerializerOptions Plain = new() { IncludeFields = true }; - - public static string Cut(string? s) => s is null ? "(null)" : s.Length > 220 ? s[..220] + "..." : s; - public static string Name(Type t) => t.IsGenericType ? t.Name[..t.Name.IndexOf('`')] + "<" + string.Join(", ", t.GetGenericArguments().Select(Name)) + ">" : t.Name; - /// A refusal's message with the type the other side holds named instead: the serializer names the shape it refused. - public static string Swap(string message, Type from, Type to) => message.Replace(from.ToString(), to.ToString()); - /// What a containing type holds: its property P or its field F. - public static object? Member(Type declared, object? holder) => - holder is null ? null : declared.GetProperty("P") is { } p ? p.GetValue(holder) : declared.GetField("F") is { } f ? f.GetValue(holder) : null; - public static string Ex(Exception e) => e.GetType().Name + ": " + Cut(e.Message); - - /// A copy of the options that writes every member: the ignore conditions reset, so a read has the member to read. - public static JsonSerializerOptions Full(JsonSerializerOptions o) => new(o) - { - DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.Never, IgnoreReadOnlyProperties = false, IgnoreReadOnlyFields = false, - // A number written as a string reads back only with AllowReadingFromString; the document is input, so it says its other numbers plainly. - NumberHandling = o.NumberHandling & ~System.Text.Json.Serialization.JsonNumberHandling.WriteAsString, - }; -} - -/// -/// The row's json.* axes, applied by JsonRow: under json.TypeInfoResolver=source-generated-context the resolver is ProbeContext alone -/// (Shapes.g.cs), which lists every shape a row holds and its twin, so the setting runs as the row names it. A shape of the claim's own -/// the context does not list (L06's Option or Result) is the generator's gap: a harness error. -/// -public static class JCtx -{ - public static JsonSerializerOptions Apply(Row r, Entry e, params Type[] shapes) - { - var o = JsonRow.Apply(r, e).Options!; - var missing = JsonRow.Unlisted(r, shapes).Select(Jx.Name).ToList(); - if (missing.Count > 0) throw new InvalidOperationException("ProbeContext does not list (run tools/probe/generators/shapes.cs): " + string.Join(", ", missing)); - return o; - } -} diff --git a/tools/probe/corpus/harness/JsonFamilyShapes.g.cs b/tools/probe/corpus/harness/JsonFamilyShapes.g.cs deleted file mode 100644 index 5cb98433..00000000 --- a/tools/probe/corpus/harness/JsonFamilyShapes.g.cs +++ /dev/null @@ -1,493 +0,0 @@ -// by tools/probe/generators/json-family.cs stand-ins: L06's polymorphic stand-ins over Option and Result. Do not edit. -#nullable disable -#pragma warning disable CS8618, CS1591, CMTK0005, CMTK0006 -using CodoMetis.TypeKit; -using Probes.Shapes; -namespace Probes.Json; - -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_string_O), "d")] public abstract class L06PB_V_record_struct_string_O { } -public sealed class L06PD_V_record_struct_string_O : L06PB_V_record_struct_string_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_string_RTE), "d")] public abstract class L06PB_V_record_struct_string_RTE { } -public sealed class L06PD_V_record_struct_string_RTE : L06PB_V_record_struct_string_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_string_RE), "d")] public abstract class L06PB_V_record_struct_string_RE { } -public sealed class L06PD_V_record_struct_string_RE : L06PB_V_record_struct_string_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_Guid_O), "d")] public abstract class L06PB_V_record_struct_Guid_O { } -public sealed class L06PD_V_record_struct_Guid_O : L06PB_V_record_struct_Guid_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_Guid_RTE), "d")] public abstract class L06PB_V_record_struct_Guid_RTE { } -public sealed class L06PD_V_record_struct_Guid_RTE : L06PB_V_record_struct_Guid_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_Guid_RE), "d")] public abstract class L06PB_V_record_struct_Guid_RE { } -public sealed class L06PD_V_record_struct_Guid_RE : L06PB_V_record_struct_Guid_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_int_O), "d")] public abstract class L06PB_V_record_struct_int_O { } -public sealed class L06PD_V_record_struct_int_O : L06PB_V_record_struct_int_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_int_RTE), "d")] public abstract class L06PB_V_record_struct_int_RTE { } -public sealed class L06PD_V_record_struct_int_RTE : L06PB_V_record_struct_int_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_int_RE), "d")] public abstract class L06PB_V_record_struct_int_RE { } -public sealed class L06PD_V_record_struct_int_RE : L06PB_V_record_struct_int_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_long_O), "d")] public abstract class L06PB_V_record_struct_long_O { } -public sealed class L06PD_V_record_struct_long_O : L06PB_V_record_struct_long_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_long_RTE), "d")] public abstract class L06PB_V_record_struct_long_RTE { } -public sealed class L06PD_V_record_struct_long_RTE : L06PB_V_record_struct_long_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_long_RE), "d")] public abstract class L06PB_V_record_struct_long_RE { } -public sealed class L06PD_V_record_struct_long_RE : L06PB_V_record_struct_long_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_byte_O), "d")] public abstract class L06PB_V_record_struct_byte_O { } -public sealed class L06PD_V_record_struct_byte_O : L06PB_V_record_struct_byte_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_byte_RTE), "d")] public abstract class L06PB_V_record_struct_byte_RTE { } -public sealed class L06PD_V_record_struct_byte_RTE : L06PB_V_record_struct_byte_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_byte_RE), "d")] public abstract class L06PB_V_record_struct_byte_RE { } -public sealed class L06PD_V_record_struct_byte_RE : L06PB_V_record_struct_byte_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_ulong_O), "d")] public abstract class L06PB_V_record_struct_ulong_O { } -public sealed class L06PD_V_record_struct_ulong_O : L06PB_V_record_struct_ulong_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_ulong_RTE), "d")] public abstract class L06PB_V_record_struct_ulong_RTE { } -public sealed class L06PD_V_record_struct_ulong_RTE : L06PB_V_record_struct_ulong_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_ulong_RE), "d")] public abstract class L06PB_V_record_struct_ulong_RE { } -public sealed class L06PD_V_record_struct_ulong_RE : L06PB_V_record_struct_ulong_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_decimal_O), "d")] public abstract class L06PB_V_record_struct_decimal_O { } -public sealed class L06PD_V_record_struct_decimal_O : L06PB_V_record_struct_decimal_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_decimal_RTE), "d")] public abstract class L06PB_V_record_struct_decimal_RTE { } -public sealed class L06PD_V_record_struct_decimal_RTE : L06PB_V_record_struct_decimal_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_decimal_RE), "d")] public abstract class L06PB_V_record_struct_decimal_RE { } -public sealed class L06PD_V_record_struct_decimal_RE : L06PB_V_record_struct_decimal_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_double_O), "d")] public abstract class L06PB_V_record_struct_double_O { } -public sealed class L06PD_V_record_struct_double_O : L06PB_V_record_struct_double_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_double_RTE), "d")] public abstract class L06PB_V_record_struct_double_RTE { } -public sealed class L06PD_V_record_struct_double_RTE : L06PB_V_record_struct_double_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_double_RE), "d")] public abstract class L06PB_V_record_struct_double_RE { } -public sealed class L06PD_V_record_struct_double_RE : L06PB_V_record_struct_double_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_bool_O), "d")] public abstract class L06PB_V_record_struct_bool_O { } -public sealed class L06PD_V_record_struct_bool_O : L06PB_V_record_struct_bool_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_bool_RTE), "d")] public abstract class L06PB_V_record_struct_bool_RTE { } -public sealed class L06PD_V_record_struct_bool_RTE : L06PB_V_record_struct_bool_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_bool_RE), "d")] public abstract class L06PB_V_record_struct_bool_RE { } -public sealed class L06PD_V_record_struct_bool_RE : L06PB_V_record_struct_bool_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_char_O), "d")] public abstract class L06PB_V_record_struct_char_O { } -public sealed class L06PD_V_record_struct_char_O : L06PB_V_record_struct_char_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_char_RTE), "d")] public abstract class L06PB_V_record_struct_char_RTE { } -public sealed class L06PD_V_record_struct_char_RTE : L06PB_V_record_struct_char_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_char_RE), "d")] public abstract class L06PB_V_record_struct_char_RE { } -public sealed class L06PD_V_record_struct_char_RE : L06PB_V_record_struct_char_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateTime_O), "d")] public abstract class L06PB_V_record_struct_DateTime_O { } -public sealed class L06PD_V_record_struct_DateTime_O : L06PB_V_record_struct_DateTime_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateTime_RTE), "d")] public abstract class L06PB_V_record_struct_DateTime_RTE { } -public sealed class L06PD_V_record_struct_DateTime_RTE : L06PB_V_record_struct_DateTime_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateTime_RE), "d")] public abstract class L06PB_V_record_struct_DateTime_RE { } -public sealed class L06PD_V_record_struct_DateTime_RE : L06PB_V_record_struct_DateTime_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateTimeOffset_O), "d")] public abstract class L06PB_V_record_struct_DateTimeOffset_O { } -public sealed class L06PD_V_record_struct_DateTimeOffset_O : L06PB_V_record_struct_DateTimeOffset_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateTimeOffset_RTE), "d")] public abstract class L06PB_V_record_struct_DateTimeOffset_RTE { } -public sealed class L06PD_V_record_struct_DateTimeOffset_RTE : L06PB_V_record_struct_DateTimeOffset_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateTimeOffset_RE), "d")] public abstract class L06PB_V_record_struct_DateTimeOffset_RE { } -public sealed class L06PD_V_record_struct_DateTimeOffset_RE : L06PB_V_record_struct_DateTimeOffset_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateOnly_O), "d")] public abstract class L06PB_V_record_struct_DateOnly_O { } -public sealed class L06PD_V_record_struct_DateOnly_O : L06PB_V_record_struct_DateOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateOnly_RTE), "d")] public abstract class L06PB_V_record_struct_DateOnly_RTE { } -public sealed class L06PD_V_record_struct_DateOnly_RTE : L06PB_V_record_struct_DateOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_DateOnly_RE), "d")] public abstract class L06PB_V_record_struct_DateOnly_RE { } -public sealed class L06PD_V_record_struct_DateOnly_RE : L06PB_V_record_struct_DateOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_TimeOnly_O), "d")] public abstract class L06PB_V_record_struct_TimeOnly_O { } -public sealed class L06PD_V_record_struct_TimeOnly_O : L06PB_V_record_struct_TimeOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_TimeOnly_RTE), "d")] public abstract class L06PB_V_record_struct_TimeOnly_RTE { } -public sealed class L06PD_V_record_struct_TimeOnly_RTE : L06PB_V_record_struct_TimeOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_TimeOnly_RE), "d")] public abstract class L06PB_V_record_struct_TimeOnly_RE { } -public sealed class L06PD_V_record_struct_TimeOnly_RE : L06PB_V_record_struct_TimeOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_TimeSpan_O), "d")] public abstract class L06PB_V_record_struct_TimeSpan_O { } -public sealed class L06PD_V_record_struct_TimeSpan_O : L06PB_V_record_struct_TimeSpan_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_TimeSpan_RTE), "d")] public abstract class L06PB_V_record_struct_TimeSpan_RTE { } -public sealed class L06PD_V_record_struct_TimeSpan_RTE : L06PB_V_record_struct_TimeSpan_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_TimeSpan_RE), "d")] public abstract class L06PB_V_record_struct_TimeSpan_RE { } -public sealed class L06PD_V_record_struct_TimeSpan_RE : L06PB_V_record_struct_TimeSpan_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_enum_O), "d")] public abstract class L06PB_V_record_struct_enum_O { } -public sealed class L06PD_V_record_struct_enum_O : L06PB_V_record_struct_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_enum_RTE), "d")] public abstract class L06PB_V_record_struct_enum_RTE { } -public sealed class L06PD_V_record_struct_enum_RTE : L06PB_V_record_struct_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_enum_RE), "d")] public abstract class L06PB_V_record_struct_enum_RE { } -public sealed class L06PD_V_record_struct_enum_RE : L06PB_V_record_struct_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_flags_enum_O), "d")] public abstract class L06PB_V_record_struct_flags_enum_O { } -public sealed class L06PD_V_record_struct_flags_enum_O : L06PB_V_record_struct_flags_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_flags_enum_RTE), "d")] public abstract class L06PB_V_record_struct_flags_enum_RTE { } -public sealed class L06PD_V_record_struct_flags_enum_RTE : L06PB_V_record_struct_flags_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_flags_enum_RE), "d")] public abstract class L06PB_V_record_struct_flags_enum_RE { } -public sealed class L06PD_V_record_struct_flags_enum_RE : L06PB_V_record_struct_flags_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_Uri_O), "d")] public abstract class L06PB_V_record_struct_Uri_O { } -public sealed class L06PD_V_record_struct_Uri_O : L06PB_V_record_struct_Uri_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_Uri_RTE), "d")] public abstract class L06PB_V_record_struct_Uri_RTE { } -public sealed class L06PD_V_record_struct_Uri_RTE : L06PB_V_record_struct_Uri_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_Uri_RE), "d")] public abstract class L06PB_V_record_struct_Uri_RE { } -public sealed class L06PD_V_record_struct_Uri_RE : L06PB_V_record_struct_Uri_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_NodaTime_Instant_O), "d")] public abstract class L06PB_V_record_struct_NodaTime_Instant_O { } -public sealed class L06PD_V_record_struct_NodaTime_Instant_O : L06PB_V_record_struct_NodaTime_Instant_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_NodaTime_Instant_RTE), "d")] public abstract class L06PB_V_record_struct_NodaTime_Instant_RTE { } -public sealed class L06PD_V_record_struct_NodaTime_Instant_RTE : L06PB_V_record_struct_NodaTime_Instant_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_NodaTime_Instant_RE), "d")] public abstract class L06PB_V_record_struct_NodaTime_Instant_RE { } -public sealed class L06PD_V_record_struct_NodaTime_Instant_RE : L06PB_V_record_struct_NodaTime_Instant_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_own_record_class_O), "d")] public abstract class L06PB_V_record_struct_own_record_class_O { } -public sealed class L06PD_V_record_struct_own_record_class_O : L06PB_V_record_struct_own_record_class_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_own_record_class_RTE), "d")] public abstract class L06PB_V_record_struct_own_record_class_RTE { } -public sealed class L06PD_V_record_struct_own_record_class_RTE : L06PB_V_record_struct_own_record_class_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_record_struct_own_record_class_RE), "d")] public abstract class L06PB_V_record_struct_own_record_class_RE { } -public sealed class L06PD_V_record_struct_own_record_class_RE : L06PB_V_record_struct_own_record_class_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_string_O), "d")] public abstract class L06PB_V_sealed_record_class_string_O { } -public sealed class L06PD_V_sealed_record_class_string_O : L06PB_V_sealed_record_class_string_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_string_RTE), "d")] public abstract class L06PB_V_sealed_record_class_string_RTE { } -public sealed class L06PD_V_sealed_record_class_string_RTE : L06PB_V_sealed_record_class_string_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_string_RE), "d")] public abstract class L06PB_V_sealed_record_class_string_RE { } -public sealed class L06PD_V_sealed_record_class_string_RE : L06PB_V_sealed_record_class_string_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_Guid_O), "d")] public abstract class L06PB_V_sealed_record_class_Guid_O { } -public sealed class L06PD_V_sealed_record_class_Guid_O : L06PB_V_sealed_record_class_Guid_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_Guid_RTE), "d")] public abstract class L06PB_V_sealed_record_class_Guid_RTE { } -public sealed class L06PD_V_sealed_record_class_Guid_RTE : L06PB_V_sealed_record_class_Guid_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_Guid_RE), "d")] public abstract class L06PB_V_sealed_record_class_Guid_RE { } -public sealed class L06PD_V_sealed_record_class_Guid_RE : L06PB_V_sealed_record_class_Guid_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_int_O), "d")] public abstract class L06PB_V_sealed_record_class_int_O { } -public sealed class L06PD_V_sealed_record_class_int_O : L06PB_V_sealed_record_class_int_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_int_RTE), "d")] public abstract class L06PB_V_sealed_record_class_int_RTE { } -public sealed class L06PD_V_sealed_record_class_int_RTE : L06PB_V_sealed_record_class_int_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_int_RE), "d")] public abstract class L06PB_V_sealed_record_class_int_RE { } -public sealed class L06PD_V_sealed_record_class_int_RE : L06PB_V_sealed_record_class_int_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_long_O), "d")] public abstract class L06PB_V_sealed_record_class_long_O { } -public sealed class L06PD_V_sealed_record_class_long_O : L06PB_V_sealed_record_class_long_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_long_RTE), "d")] public abstract class L06PB_V_sealed_record_class_long_RTE { } -public sealed class L06PD_V_sealed_record_class_long_RTE : L06PB_V_sealed_record_class_long_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_long_RE), "d")] public abstract class L06PB_V_sealed_record_class_long_RE { } -public sealed class L06PD_V_sealed_record_class_long_RE : L06PB_V_sealed_record_class_long_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_byte_O), "d")] public abstract class L06PB_V_sealed_record_class_byte_O { } -public sealed class L06PD_V_sealed_record_class_byte_O : L06PB_V_sealed_record_class_byte_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_byte_RTE), "d")] public abstract class L06PB_V_sealed_record_class_byte_RTE { } -public sealed class L06PD_V_sealed_record_class_byte_RTE : L06PB_V_sealed_record_class_byte_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_byte_RE), "d")] public abstract class L06PB_V_sealed_record_class_byte_RE { } -public sealed class L06PD_V_sealed_record_class_byte_RE : L06PB_V_sealed_record_class_byte_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_ulong_O), "d")] public abstract class L06PB_V_sealed_record_class_ulong_O { } -public sealed class L06PD_V_sealed_record_class_ulong_O : L06PB_V_sealed_record_class_ulong_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_ulong_RTE), "d")] public abstract class L06PB_V_sealed_record_class_ulong_RTE { } -public sealed class L06PD_V_sealed_record_class_ulong_RTE : L06PB_V_sealed_record_class_ulong_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_ulong_RE), "d")] public abstract class L06PB_V_sealed_record_class_ulong_RE { } -public sealed class L06PD_V_sealed_record_class_ulong_RE : L06PB_V_sealed_record_class_ulong_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_decimal_O), "d")] public abstract class L06PB_V_sealed_record_class_decimal_O { } -public sealed class L06PD_V_sealed_record_class_decimal_O : L06PB_V_sealed_record_class_decimal_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_decimal_RTE), "d")] public abstract class L06PB_V_sealed_record_class_decimal_RTE { } -public sealed class L06PD_V_sealed_record_class_decimal_RTE : L06PB_V_sealed_record_class_decimal_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_decimal_RE), "d")] public abstract class L06PB_V_sealed_record_class_decimal_RE { } -public sealed class L06PD_V_sealed_record_class_decimal_RE : L06PB_V_sealed_record_class_decimal_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_double_O), "d")] public abstract class L06PB_V_sealed_record_class_double_O { } -public sealed class L06PD_V_sealed_record_class_double_O : L06PB_V_sealed_record_class_double_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_double_RTE), "d")] public abstract class L06PB_V_sealed_record_class_double_RTE { } -public sealed class L06PD_V_sealed_record_class_double_RTE : L06PB_V_sealed_record_class_double_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_double_RE), "d")] public abstract class L06PB_V_sealed_record_class_double_RE { } -public sealed class L06PD_V_sealed_record_class_double_RE : L06PB_V_sealed_record_class_double_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_bool_O), "d")] public abstract class L06PB_V_sealed_record_class_bool_O { } -public sealed class L06PD_V_sealed_record_class_bool_O : L06PB_V_sealed_record_class_bool_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_bool_RTE), "d")] public abstract class L06PB_V_sealed_record_class_bool_RTE { } -public sealed class L06PD_V_sealed_record_class_bool_RTE : L06PB_V_sealed_record_class_bool_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_bool_RE), "d")] public abstract class L06PB_V_sealed_record_class_bool_RE { } -public sealed class L06PD_V_sealed_record_class_bool_RE : L06PB_V_sealed_record_class_bool_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_char_O), "d")] public abstract class L06PB_V_sealed_record_class_char_O { } -public sealed class L06PD_V_sealed_record_class_char_O : L06PB_V_sealed_record_class_char_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_char_RTE), "d")] public abstract class L06PB_V_sealed_record_class_char_RTE { } -public sealed class L06PD_V_sealed_record_class_char_RTE : L06PB_V_sealed_record_class_char_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_char_RE), "d")] public abstract class L06PB_V_sealed_record_class_char_RE { } -public sealed class L06PD_V_sealed_record_class_char_RE : L06PB_V_sealed_record_class_char_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateTime_O), "d")] public abstract class L06PB_V_sealed_record_class_DateTime_O { } -public sealed class L06PD_V_sealed_record_class_DateTime_O : L06PB_V_sealed_record_class_DateTime_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateTime_RTE), "d")] public abstract class L06PB_V_sealed_record_class_DateTime_RTE { } -public sealed class L06PD_V_sealed_record_class_DateTime_RTE : L06PB_V_sealed_record_class_DateTime_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateTime_RE), "d")] public abstract class L06PB_V_sealed_record_class_DateTime_RE { } -public sealed class L06PD_V_sealed_record_class_DateTime_RE : L06PB_V_sealed_record_class_DateTime_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateTimeOffset_O), "d")] public abstract class L06PB_V_sealed_record_class_DateTimeOffset_O { } -public sealed class L06PD_V_sealed_record_class_DateTimeOffset_O : L06PB_V_sealed_record_class_DateTimeOffset_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateTimeOffset_RTE), "d")] public abstract class L06PB_V_sealed_record_class_DateTimeOffset_RTE { } -public sealed class L06PD_V_sealed_record_class_DateTimeOffset_RTE : L06PB_V_sealed_record_class_DateTimeOffset_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateTimeOffset_RE), "d")] public abstract class L06PB_V_sealed_record_class_DateTimeOffset_RE { } -public sealed class L06PD_V_sealed_record_class_DateTimeOffset_RE : L06PB_V_sealed_record_class_DateTimeOffset_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateOnly_O), "d")] public abstract class L06PB_V_sealed_record_class_DateOnly_O { } -public sealed class L06PD_V_sealed_record_class_DateOnly_O : L06PB_V_sealed_record_class_DateOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateOnly_RTE), "d")] public abstract class L06PB_V_sealed_record_class_DateOnly_RTE { } -public sealed class L06PD_V_sealed_record_class_DateOnly_RTE : L06PB_V_sealed_record_class_DateOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_DateOnly_RE), "d")] public abstract class L06PB_V_sealed_record_class_DateOnly_RE { } -public sealed class L06PD_V_sealed_record_class_DateOnly_RE : L06PB_V_sealed_record_class_DateOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_TimeOnly_O), "d")] public abstract class L06PB_V_sealed_record_class_TimeOnly_O { } -public sealed class L06PD_V_sealed_record_class_TimeOnly_O : L06PB_V_sealed_record_class_TimeOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_TimeOnly_RTE), "d")] public abstract class L06PB_V_sealed_record_class_TimeOnly_RTE { } -public sealed class L06PD_V_sealed_record_class_TimeOnly_RTE : L06PB_V_sealed_record_class_TimeOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_TimeOnly_RE), "d")] public abstract class L06PB_V_sealed_record_class_TimeOnly_RE { } -public sealed class L06PD_V_sealed_record_class_TimeOnly_RE : L06PB_V_sealed_record_class_TimeOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_TimeSpan_O), "d")] public abstract class L06PB_V_sealed_record_class_TimeSpan_O { } -public sealed class L06PD_V_sealed_record_class_TimeSpan_O : L06PB_V_sealed_record_class_TimeSpan_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_TimeSpan_RTE), "d")] public abstract class L06PB_V_sealed_record_class_TimeSpan_RTE { } -public sealed class L06PD_V_sealed_record_class_TimeSpan_RTE : L06PB_V_sealed_record_class_TimeSpan_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_TimeSpan_RE), "d")] public abstract class L06PB_V_sealed_record_class_TimeSpan_RE { } -public sealed class L06PD_V_sealed_record_class_TimeSpan_RE : L06PB_V_sealed_record_class_TimeSpan_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_enum_O), "d")] public abstract class L06PB_V_sealed_record_class_enum_O { } -public sealed class L06PD_V_sealed_record_class_enum_O : L06PB_V_sealed_record_class_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_enum_RTE), "d")] public abstract class L06PB_V_sealed_record_class_enum_RTE { } -public sealed class L06PD_V_sealed_record_class_enum_RTE : L06PB_V_sealed_record_class_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_enum_RE), "d")] public abstract class L06PB_V_sealed_record_class_enum_RE { } -public sealed class L06PD_V_sealed_record_class_enum_RE : L06PB_V_sealed_record_class_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_flags_enum_O), "d")] public abstract class L06PB_V_sealed_record_class_flags_enum_O { } -public sealed class L06PD_V_sealed_record_class_flags_enum_O : L06PB_V_sealed_record_class_flags_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_flags_enum_RTE), "d")] public abstract class L06PB_V_sealed_record_class_flags_enum_RTE { } -public sealed class L06PD_V_sealed_record_class_flags_enum_RTE : L06PB_V_sealed_record_class_flags_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_flags_enum_RE), "d")] public abstract class L06PB_V_sealed_record_class_flags_enum_RE { } -public sealed class L06PD_V_sealed_record_class_flags_enum_RE : L06PB_V_sealed_record_class_flags_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_Uri_O), "d")] public abstract class L06PB_V_sealed_record_class_Uri_O { } -public sealed class L06PD_V_sealed_record_class_Uri_O : L06PB_V_sealed_record_class_Uri_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_Uri_RTE), "d")] public abstract class L06PB_V_sealed_record_class_Uri_RTE { } -public sealed class L06PD_V_sealed_record_class_Uri_RTE : L06PB_V_sealed_record_class_Uri_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_Uri_RE), "d")] public abstract class L06PB_V_sealed_record_class_Uri_RE { } -public sealed class L06PD_V_sealed_record_class_Uri_RE : L06PB_V_sealed_record_class_Uri_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_NodaTime_Instant_O), "d")] public abstract class L06PB_V_sealed_record_class_NodaTime_Instant_O { } -public sealed class L06PD_V_sealed_record_class_NodaTime_Instant_O : L06PB_V_sealed_record_class_NodaTime_Instant_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_NodaTime_Instant_RTE), "d")] public abstract class L06PB_V_sealed_record_class_NodaTime_Instant_RTE { } -public sealed class L06PD_V_sealed_record_class_NodaTime_Instant_RTE : L06PB_V_sealed_record_class_NodaTime_Instant_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_NodaTime_Instant_RE), "d")] public abstract class L06PB_V_sealed_record_class_NodaTime_Instant_RE { } -public sealed class L06PD_V_sealed_record_class_NodaTime_Instant_RE : L06PB_V_sealed_record_class_NodaTime_Instant_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_own_record_class_O), "d")] public abstract class L06PB_V_sealed_record_class_own_record_class_O { } -public sealed class L06PD_V_sealed_record_class_own_record_class_O : L06PB_V_sealed_record_class_own_record_class_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_own_record_class_RTE), "d")] public abstract class L06PB_V_sealed_record_class_own_record_class_RTE { } -public sealed class L06PD_V_sealed_record_class_own_record_class_RTE : L06PB_V_sealed_record_class_own_record_class_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_sealed_record_class_own_record_class_RE), "d")] public abstract class L06PB_V_sealed_record_class_own_record_class_RE { } -public sealed class L06PD_V_sealed_record_class_own_record_class_RE : L06PB_V_sealed_record_class_own_record_class_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_string_O), "d")] public abstract class L06PB_V_validated_struct_string_O { } -public sealed class L06PD_V_validated_struct_string_O : L06PB_V_validated_struct_string_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_string_RTE), "d")] public abstract class L06PB_V_validated_struct_string_RTE { } -public sealed class L06PD_V_validated_struct_string_RTE : L06PB_V_validated_struct_string_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_string_RE), "d")] public abstract class L06PB_V_validated_struct_string_RE { } -public sealed class L06PD_V_validated_struct_string_RE : L06PB_V_validated_struct_string_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_Guid_O), "d")] public abstract class L06PB_V_validated_struct_Guid_O { } -public sealed class L06PD_V_validated_struct_Guid_O : L06PB_V_validated_struct_Guid_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_Guid_RTE), "d")] public abstract class L06PB_V_validated_struct_Guid_RTE { } -public sealed class L06PD_V_validated_struct_Guid_RTE : L06PB_V_validated_struct_Guid_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_Guid_RE), "d")] public abstract class L06PB_V_validated_struct_Guid_RE { } -public sealed class L06PD_V_validated_struct_Guid_RE : L06PB_V_validated_struct_Guid_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_int_O), "d")] public abstract class L06PB_V_validated_struct_int_O { } -public sealed class L06PD_V_validated_struct_int_O : L06PB_V_validated_struct_int_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_int_RTE), "d")] public abstract class L06PB_V_validated_struct_int_RTE { } -public sealed class L06PD_V_validated_struct_int_RTE : L06PB_V_validated_struct_int_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_int_RE), "d")] public abstract class L06PB_V_validated_struct_int_RE { } -public sealed class L06PD_V_validated_struct_int_RE : L06PB_V_validated_struct_int_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_long_O), "d")] public abstract class L06PB_V_validated_struct_long_O { } -public sealed class L06PD_V_validated_struct_long_O : L06PB_V_validated_struct_long_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_long_RTE), "d")] public abstract class L06PB_V_validated_struct_long_RTE { } -public sealed class L06PD_V_validated_struct_long_RTE : L06PB_V_validated_struct_long_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_long_RE), "d")] public abstract class L06PB_V_validated_struct_long_RE { } -public sealed class L06PD_V_validated_struct_long_RE : L06PB_V_validated_struct_long_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_byte_O), "d")] public abstract class L06PB_V_validated_struct_byte_O { } -public sealed class L06PD_V_validated_struct_byte_O : L06PB_V_validated_struct_byte_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_byte_RTE), "d")] public abstract class L06PB_V_validated_struct_byte_RTE { } -public sealed class L06PD_V_validated_struct_byte_RTE : L06PB_V_validated_struct_byte_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_byte_RE), "d")] public abstract class L06PB_V_validated_struct_byte_RE { } -public sealed class L06PD_V_validated_struct_byte_RE : L06PB_V_validated_struct_byte_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_ulong_O), "d")] public abstract class L06PB_V_validated_struct_ulong_O { } -public sealed class L06PD_V_validated_struct_ulong_O : L06PB_V_validated_struct_ulong_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_ulong_RTE), "d")] public abstract class L06PB_V_validated_struct_ulong_RTE { } -public sealed class L06PD_V_validated_struct_ulong_RTE : L06PB_V_validated_struct_ulong_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_ulong_RE), "d")] public abstract class L06PB_V_validated_struct_ulong_RE { } -public sealed class L06PD_V_validated_struct_ulong_RE : L06PB_V_validated_struct_ulong_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_decimal_O), "d")] public abstract class L06PB_V_validated_struct_decimal_O { } -public sealed class L06PD_V_validated_struct_decimal_O : L06PB_V_validated_struct_decimal_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_decimal_RTE), "d")] public abstract class L06PB_V_validated_struct_decimal_RTE { } -public sealed class L06PD_V_validated_struct_decimal_RTE : L06PB_V_validated_struct_decimal_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_decimal_RE), "d")] public abstract class L06PB_V_validated_struct_decimal_RE { } -public sealed class L06PD_V_validated_struct_decimal_RE : L06PB_V_validated_struct_decimal_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_double_O), "d")] public abstract class L06PB_V_validated_struct_double_O { } -public sealed class L06PD_V_validated_struct_double_O : L06PB_V_validated_struct_double_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_double_RTE), "d")] public abstract class L06PB_V_validated_struct_double_RTE { } -public sealed class L06PD_V_validated_struct_double_RTE : L06PB_V_validated_struct_double_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_double_RE), "d")] public abstract class L06PB_V_validated_struct_double_RE { } -public sealed class L06PD_V_validated_struct_double_RE : L06PB_V_validated_struct_double_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_bool_O), "d")] public abstract class L06PB_V_validated_struct_bool_O { } -public sealed class L06PD_V_validated_struct_bool_O : L06PB_V_validated_struct_bool_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_bool_RTE), "d")] public abstract class L06PB_V_validated_struct_bool_RTE { } -public sealed class L06PD_V_validated_struct_bool_RTE : L06PB_V_validated_struct_bool_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_bool_RE), "d")] public abstract class L06PB_V_validated_struct_bool_RE { } -public sealed class L06PD_V_validated_struct_bool_RE : L06PB_V_validated_struct_bool_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_char_O), "d")] public abstract class L06PB_V_validated_struct_char_O { } -public sealed class L06PD_V_validated_struct_char_O : L06PB_V_validated_struct_char_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_char_RTE), "d")] public abstract class L06PB_V_validated_struct_char_RTE { } -public sealed class L06PD_V_validated_struct_char_RTE : L06PB_V_validated_struct_char_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_char_RE), "d")] public abstract class L06PB_V_validated_struct_char_RE { } -public sealed class L06PD_V_validated_struct_char_RE : L06PB_V_validated_struct_char_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateTime_O), "d")] public abstract class L06PB_V_validated_struct_DateTime_O { } -public sealed class L06PD_V_validated_struct_DateTime_O : L06PB_V_validated_struct_DateTime_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateTime_RTE), "d")] public abstract class L06PB_V_validated_struct_DateTime_RTE { } -public sealed class L06PD_V_validated_struct_DateTime_RTE : L06PB_V_validated_struct_DateTime_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateTime_RE), "d")] public abstract class L06PB_V_validated_struct_DateTime_RE { } -public sealed class L06PD_V_validated_struct_DateTime_RE : L06PB_V_validated_struct_DateTime_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateTimeOffset_O), "d")] public abstract class L06PB_V_validated_struct_DateTimeOffset_O { } -public sealed class L06PD_V_validated_struct_DateTimeOffset_O : L06PB_V_validated_struct_DateTimeOffset_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateTimeOffset_RTE), "d")] public abstract class L06PB_V_validated_struct_DateTimeOffset_RTE { } -public sealed class L06PD_V_validated_struct_DateTimeOffset_RTE : L06PB_V_validated_struct_DateTimeOffset_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateTimeOffset_RE), "d")] public abstract class L06PB_V_validated_struct_DateTimeOffset_RE { } -public sealed class L06PD_V_validated_struct_DateTimeOffset_RE : L06PB_V_validated_struct_DateTimeOffset_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateOnly_O), "d")] public abstract class L06PB_V_validated_struct_DateOnly_O { } -public sealed class L06PD_V_validated_struct_DateOnly_O : L06PB_V_validated_struct_DateOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateOnly_RTE), "d")] public abstract class L06PB_V_validated_struct_DateOnly_RTE { } -public sealed class L06PD_V_validated_struct_DateOnly_RTE : L06PB_V_validated_struct_DateOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_DateOnly_RE), "d")] public abstract class L06PB_V_validated_struct_DateOnly_RE { } -public sealed class L06PD_V_validated_struct_DateOnly_RE : L06PB_V_validated_struct_DateOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_TimeOnly_O), "d")] public abstract class L06PB_V_validated_struct_TimeOnly_O { } -public sealed class L06PD_V_validated_struct_TimeOnly_O : L06PB_V_validated_struct_TimeOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_TimeOnly_RTE), "d")] public abstract class L06PB_V_validated_struct_TimeOnly_RTE { } -public sealed class L06PD_V_validated_struct_TimeOnly_RTE : L06PB_V_validated_struct_TimeOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_TimeOnly_RE), "d")] public abstract class L06PB_V_validated_struct_TimeOnly_RE { } -public sealed class L06PD_V_validated_struct_TimeOnly_RE : L06PB_V_validated_struct_TimeOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_TimeSpan_O), "d")] public abstract class L06PB_V_validated_struct_TimeSpan_O { } -public sealed class L06PD_V_validated_struct_TimeSpan_O : L06PB_V_validated_struct_TimeSpan_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_TimeSpan_RTE), "d")] public abstract class L06PB_V_validated_struct_TimeSpan_RTE { } -public sealed class L06PD_V_validated_struct_TimeSpan_RTE : L06PB_V_validated_struct_TimeSpan_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_TimeSpan_RE), "d")] public abstract class L06PB_V_validated_struct_TimeSpan_RE { } -public sealed class L06PD_V_validated_struct_TimeSpan_RE : L06PB_V_validated_struct_TimeSpan_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_enum_O), "d")] public abstract class L06PB_V_validated_struct_enum_O { } -public sealed class L06PD_V_validated_struct_enum_O : L06PB_V_validated_struct_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_enum_RTE), "d")] public abstract class L06PB_V_validated_struct_enum_RTE { } -public sealed class L06PD_V_validated_struct_enum_RTE : L06PB_V_validated_struct_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_enum_RE), "d")] public abstract class L06PB_V_validated_struct_enum_RE { } -public sealed class L06PD_V_validated_struct_enum_RE : L06PB_V_validated_struct_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_flags_enum_O), "d")] public abstract class L06PB_V_validated_struct_flags_enum_O { } -public sealed class L06PD_V_validated_struct_flags_enum_O : L06PB_V_validated_struct_flags_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_flags_enum_RTE), "d")] public abstract class L06PB_V_validated_struct_flags_enum_RTE { } -public sealed class L06PD_V_validated_struct_flags_enum_RTE : L06PB_V_validated_struct_flags_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_flags_enum_RE), "d")] public abstract class L06PB_V_validated_struct_flags_enum_RE { } -public sealed class L06PD_V_validated_struct_flags_enum_RE : L06PB_V_validated_struct_flags_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_Uri_O), "d")] public abstract class L06PB_V_validated_struct_Uri_O { } -public sealed class L06PD_V_validated_struct_Uri_O : L06PB_V_validated_struct_Uri_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_Uri_RTE), "d")] public abstract class L06PB_V_validated_struct_Uri_RTE { } -public sealed class L06PD_V_validated_struct_Uri_RTE : L06PB_V_validated_struct_Uri_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_Uri_RE), "d")] public abstract class L06PB_V_validated_struct_Uri_RE { } -public sealed class L06PD_V_validated_struct_Uri_RE : L06PB_V_validated_struct_Uri_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_NodaTime_Instant_O), "d")] public abstract class L06PB_V_validated_struct_NodaTime_Instant_O { } -public sealed class L06PD_V_validated_struct_NodaTime_Instant_O : L06PB_V_validated_struct_NodaTime_Instant_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_NodaTime_Instant_RTE), "d")] public abstract class L06PB_V_validated_struct_NodaTime_Instant_RTE { } -public sealed class L06PD_V_validated_struct_NodaTime_Instant_RTE : L06PB_V_validated_struct_NodaTime_Instant_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_NodaTime_Instant_RE), "d")] public abstract class L06PB_V_validated_struct_NodaTime_Instant_RE { } -public sealed class L06PD_V_validated_struct_NodaTime_Instant_RE : L06PB_V_validated_struct_NodaTime_Instant_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_own_record_class_O), "d")] public abstract class L06PB_V_validated_struct_own_record_class_O { } -public sealed class L06PD_V_validated_struct_own_record_class_O : L06PB_V_validated_struct_own_record_class_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_own_record_class_RTE), "d")] public abstract class L06PB_V_validated_struct_own_record_class_RTE { } -public sealed class L06PD_V_validated_struct_own_record_class_RTE : L06PB_V_validated_struct_own_record_class_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_struct_own_record_class_RE), "d")] public abstract class L06PB_V_validated_struct_own_record_class_RE { } -public sealed class L06PD_V_validated_struct_own_record_class_RE : L06PB_V_validated_struct_own_record_class_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_string_O), "d")] public abstract class L06PB_V_validated_class_string_O { } -public sealed class L06PD_V_validated_class_string_O : L06PB_V_validated_class_string_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_string_RTE), "d")] public abstract class L06PB_V_validated_class_string_RTE { } -public sealed class L06PD_V_validated_class_string_RTE : L06PB_V_validated_class_string_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_string_RE), "d")] public abstract class L06PB_V_validated_class_string_RE { } -public sealed class L06PD_V_validated_class_string_RE : L06PB_V_validated_class_string_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_Guid_O), "d")] public abstract class L06PB_V_validated_class_Guid_O { } -public sealed class L06PD_V_validated_class_Guid_O : L06PB_V_validated_class_Guid_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_Guid_RTE), "d")] public abstract class L06PB_V_validated_class_Guid_RTE { } -public sealed class L06PD_V_validated_class_Guid_RTE : L06PB_V_validated_class_Guid_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_Guid_RE), "d")] public abstract class L06PB_V_validated_class_Guid_RE { } -public sealed class L06PD_V_validated_class_Guid_RE : L06PB_V_validated_class_Guid_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_int_O), "d")] public abstract class L06PB_V_validated_class_int_O { } -public sealed class L06PD_V_validated_class_int_O : L06PB_V_validated_class_int_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_int_RTE), "d")] public abstract class L06PB_V_validated_class_int_RTE { } -public sealed class L06PD_V_validated_class_int_RTE : L06PB_V_validated_class_int_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_int_RE), "d")] public abstract class L06PB_V_validated_class_int_RE { } -public sealed class L06PD_V_validated_class_int_RE : L06PB_V_validated_class_int_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_long_O), "d")] public abstract class L06PB_V_validated_class_long_O { } -public sealed class L06PD_V_validated_class_long_O : L06PB_V_validated_class_long_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_long_RTE), "d")] public abstract class L06PB_V_validated_class_long_RTE { } -public sealed class L06PD_V_validated_class_long_RTE : L06PB_V_validated_class_long_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_long_RE), "d")] public abstract class L06PB_V_validated_class_long_RE { } -public sealed class L06PD_V_validated_class_long_RE : L06PB_V_validated_class_long_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_byte_O), "d")] public abstract class L06PB_V_validated_class_byte_O { } -public sealed class L06PD_V_validated_class_byte_O : L06PB_V_validated_class_byte_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_byte_RTE), "d")] public abstract class L06PB_V_validated_class_byte_RTE { } -public sealed class L06PD_V_validated_class_byte_RTE : L06PB_V_validated_class_byte_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_byte_RE), "d")] public abstract class L06PB_V_validated_class_byte_RE { } -public sealed class L06PD_V_validated_class_byte_RE : L06PB_V_validated_class_byte_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_ulong_O), "d")] public abstract class L06PB_V_validated_class_ulong_O { } -public sealed class L06PD_V_validated_class_ulong_O : L06PB_V_validated_class_ulong_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_ulong_RTE), "d")] public abstract class L06PB_V_validated_class_ulong_RTE { } -public sealed class L06PD_V_validated_class_ulong_RTE : L06PB_V_validated_class_ulong_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_ulong_RE), "d")] public abstract class L06PB_V_validated_class_ulong_RE { } -public sealed class L06PD_V_validated_class_ulong_RE : L06PB_V_validated_class_ulong_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_decimal_O), "d")] public abstract class L06PB_V_validated_class_decimal_O { } -public sealed class L06PD_V_validated_class_decimal_O : L06PB_V_validated_class_decimal_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_decimal_RTE), "d")] public abstract class L06PB_V_validated_class_decimal_RTE { } -public sealed class L06PD_V_validated_class_decimal_RTE : L06PB_V_validated_class_decimal_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_decimal_RE), "d")] public abstract class L06PB_V_validated_class_decimal_RE { } -public sealed class L06PD_V_validated_class_decimal_RE : L06PB_V_validated_class_decimal_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_double_O), "d")] public abstract class L06PB_V_validated_class_double_O { } -public sealed class L06PD_V_validated_class_double_O : L06PB_V_validated_class_double_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_double_RTE), "d")] public abstract class L06PB_V_validated_class_double_RTE { } -public sealed class L06PD_V_validated_class_double_RTE : L06PB_V_validated_class_double_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_double_RE), "d")] public abstract class L06PB_V_validated_class_double_RE { } -public sealed class L06PD_V_validated_class_double_RE : L06PB_V_validated_class_double_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_bool_O), "d")] public abstract class L06PB_V_validated_class_bool_O { } -public sealed class L06PD_V_validated_class_bool_O : L06PB_V_validated_class_bool_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_bool_RTE), "d")] public abstract class L06PB_V_validated_class_bool_RTE { } -public sealed class L06PD_V_validated_class_bool_RTE : L06PB_V_validated_class_bool_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_bool_RE), "d")] public abstract class L06PB_V_validated_class_bool_RE { } -public sealed class L06PD_V_validated_class_bool_RE : L06PB_V_validated_class_bool_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_char_O), "d")] public abstract class L06PB_V_validated_class_char_O { } -public sealed class L06PD_V_validated_class_char_O : L06PB_V_validated_class_char_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_char_RTE), "d")] public abstract class L06PB_V_validated_class_char_RTE { } -public sealed class L06PD_V_validated_class_char_RTE : L06PB_V_validated_class_char_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_char_RE), "d")] public abstract class L06PB_V_validated_class_char_RE { } -public sealed class L06PD_V_validated_class_char_RE : L06PB_V_validated_class_char_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateTime_O), "d")] public abstract class L06PB_V_validated_class_DateTime_O { } -public sealed class L06PD_V_validated_class_DateTime_O : L06PB_V_validated_class_DateTime_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateTime_RTE), "d")] public abstract class L06PB_V_validated_class_DateTime_RTE { } -public sealed class L06PD_V_validated_class_DateTime_RTE : L06PB_V_validated_class_DateTime_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateTime_RE), "d")] public abstract class L06PB_V_validated_class_DateTime_RE { } -public sealed class L06PD_V_validated_class_DateTime_RE : L06PB_V_validated_class_DateTime_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateTimeOffset_O), "d")] public abstract class L06PB_V_validated_class_DateTimeOffset_O { } -public sealed class L06PD_V_validated_class_DateTimeOffset_O : L06PB_V_validated_class_DateTimeOffset_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateTimeOffset_RTE), "d")] public abstract class L06PB_V_validated_class_DateTimeOffset_RTE { } -public sealed class L06PD_V_validated_class_DateTimeOffset_RTE : L06PB_V_validated_class_DateTimeOffset_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateTimeOffset_RE), "d")] public abstract class L06PB_V_validated_class_DateTimeOffset_RE { } -public sealed class L06PD_V_validated_class_DateTimeOffset_RE : L06PB_V_validated_class_DateTimeOffset_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateOnly_O), "d")] public abstract class L06PB_V_validated_class_DateOnly_O { } -public sealed class L06PD_V_validated_class_DateOnly_O : L06PB_V_validated_class_DateOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateOnly_RTE), "d")] public abstract class L06PB_V_validated_class_DateOnly_RTE { } -public sealed class L06PD_V_validated_class_DateOnly_RTE : L06PB_V_validated_class_DateOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_DateOnly_RE), "d")] public abstract class L06PB_V_validated_class_DateOnly_RE { } -public sealed class L06PD_V_validated_class_DateOnly_RE : L06PB_V_validated_class_DateOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_TimeOnly_O), "d")] public abstract class L06PB_V_validated_class_TimeOnly_O { } -public sealed class L06PD_V_validated_class_TimeOnly_O : L06PB_V_validated_class_TimeOnly_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_TimeOnly_RTE), "d")] public abstract class L06PB_V_validated_class_TimeOnly_RTE { } -public sealed class L06PD_V_validated_class_TimeOnly_RTE : L06PB_V_validated_class_TimeOnly_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_TimeOnly_RE), "d")] public abstract class L06PB_V_validated_class_TimeOnly_RE { } -public sealed class L06PD_V_validated_class_TimeOnly_RE : L06PB_V_validated_class_TimeOnly_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_TimeSpan_O), "d")] public abstract class L06PB_V_validated_class_TimeSpan_O { } -public sealed class L06PD_V_validated_class_TimeSpan_O : L06PB_V_validated_class_TimeSpan_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_TimeSpan_RTE), "d")] public abstract class L06PB_V_validated_class_TimeSpan_RTE { } -public sealed class L06PD_V_validated_class_TimeSpan_RTE : L06PB_V_validated_class_TimeSpan_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_TimeSpan_RE), "d")] public abstract class L06PB_V_validated_class_TimeSpan_RE { } -public sealed class L06PD_V_validated_class_TimeSpan_RE : L06PB_V_validated_class_TimeSpan_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_enum_O), "d")] public abstract class L06PB_V_validated_class_enum_O { } -public sealed class L06PD_V_validated_class_enum_O : L06PB_V_validated_class_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_enum_RTE), "d")] public abstract class L06PB_V_validated_class_enum_RTE { } -public sealed class L06PD_V_validated_class_enum_RTE : L06PB_V_validated_class_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_enum_RE), "d")] public abstract class L06PB_V_validated_class_enum_RE { } -public sealed class L06PD_V_validated_class_enum_RE : L06PB_V_validated_class_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_flags_enum_O), "d")] public abstract class L06PB_V_validated_class_flags_enum_O { } -public sealed class L06PD_V_validated_class_flags_enum_O : L06PB_V_validated_class_flags_enum_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_flags_enum_RTE), "d")] public abstract class L06PB_V_validated_class_flags_enum_RTE { } -public sealed class L06PD_V_validated_class_flags_enum_RTE : L06PB_V_validated_class_flags_enum_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_flags_enum_RE), "d")] public abstract class L06PB_V_validated_class_flags_enum_RE { } -public sealed class L06PD_V_validated_class_flags_enum_RE : L06PB_V_validated_class_flags_enum_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_Uri_O), "d")] public abstract class L06PB_V_validated_class_Uri_O { } -public sealed class L06PD_V_validated_class_Uri_O : L06PB_V_validated_class_Uri_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_Uri_RTE), "d")] public abstract class L06PB_V_validated_class_Uri_RTE { } -public sealed class L06PD_V_validated_class_Uri_RTE : L06PB_V_validated_class_Uri_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_Uri_RE), "d")] public abstract class L06PB_V_validated_class_Uri_RE { } -public sealed class L06PD_V_validated_class_Uri_RE : L06PB_V_validated_class_Uri_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_NodaTime_Instant_O), "d")] public abstract class L06PB_V_validated_class_NodaTime_Instant_O { } -public sealed class L06PD_V_validated_class_NodaTime_Instant_O : L06PB_V_validated_class_NodaTime_Instant_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_NodaTime_Instant_RTE), "d")] public abstract class L06PB_V_validated_class_NodaTime_Instant_RTE { } -public sealed class L06PD_V_validated_class_NodaTime_Instant_RTE : L06PB_V_validated_class_NodaTime_Instant_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_NodaTime_Instant_RE), "d")] public abstract class L06PB_V_validated_class_NodaTime_Instant_RE { } -public sealed class L06PD_V_validated_class_NodaTime_Instant_RE : L06PB_V_validated_class_NodaTime_Instant_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_own_record_class_O), "d")] public abstract class L06PB_V_validated_class_own_record_class_O { } -public sealed class L06PD_V_validated_class_own_record_class_O : L06PB_V_validated_class_own_record_class_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_own_record_class_RTE), "d")] public abstract class L06PB_V_validated_class_own_record_class_RTE { } -public sealed class L06PD_V_validated_class_own_record_class_RTE : L06PB_V_validated_class_own_record_class_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_V_validated_class_own_record_class_RE), "d")] public abstract class L06PB_V_validated_class_own_record_class_RE { } -public sealed class L06PD_V_validated_class_own_record_class_RE : L06PB_V_validated_class_own_record_class_RE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_PSet_O), "d")] public abstract class L06PB_PSet_O { } -public sealed class L06PD_PSet_O : L06PB_PSet_O { public Option Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_PSet_RTE), "d")] public abstract class L06PB_PSet_RTE { } -public sealed class L06PD_PSet_RTE : L06PB_PSet_RTE { public Result Value { get; set; } } -[System.Text.Json.Serialization.JsonPolymorphic] [System.Text.Json.Serialization.JsonDerivedType(typeof(L06PD_PSet_RE), "d")] public abstract class L06PB_PSet_RE { } -public sealed class L06PD_PSet_RE : L06PB_PSet_RE { public Result Value { get; set; } } diff --git a/tools/probe/corpus/harness/JsonRow.cs b/tools/probe/corpus/harness/JsonRow.cs deleted file mode 100644 index f39be575..00000000 --- a/tools/probe/corpus/harness/JsonRow.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Applies a row's json.* axes to JsonSerializerOptions (reflection for every plain bool/enum setting, hand-listed values by name). -using System.Reflection; -using System.Text.Encodings.Web; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; -using CodoMetis.TypeKit.ValueObjects; -using NodaTime; -using NodaTime.Serialization.SystemTextJson; -namespace Probes.Shapes; - -public sealed class UpperPolicy : JsonNamingPolicy { public override string ConvertName(string name) => name.ToUpperInvariant(); } - -public static class Make -{ - /// - /// The type a nullable one holds: under http.nullability=nullable an entry's Vo and Plain are T?, the types the - /// endpoints declare, while the value object is still made by From(T) and read through its Value. - /// - public static Type Held(Type t) => Nullable.GetUnderlyingType(t) ?? t; - /// Whether a type admits null: a class, or a struct made nullable. A value object and its twin admit it alike (Equivalence). - public static bool AdmitsNull(Type t) => !t.IsValueType || Nullable.GetUnderlyingType(t) is not null; - - /// Creates the value object over a plain sample (From / FromKnownGood), with optional parameters filled. - public static object Vo(Entry e, object plain) - { - if (e.Kind == "closed-set") return PSet.All.First(x => x.Name == (string)plain); - var m = Held(e.Vo).GetMethods(BindingFlags.Public | BindingFlags.Static) - .First(x => (x.Name is "FromKnownGood" or "From") && x.GetParameters().Length > 0 && x.GetParameters()[0].ParameterType == Held(e.Plain)); - var args = m.GetParameters().Select((p, i) => i == 0 ? plain : Type.Missing).ToArray(); - return m.Invoke(null, BindingFlags.OptionalParamBinding | BindingFlags.Default, null, args, null)!; - } - public static object Unwrap(Entry e, object vo) => e.Kind == "closed-set" ? ((PSet)vo).Name : Held(e.Vo).GetProperty("Value")!.GetValue(vo)!; -} - -/// A converter an application registers for the wrapped type: writes "own:" + the default JSON. -public sealed class OwnWrappedConverter(JsonSerializerOptions inner) : JsonConverter -{ - public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var s = reader.GetString() ?? throw new JsonException("null"); - if (!s.StartsWith("own:")) throw new JsonException("not own"); - return JsonSerializer.Deserialize(s[4..], inner); - } - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => writer.WriteStringValue("own:" + JsonSerializer.Serialize(value, inner)); - public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Read(ref reader, typeToConvert, options)!; - public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => writer.WritePropertyName("own:" + JsonSerializer.Serialize(value, inner)); -} - -/// A converter an application registers for the value object itself: writes "vo:" + the wrapped value's default JSON. -public sealed class OwnVoFactory(Entry e, JsonSerializerOptions inner) : JsonConverterFactory -{ - public override bool CanConvert(Type t) => t == Make.Held(e.Vo); // System.Text.Json asks for T, never for T? - public override JsonConverter? CreateConverter(Type t, JsonSerializerOptions options) => - (JsonConverter)Activator.CreateInstance(typeof(OwnVo<>).MakeGenericType(t), e, inner)!; -} -public sealed class OwnVo(Entry e, JsonSerializerOptions inner) : JsonConverter -{ - public override V? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - var s = reader.GetString() ?? throw new JsonException("null"); - if (!s.StartsWith("vo:")) throw new JsonException("not vo"); - return (V)Make.Vo(e, JsonSerializer.Deserialize(s[3..], Make.Held(e.Plain), inner)!); - } - public override void Write(Utf8JsonWriter writer, V value, JsonSerializerOptions options) => - writer.WriteStringValue("vo:" + JsonSerializer.Serialize(Make.Unwrap(e, value!), Make.Held(e.Plain), inner)); - public override V ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Read(ref reader, typeToConvert, options)!; - public override void WriteAsPropertyName(Utf8JsonWriter writer, V value, JsonSerializerOptions options) => - writer.WritePropertyName("vo:" + JsonSerializer.Serialize(Make.Unwrap(e, value!), Make.Held(e.Plain), inner)); -} - -public sealed record Applied(JsonSerializerOptions? Options, string? Refused); - -public static class JsonRow -{ - public static JsonSerializerOptions Inner(Entry e) - { - var o = new JsonSerializerOptions(); - if (e.Wrapped == "NodaTime.Instant") o.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); - return o; - } - - /// Applies every json.* axis of the row to (or a new instance). Refused = STJ rejected a combination with an exception of its own (a pass). - public static Applied Apply(Row r, Entry e, JsonSerializerOptions? into = null) - { - var o = into ?? new JsonSerializerOptions(); - var dropped = new List(); - if (e.Wrapped == "NodaTime.Instant") o.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); - if (r.Get("json.PreferredObjectCreationHandling") == "Populate" && r.Get("json.ReferenceHandler") is not (null or "default")) - { - dropped.Add("json.PreferredObjectCreationHandling=Populate (STJ: incompatible with reference handling)"); - r.Substituted("json.PreferredObjectCreationHandling", "default", "STJ: incompatible with reference handling"); - r = r.With("json.PreferredObjectCreationHandling", "default"); - } - // resolver before chain: a chain on top of a resolver is a combination STJ may refuse - foreach (var kv in r.All.Where(kv => kv.Key.StartsWith("json.") && kv.Value != "default").OrderBy(kv => kv.Key == "json.TypeInfoResolverChain" ? 1 : 0)) - { - try { Set(r, o, kv.Key[5..], kv.Value, e); } - catch (Exception ex) when (ex is ArgumentException or InvalidOperationException or NotSupportedException) - { - // STJ refuses this setting with an exception of its own: a pass for the pairs of that value; the rest of the row is still probed - dropped.Add($"{kv.Key}={kv.Value} ({ex.GetType().Name})"); - r.Substituted(kv.Key, "default", "STJ refused it: " + ex.GetType().Name); - } - } - r.Note(NoteKeys.Dropped, string.Join(",", dropped)); - return new(o, dropped.Count == 0 ? null : string.Join(",", dropped)); - } - - static JsonNamingPolicy? Policy(string v) => v switch - { - "CamelCase" => JsonNamingPolicy.CamelCase, "SnakeCaseLower" => JsonNamingPolicy.SnakeCaseLower, "SnakeCaseUpper" => JsonNamingPolicy.SnakeCaseUpper, - "KebabCaseLower" => JsonNamingPolicy.KebabCaseLower, "KebabCaseUpper" => JsonNamingPolicy.KebabCaseUpper, "own-upper-case" => new UpperPolicy(), - _ => throw new ArgumentException("unknown policy " + v) - }; - - /// - /// json.TypeInfoResolver=source-generated-context is strict: the options resolve through ProbeContext alone, which lists every shape a row - /// holds and its twin (shapes.cs), with no reflection behind it; json.TypeInfoResolverChain=context-then-default is the configuration with - /// the reflection fallback, the context then reflection, beside it or on its own. A row's shape the context does not list is the generator's gap, a harness error: the serializer's refusal of - /// an unlisted type would read as the framework's. - /// - static void Listed(Row r, Entry e) - { - var plain = e.Valid(); var vo = Make.Vo(e, plain); - var pos = r["shape.position"]; var con = (r.Get("shape.containing") ?? "class"); - var (hp, hv) = Sides.Twins(pos, con, e, plain, vo); - var missing = Missing(hp.Declared, hv.Declared).Select(t => t.ToString()).ToList(); - if (missing.Count > 0) { r.Outcome("harness-error", $"ProbeContext does not list {string.Join(", ", missing)}: run tools/probe/generators/shapes.cs"); return; } - r.Note(NoteKeys.CtxStrict); - } - - /// The ProbeContext does not list, under json.TypeInfoResolver=source-generated-context: the generator's gap, which the caller reports as a harness error. - public static IEnumerable Unlisted(Row r, params Type[] shapes) => - r.Is("json.TypeInfoResolver", "source-generated-context") ? Missing(shapes) : []; - - /// - /// The types ProbeContext has no metadata for, asked through the resolver's interface, which builds no contract: building one is the - /// serializer's step, where a context refuses an Option or Result made nullable (L06's not-promised entry), not the listing's. - /// - static IEnumerable Missing(params Type[] shapes) - { - // the context answers what a type's metadata asks the options for (the struct a Nullable holds) too - var probe = new JsonSerializerOptions { TypeInfoResolver = ProbeContext.Default }; - return shapes.Where(t => ((IJsonTypeInfoResolver)ProbeContext.Default).GetTypeInfo(t, probe) is null).ToList(); - } - - static void Set(Row row, JsonSerializerOptions o, string name, string v, Entry e) - { - switch (name) - { - case "PropertyNamingPolicy": o.PropertyNamingPolicy = Policy(v); return; - case "DictionaryKeyPolicy": o.DictionaryKeyPolicy = Policy(v); return; - case "ReferenceHandler": o.ReferenceHandler = v == "Preserve" ? ReferenceHandler.Preserve : ReferenceHandler.IgnoreCycles; return; - case "Encoder": o.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; return; - case "MaxDepth": o.MaxDepth = int.Parse(v); return; - case "Converters": - switch (v) - { - case "own-for-wrapped": o.Converters.Insert(0, (JsonConverter)Activator.CreateInstance(typeof(OwnWrappedConverter<>).MakeGenericType(Make.Held(e.Plain)), Inner(e))!); break; - case "own-for-value-object": o.Converters.Insert(0, new OwnVoFactory(e, Inner(e))); break; - case "JsonStringEnumConverter": o.Converters.Add(new JsonStringEnumConverter()); break; - case "StoredJsonConverterFactory": o.Converters.Add(new StoredJsonConverterFactory()); break; - default: throw new ArgumentException("unknown converter " + v); - } - return; - case "TypeInfoResolver": - if (v == "source-generated-context") { o.TypeInfoResolver = ProbeContext.Default; Listed(row, e); } - else o.TypeInfoResolver = new DefaultJsonTypeInfoResolver { Modifiers = { ti => { foreach (var p in ti.Properties) p.Name += "_x"; } } }; - return; - case "TypeInfoResolverChain": - // The context, then reflection for what it does not list: under json.TypeInfoResolver=source-generated-context the chain - // already starts with the context, which System.Text.Json refuses to insert a second time (the resolver into its own - // chain), so the reflection fallback follows it. That pair is the context with the fallback, the strict context's other side. - if (!o.TypeInfoResolverChain.Contains(ProbeContext.Default)) o.TypeInfoResolverChain.Add(ProbeContext.Default); - o.TypeInfoResolverChain.Add(new DefaultJsonTypeInfoResolver()); return; - } - var prop = typeof(JsonSerializerOptions).GetProperty(name) ?? throw new ArgumentException("no json option " + name); - object value = prop.PropertyType == typeof(bool) ? bool.Parse(v) : prop.PropertyType.IsEnum ? Enum.Parse(prop.PropertyType, v) : throw new ArgumentException($"no hand value for {name}"); - try { prop.SetValue(o, value); } - catch (TargetInvocationException ex) { throw ex.InnerException!; } - } -} diff --git a/tools/probe/corpus/harness/KeyShapes.g.cs b/tools/probe/corpus/harness/KeyShapes.g.cs deleted file mode 100644 index 0a98b904..00000000 --- a/tools/probe/corpus/harness/KeyShapes.g.cs +++ /dev/null @@ -1,128 +0,0 @@ -// by tools/probe/generators/ef.cs keys; the EF key probes' shape catalogue (shape.kind x shape.wrapped). Do not edit. -#nullable enable -#pragma warning disable CMTK0014, CS8618, CS1591, CMTK0005, CMTK1000, CMTK0003, CMTK0006, CA1000 -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -using Probes.Shapes; -namespace Probes.Ef; -public readonly partial record struct K_record_struct_Guid : IValue; -public readonly partial record struct K_record_struct_byte : IValue; -public readonly partial record struct K_record_struct_char : IValue; -public readonly partial record struct K_record_struct_int : IValue; -public readonly partial record struct K_record_struct_long : IValue; -public readonly partial record struct K_record_struct_string : IValue; -public readonly partial record struct K_record_struct_ulong : IValue; -public sealed partial record class K_sealed_record_class_Guid : IValue; -public sealed partial record class K_sealed_record_class_byte : IValue; -public sealed partial record class K_sealed_record_class_char : IValue; -public sealed partial record class K_sealed_record_class_int : IValue; -public sealed partial record class K_sealed_record_class_long : IValue; -public sealed partial record class K_sealed_record_class_string : IValue; -public sealed partial record class K_sealed_record_class_ulong : IValue; -public sealed partial record class K_validated_class_Guid : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new K_validated_class_Guid(value); -} -public sealed partial record class K_validated_class_byte : IValidatedValue -{ - public static Result Create(byte value) => - EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new K_validated_class_byte(value); -} -public sealed partial record class K_validated_class_char : IValidatedValue -{ - public static Result Create(char value) => - EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new K_validated_class_char(value); -} -public sealed partial record class K_validated_class_int : IValidatedValue -{ - public static Result Create(int value) => - EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new K_validated_class_int(value); -} -public sealed partial record class K_validated_class_long : IValidatedValue -{ - public static Result Create(long value) => - EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new K_validated_class_long(value); -} -public sealed partial record class K_validated_class_string : IValidatedValue -{ - public static Result Create(string value) => - EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new K_validated_class_string(value); -} -public sealed partial record class K_validated_class_ulong : IValidatedValue -{ - public static Result Create(ulong value) => - EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new K_validated_class_ulong(value); -} -public readonly partial record struct K_validated_struct_Guid : IValidatedValue -{ - public static Result Create(Guid value) => - EqualityComparer.Default.Equals(value, Guid.Empty) ? Result.Error(ShapeFault.Refused) : new K_validated_struct_Guid(value); -} -public readonly partial record struct K_validated_struct_byte : IValidatedValue -{ - public static Result Create(byte value) => - EqualityComparer.Default.Equals(value, (byte)255) ? Result.Error(ShapeFault.Refused) : new K_validated_struct_byte(value); -} -public readonly partial record struct K_validated_struct_char : IValidatedValue -{ - public static Result Create(char value) => - EqualityComparer.Default.Equals(value, 'x') ? Result.Error(ShapeFault.Refused) : new K_validated_struct_char(value); -} -public readonly partial record struct K_validated_struct_int : IValidatedValue -{ - public static Result Create(int value) => - EqualityComparer.Default.Equals(value, -1) ? Result.Error(ShapeFault.Refused) : new K_validated_struct_int(value); -} -public readonly partial record struct K_validated_struct_long : IValidatedValue -{ - public static Result Create(long value) => - EqualityComparer.Default.Equals(value, -1L) ? Result.Error(ShapeFault.Refused) : new K_validated_struct_long(value); -} -public readonly partial record struct K_validated_struct_string : IValidatedValue -{ - public static Result Create(string value) => - EqualityComparer.Default.Equals(value, "SECRET-7f3a") ? Result.Error(ShapeFault.Refused) : new K_validated_struct_string(value); -} -public readonly partial record struct K_validated_struct_ulong : IValidatedValue -{ - public static Result Create(ulong value) => - EqualityComparer.Default.Equals(value, 0UL) ? Result.Error(ShapeFault.Refused) : new K_validated_struct_ulong(value); -} -public static partial class KeyRegistry -{ - public static readonly List All = Build(); - static List Build() { var e = new List(); Fill(e); return e; } - public static EfEntry Of(Probes.Shapes.Row r) { var k = r["shape.kind"]; var w = r["shape.wrapped"]; return All.First(x => x.Kind == k && x.Wrapped == w); } - public static void Fill(List e) - { - e.Add(new EfEntry("record-struct", "Guid", "top-level", typeof(K_record_struct_Guid), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("record-struct", "byte", "top-level", typeof(K_record_struct_byte), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("record-struct", "char", "top-level", typeof(K_record_struct_char), typeof(char), () => 'a')); - e.Add(new EfEntry("record-struct", "int", "top-level", typeof(K_record_struct_int), typeof(int), () => 42)); - e.Add(new EfEntry("record-struct", "long", "top-level", typeof(K_record_struct_long), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("record-struct", "string", "top-level", typeof(K_record_struct_string), typeof(string), () => "alpha")); - e.Add(new EfEntry("record-struct", "ulong", "top-level", typeof(K_record_struct_ulong), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("sealed-record-class", "Guid", "top-level", typeof(K_sealed_record_class_Guid), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("sealed-record-class", "byte", "top-level", typeof(K_sealed_record_class_byte), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("sealed-record-class", "char", "top-level", typeof(K_sealed_record_class_char), typeof(char), () => 'a')); - e.Add(new EfEntry("sealed-record-class", "int", "top-level", typeof(K_sealed_record_class_int), typeof(int), () => 42)); - e.Add(new EfEntry("sealed-record-class", "long", "top-level", typeof(K_sealed_record_class_long), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("sealed-record-class", "string", "top-level", typeof(K_sealed_record_class_string), typeof(string), () => "alpha")); - e.Add(new EfEntry("sealed-record-class", "ulong", "top-level", typeof(K_sealed_record_class_ulong), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("validated-class", "Guid", "top-level", typeof(K_validated_class_Guid), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-class", "byte", "top-level", typeof(K_validated_class_byte), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("validated-class", "char", "top-level", typeof(K_validated_class_char), typeof(char), () => 'a')); - e.Add(new EfEntry("validated-class", "int", "top-level", typeof(K_validated_class_int), typeof(int), () => 42)); - e.Add(new EfEntry("validated-class", "long", "top-level", typeof(K_validated_class_long), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("validated-class", "string", "top-level", typeof(K_validated_class_string), typeof(string), () => "alpha")); - e.Add(new EfEntry("validated-class", "ulong", "top-level", typeof(K_validated_class_ulong), typeof(ulong), () => 4200000000UL)); - e.Add(new EfEntry("validated-struct", "Guid", "top-level", typeof(K_validated_struct_Guid), typeof(Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"))); - e.Add(new EfEntry("validated-struct", "byte", "top-level", typeof(K_validated_struct_byte), typeof(byte), () => (byte)7)); - e.Add(new EfEntry("validated-struct", "char", "top-level", typeof(K_validated_struct_char), typeof(char), () => 'a')); - e.Add(new EfEntry("validated-struct", "int", "top-level", typeof(K_validated_struct_int), typeof(int), () => 42)); - e.Add(new EfEntry("validated-struct", "long", "top-level", typeof(K_validated_struct_long), typeof(long), () => 4200000000L)); - e.Add(new EfEntry("validated-struct", "string", "top-level", typeof(K_validated_struct_string), typeof(string), () => "alpha")); - e.Add(new EfEntry("validated-struct", "ulong", "top-level", typeof(K_validated_struct_ulong), typeof(ulong), () => 4200000000UL)); - } -} diff --git a/tools/probe/corpus/harness/L01JsonBytesProbe.cs b/tools/probe/corpus/harness/L01JsonBytesProbe.cs deleted file mode 100644 index 4eb89c77..00000000 --- a/tools/probe/corpus/harness/L01JsonBytesProbe.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Claim L01-json-bytes (README#what-typekit-guarantees "Swapping a primitive for a value object keeps the JSON"; docs/json.md#the-wrapped-types-json): -// the value object's JSON is the wrapped type's, byte for byte, under whatever options, as value and as key, and each reads the other's JSON. -// Oracle: differential (JsonParity). Expected: no failure for any row; STJ refusing its own option combination, and the documented -// Preserve refusal, are passes. -using Probes.Shapes; -using System.Text.Json; -namespace Probes; -public sealed class L01JsonBytesProbe -{ - public static TheoryData Data() => Rows.Data("L01JsonBytesProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run(probe, idx, async r => - { - var e = Registry.Of(r); - var a = JsonRow.Apply(r, e); - JsonSerializerOptions? plainOpts = null; - if (e.Kind == "closed-set" && r.Is("json.Converters", "own-for-wrapped")) plainOpts = JsonRow.Apply(r.With("json.Converters", "default"), e).Options; // a closed set travels as its name, not as a string - await Task.CompletedTask; - return JsonParity.Check(r, e, a.Options!, r["shape.position"], (r.Get("shape.containing") ?? "class"), r["input.json"], plainOpts); - }); -} diff --git a/tools/probe/corpus/harness/L02NoQuoteProbe.cs b/tools/probe/corpus/harness/L02NoQuoteProbe.cs deleted file mode 100644 index 11f88a8b..00000000 --- a/tools/probe/corpus/harness/L02NoQuoteProbe.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Claim L02-no-quote (README#what-typekit-guarantees; src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting). L02 (exception): a rejection never repeats the input. -// Expected: no failure for any row; the documented differences (lossy default text of TimeOnly/DateTime/DateTimeOffset, a registered converter, StoredJsonConverterFactory) are passes. -using Probes.Shapes; -namespace Probes; -public sealed class L02NoQuoteProbe -{ - public static TheoryData Data() => Rows.Data("L02NoQuoteProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run(probe, idx, r => Task.FromResult(TextClaims.NoQuote(r, Registry.Of(r)))); -} diff --git a/tools/probe/corpus/harness/L03OneRuleProbe.cs b/tools/probe/corpus/harness/L03OneRuleProbe.cs deleted file mode 100644 index e8e1fd24..00000000 --- a/tools/probe/corpus/harness/L03OneRuleProbe.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Claim L03-one-rule (README#what-typekit-guarantees; src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting). L03 (claim): every entry runs Create and names its fault. -// Expected: no failure for any row; the documented differences (lossy default text of TimeOnly/DateTime/DateTimeOffset, a registered converter, StoredJsonConverterFactory) are passes. -using Probes.Shapes; -namespace Probes; -public sealed class L03OneRuleProbe -{ - public static TheoryData Data() => Rows.Data("L03OneRuleProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run(probe, idx, r => Task.FromResult(TextClaims.OneRule(r, Registry.Of(r)))); -} diff --git a/tools/probe/corpus/harness/L04RoundTripProbe.cs b/tools/probe/corpus/harness/L04RoundTripProbe.cs deleted file mode 100644 index 2ae7ad0c..00000000 --- a/tools/probe/corpus/harness/L04RoundTripProbe.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Claim L04-round-trip (README#what-typekit-guarantees; src/CodoMetis.TypeKit.Generators/README.md#parsing-and-formatting). L04 round trip (metamorphic): VO text/JSON written by the project reads back as the same value. -// Expected: no failure for any row; the documented differences (lossy default text of TimeOnly/DateTime/DateTimeOffset, a registered converter, StoredJsonConverterFactory) are passes. -using Probes.Shapes; -namespace Probes; -public sealed class L04RoundTripProbe -{ - public static TheoryData Data() => Rows.Data("L04RoundTripProbe"); - [Theory, MemberData(nameof(Data))] - public Task Row(string probe, int idx) => Rec.Run(probe, idx, r => Task.FromResult(TextClaims.RoundTrip(r, Registry.Of(r)))); -} diff --git a/tools/probe/corpus/harness/L05Shapes.g.cs b/tools/probe/corpus/harness/L05Shapes.g.cs deleted file mode 100644 index f3f576ad..00000000 --- a/tools/probe/corpus/harness/L05Shapes.g.cs +++ /dev/null @@ -1,575 +0,0 @@ -// by tools/probe/generators/json-family.cs from the rows of L05-equality. Do not edit. -#nullable enable -#pragma warning disable CS1591, CMTK0005, CMTK1023 // CMTK1023: a base record with an explicit IEquatable is the shape under test -using CodoMetis.TypeKit; -using CodoMetis.TypeKit.ValueObjects; -using CodoMetis.TypeKit.ClosedSets; -using Probes.Shapes; -namespace Probes.Json; - -public interface IL05Tag { string Tag { get; } } -public abstract record L05B1; -public abstract record L05B2a; -public abstract record L05B2b : L05B2a; -public abstract record L05B3a; -public abstract record L05B3b : L05B3a; -public abstract record L05B3c : L05B3b; -// a deeper base whose own IEquatable says "never equal": the value object must not use it -public abstract record L05E0 : IEquatable { bool IEquatable.Equals(L05E0? other) => false; } -public abstract record L05E1 : L05E0; -public abstract class L05CB1; -public abstract class L05CB2a; -public abstract class L05CB2b : L05CB2a; -public abstract class L05CB3a; -public abstract class L05CB3b : L05CB3a; -public abstract class L05CB3c : L05CB3b; -public abstract class L05CE0 : IEquatable { bool IEquatable.Equals(L05CE0? other) => ReferenceEquals(this, other); } -public abstract class L05CE1 : L05CE0; - -public partial class L05Oc0 { public sealed partial class L05_0_closed_set__ : L05CB1, IClosedSet { public static readonly L05_0_closed_set__ Alpha = new(); public static readonly L05_0_closed_set__ Beta = new(); } } -public partial class L05Ot1 { public partial class Inner { public sealed partial class L05_1_closed_set__ : L05CB1, IClosedSet { public static readonly L05_1_closed_set__ Alpha = new(); public static readonly L05_1_closed_set__ Beta = new(); } } } -public partial class L05Oc2 { public sealed partial class L05_2_closed_set__ : L05CB2b, IClosedSet { public static readonly L05_2_closed_set__ Alpha = new(); public static readonly L05_2_closed_set__ Beta = new(); } } -public partial struct L05Os3 { public sealed partial class L05_3_closed_set__ : L05CB2b, IClosedSet { public static readonly L05_3_closed_set__ Alpha = new(); public static readonly L05_3_closed_set__ Beta = new(); } } -public sealed partial class L05_4_closed_set__ : L05CB2b, IClosedSet { public static readonly L05_4_closed_set__ Alpha = new(); public static readonly L05_4_closed_set__ Beta = new(); } -public partial class L05Oc5 { public sealed partial class L05_5_closed_set__ : L05CB3c, IClosedSet { public static readonly L05_5_closed_set__ Alpha = new(); public static readonly L05_5_closed_set__ Beta = new(); } } -public partial struct L05Os6 { public sealed partial class L05_6_closed_set__ : L05CB3c, IClosedSet { public static readonly L05_6_closed_set__ Alpha = new(); public static readonly L05_6_closed_set__ Beta = new(); } } -public partial class L05Ot7 { public partial class Inner { public sealed partial class L05_7_closed_set__ : L05CB3c, IClosedSet { public static readonly L05_7_closed_set__ Alpha = new(); public static readonly L05_7_closed_set__ Beta = new(); } } } -public sealed partial class L05_8_closed_set__ : L05CB3c, IClosedSet { public static readonly L05_8_closed_set__ Alpha = new(); public static readonly L05_8_closed_set__ Beta = new(); } -public partial class L05Oc9 { public sealed partial class L05_9_closed_set__ : L05CE1, IClosedSet { public static readonly L05_9_closed_set__ Alpha = new(); public static readonly L05_9_closed_set__ Beta = new(); } } -public partial struct L05Os10 { public sealed partial class L05_10_closed_set__ : L05CE1, IClosedSet { public static readonly L05_10_closed_set__ Alpha = new(); public static readonly L05_10_closed_set__ Beta = new(); } } -public partial class L05Ot11 { public partial class Inner { public sealed partial class L05_11_closed_set__ : L05CE1, IClosedSet { public static readonly L05_11_closed_set__ Alpha = new(); public static readonly L05_11_closed_set__ Beta = new(); } } } -public sealed partial class L05_12_closed_set__ : L05CE1, IClosedSet { public static readonly L05_12_closed_set__ Alpha = new(); public static readonly L05_12_closed_set__ Beta = new(); } -public partial class L05Oc13 { public sealed partial class L05_13_closed_set__ : IL05Tag, IClosedSet { public static readonly L05_13_closed_set__ Alpha = new(); public static readonly L05_13_closed_set__ Beta = new(); string IL05Tag.Tag => "t"; } } -public sealed partial class L05_14_closed_set__ : IL05Tag, IClosedSet { public static readonly L05_14_closed_set__ Alpha = new(); public static readonly L05_14_closed_set__ Beta = new(); string IL05Tag.Tag => "t"; } -public partial struct L05Os15 { public sealed partial class L05_15_closed_set__ : IClosedSet { public static readonly L05_15_closed_set__ Alpha = new(); public static readonly L05_15_closed_set__ Beta = new(); } } -public partial class L05Oc16 { public readonly partial record struct L05_16_record_struct_DateOnly : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial struct L05Os17 { public readonly partial record struct L05_17_record_struct_DateOnly : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Ot18 { public partial class Inner { public readonly partial record struct L05_18_record_struct_DateOnly : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public partial class L05Oc19 { public readonly partial record struct L05_19_record_struct_DateTime : IValue { } } -public partial struct L05Os20 { public readonly partial record struct L05_20_record_struct_DateTimeOffset : IValue { } } -public partial struct L05Os21 { public readonly partial record struct L05_21_record_struct_Guid : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_22_record_struct_Guid : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial class L05Oc23 { public readonly partial record struct L05_23_record_struct_NodaTime_Instant : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial struct L05Os24 { public readonly partial record struct L05_24_record_struct_NodaTime_Instant : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_25_record_struct_NodaTime_Instant : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial class L05Ot26 { public partial class Inner { public readonly partial record struct L05_26_record_struct_TimeOnly : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public readonly partial record struct L05_27_record_struct_TimeOnly : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial struct L05Os28 { public readonly partial record struct L05_28_record_struct_TimeOnly : IValue { } } -public partial class L05Oc29 { public readonly partial record struct L05_29_record_struct_TimeSpan : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Oc30 { public readonly partial record struct L05_30_record_struct_TimeSpan : IValue { } } -public readonly partial record struct L05_31_record_struct_Uri : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public readonly partial record struct L05_32_record_struct_Uri : IValue { } -public partial struct L05Os33 { public readonly partial record struct L05_33_record_struct_bool : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Ot34 { public partial class Inner { public readonly partial record struct L05_34_record_struct_bool : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public readonly partial record struct L05_35_record_struct_bool : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public readonly partial record struct L05_36_record_struct_byte : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial class L05Oc37 { public readonly partial record struct L05_37_record_struct_byte : IValue { } } -public readonly partial record struct L05_38_record_struct_char : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial struct L05Os39 { public readonly partial record struct L05_39_record_struct_char : IValue { } } -public partial class L05Oc40 { public readonly partial record struct L05_40_record_struct_decimal : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_41_record_struct_decimal : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial class L05Oc42 { public readonly partial record struct L05_42_record_struct_decimal : IValue { } } -public partial class L05Oc43 { public readonly partial record struct L05_43_record_struct_double : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial struct L05Os44 { public readonly partial record struct L05_44_record_struct_double : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Ot45 { public partial class Inner { public readonly partial record struct L05_45_record_struct_double : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public partial class L05Ot46 { public partial class Inner { public readonly partial record struct L05_46_record_struct_double : IValue { } } } -public partial class L05Oc47 { public readonly partial record struct L05_47_record_struct_enum : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial struct L05Os48 { public readonly partial record struct L05_48_record_struct_enum : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_49_record_struct_flags_enum : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public readonly partial record struct L05_50_record_struct_flags_enum : IValue { } -public partial struct L05Os51 { public readonly partial record struct L05_51_record_struct_int : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Ot52 { public partial class Inner { public readonly partial record struct L05_52_record_struct_int : IValue { } } } -public partial class L05Ot53 { public partial class Inner { public readonly partial record struct L05_53_record_struct_long : IValue { } } } -public readonly partial record struct L05_54_record_struct_long : IValue { } -public partial class L05Ot55 { public partial class Inner { public readonly partial record struct L05_55_record_struct_own_record_class : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public partial struct L05Os56 { public readonly partial record struct L05_56_record_struct_string : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_57_record_struct_string : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public partial class L05Oc58 { public readonly partial record struct L05_58_record_struct_string : IValue { } } -public partial class L05Oc59 { public readonly partial record struct L05_59_record_struct_ulong : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial struct L05Os60 { public readonly partial record struct L05_60_record_struct_ulong : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial struct L05Os61 { public sealed partial record L05_61_sealed_record_class_DateOnly : L05B2b, IValue { } } -public sealed partial record L05_62_sealed_record_class_DateOnly : L05B3c, IValue { } -public partial struct L05Os63 { public sealed partial record L05_63_sealed_record_class_DateOnly : IValue { } } -public sealed partial record L05_64_sealed_record_class_DateOnly : IValue { } -public sealed partial record L05_65_sealed_record_class_DateTime : L05B1, IValue { } -public partial class L05Oc66 { public sealed partial record L05_66_sealed_record_class_DateTime : L05B2b, IValue { } } -public partial struct L05Os67 { public sealed partial record L05_67_sealed_record_class_DateTime : L05B3c, IValue { } } -public partial class L05Ot68 { public partial class Inner { public sealed partial record L05_68_sealed_record_class_DateTime : L05B3c, IValue { } } } -public sealed partial record L05_69_sealed_record_class_DateTime : L05B3c, IValue { } -public partial struct L05Os70 { public sealed partial record L05_70_sealed_record_class_DateTime : L05E1, IValue { } } -public partial class L05Oc71 { public sealed partial record L05_71_sealed_record_class_DateTimeOffset : L05B1, IValue { } } -public sealed partial record L05_72_sealed_record_class_DateTimeOffset : L05B2b, IValue { } -public partial class L05Oc73 { public sealed partial record L05_73_sealed_record_class_DateTimeOffset : L05B3c, IValue { } } -public partial class L05Ot74 { public partial class Inner { public sealed partial record L05_74_sealed_record_class_DateTimeOffset : L05B3c, IValue { } } } -public sealed partial record L05_75_sealed_record_class_DateTimeOffset : L05B3c, IValue { } -public partial class L05Oc76 { public sealed partial record L05_76_sealed_record_class_DateTimeOffset : L05E1, IValue { } } -public sealed partial record L05_77_sealed_record_class_DateTimeOffset : L05E1, IValue { } -public partial class L05Oc78 { public sealed partial record L05_78_sealed_record_class_Guid : L05B1, IValue { } } -public partial struct L05Os79 { public sealed partial record L05_79_sealed_record_class_Guid : L05B1, IValue { } } -public sealed partial record L05_80_sealed_record_class_Guid : L05B2b, IValue { } -public sealed partial record L05_81_sealed_record_class_Guid : L05B3c, IValue { } -public partial class L05Oc82 { public sealed partial record L05_82_sealed_record_class_Guid : L05E1, IValue { } } -public partial class L05Ot83 { public partial class Inner { public sealed partial record L05_83_sealed_record_class_Guid : L05E1, IValue { } } } -public partial class L05Ot84 { public partial class Inner { public sealed partial record L05_84_sealed_record_class_NodaTime_Instant : L05B1, IValue { } } } -public partial struct L05Os85 { public sealed partial record L05_85_sealed_record_class_NodaTime_Instant : L05E1, IValue { } } -public partial struct L05Os86 { public sealed partial record L05_86_sealed_record_class_NodaTime_Instant : IValue { } } -public partial struct L05Os87 { public sealed partial record L05_87_sealed_record_class_TimeOnly : L05B3c, IValue { } } -public partial class L05Ot88 { public partial class Inner { public sealed partial record L05_88_sealed_record_class_TimeOnly : L05B3c, IValue { } } } -public partial class L05Oc89 { public sealed partial record L05_89_sealed_record_class_TimeSpan : L05B1, IValue { } } -public partial class L05Ot90 { public partial class Inner { public sealed partial record L05_90_sealed_record_class_TimeSpan : L05B1, IValue { } } } -public sealed partial record L05_91_sealed_record_class_TimeSpan : L05B2b, IValue { } -public sealed partial record L05_92_sealed_record_class_TimeSpan : L05B3c, IValue { } -public partial struct L05Os93 { public sealed partial record L05_93_sealed_record_class_TimeSpan : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Oc94 { public sealed partial record L05_94_sealed_record_class_TimeSpan : IValue { } } -public partial class L05Oc95 { public sealed partial record L05_95_sealed_record_class_Uri : L05B1, IValue { } } -public partial struct L05Os96 { public sealed partial record L05_96_sealed_record_class_Uri : L05B2b, IValue { } } -public partial struct L05Os97 { public sealed partial record L05_97_sealed_record_class_Uri : L05B3c, IValue { } } -public partial class L05Ot98 { public partial class Inner { public sealed partial record L05_98_sealed_record_class_Uri : L05E1, IValue { } } } -public partial class L05Oc99 { public sealed partial record L05_99_sealed_record_class_bool : L05B2b, IValue { } } -public partial class L05Ot100 { public partial class Inner { public sealed partial record L05_100_sealed_record_class_bool : L05B2b, IValue { } } } -public partial struct L05Os101 { public sealed partial record L05_101_sealed_record_class_bool : L05B3c, IValue { } } -public partial class L05Ot102 { public partial class Inner { public sealed partial record L05_102_sealed_record_class_bool : L05E1, IValue { } } } -public partial class L05Ot103 { public partial class Inner { public sealed partial record L05_103_sealed_record_class_bool : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public partial class L05Ot104 { public partial class Inner { public sealed partial record L05_104_sealed_record_class_byte : L05B1, IValue { } } } -public partial struct L05Os105 { public sealed partial record L05_105_sealed_record_class_byte : L05B2b, IValue { } } -public partial class L05Oc106 { public sealed partial record L05_106_sealed_record_class_byte : L05B3c, IValue { } } -public sealed partial record L05_107_sealed_record_class_byte : L05B3c, IValue { } -public partial class L05Ot108 { public partial class Inner { public sealed partial record L05_108_sealed_record_class_byte : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public sealed partial record L05_109_sealed_record_class_byte : IL05Tag, IValue { string IL05Tag.Tag => "t"; } -public sealed partial record L05_110_sealed_record_class_byte : IValue { } -public partial class L05Ot111 { public partial class Inner { public sealed partial record L05_111_sealed_record_class_char : L05B1, IValue { } } } -public sealed partial record L05_112_sealed_record_class_char : L05B2b, IValue { } -public sealed partial record L05_113_sealed_record_class_char : L05E1, IValue { } -public partial class L05Ot114 { public partial class Inner { public sealed partial record L05_114_sealed_record_class_char : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } } -public partial class L05Oc115 { public sealed partial record L05_115_sealed_record_class_decimal : L05B1, IValue { } } -public partial struct L05Os116 { public sealed partial record L05_116_sealed_record_class_decimal : L05B3c, IValue { } } -public partial class L05Oc117 { public sealed partial record L05_117_sealed_record_class_decimal : L05E1, IValue { } } -public sealed partial record L05_118_sealed_record_class_decimal : L05E1, IValue { } -public partial class L05Ot119 { public partial class Inner { public sealed partial record L05_119_sealed_record_class_double : L05B1, IValue { } } } -public sealed partial record L05_120_sealed_record_class_double : L05B2b, IValue { } -public partial class L05Oc121 { public sealed partial record L05_121_sealed_record_class_double : L05B3c, IValue { } } -public partial class L05Oc122 { public sealed partial record L05_122_sealed_record_class_double : L05E1, IValue { } } -public partial struct L05Os123 { public sealed partial record L05_123_sealed_record_class_enum : L05B1, IValue { } } -public partial class L05Ot124 { public partial class Inner { public sealed partial record L05_124_sealed_record_class_enum : L05B2b, IValue { } } } -public partial class L05Ot125 { public partial class Inner { public sealed partial record L05_125_sealed_record_class_enum : L05B3c, IValue { } } } -public partial class L05Ot126 { public partial class Inner { public sealed partial record L05_126_sealed_record_class_enum : L05E1, IValue { } } } -public partial struct L05Os127 { public sealed partial record L05_127_sealed_record_class_enum : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public partial class L05Oc128 { public sealed partial record L05_128_sealed_record_class_enum : IValue { } } -public partial class L05Oc129 { public sealed partial record L05_129_sealed_record_class_flags_enum : L05B1, IValue { } } -public partial class L05Ot130 { public partial class Inner { public sealed partial record L05_130_sealed_record_class_flags_enum : L05B1, IValue { } } } -public sealed partial record L05_131_sealed_record_class_flags_enum : L05B2b, IValue { } -public sealed partial record L05_132_sealed_record_class_flags_enum : L05B3c, IValue { } -public partial class L05Ot133 { public partial class Inner { public sealed partial record L05_133_sealed_record_class_flags_enum : L05E1, IValue { } } } -public partial struct L05Os134 { public sealed partial record L05_134_sealed_record_class_flags_enum : IL05Tag, IValue { string IL05Tag.Tag => "t"; } } -public sealed partial record L05_135_sealed_record_class_int : L05B2b, IValue { } -public partial struct L05Os136 { public sealed partial record L05_136_sealed_record_class_int : L05E1, IValue { } } -public partial class L05Ot137 { public partial class Inner { public sealed partial record L05_137_sealed_record_class_long : L05B2b, IValue { } } } -public partial class L05Ot138 { public partial class Inner { public sealed partial record L05_138_sealed_record_class_long : L05B3c, IValue { } } } -public partial struct L05Os139 { public sealed partial record L05_139_sealed_record_class_long : L05E1, IValue { } } -public partial class L05Ot140 { public partial class Inner { public sealed partial record L05_140_sealed_record_class_own_record_class : L05B2b, IValue { } } } -public partial struct L05Os141 { public sealed partial record L05_141_sealed_record_class_own_record_class : L05E1, IValue { } } -public partial class L05Ot142 { public partial class Inner { public sealed partial record L05_142_sealed_record_class_own_record_class : L05E1, IValue { } } } -public partial struct L05Os143 { public sealed partial record L05_143_sealed_record_class_string : L05B1, IValue { } } -public sealed partial record L05_144_sealed_record_class_string : L05B3c, IValue { } -public partial class L05Ot145 { public partial class Inner { public sealed partial record L05_145_sealed_record_class_string : L05E1, IValue { } } } -public partial class L05Ot146 { public partial class Inner { public sealed partial record L05_146_sealed_record_class_ulong : L05B3c, IValue { } } } -public partial class L05Ot147 { public partial class Inner { public sealed partial record L05_147_sealed_record_class_ulong : L05E1, IValue { } } } -public sealed partial record L05_148_sealed_record_class_ulong : L05E1, IValue { } -public partial struct L05Os149 { public sealed partial record L05_149_validated_class_DateOnly : L05B1, IValidatedValue { public static Result Create(DateOnly value) => new L05_149_validated_class_DateOnly(value); } } -public sealed partial record L05_150_validated_class_DateOnly : L05E1, IValidatedValue { public static Result Create(DateOnly value) => new L05_150_validated_class_DateOnly(value); } -public sealed partial record L05_151_validated_class_DateOnly : IL05Tag, IValidatedValue { public static Result Create(DateOnly value) => new L05_151_validated_class_DateOnly(value); string IL05Tag.Tag => "t"; } -public partial class L05Ot152 { public partial class Inner { public sealed partial record L05_152_validated_class_DateOnly : IValidatedValue { public static Result Create(DateOnly value) => new L05_152_validated_class_DateOnly(value); } } } -public partial struct L05Os153 { public sealed partial record L05_153_validated_class_DateTime : L05B1, IValidatedValue { public static Result Create(DateTime value) => new L05_153_validated_class_DateTime(value); } } -public partial class L05Ot154 { public partial class Inner { public sealed partial record L05_154_validated_class_DateTime : L05B1, IValidatedValue { public static Result Create(DateTime value) => new L05_154_validated_class_DateTime(value); } } } -public sealed partial record L05_155_validated_class_DateTime : L05B2b, IValidatedValue { public static Result Create(DateTime value) => new L05_155_validated_class_DateTime(value); } -public partial class L05Oc156 { public sealed partial record L05_156_validated_class_DateTime : L05B3c, IValidatedValue { public static Result Create(DateTime value) => new L05_156_validated_class_DateTime(value); } } -public partial struct L05Os157 { public sealed partial record L05_157_validated_class_DateTime : L05E1, IValidatedValue { public static Result Create(DateTime value) => new L05_157_validated_class_DateTime(value); } } -public partial class L05Oc158 { public sealed partial record L05_158_validated_class_DateTimeOffset : IL05Tag, IValidatedValue { public static Result Create(DateTimeOffset value) => new L05_158_validated_class_DateTimeOffset(value); string IL05Tag.Tag => "t"; } } -public partial class L05Oc159 { public sealed partial record L05_159_validated_class_Guid : L05B2b, IValidatedValue { public static Result Create(Guid value) => new L05_159_validated_class_Guid(value); } } -public partial class L05Ot160 { public partial class Inner { public sealed partial record L05_160_validated_class_Guid : L05B2b, IValidatedValue { public static Result Create(Guid value) => new L05_160_validated_class_Guid(value); } } } -public partial class L05Oc161 { public sealed partial record L05_161_validated_class_Guid : IL05Tag, IValidatedValue { public static Result Create(Guid value) => new L05_161_validated_class_Guid(value); string IL05Tag.Tag => "t"; } } -public partial class L05Ot162 { public partial class Inner { public sealed partial record L05_162_validated_class_NodaTime_Instant : L05B2b, IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_162_validated_class_NodaTime_Instant(value); } } } -public partial class L05Oc163 { public sealed partial record L05_163_validated_class_NodaTime_Instant : L05B3c, IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_163_validated_class_NodaTime_Instant(value); } } -public partial struct L05Os164 { public sealed partial record L05_164_validated_class_NodaTime_Instant : L05B3c, IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_164_validated_class_NodaTime_Instant(value); } } -public partial class L05Ot165 { public partial class Inner { public sealed partial record L05_165_validated_class_NodaTime_Instant : L05B3c, IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_165_validated_class_NodaTime_Instant(value); } } } -public partial class L05Oc166 { public sealed partial record L05_166_validated_class_NodaTime_Instant : L05E1, IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_166_validated_class_NodaTime_Instant(value); } } -public sealed partial record L05_167_validated_class_NodaTime_Instant : L05E1, IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_167_validated_class_NodaTime_Instant(value); } -public partial class L05Oc168 { public sealed partial record L05_168_validated_class_TimeOnly : L05B1, IValidatedValue { public static Result Create(TimeOnly value) => new L05_168_validated_class_TimeOnly(value); } } -public partial struct L05Os169 { public sealed partial record L05_169_validated_class_TimeOnly : L05B1, IValidatedValue { public static Result Create(TimeOnly value) => new L05_169_validated_class_TimeOnly(value); } } -public sealed partial record L05_170_validated_class_TimeOnly : L05B2b, IValidatedValue { public static Result Create(TimeOnly value) => new L05_170_validated_class_TimeOnly(value); } -public partial class L05Oc171 { public sealed partial record L05_171_validated_class_TimeOnly : L05E1, IValidatedValue { public static Result Create(TimeOnly value) => new L05_171_validated_class_TimeOnly(value); } } -public sealed partial record L05_172_validated_class_TimeOnly : IValidatedValue { public static Result Create(TimeOnly value) => new L05_172_validated_class_TimeOnly(value); } -public sealed partial record L05_173_validated_class_TimeSpan : L05B1, IValidatedValue { public static Result Create(TimeSpan value) => new L05_173_validated_class_TimeSpan(value); } -public partial class L05Oc174 { public sealed partial record L05_174_validated_class_TimeSpan : L05B2b, IValidatedValue { public static Result Create(TimeSpan value) => new L05_174_validated_class_TimeSpan(value); } } -public partial struct L05Os175 { public sealed partial record L05_175_validated_class_TimeSpan : L05B2b, IValidatedValue { public static Result Create(TimeSpan value) => new L05_175_validated_class_TimeSpan(value); } } -public partial class L05Ot176 { public partial class Inner { public sealed partial record L05_176_validated_class_TimeSpan : L05E1, IValidatedValue { public static Result Create(TimeSpan value) => new L05_176_validated_class_TimeSpan(value); } } } -public partial struct L05Os177 { public sealed partial record L05_177_validated_class_Uri : L05B1, IValidatedValue { public static Result Create(Uri value) => new L05_177_validated_class_Uri(value); } } -public partial class L05Ot178 { public partial class Inner { public sealed partial record L05_178_validated_class_Uri : L05B3c, IValidatedValue { public static Result Create(Uri value) => new L05_178_validated_class_Uri(value); } } } -public sealed partial record L05_179_validated_class_Uri : IL05Tag, IValidatedValue { public static Result Create(Uri value) => new L05_179_validated_class_Uri(value); string IL05Tag.Tag => "t"; } -public partial class L05Oc180 { public sealed partial record L05_180_validated_class_Uri : IValidatedValue { public static Result Create(Uri value) => new L05_180_validated_class_Uri(value); } } -public partial struct L05Os181 { public sealed partial record L05_181_validated_class_bool : L05B1, IValidatedValue { public static Result Create(bool value) => new L05_181_validated_class_bool(value); } } -public partial class L05Oc182 { public sealed partial record L05_182_validated_class_bool : L05E1, IValidatedValue { public static Result Create(bool value) => new L05_182_validated_class_bool(value); } } -public partial struct L05Os183 { public sealed partial record L05_183_validated_class_bool : IL05Tag, IValidatedValue { public static Result Create(bool value) => new L05_183_validated_class_bool(value); string IL05Tag.Tag => "t"; } } -public partial struct L05Os184 { public sealed partial record L05_184_validated_class_byte : L05B2b, IValidatedValue { public static Result Create(byte value) => new L05_184_validated_class_byte(value); } } -public partial class L05Oc185 { public sealed partial record L05_185_validated_class_byte : L05E1, IValidatedValue { public static Result Create(byte value) => new L05_185_validated_class_byte(value); } } -public partial class L05Ot186 { public partial class Inner { public sealed partial record L05_186_validated_class_byte : L05E1, IValidatedValue { public static Result Create(byte value) => new L05_186_validated_class_byte(value); } } } -public partial struct L05Os187 { public sealed partial record L05_187_validated_class_byte : IL05Tag, IValidatedValue { public static Result Create(byte value) => new L05_187_validated_class_byte(value); string IL05Tag.Tag => "t"; } } -public partial class L05Oc188 { public sealed partial record L05_188_validated_class_char : L05B2b, IValidatedValue { public static Result Create(char value) => new L05_188_validated_class_char(value); } } -public partial class L05Oc189 { public sealed partial record L05_189_validated_class_char : L05B3c, IValidatedValue { public static Result Create(char value) => new L05_189_validated_class_char(value); } } -public partial class L05Ot190 { public partial class Inner { public sealed partial record L05_190_validated_class_char : L05B3c, IValidatedValue { public static Result Create(char value) => new L05_190_validated_class_char(value); } } } -public partial class L05Ot191 { public partial class Inner { public sealed partial record L05_191_validated_class_char : L05E1, IValidatedValue { public static Result Create(char value) => new L05_191_validated_class_char(value); } } } -public sealed partial record L05_192_validated_class_char : L05E1, IValidatedValue { public static Result Create(char value) => new L05_192_validated_class_char(value); } -public sealed partial record L05_193_validated_class_decimal : L05B1, IValidatedValue { public static Result Create(decimal value) => new L05_193_validated_class_decimal(value); } -public partial class L05Ot194 { public partial class Inner { public sealed partial record L05_194_validated_class_decimal : L05B2b, IValidatedValue { public static Result Create(decimal value) => new L05_194_validated_class_decimal(value); } } } -public sealed partial record L05_195_validated_class_decimal : L05B2b, IValidatedValue { public static Result Create(decimal value) => new L05_195_validated_class_decimal(value); } -public partial struct L05Os196 { public sealed partial record L05_196_validated_class_decimal : IValidatedValue { public static Result Create(decimal value) => new L05_196_validated_class_decimal(value); } } -public sealed partial record L05_197_validated_class_decimal : IValidatedValue { public static Result Create(decimal value) => new L05_197_validated_class_decimal(value); } -public sealed partial record L05_198_validated_class_double : L05B2b, IValidatedValue { public static Result Create(double value) => new L05_198_validated_class_double(value); } -public partial struct L05Os199 { public sealed partial record L05_199_validated_class_double : L05B3c, IValidatedValue { public static Result Create(double value) => new L05_199_validated_class_double(value); } } -public partial struct L05Os200 { public sealed partial record L05_200_validated_class_double : IL05Tag, IValidatedValue { public static Result Create(double value) => new L05_200_validated_class_double(value); string IL05Tag.Tag => "t"; } } -public partial class L05Ot201 { public partial class Inner { public sealed partial record L05_201_validated_class_enum : L05B1, IValidatedValue { public static Result Create(PEnum value) => new L05_201_validated_class_enum(value); } } } -public sealed partial record L05_202_validated_class_enum : L05B2b, IValidatedValue { public static Result Create(PEnum value) => new L05_202_validated_class_enum(value); } -public partial class L05Oc203 { public sealed partial record L05_203_validated_class_flags_enum : L05E1, IValidatedValue { public static Result Create(PFlags value) => new L05_203_validated_class_flags_enum(value); } } -public partial class L05Ot204 { public partial class Inner { public sealed partial record L05_204_validated_class_flags_enum : IL05Tag, IValidatedValue { public static Result Create(PFlags value) => new L05_204_validated_class_flags_enum(value); string IL05Tag.Tag => "t"; } } } -public partial struct L05Os205 { public sealed partial record L05_205_validated_class_int : L05B1, IValidatedValue { public static Result Create(int value) => new L05_205_validated_class_int(value); } } -public partial class L05Oc206 { public sealed partial record L05_206_validated_class_int : L05B3c, IValidatedValue { public static Result Create(int value) => new L05_206_validated_class_int(value); } } -public partial class L05Oc207 { public sealed partial record L05_207_validated_class_int : IL05Tag, IValidatedValue { public static Result Create(int value) => new L05_207_validated_class_int(value); string IL05Tag.Tag => "t"; } } -public partial class L05Oc208 { public sealed partial record L05_208_validated_class_long : L05B1, IValidatedValue { public static Result Create(long value) => new L05_208_validated_class_long(value); } } -public partial class L05Ot209 { public partial class Inner { public sealed partial record L05_209_validated_class_long : L05B2b, IValidatedValue { public static Result Create(long value) => new L05_209_validated_class_long(value); } } } -public partial class L05Oc210 { public sealed partial record L05_210_validated_class_long : L05E1, IValidatedValue { public static Result Create(long value) => new L05_210_validated_class_long(value); } } -public partial struct L05Os211 { public sealed partial record L05_211_validated_class_long : L05E1, IValidatedValue { public static Result Create(long value) => new L05_211_validated_class_long(value); } } -public partial class L05Ot212 { public partial class Inner { public sealed partial record L05_212_validated_class_long : IL05Tag, IValidatedValue { public static Result Create(long value) => new L05_212_validated_class_long(value); string IL05Tag.Tag => "t"; } } } -public partial struct L05Os213 { public sealed partial record L05_213_validated_class_own_record_class : L05B1, IValidatedValue { public static Result Create(PRec value) => new L05_213_validated_class_own_record_class(value); } } -public partial class L05Ot214 { public partial class Inner { public sealed partial record L05_214_validated_class_own_record_class : L05B1, IValidatedValue { public static Result Create(PRec value) => new L05_214_validated_class_own_record_class(value); } } } -public sealed partial record L05_215_validated_class_own_record_class : L05B2b, IValidatedValue { public static Result Create(PRec value) => new L05_215_validated_class_own_record_class(value); } -public partial struct L05Os216 { public sealed partial record L05_216_validated_class_own_record_class : L05B3c, IValidatedValue { public static Result Create(PRec value) => new L05_216_validated_class_own_record_class(value); } } -public partial class L05Ot217 { public partial class Inner { public sealed partial record L05_217_validated_class_own_record_class : L05B3c, IValidatedValue { public static Result Create(PRec value) => new L05_217_validated_class_own_record_class(value); } } } -public partial struct L05Os218 { public sealed partial record L05_218_validated_class_own_record_class : L05E1, IValidatedValue { public static Result Create(PRec value) => new L05_218_validated_class_own_record_class(value); } } -public partial class L05Oc219 { public sealed partial record L05_219_validated_class_own_record_class : IValidatedValue { public static Result Create(PRec value) => new L05_219_validated_class_own_record_class(value); } } -public partial struct L05Os220 { public sealed partial record L05_220_validated_class_string : L05B1, IValidatedValue { public static Result Create(string value) => new L05_220_validated_class_string(value); } } -public partial class L05Ot221 { public partial class Inner { public sealed partial record L05_221_validated_class_string : L05B2b, IValidatedValue { public static Result Create(string value) => new L05_221_validated_class_string(value); } } } -public partial class L05Oc222 { public sealed partial record L05_222_validated_class_string : L05B3c, IValidatedValue { public static Result Create(string value) => new L05_222_validated_class_string(value); } } -public sealed partial record L05_223_validated_class_string : IL05Tag, IValidatedValue { public static Result Create(string value) => new L05_223_validated_class_string(value); string IL05Tag.Tag => "t"; } -public partial struct L05Os224 { public sealed partial record L05_224_validated_class_ulong : L05B1, IValidatedValue { public static Result Create(ulong value) => new L05_224_validated_class_ulong(value); } } -public sealed partial record L05_225_validated_class_ulong : L05B1, IValidatedValue { public static Result Create(ulong value) => new L05_225_validated_class_ulong(value); } -public sealed partial record L05_226_validated_class_ulong : L05B2b, IValidatedValue { public static Result Create(ulong value) => new L05_226_validated_class_ulong(value); } -public partial class L05Oc227 { public sealed partial record L05_227_validated_class_ulong : L05B3c, IValidatedValue { public static Result Create(ulong value) => new L05_227_validated_class_ulong(value); } } -public partial class L05Oc228 { public sealed partial record L05_228_validated_class_ulong : IL05Tag, IValidatedValue { public static Result Create(ulong value) => new L05_228_validated_class_ulong(value); string IL05Tag.Tag => "t"; } } -public partial struct L05Os229 { public sealed partial record L05_229_validated_class_ulong : IL05Tag, IValidatedValue { public static Result Create(ulong value) => new L05_229_validated_class_ulong(value); string IL05Tag.Tag => "t"; } } -public partial struct L05Os230 { public sealed partial record L05_230_validated_class_ulong : IValidatedValue { public static Result Create(ulong value) => new L05_230_validated_class_ulong(value); } } -public partial class L05Ot231 { public partial class Inner { public readonly partial record struct L05_231_validated_struct_DateOnly : IL05Tag, IValidatedValue { public static Result Create(DateOnly value) => new L05_231_validated_struct_DateOnly(value); string IL05Tag.Tag => "t"; } } } -public readonly partial record struct L05_232_validated_struct_DateOnly : IValidatedValue { public static Result Create(DateOnly value) => new L05_232_validated_struct_DateOnly(value); } -public partial class L05Ot233 { public partial class Inner { public readonly partial record struct L05_233_validated_struct_DateTime : IL05Tag, IValidatedValue { public static Result Create(DateTime value) => new L05_233_validated_struct_DateTime(value); string IL05Tag.Tag => "t"; } } } -public partial struct L05Os234 { public readonly partial record struct L05_234_validated_struct_DateTimeOffset : IValidatedValue { public static Result Create(DateTimeOffset value) => new L05_234_validated_struct_DateTimeOffset(value); } } -public readonly partial record struct L05_235_validated_struct_DateTimeOffset : IValidatedValue { public static Result Create(DateTimeOffset value) => new L05_235_validated_struct_DateTimeOffset(value); } -public partial class L05Oc236 { public readonly partial record struct L05_236_validated_struct_Guid : IValidatedValue { public static Result Create(Guid value) => new L05_236_validated_struct_Guid(value); } } -public partial struct L05Os237 { public readonly partial record struct L05_237_validated_struct_Guid : IValidatedValue { public static Result Create(Guid value) => new L05_237_validated_struct_Guid(value); } } -public readonly partial record struct L05_238_validated_struct_NodaTime_Instant : IValidatedValue { public static Result Create(global::NodaTime.Instant value) => new L05_238_validated_struct_NodaTime_Instant(value); } -public partial class L05Oc239 { public readonly partial record struct L05_239_validated_struct_TimeOnly : IL05Tag, IValidatedValue { public static Result Create(TimeOnly value) => new L05_239_validated_struct_TimeOnly(value); string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_240_validated_struct_TimeOnly : IValidatedValue { public static Result Create(TimeOnly value) => new L05_240_validated_struct_TimeOnly(value); } -public partial class L05Oc241 { public readonly partial record struct L05_241_validated_struct_TimeSpan : IValidatedValue { public static Result Create(TimeSpan value) => new L05_241_validated_struct_TimeSpan(value); } } -public partial struct L05Os242 { public readonly partial record struct L05_242_validated_struct_Uri : IL05Tag, IValidatedValue { public static Result Create(Uri value) => new L05_242_validated_struct_Uri(value); string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_243_validated_struct_Uri : IL05Tag, IValidatedValue { public static Result Create(Uri value) => new L05_243_validated_struct_Uri(value); string IL05Tag.Tag => "t"; } -public partial class L05Oc244 { public readonly partial record struct L05_244_validated_struct_Uri : IValidatedValue { public static Result Create(Uri value) => new L05_244_validated_struct_Uri(value); } } -public partial class L05Oc245 { public readonly partial record struct L05_245_validated_struct_bool : IL05Tag, IValidatedValue { public static Result Create(bool value) => new L05_245_validated_struct_bool(value); string IL05Tag.Tag => "t"; } } -public partial class L05Ot246 { public partial class Inner { public readonly partial record struct L05_246_validated_struct_bool : IValidatedValue { public static Result Create(bool value) => new L05_246_validated_struct_bool(value); } } } -public readonly partial record struct L05_247_validated_struct_byte : IL05Tag, IValidatedValue { public static Result Create(byte value) => new L05_247_validated_struct_byte(value); string IL05Tag.Tag => "t"; } -public partial class L05Oc248 { public readonly partial record struct L05_248_validated_struct_char : IL05Tag, IValidatedValue { public static Result Create(char value) => new L05_248_validated_struct_char(value); string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_249_validated_struct_decimal : IL05Tag, IValidatedValue { public static Result Create(decimal value) => new L05_249_validated_struct_decimal(value); string IL05Tag.Tag => "t"; } -public partial class L05Ot250 { public partial class Inner { public readonly partial record struct L05_250_validated_struct_double : IL05Tag, IValidatedValue { public static Result Create(double value) => new L05_250_validated_struct_double(value); string IL05Tag.Tag => "t"; } } } -public partial class L05Ot251 { public partial class Inner { public readonly partial record struct L05_251_validated_struct_double : IValidatedValue { public static Result Create(double value) => new L05_251_validated_struct_double(value); } } } -public partial class L05Oc252 { public readonly partial record struct L05_252_validated_struct_enum : IValidatedValue { public static Result Create(PEnum value) => new L05_252_validated_struct_enum(value); } } -public partial struct L05Os253 { public readonly partial record struct L05_253_validated_struct_enum : IValidatedValue { public static Result Create(PEnum value) => new L05_253_validated_struct_enum(value); } } -public partial class L05Ot254 { public partial class Inner { public readonly partial record struct L05_254_validated_struct_enum : IValidatedValue { public static Result Create(PEnum value) => new L05_254_validated_struct_enum(value); } } } -public partial class L05Ot255 { public partial class Inner { public readonly partial record struct L05_255_validated_struct_flags_enum : IValidatedValue { public static Result Create(PFlags value) => new L05_255_validated_struct_flags_enum(value); } } } -public readonly partial record struct L05_256_validated_struct_flags_enum : IValidatedValue { public static Result Create(PFlags value) => new L05_256_validated_struct_flags_enum(value); } -public partial struct L05Os257 { public readonly partial record struct L05_257_validated_struct_int : IL05Tag, IValidatedValue { public static Result Create(int value) => new L05_257_validated_struct_int(value); string IL05Tag.Tag => "t"; } } -public partial class L05Ot258 { public partial class Inner { public readonly partial record struct L05_258_validated_struct_int : IL05Tag, IValidatedValue { public static Result Create(int value) => new L05_258_validated_struct_int(value); string IL05Tag.Tag => "t"; } } } -public partial class L05Ot259 { public partial class Inner { public readonly partial record struct L05_259_validated_struct_int : IValidatedValue { public static Result Create(int value) => new L05_259_validated_struct_int(value); } } } -public readonly partial record struct L05_260_validated_struct_int : IValidatedValue { public static Result Create(int value) => new L05_260_validated_struct_int(value); } -public partial struct L05Os261 { public readonly partial record struct L05_261_validated_struct_long : IL05Tag, IValidatedValue { public static Result Create(long value) => new L05_261_validated_struct_long(value); string IL05Tag.Tag => "t"; } } -public readonly partial record struct L05_262_validated_struct_long : IL05Tag, IValidatedValue { public static Result Create(long value) => new L05_262_validated_struct_long(value); string IL05Tag.Tag => "t"; } -public readonly partial record struct L05_263_validated_struct_own_record_class : IL05Tag, IValidatedValue { public static Result Create(PRec value) => new L05_263_validated_struct_own_record_class(value); string IL05Tag.Tag => "t"; } -public partial struct L05Os264 { public readonly partial record struct L05_264_validated_struct_own_record_class : IValidatedValue { public static Result Create(PRec value) => new L05_264_validated_struct_own_record_class(value); } } -public partial class L05Ot265 { public partial class Inner { public readonly partial record struct L05_265_validated_struct_string : IL05Tag, IValidatedValue { public static Result Create(string value) => new L05_265_validated_struct_string(value); string IL05Tag.Tag => "t"; } } } -public partial class L05Oc266 { public readonly partial record struct L05_266_validated_struct_string : IValidatedValue { public static Result Create(string value) => new L05_266_validated_struct_string(value); } } -public readonly partial record struct L05_267_validated_struct_string : IValidatedValue { public static Result Create(string value) => new L05_267_validated_struct_string(value); } -public readonly partial record struct L05_268_validated_struct_ulong : IL05Tag, IValidatedValue { public static Result Create(ulong value) => new L05_268_validated_struct_ulong(value); string IL05Tag.Tag => "t"; } -public readonly partial record struct L05_269_validated_struct_ulong : IValidatedValue { public static Result Create(ulong value) => new L05_269_validated_struct_ulong(value); } - -public static partial class L05Registry -{ - static partial void Fill() - { - Add("closed-set", "-", "base-depth-1", "nested-in-class", typeof(L05Oc0.L05_0_closed_set__), () => L05Oc0.L05_0_closed_set__.Alpha, () => L05Oc0.L05_0_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Oc0.L05_0_closed_set__.Beta); - Add("closed-set", "-", "base-depth-1", "nested-two-levels", typeof(L05Ot1.Inner.L05_1_closed_set__), () => L05Ot1.Inner.L05_1_closed_set__.Alpha, () => L05Ot1.Inner.L05_1_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Ot1.Inner.L05_1_closed_set__.Beta); - Add("closed-set", "-", "base-depth-2", "nested-in-class", typeof(L05Oc2.L05_2_closed_set__), () => L05Oc2.L05_2_closed_set__.Alpha, () => L05Oc2.L05_2_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Oc2.L05_2_closed_set__.Beta); - Add("closed-set", "-", "base-depth-2", "nested-in-struct", typeof(L05Os3.L05_3_closed_set__), () => L05Os3.L05_3_closed_set__.Alpha, () => L05Os3.L05_3_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Os3.L05_3_closed_set__.Beta); - Add("closed-set", "-", "base-depth-2", "top-level", typeof(L05_4_closed_set__), () => L05_4_closed_set__.Alpha, () => L05_4_closed_set__.All.First(m => m.Name == "Alpha"), () => L05_4_closed_set__.Beta); - Add("closed-set", "-", "base-depth-3", "nested-in-class", typeof(L05Oc5.L05_5_closed_set__), () => L05Oc5.L05_5_closed_set__.Alpha, () => L05Oc5.L05_5_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Oc5.L05_5_closed_set__.Beta); - Add("closed-set", "-", "base-depth-3", "nested-in-struct", typeof(L05Os6.L05_6_closed_set__), () => L05Os6.L05_6_closed_set__.Alpha, () => L05Os6.L05_6_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Os6.L05_6_closed_set__.Beta); - Add("closed-set", "-", "base-depth-3", "nested-two-levels", typeof(L05Ot7.Inner.L05_7_closed_set__), () => L05Ot7.Inner.L05_7_closed_set__.Alpha, () => L05Ot7.Inner.L05_7_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Ot7.Inner.L05_7_closed_set__.Beta); - Add("closed-set", "-", "base-depth-3", "top-level", typeof(L05_8_closed_set__), () => L05_8_closed_set__.Alpha, () => L05_8_closed_set__.All.First(m => m.Name == "Alpha"), () => L05_8_closed_set__.Beta); - Add("closed-set", "-", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc9.L05_9_closed_set__), () => L05Oc9.L05_9_closed_set__.Alpha, () => L05Oc9.L05_9_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Oc9.L05_9_closed_set__.Beta); - Add("closed-set", "-", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os10.L05_10_closed_set__), () => L05Os10.L05_10_closed_set__.Alpha, () => L05Os10.L05_10_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Os10.L05_10_closed_set__.Beta); - Add("closed-set", "-", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot11.Inner.L05_11_closed_set__), () => L05Ot11.Inner.L05_11_closed_set__.Alpha, () => L05Ot11.Inner.L05_11_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Ot11.Inner.L05_11_closed_set__.Beta); - Add("closed-set", "-", "base-explicit-IEquatable", "top-level", typeof(L05_12_closed_set__), () => L05_12_closed_set__.Alpha, () => L05_12_closed_set__.All.First(m => m.Name == "Alpha"), () => L05_12_closed_set__.Beta); - Add("closed-set", "-", "explicit-interface-member", "nested-in-class", typeof(L05Oc13.L05_13_closed_set__), () => L05Oc13.L05_13_closed_set__.Alpha, () => L05Oc13.L05_13_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Oc13.L05_13_closed_set__.Beta); - Add("closed-set", "-", "explicit-interface-member", "top-level", typeof(L05_14_closed_set__), () => L05_14_closed_set__.Alpha, () => L05_14_closed_set__.All.First(m => m.Name == "Alpha"), () => L05_14_closed_set__.Beta); - Add("closed-set", "-", "none", "nested-in-struct", typeof(L05Os15.L05_15_closed_set__), () => L05Os15.L05_15_closed_set__.Alpha, () => L05Os15.L05_15_closed_set__.All.First(m => m.Name == "Alpha"), () => L05Os15.L05_15_closed_set__.Beta); - Add("record-struct", "DateOnly", "explicit-interface-member", "nested-in-class", typeof(L05Oc16.L05_16_record_struct_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("record-struct", "DateOnly", "explicit-interface-member", "nested-in-struct", typeof(L05Os17.L05_17_record_struct_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("record-struct", "DateOnly", "explicit-interface-member", "nested-two-levels", typeof(L05Ot18.Inner.L05_18_record_struct_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("record-struct", "DateTime", "none", "nested-in-class", typeof(L05Oc19.L05_19_record_struct_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("record-struct", "DateTimeOffset", "none", "nested-in-struct", typeof(L05Os20.L05_20_record_struct_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("record-struct", "Guid", "explicit-interface-member", "nested-in-struct", typeof(L05Os21.L05_21_record_struct_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("record-struct", "Guid", "explicit-interface-member", "top-level", typeof(L05_22_record_struct_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("record-struct", "NodaTime.Instant", "explicit-interface-member", "nested-in-class", typeof(L05Oc23.L05_23_record_struct_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("record-struct", "NodaTime.Instant", "explicit-interface-member", "nested-in-struct", typeof(L05Os24.L05_24_record_struct_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("record-struct", "NodaTime.Instant", "explicit-interface-member", "top-level", typeof(L05_25_record_struct_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("record-struct", "TimeOnly", "explicit-interface-member", "nested-two-levels", typeof(L05Ot26.Inner.L05_26_record_struct_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("record-struct", "TimeOnly", "explicit-interface-member", "top-level", typeof(L05_27_record_struct_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("record-struct", "TimeOnly", "none", "nested-in-struct", typeof(L05Os28.L05_28_record_struct_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("record-struct", "TimeSpan", "explicit-interface-member", "nested-in-class", typeof(L05Oc29.L05_29_record_struct_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("record-struct", "TimeSpan", "none", "nested-in-class", typeof(L05Oc30.L05_30_record_struct_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("record-struct", "Uri", "explicit-interface-member", "top-level", typeof(L05_31_record_struct_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("record-struct", "Uri", "none", "top-level", typeof(L05_32_record_struct_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("record-struct", "bool", "explicit-interface-member", "nested-in-struct", typeof(L05Os33.L05_33_record_struct_bool), () => false, () => false, () => true); - Add("record-struct", "bool", "explicit-interface-member", "nested-two-levels", typeof(L05Ot34.Inner.L05_34_record_struct_bool), () => false, () => false, () => true); - Add("record-struct", "bool", "explicit-interface-member", "top-level", typeof(L05_35_record_struct_bool), () => false, () => false, () => true); - Add("record-struct", "byte", "explicit-interface-member", "top-level", typeof(L05_36_record_struct_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("record-struct", "byte", "none", "nested-in-class", typeof(L05Oc37.L05_37_record_struct_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("record-struct", "char", "explicit-interface-member", "top-level", typeof(L05_38_record_struct_char), () => 'a', () => 'a', () => 'b'); - Add("record-struct", "char", "none", "nested-in-struct", typeof(L05Os39.L05_39_record_struct_char), () => 'a', () => 'a', () => 'b'); - Add("record-struct", "decimal", "explicit-interface-member", "nested-in-class", typeof(L05Oc40.L05_40_record_struct_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("record-struct", "decimal", "explicit-interface-member", "top-level", typeof(L05_41_record_struct_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("record-struct", "decimal", "none", "nested-in-class", typeof(L05Oc42.L05_42_record_struct_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("record-struct", "double", "explicit-interface-member", "nested-in-class", typeof(L05Oc43.L05_43_record_struct_double), () => 0.0, () => -0.0, () => 1.5); - Add("record-struct", "double", "explicit-interface-member", "nested-in-struct", typeof(L05Os44.L05_44_record_struct_double), () => 0.0, () => -0.0, () => 1.5); - Add("record-struct", "double", "explicit-interface-member", "nested-two-levels", typeof(L05Ot45.Inner.L05_45_record_struct_double), () => 0.0, () => -0.0, () => 1.5); - Add("record-struct", "double", "none", "nested-two-levels", typeof(L05Ot46.Inner.L05_46_record_struct_double), () => 0.0, () => -0.0, () => 1.5); - Add("record-struct", "enum", "explicit-interface-member", "nested-in-class", typeof(L05Oc47.L05_47_record_struct_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("record-struct", "enum", "explicit-interface-member", "nested-in-struct", typeof(L05Os48.L05_48_record_struct_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("record-struct", "flags-enum", "explicit-interface-member", "top-level", typeof(L05_49_record_struct_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("record-struct", "flags-enum", "none", "top-level", typeof(L05_50_record_struct_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("record-struct", "int", "explicit-interface-member", "nested-in-struct", typeof(L05Os51.L05_51_record_struct_int), () => 42, () => 42, () => 43); - Add("record-struct", "int", "none", "nested-two-levels", typeof(L05Ot52.Inner.L05_52_record_struct_int), () => 42, () => 42, () => 43); - Add("record-struct", "long", "none", "nested-two-levels", typeof(L05Ot53.Inner.L05_53_record_struct_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("record-struct", "long", "none", "top-level", typeof(L05_54_record_struct_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("record-struct", "own-record-class", "explicit-interface-member", "nested-two-levels", typeof(L05Ot55.Inner.L05_55_record_struct_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("record-struct", "string", "explicit-interface-member", "nested-in-struct", typeof(L05Os56.L05_56_record_struct_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("record-struct", "string", "explicit-interface-member", "top-level", typeof(L05_57_record_struct_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("record-struct", "string", "none", "nested-in-class", typeof(L05Oc58.L05_58_record_struct_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("record-struct", "ulong", "explicit-interface-member", "nested-in-class", typeof(L05Oc59.L05_59_record_struct_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("record-struct", "ulong", "explicit-interface-member", "nested-in-struct", typeof(L05Os60.L05_60_record_struct_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("sealed-record-class", "DateOnly", "base-depth-2", "nested-in-struct", typeof(L05Os61.L05_61_sealed_record_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("sealed-record-class", "DateOnly", "base-depth-3", "top-level", typeof(L05_62_sealed_record_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("sealed-record-class", "DateOnly", "none", "nested-in-struct", typeof(L05Os63.L05_63_sealed_record_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("sealed-record-class", "DateOnly", "none", "top-level", typeof(L05_64_sealed_record_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("sealed-record-class", "DateTime", "base-depth-1", "top-level", typeof(L05_65_sealed_record_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("sealed-record-class", "DateTime", "base-depth-2", "nested-in-class", typeof(L05Oc66.L05_66_sealed_record_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("sealed-record-class", "DateTime", "base-depth-3", "nested-in-struct", typeof(L05Os67.L05_67_sealed_record_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("sealed-record-class", "DateTime", "base-depth-3", "nested-two-levels", typeof(L05Ot68.Inner.L05_68_sealed_record_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("sealed-record-class", "DateTime", "base-depth-3", "top-level", typeof(L05_69_sealed_record_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("sealed-record-class", "DateTime", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os70.L05_70_sealed_record_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("sealed-record-class", "DateTimeOffset", "base-depth-1", "nested-in-class", typeof(L05Oc71.L05_71_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "DateTimeOffset", "base-depth-2", "top-level", typeof(L05_72_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "DateTimeOffset", "base-depth-3", "nested-in-class", typeof(L05Oc73.L05_73_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "DateTimeOffset", "base-depth-3", "nested-two-levels", typeof(L05Ot74.Inner.L05_74_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "DateTimeOffset", "base-depth-3", "top-level", typeof(L05_75_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "DateTimeOffset", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc76.L05_76_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "DateTimeOffset", "base-explicit-IEquatable", "top-level", typeof(L05_77_sealed_record_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("sealed-record-class", "Guid", "base-depth-1", "nested-in-class", typeof(L05Oc78.L05_78_sealed_record_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("sealed-record-class", "Guid", "base-depth-1", "nested-in-struct", typeof(L05Os79.L05_79_sealed_record_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("sealed-record-class", "Guid", "base-depth-2", "top-level", typeof(L05_80_sealed_record_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("sealed-record-class", "Guid", "base-depth-3", "top-level", typeof(L05_81_sealed_record_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("sealed-record-class", "Guid", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc82.L05_82_sealed_record_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("sealed-record-class", "Guid", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot83.Inner.L05_83_sealed_record_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("sealed-record-class", "NodaTime.Instant", "base-depth-1", "nested-two-levels", typeof(L05Ot84.Inner.L05_84_sealed_record_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("sealed-record-class", "NodaTime.Instant", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os85.L05_85_sealed_record_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("sealed-record-class", "NodaTime.Instant", "none", "nested-in-struct", typeof(L05Os86.L05_86_sealed_record_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("sealed-record-class", "TimeOnly", "base-depth-3", "nested-in-struct", typeof(L05Os87.L05_87_sealed_record_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("sealed-record-class", "TimeOnly", "base-depth-3", "nested-two-levels", typeof(L05Ot88.Inner.L05_88_sealed_record_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("sealed-record-class", "TimeSpan", "base-depth-1", "nested-in-class", typeof(L05Oc89.L05_89_sealed_record_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("sealed-record-class", "TimeSpan", "base-depth-1", "nested-two-levels", typeof(L05Ot90.Inner.L05_90_sealed_record_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("sealed-record-class", "TimeSpan", "base-depth-2", "top-level", typeof(L05_91_sealed_record_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("sealed-record-class", "TimeSpan", "base-depth-3", "top-level", typeof(L05_92_sealed_record_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("sealed-record-class", "TimeSpan", "explicit-interface-member", "nested-in-struct", typeof(L05Os93.L05_93_sealed_record_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("sealed-record-class", "TimeSpan", "none", "nested-in-class", typeof(L05Oc94.L05_94_sealed_record_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("sealed-record-class", "Uri", "base-depth-1", "nested-in-class", typeof(L05Oc95.L05_95_sealed_record_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("sealed-record-class", "Uri", "base-depth-2", "nested-in-struct", typeof(L05Os96.L05_96_sealed_record_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("sealed-record-class", "Uri", "base-depth-3", "nested-in-struct", typeof(L05Os97.L05_97_sealed_record_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("sealed-record-class", "Uri", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot98.Inner.L05_98_sealed_record_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("sealed-record-class", "bool", "base-depth-2", "nested-in-class", typeof(L05Oc99.L05_99_sealed_record_class_bool), () => false, () => false, () => true); - Add("sealed-record-class", "bool", "base-depth-2", "nested-two-levels", typeof(L05Ot100.Inner.L05_100_sealed_record_class_bool), () => false, () => false, () => true); - Add("sealed-record-class", "bool", "base-depth-3", "nested-in-struct", typeof(L05Os101.L05_101_sealed_record_class_bool), () => false, () => false, () => true); - Add("sealed-record-class", "bool", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot102.Inner.L05_102_sealed_record_class_bool), () => false, () => false, () => true); - Add("sealed-record-class", "bool", "explicit-interface-member", "nested-two-levels", typeof(L05Ot103.Inner.L05_103_sealed_record_class_bool), () => false, () => false, () => true); - Add("sealed-record-class", "byte", "base-depth-1", "nested-two-levels", typeof(L05Ot104.Inner.L05_104_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "byte", "base-depth-2", "nested-in-struct", typeof(L05Os105.L05_105_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "byte", "base-depth-3", "nested-in-class", typeof(L05Oc106.L05_106_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "byte", "base-depth-3", "top-level", typeof(L05_107_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "byte", "explicit-interface-member", "nested-two-levels", typeof(L05Ot108.Inner.L05_108_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "byte", "explicit-interface-member", "top-level", typeof(L05_109_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "byte", "none", "top-level", typeof(L05_110_sealed_record_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("sealed-record-class", "char", "base-depth-1", "nested-two-levels", typeof(L05Ot111.Inner.L05_111_sealed_record_class_char), () => 'a', () => 'a', () => 'b'); - Add("sealed-record-class", "char", "base-depth-2", "top-level", typeof(L05_112_sealed_record_class_char), () => 'a', () => 'a', () => 'b'); - Add("sealed-record-class", "char", "base-explicit-IEquatable", "top-level", typeof(L05_113_sealed_record_class_char), () => 'a', () => 'a', () => 'b'); - Add("sealed-record-class", "char", "explicit-interface-member", "nested-two-levels", typeof(L05Ot114.Inner.L05_114_sealed_record_class_char), () => 'a', () => 'a', () => 'b'); - Add("sealed-record-class", "decimal", "base-depth-1", "nested-in-class", typeof(L05Oc115.L05_115_sealed_record_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("sealed-record-class", "decimal", "base-depth-3", "nested-in-struct", typeof(L05Os116.L05_116_sealed_record_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("sealed-record-class", "decimal", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc117.L05_117_sealed_record_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("sealed-record-class", "decimal", "base-explicit-IEquatable", "top-level", typeof(L05_118_sealed_record_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("sealed-record-class", "double", "base-depth-1", "nested-two-levels", typeof(L05Ot119.Inner.L05_119_sealed_record_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("sealed-record-class", "double", "base-depth-2", "top-level", typeof(L05_120_sealed_record_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("sealed-record-class", "double", "base-depth-3", "nested-in-class", typeof(L05Oc121.L05_121_sealed_record_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("sealed-record-class", "double", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc122.L05_122_sealed_record_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("sealed-record-class", "enum", "base-depth-1", "nested-in-struct", typeof(L05Os123.L05_123_sealed_record_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("sealed-record-class", "enum", "base-depth-2", "nested-two-levels", typeof(L05Ot124.Inner.L05_124_sealed_record_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("sealed-record-class", "enum", "base-depth-3", "nested-two-levels", typeof(L05Ot125.Inner.L05_125_sealed_record_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("sealed-record-class", "enum", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot126.Inner.L05_126_sealed_record_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("sealed-record-class", "enum", "explicit-interface-member", "nested-in-struct", typeof(L05Os127.L05_127_sealed_record_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("sealed-record-class", "enum", "none", "nested-in-class", typeof(L05Oc128.L05_128_sealed_record_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("sealed-record-class", "flags-enum", "base-depth-1", "nested-in-class", typeof(L05Oc129.L05_129_sealed_record_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("sealed-record-class", "flags-enum", "base-depth-1", "nested-two-levels", typeof(L05Ot130.Inner.L05_130_sealed_record_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("sealed-record-class", "flags-enum", "base-depth-2", "top-level", typeof(L05_131_sealed_record_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("sealed-record-class", "flags-enum", "base-depth-3", "top-level", typeof(L05_132_sealed_record_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("sealed-record-class", "flags-enum", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot133.Inner.L05_133_sealed_record_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("sealed-record-class", "flags-enum", "explicit-interface-member", "nested-in-struct", typeof(L05Os134.L05_134_sealed_record_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("sealed-record-class", "int", "base-depth-2", "top-level", typeof(L05_135_sealed_record_class_int), () => 42, () => 42, () => 43); - Add("sealed-record-class", "int", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os136.L05_136_sealed_record_class_int), () => 42, () => 42, () => 43); - Add("sealed-record-class", "long", "base-depth-2", "nested-two-levels", typeof(L05Ot137.Inner.L05_137_sealed_record_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("sealed-record-class", "long", "base-depth-3", "nested-two-levels", typeof(L05Ot138.Inner.L05_138_sealed_record_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("sealed-record-class", "long", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os139.L05_139_sealed_record_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("sealed-record-class", "own-record-class", "base-depth-2", "nested-two-levels", typeof(L05Ot140.Inner.L05_140_sealed_record_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("sealed-record-class", "own-record-class", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os141.L05_141_sealed_record_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("sealed-record-class", "own-record-class", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot142.Inner.L05_142_sealed_record_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("sealed-record-class", "string", "base-depth-1", "nested-in-struct", typeof(L05Os143.L05_143_sealed_record_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("sealed-record-class", "string", "base-depth-3", "top-level", typeof(L05_144_sealed_record_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("sealed-record-class", "string", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot145.Inner.L05_145_sealed_record_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("sealed-record-class", "ulong", "base-depth-3", "nested-two-levels", typeof(L05Ot146.Inner.L05_146_sealed_record_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("sealed-record-class", "ulong", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot147.Inner.L05_147_sealed_record_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("sealed-record-class", "ulong", "base-explicit-IEquatable", "top-level", typeof(L05_148_sealed_record_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "DateOnly", "base-depth-1", "nested-in-struct", typeof(L05Os149.L05_149_validated_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("validated-class", "DateOnly", "base-explicit-IEquatable", "top-level", typeof(L05_150_validated_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("validated-class", "DateOnly", "explicit-interface-member", "top-level", typeof(L05_151_validated_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("validated-class", "DateOnly", "none", "nested-two-levels", typeof(L05Ot152.Inner.L05_152_validated_class_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("validated-class", "DateTime", "base-depth-1", "nested-in-struct", typeof(L05Os153.L05_153_validated_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("validated-class", "DateTime", "base-depth-1", "nested-two-levels", typeof(L05Ot154.Inner.L05_154_validated_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("validated-class", "DateTime", "base-depth-2", "top-level", typeof(L05_155_validated_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("validated-class", "DateTime", "base-depth-3", "nested-in-class", typeof(L05Oc156.L05_156_validated_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("validated-class", "DateTime", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os157.L05_157_validated_class_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("validated-class", "DateTimeOffset", "explicit-interface-member", "nested-in-class", typeof(L05Oc158.L05_158_validated_class_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("validated-class", "Guid", "base-depth-2", "nested-in-class", typeof(L05Oc159.L05_159_validated_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("validated-class", "Guid", "base-depth-2", "nested-two-levels", typeof(L05Ot160.Inner.L05_160_validated_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("validated-class", "Guid", "explicit-interface-member", "nested-in-class", typeof(L05Oc161.L05_161_validated_class_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("validated-class", "NodaTime.Instant", "base-depth-2", "nested-two-levels", typeof(L05Ot162.Inner.L05_162_validated_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-class", "NodaTime.Instant", "base-depth-3", "nested-in-class", typeof(L05Oc163.L05_163_validated_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-class", "NodaTime.Instant", "base-depth-3", "nested-in-struct", typeof(L05Os164.L05_164_validated_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-class", "NodaTime.Instant", "base-depth-3", "nested-two-levels", typeof(L05Ot165.Inner.L05_165_validated_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-class", "NodaTime.Instant", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc166.L05_166_validated_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-class", "NodaTime.Instant", "base-explicit-IEquatable", "top-level", typeof(L05_167_validated_class_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-class", "TimeOnly", "base-depth-1", "nested-in-class", typeof(L05Oc168.L05_168_validated_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-class", "TimeOnly", "base-depth-1", "nested-in-struct", typeof(L05Os169.L05_169_validated_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-class", "TimeOnly", "base-depth-2", "top-level", typeof(L05_170_validated_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-class", "TimeOnly", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc171.L05_171_validated_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-class", "TimeOnly", "none", "top-level", typeof(L05_172_validated_class_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-class", "TimeSpan", "base-depth-1", "top-level", typeof(L05_173_validated_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("validated-class", "TimeSpan", "base-depth-2", "nested-in-class", typeof(L05Oc174.L05_174_validated_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("validated-class", "TimeSpan", "base-depth-2", "nested-in-struct", typeof(L05Os175.L05_175_validated_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("validated-class", "TimeSpan", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot176.Inner.L05_176_validated_class_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("validated-class", "Uri", "base-depth-1", "nested-in-struct", typeof(L05Os177.L05_177_validated_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-class", "Uri", "base-depth-3", "nested-two-levels", typeof(L05Ot178.Inner.L05_178_validated_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-class", "Uri", "explicit-interface-member", "top-level", typeof(L05_179_validated_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-class", "Uri", "none", "nested-in-class", typeof(L05Oc180.L05_180_validated_class_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-class", "bool", "base-depth-1", "nested-in-struct", typeof(L05Os181.L05_181_validated_class_bool), () => false, () => false, () => true); - Add("validated-class", "bool", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc182.L05_182_validated_class_bool), () => false, () => false, () => true); - Add("validated-class", "bool", "explicit-interface-member", "nested-in-struct", typeof(L05Os183.L05_183_validated_class_bool), () => false, () => false, () => true); - Add("validated-class", "byte", "base-depth-2", "nested-in-struct", typeof(L05Os184.L05_184_validated_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("validated-class", "byte", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc185.L05_185_validated_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("validated-class", "byte", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot186.Inner.L05_186_validated_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("validated-class", "byte", "explicit-interface-member", "nested-in-struct", typeof(L05Os187.L05_187_validated_class_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("validated-class", "char", "base-depth-2", "nested-in-class", typeof(L05Oc188.L05_188_validated_class_char), () => 'a', () => 'a', () => 'b'); - Add("validated-class", "char", "base-depth-3", "nested-in-class", typeof(L05Oc189.L05_189_validated_class_char), () => 'a', () => 'a', () => 'b'); - Add("validated-class", "char", "base-depth-3", "nested-two-levels", typeof(L05Ot190.Inner.L05_190_validated_class_char), () => 'a', () => 'a', () => 'b'); - Add("validated-class", "char", "base-explicit-IEquatable", "nested-two-levels", typeof(L05Ot191.Inner.L05_191_validated_class_char), () => 'a', () => 'a', () => 'b'); - Add("validated-class", "char", "base-explicit-IEquatable", "top-level", typeof(L05_192_validated_class_char), () => 'a', () => 'a', () => 'b'); - Add("validated-class", "decimal", "base-depth-1", "top-level", typeof(L05_193_validated_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("validated-class", "decimal", "base-depth-2", "nested-two-levels", typeof(L05Ot194.Inner.L05_194_validated_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("validated-class", "decimal", "base-depth-2", "top-level", typeof(L05_195_validated_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("validated-class", "decimal", "none", "nested-in-struct", typeof(L05Os196.L05_196_validated_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("validated-class", "decimal", "none", "top-level", typeof(L05_197_validated_class_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("validated-class", "double", "base-depth-2", "top-level", typeof(L05_198_validated_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("validated-class", "double", "base-depth-3", "nested-in-struct", typeof(L05Os199.L05_199_validated_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("validated-class", "double", "explicit-interface-member", "nested-in-struct", typeof(L05Os200.L05_200_validated_class_double), () => 0.0, () => -0.0, () => 1.5); - Add("validated-class", "enum", "base-depth-1", "nested-two-levels", typeof(L05Ot201.Inner.L05_201_validated_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("validated-class", "enum", "base-depth-2", "top-level", typeof(L05_202_validated_class_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("validated-class", "flags-enum", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc203.L05_203_validated_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("validated-class", "flags-enum", "explicit-interface-member", "nested-two-levels", typeof(L05Ot204.Inner.L05_204_validated_class_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("validated-class", "int", "base-depth-1", "nested-in-struct", typeof(L05Os205.L05_205_validated_class_int), () => 42, () => 42, () => 43); - Add("validated-class", "int", "base-depth-3", "nested-in-class", typeof(L05Oc206.L05_206_validated_class_int), () => 42, () => 42, () => 43); - Add("validated-class", "int", "explicit-interface-member", "nested-in-class", typeof(L05Oc207.L05_207_validated_class_int), () => 42, () => 42, () => 43); - Add("validated-class", "long", "base-depth-1", "nested-in-class", typeof(L05Oc208.L05_208_validated_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-class", "long", "base-depth-2", "nested-two-levels", typeof(L05Ot209.Inner.L05_209_validated_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-class", "long", "base-explicit-IEquatable", "nested-in-class", typeof(L05Oc210.L05_210_validated_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-class", "long", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os211.L05_211_validated_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-class", "long", "explicit-interface-member", "nested-two-levels", typeof(L05Ot212.Inner.L05_212_validated_class_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-class", "own-record-class", "base-depth-1", "nested-in-struct", typeof(L05Os213.L05_213_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "own-record-class", "base-depth-1", "nested-two-levels", typeof(L05Ot214.Inner.L05_214_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "own-record-class", "base-depth-2", "top-level", typeof(L05_215_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "own-record-class", "base-depth-3", "nested-in-struct", typeof(L05Os216.L05_216_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "own-record-class", "base-depth-3", "nested-two-levels", typeof(L05Ot217.Inner.L05_217_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "own-record-class", "base-explicit-IEquatable", "nested-in-struct", typeof(L05Os218.L05_218_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "own-record-class", "none", "nested-in-class", typeof(L05Oc219.L05_219_validated_class_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-class", "string", "base-depth-1", "nested-in-struct", typeof(L05Os220.L05_220_validated_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-class", "string", "base-depth-2", "nested-two-levels", typeof(L05Ot221.Inner.L05_221_validated_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-class", "string", "base-depth-3", "nested-in-class", typeof(L05Oc222.L05_222_validated_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-class", "string", "explicit-interface-member", "top-level", typeof(L05_223_validated_class_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-class", "ulong", "base-depth-1", "nested-in-struct", typeof(L05Os224.L05_224_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "ulong", "base-depth-1", "top-level", typeof(L05_225_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "ulong", "base-depth-2", "top-level", typeof(L05_226_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "ulong", "base-depth-3", "nested-in-class", typeof(L05Oc227.L05_227_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "ulong", "explicit-interface-member", "nested-in-class", typeof(L05Oc228.L05_228_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "ulong", "explicit-interface-member", "nested-in-struct", typeof(L05Os229.L05_229_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-class", "ulong", "none", "nested-in-struct", typeof(L05Os230.L05_230_validated_class_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-struct", "DateOnly", "explicit-interface-member", "nested-two-levels", typeof(L05Ot231.Inner.L05_231_validated_struct_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("validated-struct", "DateOnly", "none", "top-level", typeof(L05_232_validated_struct_DateOnly), () => new DateOnly(2026, 10, 15), () => DateOnly.FromDayNumber(new DateOnly(2026, 10, 15).DayNumber), () => new DateOnly(2026, 10, 16)); - Add("validated-struct", "DateTime", "explicit-interface-member", "nested-two-levels", typeof(L05Ot233.Inner.L05_233_validated_struct_DateTime), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Utc), () => new DateTime(2026, 10, 15, 8, 30, 0, DateTimeKind.Unspecified), () => new DateTime(2026, 10, 15, 8, 31, 0, DateTimeKind.Utc)); - Add("validated-struct", "DateTimeOffset", "none", "nested-in-struct", typeof(L05Os234.L05_234_validated_struct_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("validated-struct", "DateTimeOffset", "none", "top-level", typeof(L05_235_validated_struct_DateTimeOffset), () => new DateTimeOffset(2026, 10, 15, 8, 30, 0, TimeSpan.Zero), () => new DateTimeOffset(2026, 10, 15, 10, 30, 0, TimeSpan.FromHours(2)), () => new DateTimeOffset(2026, 10, 15, 8, 31, 0, TimeSpan.Zero)); - Add("validated-struct", "Guid", "none", "nested-in-class", typeof(L05Oc236.L05_236_validated_struct_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("validated-struct", "Guid", "none", "nested-in-struct", typeof(L05Os237.L05_237_validated_struct_Guid), () => Guid.Parse("11111111-1111-1111-1111-111111111111"), () => new Guid("11111111111111111111111111111111"), () => Guid.Parse("22222222-2222-2222-2222-222222222222")); - Add("validated-struct", "NodaTime.Instant", "none", "top-level", typeof(L05_238_validated_struct_NodaTime_Instant), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30), () => global::NodaTime.Instant.FromUnixTimeTicks(global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 30).ToUnixTimeTicks()), () => global::NodaTime.Instant.FromUtc(2026, 10, 15, 8, 31)); - Add("validated-struct", "TimeOnly", "explicit-interface-member", "nested-in-class", typeof(L05Oc239.L05_239_validated_struct_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-struct", "TimeOnly", "none", "top-level", typeof(L05_240_validated_struct_TimeOnly), () => new TimeOnly(8, 30, 15), () => new TimeOnly(new TimeOnly(8, 30, 15).Ticks), () => new TimeOnly(8, 30, 16)); - Add("validated-struct", "TimeSpan", "none", "nested-in-class", typeof(L05Oc241.L05_241_validated_struct_TimeSpan), () => TimeSpan.FromMinutes(90), () => TimeSpan.FromSeconds(5400), () => TimeSpan.FromMinutes(91)); - Add("validated-struct", "Uri", "explicit-interface-member", "nested-in-struct", typeof(L05Os242.L05_242_validated_struct_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-struct", "Uri", "explicit-interface-member", "top-level", typeof(L05_243_validated_struct_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-struct", "Uri", "none", "nested-in-class", typeof(L05Oc244.L05_244_validated_struct_Uri), () => new Uri("https://example.com/a"), () => new Uri("HTTPS://EXAMPLE.COM/a"), () => new Uri("https://example.com/b")); - Add("validated-struct", "bool", "explicit-interface-member", "nested-in-class", typeof(L05Oc245.L05_245_validated_struct_bool), () => false, () => false, () => true); - Add("validated-struct", "bool", "none", "nested-two-levels", typeof(L05Ot246.Inner.L05_246_validated_struct_bool), () => false, () => false, () => true); - Add("validated-struct", "byte", "explicit-interface-member", "top-level", typeof(L05_247_validated_struct_byte), () => (byte)7, () => (byte)7, () => (byte)8); - Add("validated-struct", "char", "explicit-interface-member", "nested-in-class", typeof(L05Oc248.L05_248_validated_struct_char), () => 'a', () => 'a', () => 'b'); - Add("validated-struct", "decimal", "explicit-interface-member", "top-level", typeof(L05_249_validated_struct_decimal), () => 7.8m, () => 7.80m, () => 7.81m); - Add("validated-struct", "double", "explicit-interface-member", "nested-two-levels", typeof(L05Ot250.Inner.L05_250_validated_struct_double), () => 0.0, () => -0.0, () => 1.5); - Add("validated-struct", "double", "none", "nested-two-levels", typeof(L05Ot251.Inner.L05_251_validated_struct_double), () => 0.0, () => -0.0, () => 1.5); - Add("validated-struct", "enum", "none", "nested-in-class", typeof(L05Oc252.L05_252_validated_struct_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("validated-struct", "enum", "none", "nested-in-struct", typeof(L05Os253.L05_253_validated_struct_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("validated-struct", "enum", "none", "nested-two-levels", typeof(L05Ot254.Inner.L05_254_validated_struct_enum), () => PEnum.B, () => (PEnum)1, () => PEnum.C); - Add("validated-struct", "flags-enum", "none", "nested-two-levels", typeof(L05Ot255.Inner.L05_255_validated_struct_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("validated-struct", "flags-enum", "none", "top-level", typeof(L05_256_validated_struct_flags_enum), () => PFlags.P | PFlags.Q, () => (PFlags)3, () => PFlags.R); - Add("validated-struct", "int", "explicit-interface-member", "nested-in-struct", typeof(L05Os257.L05_257_validated_struct_int), () => 42, () => 42, () => 43); - Add("validated-struct", "int", "explicit-interface-member", "nested-two-levels", typeof(L05Ot258.Inner.L05_258_validated_struct_int), () => 42, () => 42, () => 43); - Add("validated-struct", "int", "none", "nested-two-levels", typeof(L05Ot259.Inner.L05_259_validated_struct_int), () => 42, () => 42, () => 43); - Add("validated-struct", "int", "none", "top-level", typeof(L05_260_validated_struct_int), () => 42, () => 42, () => 43); - Add("validated-struct", "long", "explicit-interface-member", "nested-in-struct", typeof(L05Os261.L05_261_validated_struct_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-struct", "long", "explicit-interface-member", "top-level", typeof(L05_262_validated_struct_long), () => 4200000000L, () => 4200000000L, () => 4200000001L); - Add("validated-struct", "own-record-class", "explicit-interface-member", "top-level", typeof(L05_263_validated_struct_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-struct", "own-record-class", "none", "nested-in-struct", typeof(L05Os264.L05_264_validated_struct_own_record_class), () => new PRec { A = "x", B = 1 }, () => new PRec { A = new string("x".ToCharArray()), B = 1 }, () => new PRec { A = "y", B = 1 }); - Add("validated-struct", "string", "explicit-interface-member", "nested-two-levels", typeof(L05Ot265.Inner.L05_265_validated_struct_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-struct", "string", "none", "nested-in-class", typeof(L05Oc266.L05_266_validated_struct_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-struct", "string", "none", "top-level", typeof(L05_267_validated_struct_string), () => "alpha", () => new string("alpha".ToCharArray()), () => "beta"); - Add("validated-struct", "ulong", "explicit-interface-member", "top-level", typeof(L05_268_validated_struct_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - Add("validated-struct", "ulong", "none", "top-level", typeof(L05_269_validated_struct_ulong), () => 4200000000UL, () => 4200000000UL, () => 4200000001UL); - } -} diff --git a/tools/probe/corpus/harness/OffTheWire.cs b/tools/probe/corpus/harness/OffTheWire.cs deleted file mode 100644 index eae52bbf..00000000 --- a/tools/probe/corpus/harness/OffTheWire.cs +++ /dev/null @@ -1,221 +0,0 @@ -// Claim L06-off-the-wire (README.md#what-typekit-guarantees): "Option and Result stay off the wire. System.Text.Json throws -// NotSupportedException for either, in both directions, instead of writing {} that reads back as None. [...] If you want a wire format of -// your own, a converter you register on the options takes precedence." The message names the type (src/CodoMetis.TypeKit/README.md -// "Option or Result in JSON"); a source-generated context refuses an Option? or Result<...>? property with the serializer's own -// InvalidOperationException when it builds that contract (ibid., "Good to know"). -// Oracle: exception, in every position, with the row's options and input, for an Option or Result produced by the row's operation. A -// converter of the application's for the same type in the same row is the baseline: it must win in both directions, and where the options -// leave the member out (it writes and reads nothing there), no converter runs, which is intended ("A missing property reaches no converter"). -#pragma warning disable CMTK0001 // default-instance: the default Option and Result are the shapes under test -using System.Reflection; -using System.Text.Json; -using System.Text.Json.Serialization; -using CodoMetis.TypeKit; -using Probes.Shapes; -namespace Probes.Json; - -/// An application's own converter for an Option or Result: writes "own-or" and reads it back as the value it was made with, counting reads. -public sealed class OwnOrConverter(T value) : JsonConverter -{ - public int Reads; - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - Reads++; - if (reader.TokenType is not (JsonTokenType.String or JsonTokenType.PropertyName) || reader.GetString() != "own-or") throw new JsonException("not own-or"); - return value; - } - public override void Write(Utf8JsonWriter writer, T v, JsonSerializerOptions options) => writer.WriteStringValue("own-or"); - public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Read(ref reader, typeToConvert, options); - public override void WriteAsPropertyName(Utf8JsonWriter writer, T v, JsonSerializerOptions options) => writer.WritePropertyName("own-or"); -} - -public static class OffTheWire -{ - public static async Task Check(Row r) - { - var kind = r["shape.kind"]; - var e = kind == "closed-set" ? Registry.Get(kind, "-") : Registry.Get(kind, r["shape.wrapped"]); - var position = r["shape.position"]; - var containing = position == "root" ? "class" : r["shape.containing"]; - var shape = r["or.shape"]; var op = r["or.operation"]; - _ = r["input.json"]; // the row's input, which every check of the row runs under; the read applies it - if (shape == "Result-E" && op is "query-syntax" or "FirstOrNone") - { r.Substituted("or.operation", "Match", "Result has no " + op + " (claims.json excludes the pair)"); op = "Match"; } - var voValue = Make.Vo(e, e.Valid()); - var v = Make.Held(e.Vo); - var produce = typeof(OffTheWire).GetMethod(nameof(Produce), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(v); - var (orType, orValue) = await (Task<(Type, object)>)produce.Invoke(null, [shape, op, voValue])!; - var key = shape == "Option" ? "O" : shape == "Result-E" ? "RE" : "RTE"; - var pb = typeof(OffTheWire).Assembly.GetType($"Probes.Json.L06PB_{v.Name}_{key}")!; var pd = typeof(OffTheWire).Assembly.GetType($"Probes.Json.L06PD_{v.Name}_{key}")!; - var eo = e with { Vo = orType, Plain = orType, PolyBase = pb, PolyDerived = pd, PolyBasePlain = pb, PolyDerivedPlain = pd }; - var hv = Pos.Build(position, containing, e, true, voValue); // the value object's shape: its document is the read's input - var ho = Pos.Build(position, containing, eo, true, orValue); - var o = JCtx.Apply(r, e, hv.Declared, ho.Declared); - var own = (JsonConverter)Activator.CreateInstance(typeof(OwnOrConverter<>).MakeGenericType(orType), orValue)!; - var oOwn = new JsonSerializerOptions(o); oOwn.Converters.Insert(0, own); - int OwnReads() => (int)own.GetType().GetField("Reads")!.GetValue(own)!; - var name = Jx.Name(orType); - // not-promised a-source-generated-context-refuses-a-nullable - var nullableUnderContext = r.Is("json.TypeInfoResolver", "source-generated-context") && position == "nullable-property"; - string? Refused(Exception? x, string dir) - { - if (nullableUnderContext) - return x is InvalidOperationException ? null : $"{dir}: a source-generated context refuses an {name}? property with the serializer's InvalidOperationException; got {(x is null ? "no exception" : Jx.Ex(x))}"; - if (x is not NotSupportedException) return $"{dir}: expected NotSupportedException naming {name}, got {(x is null ? "no exception" : Jx.Ex(x))}"; - // TypeKit's refusal, told by its type and never by its words: the serializer passes a converter's NotSupportedException on as the - // inner exception of its own, so one in the chain is thrown by NotWireTypeJsonConverterFactory's converter, by nameof - if (!ThrownBy(x, typeof(NotWireTypeJsonConverterFactory))) return $"{dir}: the NotSupportedException is not {nameof(NotWireTypeJsonConverterFactory)}'s: {Jx.Ex(x)}"; - return null; - } - - // the baseline: the application's own converter for the type wins, in both directions - var (jOwn, xOwn) = Jx.Ser(ho, oOwn); - var (jv, xv) = Jx.Ser(hv, o); - var refused = Baseline.Refusal; - var fw = r.Check("never-written", refused, c => - { - if (xOwn is not null) - { - if (xv is not null && xv.GetType() == xOwn.GetType()) return c.Inconclusive("write: the options refuse the shape itself, with the application's converter alike: " + Jx.Ex(xv)); - return $"write: a converter registered on the options for {name} does not take precedence: {Jx.Ex(xOwn)}"; - } - var ownWritten = Jx.Tokens(jOwn!).Any(t => t.Text == "own-or"); - var (jo, xo) = Jx.Ser(ho, o); - if (xo is null) - { - if (ownWritten || jo != jOwn) return $"write: {name} was written: {Jx.Cut(jo)}"; - // the options leave the member out, the application's converter's document alike: no converter ran - c.Note(NoteKeys.JsonMemberLeftOutByOptions, "write: " + Jx.Cut(jo)); - return c.Inconclusive("write: the options leave the member out, so no converter runs: " + Jx.Cut(jo)); - } - if (Refused(xo, "write") is { } f) return f; - c.Note(NoteKeys.Compared, $"{name} by {op}, {position}: write refused"); - return null; - }); - // reading: the value object's document with the row's input, where the Option or Result stands; measured before the check, so that - // a document the serializer refuses before the member (side (1), Sides) decides the check's baseline - var full = Jx.Full(o); - var (jf, xf) = Jx.Ser(hv, full); - // does the application's converter get called there? Its own document, read under the same options, says so - var (jOwnFull, _) = Jx.Ser(ho, Jx.Full(oOwn)); - string input = r["input.json"], text = ""; - if (xf is null) text = JsonParity.InputFor(input, e, full, jf!, position); - else if (jOwnFull is not null) { input = "valid"; text = jOwnFull; } - var reads = xOwn is null && (xf is null || jOwnFull is not null); - var (_, xOwnRead) = reads ? Jx.De(jOwnFull ?? "null", ho.Declared, oOwn) : (null, null); - var memberRead = reads && OwnReads() > 0; - var (vr, xr) = reads ? Jx.De(text, ho.Declared, o) : (null, null); - // side (1): the same document with the value object where the Option or Result stands, read under the same options; refusing alike - // (the same exception type at the same path, no message compared), the serializer refused the document before the member - var three = new Sides.Answer("read", null, xr); - var one = new Sides.Answer("read", null, reads && xr is not null && !ThrownBy(xr, typeof(NotWireTypeJsonConverterFactory)) ? Jx.De(text, hv.Declared, o).Ex : null); - var framework = Sides.Alike(one, three) ? Sides.Measured(one, "the document with the value object where the Option or Result stands") : null; - var fr = await Sides.Check(r, "never-read", refused, framework, three, null, null, async c => - { - await Task.CompletedTask; - if (xOwn is not null) return c.Inconclusive("read: the options refuse the shape itself, so no document has the member: " + Jx.Ex(xOwn)); - _ = c["input.json"]; - if (xf is not null) - { - // the value object's own shape cannot be written here (a value object over a class under Preserve, a class as a key): the - // document with the application's converter has a token where the Option or Result stands, and is read as it is - if (jOwnFull is null) return c.Inconclusive("read: no document has the member: " + Jx.Ex(xf)); - c.Substituted("input.json", "valid", "the value object's document cannot be written: " + xf.GetType().Name); - } - if (xOwnRead is not null) return $"read: a converter registered on the options for {name} does not take precedence: {Jx.Ex(xOwnRead)}"; - if (xr is null && input == "null" && position == "in-patch" && Jx.Member(ho.Declared, vr) is { } patch && patch.GetType().GetProperty("State")!.GetValue(patch)!.ToString() == "Null") - // a JSON null is the patch's own null (docs/merge-patches.md): it holds no Option or Result, and none was read - return c.Inapplicable(Cite.Docs("docs/merge-patches.md#tell-absent-null-and-a-value-apart"), $"read null: the Patch<{name}> is null, nothing of {name} read"); - if (xr is null) - { - if (memberRead) return $"read {input}: {name} was read without an exception\n text={Jx.Cut(text)}"; - c.Note(NoteKeys.JsonMemberLeftOutByOptions, "read " + input); - return c.Inapplicable(Cite.NotPromised("a-missing-property-reaches-no-converter"), "read " + input); - } - if (Refused(xr, "read " + input) is { } f) return f + $"\n text={Jx.Cut(text)}"; - c.Note(NoteKeys.Compared, $"{name} by {op}, {position}: read {input} refused"); - return null; - }); - return fw ?? fr; - } - - /// - /// Whether a refusal, or one in its chain of inner exceptions, was thrown by a converter that declares: the - /// method that threw it (its TargetSite) belongs to the factory's type or to a type nested in it. Told by types, never by a message. - /// - static bool ThrownBy(Exception? x, Type factory) - { - for (; x is not null; x = x.InnerException) - for (var t = x.TargetSite?.DeclaringType; t is not null; t = t.DeclaringType) - if (t == factory) return true; - return false; - } - - static async Task<(Type, object)> Produce(string shape, string op, V v) where V : notnull - { - switch (shape) - { - case "Option": - { - Option x = op switch - { - "Match" => Option.Some(v).Match(s => Option.Some(s), () => Option.None()), - "Bind-Map-chain" => Option.Some(v).Bind(s => Option.Some(s)).Map(s => s), - "query-syntax" => from s in Option.Some(v) select s, - "Sequence-Transpose" => Option.Some(Result.Success(v)).Transpose().Match(s => s, _ => Option.None()), - "Result.Catch" => Result.Catch(() => v).ToOption(), - "FirstOrNone" => new[] { v }.FirstOrNone(), - "default-instance" => default, - "after-await-elsewhere" => await Task.Run(() => Option.Some(v)).ConfigureAwait(false), - _ => throw new ArgumentException(op), - }; - return (typeof(Option), x); - } - case "Result-E": - { - Result x = op switch - { - "Match" => Result.Error(v).Match(() => Result.Success(), er => Result.Error(er)), - "Bind-Map-chain" => Result.Success().Bind(() => Result.Error(v)), - "Sequence-Transpose" => new[] { Result.Error(v) }.Sequence(), - "Result.Catch" => Result.Catch(() => { }).MapError(_ => v), - "default-instance" => default, - "after-await-elsewhere" => await Task.Run(() => Result.Error(v)).ConfigureAwait(false), - _ => throw new ArgumentException(op), - }; - return (typeof(Result), x); - } - default: - { - Result x; - if (shape == "Task-of-Result") - { - var ok = Task.FromResult(Result.Success(v)); - x = op switch - { - "Bind-Map-chain" => await ok.BindAsync(s => Result.Success(s)).MapAsync(s => s), - "FirstOrNone" => await Task.FromResult(new[] { v }.FirstOrNone()).ToResultAsync(ShapeFault.Refused), - "Result.Catch" => await Result.CatchAsync(() => Task.FromResult(v)).MapErrorAsync(_ => ShapeFault.Refused), - _ => await Task.FromResult(await Sync(op, v)).ConfigureAwait(false), - }; - } - else if (shape == "ValueTask-of-Result") x = await new ValueTask>(await Sync(op, v)); - else x = await Sync(op, v); - return (typeof(Result), x); - } - } - } - - static async Task> Sync(string op, V v) where V : notnull => op switch - { - "Match" => Result.Success(v).Match(s => Result.Success(s), er => Result.Error(er)), - "Bind-Map-chain" => Result.Success(v).Bind(s => Result.Success(s)).Map(s => s), - "query-syntax" => from s in Result.Success(v) select s, - "Sequence-Transpose" => new[] { Result.Success(v) }.Sequence().Map(l => l[0]), - "Result.Catch" => Result.Catch(() => v).MapError(_ => ShapeFault.Refused), - "FirstOrNone" => new[] { v }.FirstOrNone().ToResult(ShapeFault.Refused), - "default-instance" => default, - "after-await-elsewhere" => await Task.Run(() => Result.Success(v)).ConfigureAwait(false), - _ => throw new ArgumentException(op), - }; -} diff --git a/tools/probe/corpus/harness/Positions.cs b/tools/probe/corpus/harness/Positions.cs deleted file mode 100644 index 800e60ba..00000000 --- a/tools/probe/corpus/harness/Positions.cs +++ /dev/null @@ -1,328 +0,0 @@ -// Builds the value a probe serializes for a row's shape.position x shape.containing (VO side and plain side), and the JSON parity oracle. -using System.Collections; -using System.Collections.Immutable; -using System.Globalization; -using System.Reflection; -using System.Text.Json; -using CodoMetis.TypeKit; -namespace Probes.Shapes; - -public sealed record Held(Type Declared, object Value); - -public static class Pos -{ - static Type Family(string containing, string style, Type m) - { - var n = containing.Replace('-', '_'); - var arity = containing == "generic-type" ? 2 : 1; - var open = typeof(PSet).Assembly.GetType($"Probes.Shapes.Cn_{n}_{style}`{arity}") ?? throw new InvalidOperationException($"no container Cn_{n}_{style}"); - return arity == 2 ? open.MakeGenericType(m, typeof(int)) : open.MakeGenericType(m); - } - - public static Held Build(string position, string containing, Entry e, bool vo, object sample) - { - var t = vo ? e.Vo : e.Plain; - if (position == "root") return new(t, sample); - Type m; object member; string style = "P"; - switch (position) - { - case "property": case "required-init": case "field": case "record-ctor-parameter": - m = t; member = sample; - style = position switch { "field" => "F", "record-ctor-parameter" => "C", "required-init" => "R", _ => "P" }; - break; - case "nullable-property": m = t.IsValueType && Nullable.GetUnderlyingType(t) is null ? typeof(Nullable<>).MakeGenericType(t) : t; member = sample; break; - case "list-element": case "read-only-list-element": - { - var l = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(t))!; l.Add(sample); - member = l; m = position == "list-element" ? l.GetType() : typeof(IReadOnlyList<>).MakeGenericType(t); break; - } - case "array-element": { var a = Array.CreateInstance(t, 1); a.SetValue(sample, 0); member = a; m = a.GetType(); break; } - case "immutable-array-element": - { - var l = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(t))!; l.Add(sample); - var create = typeof(ImmutableArray).GetMethods().First(x => x.Name == "CreateRange" && x.GetParameters().Length == 1).MakeGenericMethod(t); - member = create.Invoke(null, [l])!; m = member.GetType(); break; - } - // a dictionary key is never null: a nullable twin (or, under http.nullability=nullable, a nullable value object) is a key of the type it holds - case "dictionary-key": { var d = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(Make.Held(t), typeof(int)))!; d.Add(sample, 1); member = d; m = d.GetType(); break; } - case "dictionary-value": { var d = (IDictionary)Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(typeof(string), t))!; d.Add("k", sample); member = d; m = d.GetType(); break; } - // a Patch holds no null (T : notnull): a nullable twin is patched as the type it holds, as a dictionary key is - case "in-patch": - member = typeof(Patch).GetMethod("Value")!.MakeGenericMethod(Make.Held(t)).Invoke(null, [sample])!; m = member.GetType(); break; - case "polymorphic-derived-property": - { - var derived = vo ? e.PolyDerived : e.PolyDerivedPlain; - var inst = Activator.CreateInstance(derived)!; derived.GetProperty("Value")!.SetValue(inst, sample); - member = inst; m = vo ? e.PolyBase : e.PolyBasePlain; break; - } - default: throw new ArgumentException("unknown position " + position); - } - var ct = Family(containing, style, m); - object c; - if (style == "C") c = Activator.CreateInstance(ct, member)!; - else - { - c = Activator.CreateInstance(ct)!; - if (style == "F") ct.GetField("F")!.SetValue(c, member); else ct.GetProperty("P")!.SetValue(c, member); - } - return new(ct, c); - } -} - -/// -/// Input equivalence for the differential oracles: the twin and the value object must hold the same shape under the same options, the -/// twin standing where the value object stands, at its nullability: both admit null or neither (shapes.cs makes the twin of a class value -/// object over a struct the struct made nullable). The one difference no plain type can mirror is a struct value object over a class, -/// which refuses the null its twin reads (not-promised a-struct-refuses-a-json-null), and a dictionary key and what a patch holds, which -/// are never null on either side. A mismatch is a harness error, never a pass or a product violation (Sides.Twins). -/// -public static class Equivalence -{ - public static string? Shapes(Type plain, Type vo, Entry e) => Shapes(plain, vo, e, key: false); - - static string? Shapes(Type plain, Type vo, Entry e, bool key) - { - if (plain == vo) return null; - if (Make.Held(vo) == Make.Held(e.Vo)) return Member(plain, vo, e, key); - if (plain.IsArray && vo.IsArray) return Shapes(plain.GetElementType()!, vo.GetElementType()!, e, false); - if (plain.IsGenericType && vo.IsGenericType && plain.GetGenericTypeDefinition() == vo.GetGenericTypeDefinition()) - { - var pa = plain.GetGenericArguments(); var va = vo.GetGenericArguments(); - // a dictionary's key and what a patch holds are never null, on either side - var notNull = plain.GetGenericTypeDefinition() == typeof(Dictionary<,>) || plain.GetGenericTypeDefinition() == typeof(Patch<>); - for (var i = 0; i < pa.Length; i++) if (Shapes(pa[i], va[i], e, notNull && i == 0) is { } why) return why; - return null; - } - // The generated stand-ins (the polymorphic bases and derived types): one per side by design, equal in - // structure: the same properties by name, each of an equivalent type, and the same polymorphism. - if (plain.IsClass && vo.IsClass && !plain.IsGenericType && !vo.IsGenericType) - { - var pp = plain.GetProperties().ToDictionary(x => x.Name); var vp = vo.GetProperties().ToDictionary(x => x.Name); - if (!pp.Keys.Order().SequenceEqual(vp.Keys.Order())) return $"{Name(plain)} and {Name(vo)} have different properties"; - foreach (var (name, prop) in pp) if (Shapes(prop.PropertyType, vp[name].PropertyType, e, false) is { } why) return $"{name}: {why}"; - var pd = plain.GetCustomAttributes(typeof(System.Text.Json.Serialization.JsonDerivedTypeAttribute), false).Length; - var vd = vo.GetCustomAttributes(typeof(System.Text.Json.Serialization.JsonDerivedTypeAttribute), false).Length; - if (pd != vd) return $"{Name(plain)} and {Name(vo)} declare {pd} and {vd} derived types"; - if ((plain.BaseType is { } pb && pb != typeof(object)) || (vo.BaseType is { } vb && vb != typeof(object))) - return Shapes(plain.BaseType!, vo.BaseType!, e, false); - return null; - } - return $"{Name(plain)} and {Name(vo)} are different shapes"; - } - - /// Where the value object stands: its twin, at its nullability. - static string? Member(Type plain, Type vo, Entry e, bool key) - { - if (Make.Held(plain) != Make.Held(e.Plain)) return $"{Name(plain)} stands where {Name(vo)} should face {Name(e.Plain)}"; - if (key || Make.AdmitsNull(plain) == Make.AdmitsNull(vo)) return null; - // a struct value object over a class refuses the JSON null its twin reads: no plain type mirrors it, the claims cite it - if (!Make.AdmitsNull(vo) && !Make.Held(e.Plain).IsValueType) return null; - return $"{Name(plain)} and {Name(vo)} differ in nullability: the twin {(Make.AdmitsNull(plain) ? "admits" : "refuses")} null, the value object {(Make.AdmitsNull(vo) ? "admits" : "refuses")} it"; - } - - public static string? Options(JsonSerializerOptions plain, JsonSerializerOptions vo, bool allowConverters) - { - if (ReferenceEquals(plain, vo)) return null; - foreach (var p in typeof(JsonSerializerOptions).GetProperties()) - { - if (p.GetIndexParameters().Length > 0 || (allowConverters && p.Name == "Converters")) continue; - var a = Print(p.GetValue(plain)); var b = Print(p.GetValue(vo)); - if (a != b) return $"options differ in {p.Name}: {a} vs {b}"; - } - return null; - } - - static string Print(object? v) => v switch - { - null => "null", - string or bool or char or int or Enum => v.ToString()!, - System.Collections.IEnumerable list => "[" + string.Join(",", list.Cast().Select(x => x?.GetType().FullName)) + "]", - _ => v.GetType().FullName!, - }; - - static string Name(Type t) => t.IsGenericType ? t.Name[..t.Name.IndexOf('`')] + "<" + string.Join(",", t.GetGenericArguments().Select(Name)) + ">" : t.Name; -} - -public static class JsonParity -{ - static (string? Json, Exception? Ex) Ser(Held h, JsonSerializerOptions o) - { try { return (JsonSerializer.Serialize(h.Value, h.Declared, o), null); } catch (Exception ex) { return (null, ex); } } - static (string? Json, Exception? Ex) De(string text, Held h, JsonSerializerOptions o) - { - try { var v = JsonSerializer.Deserialize(text, h.Declared, o); return (v is null ? "null" : JsonSerializer.Serialize(v, h.Declared, o), null); } - catch (Exception ex) { return (null, ex); } - } - - static string Limit(Entry e) => e.Wrapped switch - { - "int" => "2147483647", "long" => "9223372036854775807", "byte" => "255", "ulong" => "18446744073709551615", - "decimal" => "79228162514264337593543950335", "double" => "1.7976931348623157E+308", "bool" => "true", - "string" => "\"" + new string('x', 70000) + "\"", "char" => "\"\\uffff\"", "enum" => "2147483647", "flags-enum" => "7", - "DateTime" => "\"9999-12-31T23:59:59.9999999Z\"", "DateTimeOffset" => "\"9999-12-31T23:59:59.9999999+00:00\"", - "DateOnly" => "\"9999-12-31\"", "TimeOnly" => "\"23:59:59.9999999\"", "TimeSpan" => "\"10675199.02:48:05.4775807\"", - "Uri" => "\"https://example.com/" + new string('p', 3000) + "\"", "NodaTime.Instant" => "\"9999-12-31T23:59:59.999999999Z\"", - "own-record-class" => "{\"A\":\"x\",\"B\":2147483647}", "Guid" => "\"ffffffff-ffff-ffff-ffff-ffffffffffff\"", - _ => "\"Beta\"" - }; - - /// Text a position's JSON takes for an input.json value, built from the plain side's JSON by replacing the sample's own text. - public static string InputFor(string input, Entry e, JsonSerializerOptions o, string jp, string position) => Input(input, e, o, jp, position); - static string Input(string input, Entry e, JsonSerializerOptions o, string jp, string position) - { - string sample; - try { sample = JsonSerializer.Serialize(e.Valid(), e.Plain, o); } catch { return jp; } - var at = jp.IndexOf(sample, StringComparison.Ordinal); - string Swap(string with) => at < 0 ? jp : jp[..at] + with + jp[(at + sample.Length)..]; - switch (input) - { - case "valid": return jp; - case "refused-by-create": - if (e.Refused() is not { } rf) return jp; - try { return Swap(JsonSerializer.Serialize(rf, e.Plain, o)); } catch { return jp; } - case "wrong-token": return Swap(sample.StartsWith('"') || sample.StartsWith('{') ? "[]" : "\"zz\""); - case "null": return Swap("null"); - case "empty-string": return Swap("\"\""); - case "at-type-limit": return Swap(Limit(e)); - case "quoted-number": return Swap(sample.StartsWith('"') ? sample : "\"" + sample + "\""); - case "escape-sequence": - return sample.StartsWith('"') && sample.Length > 3 ? Swap(sample[..1] + "\\u00" + ((int)sample[1]).ToString("x2") + sample[2..]) : jp; - case "duplicate-property": return jp.StartsWith('{') && jp.Length > 2 ? "{" + jp[1..^1] + "," + jp[1..^1] + "}" : jp; - case "metadata-property": return jp.StartsWith('{') ? (jp.Length > 2 ? "{\"$id\":\"1\"," + jp[1..] : "{\"$id\":\"1\"}") : jp; - default: throw new ArgumentException("input " + input); - } - } - - static bool Validated(Entry e) => e.Kind.StartsWith("validated"); - - /// - /// The oracle "JSON parity" (differential) as L01's checks, three-sided (Sides): the value object's write (3) against the wrapped twin in - /// the same shape under the same options (2), held to the twin under the application's options less TypeKit's converters (1), as - /// the-underlying-types-json, or as-a-dictionary-key-too where the value object is a dictionary key; and the read of the twin's document - /// with the row's input.json, read-as-the-underlying-type-reads, alike. L01 promises the underlying type's JSON, so side (1) runs on every - /// row. Under an application's converter for the value object, which writes it instead of the generated one, the read is that - /// converter's own document read back. Every check runs; returns the first failure. - /// - public static string? Check(Row r, Entry e, JsonSerializerOptions o, string position, string containing, string input, JsonSerializerOptions? oPlain = null) - { - oPlain ??= o; - var plain = e.Valid(); - var voV = Make.Vo(e, plain); - var (hp, hv) = Sides.Twins(position, containing, e, plain, voV); - // Input equivalence of the options: the two sides may differ only by the substituted type, not in options (the shapes: Sides.Twins). - if (Equivalence.Options(oPlain, o, allowConverters: e.Kind == "closed-set") is { } whyOptions) { r.Outcome("harness-error", "inputs not equivalent: " + whyOptions); return null; } - var one = Sides.WithoutTypeKit(oPlain); - var w1 = Sides.Write(hp, one); var w2 = Sides.Write(hp, oPlain); var w3 = Sides.Write(hv, o); - var write = position == "dictionary-key" ? "as-a-dictionary-key-too" : "the-underlying-types-json"; - const string read = "read-as-the-underlying-type-reads"; - string? fw, fr; - if (r.Get("json.Converters") == "own-for-value-object") - { - // "Your own converter wins" (AspNetCore README#what-the-document-says): the application's converter writes the value object - // instead of the generated one, so the twin's bytes are none of its. claims.json declares the write inapplicable there. - fw = r.Check(write, Baseline.Twin, c => c.Inapplicable(Cite.Docs("src/CodoMetis.TypeKit.AspNetCore/README.md#what-the-document-says"), "write")); - fr = r.Check(read, Baseline.RoundTrip, c => Sides.Interferes(w1, w2) ?? OwnVoRead(c, e, hp, hv, oPlain, o, w3.Value, w3.Thrown, w2.Thrown)); - return fw ?? fr; - } - fw = Sides.Check(r, write, Baseline.Twin, Sides.Framework(r, e, hp, one, w1, w3), w3, w1, w2, c => Write(c, e, position, w2, w3)); - if (e.Wrapped == "byte" && position == "array-element") - fr = r.Check(read, Baseline.Twin, c => c.Inapplicable(Cite.NotPromised("a-byte-array-is-base64"), "read")); - else if (e.Kind == "closed-set" && position == "dictionary-key" && r.Get("json.DictionaryKeyPolicy") is not (null or "default")) - fr = r.Check(read, Baseline.Twin, c => c.Inapplicable(Cite.NotPromised("a-closed-set-key-is-its-name"), "read")); - else if (w2.Value is not { } jp) - fr = r.Check(read, Baseline.Twin, c => c.Inconclusive("read: the wrapped type is not written under these options, so there is no document to read")); - else - { - var text = Input(input, e, oPlain, jp, position); - var r1 = Sides.Read(text, hp, one); var r2 = Sides.Read(text, hp, oPlain); var r3 = Sides.Read(text, hv, o); - fr = Sides.Check(r, read, Baseline.Twin, Sides.Framework(r, e, hp, one, r1, r3), r3, r1, r2, c => Read(c, e, position, input, text, jp, r2, r3)); - } - return fw ?? fr; - } - - /// The value object's document (3) is the wrapped twin's (2), byte for byte, in the same shape under the same options; (1) and (3) refusing alike is decided before (Sides). - static string? Write(Check c, Entry e, string position, Sides.Answer p, Sides.Answer v) - { - // System.Text.Json writes byte[] as base64 and an array of value objects over byte as a JSON array (KB-038); claims.json declares it - if (e.Wrapped == "byte" && position == "array-element" && p.Value != v.Value) return c.Inapplicable(Cite.NotPromised("a-byte-array-is-base64"), "write"); - if (p.Refused && v.Refused) - // Both refused, not alike (Sides.Alike): evidence about refusing, not about serializing, and nothing to compare. - return c.Inconclusive($"write: both refuse, not alike: the wrapped type {p}, the value object {v}"); - if (!p.Refused && v.Refused) - { - if (c.Is("json.ReferenceHandler", "Preserve") && e.Wrapped == "own-record-class" && v.Thrown is NotSupportedException) return c.Refused(Cite.NotPromised("preserved-references-over-a-walked-class"), "write"); - return $"wrapped serialized ({p.Value}) but the value object threw {v.Thrown!.GetType().Name}: {v.Thrown.Message}"; - } - if (p.Refused) return $"value object serialized ({v.Value}) where the wrapped type threw {p.Thrown!.GetType().Name}: {p.Thrown.Message}"; - // a closed set travels as its name, which no key policy renames; claims.json declares it - if (p.Value != v.Value && e.Kind == "closed-set" && position == "dictionary-key" && c.Get("json.DictionaryKeyPolicy") is not (null or "default")) return c.Inapplicable(Cite.NotPromised("a-closed-set-key-is-its-name"), "write"); - if (p.Value != v.Value) return $"JSON differs: wrapped {Cut(p.Value)} vs value object {Cut(v.Value)}"; - c.Note(NoteKeys.Compared, "write"); - return null; - } - - /// - /// The wrapped twin's document, with the row's input.json, read into both shapes (and what each read written again): each reads it as the - /// other does, or refuses as a document says; (1) and (3) refusing alike is decided before (Sides). - /// - static string? Read(Check c, Entry e, string position, string input, string text, string jp, Sides.Answer p, Sides.Answer v) - { - var stored = c.Get("json.Converters") == "StoredJsonConverterFactory"; - if (p.Refused && v.Refused) return c.Inconclusive($"read {input}: both refuse, not alike: the wrapped type {p}, the value object {v}"); - if (!p.Refused && v.Refused) - { - var xv = v.Thrown!; - if (c.Is("json.ReferenceHandler", "Preserve") && e.Wrapped == "own-record-class" && xv is NotSupportedException) return c.Refused(Cite.NotPromised("preserved-references-over-a-walked-class"), "read"); - // The documented refusals, each the JsonException the generated converter throws. - if (!(xv is JsonException) && ((Validated(e) && input == "refused-by-create" && !stored) || (input == "null" && e.Vo.IsValueType) || (e.Kind == "closed-set" && input != "valid"))) - return $"input {input}: the refusal is {xv.GetType().Name}, not JsonException: {Cut(xv.Message)}"; - if (Validated(e) && input == "refused-by-create" && !stored) return c.Refused(Cite.NotPromised("a-validated-value-object-refuses-what-create-refuses"), $"read {input}"); - if (input == "null" && e.Vo.IsValueType) return c.Refused(Cite.NotPromised("a-struct-refuses-a-json-null"), $"read {input}"); - if (e.Kind == "closed-set" && input != "valid") return c.Refused(Cite.Docs("src/CodoMetis.TypeKit.Generators/README.md#matching-parsing-and-binding"), $"read {input}"); // "Unknown names are rejected." - return $"input {input}: wrapped read it, value object threw {xv.GetType().Name}: {Cut(xv.Message)}\n text={Cut(text)}"; - } - // a reference-type value object takes JSON null as null, as any class does - if (p.Refused && input == "null" && Make.AdmitsNull(e.Vo) && !Make.AdmitsNull(e.Plain)) return c.Inapplicable(Cite.Docs("docs/json.md#null-and-missing"), "read null"); - if (p.Refused) return $"input {input}: value object read what the wrapped type refused ({p.Thrown?.GetType().Name}: {Cut(p.Thrown?.Message)})\n text={Cut(text)}"; - if (Validated(e) && input == "refused-by-create" && text != jp && !stored) - return $"validated value object accepted the refused value{(position == "dictionary-key" ? " as a dictionary key" : "")}: {Cut(text)}"; - if (p.Value != v.Value) return $"input {input}: read-back differs: wrapped {Cut(p.Value)} vs value object {Cut(v.Value)}"; - c.Note(NoteKeys.Compared, "read " + input); - return null; - } - - /// - /// Under an application's converter for the value object, the generated converter does not run: the value object's document is that - /// converter's, and it reads back as written under the row's options. Where the value object's document cannot be written, a converter - /// the application registers for the wrapped type at the same position is the baseline. - /// - static string? OwnVoRead(Check c, Entry e, Held hp, Held hv, JsonSerializerOptions oPlain, JsonSerializerOptions o, string? jv, Exception? ev, Exception? ep) - { - var oOwn = new JsonSerializerOptions(oPlain); - oOwn.Converters.Insert(0, (System.Text.Json.Serialization.JsonConverter)Activator.CreateInstance(typeof(OwnWrappedConverter<>).MakeGenericType(Make.Held(e.Plain)), JsonRow.Inner(e))!); - var (jo, eo) = Ser(hp, oOwn); - if (ev is not null) - { - // System.Text.Json refuses any custom converter there (MaxDepth counts its value one level deeper, KB-040), the wrapped - // type's under a converter of the application's alike - if (ep is not null || (eo is not null && eo.GetType() == ev.GetType())) return c.Inconclusive($"the application's converter cannot write here, for the wrapped type too: {ev.GetType().Name}"); - return $"own VO converter row: VO serialization threw {ev.GetType().Name}: {ev.Message}"; - } - c.Note(NoteKeys.OwnVo); - var (back, eb) = De(jv!, hv, o); - if (eb is not null) - { - // the same converter for the wrapped type, at the same position: its own document does not read back under these options either - var ebOwn = jo is null ? eo : De(jo, hp, oOwn).Ex; - if (ebOwn is not null && ebOwn.GetType() == eb.GetType()) return c.Inconclusive($"the application's converter's document does not read back under these options, for the wrapped type too: {eb.GetType().Name}"); - return "own VO converter: read-back threw " + eb.GetType().Name + ": " + eb.Message; - } - if (back != jv) return $"own VO converter round trip differs: {jv} vs {back}"; - return null; - } - static string Cut(string? s) => s is null ? "(null)" : s.Length > 200 ? s[..200] + "..." : s; -} - -public static class EntryExt -{ - public static object? Refused(this Entry e) => e.Kind.StartsWith("validated") ? e.RefusedFn() : null; -} diff --git a/tools/probe/corpus/harness/PreserveGuard.cs b/tools/probe/corpus/harness/PreserveGuard.cs deleted file mode 100644 index 2f046f3d..00000000 --- a/tools/probe/corpus/harness/PreserveGuard.cs +++ /dev/null @@ -1,252 +0,0 @@ -// Claim C10-preserve-guard (src/CodoMetis.TypeKit.Generators/README.md#json): "Preserved references (ReferenceHandler.Preserve) throw a -// NotSupportedException where the serializer could write $id or $ref inside the underlying value. That's a class it walks as an object [...] -// These are unaffected: a value the serializer writes with a value converter (a number, a string, a Guid, a Uri), anything a converter of -// your own writes, on the options or on one property, a struct of such values, and ReferenceHandler.IgnoreCycles." -// Oracle: claim for the guarded rows (a value object over a class the serializer walks, under Preserve, with no converter of the -// application's for it: NotSupportedException naming the type and Preserve, both directions, never a document); differential for the -// unaffected rows (the value object's document is the wrapped type's under the same options, never an $id twice, and every read agrees -// with the wrapped type's, a refusal being the section's: a JsonException naming the value object, with no inner exception). -using System.Text.Json; -using Probes.Shapes; -namespace Probes.Json; - -public static class PreserveGuard -{ - public static string? Check(Row r) - { - var handler = r["handler"]; - var want = handler == "none" ? "default" : handler; - var row = r; - if (r.Get("json.ReferenceHandler") is { } jr && jr != want) - { - // one setting under two names: the claim's handler decides (claims.json excludes the differing pairs) - r.Substituted("json.ReferenceHandler", want, "handler is the same setting"); - row = r.With("json.ReferenceHandler", want); - } - var kind = r["shape.kind"]; - var e = kind == "closed-set" ? Registry.Get(kind, "-") : Registry.Get(kind, r["shape.wrapped"]); - var position = r["shape.position"]; - var containing = position == "root" ? "class" : r["shape.containing"]; - _ = r["input.json"]; // the row's input, which every check of the row runs under; the reads apply it - var plain = e.Valid(); var voValue = Make.Vo(e, plain); - var (hp, hv) = Sides.Twins(position, containing, e, plain, voValue); - var o = JCtx.Apply(row, e, hp.Declared, hv.Declared); - // A closed set travels as its name, which no naming policy renames and no converter for strings writes (docs/closed-sets.md). - var op = kind == "closed-set" && (row.Get("json.DictionaryKeyPolicy") is not (null or "default") || row.Is("json.Converters", "own-for-wrapped")) - ? JCtx.Apply(row.With("json.DictionaryKeyPolicy", "default").With("json.Converters", row.Is("json.Converters", "own-for-wrapped") ? "default" : row["json.Converters"]), e, hp.Declared, hv.Declared) - : o; - var ownWrapped = row.Is("json.Converters", "own-for-wrapped"); - var ownVo = row.Is("json.Converters", "own-for-value-object"); - var guarded = want == "Preserve" && e.Wrapped == "own-record-class" && !ownWrapped && !ownVo; - // The obligation the row's handler and converters select: a converter of the application's, the guarded class under Preserve, - // IgnoreCycles, and otherwise a value the serializer writes with a value converter, under Preserve or with no handler at all. - var obligation = ownWrapped || ownVo ? "own-converters-unaffected" : guarded ? "refused-where-references-could-be-written" - : want == "IgnoreCycles" ? "ignore-cycles-unaffected" : "value-converters-unaffected"; - return guarded ? Guarded(r, obligation, e, hp, hv, o) : Unaffected(r, obligation, e, hp, hv, op, o, ownVo); - } - - /// - /// The guarded rows: NotSupportedException naming the wrapped type and Preserve, in both directions, never a document. The read of the - /// wrapped type's document is three-sided (Sides): where the twin without TypeKit refuses it alike, the serializer refused the document - /// before any converter ran. - /// - static string? Guarded(Row r, string obligation, Entry e, Held hp, Held hv, JsonSerializerOptions o) - { - var wrapped = Make.Held(e.Plain); - string? Refusal(Exception? x, string what) - { - if (x is not NotSupportedException) return $"{what}: expected NotSupportedException naming {wrapped.Name} under ReferenceHandler.Preserve, got {(x is null ? "no exception" : Jx.Ex(x))}"; - if (!x.Message.Contains(wrapped.FullName!) || !x.Message.Contains("ReferenceHandler.Preserve")) return $"{what}: the NotSupportedException does not name {wrapped.FullName} and ReferenceHandler.Preserve: {x.Message}"; - return null; - } - var (jv, xv) = Jx.Ser(hv, o); - var (jp, xp) = Jx.Ser(hp, o); - var fw = r.Check(obligation, Baseline.Refusal, c => - { - if (jv is not null) - { - // the options may leave the member out of the document, for the wrapped type too: then no converter ran, and nothing was refused - if (jp is not null && !Jx.Tokens(jp).Any(t => t.Text == "x") && !Jx.Tokens(jv).Any(t => t.Text == "x")) - { c.Note(NoteKeys.JsonMemberLeftOutByOptions, "write: " + Jx.Cut(jv)); return c.Inconclusive("write: the options leave the member out, for the wrapped type too: " + Jx.Cut(jv)); } - return Refusal(null, "write") + $"; it wrote {Jx.Cut(jv)}" + (DuplicateId(jv) is { } dup ? $" with {dup} twice" : ""); - } - if (Refusal(xv, "write") is { } f) return f; - c.Note(NoteKeys.Compared, "write refused"); - return null; - }); - if (xp is not null) - return fw ?? r.Check(obligation, Baseline.Refusal, c => c.Inconclusive("read: the wrapped type's document is refused under these options, so there is none to read: " + Jx.Ex(xp))); - // reading: the wrapped type's own document, with the row's input applied - var input = r["input.json"]; - var text = JsonParity.InputFor(input, e, Jx.Full(o), Jx.Ser(hp, Jx.Full(o)).Json ?? jp!, r["shape.position"]); - var (vp, ep) = Jx.De(text, hp.Declared, o); - var (vv, ev) = Jx.De(text, hv.Declared, o); - var one = Sides.WithoutTypeKit(o); - var r1 = new Sides.Answer("read", null, Jx.De(text, hp.Declared, one).Ex); - var r3 = new Sides.Answer("read", null, ev); - var fr = Sides.Check(r, obligation, Baseline.Refusal, r1.Refused && Sides.Alike(r1, r3) ? Sides.Measured(r1, "the twin's read under the application's options, less TypeKit's converters") : null, r3, null, null, c => - { - if (ev is null) - { - // no converter ran: the read holds none of the wrapped value (a JSON null for a class, a member the options do not read) - if (vv is not null && Jx.Tokens(JsonSerializer.Serialize(vv, hv.Declared, Jx.Plain)).Any(t => t.Text == "x")) - return $"read {input}: the value object over {Make.Held(e.Plain).Name} read a document under Preserve: {Jx.Cut(text)}"; - c.Note(NoteKeys.JsonMemberLeftOutByOptions, "read " + input); - return c.Inconclusive($"read {input}: no converter ran, the read holds none of the wrapped value"); - } - if (ev is NotSupportedException) { if (Refusal(ev, "read " + input) is { } f) return f; c.Note(NoteKeys.Compared, "read " + input + " refused"); return null; } - // refused before the guard: a JsonException naming the value object, with no inner exception (Generators README#json) - if (ev is not JsonException || ev.InnerException is not null) return Refusal(ev, "read " + input) + $"\n text={Jx.Cut(text)}"; - if (!ev.Message.Contains(Make.Held(e.Vo).Name)) return Refusal(ev, "read " + input) + $"\n text={Jx.Cut(text)}"; - c.Note(NoteKeys.Compared, "read " + input + ": refused naming the value object before the guard"); - return null; - }); - return fw ?? fr; - } - - /// - /// The unaffected rows, three-sided (Sides; C10 promises these are unaffected, so side (1) runs on every row): the value object's - /// document (3) is the wrapped type's under the same options (2), which is the twin's without TypeKit's converters (1), never an $id - /// twice, and its read agrees with the wrapped type's (ReadAlike); under a converter of the application's for the value object, that - /// converter's document reads back and reads the row's input alike with and without the reference handler. - /// - static string? Unaffected(Row r, string obligation, Entry e, Held hp, Held hv, JsonSerializerOptions op, JsonSerializerOptions o, bool ownVo) - { - var one = Sides.WithoutTypeKit(op); - var w1 = Sides.Write(hp, one); var w2 = Sides.Write(hp, op); var w3 = Sides.Write(hv, o); - var (jp, xp) = (w2.Value, w2.Thrown); var (jv, xv) = (w3.Value, w3.Thrown); - // byte[] is base64 by the serializer's own rule (KB-038), an array of value objects a JSON array: unaffected means the value - // object's document reads back as written - var byteArray = e.Wrapped == "byte" && r.Is("shape.position", "array-element") && jv is not null && jp is not null && jv != jp; - var written = Sides.Framework(r, e, hp, one, w1, w3); - var fw = Sides.Check(r, obligation, ownVo || byteArray ? Baseline.RoundTrip : Baseline.Twin, written, w3, w1, w2, c => - { - if (xp is not null && xv is not null) return $"write: both threw, not alike: the wrapped type {w2}, the value object {w3}"; - if (xv is not null) return $"write: the value object threw {Jx.Ex(xv)} where the wrapped type wrote {Jx.Cut(jp)}"; - // the application's converter for the value object writes its own document: its baseline is that document read back, whatever - // the twin's writes ("anything a converter of your own writes" is unaffected) - if (xp is not null && !ownVo) return $"write: the value object wrote {Jx.Cut(jv)} where the wrapped type threw {Jx.Ex(xp)}"; - if (DuplicateId(jv!) is { } dup) return $"write: $id {dup} twice in {Jx.Cut(jv)}"; - if (ownVo) - { - c.Note(NoteKeys.OwnVo); // the application's converter for the value object writes its own document; it reads it back, unaffected - var (jf, _) = Jx.Ser(hv, Jx.Full(o)); - var (_, xr) = Jx.De(jf ?? jv!, hv.Declared, o); - if (xr is not null) return "own converter for the value object: its document does not read back: " + Jx.Ex(xr); - return null; - } - if (byteArray) - { - var (back, xb) = Jx.De(jv!, hv.Declared, o); - if (xb is not null) return "write: the array of byte value objects does not read back: " + Jx.Ex(xb); - var again = JsonSerializer.Serialize(back, hv.Declared, o); - if (again != jv) return $"round trip: {Jx.Cut(jv)} read back as {Jx.Cut(again)}"; - c.Note(NoteKeys.Compared, "an array of byte value objects round-trips as a JSON array"); - return null; - } - if (jv != jp) return $"write: the value object wrote {Jx.Cut(jv)}, the wrapped type {Jx.Cut(jp)}"; - c.Note(NoteKeys.Compared, "write"); - return null; - }); - if (ownVo) return fw ?? OwnReadsInput(r, obligation, e, hp, hv, o); - // the wrapped type's base64 document is no array of value objects (KB-038): the round trip above holds the value object to its own - if (byteArray) return fw ?? r.Check(obligation, Baseline.Twin, c => c.Inapplicable(Cite.Fact("KB-038"), "read: the wrapped type's document is a base64 string")); - // the value object's document is refused as the framework refuses it, so is its read: the write's refusal, as it is - if (written is not null && Sides.Alike(written.Answer, w3)) return fw ?? Sides.Check(r, obligation, Baseline.Twin, written, w3, null, null, _ => (string?)null); - var full = Jx.Ser(hp, Jx.Full(op)).Json ?? jp; - if (full is null) return fw ?? r.Check(obligation, Baseline.Twin, c => c.Inconclusive("read: the wrapped type is not written under these options, so there is no document to read")); - var input = r["input.json"]; - var text = JsonParity.InputFor(input, e, Jx.Full(op), full, r["shape.position"]); - var r1 = Sides.Read(text, hp, one); var r2 = Sides.Read(text, hp, op); var r3 = Sides.Read(text, hv, o); - var fr = Sides.Check(r, obligation, Baseline.Twin, Sides.Framework(r, e, hp, one, r1, r3), r3, r1, r2, c => ReadAlike.Check(c, e, input, text, r2, r3, hp, hv, op, o)); - return fw ?? fr; - } - - /// - /// The application's converter for the value object reads the row's input inside its own spelling ("vo:" and the wrapped - /// type's JSON) alike under the row's reference handler and under none: "anything a converter of your own writes" is unaffected - /// (Generators README#json). Each side writes its own document, so Preserve's metadata is its own, and only the value is rewritten. - /// Where the handler's document is refused as the framework refuses a converter's value (KB-040), the check is that refusal. - /// - static string? OwnReadsInput(Row r, string obligation, Entry e, Held hp, Held hv, JsonSerializerOptions o) - { - var input = r["input.json"]; - var inner = JsonRow.Inner(e); - var wrapped = JsonSerializer.Serialize(Make.Unwrap(e, Make.Vo(e, e.Valid())), Make.Held(e.Plain), inner); - var value = "vo:" + JsonParity.InputFor(input, e, inner, wrapped, "root"); - var bare = new JsonSerializerOptions(o) { ReferenceHandler = null }; - (string? Read, string? Refused, Sides.Answer? Write) Through(JsonSerializerOptions x) - { - var w = Sides.Write(hv, Jx.Full(x)); - if (w.Refused) return (null, "write: " + w.Thrown!.GetType().Name, w); - var own = Jx.Tokens(w.Value!).Where(t => t.Type is JsonTokenType.String or JsonTokenType.PropertyName && t.Text is { } s && s.StartsWith("vo:", StringComparison.Ordinal)).ToList(); - if (own.Count == 0) return (null, null, null); - var (v, rx) = Jx.De(Jx.Rewrite(w.Value!, own, _ => JsonSerializer.Serialize(value)), hv.Declared, x); - if (rx is not null) return (null, "read: " + rx.GetType().Name, null); - return (JsonSerializer.Serialize(v, hv.Declared, bare), null, null); - } - var handled = Through(o); var unhandled = Through(bare); - // the handler's document, written by the application's converter, refused as the framework refuses any converter's value there - var framework = (handled.Write ?? unhandled.Write) is { } refused ? Sides.WrittenByAConverter(r, e, hp, Sides.WithoutTypeKit(Jx.Full(handled.Write is null ? bare : o)), refused) : null; - return Sides.Check(r, obligation, Baseline.RoundTrip, framework, (handled.Write ?? unhandled.Write) ?? new Sides.Answer("write", null), null, null, c => - { - if (handled.Read is null && handled.Refused is null && unhandled.Read is null && unhandled.Refused is null) - { c.Note(NoteKeys.JsonMemberLeftOutByOptions, "own converter: the options write no member"); return c.Inconclusive("own converter: the options write no member to read"); } - if (handled.Read != unhandled.Read || handled.Refused != unhandled.Refused) - return $"read {input} through the application's converter: {handled.Read ?? handled.Refused ?? "no member"} under ReferenceHandler {c["handler"]}, {unhandled.Read ?? unhandled.Refused ?? "no member"} without one"; - c.Note(NoteKeys.Compared, $"read {input} through the application's converter, alike with and without the reference handler: {Jx.Cut(handled.Read ?? handled.Refused)}"); - return null; - }); - } - - /// The first $id value a document holds twice, or null. - public static string? DuplicateId(string json) - { - var t = Jx.Tokens(json); var seen = new HashSet(); - for (var i = 0; i + 1 < t.Count; i++) - if (t[i].Type == JsonTokenType.PropertyName && t[i].Text == "$id" && !seen.Add(t[i + 1].Text ?? t[i + 1].Raw)) return t[i + 1].Text; - return null; - } -} - -/// -/// One read of the same text into the wrapped type's shape (2) and the value object's (3), each written again to be compared: they agree, or -/// differ only as the documents say (a struct value object refuses a JSON null, a sealed record reads it as null, a validated one refuses what -/// Create refuses, a closed set has only its members); a refusal of the value object's is a JsonException naming it, with no inner exception -/// (Generators README#json). Side (1) refusing alike with (3) is decided before (Sides). -/// -public static class ReadAlike -{ - public static string? Check(Check c, Entry e, string input, string text, Sides.Answer p, Sides.Answer v, Held hp, Held hv, JsonSerializerOptions op, JsonSerializerOptions ov) - { - var voName = Make.Held(e.Vo).Name; - string? Named(Exception x) => x is JsonException && x.Message.Contains(voName) && x.InnerException is null ? null - : $"read {input}: the value object's refusal is {Jx.Ex(x)}{(x.InnerException is null ? "" : " with an inner exception")}, not a JsonException naming {voName}\n text={Jx.Cut(text)}"; - var stored = c.Is("json.Converters", "StoredJsonConverterFactory"); - if (!p.Refused && !v.Refused) - { - if (e.Kind.StartsWith("validated") && input == "refused-by-create" && !stored && e.Refused() is not null && text != Jx.Ser(hp, op).Json && !c.Is("shape.position", "dictionary-key")) - return $"read {input}: the validated value object read what Create refuses\n text={Jx.Cut(text)}"; - if (p.Value != v.Value) return $"read {input}: read back differs: wrapped {Jx.Cut(p.Value)} vs value object {Jx.Cut(v.Value)}\n text={Jx.Cut(text)}"; - c.Note(NoteKeys.Compared, "read " + input); return null; - } - if (p.Refused && v.Refused) - { - if (v.Operation != "read") return $"read {input}: both refuse, not alike: the wrapped type {p}, the value object {v}"; - if (Named(v.Thrown!) is { } f) return f + $"; the wrapped type: {p}"; - c.Note(NoteKeys.Compared, "read " + input + ": both refuse, the value object naming itself"); return null; - } - if (v.Refused) - { - var intended = v.Operation == "read" && ((input == "null" && e.Vo.IsValueType) || (e.Kind.StartsWith("validated") && input == "refused-by-create" && !stored) || (e.Kind == "closed-set" && input != "valid")); - if (!intended) return $"read {input}: the wrapped type read it, the value object refused: {v} {Jx.Ex(v.Thrown!)}\n text={Jx.Cut(text)}"; - if (Named(v.Thrown!) is { } f) return f; - c.Note(NoteKeys.Compared, "read " + input + ": refused as documented"); return null; - } - // the wrapped type refused and the value object read: only a JSON null for a sealed record, which reads it as any class does - if (input == "null" && Make.AdmitsNull(e.Vo) && !Make.AdmitsNull(e.Plain) && Jx.De(text, hv.Declared, ov).Value is { } read - && Jx.Tokens(JsonSerializer.Serialize(read, hv.Declared, Jx.Plain)).Any(t => t.Type == JsonTokenType.Null)) - { c.Note(NoteKeys.Compared, "read null: the sealed record reads null, as any class does"); return null; } - return $"read {input}: the value object read what the wrapped type refused ({p})\n text={Jx.Cut(text)}"; - } -} diff --git a/tools/probe/corpus/harness/Registry.cs b/tools/probe/corpus/harness/Registry.cs deleted file mode 100644 index abe2a1d8..00000000 --- a/tools/probe/corpus/harness/Registry.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Hand half of the shape registry (see gen_shapes.py). Looks an entry up by the row's shape.kind and shape.wrapped. -namespace Probes.Shapes; -public static partial class Registry -{ - public static readonly List All = Build(); - static List Build() { var e = new List(); Fill(e); return e; } - static partial void Fill(List e); - /// The entry a row names. record-class (CMTK1006) and over-value-object (CMTK1005) are refused at build, verified; the row's other axes are - /// still probed on the nearest buildable kind. - public static Entry Of(Row r) - { - var k = r["shape.kind"]; - if (k is "record-class" or "over-value-object") { k = k == "record-class" ? "sealed-record-class" : "record-struct"; r.Substituted("shape.kind", k, "the generators refuse the requested kind"); } - var e = Get(k, r["shape.wrapped"]); - if (r.Is("http.nullability", "nullable")) - { - // The parameter or body declared nullable on both sides (T? against wrapped?): the dimension G1 exposed. - static Type N(Type t) => t.IsValueType && Nullable.GetUnderlyingType(t) is null ? typeof(Nullable<>).MakeGenericType(t) : t; - r.Note(NoteKeys.BindingNullable); - e = e with { Vo = N(e.Vo), Plain = N(e.Plain) }; - } - return e; - } - public static Entry Get(string kind, string wrapped) => - kind == "closed-set" ? All.First(x => x.Kind == "closed-set") - : All.First(x => x.Kind == kind && x.Wrapped == wrapped); -} diff --git a/tools/probe/corpus/harness/ReplayProbe.cs b/tools/probe/corpus/harness/ReplayProbe.cs deleted file mode 100644 index 07249dad..00000000 --- a/tools/probe/corpus/harness/ReplayProbe.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Debug aid (not a claim): PROBE_REPLAY="rowsfile:idx" re-runs the baseline for one row and writes its exchange log to /tmp/replay.txt. -using Probes.Shapes; -namespace Probes; -public sealed class ReplayProbe -{ - [Fact] - public async Task Replay() - { - var spec = Environment.GetEnvironmentVariable("PROBE_REPLAY"); if (spec is null) return; - var parts = spec.Split(':'); var r = Rows.Get(parts[0], int.Parse(parts[1])); - var f = await HttpBaseline.Run(r, Registry.Of(r)); - File.WriteAllText("/tmp/replay.txt", r.ToString() + "\nRESULT: " + (f ?? "pass") + "\nNOTES: " + r.Notes + "\n" + r.Log); - } -} diff --git a/tools/probe/corpus/harness/Row.cs b/tools/probe/corpus/harness/Row.cs deleted file mode 100644 index 79703c65..00000000 --- a/tools/probe/corpus/harness/Row.cs +++ /dev/null @@ -1,592 +0,0 @@ -// Row plumbing shared by every probe: each probe's rows are its own file, written by `prober rows --probe P` (the corpus's -// rows/P.json.gz, unpacked by the replay to Probes/rows/P.json); each probe records one line per row to $PROBE_OUT/