Skip to content

Commit f866cb4

Browse files
dmealingclaude
andcommitted
docs(specs): FR6 family + ADR-0010 (template.output parser-on-receipt codegen)
Brainstormed re-scope of the original FR6 draft. The new structure: ADR-0010 — cross-port contract: - Codegen emits a typed parser-on-receipt for every template.output (not provider-side schemas, not combined workflow handles). - Per-port idiomatic emission: TS dual API (parse + safeParse), C# Parse/ TryParse, Python parse_xxx throws, Java parseXxx throws. - Soft cross-port contract: every port's generated parser documents its failure mode in docstring/JSDoc/XML doc. - @payloadRef symmetric with template.prompt (no new @outputRef attribute). - meta verify extends to cover output drift; diagnostic output gains kind: "prompt" | "output" on each finding. Per-port FRs: - FR6 parent — cross-port design. - FR6-ts (plan-of-record): outputParser() generator factory, dual-API Zod emission, verify.ts per-subtype branch, template-output-simple conformance fixture. - FR6-csharp (sketch): lighter brainstorm; C# codegen layer ready. - FR6-python (sketch, gated): Python codegen layer not shipped yet (post-H3). - FR6-java (sketch, gated): Java codegen layer not shipped yet (H4). Supersedes the original 2026-05-25-fr-template-output-codegen-pipeline- design.md (deleted; was a single under-scoped design proposal). Roadmap updated to reflect the family. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b677021 commit f866cb4

8 files changed

Lines changed: 818 additions & 155 deletions

docs/superpowers/specs/2026-05-25-fr-template-output-codegen-pipeline-design.md

Lines changed: 0 additions & 152 deletions
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# FR6-csharp — C# `template.output` parser codegen (sketch)
2+
3+
**Status:** Design proposal — needs brainstorm before implementation (lighter brainstorm than TS — C# codegen layer is already mature)
4+
**Date:** 2026-05-25
5+
**Scope:** C# — `MetaObjects.Codegen` (parser emission) + `meta verify` extension (C# CLI per CLAUDE.md)
6+
**Depends on:** [ADR-0010](../../../spec/decisions/ADR-0010-template-output-parser-codegen.md); existing `MetaObjects.Render` + `MetaObjects.Codegen` (shipped per CLAUDE.md status)
7+
**Parent:** [FR6 cross-port design](./2026-05-25-fr6-template-output-parser-codegen.md)
8+
9+
## Goal
10+
11+
For every declared `template.output`, the C# codegen emits a parser class with the
12+
dual-API shape from ADR-0010 (matching .NET BCL `Parse`/`TryParse` convention):
13+
14+
```csharp
15+
// Generated NpcResponse.Output.cs
16+
public static class NpcResponseOutputParser {
17+
private static readonly JsonSerializerOptions Options = new() {
18+
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
19+
};
20+
21+
/// <summary>Parse an LLM response into a typed NpcResponse.</summary>
22+
/// <exception cref="JsonException">when JSON parse fails or shape doesn't match.</exception>
23+
public static NpcResponse Parse(string text) =>
24+
JsonSerializer.Deserialize<NpcResponse>(text, Options)
25+
?? throw new JsonException("null response");
26+
27+
/// <summary>Parse with Result-style return; does not throw.</summary>
28+
public static bool TryParse(string text, out NpcResponse? result, out JsonException? error) {
29+
try { result = JsonSerializer.Deserialize<NpcResponse>(text, Options); error = null; return result is not null; }
30+
catch (JsonException ex) { result = null; error = ex; return false; }
31+
}
32+
}
33+
```
34+
35+
Plus `meta verify` extension (C# CLI's `verify` command per CLAUDE.md).
36+
37+
## Why this is a sketch, not implementation-ready
38+
39+
The design largely follows the TS FR6 shape but with .NET idioms. The brainstorm
40+
items expected:
41+
42+
1. **Source-generator vs reflection.** .NET AOT prefers source generators (per
43+
ADR-0001's reflection-replacement principle). The TS port uses Zod (runtime
44+
validation). The C# port should use `System.Text.Json` source generators for AOT
45+
compatibility — but this needs confirmation against the existing C# codegen
46+
patterns. Existing `MetaObjects.Codegen` may already establish a preference.
47+
2. **JsonNamingPolicy.** C# convention is PascalCase properties; JSON convention is
48+
camelCase. The existing C# codegen for entities + payload-VOs has presumably
49+
already made this choice. The output parser should match.
50+
3. **Nullable reference type contracts.** `Parse` returns `T` non-null; `TryParse`'s
51+
`out result` is `T?`. Match existing `MetaObjects.Codegen` patterns.
52+
53+
## Tests + verification
54+
55+
- Unit tests on the field-type → System.Text.Json attribute mapping.
56+
- Golden tests under `MetaObjects.Codegen.Tests/Golden/` matching existing
57+
C# codegen test patterns.
58+
- New conformance fixture `template-output-simple` shares structure with TS; C#
59+
conformance runner verifies `expected/NpcResponseOutput.Output.cs` byte-match.
60+
- `meta verify --kind output` tests under the C# CLI test project.
61+
62+
## Out of scope
63+
64+
Same exclusions as FR6 parent.
65+
66+
## Open questions
67+
68+
To be settled during the lighter brainstorm:
69+
70+
1. System.Text.Json source generator vs runtime reflection.
71+
2. JsonNamingPolicy choice (probably already established by existing C# codegen).
72+
3. Whether to ship a barrel/index file aggregating all output parsers, or stay file-per-template (matches C# codegen layout established by existing entity emit).
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# FR6-java — Java `template.output` parser codegen (sketch, gated)
2+
3+
**Status:** Design sketch — gated on Java codegen layer (planned in H4)
4+
**Date:** 2026-05-25
5+
**Scope:** Java — codegen target (planned per roadmap H4: "TS codegen Java target — Refactor TS codegen to pluggable targets; Java target emits Spring JDBC DAOs, Spring MVC controllers, POJOs")
6+
**Depends on:** [ADR-0010](../../../spec/decisions/ADR-0010-template-output-parser-codegen.md); Java codegen layer existing (not yet)
7+
**Parent:** [FR6 cross-port design](./2026-05-25-fr6-template-output-parser-codegen.md)
8+
9+
## Goal
10+
11+
For every declared `template.output`, the Java codegen emits a parser class with
12+
the Java throw-only convention (matching Jackson):
13+
14+
```java
15+
// Generated NpcResponseOutputParser.java
16+
public final class NpcResponseOutputParser {
17+
private static final ObjectMapper MAPPER = new ObjectMapper()
18+
.registerModule(new JavaTimeModule());
19+
20+
/**
21+
* Parse an LLM response into a typed NpcResponse.
22+
*
23+
* @throws JsonProcessingException when JSON parse or schema validation fails
24+
*/
25+
public static NpcResponse parseNpcResponse(String text) throws JsonProcessingException {
26+
return MAPPER.readValue(text, NpcResponse.class);
27+
}
28+
}
29+
```
30+
31+
Plus eventual `meta verify` extension when a Java CLI surfaces (today's
32+
metaobjects CLI is TS; Java may share or grow its own).
33+
34+
## Why this is a sketch — implementation gated
35+
36+
Java doesn't have a codegen layer yet. Per roadmap H4: "TS codegen Java target —
37+
2-3 wk." When that ships, this FR ships alongside as one of the codegen targets
38+
the Java codegen produces.
39+
40+
## Design (when ready)
41+
42+
### Jackson alignment
43+
44+
Jackson is the de facto JSON-parsing library in the Java ecosystem. Spring Boot
45+
defaults to it; most LLM-Java libraries use it. The generated parser uses
46+
`ObjectMapper.readValue(text, Xxx.class)` — the canonical Jackson call.
47+
48+
The Java codegen layer (per H4) will already need to make Jackson-vs-Gson-vs-other
49+
decisions for entity and payload-VO emission; the output parser inherits that
50+
choice.
51+
52+
### No dual API
53+
54+
Java doesn't have an idiomatic dual-API precedent like .NET's `Parse`/`TryParse`.
55+
Jackson throws `JsonProcessingException`; callers wrap in try/catch. Matching the
56+
ecosystem norm, the generated parser is single-API throw-only.
57+
58+
If a Java adopter wants a Result-style API, they wrap the call themselves —
59+
likely using Vavr's `Try<T>` or a hand-rolled `Result<T>` type. The codegen
60+
doesn't bless one.
61+
62+
### Field-type → Jackson-annotation mapping
63+
64+
The payload-VO (POJO emitted by the Java codegen) carries Jackson annotations:
65+
66+
| Field subtype | Jackson / POJO shape |
67+
|---|---|
68+
| `field.string` | `String` (with `@JsonProperty` for camelCase if needed) |
69+
| `field.int` / `field.long` / `field.short` / `field.byte` | matching primitive or boxed |
70+
| `field.double` / `field.float` | matching primitive or boxed |
71+
| `field.boolean` | `boolean` |
72+
| `field.date` / `field.time` / `field.timestamp` | `java.time.{LocalDate, LocalTime, Instant}` |
73+
| `field.enum` | Java `enum` |
74+
| `field.currency` | `long` (minor units) |
75+
| `field.object` | nested POJO |
76+
| `isArray: true` | `List<...>` |
77+
78+
## Out of scope
79+
80+
Same exclusions as FR6 parent. Plus: no Java implementation until the codegen
81+
layer ships (gated on H4).
82+
83+
## Open questions
84+
85+
When implementation time comes:
86+
87+
1. Jackson vs Gson vs other (presumably settled by the broader Java codegen design
88+
in H4).
89+
2. Whether to emit a separate parser class or add a `parse` static method to the
90+
POJO itself (Java conventions vary).
91+
3. `meta verify` story for Java — whether to ship a Java CLI extension or rely on
92+
the TS CLI (TS CLI can verify Java metadata since metadata is language-agnostic).

0 commit comments

Comments
 (0)