Skip to content

intent: render a posts set constant for its target column's Java type, and print a remedy that survives YAML (#7287) - #7312

Merged
delchev merged 1 commit into
masterfrom
issue-7287-typed-post-set
Sep 11, 2026
Merged

intent: render a posts set constant for its target column's Java type, and print a remedy that survives YAML (#7287)#7312
delchev merged 1 commit into
masterfrom
issue-7287-typed-post-set

Conversation

@delchev

@delchev delchev commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #7246 / PR #7268: the refusal was right, three of its neighbours were not - all of them the same defect class it set out to close, a posts: set: value that reaches javac as something it cannot compile.

1. The remedy the refusal printed did not work

validatePostSets answered a dotted path with quote it ("Receipt.Store") to mean that text. YAML strips one level of quoting before the parser sees the scalar, so an author who followed that remedy handed the parser the same bare dotted path and got the identical refusal. The spelling that actually reaches PostSetSupport.QUOTED is '"Receipt.Store"' - single quotes wrapping the literal double quotes - which is what the refusal now prints (PostSetSupport.quotedSpelling), with a clause saying why the single quotes are there. QUOTED's own javadoc carried the same misunderstanding and is corrected.

The escape hatch also had no test through the YAML layer. GluePostsTest.theQuotedRemedySurvivesYaml now takes the remedy out of the refusal message, feeds it back through IntentParser.parse, and asserts the rendered "Receipt.Store" string literal.

2. A numeric constant was rendered bare regardless of the target column

Every intent numeric-with-scale type is a java.math.BigDecimal in the generated entity and long is a Long, so Quantity: -3.5 emitted row.Quantity = -3.5; and Sequence: 2 emitted row.Sequence = 2; - compile errors of the whole generated module. Only integer FKs happened to work.

PostSetSupport.targetType now reads the column's type off the target entity - a field by its own spelling (PascalCased on both sides, as the generated assignment is), a to-one relation by its target's key type - and expression renders to it:

column authored rendered
decimal / double -3.5 new java.math.BigDecimal("-3.5")
long 2 2L
integer / relation FK 2 2
string 2, true "2", "true"
not resolvable 2 2 (as before)

A constant the column cannot hold in any spelling - a text into a decimal, a fraction into a whole-number column, a number into a boolean, any constant into a date/time - is refused at parse by typeMismatch, naming the column and the reason, rather than shipped as a literal of the wrong type. A copy (item.<Field> / source.<Field> / null) is not type-checked: the two columns' types are the author's business. No module in the fleet authors posts: today, so nothing in the field is affected by the new refusals.

3. A fourth copy of the same escape loop

PostSetSupport.escape was byte-for-byte JavaLiterals.escape (ide-template, package-private), and GlueIntentGenerator.javaLiteral was a third, weaker vocabulary for the same job - a backslash-then-quote pass that survives a quote but not a newline, which closes the literal too. JavaLiterals is now public (engine-intent already depends on ide-template), both call sites use it, and its javadoc says it is THE escape so a fifth copy does not appear. Pattern noted in #7241.

Verified

  • mvn -pl components/engine/engine-intent,components/ide/ide-template test: 1212 and 143 green.
  • GluePostsTest (8 cases): the typed rendering per TargetType, the type read off a parsed model, the four type refusals, and the quoted remedy driven through IntentParser.parse.
  • IntentEngineIT#posts_writes_every_row_of_one_source_event_in_one_transaction: the fixture sets a decimal, a long, an integer and a text constant; the generated post must carry row.Factor = new java.math.BigDecimal("-1.5");, row.Sequence = 7L;, row.Direction = 2;, row.Ledger = "issued";. Green.
  • IntentPostsAtomicityIT: its fixture now sets a decimal (-1.5) and a long (7) constant, so the whole generate → publish → compile → post → read-back run is the proof they compile - the bare literals would have produced no handler and no rows. Green.

Not verified: no other IT or template branch renders posts: set: (grep), and no .intent in the module fleet authors posts: at all, so there is nothing else to regenerate.

Fixes #7287

🤖 Generated with Claude Code

…, and print a remedy that survives YAML (#7287)

Three neighbours of the #7246 refusal, all of them the same defect class it
set out to close - a `posts: set:` value that reaches javac as something it
cannot compile.

1. The remedy the refusal printed did not work. It named `"Receipt.Store"`,
   which YAML unquotes back into the very dotted path being refused, so an
   author who followed it got the identical refusal. It now names the one
   spelling that survives YAML, `'"Receipt.Store"'`, and says why the single
   quotes are there. PostSetSupport.QUOTED carried the same misunderstanding
   in its javadoc.

2. A numeric constant was rendered bare regardless of the target column. Every
   intent numeric-with-scale type is a BigDecimal in the generated entity and
   `long` is a Long, so `Quantity: -3.5` emitted `row.Quantity = -3.5;` and
   `Sequence: 2` emitted `row.Sequence = 2;` - compile errors of the whole
   generated module. PostSetSupport.targetType now reads the column's type off
   the target entity (a field by its own spelling, a to-one relation by its
   target's key) and expression() renders to it: `new
   java.math.BigDecimal("-3.5")`, `2L`, `2`, and `"2"` into a text column. A
   constant the column cannot hold at all - a text into a decimal, a fraction
   into a long, a number into a boolean, any constant into a date - is refused
   at parse by typeMismatch(), naming the column and the reason.

3. The escape loop had a fourth copy. PostSetSupport.escape was byte-for-byte
   JavaLiterals.escape, and GlueIntentGenerator.javaLiteral was a third,
   weaker vocabulary (a backslash-then-quote pass that a newline still closes).
   JavaLiterals is now public and both call it.

Verified: engine-intent (1212) and ide-template (143) unit suites green;
GluePostsTest drives the quoted remedy THROUGH IntentParser.parse and asserts
the typed rendering off a parsed model; IntentEngineIT asserts the emitted
`row.Factor = new java.math.BigDecimal("-1.5");` / `row.Sequence = 7L;`; and
IntentPostsAtomicityIT now sets a decimal and a long constant, so its
generate-publish-compile-post run is the proof they compile - both ITs green.

Fixes #7287

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@delchev
delchev merged commit b81eb85 into master Sep 11, 2026
10 checks passed
@delchev
delchev deleted the issue-7287-typed-post-set branch September 11, 2026 06:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant