Skip to content

land kanban 534 - #400

Merged
StevenTCramer merged 6 commits into
feature/overnight-2026-11-14from
task/526-json-member-schema-publish-typed-ids-and-other
Nov 13, 2026
Merged

StevenTCramer merged 6 commits into
feature/overnight-2026-11-14from
task/526-json-member-schema-publish-typed-ids-and-other

Conversation

@StevenTCramer

Copy link
Copy Markdown
Contributor

Summary

What changed

  • Generator (operation-endpoint-extractor.json-string-types.cs, new): for each [Operation] JSON member
    the extractor walks the member type (type arguments, array elements, public instance properties of
    non-framework types, base types included) and records each type that has its own [JsonConverter]
    (string-enum converter excluded) and implements IParsable<TSelf>. IsUuid is set when it has a public
    instance Guid Value. Carried on OptionDefinition.JsonStringTypes (JsonStringType record, equatable).
  • Emitter (capabilities-emitter.cs): passes them to NuruJsonMemberSchema.Create(..., stringTypes: [...], uuidTypes: [...]); members with none emit the old call unchanged.
  • Runtime (nuru-json-member-schema.cs): Create gained optional stringTypes/uuidTypes. The
    transform rewrites an untyped node (true or a typeless object) of those types to {"type":"string"}
    (+ "format":"uuid"), ["string","null"] for Nullable<T> or a nullable reference property, and fills
    missing items / additionalProperties for collections and dictionaries of them (the exporter omits
    them). [Description] runs after, so it is kept. Done at compile time because timewarp-nuru is
    IsAotCompatible + trim analyzed: no GetInterfaces() reflection.
  • Top-level typed-ID option (checked, was broken, fixed): an [Operation] property of a typed-ID type
    is not a scalar, so it is a JSON member (type json Ns.PrincipalId). Before: its schema was true
    (untyped) in --capabilities and McpHost, and the --json-args/MCP binder's kind gate accepted only an
    object or array, so every value was rejected (wrong JSON type. Expected json). Now the schema is
    {"type":"string","format":"uuid"} and the kind gate (json-args-emitter.validation.cs) takes a JSON
    string for a member whose own type is a typed ID (OptionDefinition.IsJsonStringValue; expected type
    reads string). Argv still rejects JSON members (--Owner is JSON. Pass it with --json-args.); accepting
    a typed ID on argv is a separate change, not done here.
  • Tests: tests/timewarp-nuru-mcphost-tests/mcphost-08-typed-id-schema.cs (in CI multi-mode via the
    mcphost glob): test-local Guid-backed TidPrincipalId (record struct, converter writing the Guid string,
    ISpanParsable) and string-backed reference TidSlug. Covers top-level (capabilities option schema +
    McpHost inputSchema, non-null and nullable), array items, nested object with [Description], nullable
    struct, nullable reference without format, nested list, dictionary values, string-enum unchanged, and
    binding through --json-args and NuruMcpToolInvoker (good value, object rejected with Expected string, unparsable rejected as a bind error).
  • Docs: documentation/user/features/agent-invocation.md (JSON member schema section),
    documentation/user/features/neutral-contracts.md (derivation table), changelog.md (Unreleased / Fixed).
  • Out of scope, unchanged: other custom converters (e.g. Roslynk-style lenient converters) still publish
    untyped; property-level [JsonConverter] is not detected.
  • Release: not cut. Version stays 4.0.0-beta.13 (released); ships in the next Nuru beta when one is asked for.

Gates

Gate Command Result
Build ./bin/dev build pass, 0 warnings, 0 errors
Test ./bin/dev test (after ganda runfile cache --clear) pass: multi-mode 2208 total, 2202 passed, 6 skipped, 0 failed; standalone 47 files, 0 failed
Audit ganda repo audit pass, 1 advisory (vscode-window-icon, gitignored .vscode/settings.json); ganda repo audit --fix fixed it, all checks pass

Test plan

Smoke:

ganda runfile cache --clear
cd tests/timewarp-nuru-mcphost-tests && dotnet run mcphost-08-typed-id-schema.cs

Expect: Passed: 3 (Should_publish_a_top_level_typed_id_as_a_uuid_string,
Should_publish_typed_ids_nested_in_arrays_objects_and_dictionaries,
Should_bind_typed_ids_through_json_args_and_mcp_arguments). The Owner schema is
{"type":"string","format":"uuid"}, Members.items is the same, Details.properties.Backup is
["string","null"], and tid-assign --json-args '{"Owner":"<guid>",...}' exits 0.

Kanban task 526
Session: Roslynk

StevenTCramer and others added 6 commits November 14, 2026 06:11
Land-Holder: cramer
…s (526)

A type with its own [JsonConverter] that implements IParsable<TSelf> (typed IDs)
was exported untyped by JsonSchemaExporter, and an array of them had no items.
The generator now finds those types at build time and passes them to
NuruJsonMemberSchema.Create, which publishes {"type":"string"} (plus
"format":"uuid" for a Guid Value) at the root, nested, as array items and as
dictionary values, keeping [Description] and nullability.

A JSON member whose own type is a typed ID now takes a JSON string in
--json-args and MCP arguments; the kind gate accepted only object or array.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@StevenTCramer
StevenTCramer merged commit 94bde07 into feature/overnight-2026-11-14 Nov 13, 2026
7 checks passed
@StevenTCramer
StevenTCramer deleted the task/526-json-member-schema-publish-typed-ids-and-other branch November 13, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant