Skip to content

feat(intent): posts: declarative event-driven row posting (stage 1 - model + glue)#6405

Merged
delchev merged 1 commit into
masterfrom
feat/intent-posts
Jul 24, 2026
Merged

feat(intent): posts: declarative event-driven row posting (stage 1 - model + glue)#6405
delchev merged 1 commit into
masterfrom
feat/intent-posts

Conversation

@delchev

@delchev delchev commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

What

First stage of posts: - a declarative construct that, on a document event, emits mapped rows
into a target entity (per line item), idempotently by a back-reference. It replaces the recurring
hand-written ledger/journal-posting glue (e.g. goods documents → StockMovement lines; document →
GL journal line) - ~8 hand-written delegates/listeners in one KeyFolders module alone.

This PR lands the model + structural glue + test only; the handler template and BPMN/listener
wiring are the next stages (kept small for review).

Changes

  • PostIntent model: name, forEntity, event, forEach, into, idempotentBy, guard,
    set (field → value).
  • IntentModel.posts + accessors.
  • GlueIntentGenerator.buildPosts - emits the glue descriptor per rule: source entity, trigger
    event, per-item collection, target, idempotency back-reference, and the pascal-cased field map
    (Calc values - constants, Master.field, item.field, sign-flip expressions - pass through
    verbatim).
  • GluePostsTest - asserts the emission for a goods-issue-ledger example.

Authoring shape

posts:
  - name: goodsIssueLedger
    forEntity: GoodsIssue
    event: POSTED            # a document status value, or `create`
    forEach: items           # composition-child collection (omit = one row per master)
    into: StockMovement       # target entity (local or cross-model)
    idempotentBy: GoodsIssue  # back-reference FK; skip if target rows already exist
    guard: negativeStock      # optional precondition
    set:
      Product:  item.Product
      Quantity: "-item.Quantity"   # sign flip via Calc expression
      GoodsIssue: Issue.Id         # the back-reference

Note the trigger key is event:, not on: - on is a YAML 1.1 boolean keyword (SnakeYAML
resolves the key to a boolean, so an on: field never binds).

Verification

engine-intent 217/217 green (incl. the new GluePostsTest).

Follow-ups (separate PRs)

  • Handler template: an idempotent status-delegate (event = a status value) / create-listener
    (event = create) that renders set: through the Calc engine and does the idempotentBy
    pre-check; wire it to the trigger (BPMN apply step / -transitioned topic / create topic).
  • Emission oracle; then adopt in the inventory module (retire the 6-7 ledger delegates) and verify
    the ledger posts identically.

🤖 Generated with Claude Code

…lue (stage 1)

First vertical slice of `posts:` (retires the hand-written ledger-posting glue; see kf-catalog
PROPOSAL_EVENT_POSTING.md): PostIntent model (name/forEntity/event/forEach/into/idempotentBy/guard/set)
+ IntentModel.posts + GlueIntentGenerator.buildPosts emitting the structural glue descriptor
(source entity, trigger event, per-item collection, target, idempotency back-reference, pascal-cased
field map with pass-through Calc values incl. sign-flip). GluePostsTest verifies the emission;
engine-intent 217/217 green.

The trigger key is `event:` NOT `on:` - `on` is a YAML 1.1 boolean keyword (SnakeYAML mangles the key
so the field never binds). The handler template (idempotent status-delegate / create-listener) +
BPMN/listener wiring + the emission oracle + inventory adoption are the next stages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@delchev
delchev merged commit 86bb7a4 into master Jul 24, 2026
10 checks passed
@delchev
delchev deleted the feat/intent-posts branch July 24, 2026 13:20
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