Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .claude/probe-axes.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ and `GeneratedHarnessTests` in the conventions tests holds each file to its app'
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`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ public sealed class GeneratedHarnessTests
/// </summary>
private static readonly (string File, string App, string[] Arguments)[] Generators =
[
("Shapes.g.cs", "shapes.cs", ["--axes", Axes]),
("Shapes.g.cs", "shapes.cs", ["--axes", Axes, "--l06", $"{Rows}/L06OffTheWireProbe.json.gz"]),
("Containers.g.cs", "containers.cs", ["--axes", Axes]),
("EfShapes.g.cs", "ef.cs", ["catalogue", .. EfCatalogue]),
("EfShapes3.g.cs", "ef.cs", ["top-level", .. EfCatalogue]),
("EfShapes4.g.cs", "ef.cs", ["nested", .. EfCatalogue]),
("KeyShapes.g.cs", "ef.cs", ["keys", "--rows", $"{Rows}/E04IntegerKeyProbe.json.gz"]),
("JsonFamilyShapes.g.cs", "json-family.cs",
["contexts", "--c01", $"{Rows}/C01DecimalSpellingProbe.json.gz", "--c10", $"{Rows}/C10PreserveGuardProbe.json.gz", "--l06", $"{Rows}/L06OffTheWireProbe.json.gz"]),
("JsonFamilyShapes.g.cs", "json-family.cs", ["stand-ins"]),
("L05Shapes.g.cs", "json-family.cs", ["l05", "--rows", $"{Rows}/L05EqualityProbe.json.gz"]),
("C09Shapes.g.cs", "decls.cs", ["C09", "--rows", $"{Rows}/C09BaseRecordEqualityProbe.json.gz"]),
("C11Shapes.g.cs", "decls.cs", ["C11", "--rows", $"{Rows}/C11ParseShapesBuildProbe.json.gz"]),
Expand Down
54 changes: 0 additions & 54 deletions tools/probe/corpus/claims.json
Original file line number Diff line number Diff line change
Expand Up @@ -725,15 +725,6 @@
"json.ReferenceHandler=IgnoreCycles"
]
]
},
{
"reason": "System.Text.Json refuses adding resolvers to TypeInfoResolverChain once a JsonSerializerContext is the TypeInfoResolver (JsonRow notes it as substituted, STJ refused it), so the strict context never runs with the chain.",
"pairs": [
[
"json.TypeInfoResolver=source-generated-context",
"json.TypeInfoResolverChain=context-then-default"
]
]
}
]
},
Expand Down Expand Up @@ -855,15 +846,6 @@
"json.ReferenceHandler=IgnoreCycles"
]
]
},
{
"reason": "System.Text.Json refuses adding resolvers to TypeInfoResolverChain once a JsonSerializerContext is the TypeInfoResolver (JsonRow notes it as substituted, STJ refused it), so the strict context never runs with the chain.",
"pairs": [
[
"json.TypeInfoResolver=source-generated-context",
"json.TypeInfoResolverChain=context-then-default"
]
]
}
]
},
Expand Down Expand Up @@ -957,15 +939,6 @@
"json.ReferenceHandler=IgnoreCycles"
]
]
},
{
"reason": "System.Text.Json refuses adding resolvers to TypeInfoResolverChain once a JsonSerializerContext is the TypeInfoResolver (JsonRow notes it as substituted, STJ refused it), so the strict context never runs with the chain.",
"pairs": [
[
"json.TypeInfoResolver=source-generated-context",
"json.TypeInfoResolverChain=context-then-default"
]
]
}
]
},
Expand Down Expand Up @@ -6591,15 +6564,6 @@
"json.ReferenceHandler=IgnoreCycles"
]
]
},
{
"reason": "System.Text.Json refuses adding resolvers to TypeInfoResolverChain once a JsonSerializerContext is the TypeInfoResolver (JsonRow notes it as substituted, STJ refused it), so the strict context never runs with the chain.",
"pairs": [
[
"json.TypeInfoResolver=source-generated-context",
"json.TypeInfoResolverChain=context-then-default"
]
]
}
]
},
Expand Down Expand Up @@ -6654,15 +6618,6 @@
"json.ReferenceHandler=IgnoreCycles"
]
]
},
{
"reason": "System.Text.Json refuses adding resolvers to TypeInfoResolverChain once a JsonSerializerContext is the TypeInfoResolver (JsonRow notes it as substituted, STJ refused it), so the strict context never runs with the chain.",
"pairs": [
[
"json.TypeInfoResolver=source-generated-context",
"json.TypeInfoResolverChain=context-then-default"
]
]
}
]
},
Expand Down Expand Up @@ -11747,15 +11702,6 @@
]
]
},
{
"reason": "System.Text.Json refuses adding resolvers to TypeInfoResolverChain once a JsonSerializerContext is the TypeInfoResolver (JsonRow notes it as substituted, STJ refused it), so the strict context never runs with the chain.",
"pairs": [
[
"json.TypeInfoResolver=source-generated-context",
"json.TypeInfoResolverChain=context-then-default"
]
]
},
{
"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; the probe notes closed-set-differs.",
"pairs": [
Expand Down
4 changes: 2 additions & 2 deletions tools/probe/corpus/harness/ComposedProbes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public static class ComposedClaims
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) { down = ex; }
catch (Exception ex) when (ex is not Sides.InputsNotEquivalent) { down = ex; }
await using var _ = app;
string? failed = null;
if (down is not null)
Expand Down Expand Up @@ -144,7 +144,7 @@ public static class ComposedClaims
};
WebApplication? app = null;
try { app = await Hx.Start(r, en, cfg); }
catch (Exception ex)
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)}";
}
Expand Down
5 changes: 2 additions & 3 deletions tools/probe/corpus/harness/DecimalSpelling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ sealed record Form(string Name, string Json, Exception? Ep, Exception? Ev, List<
JsonConverter conv = number ? new DecimalNumberJsonConverter() : new DecimalStringJsonConverter();
var position = r["shape.position"];
var containing = position == "root" ? "class" : r["shape.containing"];
var hp = Pos.Build(position, containing, e, false, d);
var hv = Pos.Build(position, containing, e, true, Make.Vo(e, d));
var o = JCtx.Apply(r, e, C01JsonContext.Default, hp.Declared, hv.Declared);
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
Expand Down
23 changes: 4 additions & 19 deletions tools/probe/corpus/harness/FaultClaim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,32 +229,15 @@ static void Walk(IEndpointRouteBuilder? b, MGrp g, Decl[] above, string prefix,
return (eps, cfg);
}

const string Listed = "the probes' source-generated context (ProbeContext) lists value objects at root and as a property of a class only";

/// <summary>
/// Under json.TypeInfoResolver=source-generated-context the payload's shape moves to one the context lists (as a property of a class),
/// so the strict context applies and its pairs with the fault axes are earned; JsonRow would otherwise fall back to reflection for the
/// whole row. NodaTime.Instant is listed nowhere and keeps JsonRow's fallback. The pairs of the strict context with the other positions
/// and containers are left uncovered: a limit of this harness, not a refusal of the product, so claims.json excludes none of them.
/// </summary>
static Row StrictContext(Row r)
{
if (!r.Is("json.TypeInfoResolver", "source-generated-context") || r["shape.wrapped"] == "NodaTime.Instant") return r;
if (r["shape.position"] is not ("root" or "property")) { r = r.With("shape.position", "property"); r.Substituted("shape.position", "property", Listed); }
if (r.Get("shape.containing") is not (null or "class")) { r = r.With("shape.containing", "class"); r.Substituted("shape.containing", "class", Listed); }
return r;
}

public static async Task<string?> Run(Row r, Spec s)
{
r = StrictContext(r);
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) { down = ex; }
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;
Expand Down Expand Up @@ -342,7 +325,9 @@ static Row StrictContext(Row r)
await using var app = await Hx.Start(r, en, alone);
await Hx.Doc(app);
}
catch (Exception ex) when (ex.GetType() == withTypeKit.GetType() && ex.Message == withTypeKit.Message)
// the same refusal, at another byte of each document (Hx.Unplaced: the two differ in length by what AddTypeKit() wrote; rows 73 and
// 157 of C06's regenerated rows, a char under WriteAsString)
catch (Exception ex) when (ex.GetType() == withTypeKit.GetType() && Hx.Unplaced(ex.Message) == Hx.Unplaced(withTypeKit.Message))
{
r.Note(NoteKeys.DocRefusedByAspnetAlone, ex.GetType().Name);
return null;
Expand Down
Loading
Loading