intent: a create-from's items where:/refuse: refusal is decided before the header save (#7224) - #7277
Merged
Merged
Conversation
…e the header save (#7224) The two refusals of a create-from's source-row rule ran after the target header was saved. The unit of work took the header back, but the document number allocation and the History create entry live outside it by design, so every refused click spent a number of a gap-free series and left a trail row for a document that never existed. The rule block now runs right after the at-most-once guard, before the target is built; IntentEmissionCoverageIT asserts the emitted order and, end to end, that a refused run leaves the Bill series counter and the Bill history trail unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ThuF
force-pushed
the
fix/7224-refuse-before-header-save
branch
from
September 10, 2026 07:46
fd87883 to
a457bb2
Compare
| /** The number the Bill series hands out right after the given one: same prefix, same width. */ | ||
| private static String nextBillNumber(String number) { | ||
| String digits = number.substring(BILL_NUMBER_PREFIX.length()); | ||
| return BILL_NUMBER_PREFIX + String.format("%0" + digits.length() + "d", Integer.parseInt(digits) + 1); |
…ore-header-save # Conflicts: # .claude/docs/intent-layer.md
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.
#7164 (#7091) added
items: where:+refuse:to a create-from, and both refusals - "an unqualified row exists" and "no row qualifies, the target would have no lines" - were evaluated after the target header had been saved. The header row itself is rolled back by theUnitOfWork, but two things the generated repository does insidesave()deliberately live outside the unit (#7069): the document-number allocation (the counter is a sequence in its own transaction, so concurrent creates never serialize on it) and theHistorycreate entry. Every refused click therefore spent a number of a "continuous, never auto-reset" series and left a trail row for a document that never existed - pressing "Invoice this month" three times on a month with one rejected timesheet burned three invoice numbers.Fix
Both refusal queries depend on nothing but the source rows, so
Generate.java.templatenow runs the whole rule block - the narrowed item query, therefuse:scan and the empty-result check - right after the at-most-once guard, before the target header is built and saved. It stays inside the unit; the clone loop below the save reads the samequalifyinglist. A refused click now writes nothing at all, which is what the template already promised for a missing requiredprompt:input. The comment carries the reasoning; the generated class's Javadoc states the guarantee.Tests
IntentEmissionCoverageIT:Bill- the target of both rule-carrying create-froms - now declareshistory: trueand anumber:field on a newEmission Billseries in the authored.numbers.BillRepository().save(target)in the generated classes.EMISSION_BILL_HISTORYis unchanged across the two refused runs (CREATE rows only, because theBillFlowprocess writes itsProcessIdback asynchronously), and the next Bill minted takes the very next number after the last successful one.Green locally with the fix (239 s). With the original template swapped back in, the IT fails at the new emission-order assertion.
formatter:validategreen.Docs
.claude/docs/client-java.md,.claude/docs/intent-layer.md,engine-intent/CLAUDE.md,intent-assistant-guide.md- one sentence each on the ordering rule.Fixes #7224
🤖 Generated with Claude Code