Repository navigation
build: answer the gate's refusals with rows, declarations and exclusions; the gate passes - #62
Merged
Merged
Conversation
…tches
C22GeneratorRefusalsProbe builds its consumer in a child process, so the
coverage report of its own process shows no file under src/, and
`prober footprint` refused to record an empty footprint ("it would never go
stale"), however many paths its registry entry watched. With no footprint
the probe was never current, and the gate counted all 621 of
C22-generator-refusals' pairs uncovered.
`footprint` now records an empty footprint where the entry watches
something, and refuses only where nothing ran and nothing is watched; a
footprint is current by its watched paths when it ran nothing under src/.
C22's entry watches what its consumer compiles against: the base package,
the analyzers it carries, the generators, and src/Directory.Build.* (it
watched the first and the last two, as C18 does, and lacked the generators
and the analyzers).
Recovers 607 of C22's 621 pairs, the rest of what its rows hold; its
other 14 pairs had no row and get rows with the scattered pairs.
Tests: WatchedTests gains a probe that ran nothing under src/ (recorded by
what it watches, current, and stale when a watched path changes) and one
that also watches nothing (refused). Each fails with its half of the change
reverted, and the refusal test fails with the refusal removed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for the rest of C12, C13, C16 and C21 Decision 108 stopped crediting checks that compared nothing but a document both hosts refuse, which left 821 pairs of C12, 48 of C13, 455 of C16 and 677 of C21 uncovered. Declarations (claims.json, `inapplicable`, cite record:0099): - json.ReferenceHandler=Preserve on every obligation of C12, C16 and C21, and on C13's two document obligations (doc-required-where-rejected, doc-optional-where-absent); absent-is-default reads the wire and stays wanted there. Measured at 938d8f8 from an empty state: every row of the four probes under Preserve had its document refused by ASP.NET alone too (C12 76, C13 71, C16 93, C21 63 rows), none written. - json.MaxDepth=3 together with source IDescribedJsonConverter or JsonSchemaDescriptions on C12's four obligations: the coord host's document is refused by ASP.NET alone in every such row (106 rows at 938d8f8, 166 after the new rows, none written), while under the decimal-converter source it is written in every row (29 and 55). No declaration under json.MaxDepth=3 alone: the documents of C12's decimal host, of C13 (47 rows), C16 (91) and C21 (59) are written and compared there, so it would not be true, and its pairs were covered already. Rows: `rows --probe` for C12, C13, C16 and C21 (C13's came out the same, since Preserve stays wanted by absent-is-default), then rows from `rows --claim` appended until the pairs converged: C12 302 -> 462 rows, C13 296 -> 321, C16 298, C21 295 -> 435. Under MaxDepth=3 without Preserve about two thirds of the documents are refused for ASP.NET alone too, decided by the depth of the row's shape rather than by an axis, so those pairs needed further rows rather than a declaration. Recovers C12 821 (647 by rows, 174 declared), C13 48, C16 455 (283 by rows, 172 declared), and 664 of C21's 698 (498 by rows, 166 declared). C21's regenerated rows fail in 8 rows and its appended rows in 2 more; their triage is in the next commits and in the pull request. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…bject admits null and ASP.NET drops it Decision 36: "A nullable value object admits null in the OpenAPI document wherever it appears". C21 quoted it as `a-class-value-object-admits-null` for the class kinds only; a nullable struct value object admits null the same way, so the entry `a-nullable-value-object-admits-null` quotes the same sentence for http.nullability=nullable. Triage step 3 of row 216 of C21OpenapiSchemaParityProbe (a validated struct over double, nullable, in a read-only list, under AllowNamedFloatingPointLiterals): ASP.NET writes the items of the twin's IReadOnlyList<double?> without null, on the host without TypeKit as well, and the value object's items are its component or null, as decision 36 says; the schemas are otherwise the same. No finding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…at, decision 36 for an added null, and cannot tell a form-bound record class Triage of the rows C21OpenapiSchemaParityProbe failed after its rows were written again; each failed in three runs at 938d8f8 (two replays and a try). - Rows 113 and 282 (triage 2, KB-001): a class value object over TimeOnly and over char at the root, nullable, under OpenAPI 2.0. The minimal schema endpoint's twin body is TimeOnly? / char?, which ASP.NET writes as its format and allOf [{x-nullable: true}] alone, on the host without TypeKit as well; the class value object's body is not nullable in a minimal API and keeps its schema. KB-001 (executable, KB001.cs) says a nullable body is written as "its format and allOf: [{"x-nullable": true}]"; the harness cited not-promised openapi-2-nullable-body-keeps-only-its-null only where the body kept nothing but its null (an enum), and now cites it where it keeps its format too. - Row 216 (triage 3, decision 36): the value object admits null where ASP.NET writes the twin's nullable type without it, the schemas otherwise the same: cites a-nullable-value-object-admits-null (previous commit). - Row 62 (triage 1): a validated class over a record class, bound from an MVC form. ASP.NET binds the wrapped record class by its properties (A, B) and the value object otherwise (Value.A, Value.B); the harness already ended parameters that differ this way inconclusive, and now does the same for a form body. Rows 38, 170, 184, 196, 330, 358, 386, 408, 415 and 422 still fail; the pull request carries their triage (code-analyst hand-offs and the harness gaps left). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hey substituted The stored rows of C17Cmtk0014Probe and C19Cmtk0010KindsProbe put shape.refused-kind values in rows whose other settings exclude them; the probes substituted another kind there and credited values the row did not run. `rows --probe` now leaves such an axis out of the row (decision 108), so both files are written again whole: C17 283 -> 295 rows (14 leave an axis out), C19 282 -> 297 (14 leave an axis out). Both replay with every row passing. Recovers C17-cmtk0014's 41 pairs and C19-cmtk0010-kinds' 50. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, and its JSON check reads a value of another kind L02 (README "Rejections never repeat the input") left 74 pairs uncovered, 6 of them json.Converters=own-for-wrapped|own-for-value-object against text.entry=TryFrom|ToString-format|TryFormat-short-span: in such a row the JSON check is declared inapplicable (not-promised the-applications-own-converter) and nothing else ran. What is true there, and so what this commit says: TryFrom, ToString-format and TryFormat-short-span reject no text. TryFrom answers None, and formatting reads no input; the Generators README's "When text is rejected" names the rejections, a FormatException from Parse and false from TryParse. The probe already runs its parsing checks only for Parse, TryParse, IParsable, ISpanParsable and the type converter (TextRow.Reads), which are the `axes` both obligations list. So parsing-never-repeats and no-inner-that-quotes declare themselves inapplicable at those three entries (cite docs:src/CodoMetis.TypeKit.Generators/README.md#when-text-is-rejected). The 6 pairs are then wanted by no obligation; every other pair of those entries stays wanted by json-never-repeats. Rows could not reach them: no check of the claim applies there. json-never-repeats placed the secret only where the wrapped value stands, as a string, and an unvalidated value object over string or Uri reads every string, so such rows ended "every JSON input read, none refused". Where every variant was read, the check now also sends an array holding the secret in that place, which such a value object refuses, and requires the refusal not to quote it (not at a dictionary key, which is a property name). 22 of the 26 rows inconclusive that way now pass, none fails. Exclusions: json.PreferredObjectCreationHandling=Populate against a reference handler, which System.Text.Json refuses (JsonRow substitutes the default), as twelve other claims exclude it; and a record class as a dictionary key, which System.Text.Json writes only through a converter of the application's (NotSupportedException for the wrapped type alike), where the JSON half is not promised, and which has no parsing. Rows: `rows --probe` (289 rows), then rows from `rows --claim` appended, and 8 rows set by hand from a passing row's settings for pairs the covering array kept placing in rows that read nothing: own-for-value-object with Parse, a record class with a wrong token and as a nullable property, Uri and TryFrom as a field (with IncludeFields), and an enum with ISpanParsable; 366 rows. Recovers all 74: 6 declared, 3 excluded, 65 by rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g, bool and Uri, and holds group-by at two levels over DateTimeOffset
E02ValueTranslatesProbe built where-value-compare with
Expression.GreaterThanOrEqual and, where that throws, substituted
where-equals ("the wrapped type has no >= operator"), so 5 pairs of
ef.query=where-value-compare never ran: string, bool, Uri, enum and flags
enum. The reason is true of the first three, which have no >= in C#, and
not of an enum, which C# compares with >= over its underlying type: an
expression tree the compiler writes for `o.Status.Value >= Status.B`
converts both sides to it.
- The probe now compares an enum (or a nullable enum) as C# does, through
the underlying type on both sides; rows 216 and 217 (an enum and a flags
enum) run where-value-compare and pass, the rows and the SQL the twin's.
- claims.json excludes where-value-compare over string, bool and Uri with
that reason.
- One group-by row for shape.site=nested-two-levels x
shape.wrapped=DateTimeOffset (row 215), and the two rows above, appended
from `rows --claim`.
Recovers all 6 of E02's pairs: 3 excluded, 3 by rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…01, L03, L04, L06 and C22 Exclusions, each with its reason: - json.PreferredObjectCreationHandling=Populate against json.ReferenceHandler=Preserve|IgnoreCycles for C03, C05, L01, L03 and L04, the reason twelve other claims already give: System.Text.Json refuses Populate with a reference handler, and JsonRow substitutes the default. Recovers C03's 2, C05's 2, L04's 2, and 2 each of L01 and L03. - C02: AsText and AsOptionalText in globalization-invariant mode, not promised (as-text-refused-in-globalization-invariant-mode): AsText() throws PlatformNotSupportedException there (docs/text.md, "Globalization- invariant mode") and AsOptionalText() calls it; the probe checks that refusal without credit and runs the row on the identifier counterpart. 2 pairs. Rows, appended from `rows --claim` and replayed: - C02: 4 rows in globalization-invariant mode (the other 5 of its 7 pairs). - L01: 3 rows (read-only-list-element x flags enum, wrong-token x enum, and a record class as a dictionary key, row 582, which ends framework-refuses), and row 584, set by hand from row 582: a record class as a dictionary key under json.Converters=own-for-wrapped, the only converter under which System.Text.Json writes a record class as a key (row 582 and every earlier row with the pair end framework-refuses, NotSupportedException for the twin alike). Recovers L01's other 3. - L03: 2 rows (polymorphic-derived-property x a record class, TimeOnly x ToString-format, a record class x Parse). Recovers L03's other 3. - L06: 1 row, field x string under IncludeFields; ProbeContext gains its carrier (Shapes.g.cs, written again by shapes.cs from L06's rows, as the generators' README says). Recovers L06's 1. - C22: 9 rows for the 14 pairs no row held once its footprint was current (shape.inheritance, shape.kind and shape.site against DateTime, DateTimeOffset, DateOnly, Uri, long and char). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d C21's obligations do not apply there Triage step 2 of row 408 of C21OpenapiSchemaParityProbe (a validated class over char as a polymorphic derived property, json.MaxDepth=3 and json.NumberHandling=WriteAsString); it failed in three runs of `try` at 53050b7. AddTypeKit() refused the document with a JsonException reading an OpenApiJsonSchema, ASP.NET alone with MaxDepth's InvalidOperationException: two refusals that differ by type, which decision 108 makes a violation unless a sentence makes them intended. Neither is TypeKit's. ASP.NET builds each schema with System.Text.Json's exporter under the host's options and reads the node back as its own OpenApiJsonSchema; a char's schema is minLength and maxLength 1, which reach the reader as strings under WriteAsString. Measured in a host without TypeKit (KB042.cs, its fixture): a body holding a char is refused so, one holding an int is written, and so is a char under the default number handling. With MaxDepth left at its default, ASP.NET alone refuses row 408's document with this same JsonException; under MaxDepth=3 it meets the depth limit first at the twin's endpoint, where TypeKit asks for the char while it describes the value object's. So no document is written for a char under WriteAsString, by either host: each obligation of C21 declares the pair json.NumberHandling=WriteAsString x shape.wrapped=char inapplicable, citing fact:KB-042. No finding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…first-use null, a 2.0 nullable element, or a library's converter Triage step 3 of rows 196, 358 and 422 of C21OpenapiSchemaParityProbe, each failing in three runs of `try` at 53050b7; the harness cites the entries in the next commit. - Row 196 (a validated struct over an enum written by name, a polymorphic derived type's property): the twin's property refers to the enum's component, which lists null because ASP.NET met it first as a nullable use, on the host without TypeKit as well; the value object's property is not nullable there and its component lists no null. KB-027 (executable) says so for every use: "met first as a nullable parameter, the component lists null among its values, for its non-nullable uses too". The entry enum-component-is-its-first-use quotes the sentence about parameters only; enum-component-lists-the-null-of-its-first-use quotes this one. - Row 358 (a nullable validated struct over bool as a dictionary's value, OpenAPI 2.0): the value object's value is its component or null, which the 2.0 writer writes as allOf [{x-nullable: true}] without the reference (KB-026), where the twin's bool? keeps its type. The AspNetCore README said so of a property and named the element the component or null "as a nullable property is", but not that it loses its type under 2.0; it says so now, and openapi-2-nullable-element-loses-its-type quotes it. - Row 422 (a nullable record struct over NodaTime's Instant in a list, OpenAPI 3.0): ASP.NET drops the twin's items, since it cannot see through NodaTime's converter, on the host without TypeKit as well, and the value object's items are put back. The README said so of "a JSON converter you write yourself", which own-converter-for-the-wrapped-type quotes under json.Converters=own-for-wrapped only; it now says the same of a converter a library registers for its own type, and a-librarys-converter-for-the-wrapped-type quotes it for shape.wrapped=NodaTime.Instant. No finding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on and for an element, and KB-027 and a library's converter for a property Triage of rows 196, 358, 386 and 422 of C21OpenapiSchemaParityProbe, each failing in three runs of `try` at 53050b7; with this commit each ends inapplicable with its citation in `try`. - Row 386 (triage 3, KB-026): a nullable validated struct over Uri as a required-init property, OpenAPI 2.0. The value object's property is the 2.0 null flag with the wrapped type's format beside it, the twin's Uri keeps its type. The harness cited openapi-2-nullable-component-loses- its-type only where side (1) wrote the same at the value object's path, before any normalisation; a nullable struct value object over a class had its null flag taken out by the spellings' normalisation first, which left only the missing type. It is now told by its structure: the format beside the null flag alone, and the twin's the same with its type. - Row 358 (triage 3): a dictionary's nullable value is the null flag alone under 2.0, where ASP.NET alone drops a converter-backed element, so side (1) has nothing there; told by its structure, it cites openapi-2-nullable-element-loses-its-type. - Row 196 (triage 3, KB-027): the branch that cites enum-component-is-its-first-use for a parameter now takes a property too, citing enum-component-lists-the-null-of-its-first-use, on the same evidence (the twin's enum is a resolved component, side (1) lists the same null). - Row 422 (triage 3): a list of Instant whose twin has no items, side (1) neither, cites a-librarys-converter-for-the-wrapped-type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re MVC's formatters decide them, and tells KB-026 by the null flag beside a format
With F4's fix applied (its own pull request, fix/component-keeps-null),
`try` of all of C21OpenapiSchemaParityProbe failed rows 38, 178, 181 and 243;
each now passes or cites, and so does the whole probe.
- Row 38 (triage 1): with the null in place, the next difference was the
MVC body's media types: the value object's lists application/xml,
text/xml and application/*+xml, the twin's does not. Under
mvc.InputFormatters=xml-added, XmlSerializerInputFormatter reads the
sealed record class value object and not the Uri it wraps; ASP.NET alone,
with both sides' endpoints, lists the same for each side. The harness
compared which media types MVC's formatters accept for two .NET types,
which the claim does not speak to. Where side (1) lists each side's media
types as the document does, the schemas are now compared under the media
types both list; otherwise as before, so a media type lost to TypeKit
still fails.
- Rows 178, 181 and 243 (triage 3, KB-026, openapi-2-nullable-component-
loses-its-type): class value objects over long, bool and int whose
property admits null as a type parameter's or set through the
constructor, OpenAPI 2.0. With F4's null around the reference, the 2.0
writer writes the property as allOf [{x-nullable: true}] beside the
wrapped type's format, without the type and pattern the twin keeps, as
the AspNetCore README says. The branch row 386 needed is told the same
way for any content the writer drops: the value object's property is the
null flag, alone or beside a format, and the twin's admits null with the
same format.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…twin is a component itself `prober status` after a replay of the http family, with F4's fix applied: C21 had 13,677 of its 13,716 wanted pairs current, 39 uncovered. `rows --claim C21-openapi-schema-parity` proposed 14 rows, 5 of them the same as stored rows that earned nothing: under json.MaxDepth=3 both hosts refuse the document (409, 426, 430), a record class bound from an MVC form is inconclusive (411), and two nullable arrays ASP.NET names as one component (425). In each proposed row the axes no target pair names were set apart from those: json.MaxDepth and openapi.CreateSchemaReferenceId to their defaults, an own-record-class's form binding to the body, and the array's nullability to as-declared. The 14 are appended as rows 435 to 448. Row 444 (triage 3, KB-026): a validated class over a record class as a property, OpenAPI 2.0. The value object's property is the null flag alone; the twin's is the record class's component, whose reference ASP.NET's own rule leaves without a null, where the value object admits one (decision 36). The structural KB-026 branch now takes a twin that is a resolved component beside one that admits null. `try` of all 449 rows: pass 292, expected-refusal 112, inapplicable 26, inconclusive 19, no violation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…MaxDepth=3, and rows for its last 12 pairs `prober gate --since v2.1.0` after `replay --all` with F4's fix applied: 45 probes passed, C21 had 12 of its 13,716 wanted pairs uncovered, from rows 436, 440, 443 and 446 of the previous commit, which earned nothing. - json.MaxDepth=3 x shape.wrapped=own-record-class: every one of the 26 stored rows that holds the pair ends as ASP.NET alone refusing the document (the schema exporter's MaxDepth InvalidOperationException, at every position and host) or inconclusive; none can compare a document. Each obligation declares the pair inapplicable, citing record 0099, as it does json.ReferenceHandler=Preserve. - The other 11 pairs get five rows (449 to 453), each from `rows --claim` with the axes its target pairs do not name set where the document compares like with like: json.MaxDepth at its default; an own record class or an Instant as declared, not nullable, since F4 has a nullable value object admit the null its twin's component lacks (decision 36); a struct value object over a record class made a validated class with everything inlined, since a struct over a class has no twin at its nullability; a list of Instant on the host with controllers alone, whose minimal schema endpoint drops the twin's items (not-promised a-librarys-converter-for-the-wrapped-type); bodies rather than a query for a record class, which ASP.NET binds by its properties. `try` of rows 449 to 453: 5 pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`prober gate --since v2.1.0` passes on probes alone, with no waiver: after `replay --all` from an empty PROBE_STATE_DIR with F4's fix applied (its own pull request), "44 claim(s) touched and fully covered, every probe replayed and passing, no open finding". The item "Grow the probe corpus until `prober gate` passes" goes, and so does the WS2 item's list of what the harness left the gate (C12, C13, C16 and C21's document-only pairs, C22's footprint), which this pull request answered. The roadmap holds what is open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
F4's fix (#63), which C21's rows 38, 170, 184, 330 and 415 need. # Conflicts: # tools/probe/corpus/harness/HttpBaseline.cs
This was referenced Oct 18, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The 17 refusals
prober gate --since v2.1.0gave at 938d8f8, answered with what decision 97 allows: probes' rows, declarations of inapplicability and exclusions with their reasons. There is no waiver, no workflow edit, no message matching and no product change.Verdict: the gate passes.
prober gate --since v2.1.0, afterprober replay --allfrom an emptyPROBE_STATE_DIRat cfe942a: "44 claim(s) touched and fully covered, every probe replayed and passing, no open finding." All 17 refusals are answered with probes' rows, declarations, exclusions and one product fix (F4, #63). There is no waiver. Every probe's seeds were caught again: 170 of 170.C21's last ten failing rows were triaged (below). Five of them were one product defect, F4, confirmed by the code-analyst and fixed in #63 and merged here through release/2.2.0. The other five, and four more that the fix exposed, are a harness gap, a new verified fact (KB-042) and entries the claim does not promise. Rows 435–453 cover C21's last pairs.
Before and after
prober replay --allfrom an empty state (PROBE_STATE_DIRin a scratch directory), thenprober gate --since v2.1.0. Before: release/2.2.0 at 938d8f8. After: this branch at cfe942a (C21 finished after 53050b7; the earlier groups were measured at 53050b7). Both runs used the tools built in the worktree, on Linux x64 (32 threads).prober statusat 53050b7: 0 open findings, 0 uncredited obligations in all 44 claims.docs-query checkat cfe942a: 0 problems (42 facts, 17 fact citations).Commits
build:a probe that runs nothing under src/ is recorded by what it watchestest:the document obligations do not apply under Preserve, and rows for the rest of C12, C13, C16 and C21docs:C21 does not promise the twin's schema where a nullable value object admits null and ASP.NET drops ittest:C21's schema comparison cites KB-001 …, decision 36 …, and cannot tell a form-bound record classtest:C17's and C19's rows written again, without the refused kinds they substitutedtest:L02's parsing obligations do not apply to TryFrom or formatting, and its JSON check reads a value of another kindtest:E02 compares an enum with >= as C# does, excludes >= over string, bool and Uri, …test:rows and exclusions for the scattered pairs of C02, C03, C05, L01, L03, L04, L06 and C22test:KB-042, ASP.NET refuses a char's schema under WriteAsString, and C21's obligations do not apply theredocs:C21 does not promise the twin's schema for an enum component's first-use null, a 2.0 nullable element, or a library's convertertest:C21's schema comparison cites KB-026 after the null normalisation and for an element, and KB-027 and a library's converter for a propertyfix:a nullable value object that is a component keeps its null as a get-only property, a field and an oblivious onetest:C21 compares schemas under the media types both bodies list where MVC's formatters decide them, and tells KB-026 by the null flag beside a formattest:rows for C21's last uncovered pairs, and KB-026 told where the twin is a component itselftest:C21's obligations do not apply to a wrapped record class under MaxDepth=3, and rows for its last 12 pairsdocs:the roadmap's 2.2.0 gate item is done1. C22: an empty footprint (
build:)The probe builds its consumer in a child process, so the coverage of its own process shows nothing under
src/.prober footprintrefused to record an empty footprint whatever the registry entry watched, which is why addingwatchedalone could not answer this refusal. C22's entry already watched what C18's does.footprintnow records an empty footprint when the entry watches something, and still refuses when nothing ran and nothing is watched. A footprint that ran nothing undersrc/is current by its watched paths. C22's entry now also watches the generators and the analyzers its consumer compiles against. Two newWatchedTests; each fails with its half of the change reverted, and the refusal test fails with the refusal removed. Its other 14 pairs had no row, and got rows in group 6.2. C12, C13, C16, C21: documents both hosts refuse
inapplicable)json.ReferenceHandler=Preserverecord:0099json.MaxDepth=3withsourceIDescribedJsonConverter or JsonSchemaDescriptionsrecord:0099Not declared:
json.MaxDepth=3on its own. The brief asked for it, but it would not be true. Under it, documents are written and compared in C12's decimal host and in 47 rows of C13, 91 of C16 and 59 of C21, and its pairs were covered already. Whether ASP.NET refuses a document under MaxDepth=3 depends on the depth of the row's shape, not on an axis, so those pairs needed more rows instead. No fact backs these declarations: KB-040 and KB-041 are about a converter's depth charge and MVC's 400, not the document. So they cite record 0099, which states the refusal.docs-query checkstays at 0 problems.Rows:
rows --probefor the four probes, then rows appended fromrows --claimuntil the pairs converged: C12 → 462 rows, C13 → 321, C16 298, C21 → 435. C13'srows --probecame out the same as before, because Preserve stays wanted there.3. C17, C19
Both rows files were written again with
rows --probe, which now leaves out of a row an axis none of whose values can join it (14 rows of each). Every row passes.4. L02: the own-converter pairs of TryFrom and formatting
I chose a declaration, because no rows could reach these pairs. TryFrom, ToString-format and TryFormat-short-span reject no text: TryFrom answers None, and formatting reads no input. The probe already runs its parsing checks only for the five parsing entries, which are the
axesboth parsing obligations list. So parsing-never-repeats and no-inner-that-quotes declare themselves inapplicable at those three entries (docs:src/CodoMetis.TypeKit.Generators/README.md#when-text-is-rejected). Under an application's own converter, the JSON check is already not promised (not-promised:the-applications-own-converter). So those 6 pairs are wanted by no obligation. Every other pair of those entries stays wanted by json-never-repeats.L02's JSON check put the secret only where the wrapped value stands, as a string. An unvalidated value object over string or Uri reads every string, so those rows ended inconclusive. Where every variant was read, the check now also sends an array holding the secret in that place, and requires the refusal not to quote it. 22 of those 26 rows now pass and none fails. Two exclusions: Populate with a reference handler, as twelve other claims already exclude it; and a record class as a dictionary key (below). 8 rows were set by hand from a passing row's settings, for pairs the covering array kept placing in rows that read nothing.
5. E02
The probe substituted where-equals for where-value-compare wherever
Expression.GreaterThanOrEqualthrows. "No>=operator" is true of string, bool and Uri, which are now excluded. It is not true of an enum: C# compares two enum values over the underlying type. So the probe now writes that comparison, and rows 216 and 217 (enum, flags enum) run it and pass. Row 215 is the group-by row for nested-two-levels × DateTimeOffset.6. The scattered pairs
Rows for C02 (4), L01 (3, plus row 584 below), L03 (2), L06 (1;
Shapes.g.cswritten again byshapes.cs, since its context lists L06's carriers) and C22 (9), and the exclusions below.Declarations and exclusions added
json.ReferenceHandler=Preserverecord:0099; measured abovejson.MaxDepth=3×sourceIDescribedJsonConverter, JsonSchemaDescriptionsrecord:0099; measured abovetext.entryTryFrom, ToString-format, TryFormat-short-spandocs:src/CodoMetis.TypeKit.Generators/README.md#when-text-is-rejecteda-nullable-value-object-admits-null(http.nullability=nullable)as-text-refused-in-globalization-invariant-mode: AsText throws there (docs/text.md#globalization-invariant-mode), and AsOptionalText calls it>=for themL01's dictionary-key × own-record-class pair is covered by a row, not excluded. Row 584 runs it under
json.Converters=own-for-wrapped, the only converter under which System.Text.Json writes a record class as a key, and it passes.C21: the rows that failed (probe-triage)
Every row failed in three
tryruns at 53050b7 before it was triaged. Rows 62, 113, 216 and 282 were triaged in 7b0edf0 and 9b6f58e (step 1: a form-bound record class; step 2: KB-001; step 3: decision 36). The other ten:$refto its component where the twin's inline schema admitted null: a get-only property set through the constructor (170), a property typed by a type parameter (184, 330, 415), one without nullable annotations (38)NullabilityInfoContext's write state is nullable (TypeExtensions.ShouldApplyNullablePropertySchema). The twin's inline null comes from System.Text.Json'sIsGetNullable/IsSetNullable. ASP.NET alone writes the same bare reference for the value object (side (1)); decision 36 says a nullable value object admits null wherever it appears. Confirmed by the code-analyst on the maintainer's machine; fixed in #63 (Found-By: PR) by the session that owns it, and merged here through release/2.2.0.JsonExceptionreadingOpenApiJsonSchema, ASP.NET alone with MaxDepth'sInvalidOperationExceptionNumberHandling=WriteAsString, ASP.NET refuses any document whose schema holds achar(the exporter'sminLength/maxLengthreach its reader as strings), measured without TypeKit. Both hosts refuse; TypeKit meets that refusal first, ASP.NET alone meets MaxDepth first at another endpoint. Each C21 obligation declaresjson.NumberHandling=WriteAsString×shape.wrapped=charinapplicable,fact:KB-042(4675d2e). The code-analyst refuted it as a defect on the same grounds.enum-component-lists-the-null-of-its-first-use; the KB-027 branch now takes a property as well as a parameter.{"allOf":[{"x-nullable":true}]}under 2.0, the twin'sbool?keeps its typeopenapi-2-nullable-element-loses-its-type, told by structure (side (1) drops the element).typethe twin's hasopenapi-2-nullable-component-loses-its-type): the property is the null flag beside the wrapped type's format. Told by structure; the same branch now also covers 178, 181, 243 and 444.Instant: ASP.NET drops the twin'sitems, the value object's are put backa-librarys-converter-for-the-wrapped-type, side (1) showing the same.What F4's fix exposed, each failing in
trywith the fix applied:XmlSerializerInputFormatterreads a record class value object, not theUriit wraps. ASP.NET alone lists the same media types for each side. The harness now compares the schemas under the media types both list, but only where side (1) lists each side's media types the same way, so a media type TypeKit lost still fails.format, as the README says.A leftover to drop with the next harness change. At the merge of release/2.2.0 (cfe942a),
HttpBaseline.SchemaParitykept #63's own 2.0 citation branch and its helperTheNullFlagWithoutItsReferencebeside this branch's structural KB-026 branch, which covers the same rows. Both citeopenapi-2-nullable-component-loses-its-type, so the extra branch is redundant and harmless. Dropping it now would change the harness, which is in every probe's identity, and re-stale every probe's seeds (about four hours), so it stays until the harness next changes.C21's last pairs
rows --claimproposed 14 rows, 5 of them copies of stored rows that earned nothing:MaxDepth=3refusals, a form-bound record class, two nullable arrays ASP.NET names as one component. The axes no target pair names were set away from those, and the rows appended as 435–448.json.MaxDepth=3×shape.wrapped=own-record-class: all 26 stored rows holding the pair end as ASP.NET alone refusing the document, or inconclusive, at every position and host, so each obligation declares it inapplicable, citingrecord:0099as it does Preserve. Rows 449–453 hold the other 11 pairs.Probes replayed and reseeded
replay --allfrom empty states, 45 of 45 passed each time: at 4558f41 and fe453f9 (with F4's first fix, never pushed), and at 158faa5, this branch merged with fix: a nullable value object that is a component keeps its null as a get-only property, a field and an oblivious one #63's head, which has the same tree as cfe942a (d536262). At cfe942a the gate ran against that last replay's ledger.prober seeds --probe Pran for all 45 probes in two lanes. Each lane was a separate detached checkout at 158faa5 (tree d536262, the same as cfe942a) reading the unseeded rows from a copy of the final replay's ledger. Wall time 09:42 to 13:31.170 seeds of 45 probes, 170 caught, each by a check of its own obligation; none missed, no seeded build failed.
Every seed, with the row and the check that caught it
BaseProbeclaim)claimC01DecimalSpellingProbecovers-every-decimalcovers-every-decimalC01DecimalSpellingProbekeeps-the-scale-it-readskeeps-the-scale-it-readsC01DecimalSpellingProbenumber-is-a-numbernumber-is-a-numberC01DecimalSpellingProbereads-a-number-or-a-stringreads-a-number-or-a-stringC01DecimalSpellingProbesmallest-scalesmallest-scaleC01DecimalSpellingProbestring-is-a-stringstring-is-a-stringC02OptionalTextProbehidden-is-an-error-in-bothhidden-is-an-error-in-bothC02OptionalTextProbenull-is-blanknull-is-blankC02OptionalTextProbeoptional-blank-is-no-valueoptional-blank-is-no-valueC02OptionalTextProberequired-blank-is-an-errorrequired-blank-is-an-errorC03ComposedProbedetail-and-rule-intactdetail-and-rule-intactC03ComposedProbeeach-error-own-seteach-error-own-setC03ComposedProbeshared-status-typesshared-status-typesC03ComposedProbestatuses-ascendingstatuses-ascendingC03ComposedProbeunmapped-set-stops-startunmapped-set-stops-startC04WithoutFaultsProbedoc-omits-left-outdoc-omits-left-outC04WithoutFaultsProbeleft-out-everywhere-stops-startleft-out-everywhere-stops-startC04WithoutFaultsProbenarrows-wider-statusnarrows-wider-statusC04WithoutFaultsProbereporting-left-out-throwsreporting-left-out-throwsC05RuleProbenested-chainnested-chainC05RuleProbeno-namespaceno-namespaceC05RuleProberule-qualifiedrule-qualifiedC05RuleProbestays-the-errorsstays-the-errorsC05RuleProbeunnamed-value-throwsunnamed-value-throwsC06FaultKindsProbedescription-as-detaildescription-as-detailC06FaultKindsProbekind-gives-statuskind-gives-statusC06FaultKindsProbemember-must-have-kindmember-must-have-kindC06FaultKindsProbeno-description-no-detailno-description-no-detailC07BlanketMappingProbeby-kindby-kindC07BlanketMappingProbeenum-needs-own-mappingenum-needs-own-mappingC07BlanketMappingProbemapping-refusal-stops-startmapping-refusal-stops-startC07BlanketMappingProbemember-without-kind-stops-startmember-without-kind-stops-startC07BlanketMappingProbeown-mappingown-mappingC07BlanketMappingProbeown-set-keeps-mappingown-set-keeps-mappingC08SameNameWarningProbebare-names-warnbare-names-warnC08SameNameWarningProbeleave-one-out-fixesleave-one-out-fixesC08SameNameWarningProbequalified-chain-warnsqualified-chain-warnsC08SameNameWarningProbequalified-names-fixqualified-names-fixC08SameNameWarningProbewarning-names-bothwarning-names-bothC09BaseRecordEqualityProbeequal-by-the-wrapped-valueequal-by-the-wrapped-valueC09BaseRecordEqualityProbein-a-collection-of-the-basein-a-collection-of-the-baseC10PreserveGuardProbeignore-cycles-unaffectedignore-cycles-unaffectedC10PreserveGuardProbeown-converters-unaffectedown-converters-unaffectedC10PreserveGuardProberefused-where-references-could-be-writtenrefused-where-references-could-be-writtenC10PreserveGuardProbevalue-converters-unaffectedvalue-converters-unaffectedC11ParseShapesBuildProbeabstract-string-constructorabstract-string-constructorC11ParseShapesBuildProbeimplicit-resultimplicit-resultC11ParseShapesBuildProbeparsing-where-it-can-be-parsedparsing-where-it-can-be-parsedC11ParseShapesBuildProberef-textref-textC12DescribedConverterProbeevery-positionevery-positionC12DescribedConverterProbeoptions-describeoptions-describeC12DescribedConverterProbeown-converter-describes-itselfown-converter-describes-itselfC12DescribedConverterProbeparameter-keeps-aspnetparameter-keeps-aspnetC13PatchRequiredProbeabsent-is-defaultabsent-is-defaultC13PatchRequiredProbedoc-optional-where-absentdoc-optional-where-absentC13PatchRequiredProbedoc-required-where-rejecteddoc-required-where-rejectedC14DeclaredProblemProbeapplication-json-declaredapplication-json-declaredC14DeclaredProblemProbeascending-with-declaredascending-with-declaredC14DeclaredProblemProbedeclared-describes-faultdeclared-describes-faultC14DeclaredProblemProbedeclared-names-typesdeclared-names-typesC15MvcFaultStatusDocProbebuilder-reaches-docbuilder-reaches-docC15MvcFaultStatusDocProbestatus-per-scopestatus-per-scopeC15MvcFaultStatusDocProbewithout-faults-leaves-docwithout-faults-leaves-docC16OptionsAgreementProbediffering-refuseddiffering-refusedC16OptionsAgreementProbeerror-names-type-and-descriptionserror-names-type-and-descriptionsC16OptionsAgreementProbeminimal-host-not-comparedminimal-host-not-comparedC16OptionsAgreementProbepatch-held-refusedpatch-held-refusedC16OptionsAgreementProbesame-converters-buildsame-converters-buildC17Cmtk0014Probea-cast-naming-no-membera-cast-naming-no-memberC17Cmtk0014Probea-member-is-silenta-member-is-silentC17Cmtk0014Probeconstructor-accessibility-tooconstructor-accessibility-tooC17Cmtk0014Probedefault-and-zerodefault-and-zeroC17Cmtk0014Probereported-where-writtenreported-where-writtenC18Cmtk1023Probea-warning-and-generateda-warning-and-generatedC18Cmtk1023Probegenerated-equality-never-calls-the-basegenerated-equality-never-calls-the-baseC18Cmtk1023Probenames-each-base-membernames-each-base-memberC19Cmtk0010KindsProbea-pair-once-at-the-later-argumenta-pair-once-at-the-later-argumentC19Cmtk0010KindsProbeflags-enum-and-read-only-structflags-enum-and-read-only-structC19Cmtk0010KindsProbeinterface-and-unsealedinterface-and-unsealedC19Cmtk0010KindsProbemethods-the-compiler-callsmethods-the-compiler-callsC19Cmtk0010KindsProbevalue-object-and-closed-setvalue-object-and-closed-setC20ShouldHoldProbea-failure-says-the-outcomea-failure-says-the-outcomeC20ShouldHoldProbefails-unless-it-holds-that-reasonfails-unless-it-holds-that-reasonC20ShouldHoldProbehands-back-detail-and-rulehands-back-detail-and-ruleC20ShouldHoldProbeuninitialized-failsuninitialized-failsC20ShouldHoldProbewhichever-of-its-typeswhichever-of-its-typesC21OpenapiSchemaParityProbecontainer-elementscontainer-elementsC21OpenapiSchemaParityProbedictionary-keydictionary-keyC21OpenapiSchemaParityProbeevery-document-versionevery-document-versionC21OpenapiSchemaParityProbenullable-admits-null-as-the-wrapped-doesnullable-admits-null-as-the-wrapped-doesC21OpenapiSchemaParityProbethe-underlying-types-schemathe-underlying-types-schemaC22GeneratorRefusalsProbeabstractabstractC22GeneratorRefusalsProbeclosed-set-named-as-generated-memberclosed-set-named-as-generated-memberC22GeneratorRefusalsProbeequality-operatorequality-operatorC22GeneratorRefusalsProbeevery-error-links-the-tableevery-error-links-the-tableC22GeneratorRefusalsProbegeneric-wrappedgeneric-wrappedC22GeneratorRefusalsProbenamed-as-generated-membernamed-as-generated-memberC22GeneratorRefusalsProbeno-type-half-generatedno-type-half-generatedC22GeneratorRefusalsProbeover-objectover-objectC22GeneratorRefusalsProbeover-system-enumover-system-enumC22GeneratorRefusalsProbeover-value-objectover-value-objectC22GeneratorRefusalsProbeunsealed-record-classunsealed-record-classE01ColumnParityProbecolumn-typecolumn-typeE01ColumnParityProbefacet-keptfacet-keptE01ColumnParityProbenullablenullableE02ValueTranslatesProbecolumn-not-castcolumn-not-castE02ValueTranslatesProbeget-valueget-valueE02ValueTranslatesProbevalue-or-nullvalue-or-nullE02ValueTranslatesProbevaluevalueE03ColumnRoundTripProbekeyskeysE03ColumnRoundTripProbenullable-propertiesnullable-propertiesE03ColumnRoundTripProbestored-as-underlyingstored-as-underlyingE04IntegerKeyProbebyte-not-generatedbyte-not-generatedE04IntegerKeyProbechar-key-yourschar-key-yoursE04IntegerKeyProbegenerated-on-addgenerated-on-addE04IntegerKeyProbeguid-key-yoursguid-key-yoursE04IntegerKeyProbenot-on-efs-listnot-on-efs-listE04IntegerKeyProbeown-configuration-winsown-configuration-winsE05OwnCompareToProbecomparisoncomparisonE05OwnCompareToProbeequality-allowedequality-allowedE05OwnCompareToProbemin-maxmin-maxE05OwnCompareToProbeorderingorderingE05OwnCompareToProbequery-filterquery-filterE05OwnCompareToProbevalue-order-allowedvalue-order-allowedE06OwnConverterNoValueProbevalue-not-translatedvalue-not-translatedE06OwnConverterNoValueProbevalue-object-comparisonvalue-object-comparisonE07ClosedSetNameProbein-collections-and-jsonin-collections-and-jsonE07ClosedSetNameProbenon-member-throwsnon-member-throwsE07ClosedSetNameProbestored-as-namestored-as-nameE07ClosedSetNameProbeunknown-name-throwsunknown-name-throwsE08OptionResultNotColumnsProbeerror-says-soerror-says-soE08OptionResultNotColumnsProbemodel-failsmodel-failsE09OrNoneInDbProbeelement-at-skipselement-at-skipsE09OrNoneInDbProbefirst-reads-one-rowfirst-reads-one-rowE09OrNoneInDbProbesingle-asks-for-twosingle-asks-for-twoE10ReadBackSkipsValidationProbereads-without-createreads-without-createE10ReadBackSkipsValidationProberevalidate-findsrevalidate-findsE11UseTypeKitOrderProbeorder-does-not-matterorder-does-not-matterE12ConventionByTypeProbeunderlying-type-does-not-reachunderlying-type-does-not-reachE12ConventionByTypeProbevalue-object-type-reachesvalue-object-type-reachesE13PrimitiveCollectionProbecontainscontainsE13PrimitiveCollectionProbeelement-valueelement-valueE14InheritanceKeyProbetpc-assign-on-sqlitetpc-assign-on-sqliteE14InheritanceKeyProbetph-tpt-roottph-tpt-rootE15CompositeKeyProbeas-for-primitivesas-for-primitivesE16OwnConfigurationWinsProbecolumn-typecolumn-typeE16OwnConfigurationWinsProbeconversionconversionE16OwnConfigurationWinsProbeneverneverE16OwnConfigurationWinsProbeon-addon-addE16OwnConfigurationWinsProbeoptionaloptionalL01JsonBytesProbeas-a-dictionary-key-tooas-a-dictionary-key-tooL01JsonBytesProberead-as-the-underlying-type-readsread-as-the-underlying-type-readsL01JsonBytesProbethe-underlying-types-jsonthe-underlying-types-jsonL02NoQuoteProbejson-never-repeatsjson-never-repeatsL02NoQuoteProbeno-inner-that-quotesno-inner-that-quotesL02NoQuoteProbeparsing-never-repeatsparsing-never-repeatsL03OneRuleProbejson-runs-createjson-runs-createL03OneRuleProbeparsing-runs-createparsing-runs-createL03OneRuleProberefusals-name-the-faultrefusals-name-the-faultL03OneRuleProbetryfrom-runs-createtryfrom-runs-createL04RoundTripProbeinvariant-whatever-the-cultureinvariant-whatever-the-cultureL04RoundTripProbejson-refusal-is-a-json-exceptionjson-refusal-is-a-json-exceptionL04RoundTripProbetext-reads-backtext-reads-backL04RoundTripProbethe-type-converter-writes-the-samethe-type-converter-writes-the-sameL05EqualityProbeequality-is-the-underlying-valuesequality-is-the-underlying-valuesL05EqualityProbeordering-follows-the-underlying-typeordering-follows-the-underlying-typeL05EqualityProbethrough-every-basethrough-every-baseL06OffTheWireProbenever-readnever-readL06OffTheWireProbenever-writtennever-writtenTests
Through
build-verdict test --project Pat 60de568: CodoMetis.TypeKit.Prober.Tests 270 passed, CodoMetis.TypeKit.Conventions.Tests 1,501 passed, CodoMetis.TypeKit.Facts 91 passed and 9 skipped (the PostgreSQL facts, withoutTYPEKIT_PG; KB042 is new, and fails with its setting removed). F4's tests are in #63.docs-query check: 0 problems.The gate's final output
🤖 Generated with Claude Code